Compare commits
	
		
			57 Commits
		
	
	
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|   | 65c7ac80b5 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | dd3fb32ec7 | ||
|   | 2a3f475ff5 | ||
|   | 7288f71201 | ||
|   | 9c43eff753 | ||
|   | c8d7fdeedc | ||
|   | c211152e23 | ||
|   | ab75d5097e | ||
|   | c3644c8d3b | ||
|   | 6438a3dba3 | ||
|   | 4b226a6a63 | ||
|   | 4801850013 | ||
|   | 6a7412bf2b | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 5a1fd7dadd | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | ac06a26809 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 61d56f26f8 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | 6aa05b3981 | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | aad60c882e | ||
| ![dependabot[bot]](/assets/img/avatar_default.png)  | fecca57507 | ||
|   | 2bcad846c0 | ||
|   | 15ad0165fc | ||
|   | 2e8ab11978 | ||
|   | 9a8ce9b17e | ||
|   | 16ab4c6fed | ||
|   | e3ee0df7ba | ||
|   | 8f7ab280e2 | ||
|   | dbedc99421 | ||
|   | 6cb359cb80 | ||
|   | ae2ad824a9 | ||
|   | 02e3d7852b | ||
|   | 3893a035be | ||
|   | 658bdd9faa | ||
|   | e1eebcd4e0 | ||
|   | 062b831e88 | ||
|   | b275efaeff | ||
|   | 80d3033456 | ||
|   | bd0516f09a | ||
|   | df4d76e466 | ||
|   | dcbd7f8cad | ||
|   | 73ec02ab9d | ||
|   | d1f8347071 | ||
|   | 8601eedada | ||
|   | 9afd33cdfc | ||
|   | 5e1be8e558 | ||
|   | 835dd2635a | ||
|   | f65b18c2f6 | ||
|   | b0e7b84f40 | ||
|   | 1635db93c7 | ||
|   | c4fe462d11 | ||
|   | b1f403165d | ||
|   | 46e4317b77 | ||
|   | e3ffbcadd8 | ||
|   | b7d73077e5 | ||
|   | 77f61ee20a | ||
|   | 8967f02fc9 | ||
|   | 831ff6d0a9 | ||
|   | 2199174def | 
							
								
								
									
										22
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								.github/dependabot.yml
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| # Docs: <https://docs.github.com/en/free-pro-team@latest/github/administering-a-repository/customizing-dependency-updates> | ||||
|  | ||||
| version: 2 | ||||
|  | ||||
| updates: | ||||
|   - package-ecosystem: gomod | ||||
|     directory: / | ||||
|     schedule: {interval: weekly} | ||||
|     reviewers: [42wim] | ||||
|     assignees: [42wim] | ||||
|  | ||||
|   - package-ecosystem: github-actions | ||||
|     directory: / | ||||
|     schedule: {interval: weekly} | ||||
|     reviewers: [42wim] | ||||
|     assignees: [42wim] | ||||
|  | ||||
|   - package-ecosystem: docker | ||||
|     directory: / | ||||
|     schedule: {interval: weekly} | ||||
|     reviewers: [42wim] | ||||
|     assignees: [42wim] | ||||
							
								
								
									
										6
									
								
								.github/workflows/development.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								.github/workflows/development.yml
									
									
									
									
										vendored
									
									
								
							| @@ -35,9 +35,9 @@ jobs: | ||||
|       run: | | ||||
|         mkdir -p output/{win,lin,arm,mac} | ||||
|         VERSION=$(git describe --tags) | ||||
|         CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o output/lin/matterbridge-$VERSION-linux-amd64 | ||||
|         CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o output/win/matterbridge-$VERSION-windows-amd64.exe | ||||
|         CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -X main.githash=$(git log --pretty=format:'%h' -n 1)" -o output/mac/matterbridge-$VERSION-darwin-amd64 | ||||
|         CGO_ENABLED=0 GOOS=linux GOARCH=amd64 go build -ldflags "-s -X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o output/lin/matterbridge-$VERSION-linux-amd64 | ||||
|         CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o output/win/matterbridge-$VERSION-windows-amd64.exe | ||||
|         CGO_ENABLED=0 GOOS=darwin GOARCH=amd64 go build -ldflags "-s -X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o output/mac/matterbridge-$VERSION-darwin-amd64 | ||||
|     - name: Upload linux 64-bit | ||||
|       if: startsWith(matrix.go-version,'1.17') | ||||
|       uses: actions/upload-artifact@v2 | ||||
|   | ||||
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @@ -4,3 +4,6 @@ | ||||
|  | ||||
| # Exclude configuration file | ||||
| matterbridge.toml | ||||
|  | ||||
| # Exclude IDE Files | ||||
| .vscode | ||||
|   | ||||
| @@ -186,7 +186,24 @@ linters: | ||||
|     - errorlint | ||||
|     - nlreturn | ||||
|     - exhaustivestruct | ||||
|  | ||||
|     - forbidigo | ||||
|     - wrapcheck | ||||
|     - varnamelen | ||||
|     - ireturn | ||||
|     - errorlint | ||||
|     - tparallel | ||||
|     - wrapcheck | ||||
|     - paralleltest | ||||
|     - makezero | ||||
|     - thelper | ||||
|     - cyclop | ||||
|     - revive | ||||
|     - importas | ||||
|     - gomoddirectives | ||||
|     - promlinter | ||||
|     - tagliatelle | ||||
|     - errname | ||||
|     - typecheck | ||||
| # rules to deal with reported isues | ||||
| issues: | ||||
|   # List of regexps of issue texts to exclude, empty list by default. | ||||
|   | ||||
| @@ -22,7 +22,7 @@ builds: | ||||
|     - 6 | ||||
|     - 7 | ||||
|   ldflags: | ||||
|     - -s -w -X main.githash={{.ShortCommit}} | ||||
|     - -s -w -X github.com/42wim/matterbridge/version.GitHash={{.ShortCommit}} | ||||
|  | ||||
| archives: | ||||
|   - | ||||
|   | ||||
| @@ -1,9 +1,9 @@ | ||||
| FROM alpine:edge AS builder | ||||
| FROM alpine AS builder | ||||
|  | ||||
| COPY . /go/src/matterbridge | ||||
| RUN apk --no-cache add go git \ | ||||
|         && cd /go/src/matterbridge \ | ||||
|         && CGO_ENABLED=0 go build -mod vendor -ldflags "-X main.githash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge | ||||
|         && CGO_ENABLED=0 go build -mod vendor -ldflags "-X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge | ||||
|  | ||||
| FROM alpine | ||||
| RUN apk --no-cache add ca-certificates mailcap | ||||
|   | ||||
| @@ -164,7 +164,7 @@ See <https://github.com/42wim/matterbridge/wiki> | ||||
|  | ||||
| ### Binaries | ||||
|  | ||||
| - Latest stable release [v1.23.0](https://github.com/42wim/matterbridge/releases/latest) | ||||
| - Latest stable release [v1.24.0](https://github.com/42wim/matterbridge/releases/latest) | ||||
| - Development releases (follows master) can be downloaded [here](https://github.com/42wim/matterbridge/actions) selecting the latest green build and then artifacts. | ||||
|  | ||||
| To install or upgrade just download the latest [binary](https://github.com/42wim/matterbridge/releases/latest). On \*nix platforms you may need to make the binary executable - you can do this by running `chmod a+x` on the binary (example: `chmod a+x matterbridge-1.20.0-linux-64bit`). After downloading (and making the binary executable, if necessary), follow the instructions on the [howto](https://github.com/42wim/matterbridge/wiki/How-to-create-your-config) for a step by step walkthrough for creating your configuration. | ||||
| @@ -336,6 +336,7 @@ See [FAQ](https://github.com/42wim/matterbridge/wiki/FAQ) | ||||
| - <https://daniele.tech/2019/02/how-to-use-matterbridge-to-connect-2-different-slack-workspaces/> | ||||
| - <https://userlinux.net/mattermost-and-matterbridge.html> | ||||
| - <https://nextcloud.com/blog/bridging-chat-services-in-talk/> | ||||
| - <https://minecraftchest1.wordpress.com/2021/06/05/how-to-install-and-setup-matterbridge/> | ||||
| - Youtube: [whatsapp - telegram bridging](https://www.youtube.com/watch?v=W-VXISoKtNc) | ||||
|  | ||||
| ## Thanks | ||||
|   | ||||
| @@ -23,6 +23,7 @@ const ( | ||||
| 	EventRejoinChannels    = "rejoin_channels" | ||||
| 	EventUserAction        = "user_action" | ||||
| 	EventMsgDelete         = "msg_delete" | ||||
| 	EventFileDelete        = "file_delete" | ||||
| 	EventAPIConnected      = "api_connected" | ||||
| 	EventUserTyping        = "user_typing" | ||||
| 	EventGetChannelMembers = "get_channel_members" | ||||
| @@ -56,13 +57,14 @@ func (m Message) ParentValid() bool { | ||||
| } | ||||
|  | ||||
| type FileInfo struct { | ||||
| 	Name    string | ||||
| 	Data    *[]byte | ||||
| 	Comment string | ||||
| 	URL     string | ||||
| 	Size    int64 | ||||
| 	Avatar  bool | ||||
| 	SHA     string | ||||
| 	Name     string | ||||
| 	Data     *[]byte | ||||
| 	Comment  string | ||||
| 	URL      string | ||||
| 	Size     int64 | ||||
| 	Avatar   bool | ||||
| 	SHA      string | ||||
| 	NativeID string | ||||
| } | ||||
|  | ||||
| type ChannelInfo struct { | ||||
| @@ -168,7 +170,7 @@ type Protocol struct { | ||||
| 	UseTLS                 bool       // IRC | ||||
| 	UseDiscriminator       bool       // discord | ||||
| 	UseFirstName           bool       // telegram | ||||
| 	UseUserName            bool       // discord, matrix | ||||
| 	UseUserName            bool       // discord, matrix, mattermost | ||||
| 	UseInsecureURL         bool       // telegram | ||||
| 	UserName               string     // IRC | ||||
| 	VerboseJoinPart        bool       // IRC | ||||
|   | ||||
| @@ -10,10 +10,14 @@ import ( | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/discord/transmitter" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	lru "github.com/hashicorp/golang-lru" | ||||
| 	"github.com/matterbridge/discordgo" | ||||
| ) | ||||
|  | ||||
| const MessageLength = 1950 | ||||
| const ( | ||||
| 	MessageLength = 1950 | ||||
| 	cFileUpload   = "file_upload" | ||||
| ) | ||||
|  | ||||
| type Bdiscord struct { | ||||
| 	*bridge.Config | ||||
| @@ -35,10 +39,20 @@ type Bdiscord struct { | ||||
| 	// Webhook specific logic | ||||
| 	useAutoWebhooks bool | ||||
| 	transmitter     *transmitter.Transmitter | ||||
| 	cache           *lru.Cache | ||||
| } | ||||
|  | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Bdiscord{Config: cfg} | ||||
| 	newCache, err := lru.New(5000) | ||||
| 	if err != nil { | ||||
| 		cfg.Log.Fatalf("Could not create LRU cache: %v", err) | ||||
| 	} | ||||
|  | ||||
| 	b := &Bdiscord{ | ||||
| 		Config: cfg, | ||||
| 		cache:  newCache, | ||||
| 	} | ||||
|  | ||||
| 	b.userMemberMap = make(map[string]*discordgo.Member) | ||||
| 	b.nickMemberMap = make(map[string]*discordgo.Member) | ||||
| 	b.channelInfoMap = make(map[string]*config.ChannelInfo) | ||||
| @@ -75,6 +89,9 @@ func (b *Bdiscord) Connect() error { | ||||
| 	b.c.AddHandler(b.messageDeleteBulk) | ||||
| 	b.c.AddHandler(b.memberAdd) | ||||
| 	b.c.AddHandler(b.memberRemove) | ||||
| 	if b.GetInt("debuglevel") == 1 { | ||||
| 		b.c.AddHandler(b.messageEvent) | ||||
| 	} | ||||
| 	// Add privileged intent for guild member tracking. This is needed to track nicks | ||||
| 	// for display names and @mention translation | ||||
| 	b.c.Identify.Intents = discordgo.MakeIntent(discordgo.IntentsAllWithoutPrivileged | | ||||
| @@ -153,7 +170,7 @@ func (b *Bdiscord) Connect() error { | ||||
| 		return fmt.Errorf("use of removed WebhookURL setting") | ||||
| 	} | ||||
|  | ||||
| 	if b.GetInt("debuglevel") > 0 { | ||||
| 	if b.GetInt("debuglevel") == 2 { | ||||
| 		b.Log.Debug("enabling even more discord debug") | ||||
| 		b.c.Debug = true | ||||
| 	} | ||||
| @@ -280,6 +297,21 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	// Delete a file | ||||
| 	if msg.Event == config.EventFileDelete { | ||||
| 		if msg.ID == "" { | ||||
| 			return "", nil | ||||
| 		} | ||||
|  | ||||
| 		if fi, ok := b.cache.Get(cFileUpload + msg.ID); ok { | ||||
| 			err := b.c.ChannelMessageDelete(channelID, fi.(string)) // nolint:forcetypeassert | ||||
| 			b.cache.Remove(cFileUpload + msg.ID) | ||||
| 			return "", err | ||||
| 		} | ||||
|  | ||||
| 		return "", fmt.Errorf("file %s not found", msg.ID) | ||||
| 	} | ||||
|  | ||||
| 	// Upload a file if it exists | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(msg, b.General) { | ||||
| @@ -327,7 +359,6 @@ func (b *Bdiscord) handleEventBotUser(msg *config.Message, channelID string) (st | ||||
|  | ||||
| // handleUploadFile handles native upload of files | ||||
| func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (string, error) { | ||||
| 	var err error | ||||
| 	for _, f := range msg.Extra["file"] { | ||||
| 		fi := f.(config.FileInfo) | ||||
| 		file := discordgo.File{ | ||||
| @@ -340,10 +371,15 @@ func (b *Bdiscord) handleUploadFile(msg *config.Message, channelID string) (stri | ||||
| 			Files:           []*discordgo.File{&file}, | ||||
| 			AllowedMentions: b.getAllowedMentions(), | ||||
| 		} | ||||
| 		_, err = b.c.ChannelMessageSendComplex(channelID, &m) | ||||
| 		res, err := b.c.ChannelMessageSendComplex(channelID, &m) | ||||
| 		if err != nil { | ||||
| 			return "", fmt.Errorf("file upload failed: %s", err) | ||||
| 		} | ||||
|  | ||||
| 		// link file_upload_nativeID (file ID from the original bridge) to our upload id | ||||
| 		// so that we can remove this later when it eg needs to be deleted | ||||
| 		b.cache.Add(cFileUpload+fi.NativeID, res.ID) | ||||
| 	} | ||||
|  | ||||
| 	return "", nil | ||||
| } | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package bdiscord | ||||
|  | ||||
| import ( | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/davecgh/go-spew/spew" | ||||
| 	"github.com/matterbridge/discordgo" | ||||
| ) | ||||
|  | ||||
| @@ -31,6 +32,10 @@ func (b *Bdiscord) messageDeleteBulk(s *discordgo.Session, m *discordgo.MessageD | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Bdiscord) messageEvent(s *discordgo.Session, m *discordgo.Event) { | ||||
| 	b.Log.Debug(spew.Sdump(m.Struct)) | ||||
| } | ||||
|  | ||||
| func (b *Bdiscord) messageTyping(s *discordgo.Session, m *discordgo.TypingStart) { | ||||
| 	if !b.GetBool("ShowUserTyping") { | ||||
| 		return | ||||
| @@ -82,8 +87,9 @@ func (b *Bdiscord) messageCreate(s *discordgo.Session, m *discordgo.MessageCreat | ||||
|  | ||||
| 	rmsg := config.Message{Account: b.Account, Avatar: "https://cdn.discordapp.com/avatars/" + m.Author.ID + "/" + m.Author.Avatar + ".jpg", UserID: m.Author.ID, ID: m.ID} | ||||
|  | ||||
| 	b.Log.Debugf("== Receiving event %#v", m.Message) | ||||
|  | ||||
| 	if m.Content != "" { | ||||
| 		b.Log.Debugf("== Receiving event %#v", m.Message) | ||||
| 		m.Message.Content = b.replaceChannelMentions(m.Message.Content) | ||||
| 		rmsg.Text, err = m.ContentWithMoreMentionsReplaced(b.c) | ||||
| 		if err != nil { | ||||
|   | ||||
| @@ -82,10 +82,8 @@ func (b *Bdiscord) webhookSend(msg *config.Message, channelID string) (*discordg | ||||
| 				ContentType: "", | ||||
| 				Reader:      bytes.NewReader(*fi.Data), | ||||
| 			} | ||||
| 			content := "" | ||||
| 			if msg.Text == "" { | ||||
| 				content = fi.Comment | ||||
| 			} | ||||
| 			content := fi.Comment | ||||
|  | ||||
| 			_, e2 := b.transmitter.Send( | ||||
| 				channelID, | ||||
| 				&discordgo.WebhookParams{ | ||||
|   | ||||
							
								
								
									
										252
									
								
								bridge/harmony/harmony.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										252
									
								
								bridge/harmony/harmony.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,252 @@ | ||||
| package harmony | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"log" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/harmony-development/shibshib" | ||||
| 	chatv1 "github.com/harmony-development/shibshib/gen/chat/v1" | ||||
| 	typesv1 "github.com/harmony-development/shibshib/gen/harmonytypes/v1" | ||||
| 	profilev1 "github.com/harmony-development/shibshib/gen/profile/v1" | ||||
| ) | ||||
|  | ||||
| type cachedProfile struct { | ||||
| 	data        *profilev1.GetProfileResponse | ||||
| 	lastUpdated time.Time | ||||
| } | ||||
|  | ||||
| type Bharmony struct { | ||||
| 	*bridge.Config | ||||
|  | ||||
| 	c            *shibshib.Client | ||||
| 	profileCache map[uint64]cachedProfile | ||||
| } | ||||
|  | ||||
| func uToStr(in uint64) string { | ||||
| 	return strconv.FormatUint(in, 10) | ||||
| } | ||||
|  | ||||
| func strToU(in string) (uint64, error) { | ||||
| 	return strconv.ParseUint(in, 10, 64) | ||||
| } | ||||
|  | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Bharmony{ | ||||
| 		Config:       cfg, | ||||
| 		profileCache: map[uint64]cachedProfile{}, | ||||
| 	} | ||||
|  | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) getProfile(u uint64) (*profilev1.GetProfileResponse, error) { | ||||
| 	if v, ok := b.profileCache[u]; ok && time.Since(v.lastUpdated) < time.Minute*10 { | ||||
| 		return v.data, nil | ||||
| 	} | ||||
|  | ||||
| 	resp, err := b.c.ProfileKit.GetProfile(&profilev1.GetProfileRequest{ | ||||
| 		UserId: u, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		if v, ok := b.profileCache[u]; ok { | ||||
| 			return v.data, nil | ||||
| 		} | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	b.profileCache[u] = cachedProfile{ | ||||
| 		data:        resp, | ||||
| 		lastUpdated: time.Now(), | ||||
| 	} | ||||
| 	return resp, nil | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) avatarFor(m *chatv1.Message) string { | ||||
| 	if m.Overrides != nil { | ||||
| 		return m.Overrides.GetAvatar() | ||||
| 	} | ||||
|  | ||||
| 	profi, err := b.getProfile(m.AuthorId) | ||||
| 	if err != nil { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	return b.c.TransformHMCURL(profi.Profile.GetUserAvatar()) | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) usernameFor(m *chatv1.Message) string { | ||||
| 	if m.Overrides != nil { | ||||
| 		return m.Overrides.GetUsername() | ||||
| 	} | ||||
|  | ||||
| 	profi, err := b.getProfile(m.AuthorId) | ||||
| 	if err != nil { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	return profi.Profile.UserName | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) toMessage(msg *shibshib.LocatedMessage) config.Message { | ||||
| 	message := config.Message{} | ||||
| 	message.Account = b.Account | ||||
| 	message.UserID = uToStr(msg.Message.AuthorId) | ||||
| 	message.Avatar = b.avatarFor(msg.Message) | ||||
| 	message.Username = b.usernameFor(msg.Message) | ||||
| 	message.Channel = uToStr(msg.ChannelID) | ||||
| 	message.ID = uToStr(msg.MessageId) | ||||
|  | ||||
| 	switch content := msg.Message.Content.Content.(type) { | ||||
| 	case *chatv1.Content_EmbedMessage: | ||||
| 		message.Text = "Embed" | ||||
| 	case *chatv1.Content_AttachmentMessage: | ||||
| 		var s strings.Builder | ||||
| 		for idx, attach := range content.AttachmentMessage.Files { | ||||
| 			s.WriteString(b.c.TransformHMCURL(attach.Id)) | ||||
| 			if idx < len(content.AttachmentMessage.Files)-1 { | ||||
| 				s.WriteString(", ") | ||||
| 			} | ||||
| 		} | ||||
| 		message.Text = s.String() | ||||
| 	case *chatv1.Content_PhotoMessage: | ||||
| 		var s strings.Builder | ||||
| 		for idx, attach := range content.PhotoMessage.GetPhotos() { | ||||
| 			s.WriteString(attach.GetCaption().GetText()) | ||||
| 			s.WriteString("\n") | ||||
| 			s.WriteString(b.c.TransformHMCURL(attach.GetHmc())) | ||||
| 			if idx < len(content.PhotoMessage.GetPhotos())-1 { | ||||
| 				s.WriteString("\n\n") | ||||
| 			} | ||||
| 		} | ||||
| 		message.Text = s.String() | ||||
| 	case *chatv1.Content_TextMessage: | ||||
| 		message.Text = content.TextMessage.Content.Text | ||||
| 	} | ||||
|  | ||||
| 	return message | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) outputMessages() { | ||||
| 	for { | ||||
| 		msg := <-b.c.EventsStream() | ||||
|  | ||||
| 		if msg.Message.AuthorId == b.c.UserID { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		b.Remote <- b.toMessage(msg) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) GetUint64(conf string) uint64 { | ||||
| 	num, err := strToU(b.GetString(conf)) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	return num | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) Connect() (err error) { | ||||
| 	b.c, err = shibshib.NewClient(b.GetString("Homeserver"), b.GetString("Token"), b.GetUint64("UserID")) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
| 	b.c.SubscribeToGuild(b.GetUint64("Community")) | ||||
|  | ||||
| 	go b.outputMessages() | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) send(msg config.Message) (id string, err error) { | ||||
| 	msgChan, err := strToU(msg.Channel) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	retID, err := b.c.ChatKit.SendMessage(&chatv1.SendMessageRequest{ | ||||
| 		GuildId:   b.GetUint64("Community"), | ||||
| 		ChannelId: msgChan, | ||||
| 		Content: &chatv1.Content{ | ||||
| 			Content: &chatv1.Content_TextMessage{ | ||||
| 				TextMessage: &chatv1.Content_TextContent{ | ||||
| 					Content: &chatv1.FormattedText{ | ||||
| 						Text: msg.Text, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 		Overrides: &chatv1.Overrides{ | ||||
| 			Username: &msg.Username, | ||||
| 			Avatar:   &msg.Avatar, | ||||
| 			Reason:   &chatv1.Overrides_Bridge{Bridge: &typesv1.Empty{}}, | ||||
| 		}, | ||||
| 		InReplyTo: nil, | ||||
| 		EchoId:    nil, | ||||
| 		Metadata:  nil, | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		err = fmt.Errorf("send: error sending message: %w", err) | ||||
| 		log.Println(err.Error()) | ||||
| 	} | ||||
|  | ||||
| 	return uToStr(retID.MessageId), err | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) delete(msg config.Message) (id string, err error) { | ||||
| 	msgChan, err := strToU(msg.Channel) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	msgID, err := strToU(msg.ID) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	_, err = b.c.ChatKit.DeleteMessage(&chatv1.DeleteMessageRequest{ | ||||
| 		GuildId:   b.GetUint64("Community"), | ||||
| 		ChannelId: msgChan, | ||||
| 		MessageId: msgID, | ||||
| 	}) | ||||
| 	return "", err | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) typing(msg config.Message) (id string, err error) { | ||||
| 	msgChan, err := strToU(msg.Channel) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	_, err = b.c.ChatKit.Typing(&chatv1.TypingRequest{ | ||||
| 		GuildId:   b.GetUint64("Community"), | ||||
| 		ChannelId: msgChan, | ||||
| 	}) | ||||
| 	return "", err | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) Send(msg config.Message) (id string, err error) { | ||||
| 	switch msg.Event { | ||||
| 	case "": | ||||
| 		return b.send(msg) | ||||
| 	case config.EventMsgDelete: | ||||
| 		return b.delete(msg) | ||||
| 	case config.EventUserTyping: | ||||
| 		return b.typing(msg) | ||||
| 	default: | ||||
| 		return "", nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (b *Bharmony) Disconnect() error { | ||||
| 	return nil | ||||
| } | ||||
| @@ -168,17 +168,23 @@ func HandleDownloadSize(logger *logrus.Entry, msg *config.Message, name string, | ||||
|  | ||||
| // HandleDownloadData adds the data for a remote file into a Matterbridge gateway message. | ||||
| func HandleDownloadData(logger *logrus.Entry, msg *config.Message, name, comment, url string, data *[]byte, general *config.Protocol) { | ||||
| 	HandleDownloadData2(logger, msg, name, "", comment, url, data, general) | ||||
| } | ||||
|  | ||||
| // HandleDownloadData adds the data for a remote file into a Matterbridge gateway message. | ||||
| func HandleDownloadData2(logger *logrus.Entry, msg *config.Message, name, id, comment, url string, data *[]byte, general *config.Protocol) { | ||||
| 	var avatar bool | ||||
| 	logger.Debugf("Download OK %#v %#v", name, len(*data)) | ||||
| 	if msg.Event == config.EventAvatarDownload { | ||||
| 		avatar = true | ||||
| 	} | ||||
| 	msg.Extra["file"] = append(msg.Extra["file"], config.FileInfo{ | ||||
| 		Name:    name, | ||||
| 		Data:    data, | ||||
| 		URL:     url, | ||||
| 		Comment: comment, | ||||
| 		Avatar:  avatar, | ||||
| 		Name:     name, | ||||
| 		Data:     data, | ||||
| 		URL:      url, | ||||
| 		Comment:  comment, | ||||
| 		Avatar:   avatar, | ||||
| 		NativeID: id, | ||||
| 	}) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package birc | ||||
|  | ||||
| import ( | ||||
| 	"crypto/tls" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"hash/crc32" | ||||
| 	"io/ioutil" | ||||
| @@ -72,6 +73,10 @@ func (b *Birc) Command(msg *config.Message) string { | ||||
| } | ||||
|  | ||||
| func (b *Birc) Connect() error { | ||||
| 	if b.GetBool("UseSASL") && b.GetString("TLSClientCertificate") != "" { | ||||
| 		return errors.New("you can't enable SASL and TLSClientCertificate at the same time") | ||||
| 	} | ||||
|  | ||||
| 	b.Local = make(chan config.Message, b.MessageQueue+10) | ||||
| 	b.Log.Infof("Connecting %s", b.GetString("Server")) | ||||
|  | ||||
| @@ -300,6 +305,11 @@ func (b *Birc) getClient() (*girc.Client, error) { | ||||
|  | ||||
| 	b.Log.Debugf("setting pingdelay to %s", pingDelay) | ||||
|  | ||||
| 	tlsConfig, err := b.getTLSConfig() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	i := girc.New(girc.Config{ | ||||
| 		Server:     server, | ||||
| 		ServerPass: b.GetString("Password"), | ||||
| @@ -308,7 +318,8 @@ func (b *Birc) getClient() (*girc.Client, error) { | ||||
| 		User:       user, | ||||
| 		Name:       realName, | ||||
| 		SSL:        b.GetBool("UseTLS"), | ||||
| 		TLSConfig:  &tls.Config{InsecureSkipVerify: b.GetBool("SkipTLSVerify"), ServerName: server}, //nolint:gosec | ||||
| 		Bind:       b.GetString("Bind"), | ||||
| 		TLSConfig:  tlsConfig, | ||||
| 		PingDelay:  pingDelay, | ||||
| 		// skip gIRC internal rate limiting, since we have our own throttling | ||||
| 		AllowFlood:    true, | ||||
| @@ -380,3 +391,23 @@ func (b *Birc) storeNames(client *girc.Client, event girc.Event) { | ||||
| func (b *Birc) formatnicks(nicks []string) string { | ||||
| 	return strings.Join(nicks, ", ") + " currently on IRC" | ||||
| } | ||||
|  | ||||
| func (b *Birc) getTLSConfig() (*tls.Config, error) { | ||||
| 	server, _, _ := net.SplitHostPort(b.GetString("server")) | ||||
|  | ||||
| 	tlsConfig := &tls.Config{ | ||||
| 		InsecureSkipVerify: b.GetBool("skiptlsverify"), //nolint:gosec | ||||
| 		ServerName:         server, | ||||
| 	} | ||||
|  | ||||
| 	if filename := b.GetString("TLSClientCertificate"); filename != "" { | ||||
| 		cert, err := tls.LoadX509KeyPair(filename, filename) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		tlsConfig.Certificates = []tls.Certificate{cert} | ||||
| 	} | ||||
|  | ||||
| 	return tlsConfig, nil | ||||
| } | ||||
|   | ||||
| @@ -48,8 +48,10 @@ type matrixUsername struct { | ||||
|  | ||||
| // SubTextMessage represents the new content of the message in edit messages. | ||||
| type SubTextMessage struct { | ||||
| 	MsgType string `json:"msgtype"` | ||||
| 	Body    string `json:"body"` | ||||
| 	MsgType       string `json:"msgtype"` | ||||
| 	Body          string `json:"body"` | ||||
| 	FormattedBody string `json:"formatted_body,omitempty"` | ||||
| 	Format        string `json:"format,omitempty"` | ||||
| } | ||||
|  | ||||
| // MessageRelation explains how the current message relates to a previous message. | ||||
| @@ -65,6 +67,19 @@ type EditedMessage struct { | ||||
| 	matrix.TextMessage | ||||
| } | ||||
|  | ||||
| type InReplyToRelationContent struct { | ||||
| 	EventID string `json:"event_id"` | ||||
| } | ||||
|  | ||||
| type InReplyToRelation struct { | ||||
| 	InReplyTo InReplyToRelationContent `json:"m.in_reply_to"` | ||||
| } | ||||
|  | ||||
| type ReplyMessage struct { | ||||
| 	RelatedTo InReplyToRelation `json:"m.relates_to"` | ||||
| 	matrix.TextMessage | ||||
| } | ||||
|  | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Bmatrix{Config: cfg} | ||||
| 	b.RoomMap = make(map[string]string) | ||||
| @@ -138,7 +153,13 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) { | ||||
| 		m := matrix.TextMessage{ | ||||
| 			MsgType:       "m.emote", | ||||
| 			Body:          username.plain + msg.Text, | ||||
| 			FormattedBody: username.formatted + msg.Text, | ||||
| 			FormattedBody: username.formatted + helper.ParseMarkdown(msg.Text), | ||||
| 			Format:        "org.matrix.custom.html", | ||||
| 		} | ||||
|  | ||||
| 		if b.GetBool("HTMLDisable") { | ||||
| 			m.Format = "" | ||||
| 			m.FormattedBody = "" | ||||
| 		} | ||||
|  | ||||
| 		msgID := "" | ||||
| @@ -201,20 +222,29 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) { | ||||
|  | ||||
| 	// Edit message if we have an ID | ||||
| 	if msg.ID != "" { | ||||
| 		rmsg := EditedMessage{TextMessage: matrix.TextMessage{ | ||||
| 			Body:    username.plain + msg.Text, | ||||
| 			MsgType: "m.text", | ||||
| 		}} | ||||
| 		if b.GetBool("HTMLDisable") { | ||||
| 			rmsg.TextMessage.FormattedBody = username.formatted + "* " + msg.Text | ||||
| 		} else { | ||||
| 			rmsg.Format = "org.matrix.custom.html" | ||||
| 			rmsg.TextMessage.FormattedBody = username.formatted + "* " + helper.ParseMarkdown(msg.Text) | ||||
| 		rmsg := EditedMessage{ | ||||
| 			TextMessage: matrix.TextMessage{ | ||||
| 				Body:          username.plain + msg.Text, | ||||
| 				MsgType:       "m.text", | ||||
| 				Format:        "org.matrix.custom.html", | ||||
| 				FormattedBody: username.formatted + helper.ParseMarkdown(msg.Text), | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| 		rmsg.NewContent = SubTextMessage{ | ||||
| 			Body:    rmsg.TextMessage.Body, | ||||
| 			MsgType: "m.text", | ||||
| 			Body:          rmsg.TextMessage.Body, | ||||
| 			FormattedBody: rmsg.TextMessage.FormattedBody, | ||||
| 			Format:        rmsg.TextMessage.Format, | ||||
| 			MsgType:       "m.text", | ||||
| 		} | ||||
|  | ||||
| 		if b.GetBool("HTMLDisable") { | ||||
| 			rmsg.TextMessage.Format = "" | ||||
| 			rmsg.TextMessage.FormattedBody = "" | ||||
| 			rmsg.NewContent.Format = "" | ||||
| 			rmsg.NewContent.FormattedBody = "" | ||||
| 		} | ||||
|  | ||||
| 		rmsg.RelatedTo = MessageRelation{ | ||||
| 			EventID: msg.ID, | ||||
| 			Type:    "m.replace", | ||||
| @@ -238,6 +268,50 @@ func (b *Bmatrix) Send(msg config.Message) (string, error) { | ||||
| 			MsgType:       "m.notice", | ||||
| 			Body:          username.plain + msg.Text, | ||||
| 			FormattedBody: username.formatted + msg.Text, | ||||
| 			Format:        "org.matrix.custom.html", | ||||
| 		} | ||||
|  | ||||
| 		if b.GetBool("HTMLDisable") { | ||||
| 			m.Format = "" | ||||
| 			m.FormattedBody = "" | ||||
| 		} | ||||
|  | ||||
| 		var ( | ||||
| 			resp *matrix.RespSendEvent | ||||
| 			err  error | ||||
| 		) | ||||
|  | ||||
| 		err = b.retry(func() error { | ||||
| 			resp, err = b.mc.SendMessageEvent(channel, "m.room.message", m) | ||||
|  | ||||
| 			return err | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			return "", err | ||||
| 		} | ||||
|  | ||||
| 		return resp.EventID, err | ||||
| 	} | ||||
|  | ||||
| 	if msg.ParentValid() { | ||||
| 		m := ReplyMessage{ | ||||
| 			TextMessage: matrix.TextMessage{ | ||||
| 				MsgType:       "m.text", | ||||
| 				Body:          username.plain + msg.Text, | ||||
| 				FormattedBody: username.formatted + helper.ParseMarkdown(msg.Text), | ||||
| 				Format:        "org.matrix.custom.html", | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| 		if b.GetBool("HTMLDisable") { | ||||
| 			m.TextMessage.Format = "" | ||||
| 			m.TextMessage.FormattedBody = "" | ||||
| 		} | ||||
|  | ||||
| 		m.RelatedTo = InReplyToRelation{ | ||||
| 			InReplyTo: InReplyToRelationContent{ | ||||
| 				EventID: msg.ParentID, | ||||
| 			}, | ||||
| 		} | ||||
|  | ||||
| 		var ( | ||||
| @@ -301,6 +375,9 @@ func (b *Bmatrix) handlematrix() { | ||||
| 	syncer.OnEventType("m.room.member", b.handleMemberChange) | ||||
| 	go func() { | ||||
| 		for { | ||||
| 			if b == nil { | ||||
| 				return | ||||
| 			} | ||||
| 			if err := b.mc.Sync(); err != nil { | ||||
| 				b.Log.Println("Sync() returned ", err) | ||||
| 			} | ||||
| @@ -338,6 +415,35 @@ func (b *Bmatrix) handleEdit(ev *matrix.Event, rmsg config.Message) bool { | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func (b *Bmatrix) handleReply(ev *matrix.Event, rmsg config.Message) bool { | ||||
| 	relationInterface, present := ev.Content["m.relates_to"] | ||||
| 	if !present { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	var relation InReplyToRelation | ||||
| 	if err := interface2Struct(relationInterface, &relation); err != nil { | ||||
| 		// probably fine | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	body := rmsg.Text | ||||
| 	for strings.HasPrefix(body, "> ") { | ||||
| 		lineIdx := strings.IndexRune(body, '\n') | ||||
| 		if lineIdx == -1 { | ||||
| 			body = "" | ||||
| 		} else { | ||||
| 			body = body[(lineIdx + 1):] | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	rmsg.Text = body | ||||
| 	rmsg.ParentID = relation.InReplyTo.EventID | ||||
| 	b.Remote <- rmsg | ||||
|  | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func (b *Bmatrix) handleMemberChange(ev *matrix.Event) { | ||||
| 	// Update the displayname on join messages, according to https://matrix.org/docs/spec/client_server/r0.6.1#events-on-change-of-profile-information | ||||
| 	if ev.Content["membership"] == "join" { | ||||
| @@ -400,6 +506,11 @@ func (b *Bmatrix) handleEvent(ev *matrix.Event) { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		// Is it a reply? | ||||
| 		if b.handleReply(ev, rmsg) { | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		// Do we have attachments | ||||
| 		if b.containsAttachment(ev.Content) { | ||||
| 			err := b.handleDownloadFile(&rmsg, ev.Content) | ||||
|   | ||||
| @@ -140,9 +140,14 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		channelName := b.getChannelName(message.Post.ChannelId) | ||||
| 		if channelName == "" { | ||||
| 			channelName = message.Channel | ||||
| 		} | ||||
|  | ||||
| 		// only download avatars if we have a place to upload them (configured mediaserver) | ||||
| 		if b.General.MediaServerUpload != "" || b.General.MediaDownloadPath != "" { | ||||
| 			b.handleDownloadAvatar(message.UserID, message.Channel) | ||||
| 			b.handleDownloadAvatar(message.UserID, channelName) | ||||
| 		} | ||||
|  | ||||
| 		b.Log.Debugf("== Receiving event %#v", message) | ||||
| @@ -150,7 +155,7 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) { | ||||
| 		rmsg := &config.Message{ | ||||
| 			Username: message.Username, | ||||
| 			UserID:   message.UserID, | ||||
| 			Channel:  message.Channel, | ||||
| 			Channel:  channelName, | ||||
| 			Text:     message.Text, | ||||
| 			ID:       message.Post.Id, | ||||
| 			ParentID: message.Post.RootId, // ParentID is obsolete with mattermost | ||||
| @@ -177,8 +182,10 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) { | ||||
| 		} | ||||
|  | ||||
| 		// Use nickname instead of username if defined | ||||
| 		if nick := b.mc.GetNickName(rmsg.UserID); nick != "" { | ||||
| 			rmsg.Username = nick | ||||
| 		if !b.GetBool("useusername") { | ||||
| 			if nick := b.mc.GetNickName(rmsg.UserID); nick != "" { | ||||
| 				rmsg.Username = nick | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		messages <- rmsg | ||||
| @@ -188,16 +195,21 @@ func (b *Bmattermost) handleMatterClient(messages chan *config.Message) { | ||||
| // nolint:cyclop | ||||
| func (b *Bmattermost) handleMatterClient6(messages chan *config.Message) { | ||||
| 	for message := range b.mc6.MessageChan { | ||||
| 		b.Log.Debugf("%#v", message.Raw.GetData()) | ||||
| 		b.Log.Debugf("%#v %#v", message.Raw.GetData(), message.Raw.EventType()) | ||||
|  | ||||
| 		if b.skipMessage6(message) { | ||||
| 			b.Log.Debugf("Skipped message: %#v", message) | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		channelName := b.getChannelName(message.Post.ChannelId) | ||||
| 		if channelName == "" { | ||||
| 			channelName = message.Channel | ||||
| 		} | ||||
|  | ||||
| 		// only download avatars if we have a place to upload them (configured mediaserver) | ||||
| 		if b.General.MediaServerUpload != "" || b.General.MediaDownloadPath != "" { | ||||
| 			b.handleDownloadAvatar(message.UserID, message.Channel) | ||||
| 			b.handleDownloadAvatar(message.UserID, channelName) | ||||
| 		} | ||||
|  | ||||
| 		b.Log.Debugf("== Receiving event %#v", message) | ||||
| @@ -205,7 +217,7 @@ func (b *Bmattermost) handleMatterClient6(messages chan *config.Message) { | ||||
| 		rmsg := &config.Message{ | ||||
| 			Username: message.Username, | ||||
| 			UserID:   message.UserID, | ||||
| 			Channel:  message.Channel, | ||||
| 			Channel:  channelName, | ||||
| 			Text:     message.Text, | ||||
| 			ID:       message.Post.Id, | ||||
| 			ParentID: message.Post.RootId, // ParentID is obsolete with mattermost | ||||
| @@ -232,8 +244,10 @@ func (b *Bmattermost) handleMatterClient6(messages chan *config.Message) { | ||||
| 		} | ||||
|  | ||||
| 		// Use nickname instead of username if defined | ||||
| 		if nick := b.mc6.GetNickName(rmsg.UserID); nick != "" { | ||||
| 			rmsg.Username = nick | ||||
| 		if !b.GetBool("useusername") { | ||||
| 			if nick := b.mc6.GetNickName(rmsg.UserID); nick != "" { | ||||
| 				rmsg.Username = nick | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		messages <- rmsg | ||||
| @@ -244,6 +258,7 @@ func (b *Bmattermost) handleMatterHook(messages chan *config.Message) { | ||||
| 	for { | ||||
| 		message := b.mh.Receive() | ||||
| 		b.Log.Debugf("Receiving from matterhook %#v", message) | ||||
|  | ||||
| 		messages <- &config.Message{ | ||||
| 			UserID:   message.UserID, | ||||
| 			Username: message.UserName, | ||||
| @@ -261,7 +276,7 @@ func (b *Bmattermost) handleUploadFile(msg *config.Message) (string, error) { | ||||
|  | ||||
| 	var err error | ||||
| 	var res, id string | ||||
| 	channelID := b.mc.GetChannelId(msg.Channel, b.TeamID) | ||||
| 	channelID := b.getChannelID(msg.Channel) | ||||
| 	for _, f := range msg.Extra["file"] { | ||||
| 		fi := f.(config.FileInfo) | ||||
| 		id, err = b.mc.UploadFile(*fi.Data, channelID, fi.Name) | ||||
| @@ -281,7 +296,7 @@ func (b *Bmattermost) handleUploadFile(msg *config.Message) (string, error) { | ||||
| func (b *Bmattermost) handleUploadFile6(msg *config.Message) (string, error) { | ||||
| 	var err error | ||||
| 	var res, id string | ||||
| 	channelID := b.mc6.GetChannelID(msg.Channel, b.TeamID) | ||||
| 	channelID := b.getChannelID(msg.Channel) | ||||
| 	for _, f := range msg.Extra["file"] { | ||||
| 		fi := f.(config.FileInfo) | ||||
| 		id, err = b.mc6.UploadFile(*fi.Data, channelID, fi.Name) | ||||
|   | ||||
| @@ -241,11 +241,17 @@ func (b *Bmattermost) skipMessage(message *matterclient.Message) bool { | ||||
| 		if b.GetBool("nosendjoinpart") { | ||||
| 			return true | ||||
| 		} | ||||
|  | ||||
| 		channelName := b.getChannelName(message.Post.ChannelId) | ||||
| 		if channelName == "" { | ||||
| 			channelName = message.Channel | ||||
| 		} | ||||
|  | ||||
| 		b.Log.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account) | ||||
| 		b.Remote <- config.Message{ | ||||
| 			Username: "system", | ||||
| 			Text:     message.Text, | ||||
| 			Channel:  message.Channel, | ||||
| 			Channel:  channelName, | ||||
| 			Account:  b.Account, | ||||
| 			Event:    config.EventJoinLeave, | ||||
| 		} | ||||
| @@ -304,11 +310,17 @@ func (b *Bmattermost) skipMessage6(message *matterclient6.Message) bool { | ||||
| 		if b.GetBool("nosendjoinpart") { | ||||
| 			return true | ||||
| 		} | ||||
|  | ||||
| 		channelName := b.getChannelName(message.Post.ChannelId) | ||||
| 		if channelName == "" { | ||||
| 			channelName = message.Channel | ||||
| 		} | ||||
|  | ||||
| 		b.Log.Debugf("Sending JOIN_LEAVE event from %s to gateway", b.Account) | ||||
| 		b.Remote <- config.Message{ | ||||
| 			Username: "system", | ||||
| 			Text:     message.Text, | ||||
| 			Channel:  message.Channel, | ||||
| 			Channel:  channelName, | ||||
| 			Account:  b.Account, | ||||
| 			Event:    config.EventJoinLeave, | ||||
| 		} | ||||
| @@ -329,13 +341,14 @@ func (b *Bmattermost) skipMessage6(message *matterclient6.Message) bool { | ||||
| 	// Ignore messages sent from matterbridge | ||||
| 	if message.Post.Props != nil { | ||||
| 		if _, ok := message.Post.Props["matterbridge_"+b.uuid].(bool); ok { | ||||
| 			b.Log.Debugf("sent by matterbridge, ignoring") | ||||
| 			b.Log.Debug("sent by matterbridge, ignoring") | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Ignore messages sent from a user logged in as the bot | ||||
| 	if b.mc6.User.Username == message.Username { | ||||
| 		b.Log.Debug("message from same user as bot, ignoring") | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| @@ -346,6 +359,7 @@ func (b *Bmattermost) skipMessage6(message *matterclient6.Message) bool { | ||||
|  | ||||
| 	// ignore messages from other teams than ours | ||||
| 	if message.Raw.GetData()["team_id"].(string) != b.TeamID { | ||||
| 		b.Log.Debug("message from other team, ignoring") | ||||
| 		return true | ||||
| 	} | ||||
|  | ||||
| @@ -374,3 +388,30 @@ func (b *Bmattermost) getVersion() string { | ||||
|  | ||||
| 	return resp.Header.Get("X-Version-Id") | ||||
| } | ||||
|  | ||||
| func (b *Bmattermost) getChannelID(name string) string { | ||||
| 	idcheck := strings.Split(name, "ID:") | ||||
| 	if len(idcheck) > 1 { | ||||
| 		return idcheck[1] | ||||
| 	} | ||||
|  | ||||
| 	if b.mc6 != nil { | ||||
| 		return b.mc6.GetChannelID(name, b.TeamID) | ||||
| 	} | ||||
|  | ||||
| 	return b.mc.GetChannelId(name, b.TeamID) | ||||
| } | ||||
|  | ||||
| func (b *Bmattermost) getChannelName(id string) string { | ||||
| 	b.channelsMutex.RLock() | ||||
| 	defer b.channelsMutex.RUnlock() | ||||
|  | ||||
| 	for _, c := range b.channelInfoMap { | ||||
| 		if c.Name == "ID:"+id { | ||||
| 			// if we have ID: specified in our gateway configuration return this | ||||
| 			return c.Name | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return "" | ||||
| } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| @@ -22,13 +23,19 @@ type Bmattermost struct { | ||||
| 	uuid   string | ||||
| 	TeamID string | ||||
| 	*bridge.Config | ||||
| 	avatarMap map[string]string | ||||
| 	avatarMap      map[string]string | ||||
| 	channelsMutex  sync.RWMutex | ||||
| 	channelInfoMap map[string]*config.ChannelInfo | ||||
| } | ||||
|  | ||||
| const mattermostPlugin = "mattermost.plugin" | ||||
|  | ||||
| func New(cfg *bridge.Config) bridge.Bridger { | ||||
| 	b := &Bmattermost{Config: cfg, avatarMap: make(map[string]string)} | ||||
| 	b := &Bmattermost{ | ||||
| 		Config:         cfg, | ||||
| 		avatarMap:      make(map[string]string), | ||||
| 		channelInfoMap: make(map[string]*config.ChannelInfo), | ||||
| 	} | ||||
|  | ||||
| 	b.v6 = b.GetBool("v6") | ||||
| 	b.uuid = xid.New().String() | ||||
| @@ -113,14 +120,14 @@ func (b *Bmattermost) JoinChannel(channel config.ChannelInfo) error { | ||||
| 	if b.Account == mattermostPlugin { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	b.channelsMutex.Lock() | ||||
| 	b.channelInfoMap[channel.ID] = &channel | ||||
| 	b.channelsMutex.Unlock() | ||||
|  | ||||
| 	// we can only join channels using the API | ||||
| 	if b.GetString("WebhookURL") == "" && b.GetString("WebhookBindAddress") == "" { | ||||
| 		var id string | ||||
| 		if b.mc6 != nil { | ||||
| 			id = b.mc6.GetChannelID(channel.Name, b.TeamID) | ||||
| 		} else { | ||||
| 			id = b.mc.GetChannelId(channel.Name, b.TeamID) | ||||
| 		} | ||||
| 		id := b.getChannelID(channel.Name) | ||||
| 		if id == "" { | ||||
| 			return fmt.Errorf("Could not find channel ID for channel %s", channel.Name) | ||||
| 		} | ||||
| @@ -131,6 +138,7 @@ func (b *Bmattermost) JoinChannel(channel config.ChannelInfo) error { | ||||
|  | ||||
| 		return b.mc.JoinChannel(id) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| @@ -180,13 +188,17 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) { | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("getting post %s failed: %s", msg.ParentID, err) | ||||
| 			} | ||||
| 			msg.ParentID = post.RootId | ||||
| 			if post.RootId != "" { | ||||
| 				msg.ParentID = post.RootId | ||||
| 			} | ||||
| 		} else { | ||||
| 			post, res := b.mc.Client.GetPost(msg.ParentID, "") | ||||
| 			if res.Error != nil { | ||||
| 				b.Log.Errorf("getting post %s failed: %s", msg.ParentID, res.Error.DetailedError) | ||||
| 			} | ||||
| 			msg.ParentID = post.RootId | ||||
| 			if post.RootId != "" { | ||||
| 				msg.ParentID = post.RootId | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| @@ -194,11 +206,11 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) { | ||||
| 	if msg.Extra != nil { | ||||
| 		for _, rmsg := range helper.HandleExtra(&msg, b.General) { | ||||
| 			if b.mc6 != nil { | ||||
| 				if _, err := b.mc6.PostMessage(b.mc.GetChannelId(rmsg.Channel, b.TeamID), rmsg.Username+rmsg.Text, msg.ParentID); err != nil { | ||||
| 				if _, err := b.mc6.PostMessage(b.getChannelID(rmsg.Channel), rmsg.Username+rmsg.Text, msg.ParentID); err != nil { | ||||
| 					b.Log.Errorf("PostMessage failed: %s", err) | ||||
| 				} | ||||
| 			} else { | ||||
| 				if _, err := b.mc.PostMessage(b.mc.GetChannelId(rmsg.Channel, b.TeamID), rmsg.Username+rmsg.Text, msg.ParentID); err != nil { | ||||
| 				if _, err := b.mc.PostMessage(b.getChannelID(rmsg.Channel), rmsg.Username+rmsg.Text, msg.ParentID); err != nil { | ||||
| 					b.Log.Errorf("PostMessage failed: %s", err) | ||||
| 				} | ||||
| 			} | ||||
| @@ -224,8 +236,8 @@ func (b *Bmattermost) Send(msg config.Message) (string, error) { | ||||
|  | ||||
| 	// Post normal message | ||||
| 	if b.mc6 != nil { | ||||
| 		return b.mc6.PostMessage(b.mc6.GetChannelID(msg.Channel, b.TeamID), msg.Text, msg.ParentID) // nolint:wrapcheck | ||||
| 		return b.mc6.PostMessage(b.getChannelID(msg.Channel), msg.Text, msg.ParentID) // nolint:wrapcheck | ||||
| 	} | ||||
|  | ||||
| 	return b.mc.PostMessage(b.mc.GetChannelId(msg.Channel, b.TeamID), msg.Text, msg.ParentID) | ||||
| 	return b.mc.PostMessage(b.getChannelID(msg.Channel), msg.Text, msg.ParentID) | ||||
| } | ||||
|   | ||||
| @@ -19,8 +19,10 @@ import ( | ||||
| 	"golang.org/x/oauth2" | ||||
| ) | ||||
|  | ||||
| var defaultScopes = []string{"openid", "profile", "offline_access", "Group.Read.All", "Group.ReadWrite.All"} | ||||
| var attachRE = regexp.MustCompile(`<attachment id=.*?attachment>`) | ||||
| var ( | ||||
| 	defaultScopes = []string{"openid", "profile", "offline_access", "Group.Read.All", "Group.ReadWrite.All"} | ||||
| 	attachRE      = regexp.MustCompile(`<attachment id=.*?attachment>`) | ||||
| ) | ||||
|  | ||||
| type Bmsteams struct { | ||||
| 	gc    *msgraph.GraphServiceRequestBuilder | ||||
| @@ -50,7 +52,7 @@ func (b *Bmsteams) Connect() error { | ||||
| 		b.Log.Errorf("Couldn't save sessionfile in %s: %s", tokenCachePath, err) | ||||
| 	} | ||||
| 	// make file readable only for matterbridge user | ||||
| 	err = os.Chmod(tokenCachePath, 0600) | ||||
| 	err = os.Chmod(tokenCachePath, 0o600) | ||||
| 	if err != nil { | ||||
| 		b.Log.Errorf("Couldn't change permissions for %s: %s", tokenCachePath, err) | ||||
| 	} | ||||
| @@ -168,7 +170,7 @@ func (b *Bmsteams) poll(channelName string) error { | ||||
| 			} | ||||
|  | ||||
| 			// skip non-user message for now. | ||||
| 			if msg.From.User == nil { | ||||
| 			if msg.From == nil || msg.From.User == nil { | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
|   | ||||
| @@ -27,7 +27,8 @@ func (b *Bslack) handleSlack() { | ||||
| 	b.Log.Debug("Start listening for Slack messages") | ||||
| 	for message := range messages { | ||||
| 		// don't do any action on deleted/typing messages | ||||
| 		if message.Event != config.EventUserTyping && message.Event != config.EventMsgDelete { | ||||
| 		if message.Event != config.EventUserTyping && message.Event != config.EventMsgDelete && | ||||
| 			message.Event != config.EventFileDelete { | ||||
| 			b.Log.Debugf("<= Sending message from %s on %s to gateway", message.Username, b.Account) | ||||
| 			// cleanup the message | ||||
| 			message.Text = b.replaceMention(message.Text) | ||||
| @@ -76,6 +77,13 @@ func (b *Bslack) handleSlackClient(messages chan *config.Message) { | ||||
| 				continue | ||||
| 			} | ||||
| 			messages <- rmsg | ||||
| 		case *slack.FileDeletedEvent: | ||||
| 			rmsg, err := b.handleFileDeletedEvent(ev) | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("%#v", err) | ||||
| 				continue | ||||
| 			} | ||||
| 			messages <- rmsg | ||||
| 		case *slack.OutgoingErrorEvent: | ||||
| 			b.Log.Debugf("%#v", ev.Error()) | ||||
| 		case *slack.ChannelJoinedEvent: | ||||
| @@ -222,6 +230,26 @@ func (b *Bslack) handleMessageEvent(ev *slack.MessageEvent) (*config.Message, er | ||||
| 	return rmsg, nil | ||||
| } | ||||
|  | ||||
| func (b *Bslack) handleFileDeletedEvent(ev *slack.FileDeletedEvent) (*config.Message, error) { | ||||
| 	if rawChannel, ok := b.cache.Get(cfileDownloadChannel + ev.FileID); ok { | ||||
| 		channel, err := b.channels.getChannelByID(rawChannel.(string)) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
|  | ||||
| 		return &config.Message{ | ||||
| 			Event:    config.EventFileDelete, | ||||
| 			Text:     config.EventFileDelete, | ||||
| 			Channel:  channel.Name, | ||||
| 			Account:  b.Account, | ||||
| 			ID:       ev.FileID, | ||||
| 			Protocol: b.Protocol, | ||||
| 		}, nil | ||||
| 	} | ||||
|  | ||||
| 	return nil, fmt.Errorf("channel ID for file ID %s not found", ev.FileID) | ||||
| } | ||||
|  | ||||
| func (b *Bslack) handleStatusEvent(ev *slack.MessageEvent, rmsg *config.Message) bool { | ||||
| 	switch ev.SubType { | ||||
| 	case sChannelJoined, sMemberJoined: | ||||
| @@ -281,6 +309,8 @@ func (b *Bslack) handleAttachments(ev *slack.MessageEvent, rmsg *config.Message) | ||||
|  | ||||
| 	// If we have files attached, download them (in memory) and put a pointer to it in msg.Extra. | ||||
| 	for i := range ev.Files { | ||||
| 		// keep reference in cache on which channel we added this file | ||||
| 		b.cache.Add(cfileDownloadChannel+ev.Files[i].ID, ev.Channel) | ||||
| 		if err := b.handleDownloadFile(rmsg, &ev.Files[i], false); err != nil { | ||||
| 			b.Log.Errorf("Could not download incoming file: %#v", err) | ||||
| 		} | ||||
| @@ -330,7 +360,7 @@ func (b *Bslack) handleDownloadFile(rmsg *config.Message, file *slack.File, retr | ||||
| 	// that the comment is not duplicated. | ||||
| 	comment := rmsg.Text | ||||
| 	rmsg.Text = "" | ||||
| 	helper.HandleDownloadData(b.Log, rmsg, file.Name, comment, file.URLPrivateDownload, data, b.General) | ||||
| 	helper.HandleDownloadData2(b.Log, rmsg, file.Name, file.ID, comment, file.URLPrivateDownload, data, b.General) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -36,24 +36,25 @@ type Bslack struct { | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	sHello           = "hello" | ||||
| 	sChannelJoin     = "channel_join" | ||||
| 	sChannelLeave    = "channel_leave" | ||||
| 	sChannelJoined   = "channel_joined" | ||||
| 	sMemberJoined    = "member_joined_channel" | ||||
| 	sMessageChanged  = "message_changed" | ||||
| 	sMessageDeleted  = "message_deleted" | ||||
| 	sSlackAttachment = "slack_attachment" | ||||
| 	sPinnedItem      = "pinned_item" | ||||
| 	sUnpinnedItem    = "unpinned_item" | ||||
| 	sChannelTopic    = "channel_topic" | ||||
| 	sChannelPurpose  = "channel_purpose" | ||||
| 	sFileComment     = "file_comment" | ||||
| 	sMeMessage       = "me_message" | ||||
| 	sUserTyping      = "user_typing" | ||||
| 	sLatencyReport   = "latency_report" | ||||
| 	sSystemUser      = "system" | ||||
| 	sSlackBotUser    = "slackbot" | ||||
| 	sHello               = "hello" | ||||
| 	sChannelJoin         = "channel_join" | ||||
| 	sChannelLeave        = "channel_leave" | ||||
| 	sChannelJoined       = "channel_joined" | ||||
| 	sMemberJoined        = "member_joined_channel" | ||||
| 	sMessageChanged      = "message_changed" | ||||
| 	sMessageDeleted      = "message_deleted" | ||||
| 	sSlackAttachment     = "slack_attachment" | ||||
| 	sPinnedItem          = "pinned_item" | ||||
| 	sUnpinnedItem        = "unpinned_item" | ||||
| 	sChannelTopic        = "channel_topic" | ||||
| 	sChannelPurpose      = "channel_purpose" | ||||
| 	sFileComment         = "file_comment" | ||||
| 	sMeMessage           = "me_message" | ||||
| 	sUserTyping          = "user_typing" | ||||
| 	sLatencyReport       = "latency_report" | ||||
| 	sSystemUser          = "system" | ||||
| 	sSlackBotUser        = "slackbot" | ||||
| 	cfileDownloadChannel = "file_download_channel" | ||||
|  | ||||
| 	tokenConfig           = "Token" | ||||
| 	incomingWebhookConfig = "WebhookBindAddress" | ||||
|   | ||||
| @@ -291,6 +291,7 @@ func (b *channels) populateChannels(wait bool) { | ||||
| 	queryParams := &slack.GetConversationsParameters{ | ||||
| 		ExcludeArchived: true, | ||||
| 		Types:           []string{"public_channel,private_channel"}, | ||||
| 		Limit:           1000, | ||||
| 	} | ||||
| 	for { | ||||
| 		channels, nextCursor, err := b.sc.GetConversations(queryParams) | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package btelegram | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"html" | ||||
| 	"path/filepath" | ||||
| 	"strconv" | ||||
| @@ -9,14 +10,27 @@ import ( | ||||
|  | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api" | ||||
| 	"github.com/davecgh/go-spew/spew" | ||||
| 	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" | ||||
| ) | ||||
|  | ||||
| func (b *Btelegram) handleUpdate(rmsg *config.Message, message, posted, edited *tgbotapi.Message) *tgbotapi.Message { | ||||
| 	// handle channels | ||||
| 	if posted != nil { | ||||
| 		message = posted | ||||
| 		rmsg.Text = message.Text | ||||
| 		if posted.Text == "/chatId" { | ||||
| 			chatID := strconv.FormatInt(posted.Chat.ID, 10) | ||||
|  | ||||
| 			_, err := b.Send(config.Message{ | ||||
| 				Channel: chatID, | ||||
| 				Text:    fmt.Sprintf("ID of this chat: %s", chatID), | ||||
| 			}) | ||||
| 			if err != nil { | ||||
| 				b.Log.Warnf("Unable to send chatID to %s", chatID) | ||||
| 			} | ||||
| 		} else { | ||||
| 			message = posted | ||||
| 			rmsg.Text = message.Text | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// edited channel message | ||||
| @@ -94,7 +108,7 @@ func (b *Btelegram) handleQuoting(rmsg *config.Message, message *tgbotapi.Messag | ||||
| // handleUsername handles the correct setting of the username | ||||
| func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Message) { | ||||
| 	if message.From != nil { | ||||
| 		rmsg.UserID = strconv.Itoa(message.From.ID) | ||||
| 		rmsg.UserID = strconv.FormatInt(message.From.ID, 10) | ||||
| 		if b.GetBool("UseFirstName") { | ||||
| 			rmsg.Username = message.From.FirstName | ||||
| 		} | ||||
| @@ -110,6 +124,25 @@ func (b *Btelegram) handleUsername(rmsg *config.Message, message *tgbotapi.Messa | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if message.SenderChat != nil { //nolint:nestif | ||||
| 		rmsg.UserID = strconv.FormatInt(message.SenderChat.ID, 10) | ||||
| 		if b.GetBool("UseFirstName") { | ||||
| 			rmsg.Username = message.SenderChat.FirstName | ||||
| 		} | ||||
|  | ||||
| 		if rmsg.Username == "" || rmsg.Username == "Channel_Bot" { | ||||
| 			rmsg.Username = message.SenderChat.UserName | ||||
|  | ||||
| 			if rmsg.Username == "" || rmsg.Username == "Channel_Bot" { | ||||
| 				rmsg.Username = message.SenderChat.FirstName | ||||
| 			} | ||||
| 		} | ||||
| 		// only download avatars if we have a place to upload them (configured mediaserver) | ||||
| 		if b.General.MediaServerUpload != "" || (b.General.MediaServerDownload != "" && b.General.MediaDownloadPath != "") { | ||||
| 			b.handleDownloadAvatar(message.SenderChat.ID, rmsg.Channel) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// if we really didn't find a username, set it to unknown | ||||
| 	if rmsg.Username == "" { | ||||
| 		rmsg.Username = unknownUser | ||||
| @@ -126,6 +159,10 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if b.GetInt("debuglevel") == 1 { | ||||
| 			spew.Dump(update.Message) | ||||
| 		} | ||||
|  | ||||
| 		var message *tgbotapi.Message | ||||
|  | ||||
| 		rmsg := config.Message{Account: b.Account, Extra: make(map[string][]interface{})} | ||||
| @@ -167,7 +204,7 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | ||||
| 			rmsg.Text = helper.RemoveEmptyNewLines(rmsg.Text) | ||||
| 			// channels don't have (always?) user information. see #410 | ||||
| 			if message.From != nil { | ||||
| 				rmsg.Avatar = helper.GetAvatar(b.avatarMap, strconv.Itoa(message.From.ID), b.General) | ||||
| 				rmsg.Avatar = helper.GetAvatar(b.avatarMap, strconv.FormatInt(message.From.ID, 10), b.General) | ||||
| 			} | ||||
|  | ||||
| 			b.Log.Debugf("<= Sending message from %s on %s to gateway", rmsg.Username, b.Account) | ||||
| @@ -180,42 +217,44 @@ func (b *Btelegram) handleRecv(updates <-chan tgbotapi.Update) { | ||||
| // handleDownloadAvatar downloads the avatar of userid from channel | ||||
| // sends a EVENT_AVATAR_DOWNLOAD message to the gateway if successful. | ||||
| // logs an error message if it fails | ||||
| func (b *Btelegram) handleDownloadAvatar(userid int, channel string) { | ||||
| func (b *Btelegram) handleDownloadAvatar(userid int64, channel string) { | ||||
| 	rmsg := config.Message{ | ||||
| 		Username: "system", | ||||
| 		Text:     "avatar", | ||||
| 		Channel:  channel, | ||||
| 		Account:  b.Account, | ||||
| 		UserID:   strconv.Itoa(userid), | ||||
| 		UserID:   strconv.FormatInt(userid, 10), | ||||
| 		Event:    config.EventAvatarDownload, | ||||
| 		Extra:    make(map[string][]interface{}), | ||||
| 	} | ||||
|  | ||||
| 	if _, ok := b.avatarMap[strconv.Itoa(userid)]; !ok { | ||||
| 		photos, err := b.c.GetUserProfilePhotos(tgbotapi.UserProfilePhotosConfig{UserID: userid, Limit: 1}) | ||||
| 	if _, ok := b.avatarMap[strconv.FormatInt(userid, 10)]; ok { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	photos, err := b.c.GetUserProfilePhotos(tgbotapi.UserProfilePhotosConfig{UserID: userid, Limit: 1}) | ||||
| 	if err != nil { | ||||
| 		b.Log.Errorf("Userprofile download failed for %#v %s", userid, err) | ||||
| 	} | ||||
|  | ||||
| 	if len(photos.Photos) > 0 { | ||||
| 		photo := photos.Photos[0][0] | ||||
| 		url := b.getFileDirectURL(photo.FileID) | ||||
| 		name := strconv.FormatInt(userid, 10) + ".png" | ||||
| 		b.Log.Debugf("trying to download %#v fileid %#v with size %#v", name, photo.FileID, photo.FileSize) | ||||
|  | ||||
| 		err := helper.HandleDownloadSize(b.Log, &rmsg, name, int64(photo.FileSize), b.General) | ||||
| 		if err != nil { | ||||
| 			b.Log.Errorf("Userprofile download failed for %#v %s", userid, err) | ||||
| 			b.Log.Error(err) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		if len(photos.Photos) > 0 { | ||||
| 			photo := photos.Photos[0][0] | ||||
| 			url := b.getFileDirectURL(photo.FileID) | ||||
| 			name := strconv.Itoa(userid) + ".png" | ||||
| 			b.Log.Debugf("trying to download %#v fileid %#v with size %#v", name, photo.FileID, photo.FileSize) | ||||
|  | ||||
| 			err := helper.HandleDownloadSize(b.Log, &rmsg, name, int64(photo.FileSize), b.General) | ||||
| 			if err != nil { | ||||
| 				b.Log.Error(err) | ||||
| 				return | ||||
| 			} | ||||
| 			data, err := helper.DownloadFile(url) | ||||
| 			if err != nil { | ||||
| 				b.Log.Errorf("download %s failed %#v", url, err) | ||||
| 				return | ||||
| 			} | ||||
| 			helper.HandleDownloadData(b.Log, &rmsg, name, rmsg.Text, "", data, b.General) | ||||
| 			b.Remote <- rmsg | ||||
| 		data, err := helper.DownloadFile(url) | ||||
| 		if err != nil { | ||||
| 			b.Log.Errorf("download %s failed %#v", url, err) | ||||
| 			return | ||||
| 		} | ||||
| 		helper.HandleDownloadData(b.Log, &rmsg, name, rmsg.Text, "", data, b.General) | ||||
| 		b.Remote <- rmsg | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -272,7 +311,7 @@ func (b *Btelegram) handleDownload(rmsg *config.Message, message *tgbotapi.Messa | ||||
| 		name = message.Document.FileName | ||||
| 		text = " " + message.Document.FileName + " : " + url | ||||
| 	case message.Photo != nil: | ||||
| 		photos := *message.Photo | ||||
| 		photos := message.Photo | ||||
| 		size = photos[len(photos)-1].FileSize | ||||
| 		text, name, url = b.getDownloadInfo(photos[len(photos)-1].FileID, "", true) | ||||
| 	} | ||||
| @@ -331,11 +370,15 @@ func (b *Btelegram) handleDelete(msg *config.Message, chatid int64) (string, err | ||||
| 	if msg.ID == "" { | ||||
| 		return "", nil | ||||
| 	} | ||||
|  | ||||
| 	msgid, err := strconv.Atoi(msg.ID) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	_, err = b.c.DeleteMessage(tgbotapi.DeleteMessageConfig{ChatID: chatid, MessageID: msgid}) | ||||
|  | ||||
| 	cfg := tgbotapi.NewDeleteMessage(chatid, msgid) | ||||
| 	_, err = b.c.Send(cfg) | ||||
|  | ||||
| 	return "", err | ||||
| } | ||||
|  | ||||
| @@ -383,23 +426,23 @@ func (b *Btelegram) handleUploadFile(msg *config.Message, chatid int64) string { | ||||
| 		} | ||||
| 		switch filepath.Ext(fi.Name) { | ||||
| 		case ".jpg", ".jpe", ".png": | ||||
| 			pc := tgbotapi.NewPhotoUpload(chatid, file) | ||||
| 			pc := tgbotapi.NewPhoto(chatid, file) | ||||
| 			pc.Caption, pc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | ||||
| 			c = pc | ||||
| 		case ".mp4", ".m4v": | ||||
| 			vc := tgbotapi.NewVideoUpload(chatid, file) | ||||
| 			vc := tgbotapi.NewVideo(chatid, file) | ||||
| 			vc.Caption, vc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | ||||
| 			c = vc | ||||
| 		case ".mp3", ".oga": | ||||
| 			ac := tgbotapi.NewAudioUpload(chatid, file) | ||||
| 			ac := tgbotapi.NewAudio(chatid, file) | ||||
| 			ac.Caption, ac.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | ||||
| 			c = ac | ||||
| 		case ".ogg": | ||||
| 			voc := tgbotapi.NewVoiceUpload(chatid, file) | ||||
| 			voc := tgbotapi.NewVoice(chatid, file) | ||||
| 			voc.Caption, voc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | ||||
| 			c = voc | ||||
| 		default: | ||||
| 			dc := tgbotapi.NewDocumentUpload(chatid, file) | ||||
| 			dc := tgbotapi.NewDocument(chatid, file) | ||||
| 			dc.Caption, dc.ParseMode = TGGetParseMode(b, msg.Username, fi.Comment) | ||||
| 			c = dc | ||||
| 		} | ||||
| @@ -435,8 +478,11 @@ func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Messa | ||||
| 	if message.Entities == nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	indexMovedBy := 0 | ||||
|  | ||||
| 	// for now only do URL replacements | ||||
| 	for _, e := range *message.Entities { | ||||
| 	for _, e := range message.Entities { | ||||
| 		if e.Type == "text_link" { | ||||
| 			url, err := e.ParseURL() | ||||
| 			if err != nil { | ||||
| @@ -451,5 +497,17 @@ func (b *Btelegram) handleEntities(rmsg *config.Message, message *tgbotapi.Messa | ||||
| 			link := utf16.Decode(utfEncodedString[e.Offset : e.Offset+e.Length]) | ||||
| 			rmsg.Text = strings.Replace(rmsg.Text, string(link), url.String(), 1) | ||||
| 		} | ||||
|  | ||||
| 		if e.Type == "code" { | ||||
| 			offset := e.Offset + indexMovedBy | ||||
| 			rmsg.Text = rmsg.Text[:offset] + "`" + rmsg.Text[offset:offset+e.Length] + "`" + rmsg.Text[offset+e.Length:] | ||||
| 			indexMovedBy += 2 | ||||
| 		} | ||||
|  | ||||
| 		if e.Type == "pre" { | ||||
| 			offset := e.Offset + indexMovedBy | ||||
| 			rmsg.Text = rmsg.Text[:offset] + "```\n" + rmsg.Text[offset:offset+e.Length] + "\n```" + rmsg.Text[offset+e.Length:] | ||||
| 			indexMovedBy += 8 | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import ( | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api" | ||||
| 	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| @@ -49,11 +49,7 @@ func (b *Btelegram) Connect() error { | ||||
| 	} | ||||
| 	u := tgbotapi.NewUpdate(0) | ||||
| 	u.Timeout = 60 | ||||
| 	updates, err := b.c.GetUpdatesChan(u) | ||||
| 	if err != nil { | ||||
| 		b.Log.Debugf("%#v", err) | ||||
| 		return err | ||||
| 	} | ||||
| 	updates := b.c.GetUpdatesChan(u) | ||||
| 	b.Log.Info("Connection succeeded") | ||||
| 	go b.handleRecv(updates) | ||||
| 	return nil | ||||
|   | ||||
| @@ -34,6 +34,7 @@ type user struct { | ||||
|  | ||||
| type Bvk struct { | ||||
| 	c            *api.VK | ||||
| 	lp           *longpoll.LongPoll | ||||
| 	usernamesMap map[int]user // cache of user names and avatar URLs | ||||
| 	*bridge.Config | ||||
| } | ||||
| @@ -45,21 +46,23 @@ func New(cfg *bridge.Config) bridge.Bridger { | ||||
| func (b *Bvk) Connect() error { | ||||
| 	b.Log.Info("Connecting") | ||||
| 	b.c = api.NewVK(b.GetString("Token")) | ||||
| 	lp, err := longpoll.NewLongPoll(b.c, b.GetInt("GroupID")) | ||||
|  | ||||
| 	var err error | ||||
| 	b.lp, err = longpoll.NewLongPollCommunity(b.c) | ||||
| 	if err != nil { | ||||
| 		b.Log.Debugf("%#v", err) | ||||
|  | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	lp.MessageNew(func(ctx context.Context, obj events.MessageNewObject) { | ||||
| 	b.lp.MessageNew(func(ctx context.Context, obj events.MessageNewObject) { | ||||
| 		b.handleMessage(obj.Message, false) | ||||
| 	}) | ||||
|  | ||||
| 	b.Log.Info("Connection succeeded") | ||||
|  | ||||
| 	go func() { | ||||
| 		err := lp.Run() | ||||
| 		err := b.lp.Run() | ||||
| 		if err != nil { | ||||
| 			b.Log.Fatal("Enable longpoll in group management") | ||||
| 		} | ||||
| @@ -69,6 +72,8 @@ func (b *Bvk) Connect() error { | ||||
| } | ||||
|  | ||||
| func (b *Bvk) Disconnect() error { | ||||
| 	b.lp.Shutdown() | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -293,7 +293,11 @@ func (b *Bwhatsapp) Send(msg config.Message) (string, error) { | ||||
| 	if msg.ID != "" { | ||||
| 		b.Log.Debugf("updating message with id %s", msg.ID) | ||||
|  | ||||
| 		msg.Text += " (edited)" | ||||
| 		if b.GetString("editsuffix") != "" { | ||||
| 			msg.Text += b.GetString("EditSuffix") | ||||
| 		} else { | ||||
| 			msg.Text += " (edited)" | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Handle Upload a file | ||||
|   | ||||
| @@ -128,7 +128,6 @@ func (b *Bxmpp) Send(msg config.Message) (string, error) { | ||||
| 	var msgReplaceID string | ||||
| 	msgID := xid.New().String() | ||||
| 	if msg.ID != "" { | ||||
| 		msgID = msg.ID | ||||
| 		msgReplaceID = msg.ID | ||||
| 	} | ||||
| 	b.Log.Debugf("=> Sending message %#v", msg) | ||||
| @@ -284,7 +283,13 @@ func (b *Bxmpp) handleXMPP() error { | ||||
| 	for { | ||||
| 		m, err := b.xc.Recv() | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 			// An error together with AvatarData is non-fatal | ||||
| 			switch m.(type) { | ||||
| 			case xmpp.AvatarData: | ||||
| 				continue | ||||
| 			default: | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		switch v := m.(type) { | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package bzulip | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io/ioutil" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| @@ -11,6 +12,7 @@ import ( | ||||
| 	"github.com/42wim/matterbridge/bridge" | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/bridge/helper" | ||||
| 	"github.com/42wim/matterbridge/version" | ||||
| 	gzb "github.com/matterbridge/gozulipbot" | ||||
| ) | ||||
|  | ||||
| @@ -27,7 +29,7 @@ func New(cfg *bridge.Config) bridge.Bridger { | ||||
| } | ||||
|  | ||||
| func (b *Bzulip) Connect() error { | ||||
| 	bot := gzb.Bot{APIKey: b.GetString("token"), APIURL: b.GetString("server") + "/api/v1/", Email: b.GetString("login")} | ||||
| 	bot := gzb.Bot{APIKey: b.GetString("token"), APIURL: b.GetString("server") + "/api/v1/", Email: b.GetString("login"), UserAgent: fmt.Sprintf("matterbridge/%s", version.Release)} | ||||
| 	bot.Init() | ||||
| 	q, err := bot.RegisterAll() | ||||
| 	b.q = q | ||||
| @@ -125,6 +127,7 @@ func (b *Bzulip) handleQueue() error { | ||||
| 			b.Log.Debug("heartbeat received.") | ||||
| 		default: | ||||
| 			b.Log.Debugf("receiving error: %#v", err) | ||||
| 			time.Sleep(time.Second * 10) | ||||
| 		} | ||||
| 		if err != nil { | ||||
| 			continue | ||||
|   | ||||
							
								
								
									
										56
									
								
								changelog.md
									
									
									
									
									
								
							
							
						
						
									
										56
									
								
								changelog.md
									
									
									
									
									
								
							| @@ -1,3 +1,57 @@ | ||||
| # v1.24.0 | ||||
|  | ||||
| ## New features | ||||
|  | ||||
| - harmony: new protocol added: Add support for Harmony (#1656) | ||||
| - irc: Allow binding to IP on IRC (#1640) | ||||
| - irc: Add support for client certificate (irc) (#1710) | ||||
| - mattermost: Add UseUsername option (mattermost). Fixes #1665 (#1714) | ||||
| - mattermost: Add support for using ID in channel config (mattermost) (#1715) | ||||
| - matrix: Reply support for Matrix (#1664) | ||||
| - telegram: Add Telegram Bot Command /chatId (telegram) (#1703) | ||||
|  | ||||
| ## Enhancements | ||||
|  | ||||
| - general: Update dependencies/vendor (#1659) | ||||
| - discord: Add more debug options for discord (#1712) | ||||
| - docker: Use Alpine stable again in Dockerfile (#1643) | ||||
| - mattermost: Log eventtype in debug (mattermost) (#1676) | ||||
| - mattermost: Add more ignore debug messages (mattermost) (#1678) | ||||
| - slack: Add support for deleting files from slack to discord. Fixes #1705 (#1709) | ||||
| - telegram: Add support for code blocks in telegram (#1650) | ||||
| - telegram: Update telegram-bot-api to v5 (#1660) | ||||
| - telegram: Add comments to messages (telegram) (#1652) | ||||
| - telegram: Add support for sender_chat (telegram) (#1677) | ||||
| - vk: Remove GroupID (vk) (#1668) | ||||
|  | ||||
| ## Bugfix | ||||
|  | ||||
| - mattermost: Use current parentID if rootId is not set (mattermost) (#1675) | ||||
| - matrix: Make HTMLDisable work correct (matrix) (#1716) | ||||
| - whatsapp: Make EditSuffix option actually work (whatsapp). Fixes #1510 (#1728) | ||||
|  | ||||
| # v1.23.2 | ||||
|  | ||||
| If you're running whatsapp you should update. | ||||
|  | ||||
| ## Bugfix | ||||
|  | ||||
| - whatsapp: Update go-whatsapp version (#1630) | ||||
|  | ||||
| # v1.23.1 | ||||
|  | ||||
| If you're running mattermost 6 you should update. | ||||
|  | ||||
| ## Bugfix | ||||
|  | ||||
| - mattermost: Do not check cache on deleted messages (mattermost). Fixes #1555 (#1624) | ||||
| - mattermost: Fix crash on users updating info. Update matterclient dep. Fixes #1617 | ||||
| - matrix: Keep the logger on a disabled bridge. Fixes #1616 (#1621) | ||||
| - msteams: Fix panic in msteams. Fixes #1588 (#1622) | ||||
| - xmpp: Do not fail on no avatar data (xmpp) #1529 (#1627) | ||||
| - xmpp: Use a new msgID when replacing messages (xmpp). Fixes #1584 (#1623) | ||||
| - zulip: Add better error handling on Zulip (#1589) | ||||
|  | ||||
| # v1.23.0 | ||||
|  | ||||
| ## New features | ||||
| @@ -24,8 +78,6 @@ | ||||
| This release couldn't exist without the following contributors: | ||||
| @powerjungle, @gary-kim, @KingPin, @Benau, @keenan-v1, @tytan652, @KidA001,@minecraftchest1, @irydacea | ||||
|  | ||||
| ## | ||||
|  | ||||
| # v1.22.3 | ||||
|  | ||||
| ## Bugfixes | ||||
|   | ||||
							
								
								
									
										12
									
								
								gateway/bridgemap/bharmony.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								gateway/bridgemap/bharmony.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| //go:build !noharmony | ||||
| // +build !noharmony | ||||
|  | ||||
| package bridgemap | ||||
|  | ||||
| import ( | ||||
| 	bharmony "github.com/42wim/matterbridge/bridge/harmony" | ||||
| ) | ||||
|  | ||||
| func init() { | ||||
| 	FullMap["harmony"] = bharmony.New | ||||
| } | ||||
| @@ -66,7 +66,7 @@ func New(rootLogger *logrus.Logger, cfg *config.Gateway, r *Router) *Gateway { | ||||
| func (gw *Gateway) FindCanonicalMsgID(protocol string, mID string) string { | ||||
| 	ID := protocol + " " + mID | ||||
| 	if gw.Messages.Contains(ID) { | ||||
| 		return mID | ||||
| 		return ID | ||||
| 	} | ||||
|  | ||||
| 	// If not keyed, iterate through cache for downstream, and infer upstream. | ||||
| @@ -75,7 +75,7 @@ func (gw *Gateway) FindCanonicalMsgID(protocol string, mID string) string { | ||||
| 		ids := v.([]*BrMsgID) | ||||
| 		for _, downstreamMsgObj := range ids { | ||||
| 			if ID == downstreamMsgObj.ID { | ||||
| 				return strings.Replace(mid.(string), protocol+" ", "", 1) | ||||
| 				return mid.(string) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| @@ -447,16 +447,19 @@ func (gw *Gateway) SendMessage( | ||||
| 	msg.Avatar = gw.modifyAvatar(rmsg, dest) | ||||
| 	msg.Username = gw.modifyUsername(rmsg, dest) | ||||
|  | ||||
| 	msg.ID = gw.getDestMsgID(rmsg.Protocol+" "+rmsg.ID, dest, channel) | ||||
| 	// exclude file delete event as the msg ID here is the native file ID that needs to be deleted | ||||
| 	if msg.Event != config.EventFileDelete { | ||||
| 		msg.ID = gw.getDestMsgID(rmsg.Protocol+" "+rmsg.ID, dest, channel) | ||||
| 	} | ||||
|  | ||||
| 	// for api we need originchannel as channel | ||||
| 	if dest.Protocol == apiProtocol { | ||||
| 		msg.Channel = rmsg.Channel | ||||
| 	} | ||||
|  | ||||
| 	msg.ParentID = gw.getDestMsgID(rmsg.Protocol+" "+canonicalParentMsgID, dest, channel) | ||||
| 	msg.ParentID = gw.getDestMsgID(canonicalParentMsgID, dest, channel) | ||||
| 	if msg.ParentID == "" { | ||||
| 		msg.ParentID = canonicalParentMsgID | ||||
| 		msg.ParentID = strings.Replace(canonicalParentMsgID, dest.Protocol+" ", "", 1) | ||||
| 	} | ||||
|  | ||||
| 	// if the parentID is still empty and we have a parentID set in the original message | ||||
|   | ||||
| @@ -110,7 +110,9 @@ func (r *Router) disableBridge(br *bridge.Bridge, err error) bool { | ||||
| 	if r.BridgeValues().General.IgnoreFailureOnStart { | ||||
| 		r.logger.Error(err) | ||||
| 		// setting this bridge empty | ||||
| 		*br = bridge.Bridge{} | ||||
| 		*br = bridge.Bridge{ | ||||
| 			Log: br.Log, | ||||
| 		} | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
|   | ||||
							
								
								
									
										75
									
								
								go.mod
									
									
									
									
									
								
							
							
						
						
									
										75
									
								
								go.mod
									
									
									
									
									
								
							| @@ -5,31 +5,32 @@ require ( | ||||
| 	github.com/Baozisoftware/qrcode-terminal-go v0.0.0-20170407111555-c0650d8dff0f | ||||
| 	github.com/Benau/tgsconverter v0.0.0-20210809170556-99f4a4f6337f | ||||
| 	github.com/Philipp15b/go-steam v1.0.1-0.20200727090957-6ae9b3c0a560 | ||||
| 	github.com/Rhymen/go-whatsapp v0.1.2-0.20210615184944-2b8a3e9b8aa2 | ||||
| 	github.com/SevereCloud/vksdk/v2 v2.10.0 | ||||
| 	github.com/d5/tengo/v2 v2.8.0 | ||||
| 	github.com/Rhymen/go-whatsapp v0.1.2-0.20211102134409-31a2e740845c | ||||
| 	github.com/SevereCloud/vksdk/v2 v2.13.1 | ||||
| 	github.com/d5/tengo/v2 v2.10.0 | ||||
| 	github.com/davecgh/go-spew v1.1.1 | ||||
| 	github.com/fsnotify/fsnotify v1.5.1 | ||||
| 	github.com/go-telegram-bot-api/telegram-bot-api v1.0.1-0.20200524105306-7434b0456e81 | ||||
| 	github.com/gomarkdown/markdown v0.0.0-20210918233619-6c1113f12c4a | ||||
| 	github.com/google/gops v0.3.21 | ||||
| 	github.com/go-telegram-bot-api/telegram-bot-api/v5 v5.5.1 | ||||
| 	github.com/gomarkdown/markdown v0.0.0-20211207152620-5d6539fd8bfc | ||||
| 	github.com/google/gops v0.3.22 | ||||
| 	github.com/gorilla/schema v1.2.0 | ||||
| 	github.com/gorilla/websocket v1.4.2 | ||||
| 	github.com/harmony-development/shibshib v0.0.0-20211127182844-512296f7c548 | ||||
| 	github.com/hashicorp/golang-lru v0.5.4 | ||||
| 	github.com/jpillora/backoff v1.0.0 | ||||
| 	github.com/keybase/go-keybase-chat-bot v0.0.0-20211004153716-fd2ee4d6be11 | ||||
| 	github.com/keybase/go-keybase-chat-bot v0.0.0-20211201215354-ee4b23828b55 | ||||
| 	github.com/kyokomi/emoji/v2 v2.2.8 | ||||
| 	github.com/labstack/echo/v4 v4.6.1 | ||||
| 	github.com/lrstanley/girc v0.0.0-20210611213246-771323f1624b | ||||
| 	github.com/labstack/echo/v4 v4.6.3 | ||||
| 	github.com/lrstanley/girc v0.0.0-20211023233735-147f0ff77566 | ||||
| 	github.com/matrix-org/gomatrix v0.0.0-20210324163249-be2af5ef2e16 | ||||
| 	github.com/matterbridge/Rocket.Chat.Go.SDK v0.0.0-20211016222428-79310a412696 | ||||
| 	github.com/matterbridge/discordgo v0.21.2-0.20210201201054-fb39a175b4f7 | ||||
| 	github.com/matterbridge/go-xmpp v0.0.0-20210731150933-5702291c239f | ||||
| 	github.com/matterbridge/gozulipbot v0.0.0-20200820220548-be5824faa913 | ||||
| 	github.com/matterbridge/go-xmpp v0.0.0-20211030125215-791a06c5f1be | ||||
| 	github.com/matterbridge/gozulipbot v0.0.0-20211023205727-a19d6c1f3b75 | ||||
| 	github.com/matterbridge/logrus-prefixed-formatter v0.5.3-0.20200523233437-d971309a77ba | ||||
| 	github.com/matterbridge/matterclient v0.0.0-20211016195328-346acac403d8 | ||||
| 	github.com/mattermost/mattermost-server/v5 v5.39.0 | ||||
| 	github.com/mattermost/mattermost-server/v6 v6.0.0 | ||||
| 	github.com/matterbridge/matterclient v0.0.0-20211107234719-faca3cd42315 | ||||
| 	github.com/mattermost/mattermost-server/v5 v5.39.3 | ||||
| 	github.com/mattermost/mattermost-server/v6 v6.3.0 | ||||
| 	github.com/mattn/godown v0.0.1 | ||||
| 	github.com/missdeer/golib v1.0.4 | ||||
| 	github.com/nelsonken/gomf v0.0.0-20180504123937-a9dd2f9deae9 | ||||
| @@ -39,15 +40,15 @@ require ( | ||||
| 	github.com/saintfish/chardet v0.0.0-20120816061221-3af4cd4741ca | ||||
| 	github.com/shazow/ssh-chat v1.10.1 | ||||
| 	github.com/sirupsen/logrus v1.8.1 | ||||
| 	github.com/slack-go/slack v0.9.5 | ||||
| 	github.com/spf13/viper v1.9.0 | ||||
| 	github.com/slack-go/slack v0.10.0 | ||||
| 	github.com/spf13/viper v1.10.1 | ||||
| 	github.com/stretchr/testify v1.7.0 | ||||
| 	github.com/vincent-petithory/dataurl v0.0.0-20191104211930-d1553a71de50 | ||||
| 	github.com/vincent-petithory/dataurl v1.0.0 | ||||
| 	github.com/writeas/go-strip-markdown v2.0.1+incompatible | ||||
| 	github.com/yaegashi/msgraph.go v0.1.4 | ||||
| 	github.com/zfjagann/golang-ring v0.0.0-20210116075443-7c86fdb43134 | ||||
| 	golang.org/x/image v0.0.0-20210628002857-a66eb6448b8d | ||||
| 	golang.org/x/oauth2 v0.0.0-20211005180243-6b3c2da341f1 | ||||
| 	golang.org/x/image v0.0.0-20211028202545-6944b10bf410 | ||||
| 	golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 | ||||
| 	gomod.garykim.dev/nc-talk v0.3.0 | ||||
| 	gopkg.in/olahol/melody.v1 v1.0.0-20170518105555-d52139073376 | ||||
| 	layeh.com/gumble v0.0.0-20200818122324-146f9205029b | ||||
| @@ -65,31 +66,32 @@ require ( | ||||
| 	github.com/go-asn1-ber/asn1-ber v1.5.3 // indirect | ||||
| 	github.com/golang-jwt/jwt v3.2.2+incompatible // indirect | ||||
| 	github.com/golang/protobuf v1.5.2 // indirect | ||||
| 	github.com/google/uuid v1.2.0 // indirect | ||||
| 	github.com/google/uuid v1.3.0 // indirect | ||||
| 	github.com/gopackage/ddp v0.0.3 // indirect | ||||
| 	github.com/hashicorp/errwrap v1.1.0 // indirect | ||||
| 	github.com/hashicorp/go-multierror v1.1.1 // indirect | ||||
| 	github.com/hashicorp/hcl v1.0.0 // indirect | ||||
| 	github.com/json-iterator/go v1.1.11 // indirect | ||||
| 	github.com/json-iterator/go v1.1.12 // indirect | ||||
| 	github.com/kettek/apng v0.0.0-20191108220231-414630eed80f // indirect | ||||
| 	github.com/klauspost/cpuid/v2 v2.0.6 // indirect | ||||
| 	github.com/labstack/gommon v0.3.0 // indirect | ||||
| 	github.com/klauspost/compress v1.14.2 // indirect | ||||
| 	github.com/klauspost/cpuid/v2 v2.0.9 // indirect | ||||
| 	github.com/labstack/gommon v0.3.1 // indirect | ||||
| 	github.com/magiconair/properties v1.8.5 // indirect | ||||
| 	github.com/mattermost/go-i18n v1.11.0 // indirect | ||||
| 	github.com/mattermost/go-i18n v1.11.1-0.20211013152124-5c415071e404 // indirect | ||||
| 	github.com/mattermost/ldap v0.0.0-20201202150706-ee0e6284187d // indirect | ||||
| 	github.com/mattermost/logr v1.0.13 // indirect | ||||
| 	github.com/mattermost/logr/v2 v2.0.10 // indirect | ||||
| 	github.com/mattn/go-colorable v0.1.8 // indirect | ||||
| 	github.com/mattermost/logr/v2 v2.0.15 // indirect | ||||
| 	github.com/mattn/go-colorable v0.1.12 // indirect | ||||
| 	github.com/mattn/go-isatty v0.0.14 // indirect | ||||
| 	github.com/mattn/go-runewidth v0.0.13 // indirect | ||||
| 	github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect | ||||
| 	github.com/minio/md5-simd v1.1.2 // indirect | ||||
| 	github.com/minio/minio-go/v7 v7.0.11 // indirect | ||||
| 	github.com/minio/minio-go/v7 v7.0.16 // indirect | ||||
| 	github.com/minio/sha256-simd v1.0.0 // indirect | ||||
| 	github.com/mitchellh/go-homedir v1.1.0 // indirect | ||||
| 	github.com/mitchellh/mapstructure v1.4.2 // indirect | ||||
| 	github.com/mitchellh/mapstructure v1.4.3 // indirect | ||||
| 	github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect | ||||
| 	github.com/modern-go/reflect2 v1.0.1 // indirect | ||||
| 	github.com/modern-go/reflect2 v1.0.2 // indirect | ||||
| 	github.com/monaco-io/request v1.0.5 // indirect | ||||
| 	github.com/mreiferson/go-httpclient v0.0.0-20201222173833-5e475fde3a4d // indirect | ||||
| 	github.com/mrexodia/wray v0.0.0-20160318003008-78a2c1f284ff // indirect | ||||
| @@ -109,28 +111,31 @@ require ( | ||||
| 	github.com/spf13/jwalterweatherman v1.1.0 // indirect | ||||
| 	github.com/spf13/pflag v1.0.5 // indirect | ||||
| 	github.com/subosito/gotenv v1.2.0 // indirect | ||||
| 	github.com/technoweenie/multipartstreamer v1.0.1 // indirect | ||||
| 	github.com/tinylib/msgp v1.1.6 // indirect | ||||
| 	github.com/valyala/bytebufferpool v1.0.0 // indirect | ||||
| 	github.com/valyala/fasttemplate v1.2.1 // indirect | ||||
| 	github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect | ||||
| 	github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect | ||||
| 	github.com/wiggin77/cfg v1.0.2 // indirect | ||||
| 	github.com/wiggin77/merror v1.0.3 // indirect | ||||
| 	github.com/wiggin77/srslog v1.0.1 // indirect | ||||
| 	go.uber.org/atomic v1.8.0 // indirect | ||||
| 	go.uber.org/atomic v1.9.0 // indirect | ||||
| 	go.uber.org/multierr v1.7.0 // indirect | ||||
| 	go.uber.org/zap v1.17.0 // indirect | ||||
| 	golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect | ||||
| 	golang.org/x/net v0.0.0-20210913180222-943fd674d43e // indirect | ||||
| 	golang.org/x/sys v0.0.0-20210910150752-751e447fb3d0 // indirect | ||||
| 	golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 // indirect | ||||
| 	golang.org/x/net v0.0.0-20211123203042-d83791d6bcd9 // indirect | ||||
| 	golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect | ||||
| 	golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect | ||||
| 	golang.org/x/text v0.3.7 // indirect | ||||
| 	golang.org/x/time v0.0.0-20201208040808-7e3f01d25324 // indirect | ||||
| 	google.golang.org/appengine v1.6.7 // indirect | ||||
| 	google.golang.org/protobuf v1.27.1 // indirect | ||||
| 	gopkg.in/ini.v1 v1.63.2 // indirect | ||||
| 	gopkg.in/ini.v1 v1.66.2 // indirect | ||||
| 	gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect | ||||
| 	gopkg.in/yaml.v2 v2.4.0 // indirect | ||||
| 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect | ||||
| ) | ||||
|  | ||||
| replace github.com/matrix-org/gomatrix => github.com/matterbridge/gomatrix v0.0.0-20220205235239-607eb9ee6419 | ||||
|  | ||||
| go 1.17 | ||||
|   | ||||
| @@ -7,6 +7,7 @@ import ( | ||||
| 	"log" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"regexp" | ||||
| ) | ||||
|  | ||||
| // Message for rocketchat outgoing webhook. | ||||
| @@ -68,7 +69,6 @@ func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||
| 	} | ||||
| 	msg := Message{} | ||||
| 	body, err := ioutil.ReadAll(r.Body) | ||||
| 	log.Println(string(body)) | ||||
| 	if err != nil { | ||||
| 		log.Println(err) | ||||
| 		http.NotFound(w, r) | ||||
| @@ -89,7 +89,11 @@ func (c *Client) ServeHTTP(w http.ResponseWriter, r *http.Request) { | ||||
| 	msg.ChannelName = "#" + msg.ChannelName | ||||
| 	if c.Token != "" { | ||||
| 		if msg.Token != c.Token { | ||||
| 			log.Println("invalid token " + msg.Token + " from " + r.RemoteAddr) | ||||
| 			if regexp.MustCompile(`[^a-zA-Z0-9]+`).MatchString(msg.Token) { | ||||
| 				log.Println("invalid token " + msg.Token + " from " + r.RemoteAddr) | ||||
| 			} else { | ||||
| 				log.Println("invalid token from " + r.RemoteAddr) | ||||
| 			} | ||||
| 			http.NotFound(w, r) | ||||
| 			return | ||||
| 		} | ||||
|   | ||||
| @@ -10,15 +10,13 @@ import ( | ||||
| 	"github.com/42wim/matterbridge/bridge/config" | ||||
| 	"github.com/42wim/matterbridge/gateway" | ||||
| 	"github.com/42wim/matterbridge/gateway/bridgemap" | ||||
| 	"github.com/42wim/matterbridge/version" | ||||
| 	"github.com/google/gops/agent" | ||||
| 	prefixed "github.com/matterbridge/logrus-prefixed-formatter" | ||||
| 	"github.com/sirupsen/logrus" | ||||
| ) | ||||
|  | ||||
| var ( | ||||
| 	version = "1.23.0" | ||||
| 	githash string | ||||
|  | ||||
| 	flagConfig  = flag.String("conf", "matterbridge.toml", "config file") | ||||
| 	flagDebug   = flag.Bool("debug", false, "enable debug") | ||||
| 	flagVersion = flag.Bool("version", false, "show version") | ||||
| @@ -28,7 +26,7 @@ var ( | ||||
| func main() { | ||||
| 	flag.Parse() | ||||
| 	if *flagVersion { | ||||
| 		fmt.Printf("version: %s %s\n", version, githash) | ||||
| 		fmt.Printf("version: %s %s\n", version.Release, version.GitHash) | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| @@ -43,8 +41,8 @@ func main() { | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	logger.Printf("Running version %s %s", version, githash) | ||||
| 	if strings.Contains(version, "-dev") { | ||||
| 	logger.Printf("Running version %s %s", version.Release, version.GitHash) | ||||
| 	if strings.Contains(version.Release, "-dev") { | ||||
| 		logger.Println("WARNING: THIS IS A DEVELOPMENT VERSION. Things may break.") | ||||
| 	} | ||||
|  | ||||
|   | ||||
| @@ -24,6 +24,13 @@ Password="" | ||||
| #OPTIONAL (default false) | ||||
| UseTLS=false | ||||
|  | ||||
| #Use client certificate - see CertFP https://libera.chat/guides/certfp.html | ||||
| #Specify filename which contains private key and cert | ||||
| #OPTIONAL (default "") | ||||
| # | ||||
| #TLSClientCertificate="cert.pem" | ||||
| TLSClientCertificate="" | ||||
|  | ||||
| #Enable SASL (PLAIN) authentication. (libera requires this from eg AWS hosts) | ||||
| #It uses NickServNick and NickServPassword as login and password | ||||
| #OPTIONAL (default false) | ||||
| @@ -34,6 +41,11 @@ UseSASL=false | ||||
| #OPTIONAL (default false) | ||||
| SkipTLSVerify=true | ||||
|  | ||||
| #Local address to use for server connection | ||||
| #Note that Server and Bind must resolve to addresses of the same family. | ||||
| #OPTIONAL (default "") | ||||
| Bind="" | ||||
|  | ||||
| #If you know your charset, you can specify it manually. | ||||
| #Otherwise it tries to detect this automatically. Select one below | ||||
| # "iso-8859-2:1987", "iso-8859-9:1989", "866", "latin9", "iso-8859-10:1992", "iso-ir-109", "hebrew", | ||||
| @@ -396,6 +408,10 @@ SkipTLSVerify=true | ||||
| ## RELOADABLE SETTINGS | ||||
| ## Settings below can be reloaded by editing the file | ||||
|  | ||||
| # UseUserName shows the username instead of the server nickname | ||||
| # OPTIONAL (default false) | ||||
| UseUserName=false | ||||
|  | ||||
| #how to format the list of IRC nicks when displayed in mattermost. | ||||
| #Possible options are "table" and "plain" | ||||
| #OPTIONAL (default plain) | ||||
| @@ -1534,10 +1550,6 @@ MessageClipped="<clipped message>" | ||||
| #See https://vk.com/dev/bots_docs | ||||
| Token="Yourtokenhere" | ||||
|  | ||||
| #Group ID | ||||
| #For example in URL https://vk.com/public168963511 group ID is 168963511 | ||||
| GroupID=123456789 | ||||
|  | ||||
| ################################################################### | ||||
| # WhatsApp | ||||
| ################################################################### | ||||
| @@ -1655,6 +1667,18 @@ StripNick=false | ||||
| #OPTIONAL (default false) | ||||
| ShowTopicChange=false | ||||
|  | ||||
| ################################################################### | ||||
| # Harmony | ||||
| ################################################################### | ||||
|  | ||||
| [harmony.chat_harmonyapp_io] | ||||
| Homeserver = "https://chat.harmonyapp.io:2289" | ||||
| Token = "your token goes here" | ||||
| UserID = "user id of the bot account" | ||||
| Community = "community id that channels will be located in" | ||||
| UseUserName = true | ||||
| RemoteNickFormat = "{NICK}" | ||||
|  | ||||
| ################################################################### | ||||
| #API | ||||
| ################################################################### | ||||
| @@ -1700,6 +1724,7 @@ RemoteNickFormat="{NICK}" | ||||
|  | ||||
| #RemoteNickFormat defines how remote users appear on this bridge | ||||
| #The string "{NICK}" (case sensitive) will be replaced by the actual nick. | ||||
| #The string "{NOPINGNICK}" (case sensitive) will be replaced by the actual nick / username, but with a ZWSP inside the nick, so the irc user with the same nick won't get pinged. | ||||
| #The string "{USERID}" (case sensitive) will be replaced by the user ID. | ||||
| #The string "{BRIDGE}" (case sensitive) will be replaced by the sending bridge | ||||
| #The string "{LABEL}" (case sensitive) will be replaced by label= field of the sending bridge | ||||
| @@ -1872,7 +1897,8 @@ enable=true | ||||
|     # ------------------------------------------------------------------------------------------------------------------------------------- | ||||
|     #    irc     |      channel       |            #general           | The # symbol is required and should be lowercase! | ||||
|     # ------------------------------------------------------------------------------------------------------------------------------------- | ||||
|     # mattermost |      channel       |            general            | This is the channel name as seen in the URL, not the display name | ||||
|     #            |      channel       |            general            | This is the channel name as seen in the URL, not the display name | ||||
|     # mattermost |    channel id      | ID:oc4wifyuojgw5f3nsuweesmz8w | This is the channel ID (only use if you know what you're doing) | ||||
|     # ------------------------------------------------------------------------------------------------------------------------------------- | ||||
|     #   matrix   | #channel:server    |    #yourchannel:matrix.org    | Encrypted rooms are not supported in matrix | ||||
|     # ------------------------------------------------------------------------------------------------------------------------------------- | ||||
| @@ -1898,7 +1924,7 @@ enable=true | ||||
|     # ------------------------------------------------------------------------------------------------------------------------------------- | ||||
|     #    xmpp    |      channel       |            general            | The room name | ||||
|     # ------------------------------------------------------------------------------------------------------------------------------------- | ||||
|     #   zulip    | stream/topic:topic |     general/off-topic:food    | Do not use the # when specifying a topic | ||||
|     #   zulip    | stream/topic:topic |      general/topic:food       | Do not use the # when specifying a topic | ||||
|     # ------------------------------------------------------------------------------------------------------------------------------------- | ||||
|  | ||||
|     # | ||||
| @@ -1947,6 +1973,10 @@ enable=true | ||||
|     account="zulip.streamchat" | ||||
|     channel="general/topic:mytopic" | ||||
|  | ||||
|     [[gateway.inout]] | ||||
|     account="harmony.chat_harmonyapp_io" | ||||
|     channel="channel id goes here" | ||||
|  | ||||
|     #API example | ||||
|     #[[gateway.inout]] | ||||
|     #account="api.local" | ||||
|   | ||||
| @@ -9,7 +9,7 @@ import ( | ||||
| func (m *MMClient) parseActionPost(rmsg *Message) { | ||||
| 	// add post to cache, if it already exists don't relay this again. | ||||
| 	// this should fix reposts | ||||
| 	if ok, _ := m.lruCache.ContainsOrAdd(digestString(rmsg.Raw.Data["post"].(string)), true); ok { | ||||
| 	if ok, _ := m.lruCache.ContainsOrAdd(digestString(rmsg.Raw.Data["post"].(string)), true); ok && rmsg.Raw.Event != model.WEBSOCKET_EVENT_POST_DELETED { | ||||
| 		m.logger.Debugf("message %#v in cache, not processing again", rmsg.Raw.Data["post"].(string)) | ||||
| 		rmsg.Text = "" | ||||
| 		return | ||||
|   | ||||
| @@ -5,7 +5,7 @@ RUN apk add \ | ||||
|     go \ | ||||
|     git \ | ||||
|   && cd /go/src/matterbridge \ | ||||
|   && go build -mod vendor -ldflags "-X main.githash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge | ||||
|   && CGO_ENABLED=0 go build -mod vendor -ldflags "-X github.com/42wim/matterbridge/version.GitHash=$(git log --pretty=format:'%h' -n 1)" -o /bin/matterbridge | ||||
|  | ||||
| FROM alpine | ||||
| RUN apk --no-cache add \ | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/Rhymen/go-whatsapp/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/Rhymen/go-whatsapp/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -70,7 +70,7 @@ func (myHandler) HandleContactMessage(message whatsapp.ContactMessage) { | ||||
| 	fmt.Println(message) | ||||
| } | ||||
|  | ||||
| func (myHandler) HandleBatteryMessage(msg whatsapp.BatteryMessage) { | ||||
| func (myHandler) HandleBatteryMessage(message whatsapp.BatteryMessage) { | ||||
| 	fmt.Println(message) | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/Rhymen/go-whatsapp/session.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/Rhymen/go-whatsapp/session.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -18,7 +18,7 @@ import ( | ||||
| ) | ||||
|  | ||||
| //represents the WhatsAppWeb client version | ||||
| var waVersion = []int{2, 2121, 6} | ||||
| var waVersion = []int{2, 2142, 12} | ||||
|  | ||||
| /* | ||||
| Session contains session individual information. To be able to resume the connection without scanning the qr code | ||||
| @@ -526,5 +526,7 @@ func (wac *Conn) Logout() error { | ||||
| 		return fmt.Errorf("error writing logout: %v\n", err) | ||||
| 	} | ||||
|  | ||||
| 	wac.loggedIn = false | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|   | ||||
							
								
								
									
										14
									
								
								vendor/github.com/SevereCloud/vksdk/v2/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/github.com/SevereCloud/vksdk/v2/.golangci.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -48,10 +48,18 @@ linters: | ||||
|     - nilerr | ||||
|     - revive | ||||
|     - wastedassign | ||||
|     - bidichk | ||||
|     - contextcheck | ||||
|     - ireturn | ||||
|     - nilnil | ||||
|     - tenv | ||||
|     - nestif | ||||
|     - grouper | ||||
|     - decorder | ||||
|     - containedctx | ||||
|  | ||||
| # - wrapcheck # TODO: v3 Fix | ||||
| # - testpackage # TODO: Fix testpackage | ||||
| # - nestif # TODO: Fix nestif | ||||
| # - noctx # TODO: Fix noctx | ||||
|  | ||||
| # don't enable: | ||||
| @@ -75,6 +83,10 @@ linters: | ||||
| # - cyclop | ||||
| # - promlinter | ||||
| # - tagliatelle | ||||
| # - errname | ||||
| # - varnamelen | ||||
| # - errchkjson | ||||
| # - maintidx | ||||
|  | ||||
| # depricated | ||||
| # - maligned | ||||
|   | ||||
							
								
								
									
										1
									
								
								vendor/github.com/SevereCloud/vksdk/v2/.markdownlint.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/SevereCloud/vksdk/v2/.markdownlint.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,2 +1,3 @@ | ||||
| --- | ||||
| no-hard-tabs: false | ||||
| no-duplicate-heading: false | ||||
|   | ||||
							
								
								
									
										20
									
								
								vendor/github.com/SevereCloud/vksdk/v2/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/SevereCloud/vksdk/v2/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,20 +0,0 @@ | ||||
| --- | ||||
| language: go | ||||
|  | ||||
| cache: | ||||
|   directories: | ||||
|     - $HOME/.cache/go-build | ||||
|     - $HOME/gopath/pkg/mod | ||||
|  | ||||
| go: | ||||
|   - 1.x | ||||
|  | ||||
| before_script: | ||||
|   - git fetch --depth=1 origin +refs/tags/*:refs/tags/* | ||||
|   - git describe --tags $(git rev-list --tags --max-count=1) --always | ||||
|  | ||||
| script: | ||||
|   - go test -v -race -coverprofile=coverage.txt -covermode=atomic -p=1 ./... | ||||
|  | ||||
| after_success: | ||||
|   - bash <(curl -s https://codecov.io/bash) | ||||
							
								
								
									
										4
									
								
								vendor/github.com/SevereCloud/vksdk/v2/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/SevereCloud/vksdk/v2/CONTRIBUTING.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -6,7 +6,7 @@ | ||||
|  | ||||
| Требования: | ||||
|  | ||||
| - [Go 1.13+](https://golang.org/doc/install) | ||||
| - [Go 1.16+](https://golang.org/doc/install) | ||||
| - [golangci-lint](https://github.com/golangci/golangci-lint) | ||||
| - [global .gitignore](https://help.github.com/en/articles/ignoring-files#create-a-global-gitignore) | ||||
|  | ||||
| @@ -39,6 +39,7 @@ golangci-lint run | ||||
| # CLIENT_SECRET="" | ||||
| # USER_TOKEN="" | ||||
| # WIDGET_TOKEN="" | ||||
| # MARUSIA_TOKEN="" | ||||
| # CLIENT_ID="123456" | ||||
| # GROUP_ID="123456" | ||||
| # ACCOUNT_ID="123456" | ||||
| @@ -56,6 +57,7 @@ go test ./... | ||||
|     "go.testEnvVars": { | ||||
|         "SERVICE_TOKEN": "", | ||||
|         "WIDGET_TOKEN": "", | ||||
|         "MARUSIA_TOKEN": "", | ||||
|         "GROUP_TOKEN": "", | ||||
|         "CLIENT_SECRET": "", | ||||
|         "USER_TOKEN": "", | ||||
|   | ||||
							
								
								
									
										252
									
								
								vendor/github.com/SevereCloud/vksdk/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										252
									
								
								vendor/github.com/SevereCloud/vksdk/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,125 +1,127 @@ | ||||
| # VK SDK for Golang | ||||
|  | ||||
| [](https://travis-ci.com/SevereCloud/vksdk) | ||||
| [](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2?tab=subdirectories) | ||||
| [](https://vk.com/dev/) | ||||
| [](https://codecov.io/gh/SevereCloud/vksdk) | ||||
| [](https://vk.me/join/AJQ1d6Or8Q00Y_CSOESfbqGt) | ||||
| [](https://github.com/SevereCloud/vksdk/releases) | ||||
| [](https://github.com/SevereCloud/vksdk/blob/master/LICENSE) | ||||
|  | ||||
| **VK SDK for Golang** ready implementation of the main VK API functions for Go. | ||||
|  | ||||
| [Russian documentation](https://github.com/SevereCloud/vksdk/wiki) | ||||
|  | ||||
| ## Features | ||||
|  | ||||
| Version API 5.131. | ||||
|  | ||||
| - [API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/api) | ||||
|   - 400+ methods | ||||
|   - Ability to change the request handler | ||||
|   - Ability to modify HTTP client | ||||
|   - Request Limiter | ||||
|   - Token pool | ||||
| - [Callback API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/callback) | ||||
|   - Tracking tool for users activity in your VK communities | ||||
|   - Supports all events | ||||
|   - Auto setting callback | ||||
| - [Bots Long Poll API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/longpoll-bot) | ||||
|   - Allows you to work with community events in real time | ||||
|   - Supports all events | ||||
|   - Ability to modify HTTP client | ||||
| - [User Long Poll API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/longpoll-user) | ||||
|   - Allows you to work with user events in real time | ||||
|   - Ability to modify HTTP client | ||||
| - [Streaming API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/streaming) | ||||
|   - Receiving public data from VK by specified keywords | ||||
|   - Ability to modify HTTP client | ||||
| - [FOAF](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/foaf) | ||||
|   - Machine-readable ontology describing persons | ||||
|   - Works with users and groups | ||||
|   - The only place to get page creation date | ||||
| - [Games](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/games) | ||||
|   - Checking launch parameters | ||||
|   - Intermediate http handler | ||||
| - [VK Mini Apps](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/vkapps) | ||||
|   - Checking launch parameters | ||||
|   - Intermediate http handler | ||||
| - [Payments API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/payments) | ||||
|   - Processes payment notifications | ||||
| - [Marusia Skills](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/marusia) | ||||
|   - For creating Marusia Skills | ||||
|   - Support SSML | ||||
|  | ||||
| ## Install | ||||
|  | ||||
| ```bash | ||||
| # go mod init mymodulename | ||||
| go get github.com/SevereCloud/vksdk/v2@latest | ||||
| ``` | ||||
|  | ||||
| ## Use by | ||||
|  | ||||
| - [Joe](https://github.com/go-joe/joe) adapter: <https://github.com/tdakkota/joe-vk-adapter> | ||||
| - [Logrus](https://github.com/sirupsen/logrus) hook: <https://github.com/SevereCloud/vkrus> | ||||
|  | ||||
| ### Example | ||||
|  | ||||
| ```go | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"log" | ||||
|  | ||||
| 	"github.com/SevereCloud/vksdk/v2/api" | ||||
| 	"github.com/SevereCloud/vksdk/v2/api/params" | ||||
| 	"github.com/SevereCloud/vksdk/v2/events" | ||||
| 	"github.com/SevereCloud/vksdk/v2/longpoll-bot" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	token := "<TOKEN>" // use os.Getenv("TOKEN") | ||||
| 	vk := api.NewVK(token) | ||||
|  | ||||
| 	// get information about the group | ||||
| 	group, err := vk.GroupsGetByID(nil) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// Initializing Long Poll | ||||
| 	lp, err := longpoll.NewLongPoll(vk, group[0].ID) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// New message event | ||||
| 	lp.MessageNew(func(_ context.Context, obj events.MessageNewObject) { | ||||
| 		log.Printf("%d: %s", obj.Message.PeerID, obj.Message.Text) | ||||
|  | ||||
| 		if obj.Message.Text == "ping" { | ||||
| 			b := params.NewMessagesSendBuilder() | ||||
| 			b.Message("pong") | ||||
| 			b.RandomID(0) | ||||
| 			b.PeerID(obj.Message.PeerID) | ||||
|  | ||||
| 			_, err := vk.MessagesSend(b.Params) | ||||
| 			if err != nil { | ||||
| 				log.Fatal(err) | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	// Run Bots Long Poll | ||||
| 	log.Println("Start Long Poll") | ||||
| 	if err := lp.Run(); err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ## LICENSE | ||||
|  | ||||
| [](https://app.fossa.io/projects/git%2Bgithub.com%2FSevereCloud%2Fvksdk?ref=badge_large) | ||||
| # VK SDK for Golang | ||||
|  | ||||
| [](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2?tab=subdirectories) | ||||
| [](https://vk.com/dev/) | ||||
| [](https://codecov.io/gh/SevereCloud/vksdk) | ||||
| [](https://vk.me/join/AJQ1d6Or8Q00Y_CSOESfbqGt) | ||||
| [](https://github.com/SevereCloud/vksdk/releases) | ||||
| [](https://github.com/SevereCloud/vksdk/blob/master/LICENSE) | ||||
|  | ||||
| **VK SDK for Golang** ready implementation of the main VK API functions for Go. | ||||
|  | ||||
| [Russian documentation](https://github.com/SevereCloud/vksdk/wiki) | ||||
|  | ||||
| ## Features | ||||
|  | ||||
| Version API 5.131. | ||||
|  | ||||
| - [API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/api) | ||||
|   - 500+ methods | ||||
|   - Ability to modify HTTP client | ||||
|   - Request Limiter | ||||
|   - Support [zstd](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/api#VK.EnableZstd) | ||||
| and [MessagePack](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/api#VK.EnableMessagePack) | ||||
|   - Token pool | ||||
|   - [OAuth](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/api/oauth) | ||||
| - [Callback API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/callback) | ||||
|   - Tracking tool for users activity in your VK communities | ||||
|   - Supports all events | ||||
|   - Auto setting callback | ||||
| - [Bots Long Poll API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/longpoll-bot) | ||||
|   - Allows you to work with community events in real time | ||||
|   - Supports all events | ||||
|   - Ability to modify HTTP client | ||||
| - [User Long Poll API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/longpoll-user) | ||||
|   - Allows you to work with user events in real time | ||||
|   - Ability to modify HTTP client | ||||
| - [Streaming API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/streaming) | ||||
|   - Receiving public data from VK by specified keywords | ||||
|   - Ability to modify HTTP client | ||||
| - [FOAF](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/foaf) | ||||
|   - Machine-readable ontology describing persons | ||||
|   - Works with users and groups | ||||
|   - The only place to get page creation date | ||||
| - [Games](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/games) | ||||
|   - Checking launch parameters | ||||
|   - Intermediate http handler | ||||
| - [VK Mini Apps](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/vkapps) | ||||
|   - Checking launch parameters | ||||
|   - Intermediate http handler | ||||
| - [Payments API](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/payments) | ||||
|   - Processes payment notifications | ||||
| - [Marusia Skills](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/marusia) | ||||
|   - For creating Marusia Skills | ||||
|   - Support SSML | ||||
|  | ||||
| ## Install | ||||
|  | ||||
| ```bash | ||||
| # go mod init mymodulename | ||||
| go get github.com/SevereCloud/vksdk/v2@latest | ||||
| ``` | ||||
|  | ||||
| ## Use by | ||||
|  | ||||
| - A simple chat bridge: <https://github.com/42wim/matterbridge> | ||||
| - [Joe](https://github.com/go-joe/joe) adapter: <https://github.com/tdakkota/joe-vk-adapter> | ||||
| - [Logrus](https://github.com/sirupsen/logrus) hook: <https://github.com/SevereCloud/vkrus> | ||||
|  | ||||
| ### Example | ||||
|  | ||||
| ```go | ||||
| package main | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"log" | ||||
|  | ||||
| 	"github.com/SevereCloud/vksdk/v2/api" | ||||
| 	"github.com/SevereCloud/vksdk/v2/api/params" | ||||
| 	"github.com/SevereCloud/vksdk/v2/events" | ||||
| 	"github.com/SevereCloud/vksdk/v2/longpoll-bot" | ||||
| ) | ||||
|  | ||||
| func main() { | ||||
| 	token := "<TOKEN>" // use os.Getenv("TOKEN") | ||||
| 	vk := api.NewVK(token) | ||||
|  | ||||
| 	// get information about the group | ||||
| 	group, err := vk.GroupsGetByID(nil) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// Initializing Long Poll | ||||
| 	lp, err := longpoll.NewLongPoll(vk, group[0].ID) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
|  | ||||
| 	// New message event | ||||
| 	lp.MessageNew(func(_ context.Context, obj events.MessageNewObject) { | ||||
| 		log.Printf("%d: %s", obj.Message.PeerID, obj.Message.Text) | ||||
|  | ||||
| 		if obj.Message.Text == "ping" { | ||||
| 			b := params.NewMessagesSendBuilder() | ||||
| 			b.Message("pong") | ||||
| 			b.RandomID(0) | ||||
| 			b.PeerID(obj.Message.PeerID) | ||||
|  | ||||
| 			_, err := vk.MessagesSend(b.Params) | ||||
| 			if err != nil { | ||||
| 				log.Fatal(err) | ||||
| 			} | ||||
| 		} | ||||
| 	}) | ||||
|  | ||||
| 	// Run Bots Long Poll | ||||
| 	log.Println("Start Long Poll") | ||||
| 	if err := lp.Run(); err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| } | ||||
| ``` | ||||
|  | ||||
| ## LICENSE | ||||
|  | ||||
| [](https://app.fossa.io/projects/git%2Bgithub.com%2FSevereCloud%2Fvksdk?ref=badge_large) | ||||
|   | ||||
							
								
								
									
										50
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										50
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -3,7 +3,7 @@ | ||||
| [](https://pkg.go.dev/github.com/SevereCloud/vksdk/v2/api) | ||||
| [](https://vk.com/dev/first_guide) | ||||
|  | ||||
| Данная библиотека поддерживает версию API **5.122**. | ||||
| Данная библиотека поддерживает версию API **5.131**. | ||||
|  | ||||
| ## Запросы | ||||
|  | ||||
| @@ -80,6 +80,54 @@ if errors.As(err, &e) { | ||||
|  | ||||
| Для Execute существует отдельная ошибка `ExecuteErrors` | ||||
|  | ||||
| ### Поддержка MessagePack и zstd | ||||
|  | ||||
| > Результат перехода с gzip (JSON) на zstd (msgpack): | ||||
| > | ||||
| > - в 7 раз быстрее сжатие (–1 мкс); | ||||
| > - на 10% меньше размер данных (8 Кбайт вместо 9 Кбайт); | ||||
| > - продуктовый эффект не статзначимый :( | ||||
| > | ||||
| > [Как мы отказались от JPEG, JSON, TCP и ускорили ВКонтакте в два раза](https://habr.com/ru/company/vk/blog/594633/) | ||||
|  | ||||
| VK API способно возвращать ответ в виде [MessagePack](https://msgpack.org/). | ||||
| Это эффективный формат двоичной сериализации, похожий на JSON, только быстрее | ||||
| и меньше по размеру. | ||||
|  | ||||
| ВНИМАНИЕ, C MessagePack НЕКОТОРЫЕ МЕТОДЫ МОГУТ ВОЗВРАЩАТЬ | ||||
| СЛОМАННУЮ КОДИРОВКУ. | ||||
|  | ||||
| Для сжатия, вместо классического gzip, можно использовать | ||||
| [zstd](https://github.com/facebook/zstd). Сейчас vksdk поддерживает zstd без | ||||
| словаря. Если кто знает как получать словарь, | ||||
| [отпишитесь сюда](https://github.com/SevereCloud/vksdk/issues/180). | ||||
|  | ||||
| ```go | ||||
| vk := api.NewVK(os.Getenv("USER_TOKEN")) | ||||
|  | ||||
| method := "store.getStickersKeywords" | ||||
| params := api.Params{ | ||||
| 	"aliases":       true, | ||||
| 	"all_products":  true, | ||||
| 	"need_stickers": true, | ||||
| } | ||||
|  | ||||
| r, err := vk.Request(method, params) // Content-Length: 44758 | ||||
| if err != nil { | ||||
| 	log.Fatal(err) | ||||
| } | ||||
| log.Println("json:", len(r)) // json: 814231 | ||||
|  | ||||
| vk.EnableMessagePack() // Включаем поддержку MessagePack | ||||
| vk.EnableZstd() // Включаем поддержку zstd | ||||
|  | ||||
| r, err = vk.Request(method, params) // Content-Length: 35755 | ||||
| if err != nil { | ||||
| 	log.Fatal(err) | ||||
| } | ||||
| log.Println("msgpack:", len(r)) // msgpack: 650775 | ||||
| ``` | ||||
|  | ||||
| ### Запрос любого метода | ||||
|  | ||||
| Пример запроса [users.get](https://vk.com/dev/users.get) | ||||
|   | ||||
							
								
								
									
										21
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/ads.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/ads.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,9 +1,11 @@ | ||||
| package api // import "github.com/SevereCloud/vksdk/v2/api" | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
|  | ||||
| 	"github.com/SevereCloud/vksdk/v2/object" | ||||
| 	"github.com/vmihailenco/msgpack/v5" | ||||
| ) | ||||
|  | ||||
| // AdsAddOfficeUsersItem struct. | ||||
| @@ -21,6 +23,23 @@ func (r *AdsAddOfficeUsersItem) UnmarshalJSON(data []byte) (err error) { | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // DecodeMsgpack func. | ||||
| func (r *AdsAddOfficeUsersItem) DecodeMsgpack(dec *msgpack.Decoder) error { | ||||
| 	data, err := dec.DecodeRaw() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if msgpack.Unmarshal(data, &r.OK) != nil { | ||||
| 		d := msgpack.NewDecoder(bytes.NewReader(data)) | ||||
| 		d.SetCustomStructTag("json") | ||||
|  | ||||
| 		return d.Decode(&r.Error) | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // AdsAddOfficeUsersResponse struct. | ||||
| type AdsAddOfficeUsersResponse []AdsAddOfficeUsersItem | ||||
|  | ||||
| @@ -349,7 +368,7 @@ func (vk *VK) AdsGetAdsLayout(params Params) (response AdsGetAdsLayoutResponse, | ||||
|  | ||||
| // AdsGetMusiciansResponse struct. | ||||
| type AdsGetMusiciansResponse struct { | ||||
| 	Items []object.BaseObjectWithName | ||||
| 	Items []object.AdsMusician | ||||
| } | ||||
|  | ||||
| // AdsGetMusicians returns a list of musicians. | ||||
|   | ||||
							
								
								
									
										98
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/api.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										98
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/api.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -7,9 +7,11 @@ package api // import "github.com/SevereCloud/vksdk/v2/api" | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"compress/gzip" | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"mime" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| @@ -21,6 +23,8 @@ import ( | ||||
| 	"github.com/SevereCloud/vksdk/v2" | ||||
| 	"github.com/SevereCloud/vksdk/v2/internal" | ||||
| 	"github.com/SevereCloud/vksdk/v2/object" | ||||
| 	"github.com/klauspost/compress/zstd" | ||||
| 	"github.com/vmihailenco/msgpack/v5" | ||||
| ) | ||||
|  | ||||
| // Api constants. | ||||
| @@ -91,6 +95,9 @@ type VK struct { | ||||
| 	UserAgent    string | ||||
| 	Handler      func(method string, params ...Params) (Response, error) | ||||
|  | ||||
| 	msgpack bool | ||||
| 	zstd    bool | ||||
|  | ||||
| 	mux      sync.Mutex | ||||
| 	lastTime time.Time | ||||
| 	rps      int | ||||
| @@ -98,9 +105,9 @@ type VK struct { | ||||
|  | ||||
| // Response struct. | ||||
| type Response struct { | ||||
| 	Response      json.RawMessage `json:"response"` | ||||
| 	Error         Error           `json:"error"` | ||||
| 	ExecuteErrors ExecuteErrors   `json:"execute_errors"` | ||||
| 	Response      object.RawMessage `json:"response"` | ||||
| 	Error         Error             `json:"error"` | ||||
| 	ExecuteErrors ExecuteErrors     `json:"execute_errors"` | ||||
| } | ||||
|  | ||||
| // NewVK returns a new VK. | ||||
| @@ -121,7 +128,7 @@ func NewVK(tokens ...string) *VK { | ||||
| 	vk.accessTokens = tokens | ||||
| 	vk.Version = Version | ||||
|  | ||||
| 	vk.Handler = vk.defaultHandler | ||||
| 	vk.Handler = vk.DefaultHandler | ||||
|  | ||||
| 	vk.MethodURL = MethodURL | ||||
| 	vk.Client = http.DefaultClient | ||||
| @@ -207,8 +214,8 @@ func buildQuery(sliceParams ...Params) (context.Context, url.Values) { | ||||
| 	return ctx, query | ||||
| } | ||||
|  | ||||
| // defaultHandler provides access to VK API methods. | ||||
| func (vk *VK) defaultHandler(method string, sliceParams ...Params) (Response, error) { | ||||
| // DefaultHandler provides access to VK API methods. | ||||
| func (vk *VK) DefaultHandler(method string, sliceParams ...Params) (Response, error) { | ||||
| 	u := vk.MethodURL + method | ||||
| 	ctx, query := buildQuery(sliceParams...) | ||||
| 	attempt := 0 | ||||
| @@ -243,24 +250,58 @@ func (vk *VK) defaultHandler(method string, sliceParams ...Params) (Response, er | ||||
| 			return response, err | ||||
| 		} | ||||
|  | ||||
| 		acceptEncoding := "gzip" | ||||
| 		if vk.zstd { | ||||
| 			acceptEncoding = "zstd" | ||||
| 		} | ||||
|  | ||||
| 		req.Header.Set("User-Agent", vk.UserAgent) | ||||
| 		req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||||
|  | ||||
| 		req.Header.Set("Accept-Encoding", acceptEncoding) | ||||
|  | ||||
| 		var reader io.Reader | ||||
|  | ||||
| 		resp, err := vk.Client.Do(req) | ||||
| 		if err != nil { | ||||
| 			return response, err | ||||
| 		} | ||||
|  | ||||
| 		mediatype, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type")) | ||||
| 		if mediatype != "application/json" { | ||||
| 			_ = resp.Body.Close() | ||||
| 			return response, &InvalidContentType{mediatype} | ||||
| 		switch resp.Header.Get("Content-Encoding") { | ||||
| 		case "zstd": | ||||
| 			zstdReader, _ := zstd.NewReader(resp.Body) | ||||
| 			defer zstdReader.Close() | ||||
|  | ||||
| 			reader = zstdReader | ||||
| 		case "gzip": | ||||
| 			gzipReader, _ := gzip.NewReader(resp.Body) | ||||
| 			defer gzipReader.Close() | ||||
|  | ||||
| 			reader = gzipReader | ||||
| 		default: | ||||
| 			reader = resp.Body | ||||
| 		} | ||||
|  | ||||
| 		err = json.NewDecoder(resp.Body).Decode(&response) | ||||
| 		if err != nil { | ||||
| 		mediatype, _, _ := mime.ParseMediaType(resp.Header.Get("Content-Type")) | ||||
| 		switch mediatype { | ||||
| 		case "application/json": | ||||
| 			err = json.NewDecoder(reader).Decode(&response) | ||||
| 			if err != nil { | ||||
| 				_ = resp.Body.Close() | ||||
| 				return response, err | ||||
| 			} | ||||
| 		case "application/x-msgpack": | ||||
| 			dec := msgpack.NewDecoder(reader) | ||||
| 			dec.SetCustomStructTag("json") | ||||
|  | ||||
| 			err = dec.Decode(&response) | ||||
| 			if err != nil { | ||||
| 				_ = resp.Body.Close() | ||||
| 				return response, err | ||||
| 			} | ||||
| 		default: | ||||
| 			_ = resp.Body.Close() | ||||
| 			return response, err | ||||
| 			return response, &InvalidContentType{mediatype} | ||||
| 		} | ||||
|  | ||||
| 		_ = resp.Body.Close() | ||||
| @@ -291,6 +332,10 @@ func (vk *VK) Request(method string, sliceParams ...Params) ([]byte, error) { | ||||
|  | ||||
| 	sliceParams = append(sliceParams, reqParams) | ||||
|  | ||||
| 	if vk.msgpack { | ||||
| 		method += ".msgpack" | ||||
| 	} | ||||
|  | ||||
| 	resp, err := vk.Handler(method, sliceParams...) | ||||
|  | ||||
| 	return resp.Response, err | ||||
| @@ -303,7 +348,32 @@ func (vk *VK) RequestUnmarshal(method string, obj interface{}, sliceParams ...Pa | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	return json.Unmarshal(rawResponse, &obj) | ||||
| 	if vk.msgpack { | ||||
| 		dec := msgpack.NewDecoder(bytes.NewReader(rawResponse)) | ||||
| 		dec.SetCustomStructTag("json") | ||||
|  | ||||
| 		err = dec.Decode(&obj) | ||||
| 	} else { | ||||
| 		err = json.Unmarshal(rawResponse, &obj) | ||||
| 	} | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // EnableMessagePack enable using MessagePack instead of JSON. | ||||
| // | ||||
| // THIS IS EXPERIMENTAL FUNCTION! Broken encoding returned in some methods. | ||||
| // | ||||
| // See https://msgpack.org | ||||
| func (vk *VK) EnableMessagePack() { | ||||
| 	vk.msgpack = true | ||||
| } | ||||
|  | ||||
| // EnableZstd enable using zstd instead of gzip. | ||||
| // | ||||
| // This not use dict. | ||||
| func (vk *VK) EnableZstd() { | ||||
| 	vk.zstd = true | ||||
| } | ||||
|  | ||||
| func fmtReflectValue(value reflect.Value, depth int) string { | ||||
|   | ||||
							
								
								
									
										59
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/auth.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										59
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/auth.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,5 +1,9 @@ | ||||
| package api // import "github.com/SevereCloud/vksdk/v2/api" | ||||
|  | ||||
| import ( | ||||
| 	"github.com/SevereCloud/vksdk/v2/object" | ||||
| ) | ||||
|  | ||||
| // AuthCheckPhone checks a user's phone number for correctness. | ||||
| // | ||||
| // https://vk.com/dev/auth.checkPhone | ||||
| @@ -24,3 +28,58 @@ func (vk *VK) AuthRestore(params Params) (response AuthRestoreResponse, err erro | ||||
| 	err = vk.RequestUnmarshal("auth.restore", &response, params) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // AuthGetProfileInfoBySilentTokenResponse struct. | ||||
| type AuthGetProfileInfoBySilentTokenResponse struct { | ||||
| 	Success []object.AuthSilentTokenProfile `json:"success"` | ||||
| 	Errors  []AuthSilentTokenError          `json:"errors"` | ||||
| } | ||||
|  | ||||
| // AuthGetProfileInfoBySilentToken method. | ||||
| // | ||||
| // https://platform.vk.com/?p=DocsDashboard&docs=tokens_silent-token | ||||
| func (vk *VK) AuthGetProfileInfoBySilentToken(params Params) (response AuthGetProfileInfoBySilentTokenResponse, err error) { | ||||
| 	err = vk.RequestUnmarshal("auth.getProfileInfoBySilentToken", &response, params) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // ExchangeSilentTokenSource call conditions exchangeSilentToken. | ||||
| // | ||||
| // 	0	Unknown | ||||
| // 	1	Silent authentication | ||||
| // 	2	Auth by login and password | ||||
| // 	3	Extended registration | ||||
| // 	4	Auth by exchange token | ||||
| // 	5	Auth by exchange token on reset password | ||||
| // 	6	Auth by exchange token on unblock | ||||
| // 	7	Auth by exchange token on reset session | ||||
| // 	8	Auth by exchange token on change password | ||||
| // 	9	Finish phone validation on authentication | ||||
| // 	10	Auth by code | ||||
| // 	11	Auth by external oauth | ||||
| // 	12	Reactivation | ||||
| // 	15	Auth by SDK temporary access-token | ||||
| type ExchangeSilentTokenSource int | ||||
|  | ||||
| // AuthExchangeSilentAuthTokenResponse struct. | ||||
| type AuthExchangeSilentAuthTokenResponse struct { | ||||
| 	AccessToken              string                    `json:"access_token"` | ||||
| 	AccessTokenID            string                    `json:"access_token_id"` | ||||
| 	UserID                   int                       `json:"user_id"` | ||||
| 	Phone                    string                    `json:"phone"` | ||||
| 	PhoneValidated           interface{}               `json:"phone_validated"` | ||||
| 	IsPartial                bool                      `json:"is_partial"` | ||||
| 	IsService                bool                      `json:"is_service"` | ||||
| 	AdditionalSignupRequired bool                      `json:"additional_signup_required"` | ||||
| 	Email                    string                    `json:"email"` | ||||
| 	Source                   ExchangeSilentTokenSource `json:"source"` | ||||
| 	SourceDescription        string                    `json:"source_description"` | ||||
| } | ||||
|  | ||||
| // AuthExchangeSilentAuthToken method. | ||||
| // | ||||
| // https://platform.vk.com/?p=DocsDashboard&docs=tokens_access-token | ||||
| func (vk *VK) AuthExchangeSilentAuthToken(params Params) (response AuthExchangeSilentAuthTokenResponse, err error) { | ||||
| 	err = vk.RequestUnmarshal("auth.exchangeSilentAuthToken", &response, params) | ||||
| 	return | ||||
| } | ||||
|   | ||||
							
								
								
									
										82
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										82
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/errors.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -159,6 +159,9 @@ const ( | ||||
| 	ErrRateLimit      ErrorType = 29 | ||||
| 	ErrPrivateProfile ErrorType = 30 // This profile is private | ||||
|  | ||||
| 	// Client version deprecated. | ||||
| 	ErrClientVersionDeprecated ErrorType = 34 | ||||
|  | ||||
| 	// Method execution was interrupted due to timeout. | ||||
| 	ErrExecutionTimeout ErrorType = 36 | ||||
|  | ||||
| @@ -177,6 +180,9 @@ const ( | ||||
| 	// Additional signup required. | ||||
| 	ErrAdditionalSignupRequired ErrorType = 41 | ||||
|  | ||||
| 	// IP is not allowed. | ||||
| 	ErrIPNotAllowed ErrorType = 42 | ||||
|  | ||||
| 	// One of the parameters specified was missing or invalid | ||||
| 	// | ||||
| 	// Check the required parameters list and their format on a method | ||||
| @@ -586,6 +592,18 @@ const ( | ||||
| 	// Can't send message, reply timed out. | ||||
| 	ErrMessagesReplyTimedOut ErrorType = 950 | ||||
|  | ||||
| 	// You can't access donut chat without subscription. | ||||
| 	ErrMessagesAccessDonutChat ErrorType = 962 | ||||
|  | ||||
| 	// This user can't be added to the work chat, as they aren't an employe. | ||||
| 	ErrMessagesAccessWorkChat ErrorType = 967 | ||||
|  | ||||
| 	// Message cannot be forwarded. | ||||
| 	ErrMessagesCantForwarded ErrorType = 969 | ||||
|  | ||||
| 	// Cannot pin an expiring message. | ||||
| 	ErrMessagesPinExpiringMessage ErrorType = 970 | ||||
|  | ||||
| 	// Invalid phone number. | ||||
| 	ErrParamPhone ErrorType = 1000 | ||||
|  | ||||
| @@ -598,6 +616,12 @@ const ( | ||||
| 	// Processing.. Try later. | ||||
| 	ErrAuthDelay ErrorType = 1112 | ||||
|  | ||||
| 	// Anonymous token has expired. | ||||
| 	ErrAnonymousTokenExpired ErrorType = 1114 | ||||
|  | ||||
| 	// Anonymous token is invalid. | ||||
| 	ErrAnonymousTokenInvalid ErrorType = 1116 | ||||
|  | ||||
| 	// Invalid document id. | ||||
| 	ErrParamDocID ErrorType = 1150 | ||||
|  | ||||
| @@ -724,6 +748,9 @@ const ( | ||||
| 	// Market was already disabled in this group. | ||||
| 	ErrMarketAlreadyDisabled ErrorType = 1432 | ||||
|  | ||||
| 	// Main album can not be hidden. | ||||
| 	ErrMainAlbumCantHidden ErrorType = 1446 | ||||
|  | ||||
| 	// Story has already expired. | ||||
| 	ErrStoryExpired ErrorType = 1600 | ||||
|  | ||||
| @@ -783,6 +810,33 @@ const ( | ||||
|  | ||||
| 	// Can't set AliExpress tag to this type of object. | ||||
| 	ErrAliExpressTag ErrorType = 3800 | ||||
|  | ||||
| 	// Invalid upload response. | ||||
| 	ErrInvalidUploadResponse ErrorType = 5701 | ||||
|  | ||||
| 	// Invalid upload hash. | ||||
| 	ErrInvalidUploadHash ErrorType = 5702 | ||||
|  | ||||
| 	// Invalid upload user. | ||||
| 	ErrInvalidUploadUser ErrorType = 5703 | ||||
|  | ||||
| 	// Invalid upload group. | ||||
| 	ErrInvalidUploadGroup ErrorType = 5704 | ||||
|  | ||||
| 	// Invalid crop data. | ||||
| 	ErrInvalidCropData ErrorType = 5705 | ||||
|  | ||||
| 	// To small avatar. | ||||
| 	ErrToSmallAvatar ErrorType = 5706 | ||||
|  | ||||
| 	// Photo not found. | ||||
| 	ErrPhotoNotFound ErrorType = 5708 | ||||
|  | ||||
| 	// Invalid Photo. | ||||
| 	ErrInvalidPhoto ErrorType = 5709 | ||||
|  | ||||
| 	// Invalid hash. | ||||
| 	ErrInvalidHash ErrorType = 5710 | ||||
| ) | ||||
|  | ||||
| // ErrorSubtype is the subtype of an error. | ||||
| @@ -946,3 +1000,31 @@ func (e AdsError) Is(target error) bool { | ||||
|  | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // AuthSilentTokenError struct. | ||||
| type AuthSilentTokenError struct { | ||||
| 	Token       string    `json:"token"` | ||||
| 	Code        ErrorType `json:"code"` | ||||
| 	Description string    `json:"description"` | ||||
| } | ||||
|  | ||||
| // Error returns the description of a AuthSilentTokenError. | ||||
| func (e AuthSilentTokenError) Error() string { | ||||
| 	return "api: " + e.Description | ||||
| } | ||||
|  | ||||
| // Is unwraps its first argument sequentially looking for an error that matches | ||||
| // the second. | ||||
| func (e AuthSilentTokenError) Is(target error) bool { | ||||
| 	var tError *AuthSilentTokenError | ||||
| 	if errors.As(target, &tError) { | ||||
| 		return e.Code == tError.Code && e.Description == tError.Description | ||||
| 	} | ||||
|  | ||||
| 	var tErrorType ErrorType | ||||
| 	if errors.As(target, &tErrorType) { | ||||
| 		return e.Code == tErrorType | ||||
| 	} | ||||
|  | ||||
| 	return false | ||||
| } | ||||
|   | ||||
							
								
								
									
										26
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/execute.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/execute.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,6 +1,11 @@ | ||||
| package api | ||||
|  | ||||
| import "encoding/json" | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
|  | ||||
| 	"github.com/vmihailenco/msgpack/v5" | ||||
| ) | ||||
|  | ||||
| // ExecuteWithArgs a universal method for calling a sequence of other methods | ||||
| // while saving and filtering interim results. | ||||
| @@ -22,10 +27,23 @@ func (vk *VK) ExecuteWithArgs(code string, params Params, obj interface{}) error | ||||
| 	} | ||||
|  | ||||
| 	resp, err := vk.Handler("execute", params, reqParams) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	jsonErr := json.Unmarshal(resp.Response, &obj) | ||||
| 	if jsonErr != nil { | ||||
| 		return jsonErr | ||||
| 	var decoderErr error | ||||
|  | ||||
| 	if vk.msgpack { | ||||
| 		dec := msgpack.NewDecoder(bytes.NewReader(resp.Response)) | ||||
| 		dec.SetCustomStructTag("json") | ||||
|  | ||||
| 		decoderErr = dec.Decode(&obj) | ||||
| 	} else { | ||||
| 		decoderErr = json.Unmarshal(resp.Response, &obj) | ||||
| 	} | ||||
|  | ||||
| 	if decoderErr != nil { | ||||
| 		return decoderErr | ||||
| 	} | ||||
|  | ||||
| 	if resp.ExecuteErrors != nil { | ||||
|   | ||||
							
								
								
									
										17
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/market.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/market.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -20,6 +20,7 @@ func (vk *VK) MarketAdd(params Params) (response MarketAddResponse, err error) { | ||||
| // MarketAddAlbumResponse struct. | ||||
| type MarketAddAlbumResponse struct { | ||||
| 	MarketAlbumID int `json:"market_album_id"` // Album ID | ||||
| 	AlbumsCount   int `json:"albums_count"` | ||||
| } | ||||
|  | ||||
| // MarketAddAlbum creates new collection of items. | ||||
| @@ -318,3 +319,19 @@ func (vk *VK) MarketSearch(params Params) (response MarketSearchResponse, err er | ||||
| 	err = vk.RequestUnmarshal("market.search", &response, params) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // MarketSearchItemsResponse struct. | ||||
| type MarketSearchItemsResponse struct { | ||||
| 	Count    int                       `json:"count"` | ||||
| 	ViewType int                       `json:"view_type"` | ||||
| 	Items    []object.MarketMarketItem `json:"items"` | ||||
| 	Groups   []object.GroupsGroup      `json:"groups,omitempty"` | ||||
| } | ||||
|  | ||||
| // MarketSearchItems method. | ||||
| // | ||||
| // https://vk.com/dev/market.searchItems | ||||
| func (vk *VK) MarketSearchItems(params Params) (response MarketSearchItemsResponse, err error) { | ||||
| 	err = vk.RequestUnmarshal("market.searchItems", &response, params) | ||||
| 	return | ||||
| } | ||||
|   | ||||
							
								
								
									
										103
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/marusia.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										103
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/marusia.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,103 @@ | ||||
| package api // import "github.com/SevereCloud/vksdk/v2/api" | ||||
|  | ||||
| import ( | ||||
| 	"github.com/SevereCloud/vksdk/v2/object" | ||||
| ) | ||||
|  | ||||
| // MarusiaGetPictureUploadLinkResponse struct. | ||||
| type MarusiaGetPictureUploadLinkResponse struct { | ||||
| 	PictureUploadLink string `json:"picture_upload_link"` // Link | ||||
| } | ||||
|  | ||||
| // MarusiaGetPictureUploadLink method. | ||||
| // | ||||
| // https://vk.com/dev/marusia_skill_docs10 | ||||
| func (vk *VK) MarusiaGetPictureUploadLink(params Params) (response MarusiaGetPictureUploadLinkResponse, err error) { | ||||
| 	err = vk.RequestUnmarshal("marusia.getPictureUploadLink", &response, params) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // MarusiaSavePictureResponse struct. | ||||
| type MarusiaSavePictureResponse struct { | ||||
| 	AppID   int `json:"app_id"` | ||||
| 	PhotoID int `json:"photo_id"` | ||||
| } | ||||
|  | ||||
| // MarusiaSavePicture method. | ||||
| // | ||||
| // https://vk.com/dev/marusia_skill_docs10 | ||||
| func (vk *VK) MarusiaSavePicture(params Params) (response MarusiaSavePictureResponse, err error) { | ||||
| 	err = vk.RequestUnmarshal("marusia.savePicture", &response, params) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // MarusiaGetPicturesResponse struct. | ||||
| type MarusiaGetPicturesResponse struct { | ||||
| 	Count int                     `json:"count"` | ||||
| 	Items []object.MarusiaPicture `json:"items"` | ||||
| } | ||||
|  | ||||
| // MarusiaGetPictures method. | ||||
| // | ||||
| // https://vk.com/dev/marusia_skill_docs10 | ||||
| func (vk *VK) MarusiaGetPictures(params Params) (response MarusiaGetPicturesResponse, err error) { | ||||
| 	err = vk.RequestUnmarshal("marusia.getPictures", &response, params) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // MarusiaDeletePicture delete picture. | ||||
| // | ||||
| // https://vk.com/dev/marusia_skill_docs10 | ||||
| func (vk *VK) MarusiaDeletePicture(params Params) (response int, err error) { | ||||
| 	err = vk.RequestUnmarshal("marusia.deletePicture", &response, params) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // MarusiaGetAudioUploadLinkResponse struct. | ||||
| type MarusiaGetAudioUploadLinkResponse struct { | ||||
| 	AudioUploadLink string `json:"audio_upload_link"` // Link | ||||
| } | ||||
|  | ||||
| // MarusiaGetAudioUploadLink method. | ||||
| // | ||||
| // https://vk.com/dev/marusia_skill_docs10 | ||||
| func (vk *VK) MarusiaGetAudioUploadLink(params Params) (response MarusiaGetAudioUploadLinkResponse, err error) { | ||||
| 	err = vk.RequestUnmarshal("marusia.getAudioUploadLink", &response, params) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // MarusiaCreateAudioResponse struct. | ||||
| type MarusiaCreateAudioResponse struct { | ||||
| 	ID    int    `json:"id"` | ||||
| 	Title string `json:"title"` | ||||
| } | ||||
|  | ||||
| // MarusiaCreateAudio method. | ||||
| // | ||||
| // https://vk.com/dev/marusia_skill_docs10 | ||||
| func (vk *VK) MarusiaCreateAudio(params Params) (response MarusiaCreateAudioResponse, err error) { | ||||
| 	err = vk.RequestUnmarshal("marusia.createAudio", &response, params) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // MarusiaGetAudiosResponse struct. | ||||
| type MarusiaGetAudiosResponse struct { | ||||
| 	Count  int                   `json:"count"` | ||||
| 	Audios []object.MarusiaAudio `json:"audios"` | ||||
| } | ||||
|  | ||||
| // MarusiaGetAudios method. | ||||
| // | ||||
| // https://vk.com/dev/marusia_skill_docs10 | ||||
| func (vk *VK) MarusiaGetAudios(params Params) (response MarusiaGetAudiosResponse, err error) { | ||||
| 	err = vk.RequestUnmarshal("marusia.getAudios", &response, params) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // MarusiaDeleteAudio delete audio. | ||||
| // | ||||
| // https://vk.com/dev/marusia_skill_docs10 | ||||
| func (vk *VK) MarusiaDeleteAudio(params Params) (response int, err error) { | ||||
| 	err = vk.RequestUnmarshal("marusia.deleteAudio", &response, params) | ||||
| 	return | ||||
| } | ||||
							
								
								
									
										26
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/messages.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/messages.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,7 +1,10 @@ | ||||
| package api // import "github.com/SevereCloud/vksdk/v2/api" | ||||
|  | ||||
| import ( | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/SevereCloud/vksdk/v2/object" | ||||
| 	"github.com/vmihailenco/msgpack/v5" | ||||
| ) | ||||
|  | ||||
| // MessagesAddChatUser adds a new user to a chat. | ||||
| @@ -31,11 +34,34 @@ func (vk *VK) MessagesCreateChat(params Params) (response int, err error) { | ||||
| // MessagesDeleteResponse struct. | ||||
| type MessagesDeleteResponse map[string]int | ||||
|  | ||||
| // DecodeMsgpack funcion. | ||||
| func (resp *MessagesDeleteResponse) DecodeMsgpack(dec *msgpack.Decoder) error { | ||||
| 	data, err := dec.DecodeRaw() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var respMap map[int]int | ||||
|  | ||||
| 	err = msgpack.Unmarshal(data, &respMap) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	*resp = make(MessagesDeleteResponse) | ||||
| 	for key, val := range respMap { | ||||
| 		(*resp)[strconv.Itoa(key)] = val | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // MessagesDelete deletes one or more messages. | ||||
| // | ||||
| // https://vk.com/dev/messages.delete | ||||
| func (vk *VK) MessagesDelete(params Params) (response MessagesDeleteResponse, err error) { | ||||
| 	err = vk.RequestUnmarshal("messages.delete", &response, params) | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										13
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/photos.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										13
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/photos.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -571,12 +571,13 @@ func (vk *VK) PhotosSaveOwnerCoverPhoto(params Params) (response PhotosSaveOwner | ||||
|  | ||||
| // PhotosSaveOwnerPhotoResponse struct. | ||||
| type PhotosSaveOwnerPhotoResponse struct { | ||||
| 	PhotoHash     string `json:"photo_hash"` | ||||
| 	PhotoSrc      string `json:"photo_src"` | ||||
| 	PhotoSrcBig   string `json:"photo_src_big"` | ||||
| 	PhotoSrcSmall string `json:"photo_src_small"` | ||||
| 	Saved         int    `json:"saved"` | ||||
| 	PostID        int    `json:"post_id"` | ||||
| 	PhotoHash string `json:"photo_hash"` | ||||
| 	// BUG(VK): returns false | ||||
| 	// PhotoSrc      string `json:"photo_src"` | ||||
| 	// PhotoSrcBig   string `json:"photo_src_big"` | ||||
| 	// PhotoSrcSmall string `json:"photo_src_small"` | ||||
| 	Saved  int `json:"saved"` | ||||
| 	PostID int `json:"post_id"` | ||||
| } | ||||
|  | ||||
| // PhotosSaveOwnerPhoto saves a profile or community photo. | ||||
|   | ||||
							
								
								
									
										54
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/upload.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										54
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/upload.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -959,3 +959,57 @@ func (vk *VK) UploadGroupImage(imageType string, file io.Reader) (response objec | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // UploadMarusiaPicture uploading picture. | ||||
| // | ||||
| // Limits: height not more than 600 px, | ||||
| // aspect ratio of at least 2:1. | ||||
| func (vk *VK) UploadMarusiaPicture(file io.Reader) (response MarusiaSavePictureResponse, err error) { | ||||
| 	uploadServer, err := vk.MarusiaGetPictureUploadLink(nil) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	bodyContent, err := vk.UploadFile(uploadServer.PictureUploadLink, file, "photo", "photo.jpg") | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	var handler object.MarusiaPictureUploadResponse | ||||
|  | ||||
| 	err = json.Unmarshal(bodyContent, &handler) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	photo, _ := json.Marshal(handler.Photo) | ||||
|  | ||||
| 	response, err = vk.MarusiaSavePicture(Params{ | ||||
| 		"server": handler.Server, | ||||
| 		"photo":  string(photo), | ||||
| 		"hash":   handler.Hash, | ||||
| 	}) | ||||
|  | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // UploadMarusiaAudio uploading audio. | ||||
| // | ||||
| // https://vk.com/dev/marusia_skill_docs10 | ||||
| func (vk *VK) UploadMarusiaAudio(file io.Reader) (response MarusiaCreateAudioResponse, err error) { | ||||
| 	uploadServer, err := vk.MarusiaGetAudioUploadLink(nil) | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	bodyContent, err := vk.UploadFile(uploadServer.AudioUploadLink, file, "file", "audio.mp3") | ||||
| 	if err != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	response, err = vk.MarusiaCreateAudio(Params{ | ||||
| 		"audio_meta": string(bodyContent), | ||||
| 	}) | ||||
|  | ||||
| 	return | ||||
| } | ||||
|   | ||||
							
								
								
									
										36
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										36
									
								
								vendor/github.com/SevereCloud/vksdk/v2/api/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,9 +1,8 @@ | ||||
| package api // import "github.com/SevereCloud/vksdk/v2/api" | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
|  | ||||
| 	"github.com/SevereCloud/vksdk/v2/object" | ||||
| 	"github.com/vmihailenco/msgpack/v5" | ||||
| ) | ||||
|  | ||||
| // UtilsCheckLinkResponse struct. | ||||
| @@ -89,17 +88,34 @@ func (vk *VK) UtilsGetShortLink(params Params) (response UtilsGetShortLinkRespon | ||||
| // UtilsResolveScreenNameResponse struct. | ||||
| type UtilsResolveScreenNameResponse object.UtilsDomainResolved | ||||
|  | ||||
| // UnmarshalJSON UtilsResolveScreenNameResponse. | ||||
| // | ||||
| // BUG(VK): UtilsResolveScreenNameResponse return []. | ||||
| func (resp *UtilsResolveScreenNameResponse) UnmarshalJSON(data []byte) error { | ||||
| 	var p object.UtilsDomainResolved | ||||
| 	err := p.UnmarshalJSON(data) | ||||
|  | ||||
| 	*resp = UtilsResolveScreenNameResponse(p) | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // DecodeMsgpack UtilsResolveScreenNameResponse. | ||||
| // | ||||
| // BUG(VK): UtilsResolveScreenNameResponse return []. | ||||
| func (resp *UtilsResolveScreenNameResponse) DecodeMsgpack(dec *msgpack.Decoder) error { | ||||
| 	var p object.UtilsDomainResolved | ||||
| 	err := p.DecodeMsgpack(dec) | ||||
|  | ||||
| 	*resp = UtilsResolveScreenNameResponse(p) | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // UtilsResolveScreenName detects a type of object (e.g., user, community, application) and its ID by screen name. | ||||
| // | ||||
| // https://vk.com/dev/utils.resolveScreenName | ||||
| func (vk *VK) UtilsResolveScreenName(params Params) (response UtilsResolveScreenNameResponse, err error) { | ||||
| 	rawResponse, err := vk.Request("utils.resolveScreenName", params) | ||||
| 	// Если короткое имя screen_name не занято, то будет возвращён пустой объект. | ||||
| 	if err != nil || string(rawResponse) == "[]" { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	err = json.Unmarshal(rawResponse, &response) | ||||
|  | ||||
| 	err = vk.RequestUnmarshal("utils.resolveScreenName", &response, params) | ||||
| 	return | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/doc.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -7,6 +7,6 @@ package vksdk | ||||
|  | ||||
| // Module constants. | ||||
| const ( | ||||
| 	Version = "2.10.0" | ||||
| 	Version = "2.13.1" | ||||
| 	API     = "5.131" | ||||
| ) | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -10,7 +10,7 @@ Long Poll настраивается автоматически. Вам не т | ||||
|  | ||||
| ### Версия API | ||||
|  | ||||
| Данная библиотека поддерживает версию API **5.122**. | ||||
| Данная библиотека поддерживает версию API **5.131**. | ||||
|  | ||||
| ### Инициализация | ||||
|  | ||||
|   | ||||
							
								
								
									
										58
									
								
								vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/longpoll.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										58
									
								
								vendor/github.com/SevereCloud/vksdk/v2/longpoll-bot/longpoll.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -8,8 +8,11 @@ package longpoll // import "github.com/SevereCloud/vksdk/v2/longpoll-bot" | ||||
| import ( | ||||
| 	"context" | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net/http" | ||||
| 	"strconv" | ||||
|  | ||||
| 	"github.com/SevereCloud/vksdk/v2" | ||||
| 	"github.com/SevereCloud/vksdk/v2/api" | ||||
| @@ -117,7 +120,7 @@ func (lp *LongPoll) check(ctx context.Context) (response Response, err error) { | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	err = json.NewDecoder(resp.Body).Decode(&response) | ||||
| 	response, err = parseResponse(resp.Body) | ||||
| 	if err != nil { | ||||
| 		return response, err | ||||
| 	} | ||||
| @@ -127,6 +130,59 @@ func (lp *LongPoll) check(ctx context.Context) (response Response, err error) { | ||||
| 	return response, err | ||||
| } | ||||
|  | ||||
| func parseResponse(reader io.Reader) (response Response, err error) { | ||||
| 	decoder := json.NewDecoder(reader) | ||||
| 	for decoder.More() { | ||||
| 		token, err := decoder.Token() | ||||
| 		if err != nil { | ||||
| 			if errors.Is(err, io.EOF) { | ||||
| 				break | ||||
| 			} | ||||
|  | ||||
| 			return response, err | ||||
| 		} | ||||
|  | ||||
| 		t, ok := token.(string) | ||||
| 		if !ok { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		switch t { | ||||
| 		case "failed": | ||||
| 			raw, err := decoder.Token() | ||||
| 			if err != nil { | ||||
| 				return response, err | ||||
| 			} | ||||
|  | ||||
| 			response.Failed = int(raw.(float64)) | ||||
| 		case "updates": | ||||
| 			var updates []events.GroupEvent | ||||
|  | ||||
| 			err = decoder.Decode(&updates) | ||||
| 			if err != nil { | ||||
| 				return response, err | ||||
| 			} | ||||
|  | ||||
| 			response.Updates = updates | ||||
| 		case "ts": | ||||
| 			// can be a number in the response with "failed" field: {"ts":8,"failed":1} | ||||
| 			// or string, e.g. {"ts":"8","updates":[]} | ||||
| 			rawTs, err := decoder.Token() | ||||
| 			if err != nil { | ||||
| 				return response, err | ||||
| 			} | ||||
|  | ||||
| 			if ts, isNumber := rawTs.(float64); isNumber { | ||||
| 				response.Ts = strconv.Itoa(int(ts)) | ||||
| 			} else { | ||||
| 				response.Ts = rawTs.(string) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return response, err | ||||
| } | ||||
|  | ||||
| func (lp *LongPoll) checkResponse(response Response) (err error) { | ||||
| 	switch response.Failed { | ||||
| 	case 0: | ||||
|   | ||||
							
								
								
									
										34
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/account.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										34
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/account.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -62,21 +62,24 @@ type AccountOffer struct { | ||||
|  | ||||
| // AccountAccountCounters struct. | ||||
| type AccountAccountCounters struct { | ||||
| 	AppRequests            int `json:"app_requests"`            // New app requests number | ||||
| 	Events                 int `json:"events"`                  // New events number | ||||
| 	Friends                int `json:"friends"`                 // New friends requests number | ||||
| 	FriendsRecommendations int `json:"friends_recommendations"` // New friends recommendations number | ||||
| 	FriendsSuggestions     int `json:"friends_suggestions"`     // New friends suggestions number | ||||
| 	Gifts                  int `json:"gifts"`                   // New gifts number | ||||
| 	Groups                 int `json:"groups"`                  // New groups number | ||||
| 	Messages               int `json:"messages"`                // New messages number | ||||
| 	Notifications          int `json:"notifications"`           // New notifications number | ||||
| 	Photos                 int `json:"photos"`                  // New photo tags number | ||||
| 	SDK                    int `json:"sdk"`                     // New SDK number | ||||
| 	MenuDiscoverBadge      int `json:"menu_discover_badge"`     // New menu discover badge number | ||||
| 	MenuClipsBadge         int `json:"menu_clips_badge"`        // New menu clips badge number | ||||
| 	Videos                 int `json:"videos"`                  // New video tags number | ||||
| 	Faves                  int `json:"faves"`                   // New faves number | ||||
| 	AppRequests              int `json:"app_requests"`            // New app requests number | ||||
| 	Events                   int `json:"events"`                  // New events number | ||||
| 	Friends                  int `json:"friends"`                 // New friends requests number | ||||
| 	FriendsRecommendations   int `json:"friends_recommendations"` // New friends recommendations number | ||||
| 	FriendsSuggestions       int `json:"friends_suggestions"`     // New friends suggestions number | ||||
| 	Gifts                    int `json:"gifts"`                   // New gifts number | ||||
| 	Groups                   int `json:"groups"`                  // New groups number | ||||
| 	Messages                 int `json:"messages"`                // New messages number | ||||
| 	Notifications            int `json:"notifications"`           // New notifications number | ||||
| 	Photos                   int `json:"photos"`                  // New photo tags number | ||||
| 	SDK                      int `json:"sdk"`                     // New SDK number | ||||
| 	MenuDiscoverBadge        int `json:"menu_discover_badge"`     // New menu discover badge number | ||||
| 	MenuClipsBadge           int `json:"menu_clips_badge"`        // New menu clips badge number | ||||
| 	Videos                   int `json:"videos"`                  // New video tags number | ||||
| 	Faves                    int `json:"faves"`                   // New faves number | ||||
| 	Calls                    int `json:"calls"`                   // New calls number | ||||
| 	MenuSuperappFriendsBadge int `json:"menu_superapp_friends_badge"` | ||||
| 	MenuNewClipsBadge        int `json:"menu_new_clips_badge"` | ||||
| } | ||||
|  | ||||
| // AccountInfo struct. | ||||
| @@ -107,6 +110,7 @@ type AccountInfo struct { | ||||
| 	IsLiveStreamingEnabled    BaseBoolInt       `json:"is_live_streaming_enabled"` | ||||
| 	IsNewLiveStreamingEnabled BaseBoolInt       `json:"is_new_live_streaming_enabled"` | ||||
| 	LinkRedirects             map[string]string `json:"link_redirects"` | ||||
| 	VkPayEndpointV2           string            `json:"vk_pay_endpoint_v2"` | ||||
| } | ||||
|  | ||||
| // AccountPushSettings struct. | ||||
|   | ||||
							
								
								
									
										20
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/ads.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										20
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/ads.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -8,12 +8,13 @@ type AdsAccesses struct { | ||||
|  | ||||
| // AdsAccount struct. | ||||
| type AdsAccount struct { | ||||
| 	AccessRole    string      `json:"access_role"` | ||||
| 	AccountID     int         `json:"account_id"` // Account ID | ||||
| 	AccountName   string      `json:"account_name"` | ||||
| 	AccountStatus BaseBoolInt `json:"account_status"` // Information whether account is active | ||||
| 	CanViewBudget BaseBoolInt `json:"can_view_budget"` | ||||
| 	AccountType   string      `json:"account_type"` | ||||
| 	AccessRole                  string      `json:"access_role"` | ||||
| 	AccountID                   int         `json:"account_id"` // Account ID | ||||
| 	AccountName                 string      `json:"account_name"` | ||||
| 	AccountStatus               BaseBoolInt `json:"account_status"` // Information whether account is active | ||||
| 	CanViewBudget               BaseBoolInt `json:"can_view_budget"` | ||||
| 	AdNetworkAllowedPotentially BaseBoolInt `json:"ad_network_allowed_potentially"` | ||||
| 	AccountType                 string      `json:"account_type"` | ||||
| } | ||||
|  | ||||
| // AdsAdLayout struct. | ||||
| @@ -318,3 +319,10 @@ type AdsPromotedPostReach struct { | ||||
| 	VideoViews75p    int `json:"video_views_75p"`   // Video views for 75 percent | ||||
| 	VideoViewsStart  int `json:"video_views_start"` // Video starts | ||||
| } | ||||
|  | ||||
| // AdsMusician struct. | ||||
| type AdsMusician struct { | ||||
| 	ID     int    `json:"id"`               // Targeting music artist ID | ||||
| 	Name   string `json:"name"`             // Music artist name | ||||
| 	Avatar string `json:"avatar,omitempty"` // Music artist photo. | ||||
| } | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/apps.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/apps.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -60,6 +60,7 @@ type AppsApp struct { | ||||
| 	IsNew           BaseBoolInt `json:"is_new"` | ||||
| 	New             BaseBoolInt `json:"new"` | ||||
| 	IsInstalled     BaseBoolInt `json:"is_installed"` | ||||
| 	HasVkConnect    BaseBoolInt `json:"has_vk_connect"` | ||||
| 	LeaderboardType int         `json:"leaderboard_type"` | ||||
| 	MembersCount    int         `json:"members_count"` // Members number | ||||
| 	PlatformID      int         `json:"platform_id"`   // Application ID in store | ||||
| @@ -78,7 +79,7 @@ type AppsApp struct { | ||||
|  | ||||
| 	// mobile_controls_type = 0 - прозрачный элемент управления поверх области с игрой; | ||||
| 	// mobile_controls_type = 1 - чёрная полоска над областью с игрой; | ||||
| 	// mobile_controls_type = 2 - только для vk apps, без контроллов. | ||||
| 	// mobile_controls_type = 2 - только для vk apps, без элементов управления'. | ||||
| 	MobileControlsType int `json:"mobile_controls_type"` | ||||
|  | ||||
| 	// mobile_view_support_type = 0 - игра не использует нижнюю часть экрана на iPhoneX, черная полоса есть. | ||||
|   | ||||
							
								
								
									
										17
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/auth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/auth.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| package object // import "github.com/SevereCloud/vksdk/v2/object" | ||||
|  | ||||
| // AuthSilentTokenProfile struct. | ||||
| type AuthSilentTokenProfile struct { | ||||
| 	Token          string      `json:"token"` | ||||
| 	Expires        int         `json:"expires"` | ||||
| 	FirstName      string      `json:"first_name"` | ||||
| 	LastName       string      `json:"last_name"` | ||||
| 	Photo50        string      `json:"photo_50"` | ||||
| 	Photo100       string      `json:"photo_100"` | ||||
| 	Photo200       string      `json:"photo_200"` | ||||
| 	Phone          string      `json:"phone"` | ||||
| 	PhoneValidated interface{} `json:"phone_validated"` // int | bool | ||||
| 	UserID         int         `json:"user_id"` | ||||
| 	IsPartial      BaseBoolInt `json:"is_partial"` | ||||
| 	IsService      BaseBoolInt `json:"is_service"` | ||||
| } | ||||
							
								
								
									
										6
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/database.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/database.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -4,9 +4,9 @@ package object // import "github.com/SevereCloud/vksdk/v2/object" | ||||
| type DatabaseCity struct { | ||||
| 	ID        int         `json:"id"`    // City ID | ||||
| 	Title     string      `json:"title"` // City title | ||||
| 	Area      string      `json:"area"` | ||||
| 	Region    string      `json:"region"` | ||||
| 	Important BaseBoolInt `json:"important"` | ||||
| 	Area      string      `json:"area,omitempty"` | ||||
| 	Region    string      `json:"region,omitempty"` | ||||
| 	Important BaseBoolInt `json:"important,omitempty"` | ||||
| } | ||||
|  | ||||
| // DatabaseMetroStation  struct. | ||||
|   | ||||
							
								
								
									
										325
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/groups.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										325
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/groups.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,9 +1,13 @@ | ||||
| package object // import "github.com/SevereCloud/vksdk/v2/object" | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
|  | ||||
| 	"github.com/vmihailenco/msgpack/v5" | ||||
| 	"github.com/vmihailenco/msgpack/v5/msgpcode" | ||||
| ) | ||||
|  | ||||
| // GroupsAddress WorkInfoStatus of information about timetable. | ||||
| @@ -110,112 +114,113 @@ const ( | ||||
|  | ||||
| // GroupsGroup struct. | ||||
| type GroupsGroup struct { | ||||
| 	AdminLevel   int              `json:"admin_level"` | ||||
| 	Deactivated  string           `json:"deactivated"` // Information whether community is banned | ||||
| 	FinishDate   int              `json:"finish_date"` // Finish date in Unixtime format | ||||
| 	ID           int              `json:"id"`          // Community ID | ||||
| 	Name         string           `json:"name"`        // Community name | ||||
| 	Photo100     string           `json:"photo_100"`   // URL of square photo of the community with 100 pixels in width | ||||
| 	Photo200     string           `json:"photo_200"`   // URL of square photo of the community with 200 pixels in width | ||||
| 	Photo50      string           `json:"photo_50"`    // URL of square photo of the community with 50 pixels in width | ||||
| 	ScreenName   string           `json:"screen_name"` // Domain of the community page | ||||
| 	StartDate    int              `json:"start_date"`  // Start date in Unixtime format | ||||
| 	Type         string           `json:"type"` | ||||
| 	Market       GroupsMarketInfo `json:"market"` | ||||
| 	MemberStatus int              `json:"member_status"` // Current user's member status | ||||
| 	IsClosed     int              `json:"is_closed"` | ||||
| 	City         BaseObject       `json:"city"` | ||||
| 	Country      BaseCountry      `json:"country"` | ||||
| 	AdminLevel   int              `json:"admin_level,omitempty"` | ||||
| 	Deactivated  string           `json:"deactivated,omitempty"` // Information whether community is banned | ||||
| 	FinishDate   int              `json:"finish_date,omitempty"` // Finish date in Unixtime format | ||||
| 	Photo100     string           `json:"photo_100,omitempty"`   // URL of square photo of the community with 100 pixels in width | ||||
| 	Photo200     string           `json:"photo_200,omitempty"`   // URL of square photo of the community with 200 pixels in width | ||||
| 	Photo50      string           `json:"photo_50,omitempty"`    // URL of square photo of the community with 50 pixels in width | ||||
| 	StartDate    int              `json:"start_date,omitempty"`  // Start date in Unixtime format | ||||
| 	Market       GroupsMarketInfo `json:"market,omitempty"` | ||||
| 	MemberStatus int              `json:"member_status,omitempty"` // Current user's member status | ||||
| 	City         BaseObject       `json:"city,omitempty"` | ||||
| 	Country      BaseCountry      `json:"country,omitempty"` | ||||
|  | ||||
| 	// Information whether current user is administrator. | ||||
| 	IsAdmin BaseBoolInt `json:"is_admin"` | ||||
|  | ||||
| 	// Information whether current user is advertiser. | ||||
| 	IsAdvertiser BaseBoolInt `json:"is_advertiser"` | ||||
| 	IsAdvertiser BaseBoolInt `json:"is_advertiser,omitempty"` | ||||
|  | ||||
| 	// Information whether current user is member. | ||||
| 	IsMember BaseBoolInt `json:"is_member"` | ||||
| 	IsMember BaseBoolInt `json:"is_member,omitempty"` | ||||
|  | ||||
| 	// Information whether community is in faves. | ||||
| 	IsFavorite BaseBoolInt `json:"is_favorite"` | ||||
| 	IsFavorite BaseBoolInt `json:"is_favorite,omitempty"` | ||||
|  | ||||
| 	// Information whether community is adult. | ||||
| 	IsAdult BaseBoolInt `json:"is_adult"` | ||||
| 	IsAdult BaseBoolInt `json:"is_adult,omitempty"` | ||||
|  | ||||
| 	// Information whether current user is subscribed. | ||||
| 	IsSubscribed BaseBoolInt `json:"is_subscribed"` | ||||
| 	IsSubscribed BaseBoolInt `json:"is_subscribed,omitempty"` | ||||
|  | ||||
| 	// Information whether current user can post on community's wall. | ||||
| 	CanPost BaseBoolInt `json:"can_post"` | ||||
| 	CanPost BaseBoolInt `json:"can_post,omitempty"` | ||||
|  | ||||
| 	// Information whether current user can see all posts on community's wall. | ||||
| 	CanSeeAllPosts BaseBoolInt `json:"can_see_all_posts"` | ||||
| 	CanSeeAllPosts BaseBoolInt `json:"can_see_all_posts,omitempty"` | ||||
|  | ||||
| 	// Information whether current user can create topic. | ||||
| 	CanCreateTopic BaseBoolInt `json:"can_create_topic"` | ||||
| 	CanCreateTopic BaseBoolInt `json:"can_create_topic,omitempty"` | ||||
|  | ||||
| 	// Information whether current user can upload video. | ||||
| 	CanUploadVideo BaseBoolInt `json:"can_upload_video"` | ||||
| 	CanUploadVideo BaseBoolInt `json:"can_upload_video,omitempty"` | ||||
|  | ||||
| 	// Information whether current user can upload doc. | ||||
| 	CanUploadDoc BaseBoolInt `json:"can_upload_doc"` | ||||
| 	CanUploadDoc BaseBoolInt `json:"can_upload_doc,omitempty"` | ||||
|  | ||||
| 	// Information whether community has photo. | ||||
| 	HasPhoto BaseBoolInt `json:"has_photo"` | ||||
| 	HasPhoto BaseBoolInt `json:"has_photo,omitempty"` | ||||
|  | ||||
| 	// Information whether current user can send a message to community. | ||||
| 	CanMessage BaseBoolInt `json:"can_message"` | ||||
| 	CanMessage BaseBoolInt `json:"can_message,omitempty"` | ||||
|  | ||||
| 	// Information whether community can send a message to current user. | ||||
| 	IsMessagesBlocked BaseBoolInt `json:"is_messages_blocked"` | ||||
| 	IsMessagesBlocked BaseBoolInt `json:"is_messages_blocked,omitempty"` | ||||
|  | ||||
| 	// Information whether community can send notifications by phone number to current user. | ||||
| 	CanSendNotify BaseBoolInt `json:"can_send_notify"` | ||||
| 	CanSendNotify BaseBoolInt `json:"can_send_notify,omitempty"` | ||||
|  | ||||
| 	// Information whether current user is subscribed to podcasts. | ||||
| 	IsSubscribedPodcasts BaseBoolInt `json:"is_subscribed_podcasts"` | ||||
| 	IsSubscribedPodcasts BaseBoolInt `json:"is_subscribed_podcasts,omitempty"` | ||||
|  | ||||
| 	// Owner in whitelist or not. | ||||
| 	CanSubscribePodcasts BaseBoolInt `json:"can_subscribe_podcasts"` | ||||
| 	CanSubscribePodcasts BaseBoolInt `json:"can_subscribe_podcasts,omitempty"` | ||||
|  | ||||
| 	// Can subscribe to wall. | ||||
| 	CanSubscribePosts BaseBoolInt `json:"can_subscribe_posts"` | ||||
| 	CanSubscribePosts BaseBoolInt `json:"can_subscribe_posts,omitempty"` | ||||
|  | ||||
| 	// Information whether community has market app. | ||||
| 	HasMarketApp        BaseBoolInt `json:"has_market_app"` | ||||
| 	IsHiddenFromFeed    BaseBoolInt `json:"is_hidden_from_feed"` | ||||
| 	IsMarketCartEnabled BaseBoolInt `json:"is_market_cart_enabled"` | ||||
| 	Verified            BaseBoolInt `json:"verified"` // Information whether community is verified | ||||
| 	HasMarketApp        BaseBoolInt `json:"has_market_app,omitempty"` | ||||
| 	IsHiddenFromFeed    BaseBoolInt `json:"is_hidden_from_feed,omitempty"` | ||||
| 	IsMarketCartEnabled BaseBoolInt `json:"is_market_cart_enabled,omitempty"` | ||||
| 	Verified            BaseBoolInt `json:"verified,omitempty"` // Information whether community is verified | ||||
|  | ||||
| 	// Information whether the community has a fire pictogram. | ||||
| 	Trending     BaseBoolInt         `json:"trending"` | ||||
| 	Description  string              `json:"description"`   // Community description | ||||
| 	WikiPage     string              `json:"wiki_page"`     // Community's main wiki page title | ||||
| 	MembersCount int                 `json:"members_count"` // Community members number | ||||
| 	Counters     GroupsCountersGroup `json:"counters"` | ||||
| 	Cover        GroupsCover         `json:"cover"` | ||||
| 	Trending     BaseBoolInt         `json:"trending,omitempty"` | ||||
| 	Description  string              `json:"description,omitempty"`   // Community description | ||||
| 	WikiPage     string              `json:"wiki_page,omitempty"`     // Community's main wiki page title | ||||
| 	MembersCount int                 `json:"members_count,omitempty"` // Community members number | ||||
| 	Counters     GroupsCountersGroup `json:"counters,omitempty"` | ||||
| 	Cover        GroupsCover         `json:"cover,omitempty"` | ||||
|  | ||||
| 	// Type of group, start date of event or category of public page. | ||||
| 	Activity        string               `json:"activity"` | ||||
| 	FixedPost       int                  `json:"fixed_post"`    // Fixed post ID | ||||
| 	Status          string               `json:"status"`        // Community status | ||||
| 	MainAlbumID     int                  `json:"main_album_id"` // Community's main photo album ID | ||||
| 	Links           []GroupsLinksItem    `json:"links"` | ||||
| 	Contacts        []GroupsContactsItem `json:"contacts"` | ||||
| 	Site            string               `json:"site"` // Community's website | ||||
| 	MainSection     int                  `json:"main_section"` | ||||
| 	OnlineStatus    GroupsOnlineStatus   `json:"online_status"` // Status of replies in community messages | ||||
| 	AgeLimits       int                  `json:"age_limits"`    // Information whether age limit | ||||
| 	BanInfo         GroupsGroupBanInfo   `json:"ban_info"`      // User ban info | ||||
| 	Addresses       GroupsAddressesInfo  `json:"addresses"`     // Info about addresses in Groups | ||||
| 	LiveCovers      GroupsLiveCovers     `json:"live_covers"` | ||||
| 	CropPhoto       UsersCropPhoto       `json:"crop_photo"` | ||||
| 	Wall            int                  `json:"wall"` | ||||
| 	ActionButton    GroupsActionButton   `json:"action_button"` | ||||
| 	TrackCode       string               `json:"track_code"` | ||||
| 	PublicDateLabel string               `json:"public_date_label"` | ||||
| 	AuthorID        int                  `json:"author_id"` | ||||
| 	Phone           string               `json:"phone"` | ||||
| 	Activity        string               `json:"activity,omitempty"` | ||||
| 	FixedPost       int                  `json:"fixed_post,omitempty"`    // Fixed post ID | ||||
| 	Status          string               `json:"status,omitempty"`        // Community status | ||||
| 	MainAlbumID     int                  `json:"main_album_id,omitempty"` // Community's main photo album ID | ||||
| 	Links           []GroupsLinksItem    `json:"links,omitempty"` | ||||
| 	Contacts        []GroupsContactsItem `json:"contacts,omitempty"` | ||||
| 	Site            string               `json:"site,omitempty"` // Community's website | ||||
| 	MainSection     int                  `json:"main_section,omitempty"` | ||||
| 	OnlineStatus    GroupsOnlineStatus   `json:"online_status,omitempty"` // Status of replies in community messages | ||||
| 	AgeLimits       int                  `json:"age_limits,omitempty"`    // Information whether age limit | ||||
| 	BanInfo         GroupsGroupBanInfo   `json:"ban_info,omitempty"`      // User ban info | ||||
| 	Addresses       GroupsAddressesInfo  `json:"addresses,omitempty"`     // Info about addresses in Groups | ||||
| 	LiveCovers      GroupsLiveCovers     `json:"live_covers,omitempty"` | ||||
| 	CropPhoto       UsersCropPhoto       `json:"crop_photo,omitempty"` | ||||
| 	Wall            int                  `json:"wall,omitempty"` | ||||
| 	ActionButton    GroupsActionButton   `json:"action_button,omitempty"` | ||||
| 	TrackCode       string               `json:"track_code,omitempty"` | ||||
| 	PublicDateLabel string               `json:"public_date_label,omitempty"` | ||||
| 	AuthorID        int                  `json:"author_id,omitempty"` | ||||
| 	Phone           string               `json:"phone,omitempty"` | ||||
| 	Like            GroupsGroupLike      `json:"like"` | ||||
| } | ||||
|  | ||||
| // ToMention return mention. | ||||
| @@ -223,6 +228,18 @@ func (group GroupsGroup) ToMention() string { | ||||
| 	return fmt.Sprintf("[club%d|%s]", group.ID, group.Name) | ||||
| } | ||||
|  | ||||
| // GroupsGroupLike struct. | ||||
| type GroupsGroupLike struct { | ||||
| 	IsLiked BaseBoolInt            `json:"is_liked"` | ||||
| 	Friends GroupsGroupLikeFriends `json:"friends"` | ||||
| } | ||||
|  | ||||
| // GroupsGroupLikeFriends struct. | ||||
| type GroupsGroupLikeFriends struct { | ||||
| 	Count   int   `json:"count"` | ||||
| 	Preview []int `json:"preview"` | ||||
| } | ||||
|  | ||||
| // GroupsLiveCovers struct. | ||||
| type GroupsLiveCovers struct { | ||||
| 	IsEnabled  BaseBoolInt `json:"is_enabled"` | ||||
| @@ -275,16 +292,70 @@ type GroupsContactsItem struct { | ||||
|  | ||||
| // GroupsCountersGroup struct. | ||||
| type GroupsCountersGroup struct { | ||||
| 	Addresses  int `json:"addresses"`  // Addresses number | ||||
| 	Albums     int `json:"albums"`     // Photo albums number | ||||
| 	Articles   int `json:"articles"`   // Articles number | ||||
| 	Audios     int `json:"audios"`     // Audios number | ||||
| 	Docs       int `json:"docs"`       // Docs number | ||||
| 	Market     int `json:"market"`     // Market items number | ||||
| 	Photos     int `json:"photos"`     // Photos number | ||||
| 	Topics     int `json:"topics"`     // Topics number | ||||
| 	Videos     int `json:"videos"`     // Videos number | ||||
| 	Narratives int `json:"narratives"` // Narratives number | ||||
| 	Addresses      int `json:"addresses"`       // Addresses number | ||||
| 	Albums         int `json:"albums"`          // Photo albums number | ||||
| 	Articles       int `json:"articles"`        // Articles number | ||||
| 	Audios         int `json:"audios"`          // Audios number | ||||
| 	Docs           int `json:"docs"`            // Docs number | ||||
| 	Market         int `json:"market"`          // Market items number | ||||
| 	Photos         int `json:"photos"`          // Photos number | ||||
| 	Topics         int `json:"topics"`          // Topics number | ||||
| 	Videos         int `json:"videos"`          // Videos number | ||||
| 	Narratives     int `json:"narratives"`      // Narratives number | ||||
| 	Clips          int `json:"clips"`           // Clips number | ||||
| 	ClipsFollowers int `json:"clips_followers"` // Clips followers number | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON GroupsCountersGroup. | ||||
| // | ||||
| // BUG(VK): GroupsCountersGroup return []. | ||||
| func (personal *GroupsCountersGroup) UnmarshalJSON(data []byte) error { | ||||
| 	if bytes.Equal(data, []byte("[]")) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	type renamedGroupsCountersGroup GroupsCountersGroup | ||||
|  | ||||
| 	var r renamedGroupsCountersGroup | ||||
|  | ||||
| 	err := json.Unmarshal(data, &r) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	*personal = GroupsCountersGroup(r) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // DecodeMsgpack GroupsCountersGroup. | ||||
| // | ||||
| // BUG(VK): GroupsCountersGroup return []. | ||||
| func (personal *GroupsCountersGroup) DecodeMsgpack(dec *msgpack.Decoder) error { | ||||
| 	data, err := dec.DecodeRaw() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if bytes.Equal(data, []byte{msgpcode.FixedArrayLow}) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	type renamedGroupsCountersGroup GroupsCountersGroup | ||||
|  | ||||
| 	var r renamedGroupsCountersGroup | ||||
|  | ||||
| 	d := msgpack.NewDecoder(bytes.NewReader(data)) | ||||
| 	d.SetCustomStructTag("json") | ||||
|  | ||||
| 	err = d.Decode(&r) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	*personal = GroupsCountersGroup(r) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // GroupsCover struct. | ||||
| @@ -479,6 +550,70 @@ type GroupsGroupSettings struct { | ||||
| 	SecondarySection int                  `json:"secondary_section"` | ||||
| 	ActionButton     GroupsActionButton   `json:"action_button"` | ||||
| 	Phone            string               `json:"phone"` | ||||
|  | ||||
| 	RecognizePhoto int `json:"recognize_photo"` | ||||
|  | ||||
| 	MarketServices GroupsMarketServices `json:"market_services"` | ||||
| 	Narratives     int                  `json:"narratives"` | ||||
| 	Clips          int                  `json:"clips"` | ||||
| 	Textlives      int                  `json:"textlives"` | ||||
| 	Youla          GroupsYoula          `json:"youla"` | ||||
| } | ||||
|  | ||||
| // GroupsMarketServices struct. | ||||
| type GroupsMarketServices struct { | ||||
| 	Enabled         BaseBoolInt         `json:"enabled"` | ||||
| 	CanMessage      BaseBoolInt         `json:"can_message"` | ||||
| 	CommentsEnabled BaseBoolInt         `json:"comments_enabled"` | ||||
| 	ContactID       int                 `json:"contact_id"` | ||||
| 	Currency        MarketCurrency      `json:"currency"` | ||||
| 	ViewType        GroupsSelectedItems `json:"view_type"` | ||||
| 	BlockName       GroupsSelectedItems `json:"block_name"` | ||||
| 	ButtonLabel     GroupsSelectedItems `json:"button_label"` | ||||
| } | ||||
|  | ||||
| // GroupsSelectedItems struct. | ||||
| type GroupsSelectedItems struct { | ||||
| 	SelectedItemID int64                `json:"selected_item_id"` | ||||
| 	Items          []BaseObjectWithName `json:"items"` | ||||
| } | ||||
|  | ||||
| // GroupsYoula struct. | ||||
| type GroupsYoula struct { | ||||
| 	CategoryTree  GroupsYoulaCategory `json:"category_tree"` | ||||
| 	GroupSettings GroupsYoulaSettings `json:"group_settings"` | ||||
| } | ||||
|  | ||||
| // GroupsYoulaCategory struct. | ||||
| type GroupsYoulaCategory struct { | ||||
| 	ID            int                      `json:"id"` | ||||
| 	Title         string                   `json:"title"` | ||||
| 	Subcategories []GroupsYoulaSubcategory `json:"subcategories"` | ||||
| } | ||||
|  | ||||
| // GroupsYoulaSubcategory struct. | ||||
| type GroupsYoulaSubcategory struct { | ||||
| 	ID            int                      `json:"id"` | ||||
| 	Title         string                   `json:"title"` | ||||
| 	ParentID      int                      `json:"parent_id"` | ||||
| 	Subcategories []GroupsYoulaSubcategory `json:"subcategories"` | ||||
| } | ||||
|  | ||||
| // GroupsYoulaSettings struct. | ||||
| type GroupsYoulaSettings struct { | ||||
| 	IsActive              BaseBoolInt `json:"is_active"` | ||||
| 	IsModerated           BaseBoolInt `json:"is_moderated"` | ||||
| 	ShowModerationSetting BaseBoolInt `json:"show_moderation_setting"` | ||||
| 	ModerationStatus      int         `json:"moderation_status"` | ||||
| 	DeclineReason         string      `json:"decline_reason"` | ||||
| 	GroupMode             int         `json:"group_mode"` | ||||
| 	SelectedCategoryIDS   []int       `json:"selected_category_ids"` | ||||
| 	Lat                   float64     `json:"lat"` | ||||
| 	Long                  float64     `json:"long"` | ||||
| 	Radius                float64     `json:"radius"` | ||||
| 	RadiusArea            string      `json:"radius_area"` | ||||
| 	Address               string      `json:"address"` | ||||
| 	Radiuses              []float64   `json:"radiuses"` | ||||
| } | ||||
|  | ||||
| // GroupsSectionsList struct. | ||||
| @@ -532,6 +667,53 @@ func (g *GroupsSectionsList) UnmarshalJSON(data []byte) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // DecodeMsgpack need for decode dynamic array (Example: [1, "Фотографии"]) to struct. | ||||
| func (g *GroupsSectionsList) DecodeMsgpack(dec *msgpack.Decoder) error { | ||||
| 	data, err := dec.DecodeRaw() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var alias []interface{} | ||||
|  | ||||
| 	err = msgpack.Unmarshal(data, &alias) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if len(alias) != 2 { | ||||
| 		return &json.UnmarshalTypeError{ | ||||
| 			Value: string(data), | ||||
| 			Type:  reflect.TypeOf((*GroupsSectionsList)(nil)), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	id, ok := alias[0].(int8) | ||||
| 	if !ok { | ||||
| 		return &json.UnmarshalTypeError{ | ||||
| 			Value:  string(data), | ||||
| 			Type:   reflect.TypeOf((*GroupsSectionsList)(nil)), | ||||
| 			Struct: "GroupsSectionsList", | ||||
| 			Field:  "ID", | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	name, ok := alias[1].(string) | ||||
| 	if !ok { | ||||
| 		return &json.UnmarshalTypeError{ | ||||
| 			Value:  string(data), | ||||
| 			Type:   reflect.TypeOf((*GroupsSectionsList)(nil)), | ||||
| 			Struct: "GroupsSectionsList", | ||||
| 			Field:  "Name", | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	g.ID = int(id) | ||||
| 	g.Name = name | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // GroupsActionType for action_button in groups. | ||||
| type GroupsActionType string | ||||
|  | ||||
| @@ -685,7 +867,10 @@ type GroupsLongPollServer struct { | ||||
| 	Ts     string `json:"ts"`     // Number of the last event | ||||
| } | ||||
|  | ||||
| // TODO: func (g GroupsLongPollServer) GetURL() string { | ||||
| // GetURL return link. | ||||
| func (lp GroupsLongPollServer) GetURL(wait int) string { | ||||
| 	return fmt.Sprintf("%s?act=a_check&key=%s&ts=%s&wait=%d", lp.Server, lp.Key, lp.Ts, wait) | ||||
| } | ||||
|  | ||||
| // GroupsLongPollSettings struct. | ||||
| type GroupsLongPollSettings struct { | ||||
| @@ -714,12 +899,14 @@ type GroupsMarketInfo struct { | ||||
| 	Enabled         BaseBoolInt       `json:"enabled"`                 // Information whether the market is enabled | ||||
| 	CommentsEnabled BaseBoolInt       `json:"comments_enabled,omitempty"` | ||||
| 	CanMessage      BaseBoolInt       `json:"can_message,omitempty"` | ||||
| 	IsHsEnabled     BaseBoolInt       `json:"is_hs_enabled,omitempty"` | ||||
| 	MainAlbumID     int               `json:"main_album_id,omitempty"` // Main market album ID | ||||
| 	PriceMax        string            `json:"price_max,omitempty"`     // Maximum price | ||||
| 	PriceMin        string            `json:"price_min,omitempty"`     // Minimum price | ||||
| 	Wiki            PagesWikipageFull `json:"wiki,omitempty"` | ||||
| 	CityIDs         []int             `json:"city_ids"` | ||||
| 	CountryIDs      []int             `json:"country_ids,omitempty"` | ||||
| 	MinOrderPrice   MarketPrice       `json:"min_order_price,omitempty"` | ||||
| } | ||||
|  | ||||
| // GroupsGroupRole Role type. | ||||
|   | ||||
							
								
								
									
										65
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/market.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										65
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/market.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -4,6 +4,9 @@ import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/vmihailenco/msgpack/v5" | ||||
| 	"github.com/vmihailenco/msgpack/v5/msgpcode" | ||||
| ) | ||||
|  | ||||
| // Information whether the MarketMarketItem is available. | ||||
| @@ -28,6 +31,8 @@ type MarketMarketAlbum struct { | ||||
| 	Photo       PhotosPhoto `json:"photo"` | ||||
| 	Title       string      `json:"title"`        // Market album title | ||||
| 	UpdatedTime int         `json:"updated_time"` // Date when album has been updated last time in Unixtime | ||||
| 	IsMain      BaseBoolInt `json:"is_main"` | ||||
| 	IsHidden    BaseBoolInt `json:"is_hidden"` | ||||
| } | ||||
|  | ||||
| // ToAttachment return attachment format. | ||||
| @@ -98,6 +103,36 @@ func (market *MarketMarketItem) UnmarshalJSON(data []byte) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // DecodeMsgpack MarketMarketItem. | ||||
| // | ||||
| // BUG(VK): https://github.com/SevereCloud/vksdk/issues/147 | ||||
| func (market *MarketMarketItem) DecodeMsgpack(dec *msgpack.Decoder) error { | ||||
| 	data, err := dec.DecodeRaw() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if bytes.Equal(data, []byte{msgpcode.False}) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	type renamedMarketMarketItem MarketMarketItem | ||||
|  | ||||
| 	var r renamedMarketMarketItem | ||||
|  | ||||
| 	d := msgpack.NewDecoder(bytes.NewReader(data)) | ||||
| 	d.SetCustomStructTag("json") | ||||
|  | ||||
| 	err = d.Decode(&r) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	*market = MarketMarketItem(r) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // MarketMarketItemProperty struct. | ||||
| type MarketMarketItemProperty struct { | ||||
| 	VariantID    int    `json:"variant_id"` | ||||
| @@ -149,6 +184,36 @@ func (m *MarketPrice) UnmarshalJSON(data []byte) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // DecodeMsgpack MarketPrice. | ||||
| // | ||||
| // BUG(VK): unavailable product, in fave.get return []. | ||||
| func (m *MarketPrice) DecodeMsgpack(dec *msgpack.Decoder) error { | ||||
| 	data, err := dec.DecodeRaw() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if bytes.Equal(data, []byte{msgpcode.FixedArrayLow}) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	type renamedMarketPrice MarketPrice | ||||
|  | ||||
| 	var r renamedMarketPrice | ||||
|  | ||||
| 	d := msgpack.NewDecoder(bytes.NewReader(data)) | ||||
| 	d.SetCustomStructTag("json") | ||||
|  | ||||
| 	err = d.Decode(&r) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	*m = MarketPrice(r) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // MarketSection struct. | ||||
| type MarketSection struct { | ||||
| 	ID   int    `json:"id"`   // Section ID | ||||
|   | ||||
							
								
								
									
										52
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/marusia.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/marusia.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,52 @@ | ||||
| package object // import "github.com/SevereCloud/vksdk/v2/object" | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| ) | ||||
|  | ||||
| // MarusiaPicture struct. | ||||
| type MarusiaPicture struct { | ||||
| 	ID      int `json:"id"` | ||||
| 	OwnerID int `json:"owner_id"` | ||||
| } | ||||
|  | ||||
| // MarusiaPictureUploadResponse struct. | ||||
| type MarusiaPictureUploadResponse struct { | ||||
| 	Hash        string          `json:"hash"`   // Uploading hash | ||||
| 	Photo       json.RawMessage `json:"photo"`  // Uploaded photo data | ||||
| 	Server      int             `json:"server"` // Upload server number | ||||
| 	AID         int             `json:"aid"` | ||||
| 	MessageCode int             `json:"message_code"` | ||||
| } | ||||
|  | ||||
| // MarusiaAudio struct. | ||||
| type MarusiaAudio struct { | ||||
| 	ID      int    `json:"id"` | ||||
| 	Title   string `json:"title"` | ||||
| 	OwnerID int    `json:"owner_id"` | ||||
| } | ||||
|  | ||||
| // MarusiaAudioUploadResponse struct. | ||||
| type MarusiaAudioUploadResponse struct { | ||||
| 	Sha       string           `json:"sha"` | ||||
| 	Secret    string           `json:"secret"` | ||||
| 	Meta      MarusiaAudioMeta `json:"meta"` | ||||
| 	Hash      string           `json:"hash"` | ||||
| 	Server    string           `json:"server"` | ||||
| 	UserID    int              `json:"user_id"` | ||||
| 	RequestID string           `json:"request_id"` | ||||
| } | ||||
|  | ||||
| // MarusiaAudioMeta struct. | ||||
| type MarusiaAudioMeta struct { | ||||
| 	Album       string `json:"album"` | ||||
| 	Artist      string `json:"artist"` | ||||
| 	Bitrate     string `json:"bitrate"` | ||||
| 	Duration    string `json:"duration"` | ||||
| 	Genre       string `json:"genre"` | ||||
| 	Kad         string `json:"kad"` | ||||
| 	Md5         string `json:"md5"` | ||||
| 	Md5DataSize string `json:"md5_data_size"` | ||||
| 	Samplerate  string `json:"samplerate"` | ||||
| 	Title       string `json:"title"` | ||||
| } | ||||
							
								
								
									
										53
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/messages.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										53
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/messages.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -79,6 +79,7 @@ type MessagesMessage struct { | ||||
| 	UpdateTime   int    `json:"update_time"`   // Date when the message has been updated in Unixtime | ||||
| 	MembersCount int    `json:"members_count"` // Members number | ||||
| 	ExpireTTL    int    `json:"expire_ttl"` | ||||
| 	MessageTag   string `json:"message_tag"` // for https://notify.mail.ru/ | ||||
| } | ||||
|  | ||||
| // MessagesBasePayload struct. | ||||
| @@ -375,17 +376,18 @@ type MessagesTemplateElement struct { | ||||
|  | ||||
| // MessagesTemplateElementCarousel struct. | ||||
| type MessagesTemplateElementCarousel struct { | ||||
| 	Title       string                                `json:"title"` | ||||
| 	Action      MessagesTemplateElementCarouselAction `json:"action"` | ||||
| 	Description string                                `json:"description"` | ||||
| 	Photo       PhotosPhoto                           `json:"photo"` | ||||
| 	Buttons     []MessagesKeyboardButton              `json:"buttons"` | ||||
| 	Title       string                                `json:"title,omitempty"` | ||||
| 	Action      MessagesTemplateElementCarouselAction `json:"action,omitempty"` | ||||
| 	Description string                                `json:"description,omitempty"` | ||||
| 	Photo       *PhotosPhoto                          `json:"photo,omitempty"`    // Only read | ||||
| 	PhotoID     string                                `json:"photo_id,omitempty"` // Only for send | ||||
| 	Buttons     []MessagesKeyboardButton              `json:"buttons,omitempty"` | ||||
| } | ||||
|  | ||||
| // MessagesTemplateElementCarouselAction struct. | ||||
| type MessagesTemplateElementCarouselAction struct { | ||||
| 	Type string `json:"type"` | ||||
| 	Link string `json:"link"` | ||||
| 	Link string `json:"link,omitempty"` | ||||
| } | ||||
|  | ||||
| // MessageContentSourceMessage ... | ||||
| @@ -443,6 +445,7 @@ type MessagesChat struct { | ||||
| 	AdminID        int         `json:"admin_id"` // Chat creator ID | ||||
| 	ID             int         `json:"id"`       // Chat ID | ||||
| 	IsDefaultPhoto BaseBoolInt `json:"is_default_photo"` | ||||
| 	IsGroupChannel BaseBoolInt `json:"is_group_channel"` | ||||
| 	Photo100       string      `json:"photo_100"` // URL of the preview image with 100 px in width | ||||
| 	Photo200       string      `json:"photo_200"` // URL of the preview image with 200 px in width | ||||
| 	Photo50        string      `json:"photo_50"`  // URL of the preview image with 50 px in width | ||||
| @@ -473,20 +476,24 @@ type MessagesChatPushSettings struct { | ||||
|  | ||||
| // MessagesChatSettingsPhoto struct. | ||||
| type MessagesChatSettingsPhoto struct { | ||||
| 	Photo100       string      `json:"photo_100"` | ||||
| 	Photo200       string      `json:"photo_200"` | ||||
| 	Photo50        string      `json:"photo_50"` | ||||
| 	IsDefaultPhoto BaseBoolInt `json:"is_default_photo"` | ||||
| 	Photo100           string      `json:"photo_100"` | ||||
| 	Photo200           string      `json:"photo_200"` | ||||
| 	Photo50            string      `json:"photo_50"` | ||||
| 	IsDefaultPhoto     BaseBoolInt `json:"is_default_photo"` | ||||
| 	IsDefaultCallPhoto bool        `json:"is_default_call_photo"` | ||||
| } | ||||
|  | ||||
| // MessagesConversation struct. | ||||
| type MessagesConversation struct { | ||||
| 	CanWrite       MessagesConversationCanWrite     `json:"can_write"` | ||||
| 	ChatSettings   MessagesConversationChatSettings `json:"chat_settings"` | ||||
| 	InRead         int                              `json:"in_read"`         // Last message user have read | ||||
| 	LastMessageID  int                              `json:"last_message_id"` // ID of the last message in conversation | ||||
| 	Mentions       []int                            `json:"mentions"`        // IDs of messages with mentions | ||||
| 	MessageRequest string                           `json:"message_request"` | ||||
| 	CanWrite                  MessagesConversationCanWrite     `json:"can_write"` | ||||
| 	ChatSettings              MessagesConversationChatSettings `json:"chat_settings"` | ||||
| 	InRead                    int                              `json:"in_read"`         // Last message user have read | ||||
| 	LastMessageID             int                              `json:"last_message_id"` // ID of the last message in conversation | ||||
| 	Mentions                  []int                            `json:"mentions"`        // IDs of messages with mentions | ||||
| 	MessageRequest            string                           `json:"message_request"` | ||||
| 	LastConversationMessageID int                              `json:"last_conversation_message_id"` | ||||
| 	InReadCMID                int                              `json:"in_read_cmid"` | ||||
| 	OutReadCMID               int                              `json:"out_read_cmid"` | ||||
|  | ||||
| 	// Last outcoming message have been read by the opponent. | ||||
| 	OutRead         int                              `json:"out_read"` | ||||
| @@ -495,6 +502,10 @@ type MessagesConversation struct { | ||||
| 	Important       BaseBoolInt                      `json:"important"` | ||||
| 	Unanswered      BaseBoolInt                      `json:"unanswered"` | ||||
| 	IsMarkedUnread  BaseBoolInt                      `json:"is_marked_unread"` | ||||
| 	CanSendMoney    BaseBoolInt                      `json:"can_send_money"` | ||||
| 	CanReceiveMoney BaseBoolInt                      `json:"can_receive_money"` | ||||
| 	IsNew           BaseBoolInt                      `json:"is_new"` | ||||
| 	IsArchived      BaseBoolInt                      `json:"is_archived"` | ||||
| 	UnreadCount     int                              `json:"unread_count"` // Unread messages number | ||||
| 	CurrentKeyboard MessagesKeyboard                 `json:"current_keyboard"` | ||||
| 	SortID          struct { | ||||
| @@ -530,6 +541,7 @@ type MessagesConversationChatSettings struct { | ||||
| 		CanCall              BaseBoolInt `json:"can_call"` | ||||
| 		CanUseMassMentions   BaseBoolInt `json:"can_use_mass_mentions"` | ||||
| 		CanChangeServiceType BaseBoolInt `json:"can_change_service_type"` | ||||
| 		CanChangeStyle       BaseBoolInt `json:"can_change_style"` | ||||
| 	} `json:"acl"` | ||||
| 	IsGroupChannel   BaseBoolInt             `json:"is_group_channel"` | ||||
| 	IsDisappearing   BaseBoolInt             `json:"is_disappearing"` | ||||
| @@ -559,6 +571,7 @@ type MessagesChatPermissions struct { | ||||
| 	SeeInviteLink   MessagesChatPermission `json:"see_invite_link"` | ||||
| 	Call            MessagesChatPermission `json:"call"` | ||||
| 	ChangeAdmins    MessagesChatPermission `json:"change_admins"` | ||||
| 	ChangeStyle     MessagesChatPermission `json:"change_style"` | ||||
| } | ||||
|  | ||||
| // MessagesConversationPeer struct. | ||||
| @@ -570,9 +583,11 @@ type MessagesConversationPeer struct { | ||||
|  | ||||
| // MessagesConversationPushSettings struct. | ||||
| type MessagesConversationPushSettings struct { | ||||
| 	DisabledUntil   int         `json:"disabled_until"` | ||||
| 	DisabledForever BaseBoolInt `json:"disabled_forever"` | ||||
| 	NoSound         BaseBoolInt `json:"no_sound"` | ||||
| 	DisabledUntil        int         `json:"disabled_until"` | ||||
| 	DisabledForever      BaseBoolInt `json:"disabled_forever"` | ||||
| 	NoSound              BaseBoolInt `json:"no_sound"` | ||||
| 	DisabledMentions     BaseBoolInt `json:"disabled_mentions"` | ||||
| 	DisabledMassMentions BaseBoolInt `json:"disabled_mass_mentions"` | ||||
| } | ||||
|  | ||||
| // MessagesConversationWithMessage struct. | ||||
|   | ||||
							
								
								
									
										6
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/notifications.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/notifications.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,7 +1,5 @@ | ||||
| package object // import "github.com/SevereCloud/vksdk/v2/object" | ||||
|  | ||||
| import "encoding/json" | ||||
|  | ||||
| // NotificationsFeedback struct. | ||||
| type NotificationsFeedback struct { | ||||
| 	Attachments []WallWallpostAttachment `json:"attachments"` | ||||
| @@ -16,8 +14,8 @@ type NotificationsFeedback struct { | ||||
| // NotificationsNotification struct. | ||||
| type NotificationsNotification struct { | ||||
| 	Date     int                `json:"date"` // Date when the event has been occurred | ||||
| 	Feedback json.RawMessage    `json:"feedback"` | ||||
| 	Parent   json.RawMessage    `json:"parent"` | ||||
| 	Feedback RawMessage         `json:"feedback"` | ||||
| 	Parent   RawMessage         `json:"parent"` | ||||
| 	Reply    NotificationsReply `json:"reply"` | ||||
| 	Type     string             `json:"type"` // Notification type | ||||
| } | ||||
|   | ||||
							
								
								
									
										71
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/object.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										71
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/object.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -9,6 +9,8 @@ import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"reflect" | ||||
|  | ||||
| 	"github.com/vmihailenco/msgpack/v5" | ||||
| ) | ||||
|  | ||||
| // Attachment interface. | ||||
| @@ -42,6 +44,44 @@ func (b *BaseBoolInt) UnmarshalJSON(data []byte) (err error) { | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // DecodeMsgpack func. | ||||
| func (b *BaseBoolInt) DecodeMsgpack(dec *msgpack.Decoder) (err error) { | ||||
| 	data, err := dec.DecodeRaw() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	var ( | ||||
| 		valueInt  int | ||||
| 		valueBool bool | ||||
| 	) | ||||
|  | ||||
| 	switch { | ||||
| 	case msgpack.Unmarshal(data, &valueBool) == nil: | ||||
| 		*b = BaseBoolInt(valueBool) | ||||
| 	case msgpack.Unmarshal(data, &valueInt) == nil: | ||||
| 		if valueInt == 1 { | ||||
| 			*b = true | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		if valueInt == 0 { | ||||
| 			*b = false | ||||
| 			break | ||||
| 		} | ||||
|  | ||||
| 		fallthrough | ||||
| 	default: | ||||
| 		// return msgpack error | ||||
| 		err = &json.UnmarshalTypeError{ | ||||
| 			Value: string(data), | ||||
| 			Type:  reflect.TypeOf((*BaseBoolInt)(nil)), | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // BaseCountry struct. | ||||
| type BaseCountry struct { | ||||
| 	ID    int    `json:"id"` | ||||
| @@ -151,6 +191,33 @@ func (obj *BaseImage) UnmarshalJSON(data []byte) (err error) { | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // DecodeMsgpack is required to support images with `src` field. | ||||
| func (obj *BaseImage) DecodeMsgpack(dec *msgpack.Decoder) (err error) { | ||||
| 	type renamedBaseImage struct { | ||||
| 		Height float64 `msgpack:"height"` | ||||
| 		URL    string  `msgpack:"url"` | ||||
| 		Src    string  `msgpack:"src"` | ||||
| 		Width  float64 `msgpack:"width"` | ||||
| 		Type   string  `msgpack:"type"` | ||||
| 	} | ||||
|  | ||||
| 	var renamedObj renamedBaseImage | ||||
|  | ||||
| 	err = dec.Decode(&renamedObj) | ||||
|  | ||||
| 	obj.Height = renamedObj.Height | ||||
| 	obj.Width = renamedObj.Width | ||||
| 	obj.Type = renamedObj.Type | ||||
|  | ||||
| 	if renamedObj.Src == "" { | ||||
| 		obj.URL = renamedObj.URL | ||||
| 	} else { | ||||
| 		obj.URL = renamedObj.Src | ||||
| 	} | ||||
|  | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // BaseLikes struct. | ||||
| type BaseLikes struct { | ||||
| 	UserLikes BaseBoolInt `json:"user_likes"` // Information whether current user likes | ||||
| @@ -346,9 +413,11 @@ const ( | ||||
| type Privacy struct { | ||||
| 	Category PrivacyCategory `json:"category,omitempty"` | ||||
| 	Lists    struct { | ||||
| 		Allowed []int `json:"allowed"` | ||||
| 		Allowed  []int `json:"allowed"` | ||||
| 		Excluded []int `json:"excluded"` | ||||
| 	} `json:"lists,omitempty"` | ||||
| 	Owners struct { | ||||
| 		Allowed  []int `json:"allowed"` | ||||
| 		Excluded []int `json:"excluded"` | ||||
| 	} `json:"owners,omitempty"` | ||||
| } | ||||
|   | ||||
							
								
								
									
										1
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/photos.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/photos.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -239,6 +239,7 @@ type PhotosPhotoFull struct { | ||||
| 	Photo1280  string             `json:"photo_1280"` // URL of image with 1280 px width | ||||
| 	Photo2560  string             `json:"photo_2560"` // URL of image with 2560 px width | ||||
| 	Sizes      []PhotosPhotoSizes `json:"sizes"` | ||||
| 	OrigPhoto  PhotosPhotoSizes   `json:"orig_photo"` | ||||
| } | ||||
|  | ||||
| // ToAttachment return attachment format. | ||||
|   | ||||
							
								
								
									
										39
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/raw.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/raw.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| package object // import "github.com/SevereCloud/vksdk/v2/object" | ||||
|  | ||||
| import "github.com/vmihailenco/msgpack/v5" | ||||
|  | ||||
| // RawMessage is a raw encoded JSON or MessagePack value. | ||||
| type RawMessage []byte | ||||
|  | ||||
| // MarshalJSON returns m as the JSON encoding of m. | ||||
| func (m RawMessage) MarshalJSON() ([]byte, error) { | ||||
| 	if m == nil { | ||||
| 		return []byte("null"), nil | ||||
| 	} | ||||
|  | ||||
| 	return m, nil | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON sets *m to a copy of data. | ||||
| func (m *RawMessage) UnmarshalJSON(data []byte) error { | ||||
| 	*m = append((*m)[0:0], data...) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // EncodeMsgpack write m as the MessagePack encoding of m. | ||||
| func (m RawMessage) EncodeMsgpack(enc *msgpack.Encoder) error { | ||||
| 	_, err := enc.Writer().Write(m) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // DecodeMsgpack sets *m to a copy of data. | ||||
| func (m *RawMessage) DecodeMsgpack(dec *msgpack.Decoder) error { | ||||
| 	msg, err := dec.DecodeRaw() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	*m = RawMessage(msg) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										37
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/stories.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										37
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/stories.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -127,6 +127,7 @@ type StoriesStory struct { | ||||
| 	Seen                 BaseBoolInt              `json:"seen"` | ||||
| 	IsOwnerPinned        BaseBoolInt              `json:"is_owner_pinned"` | ||||
| 	IsOneTime            BaseBoolInt              `json:"is_one_time"` | ||||
| 	IsAdvice             BaseBoolInt              `json:"is_advice,omitempty"` | ||||
| 	NeedMute             BaseBoolInt              `json:"need_mute"` | ||||
| 	MuteReply            BaseBoolInt              `json:"mute_reply"` | ||||
| 	CanLike              BaseBoolInt              `json:"can_like"` | ||||
| @@ -152,6 +153,7 @@ type StoriesStory struct { | ||||
| 	NarrativesCount      int                      `json:"narratives_count"` | ||||
| 	FirstNarrativeTitle  string                   `json:"first_narrative_title"` | ||||
| 	Questions            StoriesQuestions         `json:"questions"` | ||||
| 	ReactionSetID        string                   `json:"reaction_set_id"` | ||||
| } | ||||
|  | ||||
| // StoriesFeedItemType type. | ||||
| @@ -251,8 +253,10 @@ type StoriesClickableSticker struct { // nolint: maligned | ||||
| 	StickerID     int `json:"sticker_id,omitempty"` | ||||
| 	StickerPackID int `json:"sticker_pack_id,omitempty"` | ||||
|  | ||||
| 	// type=place | ||||
| 	// type=place or geo | ||||
| 	PlaceID int `json:"place_id,omitempty"` | ||||
| 	// Title | ||||
| 	CategoryID int `json:"category_id,omitempty"` | ||||
|  | ||||
| 	// type=question | ||||
| 	Question               string      `json:"question,omitempty"` | ||||
| @@ -267,8 +271,14 @@ type StoriesClickableSticker struct { // nolint: maligned | ||||
| 	Hashtag string `json:"hashtag,omitempty"` | ||||
|  | ||||
| 	// type=link | ||||
| 	LinkObject  BaseLink `json:"link_object,omitempty"` | ||||
| 	TooltipText string   `json:"tooltip_text,omitempty"` | ||||
| 	LinkObject     BaseLink `json:"link_object,omitempty"` | ||||
| 	TooltipText    string   `json:"tooltip_text,omitempty"` | ||||
| 	TooltipTextKey string   `json:"tooltip_text_key,omitempty"` | ||||
|  | ||||
| 	// type=time | ||||
| 	TimestampMs int64  `json:"timestamp_ms,omitempty"` | ||||
| 	Date        string `json:"date,omitempty"` | ||||
| 	Title       string `json:"title,omitempty"` | ||||
|  | ||||
| 	// type=market_item | ||||
| 	Subtype string `json:"subtype,omitempty"` | ||||
| @@ -290,10 +300,19 @@ type StoriesClickableSticker struct { // nolint: maligned | ||||
| 	AudioStartTime int        `json:"audio_start_time,omitempty"` | ||||
|  | ||||
| 	// type=app | ||||
| 	App                      AppsApp     `json:"app"` | ||||
| 	AppContext               string      `json:"app_context"` | ||||
| 	HasNewInteractions       BaseBoolInt `json:"has_new_interactions"` | ||||
| 	IsBroadcastNotifyAllowed BaseBoolInt `json:"is_broadcast_notify_allowed"` | ||||
| 	App                      AppsApp     `json:"app,omitempty"` | ||||
| 	AppContext               string      `json:"app_context,omitempty"` | ||||
| 	HasNewInteractions       BaseBoolInt `json:"has_new_interactions,omitempty"` | ||||
| 	IsBroadcastNotifyAllowed BaseBoolInt `json:"is_broadcast_notify_allowed,omitempty"` | ||||
|  | ||||
| 	// type=emoji | ||||
| 	Emoji string `json:"emoji,omitempty"` | ||||
|  | ||||
| 	// type=text | ||||
| 	Text            string `json:"text,omitempty"` | ||||
| 	BackgroundStyle string `json:"background_style,omitempty"` | ||||
| 	Alignment       string `json:"alignment,omitempty"` | ||||
| 	SelectionColor  string `json:"selection_color,omitempty"` | ||||
| } | ||||
|  | ||||
| // TODO: сделать несколько структур для кликабельного стикера | ||||
| @@ -313,6 +332,10 @@ const ( | ||||
| 	ClickableStickerPoll       = "poll" | ||||
| 	ClickableStickerMusic      = "music" | ||||
| 	ClickableStickerApp        = "app" | ||||
| 	ClickableStickerTime       = "time" | ||||
| 	ClickableStickerEmoji      = "emoji" | ||||
| 	ClickableStickerGeo        = "geo" | ||||
| 	ClickableStickerText       = "text" | ||||
| ) | ||||
|  | ||||
| // Subtype of clickable sticker. | ||||
|   | ||||
							
								
								
									
										33
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/users.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										33
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/users.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -4,6 +4,9 @@ import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
|  | ||||
| 	"github.com/vmihailenco/msgpack/v5" | ||||
| 	"github.com/vmihailenco/msgpack/v5/msgpcode" | ||||
| ) | ||||
|  | ||||
| // User relationship status. | ||||
| @@ -258,6 +261,36 @@ func (personal *UsersPersonal) UnmarshalJSON(data []byte) error { | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // DecodeMsgpack UsersPersonal. | ||||
| // | ||||
| // BUG(VK): UsersPersonal return []. | ||||
| func (personal *UsersPersonal) DecodeMsgpack(dec *msgpack.Decoder) error { | ||||
| 	data, err := dec.DecodeRaw() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if bytes.Equal(data, []byte{msgpcode.FixedArrayLow}) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	type renamedUsersPersonal UsersPersonal | ||||
|  | ||||
| 	var r renamedUsersPersonal | ||||
|  | ||||
| 	d := msgpack.NewDecoder(bytes.NewReader(data)) | ||||
| 	d.SetCustomStructTag("json") | ||||
|  | ||||
| 	err = d.Decode(&r) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	*personal = UsersPersonal(r) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // UsersRelative struct. | ||||
| type UsersRelative struct { | ||||
| 	BirthDate string `json:"birth_date"` // Date of child birthday (format dd.mm.yyyy) | ||||
|   | ||||
							
								
								
									
										60
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										60
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/utils.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,5 +1,13 @@ | ||||
| package object // import "github.com/SevereCloud/vksdk/v2/object" | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
|  | ||||
| 	"github.com/vmihailenco/msgpack/v5" | ||||
| 	"github.com/vmihailenco/msgpack/v5/msgpcode" | ||||
| ) | ||||
|  | ||||
| // UtilsDomainResolvedType object type. | ||||
| const ( | ||||
| 	UtilsDomainResolvedTypeUser        = "user" | ||||
| @@ -15,6 +23,58 @@ type UtilsDomainResolved struct { | ||||
| 	Type     string `json:"type"` | ||||
| } | ||||
|  | ||||
| // UnmarshalJSON UtilsDomainResolved. | ||||
| // | ||||
| // BUG(VK): UtilsDomainResolved return []. | ||||
| func (link *UtilsDomainResolved) UnmarshalJSON(data []byte) error { | ||||
| 	if bytes.Equal(data, []byte("[]")) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	type renamedUtilsDomainResolved UtilsDomainResolved | ||||
|  | ||||
| 	var r renamedUtilsDomainResolved | ||||
|  | ||||
| 	err := json.Unmarshal(data, &r) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	*link = UtilsDomainResolved(r) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // DecodeMsgpack UtilsDomainResolved. | ||||
| // | ||||
| // BUG(VK): UtilsDomainResolved return []. | ||||
| func (link *UtilsDomainResolved) DecodeMsgpack(dec *msgpack.Decoder) error { | ||||
| 	data, err := dec.DecodeRaw() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if bytes.Equal(data, []byte{msgpcode.FixedArrayLow}) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	type renamedUtilsDomainResolved UtilsDomainResolved | ||||
|  | ||||
| 	var r renamedUtilsDomainResolved | ||||
|  | ||||
| 	d := msgpack.NewDecoder(bytes.NewReader(data)) | ||||
| 	d.SetCustomStructTag("json") | ||||
|  | ||||
| 	err = d.Decode(&r) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	*link = UtilsDomainResolved(r) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // UtilsLastShortenedLink struct. | ||||
| type UtilsLastShortenedLink struct { | ||||
| 	AccessKey string `json:"access_key"` // Access key for private stats | ||||
|   | ||||
							
								
								
									
										71
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/video.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										71
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/video.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -12,6 +12,9 @@ type VideoVideo struct { | ||||
| 	// Date when the video has been added in Unixtime. | ||||
| 	AddingDate int `json:"adding_date"` | ||||
|  | ||||
| 	// Date when the video has been released in Unixtime. | ||||
| 	ReleaseDate int `json:"release_date"` | ||||
|  | ||||
| 	// Information whether current user can add the video. | ||||
| 	CanAdd BaseBoolInt `json:"can_add"` | ||||
|  | ||||
| @@ -27,12 +30,17 @@ type VideoVideo struct { | ||||
| 	// Information whether current user can like the video. | ||||
| 	CanLike BaseBoolInt `json:"can_like"` | ||||
|  | ||||
| 	// Information whether current user can download the video. | ||||
| 	CanDownload BaseBoolInt `json:"can_download"` | ||||
|  | ||||
| 	// Information whether current user can repost this video. | ||||
| 	CanRepost         BaseBoolInt       `json:"can_repost"` | ||||
| 	CanSubscribe      BaseBoolInt       `json:"can_subscribe"` | ||||
| 	CanAttachLink     BaseBoolInt       `json:"can_attach_link"` | ||||
| 	IsFavorite        BaseBoolInt       `json:"is_favorite"` | ||||
| 	IsPrivate         BaseBoolInt       `json:"is_private"` | ||||
| 	IsExplicit        BaseBoolInt       `json:"is_explicit"` | ||||
| 	IsSubscribed      BaseBoolInt       `json:"is_subscribed"` | ||||
| 	Added             BaseBoolInt       `json:"added"` | ||||
| 	Repeat            BaseBoolInt       `json:"repeat"` // Information whether the video is repeated | ||||
| 	ContentRestricted int               `json:"content_restricted"` | ||||
| @@ -43,6 +51,7 @@ type VideoVideo struct { | ||||
| 	Description       string            `json:"description"` // Video description | ||||
| 	Duration          int               `json:"duration"`    // Video duration in seconds | ||||
| 	Files             VideoVideoFiles   `json:"files"` | ||||
| 	Trailer           VideoVideoFiles   `json:"trailer,omitempty"` | ||||
| 	FirstFrame        []VideoVideoImage `json:"first_frame"` | ||||
| 	Image             []VideoVideoImage `json:"image"` | ||||
| 	Height            int               `json:"height"`   // Video height | ||||
| @@ -56,22 +65,27 @@ type VideoVideo struct { | ||||
| 	Photo1280         string            `json:"photo_1280"` // URL of the preview image with 1280 px in width | ||||
|  | ||||
| 	// URL of the page with a player that can be used to play the video in the browser. | ||||
| 	Player                   string            `json:"player"` | ||||
| 	Processing               int               `json:"processing"` // Returns if the video is processing | ||||
| 	Title                    string            `json:"title"`      // Video title | ||||
| 	Type                     string            `json:"type"` | ||||
| 	Views                    int               `json:"views"` // Number of views | ||||
| 	Width                    int               `json:"width"` // Video width | ||||
| 	Platform                 string            `json:"platform"` | ||||
| 	LocalViews               int               `json:"local_views"` | ||||
| 	Likes                    BaseLikesInfo     `json:"likes"`   // Count of likes | ||||
| 	Reposts                  BaseRepostsInfo   `json:"reposts"` // Count of views | ||||
| 	TrackCode                string            `json:"track_code"` | ||||
| 	PrivacyView              Privacy           `json:"privacy_view"` | ||||
| 	PrivacyComment           Privacy           `json:"privacy_comment"` | ||||
| 	ActionButton             VideoActionButton `json:"action_button"` | ||||
| 	Restriction              VideoRestriction  `json:"restriction"` | ||||
| 	ContentRestrictedMessage string            `json:"content_restricted_message"` | ||||
| 	Player                   string               `json:"player"` | ||||
| 	Processing               int                  `json:"processing"` // Returns if the video is processing | ||||
| 	Title                    string               `json:"title"`      // Video title | ||||
| 	Subtitle                 string               `json:"subtitle"`   // Video subtitle | ||||
| 	Type                     string               `json:"type"` | ||||
| 	Views                    int                  `json:"views"` // Number of views | ||||
| 	Width                    int                  `json:"width"` // Video width | ||||
| 	Platform                 string               `json:"platform"` | ||||
| 	LocalViews               int                  `json:"local_views"` | ||||
| 	Likes                    BaseLikesInfo        `json:"likes"`   // Count of likes | ||||
| 	Reposts                  BaseRepostsInfo      `json:"reposts"` // Count of views | ||||
| 	TrackCode                string               `json:"track_code"` | ||||
| 	PrivacyView              Privacy              `json:"privacy_view"` | ||||
| 	PrivacyComment           Privacy              `json:"privacy_comment"` | ||||
| 	ActionButton             VideoActionButton    `json:"action_button"` | ||||
| 	Restriction              VideoRestriction     `json:"restriction"` | ||||
| 	ContentRestrictedMessage string               `json:"content_restricted_message"` | ||||
| 	MainArtists              []AudioAudioArtist   `json:"main_artists"` | ||||
| 	FeaturedArtists          []AudioAudioArtist   `json:"featured_artists"` | ||||
| 	Genres                   []BaseObjectWithName `json:"genres"` | ||||
| 	OvID                     string               `json:"ov_id,omitempty"` | ||||
| } | ||||
|  | ||||
| // ToAttachment return attachment format. | ||||
| @@ -112,16 +126,20 @@ type VideoSnippet struct { | ||||
|  | ||||
| // VideoVideoFiles struct. | ||||
| type VideoVideoFiles struct { | ||||
| 	External string `json:"external"` // URL of the external player | ||||
| 	Mp4_1080 string `json:"mp4_1080"` // URL of the mpeg4 file with 1080p quality | ||||
| 	Mp4_1440 string `json:"mp4_1440"` // URL of the mpeg4 file with 2k quality | ||||
| 	Mp4_2160 string `json:"mp4_2160"` // URL of the mpeg4 file with 4k quality | ||||
| 	Mp4_240  string `json:"mp4_240"`  // URL of the mpeg4 file with 240p quality | ||||
| 	Mp4_360  string `json:"mp4_360"`  // URL of the mpeg4 file with 360p quality | ||||
| 	Mp4_480  string `json:"mp4_480"`  // URL of the mpeg4 file with 480p quality | ||||
| 	Mp4_720  string `json:"mp4_720"`  // URL of the mpeg4 file with 720p quality | ||||
| 	Live     string `json:"live"` | ||||
| 	HLS      string `json:"hls"` | ||||
| 	External     string `json:"external,omitempty"` // URL of the external player | ||||
| 	Mp4_1080     string `json:"mp4_1080,omitempty"` // URL of the mpeg4 file with 1080p quality | ||||
| 	Mp4_1440     string `json:"mp4_1440,omitempty"` // URL of the mpeg4 file with 2k quality | ||||
| 	Mp4_2160     string `json:"mp4_2160,omitempty"` // URL of the mpeg4 file with 4k quality | ||||
| 	Mp4_240      string `json:"mp4_240,omitempty"`  // URL of the mpeg4 file with 240p quality | ||||
| 	Mp4_360      string `json:"mp4_360,omitempty"`  // URL of the mpeg4 file with 360p quality | ||||
| 	Mp4_480      string `json:"mp4_480,omitempty"`  // URL of the mpeg4 file with 480p quality | ||||
| 	Mp4_720      string `json:"mp4_720,omitempty"`  // URL of the mpeg4 file with 720p quality | ||||
| 	Live         string `json:"live,omitempty"` | ||||
| 	HLS          string `json:"hls,omitempty"` | ||||
| 	DashUni      string `json:"dash_uni,omitempty"` | ||||
| 	DashSep      string `json:"dash_sep,omitempty"` | ||||
| 	DashWebm     string `json:"dash_webm,omitempty"` | ||||
| 	FailoverHost string `json:"failover_host,omitempty"` | ||||
| } | ||||
|  | ||||
| // VideoCatBlock struct. | ||||
| @@ -213,6 +231,7 @@ type VideoVideoFull struct { | ||||
| 	Description   string          `json:"description"` // Video description | ||||
| 	Duration      int             `json:"duration"`    // Video duration in seconds | ||||
| 	Files         VideoVideoFiles `json:"files"` | ||||
| 	Trailer       VideoVideoFiles `json:"trailer"` | ||||
| 	ID            int             `json:"id"` // Video ID | ||||
| 	Likes         BaseLikes       `json:"likes"` | ||||
| 	Live          int             `json:"live"`     // Returns if the video is live translation | ||||
|   | ||||
							
								
								
									
										23
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/wall.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										23
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/wall.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -128,7 +128,7 @@ const ( | ||||
| 	WallPostTypeSuggest  = "suggest" | ||||
| ) | ||||
|  | ||||
| // WallWallpost  struct. | ||||
| // WallWallpost struct. | ||||
| type WallWallpost struct { | ||||
| 	AccessKey      string                   `json:"access_key"` // Access key to private object | ||||
| 	ID             int                      `json:"id"`         // Post ID | ||||
| @@ -156,14 +156,17 @@ type WallWallpost struct { | ||||
| 	IsPinned       BaseBoolInt              `json:"is_pinned"` | ||||
| 	IsFavorite     BaseBoolInt              `json:"is_favorite"` // Information whether the post in favorites list | ||||
| 	IsArchived     BaseBoolInt              `json:"is_archived"` // Is post archived, only for post owners | ||||
| 	IsDeleted      BaseBoolInt              `json:"is_deleted"` | ||||
| 	MarkedAsAds    BaseBoolInt              `json:"marked_as_ads"` | ||||
| 	Edited         int                      `json:"edited"` // Date of editing in Unixtime | ||||
| 	Copyright      WallPostCopyright        `json:"copyright"` | ||||
| 	PostID         int                      `json:"post_id"` | ||||
| 	ParentsStack   []int                    `json:"parents_stack"` | ||||
| 	Donut          WallWallpostDonut        `json:"donut"` // need api v5.125 | ||||
| 	Donut          WallWallpostDonut        `json:"donut"` | ||||
| 	ShortTextRate  float64                  `json:"short_text_rate"` | ||||
| 	CarouselOffset int                      `json:"carousel_offset"` | ||||
| 	Header         WallWallpostHeader       `json:"header"` | ||||
| 	Hash           string                   `json:"hash"` | ||||
| } | ||||
|  | ||||
| // Attachment type. | ||||
| @@ -235,8 +238,10 @@ type WallWallpostToID struct { | ||||
| 	IsFavorite    BaseBoolInt              `json:"is_favorite"` // Information whether the post in favorites list | ||||
| 	MarkedAsAds   BaseBoolInt              `json:"marked_as_ads"` | ||||
| 	ParentsStack  []int                    `json:"parents_stack"` | ||||
| 	Donut         WallWallpostDonut        `json:"donut"` // need api v5.125 | ||||
| 	Donut         WallWallpostDonut        `json:"donut"` | ||||
| 	ShortTextRate float64                  `json:"short_text_rate"` | ||||
| 	Views         WallViews                `json:"views"` // Count of views | ||||
| 	Header        WallWallpostHeader       `json:"header"` | ||||
| } | ||||
|  | ||||
| // WallWallpostDonut info about VK Donut. | ||||
| @@ -255,3 +260,15 @@ type WallPostCopyright struct { | ||||
| 	Type string `json:"type"` | ||||
| 	Name string `json:"name"` | ||||
| } | ||||
|  | ||||
| // WallWallpostHeader struct. | ||||
| type WallWallpostHeader struct { | ||||
| 	Type              string                              `json:"type"` | ||||
| 	CustomDescription WallWallpostHeaderCustomDescription `json:"custom_description"` | ||||
| } | ||||
|  | ||||
| // WallWallpostHeaderCustomDescription struct. | ||||
| type WallWallpostHeaderCustomDescription struct { | ||||
| 	SourceID int `json:"source_id"` | ||||
| 	Date     int `json:"date"` | ||||
| } | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/widgets.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/SevereCloud/vksdk/v2/object/widgets.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -45,6 +45,9 @@ type WidgetsWidgetComment struct { | ||||
| 	Views       struct { | ||||
| 		Count int `json:"count"` | ||||
| 	} `json:"views"` | ||||
| 	Donut         WallWallpostDonut  `json:"donut"` | ||||
| 	ShortTextRate float64            `json:"short_text_rate"` | ||||
| 	Header        WallWallpostHeader `json:"header"` | ||||
| } | ||||
|  | ||||
| // WidgetsWidgetLikes struct. | ||||
|   | ||||
							
								
								
									
										4
									
								
								vendor/github.com/d5/tengo/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								vendor/github.com/d5/tengo/v2/README.md
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,7 +1,3 @@ | ||||
| <p align="center"> | ||||
|   <img src="https://raw.githubusercontent.com/d5/tengolang-share/master/logo_400.png" width="200" height="200"> | ||||
| </p> | ||||
|  | ||||
| # The Tengo Language | ||||
|  | ||||
| [](https://godoc.org/github.com/d5/tengo/v2) | ||||
|   | ||||
							
								
								
									
										70
									
								
								vendor/github.com/d5/tengo/v2/compiler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										70
									
								
								vendor/github.com/d5/tengo/v2/compiler.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,9 +1,11 @@ | ||||
| package tengo | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
| @@ -45,11 +47,12 @@ type Compiler struct { | ||||
| 	parent          *Compiler | ||||
| 	modulePath      string | ||||
| 	importDir       string | ||||
| 	importFileExt   []string | ||||
| 	constants       []Object | ||||
| 	symbolTable     *SymbolTable | ||||
| 	scopes          []compilationScope | ||||
| 	scopeIndex      int | ||||
| 	modules         *ModuleMap | ||||
| 	modules         ModuleGetter | ||||
| 	compiledModules map[string]*CompiledFunction | ||||
| 	allowFileImport bool | ||||
| 	loops           []*loop | ||||
| @@ -63,7 +66,7 @@ func NewCompiler( | ||||
| 	file *parser.SourceFile, | ||||
| 	symbolTable *SymbolTable, | ||||
| 	constants []Object, | ||||
| 	modules *ModuleMap, | ||||
| 	modules ModuleGetter, | ||||
| 	trace io.Writer, | ||||
| ) *Compiler { | ||||
| 	mainScope := compilationScope{ | ||||
| @@ -96,6 +99,7 @@ func NewCompiler( | ||||
| 		trace:           trace, | ||||
| 		modules:         modules, | ||||
| 		compiledModules: make(map[string]*CompiledFunction), | ||||
| 		importFileExt:   []string{SourceFileExtDefault}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @@ -538,12 +542,8 @@ func (c *Compiler) Compile(node parser.Node) error { | ||||
| 			} | ||||
| 		} else if c.allowFileImport { | ||||
| 			moduleName := node.ModuleName | ||||
| 			if !strings.HasSuffix(moduleName, ".tengo") { | ||||
| 				moduleName += ".tengo" | ||||
| 			} | ||||
|  | ||||
| 			modulePath, err := filepath.Abs( | ||||
| 				filepath.Join(c.importDir, moduleName)) | ||||
| 			modulePath, err := c.getPathModule(moduleName) | ||||
| 			if err != nil { | ||||
| 				return c.errorf(node, "module file path error: %s", | ||||
| 					err.Error()) | ||||
| @@ -640,6 +640,39 @@ func (c *Compiler) SetImportDir(dir string) { | ||||
| 	c.importDir = dir | ||||
| } | ||||
|  | ||||
| // SetImportFileExt sets the extension name of the source file for loading | ||||
| // local module files. | ||||
| // | ||||
| // Use this method if you want other source file extension than ".tengo". | ||||
| // | ||||
| //     // this will search for *.tengo, *.foo, *.bar | ||||
| //     err := c.SetImportFileExt(".tengo", ".foo", ".bar") | ||||
| // | ||||
| // This function requires at least one argument, since it will replace the | ||||
| // current list of extension name. | ||||
| func (c *Compiler) SetImportFileExt(exts ...string) error { | ||||
| 	if len(exts) == 0 { | ||||
| 		return fmt.Errorf("missing arg: at least one argument is required") | ||||
| 	} | ||||
|  | ||||
| 	for _, ext := range exts { | ||||
| 		if ext != filepath.Ext(ext) || ext == "" { | ||||
| 			return fmt.Errorf("invalid file extension: %s", ext) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	c.importFileExt = exts // Replace the hole current extension list | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // GetImportFileExt returns the current list of extension name. | ||||
| // Thease are the complementary suffix of the source file to search and load | ||||
| // local module files. | ||||
| func (c *Compiler) GetImportFileExt() []string { | ||||
| 	return c.importFileExt | ||||
| } | ||||
|  | ||||
| func (c *Compiler) compileAssign( | ||||
| 	node parser.Node, | ||||
| 	lhs, rhs []parser.Expr, | ||||
| @@ -1098,6 +1131,7 @@ func (c *Compiler) fork( | ||||
| 	child.parent = c              // parent to set to current compiler | ||||
| 	child.allowFileImport = c.allowFileImport | ||||
| 	child.importDir = c.importDir | ||||
| 	child.importFileExt = c.importFileExt | ||||
| 	if isFile && c.importDir != "" { | ||||
| 		child.importDir = filepath.Dir(modulePath) | ||||
| 	} | ||||
| @@ -1287,6 +1321,28 @@ func (c *Compiler) printTrace(a ...interface{}) { | ||||
| 	_, _ = fmt.Fprintln(c.trace, a...) | ||||
| } | ||||
|  | ||||
| func (c *Compiler) getPathModule(moduleName string) (pathFile string, err error) { | ||||
| 	for _, ext := range c.importFileExt { | ||||
| 		nameFile := moduleName | ||||
|  | ||||
| 		if !strings.HasSuffix(nameFile, ext) { | ||||
| 			nameFile += ext | ||||
| 		} | ||||
|  | ||||
| 		pathFile, err = filepath.Abs(filepath.Join(c.importDir, nameFile)) | ||||
| 		if err != nil { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		// Check if file exists | ||||
| 		if _, err := os.Stat(pathFile); !errors.Is(err, os.ErrNotExist) { | ||||
| 			return pathFile, nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return "", fmt.Errorf("module '%s' not found at: %s", moduleName, pathFile) | ||||
| } | ||||
|  | ||||
| func resolveAssignLHS( | ||||
| 	expr parser.Expr, | ||||
| ) (name string, selectors []parser.Expr) { | ||||
|   | ||||
							
								
								
									
										5
									
								
								vendor/github.com/d5/tengo/v2/modules.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								vendor/github.com/d5/tengo/v2/modules.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -6,6 +6,11 @@ type Importable interface { | ||||
| 	Import(moduleName string) (interface{}, error) | ||||
| } | ||||
|  | ||||
| // ModuleGetter enables implementing dynamic module loading. | ||||
| type ModuleGetter interface { | ||||
| 	Get(name string) Importable | ||||
| } | ||||
|  | ||||
| // ModuleMap represents a set of named modules. Use NewModuleMap to create a | ||||
| // new module map. | ||||
| type ModuleMap struct { | ||||
|   | ||||
							
								
								
									
										16
									
								
								vendor/github.com/d5/tengo/v2/script.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/d5/tengo/v2/script.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -12,7 +12,7 @@ import ( | ||||
| // Script can simplify compilation and execution of embedded scripts. | ||||
| type Script struct { | ||||
| 	variables        map[string]*Variable | ||||
| 	modules          *ModuleMap | ||||
| 	modules          ModuleGetter | ||||
| 	input            []byte | ||||
| 	maxAllocs        int64 | ||||
| 	maxConstObjects  int | ||||
| @@ -54,7 +54,7 @@ func (s *Script) Remove(name string) bool { | ||||
| } | ||||
|  | ||||
| // SetImports sets import modules. | ||||
| func (s *Script) SetImports(modules *ModuleMap) { | ||||
| func (s *Script) SetImports(modules ModuleGetter) { | ||||
| 	s.modules = modules | ||||
| } | ||||
|  | ||||
| @@ -219,6 +219,18 @@ func (c *Compiled) RunContext(ctx context.Context) (err error) { | ||||
| 	v := NewVM(c.bytecode, c.globals, c.maxAllocs) | ||||
| 	ch := make(chan error, 1) | ||||
| 	go func() { | ||||
| 		defer func() { | ||||
| 			if r := recover(); r != nil { | ||||
| 				switch e := r.(type) { | ||||
| 				case string: | ||||
| 					ch <- fmt.Errorf(e) | ||||
| 				case error: | ||||
| 					ch <- e | ||||
| 				default: | ||||
| 					ch <- fmt.Errorf("unknown panic: %v", e) | ||||
| 				} | ||||
| 			} | ||||
| 		}() | ||||
| 		ch <- v.Run() | ||||
| 	}() | ||||
|  | ||||
|   | ||||
							
								
								
									
										3
									
								
								vendor/github.com/d5/tengo/v2/tengo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										3
									
								
								vendor/github.com/d5/tengo/v2/tengo.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -26,6 +26,9 @@ const ( | ||||
|  | ||||
| 	// MaxFrames is the maximum number of function frames for a VM. | ||||
| 	MaxFrames = 1024 | ||||
|  | ||||
| 	// SourceFileExtDefault is the default extension for source files. | ||||
| 	SourceFileExtDefault = ".tengo" | ||||
| ) | ||||
|  | ||||
| // CallableFunc is a function signature for the callable functions. | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/github.com/d5/tengo/v2/vm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/github.com/d5/tengo/v2/vm.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -293,7 +293,7 @@ func (v *VM) run() { | ||||
| 		case parser.OpMap: | ||||
| 			v.ip += 2 | ||||
| 			numElements := int(v.curInsts[v.ip]) | int(v.curInsts[v.ip-1])<<8 | ||||
| 			kv := make(map[string]Object) | ||||
| 			kv := make(map[string]Object, numElements) | ||||
| 			for i := v.sp - numElements; i < v.sp; i += 2 { | ||||
| 				key := v.stack[i] | ||||
| 				value := v.stack[i+1] | ||||
|   | ||||
							
								
								
									
										8
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/.travis.yml
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,8 +0,0 @@ | ||||
| language: go | ||||
|  | ||||
| go: | ||||
|   - '1.10' | ||||
|   - '1.11' | ||||
|   - '1.12' | ||||
|   - '1.13' | ||||
|   - tip | ||||
							
								
								
									
										1014
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1014
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/bot.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1279
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										1279
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/configs.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										990
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										990
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/types.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -1,990 +0,0 @@ | ||||
| package tgbotapi | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // APIResponse is a response from the Telegram API with the result | ||||
| // stored raw. | ||||
| type APIResponse struct { | ||||
| 	Ok          bool                `json:"ok"` | ||||
| 	Result      json.RawMessage     `json:"result"` | ||||
| 	ErrorCode   int                 `json:"error_code"` | ||||
| 	Description string              `json:"description"` | ||||
| 	Parameters  *ResponseParameters `json:"parameters"` | ||||
| } | ||||
|  | ||||
| // ResponseParameters are various errors that can be returned in APIResponse. | ||||
| type ResponseParameters struct { | ||||
| 	MigrateToChatID int64 `json:"migrate_to_chat_id"` // optional | ||||
| 	RetryAfter      int   `json:"retry_after"`        // optional | ||||
| } | ||||
|  | ||||
| // Update is an update response, from GetUpdates. | ||||
| type Update struct { | ||||
| 	UpdateID           int                 `json:"update_id"` | ||||
| 	Message            *Message            `json:"message"` | ||||
| 	EditedMessage      *Message            `json:"edited_message"` | ||||
| 	ChannelPost        *Message            `json:"channel_post"` | ||||
| 	EditedChannelPost  *Message            `json:"edited_channel_post"` | ||||
| 	InlineQuery        *InlineQuery        `json:"inline_query"` | ||||
| 	ChosenInlineResult *ChosenInlineResult `json:"chosen_inline_result"` | ||||
| 	CallbackQuery      *CallbackQuery      `json:"callback_query"` | ||||
| 	ShippingQuery      *ShippingQuery      `json:"shipping_query"` | ||||
| 	PreCheckoutQuery   *PreCheckoutQuery   `json:"pre_checkout_query"` | ||||
| } | ||||
|  | ||||
| // UpdatesChannel is the channel for getting updates. | ||||
| type UpdatesChannel <-chan Update | ||||
|  | ||||
| // Clear discards all unprocessed incoming updates. | ||||
| func (ch UpdatesChannel) Clear() { | ||||
| 	for len(ch) != 0 { | ||||
| 		<-ch | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // User is a user on Telegram. | ||||
| type User struct { | ||||
| 	ID           int    `json:"id"` | ||||
| 	FirstName    string `json:"first_name"` | ||||
| 	LastName     string `json:"last_name"`     // optional | ||||
| 	UserName     string `json:"username"`      // optional | ||||
| 	LanguageCode string `json:"language_code"` // optional | ||||
| 	IsBot        bool   `json:"is_bot"`        // optional | ||||
| } | ||||
|  | ||||
| // String displays a simple text version of a user. | ||||
| // | ||||
| // It is normally a user's username, but falls back to a first/last | ||||
| // name as available. | ||||
| func (u *User) String() string { | ||||
| 	if u == nil { | ||||
| 		return "" | ||||
| 	} | ||||
| 	if u.UserName != "" { | ||||
| 		return u.UserName | ||||
| 	} | ||||
|  | ||||
| 	name := u.FirstName | ||||
| 	if u.LastName != "" { | ||||
| 		name += " " + u.LastName | ||||
| 	} | ||||
|  | ||||
| 	return name | ||||
| } | ||||
|  | ||||
| // GroupChat is a group chat. | ||||
| type GroupChat struct { | ||||
| 	ID    int    `json:"id"` | ||||
| 	Title string `json:"title"` | ||||
| } | ||||
|  | ||||
| // ChatPhoto represents a chat photo. | ||||
| type ChatPhoto struct { | ||||
| 	SmallFileID string `json:"small_file_id"` | ||||
| 	BigFileID   string `json:"big_file_id"` | ||||
| } | ||||
|  | ||||
| // Chat contains information about the place a message was sent. | ||||
| type Chat struct { | ||||
| 	ID                  int64      `json:"id"` | ||||
| 	Type                string     `json:"type"` | ||||
| 	Title               string     `json:"title"`                          // optional | ||||
| 	UserName            string     `json:"username"`                       // optional | ||||
| 	FirstName           string     `json:"first_name"`                     // optional | ||||
| 	LastName            string     `json:"last_name"`                      // optional | ||||
| 	AllMembersAreAdmins bool       `json:"all_members_are_administrators"` // optional | ||||
| 	Photo               *ChatPhoto `json:"photo"` | ||||
| 	Description         string     `json:"description,omitempty"` // optional | ||||
| 	InviteLink          string     `json:"invite_link,omitempty"` // optional | ||||
| 	PinnedMessage       *Message   `json:"pinned_message"`        // optional | ||||
| } | ||||
|  | ||||
| // IsPrivate returns if the Chat is a private conversation. | ||||
| func (c Chat) IsPrivate() bool { | ||||
| 	return c.Type == "private" | ||||
| } | ||||
|  | ||||
| // IsGroup returns if the Chat is a group. | ||||
| func (c Chat) IsGroup() bool { | ||||
| 	return c.Type == "group" | ||||
| } | ||||
|  | ||||
| // IsSuperGroup returns if the Chat is a supergroup. | ||||
| func (c Chat) IsSuperGroup() bool { | ||||
| 	return c.Type == "supergroup" | ||||
| } | ||||
|  | ||||
| // IsChannel returns if the Chat is a channel. | ||||
| func (c Chat) IsChannel() bool { | ||||
| 	return c.Type == "channel" | ||||
| } | ||||
|  | ||||
| // ChatConfig returns a ChatConfig struct for chat related methods. | ||||
| func (c Chat) ChatConfig() ChatConfig { | ||||
| 	return ChatConfig{ChatID: c.ID} | ||||
| } | ||||
|  | ||||
| // Message is returned by almost every request, and contains data about | ||||
| // almost anything. | ||||
| type Message struct { | ||||
| 	MessageID             int                `json:"message_id"` | ||||
| 	From                  *User              `json:"from"` // optional | ||||
| 	Date                  int                `json:"date"` | ||||
| 	Chat                  *Chat              `json:"chat"` | ||||
| 	ForwardFrom           *User              `json:"forward_from"`            // optional | ||||
| 	ForwardFromChat       *Chat              `json:"forward_from_chat"`       // optional | ||||
| 	ForwardFromMessageID  int                `json:"forward_from_message_id"` // optional | ||||
| 	ForwardDate           int                `json:"forward_date"`            // optional | ||||
| 	ReplyToMessage        *Message           `json:"reply_to_message"`        // optional | ||||
| 	EditDate              int                `json:"edit_date"`               // optional | ||||
| 	Text                  string             `json:"text"`                    // optional | ||||
| 	Entities              *[]MessageEntity   `json:"entities"`                // optional | ||||
| 	CaptionEntities       *[]MessageEntity   `json:"caption_entities"`        // optional | ||||
| 	Audio                 *Audio             `json:"audio"`                   // optional | ||||
| 	Document              *Document          `json:"document"`                // optional | ||||
| 	Animation             *ChatAnimation     `json:"animation"`               // optional | ||||
| 	Game                  *Game              `json:"game"`                    // optional | ||||
| 	Photo                 *[]PhotoSize       `json:"photo"`                   // optional | ||||
| 	Sticker               *Sticker           `json:"sticker"`                 // optional | ||||
| 	Video                 *Video             `json:"video"`                   // optional | ||||
| 	VideoNote             *VideoNote         `json:"video_note"`              // optional | ||||
| 	Voice                 *Voice             `json:"voice"`                   // optional | ||||
| 	Caption               string             `json:"caption"`                 // optional | ||||
| 	Contact               *Contact           `json:"contact"`                 // optional | ||||
| 	Location              *Location          `json:"location"`                // optional | ||||
| 	Venue                 *Venue             `json:"venue"`                   // optional | ||||
| 	NewChatMembers        *[]User            `json:"new_chat_members"`        // optional | ||||
| 	LeftChatMember        *User              `json:"left_chat_member"`        // optional | ||||
| 	NewChatTitle          string             `json:"new_chat_title"`          // optional | ||||
| 	NewChatPhoto          *[]PhotoSize       `json:"new_chat_photo"`          // optional | ||||
| 	DeleteChatPhoto       bool               `json:"delete_chat_photo"`       // optional | ||||
| 	GroupChatCreated      bool               `json:"group_chat_created"`      // optional | ||||
| 	SuperGroupChatCreated bool               `json:"supergroup_chat_created"` // optional | ||||
| 	ChannelChatCreated    bool               `json:"channel_chat_created"`    // optional | ||||
| 	MigrateToChatID       int64              `json:"migrate_to_chat_id"`      // optional | ||||
| 	MigrateFromChatID     int64              `json:"migrate_from_chat_id"`    // optional | ||||
| 	PinnedMessage         *Message           `json:"pinned_message"`          // optional | ||||
| 	Invoice               *Invoice           `json:"invoice"`                 // optional | ||||
| 	SuccessfulPayment     *SuccessfulPayment `json:"successful_payment"`      // optional | ||||
| 	PassportData          *PassportData      `json:"passport_data,omitempty"` // optional | ||||
| } | ||||
|  | ||||
| // Time converts the message timestamp into a Time. | ||||
| func (m *Message) Time() time.Time { | ||||
| 	return time.Unix(int64(m.Date), 0) | ||||
| } | ||||
|  | ||||
| // IsCommand returns true if message starts with a "bot_command" entity. | ||||
| func (m *Message) IsCommand() bool { | ||||
| 	if m.Entities == nil || len(*m.Entities) == 0 { | ||||
| 		return false | ||||
| 	} | ||||
|  | ||||
| 	entity := (*m.Entities)[0] | ||||
| 	return entity.Offset == 0 && entity.IsCommand() | ||||
| } | ||||
|  | ||||
| // Command checks if the message was a command and if it was, returns the | ||||
| // command. If the Message was not a command, it returns an empty string. | ||||
| // | ||||
| // If the command contains the at name syntax, it is removed. Use | ||||
| // CommandWithAt() if you do not want that. | ||||
| func (m *Message) Command() string { | ||||
| 	command := m.CommandWithAt() | ||||
|  | ||||
| 	if i := strings.Index(command, "@"); i != -1 { | ||||
| 		command = command[:i] | ||||
| 	} | ||||
|  | ||||
| 	return command | ||||
| } | ||||
|  | ||||
| // CommandWithAt checks if the message was a command and if it was, returns the | ||||
| // command. If the Message was not a command, it returns an empty string. | ||||
| // | ||||
| // If the command contains the at name syntax, it is not removed. Use Command() | ||||
| // if you want that. | ||||
| func (m *Message) CommandWithAt() string { | ||||
| 	if !m.IsCommand() { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	// IsCommand() checks that the message begins with a bot_command entity | ||||
| 	entity := (*m.Entities)[0] | ||||
| 	return m.Text[1:entity.Length] | ||||
| } | ||||
|  | ||||
| // CommandArguments checks if the message was a command and if it was, | ||||
| // returns all text after the command name. If the Message was not a | ||||
| // command, it returns an empty string. | ||||
| // | ||||
| // Note: The first character after the command name is omitted: | ||||
| // - "/foo bar baz" yields "bar baz", not " bar baz" | ||||
| // - "/foo-bar baz" yields "bar baz", too | ||||
| // Even though the latter is not a command conforming to the spec, the API | ||||
| // marks "/foo" as command entity. | ||||
| func (m *Message) CommandArguments() string { | ||||
| 	if !m.IsCommand() { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	// IsCommand() checks that the message begins with a bot_command entity | ||||
| 	entity := (*m.Entities)[0] | ||||
| 	if len(m.Text) == entity.Length { | ||||
| 		return "" // The command makes up the whole message | ||||
| 	} | ||||
|  | ||||
| 	return m.Text[entity.Length+1:] | ||||
| } | ||||
|  | ||||
| // MessageEntity contains information about data in a Message. | ||||
| type MessageEntity struct { | ||||
| 	Type   string `json:"type"` | ||||
| 	Offset int    `json:"offset"` | ||||
| 	Length int    `json:"length"` | ||||
| 	URL    string `json:"url"`  // optional | ||||
| 	User   *User  `json:"user"` // optional | ||||
| } | ||||
|  | ||||
| // ParseURL attempts to parse a URL contained within a MessageEntity. | ||||
| func (e MessageEntity) ParseURL() (*url.URL, error) { | ||||
| 	if e.URL == "" { | ||||
| 		return nil, errors.New(ErrBadURL) | ||||
| 	} | ||||
|  | ||||
| 	return url.Parse(e.URL) | ||||
| } | ||||
|  | ||||
| // IsMention returns true if the type of the message entity is "mention" (@username). | ||||
| func (e MessageEntity) IsMention() bool { | ||||
| 	return e.Type == "mention" | ||||
| } | ||||
|  | ||||
| // IsHashtag returns true if the type of the message entity is "hashtag". | ||||
| func (e MessageEntity) IsHashtag() bool { | ||||
| 	return e.Type == "hashtag" | ||||
| } | ||||
|  | ||||
| // IsCommand returns true if the type of the message entity is "bot_command". | ||||
| func (e MessageEntity) IsCommand() bool { | ||||
| 	return e.Type == "bot_command" | ||||
| } | ||||
|  | ||||
| // IsUrl returns true if the type of the message entity is "url". | ||||
| func (e MessageEntity) IsUrl() bool { | ||||
| 	return e.Type == "url" | ||||
| } | ||||
|  | ||||
| // IsEmail returns true if the type of the message entity is "email". | ||||
| func (e MessageEntity) IsEmail() bool { | ||||
| 	return e.Type == "email" | ||||
| } | ||||
|  | ||||
| // IsBold returns true if the type of the message entity is "bold" (bold text). | ||||
| func (e MessageEntity) IsBold() bool { | ||||
| 	return e.Type == "bold" | ||||
| } | ||||
|  | ||||
| // IsItalic returns true if the type of the message entity is "italic" (italic text). | ||||
| func (e MessageEntity) IsItalic() bool { | ||||
| 	return e.Type == "italic" | ||||
| } | ||||
|  | ||||
| // IsCode returns true if the type of the message entity is "code" (monowidth string). | ||||
| func (e MessageEntity) IsCode() bool { | ||||
| 	return e.Type == "code" | ||||
| } | ||||
|  | ||||
| // IsPre returns true if the type of the message entity is "pre" (monowidth block). | ||||
| func (e MessageEntity) IsPre() bool { | ||||
| 	return e.Type == "pre" | ||||
| } | ||||
|  | ||||
| // IsTextLink returns true if the type of the message entity is "text_link" (clickable text URL). | ||||
| func (e MessageEntity) IsTextLink() bool { | ||||
| 	return e.Type == "text_link" | ||||
| } | ||||
|  | ||||
| // PhotoSize contains information about photos. | ||||
| type PhotoSize struct { | ||||
| 	FileID   string `json:"file_id"` | ||||
| 	Width    int    `json:"width"` | ||||
| 	Height   int    `json:"height"` | ||||
| 	FileSize int    `json:"file_size"` // optional | ||||
| } | ||||
|  | ||||
| // Audio contains information about audio. | ||||
| type Audio struct { | ||||
| 	FileID    string `json:"file_id"` | ||||
| 	Duration  int    `json:"duration"` | ||||
| 	Performer string `json:"performer"` // optional | ||||
| 	Title     string `json:"title"`     // optional | ||||
| 	MimeType  string `json:"mime_type"` // optional | ||||
| 	FileSize  int    `json:"file_size"` // optional | ||||
| } | ||||
|  | ||||
| // Document contains information about a document. | ||||
| type Document struct { | ||||
| 	FileID    string     `json:"file_id"` | ||||
| 	Thumbnail *PhotoSize `json:"thumb"`     // optional | ||||
| 	FileName  string     `json:"file_name"` // optional | ||||
| 	MimeType  string     `json:"mime_type"` // optional | ||||
| 	FileSize  int        `json:"file_size"` // optional | ||||
| } | ||||
|  | ||||
| // Sticker contains information about a sticker. | ||||
| type Sticker struct { | ||||
| 	FileUniqueID string     `json:"file_unique_id"` | ||||
| 	FileID       string     `json:"file_id"` | ||||
| 	Width        int        `json:"width"` | ||||
| 	Height       int        `json:"height"` | ||||
| 	Thumbnail    *PhotoSize `json:"thumb"`       // optional | ||||
| 	Emoji        string     `json:"emoji"`       // optional | ||||
| 	FileSize     int        `json:"file_size"`   // optional | ||||
| 	SetName      string     `json:"set_name"`    // optional | ||||
| 	IsAnimated   bool       `json:"is_animated"` // optional | ||||
| } | ||||
|  | ||||
| type StickerSet struct { | ||||
| 	Name          string    `json:"name"` | ||||
| 	Title         string    `json:"title"` | ||||
| 	IsAnimated    bool      `json:"is_animated"` | ||||
| 	ContainsMasks bool      `json:"contains_masks"` | ||||
| 	Stickers      []Sticker `json:"stickers"` | ||||
| } | ||||
|  | ||||
| // ChatAnimation contains information about an animation. | ||||
| type ChatAnimation struct { | ||||
| 	FileID    string     `json:"file_id"` | ||||
| 	Width     int        `json:"width"` | ||||
| 	Height    int        `json:"height"` | ||||
| 	Duration  int        `json:"duration"` | ||||
| 	Thumbnail *PhotoSize `json:"thumb"`     // optional | ||||
| 	FileName  string     `json:"file_name"` // optional | ||||
| 	MimeType  string     `json:"mime_type"` // optional | ||||
| 	FileSize  int        `json:"file_size"` // optional | ||||
| } | ||||
|  | ||||
| // Video contains information about a video. | ||||
| type Video struct { | ||||
| 	FileID    string     `json:"file_id"` | ||||
| 	Width     int        `json:"width"` | ||||
| 	Height    int        `json:"height"` | ||||
| 	Duration  int        `json:"duration"` | ||||
| 	Thumbnail *PhotoSize `json:"thumb"`     // optional | ||||
| 	MimeType  string     `json:"mime_type"` // optional | ||||
| 	FileSize  int        `json:"file_size"` // optional | ||||
| } | ||||
|  | ||||
| // VideoNote contains information about a video. | ||||
| type VideoNote struct { | ||||
| 	FileID    string     `json:"file_id"` | ||||
| 	Length    int        `json:"length"` | ||||
| 	Duration  int        `json:"duration"` | ||||
| 	Thumbnail *PhotoSize `json:"thumb"`     // optional | ||||
| 	FileSize  int        `json:"file_size"` // optional | ||||
| } | ||||
|  | ||||
| // Voice contains information about a voice. | ||||
| type Voice struct { | ||||
| 	FileID   string `json:"file_id"` | ||||
| 	Duration int    `json:"duration"` | ||||
| 	MimeType string `json:"mime_type"` // optional | ||||
| 	FileSize int    `json:"file_size"` // optional | ||||
| } | ||||
|  | ||||
| // Contact contains information about a contact. | ||||
| // | ||||
| // Note that LastName and UserID may be empty. | ||||
| type Contact struct { | ||||
| 	PhoneNumber string `json:"phone_number"` | ||||
| 	FirstName   string `json:"first_name"` | ||||
| 	LastName    string `json:"last_name"` // optional | ||||
| 	UserID      int    `json:"user_id"`   // optional | ||||
| } | ||||
|  | ||||
| // Location contains information about a place. | ||||
| type Location struct { | ||||
| 	Longitude float64 `json:"longitude"` | ||||
| 	Latitude  float64 `json:"latitude"` | ||||
| } | ||||
|  | ||||
| // Venue contains information about a venue, including its Location. | ||||
| type Venue struct { | ||||
| 	Location     Location `json:"location"` | ||||
| 	Title        string   `json:"title"` | ||||
| 	Address      string   `json:"address"` | ||||
| 	FoursquareID string   `json:"foursquare_id"` // optional | ||||
| } | ||||
|  | ||||
| // UserProfilePhotos contains a set of user profile photos. | ||||
| type UserProfilePhotos struct { | ||||
| 	TotalCount int           `json:"total_count"` | ||||
| 	Photos     [][]PhotoSize `json:"photos"` | ||||
| } | ||||
|  | ||||
| // File contains information about a file to download from Telegram. | ||||
| type File struct { | ||||
| 	FileID   string `json:"file_id"` | ||||
| 	FileSize int    `json:"file_size"` // optional | ||||
| 	FilePath string `json:"file_path"` // optional | ||||
| } | ||||
|  | ||||
| // Link returns a full path to the download URL for a File. | ||||
| // | ||||
| // It requires the Bot Token to create the link. | ||||
| func (f *File) Link(token string) string { | ||||
| 	return fmt.Sprintf(FileEndpoint, token, f.FilePath) | ||||
| } | ||||
|  | ||||
| // ReplyKeyboardMarkup allows the Bot to set a custom keyboard. | ||||
| type ReplyKeyboardMarkup struct { | ||||
| 	Keyboard        [][]KeyboardButton `json:"keyboard"` | ||||
| 	ResizeKeyboard  bool               `json:"resize_keyboard"`   // optional | ||||
| 	OneTimeKeyboard bool               `json:"one_time_keyboard"` // optional | ||||
| 	Selective       bool               `json:"selective"`         // optional | ||||
| } | ||||
|  | ||||
| // KeyboardButton is a button within a custom keyboard. | ||||
| type KeyboardButton struct { | ||||
| 	Text            string `json:"text"` | ||||
| 	RequestContact  bool   `json:"request_contact"` | ||||
| 	RequestLocation bool   `json:"request_location"` | ||||
| } | ||||
|  | ||||
| // ReplyKeyboardHide allows the Bot to hide a custom keyboard. | ||||
| type ReplyKeyboardHide struct { | ||||
| 	HideKeyboard bool `json:"hide_keyboard"` | ||||
| 	Selective    bool `json:"selective"` // optional | ||||
| } | ||||
|  | ||||
| // ReplyKeyboardRemove allows the Bot to hide a custom keyboard. | ||||
| type ReplyKeyboardRemove struct { | ||||
| 	RemoveKeyboard bool `json:"remove_keyboard"` | ||||
| 	Selective      bool `json:"selective"` | ||||
| } | ||||
|  | ||||
| // InlineKeyboardMarkup is a custom keyboard presented for an inline bot. | ||||
| type InlineKeyboardMarkup struct { | ||||
| 	InlineKeyboard [][]InlineKeyboardButton `json:"inline_keyboard"` | ||||
| } | ||||
|  | ||||
| // InlineKeyboardButton is a button within a custom keyboard for | ||||
| // inline query responses. | ||||
| // | ||||
| // Note that some values are references as even an empty string | ||||
| // will change behavior. | ||||
| // | ||||
| // CallbackGame, if set, MUST be first button in first row. | ||||
| type InlineKeyboardButton struct { | ||||
| 	Text                         string        `json:"text"` | ||||
| 	URL                          *string       `json:"url,omitempty"`                              // optional | ||||
| 	CallbackData                 *string       `json:"callback_data,omitempty"`                    // optional | ||||
| 	SwitchInlineQuery            *string       `json:"switch_inline_query,omitempty"`              // optional | ||||
| 	SwitchInlineQueryCurrentChat *string       `json:"switch_inline_query_current_chat,omitempty"` // optional | ||||
| 	CallbackGame                 *CallbackGame `json:"callback_game,omitempty"`                    // optional | ||||
| 	Pay                          bool          `json:"pay,omitempty"`                              // optional | ||||
| } | ||||
|  | ||||
| // CallbackQuery is data sent when a keyboard button with callback data | ||||
| // is clicked. | ||||
| type CallbackQuery struct { | ||||
| 	ID              string   `json:"id"` | ||||
| 	From            *User    `json:"from"` | ||||
| 	Message         *Message `json:"message"`           // optional | ||||
| 	InlineMessageID string   `json:"inline_message_id"` // optional | ||||
| 	ChatInstance    string   `json:"chat_instance"` | ||||
| 	Data            string   `json:"data"`            // optional | ||||
| 	GameShortName   string   `json:"game_short_name"` // optional | ||||
| } | ||||
|  | ||||
| // ForceReply allows the Bot to have users directly reply to it without | ||||
| // additional interaction. | ||||
| type ForceReply struct { | ||||
| 	ForceReply bool `json:"force_reply"` | ||||
| 	Selective  bool `json:"selective"` // optional | ||||
| } | ||||
|  | ||||
| // ChatMember is information about a member in a chat. | ||||
| type ChatMember struct { | ||||
| 	User                  *User  `json:"user"` | ||||
| 	Status                string `json:"status"` | ||||
| 	UntilDate             int64  `json:"until_date,omitempty"`                // optional | ||||
| 	CanBeEdited           bool   `json:"can_be_edited,omitempty"`             // optional | ||||
| 	CanChangeInfo         bool   `json:"can_change_info,omitempty"`           // optional | ||||
| 	CanPostMessages       bool   `json:"can_post_messages,omitempty"`         // optional | ||||
| 	CanEditMessages       bool   `json:"can_edit_messages,omitempty"`         // optional | ||||
| 	CanDeleteMessages     bool   `json:"can_delete_messages,omitempty"`       // optional | ||||
| 	CanInviteUsers        bool   `json:"can_invite_users,omitempty"`          // optional | ||||
| 	CanRestrictMembers    bool   `json:"can_restrict_members,omitempty"`      // optional | ||||
| 	CanPinMessages        bool   `json:"can_pin_messages,omitempty"`          // optional | ||||
| 	CanPromoteMembers     bool   `json:"can_promote_members,omitempty"`       // optional | ||||
| 	CanSendMessages       bool   `json:"can_send_messages,omitempty"`         // optional | ||||
| 	CanSendMediaMessages  bool   `json:"can_send_media_messages,omitempty"`   // optional | ||||
| 	CanSendOtherMessages  bool   `json:"can_send_other_messages,omitempty"`   // optional | ||||
| 	CanAddWebPagePreviews bool   `json:"can_add_web_page_previews,omitempty"` // optional | ||||
| } | ||||
|  | ||||
| // IsCreator returns if the ChatMember was the creator of the chat. | ||||
| func (chat ChatMember) IsCreator() bool { return chat.Status == "creator" } | ||||
|  | ||||
| // IsAdministrator returns if the ChatMember is a chat administrator. | ||||
| func (chat ChatMember) IsAdministrator() bool { return chat.Status == "administrator" } | ||||
|  | ||||
| // IsMember returns if the ChatMember is a current member of the chat. | ||||
| func (chat ChatMember) IsMember() bool { return chat.Status == "member" } | ||||
|  | ||||
| // HasLeft returns if the ChatMember left the chat. | ||||
| func (chat ChatMember) HasLeft() bool { return chat.Status == "left" } | ||||
|  | ||||
| // WasKicked returns if the ChatMember was kicked from the chat. | ||||
| func (chat ChatMember) WasKicked() bool { return chat.Status == "kicked" } | ||||
|  | ||||
| // Game is a game within Telegram. | ||||
| type Game struct { | ||||
| 	Title        string          `json:"title"` | ||||
| 	Description  string          `json:"description"` | ||||
| 	Photo        []PhotoSize     `json:"photo"` | ||||
| 	Text         string          `json:"text"` | ||||
| 	TextEntities []MessageEntity `json:"text_entities"` | ||||
| 	Animation    Animation       `json:"animation"` | ||||
| } | ||||
|  | ||||
| // Animation is a GIF animation demonstrating the game. | ||||
| type Animation struct { | ||||
| 	FileID   string    `json:"file_id"` | ||||
| 	Thumb    PhotoSize `json:"thumb"` | ||||
| 	FileName string    `json:"file_name"` | ||||
| 	MimeType string    `json:"mime_type"` | ||||
| 	FileSize int       `json:"file_size"` | ||||
| } | ||||
|  | ||||
| // GameHighScore is a user's score and position on the leaderboard. | ||||
| type GameHighScore struct { | ||||
| 	Position int  `json:"position"` | ||||
| 	User     User `json:"user"` | ||||
| 	Score    int  `json:"score"` | ||||
| } | ||||
|  | ||||
| // CallbackGame is for starting a game in an inline keyboard button. | ||||
| type CallbackGame struct{} | ||||
|  | ||||
| // WebhookInfo is information about a currently set webhook. | ||||
| type WebhookInfo struct { | ||||
| 	URL                  string `json:"url"` | ||||
| 	HasCustomCertificate bool   `json:"has_custom_certificate"` | ||||
| 	PendingUpdateCount   int    `json:"pending_update_count"` | ||||
| 	LastErrorDate        int    `json:"last_error_date"`    // optional | ||||
| 	LastErrorMessage     string `json:"last_error_message"` // optional | ||||
| } | ||||
|  | ||||
| // IsSet returns true if a webhook is currently set. | ||||
| func (info WebhookInfo) IsSet() bool { | ||||
| 	return info.URL != "" | ||||
| } | ||||
|  | ||||
| // InputMediaPhoto contains a photo for displaying as part of a media group. | ||||
| type InputMediaPhoto struct { | ||||
| 	Type      string `json:"type"` | ||||
| 	Media     string `json:"media"` | ||||
| 	Caption   string `json:"caption"` | ||||
| 	ParseMode string `json:"parse_mode"` | ||||
| } | ||||
|  | ||||
| // InputMediaVideo contains a video for displaying as part of a media group. | ||||
| type InputMediaVideo struct { | ||||
| 	Type  string `json:"type"` | ||||
| 	Media string `json:"media"` | ||||
| 	// thumb intentionally missing as it is not currently compatible | ||||
| 	Caption           string `json:"caption"` | ||||
| 	ParseMode         string `json:"parse_mode"` | ||||
| 	Width             int    `json:"width"` | ||||
| 	Height            int    `json:"height"` | ||||
| 	Duration          int    `json:"duration"` | ||||
| 	SupportsStreaming bool   `json:"supports_streaming"` | ||||
| } | ||||
|  | ||||
| // InlineQuery is a Query from Telegram for an inline request. | ||||
| type InlineQuery struct { | ||||
| 	ID       string    `json:"id"` | ||||
| 	From     *User     `json:"from"` | ||||
| 	Location *Location `json:"location"` // optional | ||||
| 	Query    string    `json:"query"` | ||||
| 	Offset   string    `json:"offset"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultArticle is an inline query response article. | ||||
| type InlineQueryResultArticle struct { | ||||
| 	Type                string                `json:"type"`                            // required | ||||
| 	ID                  string                `json:"id"`                              // required | ||||
| 	Title               string                `json:"title"`                           // required | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` // required | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	URL                 string                `json:"url"` | ||||
| 	HideURL             bool                  `json:"hide_url"` | ||||
| 	Description         string                `json:"description"` | ||||
| 	ThumbURL            string                `json:"thumb_url"` | ||||
| 	ThumbWidth          int                   `json:"thumb_width"` | ||||
| 	ThumbHeight         int                   `json:"thumb_height"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultPhoto is an inline query response photo. | ||||
| type InlineQueryResultPhoto struct { | ||||
| 	Type                string                `json:"type"`      // required | ||||
| 	ID                  string                `json:"id"`        // required | ||||
| 	URL                 string                `json:"photo_url"` // required | ||||
| 	MimeType            string                `json:"mime_type"` | ||||
| 	Width               int                   `json:"photo_width"` | ||||
| 	Height              int                   `json:"photo_height"` | ||||
| 	ThumbURL            string                `json:"thumb_url"` | ||||
| 	Title               string                `json:"title"` | ||||
| 	Description         string                `json:"description"` | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	ParseMode           string                `json:"parse_mode"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultCachedPhoto is an inline query response with cached photo. | ||||
| type InlineQueryResultCachedPhoto struct { | ||||
| 	Type                string                `json:"type"`          // required | ||||
| 	ID                  string                `json:"id"`            // required | ||||
| 	PhotoID             string                `json:"photo_file_id"` // required | ||||
| 	Title               string                `json:"title"` | ||||
| 	Description         string                `json:"description"` | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	ParseMode           string                `json:"parse_mode"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultGIF is an inline query response GIF. | ||||
| type InlineQueryResultGIF struct { | ||||
| 	Type                string                `json:"type"`      // required | ||||
| 	ID                  string                `json:"id"`        // required | ||||
| 	URL                 string                `json:"gif_url"`   // required | ||||
| 	ThumbURL            string                `json:"thumb_url"` // required | ||||
| 	Width               int                   `json:"gif_width,omitempty"` | ||||
| 	Height              int                   `json:"gif_height,omitempty"` | ||||
| 	Duration            int                   `json:"gif_duration,omitempty"` | ||||
| 	Title               string                `json:"title,omitempty"` | ||||
| 	Caption             string                `json:"caption,omitempty"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultCachedGIF is an inline query response with cached gif. | ||||
| type InlineQueryResultCachedGIF struct { | ||||
| 	Type                string                `json:"type"`        // required | ||||
| 	ID                  string                `json:"id"`          // required | ||||
| 	GifID               string                `json:"gif_file_id"` // required | ||||
| 	Title               string                `json:"title"` | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	ParseMode           string                `json:"parse_mode"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultMPEG4GIF is an inline query response MPEG4 GIF. | ||||
| type InlineQueryResultMPEG4GIF struct { | ||||
| 	Type                string                `json:"type"`      // required | ||||
| 	ID                  string                `json:"id"`        // required | ||||
| 	URL                 string                `json:"mpeg4_url"` // required | ||||
| 	Width               int                   `json:"mpeg4_width"` | ||||
| 	Height              int                   `json:"mpeg4_height"` | ||||
| 	Duration            int                   `json:"mpeg4_duration"` | ||||
| 	ThumbURL            string                `json:"thumb_url"` | ||||
| 	Title               string                `json:"title"` | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultCachedMpeg4Gif is an inline query response with cached | ||||
| // H.264/MPEG-4 AVC video without sound gif. | ||||
| type InlineQueryResultCachedMpeg4Gif struct { | ||||
| 	Type                string                `json:"type"`          // required | ||||
| 	ID                  string                `json:"id"`            // required | ||||
| 	MGifID              string                `json:"mpeg4_file_id"` // required | ||||
| 	Title               string                `json:"title"` | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	ParseMode           string                `json:"parse_mode"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultVideo is an inline query response video. | ||||
| type InlineQueryResultVideo struct { | ||||
| 	Type                string                `json:"type"`      // required | ||||
| 	ID                  string                `json:"id"`        // required | ||||
| 	URL                 string                `json:"video_url"` // required | ||||
| 	MimeType            string                `json:"mime_type"` // required | ||||
| 	ThumbURL            string                `json:"thumb_url"` | ||||
| 	Title               string                `json:"title"` | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	Width               int                   `json:"video_width"` | ||||
| 	Height              int                   `json:"video_height"` | ||||
| 	Duration            int                   `json:"video_duration"` | ||||
| 	Description         string                `json:"description"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultCachedVideo is an inline query response with cached video. | ||||
| type InlineQueryResultCachedVideo struct { | ||||
| 	Type                string                `json:"type"`          // required | ||||
| 	ID                  string                `json:"id"`            // required | ||||
| 	VideoID             string                `json:"video_file_id"` // required | ||||
| 	Title               string                `json:"title"`         // required | ||||
| 	Description         string                `json:"description"` | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	ParseMode           string                `json:"parse_mode"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultAudio is an inline query response audio. | ||||
| type InlineQueryResultAudio struct { | ||||
| 	Type                string                `json:"type"`      // required | ||||
| 	ID                  string                `json:"id"`        // required | ||||
| 	URL                 string                `json:"audio_url"` // required | ||||
| 	Title               string                `json:"title"`     // required | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	Performer           string                `json:"performer"` | ||||
| 	Duration            int                   `json:"audio_duration"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultCachedAudio is an inline query response with cached audio. | ||||
| type InlineQueryResultCachedAudio struct { | ||||
| 	Type                string                `json:"type"`          // required | ||||
| 	ID                  string                `json:"id"`            // required | ||||
| 	AudioID             string                `json:"audio_file_id"` // required | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	ParseMode           string                `json:"parse_mode"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultVoice is an inline query response voice. | ||||
| type InlineQueryResultVoice struct { | ||||
| 	Type                string                `json:"type"`      // required | ||||
| 	ID                  string                `json:"id"`        // required | ||||
| 	URL                 string                `json:"voice_url"` // required | ||||
| 	Title               string                `json:"title"`     // required | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	Duration            int                   `json:"voice_duration"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultCachedVoice is an inline query response with cached voice. | ||||
| type InlineQueryResultCachedVoice struct { | ||||
| 	Type                string                `json:"type"`          // required | ||||
| 	ID                  string                `json:"id"`            // required | ||||
| 	VoiceID             string                `json:"voice_file_id"` // required | ||||
| 	Title               string                `json:"title"`         // required | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	ParseMode           string                `json:"parse_mode"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultDocument is an inline query response document. | ||||
| type InlineQueryResultDocument struct { | ||||
| 	Type                string                `json:"type"`  // required | ||||
| 	ID                  string                `json:"id"`    // required | ||||
| 	Title               string                `json:"title"` // required | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	URL                 string                `json:"document_url"` // required | ||||
| 	MimeType            string                `json:"mime_type"`    // required | ||||
| 	Description         string                `json:"description"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| 	ThumbURL            string                `json:"thumb_url"` | ||||
| 	ThumbWidth          int                   `json:"thumb_width"` | ||||
| 	ThumbHeight         int                   `json:"thumb_height"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultCachedDocument is an inline query response with cached document. | ||||
| type InlineQueryResultCachedDocument struct { | ||||
| 	Type                string                `json:"type"`             // required | ||||
| 	ID                  string                `json:"id"`               // required | ||||
| 	DocumentID          string                `json:"document_file_id"` // required | ||||
| 	Title               string                `json:"title"`            // required | ||||
| 	Caption             string                `json:"caption"` | ||||
| 	Description         string                `json:"description"` | ||||
| 	ParseMode           string                `json:"parse_mode"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultLocation is an inline query response location. | ||||
| type InlineQueryResultLocation struct { | ||||
| 	Type                string                `json:"type"`      // required | ||||
| 	ID                  string                `json:"id"`        // required | ||||
| 	Latitude            float64               `json:"latitude"`  // required | ||||
| 	Longitude           float64               `json:"longitude"` // required | ||||
| 	Title               string                `json:"title"`     // required | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| 	ThumbURL            string                `json:"thumb_url"` | ||||
| 	ThumbWidth          int                   `json:"thumb_width"` | ||||
| 	ThumbHeight         int                   `json:"thumb_height"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultVenue is an inline query response venue. | ||||
| type InlineQueryResultVenue struct { | ||||
| 	Type                string                `json:"type"`      // required | ||||
| 	ID                  string                `json:"id"`        // required | ||||
| 	Latitude            float64               `json:"latitude"`  // required | ||||
| 	Longitude           float64               `json:"longitude"` // required | ||||
| 	Title               string                `json:"title"`     // required | ||||
| 	Address             string                `json:"address"`   // required | ||||
| 	FoursquareID        string                `json:"foursquare_id"` | ||||
| 	FoursquareType      string                `json:"foursquare_type"` | ||||
| 	ReplyMarkup         *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| 	InputMessageContent interface{}           `json:"input_message_content,omitempty"` | ||||
| 	ThumbURL            string                `json:"thumb_url"` | ||||
| 	ThumbWidth          int                   `json:"thumb_width"` | ||||
| 	ThumbHeight         int                   `json:"thumb_height"` | ||||
| } | ||||
|  | ||||
| // InlineQueryResultGame is an inline query response game. | ||||
| type InlineQueryResultGame struct { | ||||
| 	Type          string                `json:"type"` | ||||
| 	ID            string                `json:"id"` | ||||
| 	GameShortName string                `json:"game_short_name"` | ||||
| 	ReplyMarkup   *InlineKeyboardMarkup `json:"reply_markup,omitempty"` | ||||
| } | ||||
|  | ||||
| // ChosenInlineResult is an inline query result chosen by a User | ||||
| type ChosenInlineResult struct { | ||||
| 	ResultID        string    `json:"result_id"` | ||||
| 	From            *User     `json:"from"` | ||||
| 	Location        *Location `json:"location"` | ||||
| 	InlineMessageID string    `json:"inline_message_id"` | ||||
| 	Query           string    `json:"query"` | ||||
| } | ||||
|  | ||||
| // InputTextMessageContent contains text for displaying | ||||
| // as an inline query result. | ||||
| type InputTextMessageContent struct { | ||||
| 	Text                  string `json:"message_text"` | ||||
| 	ParseMode             string `json:"parse_mode"` | ||||
| 	DisableWebPagePreview bool   `json:"disable_web_page_preview"` | ||||
| } | ||||
|  | ||||
| // InputLocationMessageContent contains a location for displaying | ||||
| // as an inline query result. | ||||
| type InputLocationMessageContent struct { | ||||
| 	Latitude  float64 `json:"latitude"` | ||||
| 	Longitude float64 `json:"longitude"` | ||||
| } | ||||
|  | ||||
| // InputVenueMessageContent contains a venue for displaying | ||||
| // as an inline query result. | ||||
| type InputVenueMessageContent struct { | ||||
| 	Latitude     float64 `json:"latitude"` | ||||
| 	Longitude    float64 `json:"longitude"` | ||||
| 	Title        string  `json:"title"` | ||||
| 	Address      string  `json:"address"` | ||||
| 	FoursquareID string  `json:"foursquare_id"` | ||||
| } | ||||
|  | ||||
| // InputContactMessageContent contains a contact for displaying | ||||
| // as an inline query result. | ||||
| type InputContactMessageContent struct { | ||||
| 	PhoneNumber string `json:"phone_number"` | ||||
| 	FirstName   string `json:"first_name"` | ||||
| 	LastName    string `json:"last_name"` | ||||
| } | ||||
|  | ||||
| // Invoice contains basic information about an invoice. | ||||
| type Invoice struct { | ||||
| 	Title          string `json:"title"` | ||||
| 	Description    string `json:"description"` | ||||
| 	StartParameter string `json:"start_parameter"` | ||||
| 	Currency       string `json:"currency"` | ||||
| 	TotalAmount    int    `json:"total_amount"` | ||||
| } | ||||
|  | ||||
| // LabeledPrice represents a portion of the price for goods or services. | ||||
| type LabeledPrice struct { | ||||
| 	Label  string `json:"label"` | ||||
| 	Amount int    `json:"amount"` | ||||
| } | ||||
|  | ||||
| // ShippingAddress represents a shipping address. | ||||
| type ShippingAddress struct { | ||||
| 	CountryCode string `json:"country_code"` | ||||
| 	State       string `json:"state"` | ||||
| 	City        string `json:"city"` | ||||
| 	StreetLine1 string `json:"street_line1"` | ||||
| 	StreetLine2 string `json:"street_line2"` | ||||
| 	PostCode    string `json:"post_code"` | ||||
| } | ||||
|  | ||||
| // OrderInfo represents information about an order. | ||||
| type OrderInfo struct { | ||||
| 	Name            string           `json:"name,omitempty"` | ||||
| 	PhoneNumber     string           `json:"phone_number,omitempty"` | ||||
| 	Email           string           `json:"email,omitempty"` | ||||
| 	ShippingAddress *ShippingAddress `json:"shipping_address,omitempty"` | ||||
| } | ||||
|  | ||||
| // ShippingOption represents one shipping option. | ||||
| type ShippingOption struct { | ||||
| 	ID     string          `json:"id"` | ||||
| 	Title  string          `json:"title"` | ||||
| 	Prices *[]LabeledPrice `json:"prices"` | ||||
| } | ||||
|  | ||||
| // SuccessfulPayment contains basic information about a successful payment. | ||||
| type SuccessfulPayment struct { | ||||
| 	Currency                string     `json:"currency"` | ||||
| 	TotalAmount             int        `json:"total_amount"` | ||||
| 	InvoicePayload          string     `json:"invoice_payload"` | ||||
| 	ShippingOptionID        string     `json:"shipping_option_id,omitempty"` | ||||
| 	OrderInfo               *OrderInfo `json:"order_info,omitempty"` | ||||
| 	TelegramPaymentChargeID string     `json:"telegram_payment_charge_id"` | ||||
| 	ProviderPaymentChargeID string     `json:"provider_payment_charge_id"` | ||||
| } | ||||
|  | ||||
| // ShippingQuery contains information about an incoming shipping query. | ||||
| type ShippingQuery struct { | ||||
| 	ID              string           `json:"id"` | ||||
| 	From            *User            `json:"from"` | ||||
| 	InvoicePayload  string           `json:"invoice_payload"` | ||||
| 	ShippingAddress *ShippingAddress `json:"shipping_address"` | ||||
| } | ||||
|  | ||||
| // PreCheckoutQuery contains information about an incoming pre-checkout query. | ||||
| type PreCheckoutQuery struct { | ||||
| 	ID               string     `json:"id"` | ||||
| 	From             *User      `json:"from"` | ||||
| 	Currency         string     `json:"currency"` | ||||
| 	TotalAmount      int        `json:"total_amount"` | ||||
| 	InvoicePayload   string     `json:"invoice_payload"` | ||||
| 	ShippingOptionID string     `json:"shipping_option_id,omitempty"` | ||||
| 	OrderInfo        *OrderInfo `json:"order_info,omitempty"` | ||||
| } | ||||
|  | ||||
| // Error is an error containing extra information returned by the Telegram API. | ||||
| type Error struct { | ||||
| 	Code    int | ||||
| 	Message string | ||||
| 	ResponseParameters | ||||
| } | ||||
|  | ||||
| func (e Error) Error() string { | ||||
| 	return e.Message | ||||
| } | ||||
| @@ -1,3 +1,4 @@ | ||||
| .idea/ | ||||
| coverage.out | ||||
| tmp/ | ||||
| book/ | ||||
| @@ -1,12 +1,14 @@ | ||||
| # Golang bindings for the Telegram Bot API | ||||
| 
 | ||||
| [](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) | ||||
| [](https://travis-ci.org/go-telegram-bot-api/telegram-bot-api) | ||||
| [](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5) | ||||
| [](https://github.com/go-telegram-bot-api/telegram-bot-api/actions/workflows/test.yml) | ||||
| 
 | ||||
| All methods are fairly self explanatory, and reading the [godoc](http://godoc.org/github.com/go-telegram-bot-api/telegram-bot-api) page should | ||||
| All methods are fairly self-explanatory, and reading the [godoc](https://pkg.go.dev/github.com/go-telegram-bot-api/telegram-bot-api/v5) page should | ||||
| explain everything. If something isn't clear, open an issue or submit | ||||
| a pull request. | ||||
| 
 | ||||
| There are more tutorials and high-level information on the website, [go-telegram-bot-api.dev](https://go-telegram-bot-api.dev). | ||||
| 
 | ||||
| The scope of this project is just to provide a wrapper around the API | ||||
| without any additional features. There are other projects for creating | ||||
| something with plugins and command handlers without having to design | ||||
| @@ -18,7 +20,7 @@ you want to ask questions or discuss development. | ||||
| ## Example | ||||
| 
 | ||||
| First, ensure the library is installed and up to date by running | ||||
| `go get -u github.com/go-telegram-bot-api/telegram-bot-api`. | ||||
| `go get -u github.com/go-telegram-bot-api/telegram-bot-api/v5`. | ||||
| 
 | ||||
| This is a very simple bot that just displays any gotten updates, | ||||
| then replies it to that chat. | ||||
| @@ -29,7 +31,7 @@ package main | ||||
| import ( | ||||
| 	"log" | ||||
| 
 | ||||
| 	"github.com/go-telegram-bot-api/telegram-bot-api" | ||||
| 	tgbotapi "github.com/go-telegram-bot-api/telegram-bot-api/v5" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| @@ -45,28 +47,21 @@ func main() { | ||||
| 	u := tgbotapi.NewUpdate(0) | ||||
| 	u.Timeout = 60 | ||||
| 
 | ||||
| 	updates, err := bot.GetUpdatesChan(u) | ||||
| 	updates := bot.GetUpdatesChan(u) | ||||
| 
 | ||||
| 	for update := range updates { | ||||
| 		if update.Message == nil { // ignore any non-Message Updates | ||||
| 			continue | ||||
| 		if update.Message != nil { // If we got a message | ||||
| 			log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text) | ||||
| 
 | ||||
| 			msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text) | ||||
| 			msg.ReplyToMessageID = update.Message.MessageID | ||||
| 
 | ||||
| 			bot.Send(msg) | ||||
| 		} | ||||
| 
 | ||||
| 		log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text) | ||||
| 
 | ||||
| 		msg := tgbotapi.NewMessage(update.Message.Chat.ID, update.Message.Text) | ||||
| 		msg.ReplyToMessageID = update.Message.MessageID | ||||
| 
 | ||||
| 		bot.Send(msg) | ||||
| 	} | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| There are more examples on the [wiki](https://github.com/go-telegram-bot-api/telegram-bot-api/wiki) | ||||
| with detailed information on how to do many different kinds of things. | ||||
| It's a great place to get started on using keyboards, commands, or other | ||||
| kinds of reply markup. | ||||
| 
 | ||||
| If you need to use webhooks (if you wish to run on Google App Engine), | ||||
| you may use a slightly different method. | ||||
| 
 | ||||
| @@ -77,7 +72,7 @@ import ( | ||||
| 	"log" | ||||
| 	"net/http" | ||||
| 
 | ||||
| 	"github.com/go-telegram-bot-api/telegram-bot-api" | ||||
| 	"github.com/go-telegram-bot-api/telegram-bot-api/v5" | ||||
| ) | ||||
| 
 | ||||
| func main() { | ||||
| @@ -90,17 +85,22 @@ func main() { | ||||
| 
 | ||||
| 	log.Printf("Authorized on account %s", bot.Self.UserName) | ||||
| 
 | ||||
| 	_, err = bot.SetWebhook(tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem")) | ||||
| 	wh, _ := tgbotapi.NewWebhookWithCert("https://www.google.com:8443/"+bot.Token, "cert.pem") | ||||
| 
 | ||||
| 	_, err = bot.SetWebhook(wh) | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	info, err := bot.GetWebhookInfo() | ||||
| 	if err != nil { | ||||
| 		log.Fatal(err) | ||||
| 	} | ||||
| 
 | ||||
| 	if info.LastErrorDate != 0 { | ||||
| 		log.Printf("Telegram callback failed: %s", info.LastErrorMessage) | ||||
| 	} | ||||
| 
 | ||||
| 	updates := bot.ListenForWebhook("/" + bot.Token) | ||||
| 	go http.ListenAndServeTLS("0.0.0.0:8443", "cert.pem", "key.pem", nil) | ||||
| 
 | ||||
| @@ -110,7 +110,7 @@ func main() { | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| If you need, you may generate a self signed certficate, as this requires | ||||
| If you need, you may generate a self-signed certificate, as this requires | ||||
| HTTPS / TLS. The above example tells Telegram that this is your | ||||
| certificate and that it should be trusted, even though it is not | ||||
| properly signed. | ||||
							
								
								
									
										9
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/book.toml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/book.toml
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| [book] | ||||
| authors = ["Syfaro"] | ||||
| language = "en" | ||||
| multilingual = false | ||||
| src = "docs" | ||||
| title = "Go Telegram Bot API" | ||||
|  | ||||
| [output.html] | ||||
| git-repository-url = "https://github.com/go-telegram-bot-api/telegram-bot-api" | ||||
							
								
								
									
										726
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										726
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/bot.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,726 @@ | ||||
| // Package tgbotapi has functions and types used for interacting with | ||||
| // the Telegram Bot API. | ||||
| package tgbotapi | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"io/ioutil" | ||||
| 	"mime/multipart" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| ) | ||||
|  | ||||
| // HTTPClient is the type needed for the bot to perform HTTP requests. | ||||
| type HTTPClient interface { | ||||
| 	Do(req *http.Request) (*http.Response, error) | ||||
| } | ||||
|  | ||||
| // BotAPI allows you to interact with the Telegram Bot API. | ||||
| type BotAPI struct { | ||||
| 	Token  string `json:"token"` | ||||
| 	Debug  bool   `json:"debug"` | ||||
| 	Buffer int    `json:"buffer"` | ||||
|  | ||||
| 	Self            User       `json:"-"` | ||||
| 	Client          HTTPClient `json:"-"` | ||||
| 	shutdownChannel chan interface{} | ||||
|  | ||||
| 	apiEndpoint string | ||||
| } | ||||
|  | ||||
| // NewBotAPI creates a new BotAPI instance. | ||||
| // | ||||
| // It requires a token, provided by @BotFather on Telegram. | ||||
| func NewBotAPI(token string) (*BotAPI, error) { | ||||
| 	return NewBotAPIWithClient(token, APIEndpoint, &http.Client{}) | ||||
| } | ||||
|  | ||||
| // NewBotAPIWithAPIEndpoint creates a new BotAPI instance | ||||
| // and allows you to pass API endpoint. | ||||
| // | ||||
| // It requires a token, provided by @BotFather on Telegram and API endpoint. | ||||
| func NewBotAPIWithAPIEndpoint(token, apiEndpoint string) (*BotAPI, error) { | ||||
| 	return NewBotAPIWithClient(token, apiEndpoint, &http.Client{}) | ||||
| } | ||||
|  | ||||
| // NewBotAPIWithClient creates a new BotAPI instance | ||||
| // and allows you to pass a http.Client. | ||||
| // | ||||
| // It requires a token, provided by @BotFather on Telegram and API endpoint. | ||||
| func NewBotAPIWithClient(token, apiEndpoint string, client HTTPClient) (*BotAPI, error) { | ||||
| 	bot := &BotAPI{ | ||||
| 		Token:           token, | ||||
| 		Client:          client, | ||||
| 		Buffer:          100, | ||||
| 		shutdownChannel: make(chan interface{}), | ||||
|  | ||||
| 		apiEndpoint: apiEndpoint, | ||||
| 	} | ||||
|  | ||||
| 	self, err := bot.GetMe() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	bot.Self = self | ||||
|  | ||||
| 	return bot, nil | ||||
| } | ||||
|  | ||||
| // SetAPIEndpoint changes the Telegram Bot API endpoint used by the instance. | ||||
| func (bot *BotAPI) SetAPIEndpoint(apiEndpoint string) { | ||||
| 	bot.apiEndpoint = apiEndpoint | ||||
| } | ||||
|  | ||||
| func buildParams(in Params) url.Values { | ||||
| 	if in == nil { | ||||
| 		return url.Values{} | ||||
| 	} | ||||
|  | ||||
| 	out := url.Values{} | ||||
|  | ||||
| 	for key, value := range in { | ||||
| 		out.Set(key, value) | ||||
| 	} | ||||
|  | ||||
| 	return out | ||||
| } | ||||
|  | ||||
| // MakeRequest makes a request to a specific endpoint with our token. | ||||
| func (bot *BotAPI) MakeRequest(endpoint string, params Params) (*APIResponse, error) { | ||||
| 	if bot.Debug { | ||||
| 		log.Printf("Endpoint: %s, params: %v\n", endpoint, params) | ||||
| 	} | ||||
|  | ||||
| 	method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint) | ||||
|  | ||||
| 	values := buildParams(params) | ||||
|  | ||||
| 	req, err := http.NewRequest("POST", method, strings.NewReader(values.Encode())) | ||||
| 	if err != nil { | ||||
| 		return &APIResponse{}, err | ||||
| 	} | ||||
| 	req.Header.Set("Content-Type", "application/x-www-form-urlencoded") | ||||
|  | ||||
| 	resp, err := bot.Client.Do(req) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	var apiResp APIResponse | ||||
| 	bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp) | ||||
| 	if err != nil { | ||||
| 		return &apiResp, err | ||||
| 	} | ||||
|  | ||||
| 	if bot.Debug { | ||||
| 		log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes)) | ||||
| 	} | ||||
|  | ||||
| 	if !apiResp.Ok { | ||||
| 		var parameters ResponseParameters | ||||
|  | ||||
| 		if apiResp.Parameters != nil { | ||||
| 			parameters = *apiResp.Parameters | ||||
| 		} | ||||
|  | ||||
| 		return &apiResp, &Error{ | ||||
| 			Code:               apiResp.ErrorCode, | ||||
| 			Message:            apiResp.Description, | ||||
| 			ResponseParameters: parameters, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &apiResp, nil | ||||
| } | ||||
|  | ||||
| // decodeAPIResponse decode response and return slice of bytes if debug enabled. | ||||
| // If debug disabled, just decode http.Response.Body stream to APIResponse struct | ||||
| // for efficient memory usage | ||||
| func (bot *BotAPI) decodeAPIResponse(responseBody io.Reader, resp *APIResponse) ([]byte, error) { | ||||
| 	if !bot.Debug { | ||||
| 		dec := json.NewDecoder(responseBody) | ||||
| 		err := dec.Decode(resp) | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	// if debug, read response body | ||||
| 	data, err := ioutil.ReadAll(responseBody) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	err = json.Unmarshal(data, resp) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return data, nil | ||||
| } | ||||
|  | ||||
| // UploadFiles makes a request to the API with files. | ||||
| func (bot *BotAPI) UploadFiles(endpoint string, params Params, files []RequestFile) (*APIResponse, error) { | ||||
| 	r, w := io.Pipe() | ||||
| 	m := multipart.NewWriter(w) | ||||
|  | ||||
| 	// This code modified from the very helpful @HirbodBehnam | ||||
| 	// https://github.com/go-telegram-bot-api/telegram-bot-api/issues/354#issuecomment-663856473 | ||||
| 	go func() { | ||||
| 		defer w.Close() | ||||
| 		defer m.Close() | ||||
|  | ||||
| 		for field, value := range params { | ||||
| 			if err := m.WriteField(field, value); err != nil { | ||||
| 				w.CloseWithError(err) | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		for _, file := range files { | ||||
| 			if file.Data.NeedsUpload() { | ||||
| 				name, reader, err := file.Data.UploadData() | ||||
| 				if err != nil { | ||||
| 					w.CloseWithError(err) | ||||
| 					return | ||||
| 				} | ||||
|  | ||||
| 				part, err := m.CreateFormFile(file.Name, name) | ||||
| 				if err != nil { | ||||
| 					w.CloseWithError(err) | ||||
| 					return | ||||
| 				} | ||||
|  | ||||
| 				if _, err := io.Copy(part, reader); err != nil { | ||||
| 					w.CloseWithError(err) | ||||
| 					return | ||||
| 				} | ||||
|  | ||||
| 				if closer, ok := reader.(io.ReadCloser); ok { | ||||
| 					if err = closer.Close(); err != nil { | ||||
| 						w.CloseWithError(err) | ||||
| 						return | ||||
| 					} | ||||
| 				} | ||||
| 			} else { | ||||
| 				value := file.Data.SendData() | ||||
|  | ||||
| 				if err := m.WriteField(file.Name, value); err != nil { | ||||
| 					w.CloseWithError(err) | ||||
| 					return | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	if bot.Debug { | ||||
| 		log.Printf("Endpoint: %s, params: %v, with %d files\n", endpoint, params, len(files)) | ||||
| 	} | ||||
|  | ||||
| 	method := fmt.Sprintf(bot.apiEndpoint, bot.Token, endpoint) | ||||
|  | ||||
| 	req, err := http.NewRequest("POST", method, r) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	req.Header.Set("Content-Type", m.FormDataContentType()) | ||||
|  | ||||
| 	resp, err := bot.Client.Do(req) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	defer resp.Body.Close() | ||||
|  | ||||
| 	var apiResp APIResponse | ||||
| 	bytes, err := bot.decodeAPIResponse(resp.Body, &apiResp) | ||||
| 	if err != nil { | ||||
| 		return &apiResp, err | ||||
| 	} | ||||
|  | ||||
| 	if bot.Debug { | ||||
| 		log.Printf("Endpoint: %s, response: %s\n", endpoint, string(bytes)) | ||||
| 	} | ||||
|  | ||||
| 	if !apiResp.Ok { | ||||
| 		var parameters ResponseParameters | ||||
|  | ||||
| 		if apiResp.Parameters != nil { | ||||
| 			parameters = *apiResp.Parameters | ||||
| 		} | ||||
|  | ||||
| 		return &apiResp, &Error{ | ||||
| 			Message:            apiResp.Description, | ||||
| 			ResponseParameters: parameters, | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return &apiResp, nil | ||||
| } | ||||
|  | ||||
| // GetFileDirectURL returns direct URL to file | ||||
| // | ||||
| // It requires the FileID. | ||||
| func (bot *BotAPI) GetFileDirectURL(fileID string) (string, error) { | ||||
| 	file, err := bot.GetFile(FileConfig{fileID}) | ||||
|  | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	return file.Link(bot.Token), nil | ||||
| } | ||||
|  | ||||
| // GetMe fetches the currently authenticated bot. | ||||
| // | ||||
| // This method is called upon creation to validate the token, | ||||
| // and so you may get this data from BotAPI.Self without the need for | ||||
| // another request. | ||||
| func (bot *BotAPI) GetMe() (User, error) { | ||||
| 	resp, err := bot.MakeRequest("getMe", nil) | ||||
| 	if err != nil { | ||||
| 		return User{}, err | ||||
| 	} | ||||
|  | ||||
| 	var user User | ||||
| 	err = json.Unmarshal(resp.Result, &user) | ||||
|  | ||||
| 	return user, err | ||||
| } | ||||
|  | ||||
| // IsMessageToMe returns true if message directed to this bot. | ||||
| // | ||||
| // It requires the Message. | ||||
| func (bot *BotAPI) IsMessageToMe(message Message) bool { | ||||
| 	return strings.Contains(message.Text, "@"+bot.Self.UserName) | ||||
| } | ||||
|  | ||||
| func hasFilesNeedingUpload(files []RequestFile) bool { | ||||
| 	for _, file := range files { | ||||
| 		if file.Data.NeedsUpload() { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Request sends a Chattable to Telegram, and returns the APIResponse. | ||||
| func (bot *BotAPI) Request(c Chattable) (*APIResponse, error) { | ||||
| 	params, err := c.params() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	if t, ok := c.(Fileable); ok { | ||||
| 		files := t.files() | ||||
|  | ||||
| 		// If we have files that need to be uploaded, we should delegate the | ||||
| 		// request to UploadFile. | ||||
| 		if hasFilesNeedingUpload(files) { | ||||
| 			return bot.UploadFiles(t.method(), params, files) | ||||
| 		} | ||||
|  | ||||
| 		// However, if there are no files to be uploaded, there's likely things | ||||
| 		// that need to be turned into params instead. | ||||
| 		for _, file := range files { | ||||
| 			params[file.Name] = file.Data.SendData() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return bot.MakeRequest(c.method(), params) | ||||
| } | ||||
|  | ||||
| // Send will send a Chattable item to Telegram and provides the | ||||
| // returned Message. | ||||
| func (bot *BotAPI) Send(c Chattable) (Message, error) { | ||||
| 	resp, err := bot.Request(c) | ||||
| 	if err != nil { | ||||
| 		return Message{}, err | ||||
| 	} | ||||
|  | ||||
| 	var message Message | ||||
| 	err = json.Unmarshal(resp.Result, &message) | ||||
|  | ||||
| 	return message, err | ||||
| } | ||||
|  | ||||
| // SendMediaGroup sends a media group and returns the resulting messages. | ||||
| func (bot *BotAPI) SendMediaGroup(config MediaGroupConfig) ([]Message, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var messages []Message | ||||
| 	err = json.Unmarshal(resp.Result, &messages) | ||||
|  | ||||
| 	return messages, err | ||||
| } | ||||
|  | ||||
| // GetUserProfilePhotos gets a user's profile photos. | ||||
| // | ||||
| // It requires UserID. | ||||
| // Offset and Limit are optional. | ||||
| func (bot *BotAPI) GetUserProfilePhotos(config UserProfilePhotosConfig) (UserProfilePhotos, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return UserProfilePhotos{}, err | ||||
| 	} | ||||
|  | ||||
| 	var profilePhotos UserProfilePhotos | ||||
| 	err = json.Unmarshal(resp.Result, &profilePhotos) | ||||
|  | ||||
| 	return profilePhotos, err | ||||
| } | ||||
|  | ||||
| // GetFile returns a File which can download a file from Telegram. | ||||
| // | ||||
| // Requires FileID. | ||||
| func (bot *BotAPI) GetFile(config FileConfig) (File, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return File{}, err | ||||
| 	} | ||||
|  | ||||
| 	var file File | ||||
| 	err = json.Unmarshal(resp.Result, &file) | ||||
|  | ||||
| 	return file, err | ||||
| } | ||||
|  | ||||
| // GetUpdates fetches updates. | ||||
| // If a WebHook is set, this will not return any data! | ||||
| // | ||||
| // Offset, Limit, Timeout, and AllowedUpdates are optional. | ||||
| // To avoid stale items, set Offset to one higher than the previous item. | ||||
| // Set Timeout to a large number to reduce requests, so you can get updates | ||||
| // instantly instead of having to wait between requests. | ||||
| func (bot *BotAPI) GetUpdates(config UpdateConfig) ([]Update, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return []Update{}, err | ||||
| 	} | ||||
|  | ||||
| 	var updates []Update | ||||
| 	err = json.Unmarshal(resp.Result, &updates) | ||||
|  | ||||
| 	return updates, err | ||||
| } | ||||
|  | ||||
| // GetWebhookInfo allows you to fetch information about a webhook and if | ||||
| // one currently is set, along with pending update count and error messages. | ||||
| func (bot *BotAPI) GetWebhookInfo() (WebhookInfo, error) { | ||||
| 	resp, err := bot.MakeRequest("getWebhookInfo", nil) | ||||
| 	if err != nil { | ||||
| 		return WebhookInfo{}, err | ||||
| 	} | ||||
|  | ||||
| 	var info WebhookInfo | ||||
| 	err = json.Unmarshal(resp.Result, &info) | ||||
|  | ||||
| 	return info, err | ||||
| } | ||||
|  | ||||
| // GetUpdatesChan starts and returns a channel for getting updates. | ||||
| func (bot *BotAPI) GetUpdatesChan(config UpdateConfig) UpdatesChannel { | ||||
| 	ch := make(chan Update, bot.Buffer) | ||||
|  | ||||
| 	go func() { | ||||
| 		for { | ||||
| 			select { | ||||
| 			case <-bot.shutdownChannel: | ||||
| 				close(ch) | ||||
| 				return | ||||
| 			default: | ||||
| 			} | ||||
|  | ||||
| 			updates, err := bot.GetUpdates(config) | ||||
| 			if err != nil { | ||||
| 				log.Println(err) | ||||
| 				log.Println("Failed to get updates, retrying in 3 seconds...") | ||||
| 				time.Sleep(time.Second * 3) | ||||
|  | ||||
| 				continue | ||||
| 			} | ||||
|  | ||||
| 			for _, update := range updates { | ||||
| 				if update.UpdateID >= config.Offset { | ||||
| 					config.Offset = update.UpdateID + 1 | ||||
| 					ch <- update | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| // StopReceivingUpdates stops the go routine which receives updates | ||||
| func (bot *BotAPI) StopReceivingUpdates() { | ||||
| 	if bot.Debug { | ||||
| 		log.Println("Stopping the update receiver routine...") | ||||
| 	} | ||||
| 	close(bot.shutdownChannel) | ||||
| } | ||||
|  | ||||
| // ListenForWebhook registers a http handler for a webhook. | ||||
| func (bot *BotAPI) ListenForWebhook(pattern string) UpdatesChannel { | ||||
| 	ch := make(chan Update, bot.Buffer) | ||||
|  | ||||
| 	http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) { | ||||
| 		update, err := bot.HandleUpdate(r) | ||||
| 		if err != nil { | ||||
| 			errMsg, _ := json.Marshal(map[string]string{"error": err.Error()}) | ||||
| 			w.WriteHeader(http.StatusBadRequest) | ||||
| 			w.Header().Set("Content-Type", "application/json") | ||||
| 			_, _ = w.Write(errMsg) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		ch <- *update | ||||
| 	}) | ||||
|  | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| // ListenForWebhookRespReqFormat registers a http handler for a single incoming webhook. | ||||
| func (bot *BotAPI) ListenForWebhookRespReqFormat(w http.ResponseWriter, r *http.Request) UpdatesChannel { | ||||
| 	ch := make(chan Update, bot.Buffer) | ||||
|  | ||||
| 	func(w http.ResponseWriter, r *http.Request) { | ||||
| 		update, err := bot.HandleUpdate(r) | ||||
| 		if err != nil { | ||||
| 			errMsg, _ := json.Marshal(map[string]string{"error": err.Error()}) | ||||
| 			w.WriteHeader(http.StatusBadRequest) | ||||
| 			w.Header().Set("Content-Type", "application/json") | ||||
| 			_, _ = w.Write(errMsg) | ||||
| 			return | ||||
| 		} | ||||
|  | ||||
| 		ch <- *update | ||||
| 		close(ch) | ||||
| 	}(w, r) | ||||
|  | ||||
| 	return ch | ||||
| } | ||||
|  | ||||
| // HandleUpdate parses and returns update received via webhook | ||||
| func (bot *BotAPI) HandleUpdate(r *http.Request) (*Update, error) { | ||||
| 	if r.Method != http.MethodPost { | ||||
| 		err := errors.New("wrong HTTP method required POST") | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var update Update | ||||
| 	err := json.NewDecoder(r.Body).Decode(&update) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return &update, nil | ||||
| } | ||||
|  | ||||
| // WriteToHTTPResponse writes the request to the HTTP ResponseWriter. | ||||
| // | ||||
| // It doesn't support uploading files. | ||||
| // | ||||
| // See https://core.telegram.org/bots/api#making-requests-when-getting-updates | ||||
| // for details. | ||||
| func WriteToHTTPResponse(w http.ResponseWriter, c Chattable) error { | ||||
| 	params, err := c.params() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if t, ok := c.(Fileable); ok { | ||||
| 		if hasFilesNeedingUpload(t.files()) { | ||||
| 			return errors.New("unable to use http response to upload files") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	values := buildParams(params) | ||||
| 	values.Set("method", c.method()) | ||||
|  | ||||
| 	w.Header().Set("Content-Type", "application/x-www-form-urlencoded") | ||||
| 	_, err = w.Write([]byte(values.Encode())) | ||||
| 	return err | ||||
| } | ||||
|  | ||||
| // GetChat gets information about a chat. | ||||
| func (bot *BotAPI) GetChat(config ChatInfoConfig) (Chat, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return Chat{}, err | ||||
| 	} | ||||
|  | ||||
| 	var chat Chat | ||||
| 	err = json.Unmarshal(resp.Result, &chat) | ||||
|  | ||||
| 	return chat, err | ||||
| } | ||||
|  | ||||
| // GetChatAdministrators gets a list of administrators in the chat. | ||||
| // | ||||
| // If none have been appointed, only the creator will be returned. | ||||
| // Bots are not shown, even if they are an administrator. | ||||
| func (bot *BotAPI) GetChatAdministrators(config ChatAdministratorsConfig) ([]ChatMember, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return []ChatMember{}, err | ||||
| 	} | ||||
|  | ||||
| 	var members []ChatMember | ||||
| 	err = json.Unmarshal(resp.Result, &members) | ||||
|  | ||||
| 	return members, err | ||||
| } | ||||
|  | ||||
| // GetChatMembersCount gets the number of users in a chat. | ||||
| func (bot *BotAPI) GetChatMembersCount(config ChatMemberCountConfig) (int, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return -1, err | ||||
| 	} | ||||
|  | ||||
| 	var count int | ||||
| 	err = json.Unmarshal(resp.Result, &count) | ||||
|  | ||||
| 	return count, err | ||||
| } | ||||
|  | ||||
| // GetChatMember gets a specific chat member. | ||||
| func (bot *BotAPI) GetChatMember(config GetChatMemberConfig) (ChatMember, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return ChatMember{}, err | ||||
| 	} | ||||
|  | ||||
| 	var member ChatMember | ||||
| 	err = json.Unmarshal(resp.Result, &member) | ||||
|  | ||||
| 	return member, err | ||||
| } | ||||
|  | ||||
| // GetGameHighScores allows you to get the high scores for a game. | ||||
| func (bot *BotAPI) GetGameHighScores(config GetGameHighScoresConfig) ([]GameHighScore, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return []GameHighScore{}, err | ||||
| 	} | ||||
|  | ||||
| 	var highScores []GameHighScore | ||||
| 	err = json.Unmarshal(resp.Result, &highScores) | ||||
|  | ||||
| 	return highScores, err | ||||
| } | ||||
|  | ||||
| // GetInviteLink get InviteLink for a chat | ||||
| func (bot *BotAPI) GetInviteLink(config ChatInviteLinkConfig) (string, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
|  | ||||
| 	var inviteLink string | ||||
| 	err = json.Unmarshal(resp.Result, &inviteLink) | ||||
|  | ||||
| 	return inviteLink, err | ||||
| } | ||||
|  | ||||
| // GetStickerSet returns a StickerSet. | ||||
| func (bot *BotAPI) GetStickerSet(config GetStickerSetConfig) (StickerSet, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return StickerSet{}, err | ||||
| 	} | ||||
|  | ||||
| 	var stickers StickerSet | ||||
| 	err = json.Unmarshal(resp.Result, &stickers) | ||||
|  | ||||
| 	return stickers, err | ||||
| } | ||||
|  | ||||
| // StopPoll stops a poll and returns the result. | ||||
| func (bot *BotAPI) StopPoll(config StopPollConfig) (Poll, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return Poll{}, err | ||||
| 	} | ||||
|  | ||||
| 	var poll Poll | ||||
| 	err = json.Unmarshal(resp.Result, &poll) | ||||
|  | ||||
| 	return poll, err | ||||
| } | ||||
|  | ||||
| // GetMyCommands gets the currently registered commands. | ||||
| func (bot *BotAPI) GetMyCommands() ([]BotCommand, error) { | ||||
| 	return bot.GetMyCommandsWithConfig(GetMyCommandsConfig{}) | ||||
| } | ||||
|  | ||||
| // GetMyCommandsWithConfig gets the currently registered commands with a config. | ||||
| func (bot *BotAPI) GetMyCommandsWithConfig(config GetMyCommandsConfig) ([]BotCommand, error) { | ||||
| 	resp, err := bot.Request(config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	var commands []BotCommand | ||||
| 	err = json.Unmarshal(resp.Result, &commands) | ||||
|  | ||||
| 	return commands, err | ||||
| } | ||||
|  | ||||
| // CopyMessage copy messages of any kind. The method is analogous to the method | ||||
| // forwardMessage, but the copied message doesn't have a link to the original | ||||
| // message. Returns the MessageID of the sent message on success. | ||||
| func (bot *BotAPI) CopyMessage(config CopyMessageConfig) (MessageID, error) { | ||||
| 	params, err := config.params() | ||||
| 	if err != nil { | ||||
| 		return MessageID{}, err | ||||
| 	} | ||||
|  | ||||
| 	resp, err := bot.MakeRequest(config.method(), params) | ||||
| 	if err != nil { | ||||
| 		return MessageID{}, err | ||||
| 	} | ||||
|  | ||||
| 	var messageID MessageID | ||||
| 	err = json.Unmarshal(resp.Result, &messageID) | ||||
|  | ||||
| 	return messageID, err | ||||
| } | ||||
|  | ||||
| // EscapeText takes an input text and escape Telegram markup symbols. | ||||
| // In this way we can send a text without being afraid of having to escape the characters manually. | ||||
| // Note that you don't have to include the formatting style in the input text, or it will be escaped too. | ||||
| // If there is an error, an empty string will be returned. | ||||
| // | ||||
| // parseMode is the text formatting mode (ModeMarkdown, ModeMarkdownV2 or ModeHTML) | ||||
| // text is the input string that will be escaped | ||||
| func EscapeText(parseMode string, text string) string { | ||||
| 	var replacer *strings.Replacer | ||||
|  | ||||
| 	if parseMode == ModeHTML { | ||||
| 		replacer = strings.NewReplacer("<", "<", ">", ">", "&", "&") | ||||
| 	} else if parseMode == ModeMarkdown { | ||||
| 		replacer = strings.NewReplacer("_", "\\_", "*", "\\*", "`", "\\`", "[", "\\[") | ||||
| 	} else if parseMode == ModeMarkdownV2 { | ||||
| 		replacer = strings.NewReplacer( | ||||
| 			"_", "\\_", "*", "\\*", "[", "\\[", "]", "\\]", "(", | ||||
| 			"\\(", ")", "\\)", "~", "\\~", "`", "\\`", ">", "\\>", | ||||
| 			"#", "\\#", "+", "\\+", "-", "\\-", "=", "\\=", "|", | ||||
| 			"\\|", "{", "\\{", "}", "\\}", ".", "\\.", "!", "\\!", | ||||
| 		) | ||||
| 	} else { | ||||
| 		return "" | ||||
| 	} | ||||
|  | ||||
| 	return replacer.Replace(text) | ||||
| } | ||||
							
								
								
									
										2468
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/configs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										2468
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/configs.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -52,241 +52,117 @@ func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewPhotoUpload creates a new photo uploader. | ||||
| // NewCopyMessage creates a new copy message. | ||||
| // | ||||
| // chatID is where to send it, fromChatID is the source chat, | ||||
| // and messageID is the ID of the original message. | ||||
| func NewCopyMessage(chatID int64, fromChatID int64, messageID int) CopyMessageConfig { | ||||
| 	return CopyMessageConfig{ | ||||
| 		BaseChat:   BaseChat{ChatID: chatID}, | ||||
| 		FromChatID: fromChatID, | ||||
| 		MessageID:  messageID, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewPhoto creates a new sendPhoto request. | ||||
| // | ||||
| // chatID is where to send it, file is a string path to the file, | ||||
| // FileReader, or FileBytes. | ||||
| // | ||||
| // Note that you must send animated GIFs as a document. | ||||
| func NewPhotoUpload(chatID int64, file interface{}) PhotoConfig { | ||||
| func NewPhoto(chatID int64, file RequestFileData) PhotoConfig { | ||||
| 	return PhotoConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			File:        file, | ||||
| 			UseExisting: false, | ||||
| 			BaseChat: BaseChat{ChatID: chatID}, | ||||
| 			File:     file, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewPhotoShare shares an existing photo. | ||||
| // You may use this to reshare an existing photo without reuploading it. | ||||
| // NewPhotoToChannel creates a new photo uploader to send a photo to a channel. | ||||
| // | ||||
| // chatID is where to send it, fileID is the ID of the file | ||||
| // already uploaded. | ||||
| func NewPhotoShare(chatID int64, fileID string) PhotoConfig { | ||||
| // Note that you must send animated GIFs as a document. | ||||
| func NewPhotoToChannel(username string, file RequestFileData) PhotoConfig { | ||||
| 	return PhotoConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			FileID:      fileID, | ||||
| 			UseExisting: true, | ||||
| 			BaseChat: BaseChat{ | ||||
| 				ChannelUsername: username, | ||||
| 			}, | ||||
| 			File: file, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewAudioUpload creates a new audio uploader. | ||||
| // | ||||
| // chatID is where to send it, file is a string path to the file, | ||||
| // FileReader, or FileBytes. | ||||
| func NewAudioUpload(chatID int64, file interface{}) AudioConfig { | ||||
| // NewAudio creates a new sendAudio request. | ||||
| func NewAudio(chatID int64, file RequestFileData) AudioConfig { | ||||
| 	return AudioConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			File:        file, | ||||
| 			UseExisting: false, | ||||
| 			BaseChat: BaseChat{ChatID: chatID}, | ||||
| 			File:     file, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewAudioShare shares an existing audio file. | ||||
| // You may use this to reshare an existing audio file without | ||||
| // reuploading it. | ||||
| // | ||||
| // chatID is where to send it, fileID is the ID of the audio | ||||
| // already uploaded. | ||||
| func NewAudioShare(chatID int64, fileID string) AudioConfig { | ||||
| 	return AudioConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			FileID:      fileID, | ||||
| 			UseExisting: true, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewDocumentUpload creates a new document uploader. | ||||
| // | ||||
| // chatID is where to send it, file is a string path to the file, | ||||
| // FileReader, or FileBytes. | ||||
| func NewDocumentUpload(chatID int64, file interface{}) DocumentConfig { | ||||
| // NewDocument creates a new sendDocument request. | ||||
| func NewDocument(chatID int64, file RequestFileData) DocumentConfig { | ||||
| 	return DocumentConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			File:        file, | ||||
| 			UseExisting: false, | ||||
| 			BaseChat: BaseChat{ChatID: chatID}, | ||||
| 			File:     file, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewDocumentShare shares an existing document. | ||||
| // You may use this to reshare an existing document without | ||||
| // reuploading it. | ||||
| // | ||||
| // chatID is where to send it, fileID is the ID of the document | ||||
| // already uploaded. | ||||
| func NewDocumentShare(chatID int64, fileID string) DocumentConfig { | ||||
| 	return DocumentConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			FileID:      fileID, | ||||
| 			UseExisting: true, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewStickerUpload creates a new sticker uploader. | ||||
| // | ||||
| // chatID is where to send it, file is a string path to the file, | ||||
| // FileReader, or FileBytes. | ||||
| func NewStickerUpload(chatID int64, file interface{}) StickerConfig { | ||||
| // NewSticker creates a new sendSticker request. | ||||
| func NewSticker(chatID int64, file RequestFileData) StickerConfig { | ||||
| 	return StickerConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			File:        file, | ||||
| 			UseExisting: false, | ||||
| 			BaseChat: BaseChat{ChatID: chatID}, | ||||
| 			File:     file, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewStickerShare shares an existing sticker. | ||||
| // You may use this to reshare an existing sticker without | ||||
| // reuploading it. | ||||
| // | ||||
| // chatID is where to send it, fileID is the ID of the sticker | ||||
| // already uploaded. | ||||
| func NewStickerShare(chatID int64, fileID string) StickerConfig { | ||||
| 	return StickerConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			FileID:      fileID, | ||||
| 			UseExisting: true, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewVideoUpload creates a new video uploader. | ||||
| // | ||||
| // chatID is where to send it, file is a string path to the file, | ||||
| // FileReader, or FileBytes. | ||||
| func NewVideoUpload(chatID int64, file interface{}) VideoConfig { | ||||
| // NewVideo creates a new sendVideo request. | ||||
| func NewVideo(chatID int64, file RequestFileData) VideoConfig { | ||||
| 	return VideoConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			File:        file, | ||||
| 			UseExisting: false, | ||||
| 			BaseChat: BaseChat{ChatID: chatID}, | ||||
| 			File:     file, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewVideoShare shares an existing video. | ||||
| // You may use this to reshare an existing video without reuploading it. | ||||
| // | ||||
| // chatID is where to send it, fileID is the ID of the video | ||||
| // already uploaded. | ||||
| func NewVideoShare(chatID int64, fileID string) VideoConfig { | ||||
| 	return VideoConfig{ | ||||
| // NewAnimation creates a new sendAnimation request. | ||||
| func NewAnimation(chatID int64, file RequestFileData) AnimationConfig { | ||||
| 	return AnimationConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			FileID:      fileID, | ||||
| 			UseExisting: true, | ||||
| 			BaseChat: BaseChat{ChatID: chatID}, | ||||
| 			File:     file, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewAnimationUpload creates a new animation uploader. | ||||
| // NewVideoNote creates a new sendVideoNote request. | ||||
| // | ||||
| // chatID is where to send it, file is a string path to the file, | ||||
| // FileReader, or FileBytes. | ||||
| func NewAnimationUpload(chatID int64, file interface{}) AnimationConfig { | ||||
| 	return AnimationConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			File:        file, | ||||
| 			UseExisting: false, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewAnimationShare shares an existing animation. | ||||
| // You may use this to reshare an existing animation without reuploading it. | ||||
| // | ||||
| // chatID is where to send it, fileID is the ID of the animation | ||||
| // already uploaded. | ||||
| func NewAnimationShare(chatID int64, fileID string) AnimationConfig { | ||||
| 	return AnimationConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			FileID:      fileID, | ||||
| 			UseExisting: true, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewVideoNoteUpload creates a new video note uploader. | ||||
| // | ||||
| // chatID is where to send it, file is a string path to the file, | ||||
| // FileReader, or FileBytes. | ||||
| func NewVideoNoteUpload(chatID int64, length int, file interface{}) VideoNoteConfig { | ||||
| func NewVideoNote(chatID int64, length int, file RequestFileData) VideoNoteConfig { | ||||
| 	return VideoNoteConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			File:        file, | ||||
| 			UseExisting: false, | ||||
| 			BaseChat: BaseChat{ChatID: chatID}, | ||||
| 			File:     file, | ||||
| 		}, | ||||
| 		Length: length, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewVideoNoteShare shares an existing video. | ||||
| // You may use this to reshare an existing video without reuploading it. | ||||
| // | ||||
| // chatID is where to send it, fileID is the ID of the video | ||||
| // already uploaded. | ||||
| func NewVideoNoteShare(chatID int64, length int, fileID string) VideoNoteConfig { | ||||
| 	return VideoNoteConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			FileID:      fileID, | ||||
| 			UseExisting: true, | ||||
| 		}, | ||||
| 		Length: length, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewVoiceUpload creates a new voice uploader. | ||||
| // | ||||
| // chatID is where to send it, file is a string path to the file, | ||||
| // FileReader, or FileBytes. | ||||
| func NewVoiceUpload(chatID int64, file interface{}) VoiceConfig { | ||||
| // NewVoice creates a new sendVoice request. | ||||
| func NewVoice(chatID int64, file RequestFileData) VoiceConfig { | ||||
| 	return VoiceConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			File:        file, | ||||
| 			UseExisting: false, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewVoiceShare shares an existing voice. | ||||
| // You may use this to reshare an existing voice without reuploading it. | ||||
| // | ||||
| // chatID is where to send it, fileID is the ID of the video | ||||
| // already uploaded. | ||||
| func NewVoiceShare(chatID int64, fileID string) VoiceConfig { | ||||
| 	return VoiceConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			FileID:      fileID, | ||||
| 			UseExisting: true, | ||||
| 			BaseChat: BaseChat{ChatID: chatID}, | ||||
| 			File:     file, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| @@ -295,26 +171,58 @@ func NewVoiceShare(chatID int64, fileID string) VoiceConfig { | ||||
| // two to ten InputMediaPhoto or InputMediaVideo. | ||||
| func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig { | ||||
| 	return MediaGroupConfig{ | ||||
| 		BaseChat: BaseChat{ | ||||
| 			ChatID: chatID, | ||||
| 		}, | ||||
| 		InputMedia: files, | ||||
| 		ChatID: chatID, | ||||
| 		Media:  files, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewInputMediaPhoto creates a new InputMediaPhoto. | ||||
| func NewInputMediaPhoto(media string) InputMediaPhoto { | ||||
| func NewInputMediaPhoto(media RequestFileData) InputMediaPhoto { | ||||
| 	return InputMediaPhoto{ | ||||
| 		Type:  "photo", | ||||
| 		Media: media, | ||||
| 		BaseInputMedia{ | ||||
| 			Type:  "photo", | ||||
| 			Media: media, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewInputMediaVideo creates a new InputMediaVideo. | ||||
| func NewInputMediaVideo(media string) InputMediaVideo { | ||||
| func NewInputMediaVideo(media RequestFileData) InputMediaVideo { | ||||
| 	return InputMediaVideo{ | ||||
| 		Type:  "video", | ||||
| 		Media: media, | ||||
| 		BaseInputMedia: BaseInputMedia{ | ||||
| 			Type:  "video", | ||||
| 			Media: media, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewInputMediaAnimation creates a new InputMediaAnimation. | ||||
| func NewInputMediaAnimation(media RequestFileData) InputMediaAnimation { | ||||
| 	return InputMediaAnimation{ | ||||
| 		BaseInputMedia: BaseInputMedia{ | ||||
| 			Type:  "animation", | ||||
| 			Media: media, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewInputMediaAudio creates a new InputMediaAudio. | ||||
| func NewInputMediaAudio(media RequestFileData) InputMediaAudio { | ||||
| 	return InputMediaAudio{ | ||||
| 		BaseInputMedia: BaseInputMedia{ | ||||
| 			Type:  "audio", | ||||
| 			Media: media, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewInputMediaDocument creates a new InputMediaDocument. | ||||
| func NewInputMediaDocument(media RequestFileData) InputMediaDocument { | ||||
| 	return InputMediaDocument{ | ||||
| 		BaseInputMedia: BaseInputMedia{ | ||||
| 			Type:  "document", | ||||
| 			Media: media, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @@ -369,7 +277,7 @@ func NewChatAction(chatID int64, action string) ChatActionConfig { | ||||
| // NewUserProfilePhotos gets user profile photos. | ||||
| // | ||||
| // userID is the ID of the user you wish to get profile photos from. | ||||
| func NewUserProfilePhotos(userID int) UserProfilePhotosConfig { | ||||
| func NewUserProfilePhotos(userID int64) UserProfilePhotosConfig { | ||||
| 	return UserProfilePhotosConfig{ | ||||
| 		UserID: userID, | ||||
| 		Offset: 0, | ||||
| @@ -392,25 +300,33 @@ func NewUpdate(offset int) UpdateConfig { | ||||
| // NewWebhook creates a new webhook. | ||||
| // | ||||
| // link is the url parsable link you wish to get the updates. | ||||
| func NewWebhook(link string) WebhookConfig { | ||||
| 	u, _ := url.Parse(link) | ||||
| func NewWebhook(link string) (WebhookConfig, error) { | ||||
| 	u, err := url.Parse(link) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return WebhookConfig{}, err | ||||
| 	} | ||||
| 
 | ||||
| 	return WebhookConfig{ | ||||
| 		URL: u, | ||||
| 	} | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // NewWebhookWithCert creates a new webhook with a certificate. | ||||
| // | ||||
| // link is the url you wish to get webhooks, | ||||
| // file contains a string to a file, FileReader, or FileBytes. | ||||
| func NewWebhookWithCert(link string, file interface{}) WebhookConfig { | ||||
| 	u, _ := url.Parse(link) | ||||
| func NewWebhookWithCert(link string, file RequestFileData) (WebhookConfig, error) { | ||||
| 	u, err := url.Parse(link) | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return WebhookConfig{}, err | ||||
| 	} | ||||
| 
 | ||||
| 	return WebhookConfig{ | ||||
| 		URL:         u, | ||||
| 		Certificate: file, | ||||
| 	} | ||||
| 	}, nil | ||||
| } | ||||
| 
 | ||||
| // NewInlineQueryResultArticle creates a new inline query article. | ||||
| @@ -438,6 +354,19 @@ func NewInlineQueryResultArticleMarkdown(id, title, messageText string) InlineQu | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewInlineQueryResultArticleMarkdownV2 creates a new inline query article with MarkdownV2 parsing. | ||||
| func NewInlineQueryResultArticleMarkdownV2(id, title, messageText string) InlineQueryResultArticle { | ||||
| 	return InlineQueryResultArticle{ | ||||
| 		Type:  "article", | ||||
| 		ID:    id, | ||||
| 		Title: title, | ||||
| 		InputMessageContent: InputTextMessageContent{ | ||||
| 			Text:      messageText, | ||||
| 			ParseMode: "MarkdownV2", | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewInlineQueryResultArticleHTML creates a new inline query article with HTML parsing. | ||||
| func NewInlineQueryResultArticleHTML(id, title, messageText string) InlineQueryResultArticle { | ||||
| 	return InlineQueryResultArticle{ | ||||
| @@ -465,7 +394,7 @@ func NewInlineQueryResultCachedGIF(id, gifID string) InlineQueryResultCachedGIF | ||||
| 	return InlineQueryResultCachedGIF{ | ||||
| 		Type:  "gif", | ||||
| 		ID:    id, | ||||
| 		GifID: gifID, | ||||
| 		GIFID: gifID, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @@ -478,12 +407,12 @@ func NewInlineQueryResultMPEG4GIF(id, url string) InlineQueryResultMPEG4GIF { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewInlineQueryResultCachedPhoto create a new inline query with cached photo. | ||||
| func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GifID string) InlineQueryResultCachedMpeg4Gif { | ||||
| 	return InlineQueryResultCachedMpeg4Gif{ | ||||
| 		Type:   "mpeg4_gif", | ||||
| 		ID:     id, | ||||
| 		MGifID: MPEG4GifID, | ||||
| // NewInlineQueryResultCachedMPEG4GIF create a new inline query with cached MPEG4 GIF. | ||||
| func NewInlineQueryResultCachedMPEG4GIF(id, MPEG4GIFID string) InlineQueryResultCachedMPEG4GIF { | ||||
| 	return InlineQueryResultCachedMPEG4GIF{ | ||||
| 		Type:        "mpeg4_gif", | ||||
| 		ID:          id, | ||||
| 		MPEG4FileID: MPEG4GIFID, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| @@ -534,6 +463,16 @@ func NewInlineQueryResultCachedVideo(id, videoID, title string) InlineQueryResul | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewInlineQueryResultCachedSticker create a new inline query with cached sticker. | ||||
| func NewInlineQueryResultCachedSticker(id, stickerID, title string) InlineQueryResultCachedSticker { | ||||
| 	return InlineQueryResultCachedSticker{ | ||||
| 		Type:      "sticker", | ||||
| 		ID:        id, | ||||
| 		StickerID: stickerID, | ||||
| 		Title:     title, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewInlineQueryResultAudio creates a new inline query audio. | ||||
| func NewInlineQueryResultAudio(id, url, title string) InlineQueryResultAudio { | ||||
| 	return InlineQueryResultAudio{ | ||||
| @@ -628,6 +567,18 @@ func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTex | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewEditMessageTextAndMarkup allows you to edit the text and replymarkup of a message. | ||||
| func NewEditMessageTextAndMarkup(chatID int64, messageID int, text string, replyMarkup InlineKeyboardMarkup) EditMessageTextConfig { | ||||
| 	return EditMessageTextConfig{ | ||||
| 		BaseEdit: BaseEdit{ | ||||
| 			ChatID:      chatID, | ||||
| 			MessageID:   messageID, | ||||
| 			ReplyMarkup: &replyMarkup, | ||||
| 		}, | ||||
| 		Text: text, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewEditMessageCaption allows you to edit the caption of a message. | ||||
| func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig { | ||||
| 	return EditMessageCaptionConfig{ | ||||
| @@ -651,17 +602,6 @@ func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKe | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewHideKeyboard hides the keyboard, with the option for being selective | ||||
| // or hiding for everyone. | ||||
| func NewHideKeyboard(selective bool) ReplyKeyboardHide { | ||||
| 	log.Println("NewHideKeyboard is deprecated, please use NewRemoveKeyboard") | ||||
| 
 | ||||
| 	return ReplyKeyboardHide{ | ||||
| 		HideKeyboard: true, | ||||
| 		Selective:    selective, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewRemoveKeyboard hides the keyboard, with the option for being selective | ||||
| // or hiding for everyone. | ||||
| func NewRemoveKeyboard(selective bool) ReplyKeyboardRemove { | ||||
| @@ -717,6 +657,13 @@ func NewReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewOneTimeReplyKeyboard creates a new one time keyboard. | ||||
| func NewOneTimeReplyKeyboard(rows ...[]KeyboardButton) ReplyKeyboardMarkup { | ||||
| 	markup := NewReplyKeyboard(rows...) | ||||
| 	markup.OneTimeKeyboard = true | ||||
| 	return markup | ||||
| } | ||||
| 
 | ||||
| // NewInlineKeyboardButtonData creates an inline keyboard button with text | ||||
| // and data for a callback. | ||||
| func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton { | ||||
| @@ -726,6 +673,15 @@ func NewInlineKeyboardButtonData(text, data string) InlineKeyboardButton { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewInlineKeyboardButtonLoginURL creates an inline keyboard button with text | ||||
| // which goes to a LoginURL. | ||||
| func NewInlineKeyboardButtonLoginURL(text string, loginURL LoginURL) InlineKeyboardButton { | ||||
| 	return InlineKeyboardButton{ | ||||
| 		Text:     text, | ||||
| 		LoginURL: &loginURL, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewInlineKeyboardButtonURL creates an inline keyboard button with text | ||||
| // which goes to a URL. | ||||
| func NewInlineKeyboardButtonURL(text, url string) InlineKeyboardButton { | ||||
| @@ -784,7 +740,7 @@ func NewCallbackWithAlert(id, text string) CallbackConfig { | ||||
| } | ||||
| 
 | ||||
| // NewInvoice creates a new Invoice request to the user. | ||||
| func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices *[]LabeledPrice) InvoiceConfig { | ||||
| func NewInvoice(chatID int64, title, description, payload, providerToken, startParameter, currency string, prices []LabeledPrice) InvoiceConfig { | ||||
| 	return InvoiceConfig{ | ||||
| 		BaseChat:       BaseChat{ChatID: chatID}, | ||||
| 		Title:          title, | ||||
| @@ -796,33 +752,176 @@ func NewInvoice(chatID int64, title, description, payload, providerToken, startP | ||||
| 		Prices:         prices} | ||||
| } | ||||
| 
 | ||||
| // NewSetChatPhotoUpload creates a new chat photo uploader. | ||||
| // | ||||
| // chatID is where to send it, file is a string path to the file, | ||||
| // FileReader, or FileBytes. | ||||
| // | ||||
| // Note that you must send animated GIFs as a document. | ||||
| func NewSetChatPhotoUpload(chatID int64, file interface{}) SetChatPhotoConfig { | ||||
| // NewChatTitle allows you to update the title of a chat. | ||||
| func NewChatTitle(chatID int64, title string) SetChatTitleConfig { | ||||
| 	return SetChatTitleConfig{ | ||||
| 		ChatID: chatID, | ||||
| 		Title:  title, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewChatDescription allows you to update the description of a chat. | ||||
| func NewChatDescription(chatID int64, description string) SetChatDescriptionConfig { | ||||
| 	return SetChatDescriptionConfig{ | ||||
| 		ChatID:      chatID, | ||||
| 		Description: description, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewChatPhoto allows you to update the photo for a chat. | ||||
| func NewChatPhoto(chatID int64, photo RequestFileData) SetChatPhotoConfig { | ||||
| 	return SetChatPhotoConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			File:        file, | ||||
| 			UseExisting: false, | ||||
| 			BaseChat: BaseChat{ | ||||
| 				ChatID: chatID, | ||||
| 			}, | ||||
| 			File: photo, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewSetChatPhotoShare shares an existing photo. | ||||
| // You may use this to reshare an existing photo without reuploading it. | ||||
| // | ||||
| // chatID is where to send it, fileID is the ID of the file | ||||
| // already uploaded. | ||||
| func NewSetChatPhotoShare(chatID int64, fileID string) SetChatPhotoConfig { | ||||
| 	return SetChatPhotoConfig{ | ||||
| 		BaseFile: BaseFile{ | ||||
| 			BaseChat:    BaseChat{ChatID: chatID}, | ||||
| 			FileID:      fileID, | ||||
| 			UseExisting: true, | ||||
| // NewDeleteChatPhoto allows you to delete the photo for a chat. | ||||
| func NewDeleteChatPhoto(chatID int64) DeleteChatPhotoConfig { | ||||
| 	return DeleteChatPhotoConfig{ | ||||
| 		ChatID: chatID, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewPoll allows you to create a new poll. | ||||
| func NewPoll(chatID int64, question string, options ...string) SendPollConfig { | ||||
| 	return SendPollConfig{ | ||||
| 		BaseChat: BaseChat{ | ||||
| 			ChatID: chatID, | ||||
| 		}, | ||||
| 		Question:    question, | ||||
| 		Options:     options, | ||||
| 		IsAnonymous: true, // This is Telegram's default. | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewStopPoll allows you to stop a poll. | ||||
| func NewStopPoll(chatID int64, messageID int) StopPollConfig { | ||||
| 	return StopPollConfig{ | ||||
| 		BaseEdit{ | ||||
| 			ChatID:    chatID, | ||||
| 			MessageID: messageID, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewDice allows you to send a random dice roll. | ||||
| func NewDice(chatID int64) DiceConfig { | ||||
| 	return DiceConfig{ | ||||
| 		BaseChat: BaseChat{ | ||||
| 			ChatID: chatID, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewDiceWithEmoji allows you to send a random roll of one of many types. | ||||
| // | ||||
| // Emoji may be 🎲 (1-6), 🎯 (1-6), or 🏀 (1-5). | ||||
| func NewDiceWithEmoji(chatID int64, emoji string) DiceConfig { | ||||
| 	return DiceConfig{ | ||||
| 		BaseChat: BaseChat{ | ||||
| 			ChatID: chatID, | ||||
| 		}, | ||||
| 		Emoji: emoji, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewBotCommandScopeDefault represents the default scope of bot commands. | ||||
| func NewBotCommandScopeDefault() BotCommandScope { | ||||
| 	return BotCommandScope{Type: "default"} | ||||
| } | ||||
| 
 | ||||
| // NewBotCommandScopeAllPrivateChats represents the scope of bot commands, | ||||
| // covering all private chats. | ||||
| func NewBotCommandScopeAllPrivateChats() BotCommandScope { | ||||
| 	return BotCommandScope{Type: "all_private_chats"} | ||||
| } | ||||
| 
 | ||||
| // NewBotCommandScopeAllGroupChats represents the scope of bot commands, | ||||
| // covering all group and supergroup chats. | ||||
| func NewBotCommandScopeAllGroupChats() BotCommandScope { | ||||
| 	return BotCommandScope{Type: "all_group_chats"} | ||||
| } | ||||
| 
 | ||||
| // NewBotCommandScopeAllChatAdministrators represents the scope of bot commands, | ||||
| // covering all group and supergroup chat administrators. | ||||
| func NewBotCommandScopeAllChatAdministrators() BotCommandScope { | ||||
| 	return BotCommandScope{Type: "all_chat_administrators"} | ||||
| } | ||||
| 
 | ||||
| // NewBotCommandScopeChat represents the scope of bot commands, covering a | ||||
| // specific chat. | ||||
| func NewBotCommandScopeChat(chatID int64) BotCommandScope { | ||||
| 	return BotCommandScope{ | ||||
| 		Type:   "chat", | ||||
| 		ChatID: chatID, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewBotCommandScopeChatAdministrators represents the scope of bot commands, | ||||
| // covering all administrators of a specific group or supergroup chat. | ||||
| func NewBotCommandScopeChatAdministrators(chatID int64) BotCommandScope { | ||||
| 	return BotCommandScope{ | ||||
| 		Type:   "chat_administrators", | ||||
| 		ChatID: chatID, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewBotCommandScopeChatMember represents the scope of bot commands, covering a | ||||
| // specific member of a group or supergroup chat. | ||||
| func NewBotCommandScopeChatMember(chatID, userID int64) BotCommandScope { | ||||
| 	return BotCommandScope{ | ||||
| 		Type:   "chat_member", | ||||
| 		ChatID: chatID, | ||||
| 		UserID: userID, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // NewGetMyCommandsWithScope allows you to set the registered commands for a | ||||
| // given scope. | ||||
| func NewGetMyCommandsWithScope(scope BotCommandScope) GetMyCommandsConfig { | ||||
| 	return GetMyCommandsConfig{Scope: &scope} | ||||
| } | ||||
| 
 | ||||
| // NewGetMyCommandsWithScopeAndLanguage allows you to set the registered | ||||
| // commands for a given scope and language code. | ||||
| func NewGetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) GetMyCommandsConfig { | ||||
| 	return GetMyCommandsConfig{Scope: &scope, LanguageCode: languageCode} | ||||
| } | ||||
| 
 | ||||
| // NewSetMyCommands allows you to set the registered commands. | ||||
| func NewSetMyCommands(commands ...BotCommand) SetMyCommandsConfig { | ||||
| 	return SetMyCommandsConfig{Commands: commands} | ||||
| } | ||||
| 
 | ||||
| // NewSetMyCommandsWithScope allows you to set the registered commands for a given scope. | ||||
| func NewSetMyCommandsWithScope(scope BotCommandScope, commands ...BotCommand) SetMyCommandsConfig { | ||||
| 	return SetMyCommandsConfig{Commands: commands, Scope: &scope} | ||||
| } | ||||
| 
 | ||||
| // NewSetMyCommandsWithScopeAndLanguage allows you to set the registered commands for a given scope | ||||
| // and language code. | ||||
| func NewSetMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string, commands ...BotCommand) SetMyCommandsConfig { | ||||
| 	return SetMyCommandsConfig{Commands: commands, Scope: &scope, LanguageCode: languageCode} | ||||
| } | ||||
| 
 | ||||
| // NewDeleteMyCommands allows you to delete the registered commands. | ||||
| func NewDeleteMyCommands() DeleteMyCommandsConfig { | ||||
| 	return DeleteMyCommandsConfig{} | ||||
| } | ||||
| 
 | ||||
| // NewDeleteMyCommandsWithScope allows you to delete the registered commands for a given | ||||
| // scope. | ||||
| func NewDeleteMyCommandsWithScope(scope BotCommandScope) DeleteMyCommandsConfig { | ||||
| 	return DeleteMyCommandsConfig{Scope: &scope} | ||||
| } | ||||
| 
 | ||||
| // NewDeleteMyCommandsWithScopeAndLanguage allows you to delete the registered commands for a given | ||||
| // scope and language code. | ||||
| func NewDeleteMyCommandsWithScopeAndLanguage(scope BotCommandScope, languageCode string) DeleteMyCommandsConfig { | ||||
| 	return DeleteMyCommandsConfig{Scope: &scope, LanguageCode: languageCode} | ||||
| } | ||||
							
								
								
									
										97
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										97
									
								
								vendor/github.com/go-telegram-bot-api/telegram-bot-api/v5/params.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,97 @@ | ||||
| package tgbotapi | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"reflect" | ||||
| 	"strconv" | ||||
| ) | ||||
|  | ||||
| // Params represents a set of parameters that gets passed to a request. | ||||
| type Params map[string]string | ||||
|  | ||||
| // AddNonEmpty adds a value if it not an empty string. | ||||
| func (p Params) AddNonEmpty(key, value string) { | ||||
| 	if value != "" { | ||||
| 		p[key] = value | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // AddNonZero adds a value if it is not zero. | ||||
| func (p Params) AddNonZero(key string, value int) { | ||||
| 	if value != 0 { | ||||
| 		p[key] = strconv.Itoa(value) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // AddNonZero64 is the same as AddNonZero except uses an int64. | ||||
| func (p Params) AddNonZero64(key string, value int64) { | ||||
| 	if value != 0 { | ||||
| 		p[key] = strconv.FormatInt(value, 10) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // AddBool adds a value of a bool if it is true. | ||||
| func (p Params) AddBool(key string, value bool) { | ||||
| 	if value { | ||||
| 		p[key] = strconv.FormatBool(value) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // AddNonZeroFloat adds a floating point value that is not zero. | ||||
| func (p Params) AddNonZeroFloat(key string, value float64) { | ||||
| 	if value != 0 { | ||||
| 		p[key] = strconv.FormatFloat(value, 'f', 6, 64) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // AddInterface adds an interface if it is not nil and can be JSON marshalled. | ||||
| func (p Params) AddInterface(key string, value interface{}) error { | ||||
| 	if value == nil || (reflect.ValueOf(value).Kind() == reflect.Ptr && reflect.ValueOf(value).IsNil()) { | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	b, err := json.Marshal(value) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	p[key] = string(b) | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // AddFirstValid attempts to add the first item that is not a default value. | ||||
| // | ||||
| // For example, AddFirstValid(0, "", "test") would add "test". | ||||
| func (p Params) AddFirstValid(key string, args ...interface{}) error { | ||||
| 	for _, arg := range args { | ||||
| 		switch v := arg.(type) { | ||||
| 		case int: | ||||
| 			if v != 0 { | ||||
| 				p[key] = strconv.Itoa(v) | ||||
| 				return nil | ||||
| 			} | ||||
| 		case int64: | ||||
| 			if v != 0 { | ||||
| 				p[key] = strconv.FormatInt(v, 10) | ||||
| 				return nil | ||||
| 			} | ||||
| 		case string: | ||||
| 			if v != "" { | ||||
| 				p[key] = v | ||||
| 				return nil | ||||
| 			} | ||||
| 		case nil: | ||||
| 		default: | ||||
| 			b, err := json.Marshal(arg) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
|  | ||||
| 			p[key] = string(b) | ||||
| 			return nil | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
| @@ -54,13 +54,15 @@ type ( | ||||
| 		Credentials *EncryptedCredentials `json:"credentials"` | ||||
| 	} | ||||
| 
 | ||||
| 	// PassportFile represents a file uploaded to Telegram Passport. Currently all | ||||
| 	// PassportFile represents a file uploaded to Telegram Passport. Currently, all | ||||
| 	// Telegram Passport files are in JPEG format when decrypted and don't exceed | ||||
| 	// 10MB. | ||||
| 	PassportFile struct { | ||||
| 		// Unique identifier for this file | ||||
| 		FileID string `json:"file_id"` | ||||
| 
 | ||||
| 		FileUniqueID string `json:"file_unique_id"` | ||||
| 
 | ||||
| 		// File size | ||||
| 		FileSize int `json:"file_size"` | ||||
| 
 | ||||
| @@ -212,7 +214,7 @@ type ( | ||||
| 	// PassportElementErrorFile represents an issue with a document scan. The | ||||
| 	// error is considered resolved when the file with the document scan changes. | ||||
| 	PassportElementErrorFile struct { | ||||
| 		// Error source, must be file | ||||
| 		// Error source, must be a file | ||||
| 		Source string `json:"source"` | ||||
| 
 | ||||
| 		// The section of the user's Telegram Passport which has the issue, one | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user