From bd151fc816ab8ce79c75bd79bca576536dd3c47f Mon Sep 17 00:00:00 2001 From: OvyFlash Date: Fri, 5 Jan 2024 22:05:00 +0200 Subject: [PATCH 1/5] Start implementing 7.0 Bot API changes --- bot_test.go | 48 ++- configs.go | 676 +++++++++++++++----------------- helpers.go => helper_methods.go | 134 ++++--- helper_structs.go | 127 ++++++ params.go | 2 +- types.go | 519 +++++++++++++++++++++++- types_test.go | 2 + 7 files changed, 1073 insertions(+), 435 deletions(-) rename helpers.go => helper_methods.go (92%) create mode 100644 helper_structs.go diff --git a/bot_test.go b/bot_test.go index 7abd790..40633d6 100644 --- a/bot_test.go +++ b/bot_test.go @@ -84,7 +84,7 @@ func TestSendWithMessageReply(t *testing.T) { bot, _ := getBot(t) msg := NewMessage(ChatID, "A test message from the test library in telegram-bot-api") - msg.ReplyToMessageID = ReplyToMessageID + msg.ReplyParameters.MessageID = ReplyToMessageID _, err := bot.Send(msg) if err != nil { @@ -169,7 +169,7 @@ func TestSendWithNewPhotoReply(t *testing.T) { bot, _ := getBot(t) msg := NewPhoto(ChatID, FilePath("tests/image.jpg")) - msg.ReplyToMessageID = ReplyToMessageID + msg.ReplyParameters.MessageID = ReplyToMessageID _, err := bot.Send(msg) @@ -699,7 +699,7 @@ func ExampleNewBotAPI() { log.Printf("[%s] %s", update.Message.From.UserName, update.Message.Text) msg := NewMessage(update.Message.Chat.ID, update.Message.Text) - msg.ReplyToMessageID = update.Message.MessageID + msg.ReplyParameters.MessageID = update.Message.MessageID bot.Send(msg) } @@ -827,8 +827,12 @@ func TestDeleteMessage(t *testing.T) { message, _ := bot.Send(msg) deleteMessageConfig := DeleteMessageConfig{ - ChatID: message.Chat.ID, - MessageID: message.MessageID, + BaseChatMessage: BaseChatMessage{ + ChatConfig: ChatConfig{ + ChatID: message.Chat.ID, + }, + MessageID: message.MessageID, + }, } _, err := bot.Request(deleteMessageConfig) @@ -845,8 +849,12 @@ func TestPinChatMessage(t *testing.T) { message, _ := bot.Send(msg) pinChatMessageConfig := PinChatMessageConfig{ - ChatID: message.Chat.ID, - MessageID: message.MessageID, + BaseChatMessage: BaseChatMessage{ + ChatConfig: ChatConfig{ + ChatID: ChatID, + }, + MessageID: message.MessageID, + }, DisableNotification: false, } _, err := bot.Request(pinChatMessageConfig) @@ -865,8 +873,12 @@ func TestUnpinChatMessage(t *testing.T) { // We need pin message to unpin something pinChatMessageConfig := PinChatMessageConfig{ - ChatID: message.Chat.ID, - MessageID: message.MessageID, + BaseChatMessage: BaseChatMessage{ + ChatConfig: ChatConfig{ + ChatID: message.Chat.ID, + }, + MessageID: message.MessageID, + }, DisableNotification: false, } @@ -875,8 +887,12 @@ func TestUnpinChatMessage(t *testing.T) { } unpinChatMessageConfig := UnpinChatMessageConfig{ - ChatID: message.Chat.ID, - MessageID: message.MessageID, + BaseChatMessage: BaseChatMessage{ + ChatConfig: ChatConfig{ + ChatID: message.Chat.ID, + }, + MessageID: message.MessageID, + }, } if _, err := bot.Request(unpinChatMessageConfig); err != nil { @@ -892,8 +908,12 @@ func TestUnpinAllChatMessages(t *testing.T) { message, _ := bot.Send(msg) pinChatMessageConfig := PinChatMessageConfig{ - ChatID: message.Chat.ID, - MessageID: message.MessageID, + BaseChatMessage: BaseChatMessage{ + ChatConfig: ChatConfig{ + ChatID: message.Chat.ID, + }, + MessageID: message.MessageID, + }, DisableNotification: true, } @@ -902,7 +922,7 @@ func TestUnpinAllChatMessages(t *testing.T) { } unpinAllChatMessagesConfig := UnpinAllChatMessagesConfig{ - ChatID: message.Chat.ID, + ChatConfig: ChatConfig{ChatID: message.Chat.ID}, } if _, err := bot.Request(unpinAllChatMessagesConfig); err != nil { diff --git a/configs.go b/configs.go index be49680..268c937 100644 --- a/configs.go +++ b/configs.go @@ -60,6 +60,12 @@ const ( // UpdateTypeEditedChannelPost is new version of a channel post that is known to the bot and was edited UpdateTypeEditedChannelPost = "edited_channel_post" + // UpdateTypeMessageReactionis is a reaction to a message was changed by a user + UpdateTypeMessageReaction = "message_reaction" + + // UpdateTypeMessageReactionCount are reactions to a message with anonymous reactions were changed + UpdateTypeMessageReactionCount = "message_reaction_count" + // UpdateTypeInlineQuery is new incoming inline query UpdateTypeInlineQuery = "inline_query" @@ -96,6 +102,14 @@ const ( // UpdateTypeChatJoinRequest is request to join the chat has been sent. // The bot must have the can_invite_users administrator right in the chat to receive these updates. UpdateTypeChatJoinRequest = "chat_join_request" + + // UpdateTypeChatBoost is chat boost was added or changed. + // The bot must be an administrator in the chat to receive these updates. + UpdateTypeChatBoost = "chat_boost" + + // UpdateTypeRemovedChatBoost is boost was removed from a chat. + // The bot must be an administrator in the chat to receive these updates. + UpdateTypeRemovedChatBoost = "removed_chat_boost" ) // Library errors @@ -266,89 +280,13 @@ func (CloseConfig) params() (Params, error) { return nil, nil } -// BaseChat is base type for all chat config types. -type BaseChat struct { - ChatID int64 // required - MessageThreadID int - ChannelUsername string - ProtectContent bool - ReplyToMessageID int - ReplyMarkup interface{} - DisableNotification bool - AllowSendingWithoutReply bool -} - -func (chat *BaseChat) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", chat.ChatID, chat.ChannelUsername) - params.AddNonZero("message_thread_id", chat.MessageThreadID) - params.AddNonZero("reply_to_message_id", chat.ReplyToMessageID) - params.AddBool("disable_notification", chat.DisableNotification) - params.AddBool("allow_sending_without_reply", chat.AllowSendingWithoutReply) - params.AddBool("protect_content", chat.ProtectContent) - - err := params.AddInterface("reply_markup", chat.ReplyMarkup) - - return params, err -} - -// BaseFile is a base type for all file config types. -type BaseFile struct { - BaseChat - File RequestFileData -} - -func (file BaseFile) params() (Params, error) { - return file.BaseChat.params() -} - -// BaseEdit is base type of all chat edits. -type BaseEdit struct { - ChatID int64 - ChannelUsername string - MessageID int - InlineMessageID string - ReplyMarkup *InlineKeyboardMarkup -} - -func (edit BaseEdit) params() (Params, error) { - params := make(Params) - - if edit.InlineMessageID != "" { - params["inline_message_id"] = edit.InlineMessageID - } else { - params.AddFirstValid("chat_id", edit.ChatID, edit.ChannelUsername) - params.AddNonZero("message_id", edit.MessageID) - } - - err := params.AddInterface("reply_markup", edit.ReplyMarkup) - - return params, err -} - -// BaseSpoiler is base type of structures with spoilers. -type BaseSpoiler struct { - HasSpoiler bool -} - -func (spoiler BaseSpoiler) params() (Params, error) { - params := make(Params) - - if spoiler.HasSpoiler { - params.AddBool("has_spoiler", true) - } - - return params, nil -} - // MessageConfig contains information about a SendMessage request. type MessageConfig struct { BaseChat - Text string - ParseMode string - Entities []MessageEntity - DisableWebPagePreview bool + Text string + ParseMode string + Entities []MessageEntity + LinkPreviewOptions LinkPreviewOptions } func (config MessageConfig) params() (Params, error) { @@ -358,9 +296,12 @@ func (config MessageConfig) params() (Params, error) { } params.AddNonEmpty("text", config.Text) - params.AddBool("disable_web_page_preview", config.DisableWebPagePreview) params.AddNonEmpty("parse_mode", config.ParseMode) err = params.AddInterface("entities", config.Entities) + if err != nil { + return params, err + } + err = params.AddInterface("link_preview_options", config.LinkPreviewOptions) return params, err } @@ -372,9 +313,8 @@ func (config MessageConfig) method() string { // ForwardConfig contains information about a ForwardMessage request. type ForwardConfig struct { BaseChat - FromChatID int64 // required - FromChannelUsername string - MessageID int // required + FromChat ChatConfig + MessageID int // required } func (config ForwardConfig) params() (Params, error) { @@ -382,8 +322,11 @@ func (config ForwardConfig) params() (Params, error) { if err != nil { return params, err } - - params.AddNonZero64("from_chat_id", config.FromChatID) + p1, err := config.FromChat.paramsWithKey("from_chat_id") + if err != nil { + return params, err + } + params.Merge(p1) params.AddNonZero("message_id", config.MessageID) return params, nil @@ -393,15 +336,41 @@ func (config ForwardConfig) method() string { return "forwardMessage" } +// ForwardMessagesConfig contains information about a ForwardMessages request. +type ForwardMessagesConfig struct { + BaseChat + FromChat ChatConfig + MessageIDs []int // required +} + +func (config ForwardMessagesConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return params, err + } + + p1, err := config.FromChat.paramsWithKey("from_chat_id") + if err != nil { + return params, err + } + params.Merge(p1) + err = params.AddInterface("message_ids", config.MessageIDs) + + return params, err +} + +func (config ForwardMessagesConfig) method() string { + return "forwardMessages" +} + // CopyMessageConfig contains information about a copyMessage request. type CopyMessageConfig struct { BaseChat - FromChatID int64 - FromChannelUsername string - MessageID int - Caption string - ParseMode string - CaptionEntities []MessageEntity + FromChat ChatConfig + MessageID int + Caption string + ParseMode string + CaptionEntities []MessageEntity } func (config CopyMessageConfig) params() (Params, error) { @@ -410,7 +379,11 @@ func (config CopyMessageConfig) params() (Params, error) { return params, err } - params.AddFirstValid("from_chat_id", config.FromChatID, config.FromChannelUsername) + p1, err := config.FromChat.paramsWithKey("from_chat_id") + if err != nil { + return params, err + } + params.Merge(p1) params.AddNonZero("message_id", config.MessageID) params.AddNonEmpty("caption", config.Caption) params.AddNonEmpty("parse_mode", config.ParseMode) @@ -423,6 +396,35 @@ func (config CopyMessageConfig) method() string { return "copyMessage" } +// CopyMessagesConfig contains information about a copyMessages request. +type CopyMessagesConfig struct { + BaseChat + FromChat ChatConfig + MessageIDs []int + RemoveCaption bool +} + +func (config CopyMessagesConfig) params() (Params, error) { + params, err := config.BaseChat.params() + if err != nil { + return params, err + } + + p1, err := config.FromChat.paramsWithKey("from_chat_id") + if err != nil { + return params, err + } + params.Merge(p1) + params.AddBool("remove_caption", config.RemoveCaption) + err = params.AddInterface("message_ids", config.MessageIDs) + + return params, err +} + +func (config CopyMessagesConfig) method() string { + return "copyMessages" +} + // PhotoConfig contains information about a SendPhoto request. type PhotoConfig struct { BaseFile @@ -970,13 +972,12 @@ func (config GameConfig) method() string { // SetGameScoreConfig allows you to update the game score in a chat. type SetGameScoreConfig struct { + BaseChatMessage + UserID int64 Score int Force bool DisableEditMessage bool - ChatID int64 - ChannelUsername string - MessageID int InlineMessageID string } @@ -990,8 +991,11 @@ func (config SetGameScoreConfig) params() (Params, error) { if config.InlineMessageID != "" { params["inline_message_id"] = config.InlineMessageID } else { - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddNonZero("message_id", config.MessageID) + p1, err := config.BaseChatMessage.params() + if err != nil { + return params, err + } + params.Merge(p1) } return params, nil @@ -1003,10 +1007,9 @@ func (config SetGameScoreConfig) method() string { // GetGameHighScoresConfig allows you to fetch the high scores for a game. type GetGameHighScoresConfig struct { + BaseChatMessage + UserID int64 - ChatID int64 - ChannelUsername string - MessageID int InlineMessageID string } @@ -1018,8 +1021,11 @@ func (config GetGameHighScoresConfig) params() (Params, error) { if config.InlineMessageID != "" { params["inline_message_id"] = config.InlineMessageID } else { - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddNonZero("message_id", config.MessageID) + p1, err := config.BaseChatMessage.params() + if err != nil { + return params, err + } + params.Merge(p1) } return params, nil @@ -1052,10 +1058,10 @@ func (config ChatActionConfig) method() string { // EditMessageTextConfig allows you to modify the text in a message. type EditMessageTextConfig struct { BaseEdit - Text string - ParseMode string - Entities []MessageEntity - DisableWebPagePreview bool + Text string + ParseMode string + Entities []MessageEntity + LinkPreviewOptions LinkPreviewOptions } func (config EditMessageTextConfig) params() (Params, error) { @@ -1066,8 +1072,11 @@ func (config EditMessageTextConfig) params() (Params, error) { params["text"] = config.Text params.AddNonEmpty("parse_mode", config.ParseMode) - params.AddBool("disable_web_page_preview", config.DisableWebPagePreview) err = params.AddInterface("entities", config.Entities) + if err != nil { + return params, err + } + err = params.AddInterface("link_preview_options", config.LinkPreviewOptions) return params, err } @@ -1154,6 +1163,28 @@ func (StopPollConfig) method() string { return "stopPoll" } +// SetMessageReactionConfig changes reactions on a message. Returns true on success. +type SetMessageReactionConfig struct { + BaseChatMessage + Reaction []ReactionType + IsBig bool +} + +func (config SetMessageReactionConfig) params() (Params, error) { + params, err := config.BaseChatMessage.params() + if err != nil { + return params, err + } + params.AddBool("is_big", config.IsBig) + err = params.AddInterface("reaction", config.Reaction) + + return params, err +} + +func (SetMessageReactionConfig) method() string { + return "setMessageReaction" +} + // UserProfilePhotosConfig contains information about a // GetUserProfilePhotos request. type UserProfilePhotosConfig struct { @@ -1370,10 +1401,17 @@ func (config CallbackConfig) params() (Params, error) { // ChatMemberConfig contains information about a user in a chat for use // with administrative functions such as kicking or unbanning a user. type ChatMemberConfig struct { - ChatID int64 - SuperGroupUsername string - ChannelUsername string - UserID int64 + ChatConfig + UserID int64 +} + +func (config ChatMemberConfig) params() (Params, error) { + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } + params.AddNonZero64("user_id", config.UserID) + return params, nil } // UnbanChatMemberConfig allows you to unban a user. @@ -1387,10 +1425,11 @@ func (config UnbanChatMemberConfig) method() string { } func (config UnbanChatMemberConfig) params() (Params, error) { - params := make(Params) + params, err := config.ChatMemberConfig.params() + if err != nil { + return params, err + } - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) - params.AddNonZero64("user_id", config.UserID) params.AddBool("only_if_banned", config.OnlyIfBanned) return params, nil @@ -1408,10 +1447,11 @@ func (config BanChatMemberConfig) method() string { } func (config BanChatMemberConfig) params() (Params, error) { - params := make(Params) + params, err := config.ChatMemberConfig.params() + if err != nil { + return params, err + } - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params.AddNonZero64("user_id", config.UserID) params.AddNonZero64("until_date", config.UntilDate) params.AddBool("revoke_messages", config.RevokeMessages) @@ -1436,14 +1476,14 @@ func (config RestrictChatMemberConfig) method() string { } func (config RestrictChatMemberConfig) params() (Params, error) { - params := make(Params) + params, err := config.ChatMemberConfig.params() + if err != nil { + return params, err + } - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) - params.AddNonZero64("user_id", config.UserID) params.AddBool("use_independent_chat_permissions", config.UseIndependentChatPermissions) - - err := params.AddInterface("permissions", config.Permissions) params.AddNonZero64("until_date", config.UntilDate) + err = params.AddInterface("permissions", config.Permissions) return params, err } @@ -1473,10 +1513,10 @@ func (config PromoteChatMemberConfig) method() string { } func (config PromoteChatMemberConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) - params.AddNonZero64("user_id", config.UserID) + params, err := config.ChatMemberConfig.params() + if err != nil { + return params, err + } params.AddBool("is_anonymous", config.IsAnonymous) params.AddBool("can_manage_chat", config.CanManageChat) @@ -1509,10 +1549,10 @@ func (SetChatAdministratorCustomTitle) method() string { } func (config SetChatAdministratorCustomTitle) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername, config.ChannelUsername) - params.AddNonZero64("user_id", config.UserID) + params, err := config.ChatMemberConfig.params() + if err != nil { + return params, err + } params.AddNonEmpty("custom_title", config.CustomTitle) return params, nil @@ -1524,10 +1564,9 @@ func (config SetChatAdministratorCustomTitle) params() (Params, error) { // administrator in the supergroup or channel for this to work and must have the // appropriate administrator rights. type BanChatSenderChatConfig struct { - ChatID int64 - ChannelUsername string - SenderChatID int64 - UntilDate int + ChatConfig + SenderChatID int64 + UntilDate int } func (config BanChatSenderChatConfig) method() string { @@ -1535,9 +1574,10 @@ func (config BanChatSenderChatConfig) method() string { } func (config BanChatSenderChatConfig) params() (Params, error) { - params := make(Params) - - _ = params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } params.AddNonZero64("sender_chat_id", config.SenderChatID) params.AddNonZero("until_date", config.UntilDate) @@ -1548,9 +1588,8 @@ func (config BanChatSenderChatConfig) params() (Params, error) { // supergroup or channel. The bot must be an administrator for this to work and // must have the appropriate administrator rights. type UnbanChatSenderChatConfig struct { - ChatID int64 - ChannelUsername string - SenderChatID int64 + ChatConfig + SenderChatID int64 } func (config UnbanChatSenderChatConfig) method() string { @@ -1558,28 +1597,15 @@ func (config UnbanChatSenderChatConfig) method() string { } func (config UnbanChatSenderChatConfig) params() (Params, error) { - params := make(Params) - - _ = params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } params.AddNonZero64("sender_chat_id", config.SenderChatID) return params, nil } -// ChatConfig contains information about getting information on a chat. -type ChatConfig struct { - ChatID int64 - SuperGroupUsername string -} - -func (config ChatConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - - return params, nil -} - // ChatInfoConfig contains information about getting chat information. type ChatInfoConfig struct { ChatConfig @@ -1621,11 +1647,13 @@ func (SetChatPermissionsConfig) method() string { } func (config SetChatPermissionsConfig) params() (Params, error) { - params := make(Params) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) params.AddBool("use_independent_chat_permissions", config.UseIndependentChatPermissions) - err := params.AddInterface("permissions", config.Permissions) + err = params.AddInterface("permissions", config.Permissions) return params, err } @@ -1642,11 +1670,7 @@ func (ChatInviteLinkConfig) method() string { } func (config ChatInviteLinkConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - - return params, nil + return config.ChatConfig.params() } // CreateChatInviteLinkConfig allows you to create an additional invite link for @@ -1666,10 +1690,12 @@ func (CreateChatInviteLinkConfig) method() string { } func (config CreateChatInviteLinkConfig) params() (Params, error) { - params := make(Params) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } params.AddNonEmpty("name", config.Name) - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) params.AddNonZero("expire_date", config.ExpireDate) params.AddNonZero("member_limit", config.MemberLimit) params.AddBool("creates_join_request", config.CreatesJoinRequest) @@ -1694,9 +1720,11 @@ func (EditChatInviteLinkConfig) method() string { } func (config EditChatInviteLinkConfig) params() (Params, error) { - params := make(Params) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) params.AddNonEmpty("name", config.Name) params["invite_link"] = config.InviteLink params.AddNonZero("expire_date", config.ExpireDate) @@ -1720,9 +1748,11 @@ func (RevokeChatInviteLinkConfig) method() string { } func (config RevokeChatInviteLinkConfig) params() (Params, error) { - params := make(Params) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) params["invite_link"] = config.InviteLink return params, nil @@ -1739,10 +1769,12 @@ func (ApproveChatJoinRequestConfig) method() string { } func (config ApproveChatJoinRequestConfig) params() (Params, error) { - params := make(Params) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params.AddNonZero("user_id", int(config.UserID)) + params.AddNonZero64("user_id", config.UserID) return params, nil } @@ -1758,18 +1790,18 @@ func (DeclineChatJoinRequest) method() string { } func (config DeclineChatJoinRequest) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params.AddNonZero("user_id", int(config.UserID)) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } + params.AddNonZero64("user_id", config.UserID) return params, nil } // LeaveChatConfig allows you to leave a chat. type LeaveChatConfig struct { - ChatID int64 - ChannelUsername string + ChatConfig } func (config LeaveChatConfig) method() string { @@ -1777,24 +1809,21 @@ func (config LeaveChatConfig) method() string { } func (config LeaveChatConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - - return params, nil + return config.ChatConfig.params() } // ChatConfigWithUser contains information about a chat and a user. type ChatConfigWithUser struct { - ChatID int64 - SuperGroupUsername string - UserID int64 + ChatConfig + UserID int64 } func (config ChatConfigWithUser) params() (Params, error) { - params := make(Params) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) params.AddNonZero64("user_id", config.UserID) return params, nil @@ -1977,9 +2006,7 @@ func (config PreCheckoutConfig) params() (Params, error) { // DeleteMessageConfig contains information of a message in a chat to delete. type DeleteMessageConfig struct { - ChannelUsername string - ChatID int64 - MessageID int + BaseChatMessage } func (config DeleteMessageConfig) method() string { @@ -1987,19 +2014,25 @@ func (config DeleteMessageConfig) method() string { } func (config DeleteMessageConfig) params() (Params, error) { - params := make(Params) + return config.BaseChatMessage.params() +} - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddNonZero("message_id", config.MessageID) +// DeleteMessageConfig contains information of a messages in a chat to delete. +type DeleteMessagesConfig struct { + BaseChatMessages +} - return params, nil +func (config DeleteMessagesConfig) method() string { + return "deleteMessages" +} + +func (config DeleteMessagesConfig) params() (Params, error) { + return config.BaseChatMessages.params() } // PinChatMessageConfig contains information of a message in a chat to pin. type PinChatMessageConfig struct { - ChatID int64 - ChannelUsername string - MessageID int + BaseChatMessage DisableNotification bool } @@ -2008,10 +2041,11 @@ func (config PinChatMessageConfig) method() string { } func (config PinChatMessageConfig) params() (Params, error) { - params := make(Params) + params, err := config.BaseChatMessage.params() + if err != nil { + return params, err + } - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddNonZero("message_id", config.MessageID) params.AddBool("disable_notification", config.DisableNotification) return params, nil @@ -2021,9 +2055,7 @@ func (config PinChatMessageConfig) params() (Params, error) { // // If MessageID is not specified, it will unpin the most recent pin. type UnpinChatMessageConfig struct { - ChatID int64 - ChannelUsername string - MessageID int + BaseChatMessage } func (config UnpinChatMessageConfig) method() string { @@ -2031,19 +2063,13 @@ func (config UnpinChatMessageConfig) method() string { } func (config UnpinChatMessageConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddNonZero("message_id", config.MessageID) - - return params, nil + return config.BaseChatMessage.params() } // UnpinAllChatMessagesConfig contains information of all messages to unpin in // a chat. type UnpinAllChatMessagesConfig struct { - ChatID int64 - ChannelUsername string + ChatConfig } func (config UnpinAllChatMessagesConfig) method() string { @@ -2051,11 +2077,7 @@ func (config UnpinAllChatMessagesConfig) method() string { } func (config UnpinAllChatMessagesConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - - return params, nil + return config.ChatConfig.params() } // SetChatPhotoConfig allows you to set a group, supergroup, or channel's photo. @@ -2076,8 +2098,7 @@ func (config SetChatPhotoConfig) files() []RequestFile { // DeleteChatPhotoConfig allows you to delete a group, supergroup, or channel's photo. type DeleteChatPhotoConfig struct { - ChatID int64 - ChannelUsername string + ChatConfig } func (config DeleteChatPhotoConfig) method() string { @@ -2085,18 +2106,12 @@ func (config DeleteChatPhotoConfig) method() string { } func (config DeleteChatPhotoConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - - return params, nil + return config.ChatConfig.params() } // SetChatTitleConfig allows you to set the title of something other than a private chat. type SetChatTitleConfig struct { - ChatID int64 - ChannelUsername string - + ChatConfig Title string } @@ -2105,9 +2120,11 @@ func (config SetChatTitleConfig) method() string { } func (config SetChatTitleConfig) params() (Params, error) { - params := make(Params) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) params["title"] = config.Title return params, nil @@ -2115,9 +2132,7 @@ func (config SetChatTitleConfig) params() (Params, error) { // SetChatDescriptionConfig allows you to set the description of a supergroup or channel. type SetChatDescriptionConfig struct { - ChatID int64 - ChannelUsername string - + ChatConfig Description string } @@ -2126,9 +2141,11 @@ func (config SetChatDescriptionConfig) method() string { } func (config SetChatDescriptionConfig) params() (Params, error) { - params := make(Params) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) params["description"] = config.Description return params, nil @@ -2432,8 +2449,7 @@ func (config SetStickerSetThumbConfig) files() []RequestFile { // SetChatStickerSetConfig allows you to set the sticker set for a supergroup. type SetChatStickerSetConfig struct { - ChatID int64 - SuperGroupUsername string + ChatConfig StickerSetName string } @@ -2443,9 +2459,11 @@ func (config SetChatStickerSetConfig) method() string { } func (config SetChatStickerSetConfig) params() (Params, error) { - params := make(Params) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) params["sticker_set_name"] = config.StickerSetName return params, nil @@ -2453,8 +2471,7 @@ func (config SetChatStickerSetConfig) params() (Params, error) { // DeleteChatStickerSetConfig allows you to remove a supergroup's sticker set. type DeleteChatStickerSetConfig struct { - ChatID int64 - SuperGroupUsername string + ChatConfig } func (config DeleteChatStickerSetConfig) method() string { @@ -2462,11 +2479,7 @@ func (config DeleteChatStickerSetConfig) method() string { } func (config DeleteChatStickerSetConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - - return params, nil + return config.ChatConfig.params() } // GetForumTopicIconStickersConfig allows you to get custom emoji stickers, @@ -2481,24 +2494,10 @@ func (config GetForumTopicIconStickersConfig) params() (Params, error) { return nil, nil } -// BaseForum is a base type for all forum config types. -type BaseForum struct { - ChatID int64 - SuperGroupUsername string -} - -func (config BaseForum) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - - return params, nil -} - // CreateForumTopicConfig allows you to create a topic // in a forum supergroup chat. type CreateForumTopicConfig struct { - BaseForum + ChatConfig Name string IconColor int IconCustomEmojiID string @@ -2509,14 +2508,29 @@ func (config CreateForumTopicConfig) method() string { } func (config CreateForumTopicConfig) params() (Params, error) { - params := make(Params) + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } params.AddNonEmpty("name", config.Name) params.AddNonZero("icon_color", config.IconColor) params.AddNonEmpty("icon_custom_emoji_id", config.IconCustomEmojiID) - p1, _ := config.BaseForum.params() - params.Merge(p1) + return params, nil +} + +type BaseForum struct { + ChatConfig + MessageThreadID int +} + +func (base BaseForum) params() (Params, error) { + params, err := base.ChatConfig.params() + if err != nil { + return params, err + } + params.AddNonZero("message_thread_id", base.MessageThreadID) return params, nil } @@ -2525,7 +2539,6 @@ func (config CreateForumTopicConfig) params() (Params, error) { // name and icon of a topic in a forum supergroup chat. type EditForumTopicConfig struct { BaseForum - MessageThreadID int Name string IconCustomEmojiID string } @@ -2535,108 +2548,48 @@ func (config EditForumTopicConfig) method() string { } func (config EditForumTopicConfig) params() (Params, error) { - params := make(Params) - - params.AddNonZero("message_thread_id", config.MessageThreadID) + params, err := config.BaseForum.params() + if err != nil { + return params, err + } params.AddNonEmpty("name", config.Name) params.AddNonEmpty("icon_custom_emoji_id", config.IconCustomEmojiID) - p1, _ := config.BaseForum.params() - params.Merge(p1) - return params, nil } // CloseForumTopicConfig allows you to close // an open topic in a forum supergroup chat. -type CloseForumTopicConfig struct { - BaseForum - MessageThreadID int -} +type CloseForumTopicConfig struct{ BaseForum } func (config CloseForumTopicConfig) method() string { return "closeForumTopic" } -func (config CloseForumTopicConfig) params() (Params, error) { - params := make(Params) - - params.AddNonZero("message_thread_id", config.MessageThreadID) - - p1, _ := config.BaseForum.params() - params.Merge(p1) - - return params, nil -} - // ReopenForumTopicConfig allows you to reopen // an closed topic in a forum supergroup chat. -type ReopenForumTopicConfig struct { - BaseForum - MessageThreadID int -} +type ReopenForumTopicConfig struct{ BaseForum } func (config ReopenForumTopicConfig) method() string { return "reopenForumTopic" } -func (config ReopenForumTopicConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params.AddNonZero("message_thread_id", config.MessageThreadID) - - p1, _ := config.BaseForum.params() - params.Merge(p1) - - return params, nil -} - // DeleteForumTopicConfig allows you to delete a forum topic // along with all its messages in a forum supergroup chat. -type DeleteForumTopicConfig struct { - BaseForum - MessageThreadID int -} +type DeleteForumTopicConfig struct{ BaseForum } func (config DeleteForumTopicConfig) method() string { return "deleteForumTopic" } -func (config DeleteForumTopicConfig) params() (Params, error) { - params := make(Params) - - params.AddNonZero("message_thread_id", config.MessageThreadID) - - p1, _ := config.BaseForum.params() - params.Merge(p1) - - return params, nil -} - // UnpinAllForumTopicMessagesConfig allows you to clear the list // of pinned messages in a forum topic. -type UnpinAllForumTopicMessagesConfig struct { - BaseForum - MessageThreadID int -} +type UnpinAllForumTopicMessagesConfig struct{ BaseForum } func (config UnpinAllForumTopicMessagesConfig) method() string { return "unpinAllForumTopicMessages" } -func (config UnpinAllForumTopicMessagesConfig) params() (Params, error) { - params := make(Params) - - params.AddFirstValid("chat_id", config.ChatID, config.SuperGroupUsername) - params.AddNonZero("message_thread_id", config.MessageThreadID) - - p1, _ := config.BaseForum.params() - params.Merge(p1) - - return params, nil -} - // UnpinAllForumTopicMessagesConfig allows you to edit the name of // the 'General' topic in a forum supergroup chat. // The bot must be an administrator in the chat for this to work @@ -2651,13 +2604,12 @@ func (config EditGeneralForumTopicConfig) method() string { } func (config EditGeneralForumTopicConfig) params() (Params, error) { - params := make(Params) - + params, err := config.BaseForum.params() + if err != nil { + return params, err + } params.AddNonEmpty("name", config.Name) - p1, _ := config.BaseForum.params() - params.Merge(p1) - return params, nil } @@ -2732,10 +2684,6 @@ func (config MediaGroupConfig) params() (Params, error) { return nil, err } - params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - params.AddBool("disable_notification", config.DisableNotification) - params.AddNonZero("reply_to_message_id", config.ReplyToMessageID) - err = params.AddInterface("media", prepareInputMediaForParams(config.Media)) return params, err @@ -2771,6 +2719,26 @@ func (config DiceConfig) params() (Params, error) { return params, err } +type GetUserChatBoostsConfig struct { + ChatConfig + UserID int64 +} + +func (config GetUserChatBoostsConfig) method() string { + return "getUserChatBoosts" +} + +func (config GetUserChatBoostsConfig) params() (Params, error) { + params, err := config.ChatConfig.params() + if err != nil { + return params, err + } + + params.AddNonZero64("user_id", config.UserID) + + return params, err +} + // GetMyCommandsConfig gets a list of the currently registered commands. type GetMyCommandsConfig struct { Scope *BotCommandScope @@ -2949,8 +2917,7 @@ func (config SetMyShortDescriptionConfig) params() (Params, error) { // SetChatMenuButtonConfig changes the bot's menu button in a private chat, // or the default menu button. type SetChatMenuButtonConfig struct { - ChatID int64 - ChannelUsername string + ChatConfig MenuButton *MenuButton } @@ -2960,19 +2927,18 @@ func (config SetChatMenuButtonConfig) method() string { } func (config SetChatMenuButtonConfig) params() (Params, error) { - params := make(Params) - - if err := params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername); err != nil { + params, err := config.ChatConfig.params() + if err != nil { return params, err } - err := params.AddInterface("menu_button", config.MenuButton) + + err = params.AddInterface("menu_button", config.MenuButton) return params, err } type GetChatMenuButtonConfig struct { - ChatID int64 - ChannelUsername string + ChatConfig } func (config GetChatMenuButtonConfig) method() string { @@ -2980,11 +2946,7 @@ func (config GetChatMenuButtonConfig) method() string { } func (config GetChatMenuButtonConfig) params() (Params, error) { - params := make(Params) - - err := params.AddFirstValid("chat_id", config.ChatID, config.ChannelUsername) - - return params, err + return config.ChatConfig.params() } type SetMyDefaultAdministratorRightsConfig struct { diff --git a/helpers.go b/helper_methods.go similarity index 92% rename from helpers.go rename to helper_methods.go index 4001d43..de2dd8a 100644 --- a/helpers.go +++ b/helper_methods.go @@ -17,19 +17,26 @@ import ( func NewMessage(chatID int64, text string) MessageConfig { return MessageConfig{ BaseChat: BaseChat{ - ChatID: chatID, - ReplyToMessageID: 0, + ChatConfig: ChatConfig{ + ChatID: chatID, + }, + }, + Text: text, + LinkPreviewOptions: LinkPreviewOptions{ + IsDisabled: false, }, - Text: text, - DisableWebPagePreview: false, } } // NewDeleteMessage creates a request to delete a message. func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig { return DeleteMessageConfig{ - ChatID: chatID, - MessageID: messageID, + BaseChatMessage: BaseChatMessage{ + ChatConfig: ChatConfig{ + ChatID: chatID, + }, + MessageID: messageID, + }, } } @@ -41,8 +48,9 @@ func NewDeleteMessage(chatID int64, messageID int) DeleteMessageConfig { func NewMessageToChannel(username string, text string) MessageConfig { return MessageConfig{ BaseChat: BaseChat{ - ChannelUsername: username, - }, + ChatConfig: ChatConfig{ + ChannelUsername: username, + }}, Text: text, } } @@ -53,9 +61,9 @@ func NewMessageToChannel(username string, text string) MessageConfig { // and messageID is the ID of the original message. func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig { return ForwardConfig{ - BaseChat: BaseChat{ChatID: chatID}, - FromChatID: fromChatID, - MessageID: messageID, + BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}}, + FromChat: ChatConfig{ChatID: fromChatID}, + MessageID: messageID, } } @@ -65,9 +73,9 @@ func NewForward(chatID int64, fromChatID int64, messageID int) ForwardConfig { // 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, + BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}}, + FromChat: ChatConfig{ChatID: fromChatID}, + MessageID: messageID, } } @@ -80,7 +88,7 @@ func NewCopyMessage(chatID int64, fromChatID int64, messageID int) CopyMessageCo func NewPhoto(chatID int64, file RequestFileData) PhotoConfig { return PhotoConfig{ BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, + BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}}, File: file, }, } @@ -92,10 +100,8 @@ func NewPhoto(chatID int64, file RequestFileData) PhotoConfig { func NewPhotoToChannel(username string, file RequestFileData) PhotoConfig { return PhotoConfig{ BaseFile: BaseFile{ - BaseChat: BaseChat{ - ChannelUsername: username, - }, - File: file, + BaseChat: BaseChat{ChatConfig: ChatConfig{ChannelUsername: username}}, + File: file, }, } } @@ -104,7 +110,7 @@ func NewPhotoToChannel(username string, file RequestFileData) PhotoConfig { func NewAudio(chatID int64, file RequestFileData) AudioConfig { return AudioConfig{ BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, + BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}}, File: file, }, } @@ -114,7 +120,7 @@ func NewAudio(chatID int64, file RequestFileData) AudioConfig { func NewDocument(chatID int64, file RequestFileData) DocumentConfig { return DocumentConfig{ BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, + BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}}, File: file, }, } @@ -124,7 +130,7 @@ func NewDocument(chatID int64, file RequestFileData) DocumentConfig { func NewSticker(chatID int64, file RequestFileData) StickerConfig { return StickerConfig{ BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, + BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}}, File: file, }, } @@ -157,7 +163,7 @@ func NewDeleteStickerSet(name, title string) DeleteStickerSetConfig { func NewVideo(chatID int64, file RequestFileData) VideoConfig { return VideoConfig{ BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, + BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}}, File: file, }, } @@ -167,7 +173,7 @@ func NewVideo(chatID int64, file RequestFileData) VideoConfig { func NewAnimation(chatID int64, file RequestFileData) AnimationConfig { return AnimationConfig{ BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, + BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}}, File: file, }, } @@ -180,7 +186,7 @@ func NewAnimation(chatID int64, file RequestFileData) AnimationConfig { func NewVideoNote(chatID int64, length int, file RequestFileData) VideoNoteConfig { return VideoNoteConfig{ BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, + BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}}, File: file, }, Length: length, @@ -191,7 +197,7 @@ func NewVideoNote(chatID int64, length int, file RequestFileData) VideoNoteConfi func NewVoice(chatID int64, file RequestFileData) VoiceConfig { return VoiceConfig{ BaseFile: BaseFile{ - BaseChat: BaseChat{ChatID: chatID}, + BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}}, File: file, }, } @@ -202,7 +208,7 @@ func NewVoice(chatID int64, file RequestFileData) VoiceConfig { func NewMediaGroup(chatID int64, files []interface{}) MediaGroupConfig { return MediaGroupConfig{ BaseChat: BaseChat{ - ChatID: chatID, + ChatConfig: ChatConfig{ChatID: chatID}, }, Media: files, } @@ -262,7 +268,7 @@ func NewInputMediaDocument(media RequestFileData) InputMediaDocument { func NewContact(chatID int64, phoneNumber, firstName string) ContactConfig { return ContactConfig{ BaseChat: BaseChat{ - ChatID: chatID, + ChatConfig: ChatConfig{ChatID: chatID}, }, PhoneNumber: phoneNumber, FirstName: firstName, @@ -275,7 +281,7 @@ func NewContact(chatID int64, phoneNumber, firstName string) ContactConfig { func NewLocation(chatID int64, latitude float64, longitude float64) LocationConfig { return LocationConfig{ BaseChat: BaseChat{ - ChatID: chatID, + ChatConfig: ChatConfig{ChatID: chatID}, }, Latitude: latitude, Longitude: longitude, @@ -286,7 +292,7 @@ func NewLocation(chatID int64, latitude float64, longitude float64) LocationConf func NewVenue(chatID int64, title, address string, latitude, longitude float64) VenueConfig { return VenueConfig{ BaseChat: BaseChat{ - ChatID: chatID, + ChatConfig: ChatConfig{ChatID: chatID}, }, Title: title, Address: address, @@ -301,7 +307,7 @@ func NewVenue(chatID int64, title, address string, latitude, longitude float64) // chatID is where to send it, action should be set via Chat constants. func NewChatAction(chatID int64, action string) ChatActionConfig { return ChatActionConfig{ - BaseChat: BaseChat{ChatID: chatID}, + BaseChat: BaseChat{ChatConfig: ChatConfig{ChatID: chatID}}, Action: action, } } @@ -592,8 +598,12 @@ func NewInlineQueryResultVenue(id, title, address string, latitude, longitude fl func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTextConfig { return EditMessageTextConfig{ BaseEdit: BaseEdit{ - ChatID: chatID, - MessageID: messageID, + BaseChatMessage: BaseChatMessage{ + ChatConfig: ChatConfig{ + ChatID: chatID, + }, + MessageID: messageID, + }, }, Text: text, } @@ -603,8 +613,12 @@ func NewEditMessageText(chatID int64, messageID int, text string) EditMessageTex func NewEditMessageTextAndMarkup(chatID int64, messageID int, text string, replyMarkup InlineKeyboardMarkup) EditMessageTextConfig { return EditMessageTextConfig{ BaseEdit: BaseEdit{ - ChatID: chatID, - MessageID: messageID, + BaseChatMessage: BaseChatMessage{ + ChatConfig: ChatConfig{ + ChatID: chatID, + }, + MessageID: messageID, + }, ReplyMarkup: &replyMarkup, }, Text: text, @@ -615,8 +629,12 @@ func NewEditMessageTextAndMarkup(chatID int64, messageID int, text string, reply func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMessageCaptionConfig { return EditMessageCaptionConfig{ BaseEdit: BaseEdit{ - ChatID: chatID, - MessageID: messageID, + BaseChatMessage: BaseChatMessage{ + ChatConfig: ChatConfig{ + ChatID: chatID, + }, + MessageID: messageID, + }, }, Caption: caption, } @@ -627,8 +645,12 @@ func NewEditMessageCaption(chatID int64, messageID int, caption string) EditMess func NewEditMessageReplyMarkup(chatID int64, messageID int, replyMarkup InlineKeyboardMarkup) EditMessageReplyMarkupConfig { return EditMessageReplyMarkupConfig{ BaseEdit: BaseEdit{ - ChatID: chatID, - MessageID: messageID, + BaseChatMessage: BaseChatMessage{ + ChatConfig: ChatConfig{ + ChatID: chatID, + }, + MessageID: messageID, + }, ReplyMarkup: &replyMarkup, }, } @@ -801,7 +823,9 @@ 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 { return InvoiceConfig{ - BaseChat: BaseChat{ChatID: chatID}, + BaseChat: BaseChat{ + ChatConfig: ChatConfig{ChatID: chatID}, + }, Title: title, Description: description, Payload: payload, @@ -814,15 +838,19 @@ func NewInvoice(chatID int64, title, description, payload, providerToken, startP // NewChatTitle allows you to update the title of a chat. func NewChatTitle(chatID int64, title string) SetChatTitleConfig { return SetChatTitleConfig{ - ChatID: chatID, - Title: title, + ChatConfig: ChatConfig{ + 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, + ChatConfig: ChatConfig{ + ChatID: chatID, + }, Description: description, } } @@ -832,7 +860,7 @@ func NewChatPhoto(chatID int64, photo RequestFileData) SetChatPhotoConfig { return SetChatPhotoConfig{ BaseFile: BaseFile{ BaseChat: BaseChat{ - ChatID: chatID, + ChatConfig: ChatConfig{ChatID: chatID}, }, File: photo, }, @@ -842,7 +870,9 @@ func NewChatPhoto(chatID int64, photo RequestFileData) SetChatPhotoConfig { // NewDeleteChatPhoto allows you to delete the photo for a chat. func NewDeleteChatPhoto(chatID int64) DeleteChatPhotoConfig { return DeleteChatPhotoConfig{ - ChatID: chatID, + ChatConfig: ChatConfig{ + ChatID: chatID, + }, } } @@ -850,7 +880,7 @@ func NewDeleteChatPhoto(chatID int64) DeleteChatPhotoConfig { func NewPoll(chatID int64, question string, options ...string) SendPollConfig { return SendPollConfig{ BaseChat: BaseChat{ - ChatID: chatID, + ChatConfig: ChatConfig{ChatID: chatID}, }, Question: question, Options: options, @@ -862,8 +892,12 @@ func NewPoll(chatID int64, question string, options ...string) SendPollConfig { func NewStopPoll(chatID int64, messageID int) StopPollConfig { return StopPollConfig{ BaseEdit{ - ChatID: chatID, - MessageID: messageID, + BaseChatMessage: BaseChatMessage{ + ChatConfig: ChatConfig{ + ChatID: chatID, + }, + MessageID: messageID, + }, }, } } @@ -872,7 +906,7 @@ func NewStopPoll(chatID int64, messageID int) StopPollConfig { func NewDice(chatID int64) DiceConfig { return DiceConfig{ BaseChat: BaseChat{ - ChatID: chatID, + ChatConfig: ChatConfig{ChatID: chatID}, }, } } @@ -883,7 +917,7 @@ func NewDice(chatID int64) DiceConfig { func NewDiceWithEmoji(chatID int64, emoji string) DiceConfig { return DiceConfig{ BaseChat: BaseChat{ - ChatID: chatID, + ChatConfig: ChatConfig{ChatID: chatID}, }, Emoji: emoji, } diff --git a/helper_structs.go b/helper_structs.go new file mode 100644 index 0000000..008fc47 --- /dev/null +++ b/helper_structs.go @@ -0,0 +1,127 @@ +package tgbotapi + +// ChatConfig is a base type for all chat identifiers +type ChatConfig struct { + ChatID int64 + ChannelUsername string + SuperGroupUsername string +} + +func (base ChatConfig) params() (Params, error) { + return base.paramsWithKey("chat_id") +} + +func (base ChatConfig) paramsWithKey(key string) (Params, error) { + params := make(Params) + return params, params.AddFirstValid(key, base.ChatID, base.ChannelUsername, base.SuperGroupUsername) +} + +// BaseChat is base type for all chat config types. +type BaseChat struct { + ChatConfig + MessageThreadID int + ProtectContent bool + ReplyMarkup interface{} + DisableNotification bool + ReplyParameters ReplyParameters +} + +func (chat *BaseChat) params() (Params, error) { + params, err := chat.ChatConfig.params() + if err != nil { + return params, err + } + + params.AddNonZero("message_thread_id", chat.MessageThreadID) + params.AddBool("disable_notification", chat.DisableNotification) + params.AddBool("protect_content", chat.ProtectContent) + + err = params.AddInterface("reply_markup", chat.ReplyMarkup) + if err != nil { + return params, err + } + err = params.AddInterface("reply_parameters", chat.ReplyParameters) + return params, err +} + +// BaseFile is a base type for all file config types. +type BaseFile struct { + BaseChat + File RequestFileData +} + +func (file BaseFile) params() (Params, error) { + return file.BaseChat.params() +} + +// BaseEdit is base type of all chat edits. +type BaseEdit struct { + BaseChatMessage + InlineMessageID string + ReplyMarkup *InlineKeyboardMarkup +} + +func (edit BaseEdit) params() (Params, error) { + params := make(Params) + + if edit.InlineMessageID != "" { + params["inline_message_id"] = edit.InlineMessageID + } else { + p1, err := edit.BaseChatMessage.params() + if err != nil { + return params, err + } + params.Merge(p1) + } + + err := params.AddInterface("reply_markup", edit.ReplyMarkup) + + return params, err +} + +// BaseSpoiler is base type of structures with spoilers. +type BaseSpoiler struct { + HasSpoiler bool +} + +func (spoiler BaseSpoiler) params() (Params, error) { + params := make(Params) + + if spoiler.HasSpoiler { + params.AddBool("has_spoiler", true) + } + + return params, nil +} + +// BaseChatMessage is a base type for all messages in chats. +type BaseChatMessage struct { + ChatConfig + MessageID int +} + +func (base BaseChatMessage) params() (Params, error) { + params, err := base.ChatConfig.params() + if err != nil { + return params, err + } + params.AddNonZero("message_id", base.MessageID) + + return params, nil +} + +// BaseChatMessages is a base type for all messages in chats. +type BaseChatMessages struct { + ChatConfig + MessageIDs []int +} + +func (base BaseChatMessages) params() (Params, error) { + params, err := base.ChatConfig.params() + if err != nil { + return params, err + } + err = params.AddInterface("message_ids", base.MessageIDs) + + return params, err +} diff --git a/params.go b/params.go index 118af36..9afd07d 100644 --- a/params.go +++ b/params.go @@ -101,4 +101,4 @@ func (p *Params) Merge(p1 Params) { for k, v := range p1 { (*p)[k] = v } -} \ No newline at end of file +} diff --git a/types.go b/types.go index a907bad..93c7fab 100644 --- a/types.go +++ b/types.go @@ -61,6 +61,14 @@ type Update struct { // // optional EditedChannelPost *Message `json:"edited_channel_post,omitempty"` + // MessageReaction is a reaction to a message was changed by a user. + // + // optional + MessageReaction *MessageReactionUpdated `json:"message_reaction,omitempty"` + // MessageReactionCount reactions to a message with anonymous reactions were changed. + // + // optional + MessageReactionCount *MessageReactionCountUpdated `json:"message_reaction_count,omitempty"` // InlineQuery new incoming inline query // // optional @@ -276,6 +284,11 @@ type Chat struct { // // optional ActiveUsernames []string `json:"active_usernames,omitempty"` + // AvailableReactions is a list of available reactions allowed in the chat. + // If omitted, then all emoji reactions are allowed. Returned only in getChat. + // + // optional + AvailableReactions []ReactionType `json:"available_reactions,omitempty"` // Custom emoji identifier of emoji status of the other party // in a private chat. Returned only in getChat. // @@ -476,6 +489,15 @@ type Message struct { // // optional ReplyToMessage *Message `json:"reply_to_message,omitempty"` + // ExternalReply is an information about the message that is being replied to, + // which may come from another chat or forum topic. + // + // optional + ExternalReply *ExternalReplyInfo `json:"external_reply,omitempty"` + // Quote for replies that quote part of the original message, the quoted part of the message + // + // optional + Quote *TextQuote `json:"text_quote,omitempty"` // ViaBot through which the message was sent; // // optional @@ -505,6 +527,11 @@ type Message struct { // // optional Entities []MessageEntity `json:"entities,omitempty"` + // LinkPreviewOptions are options used for link preview generation for the message, + // if it is a text message and link preview options were changed + // + // Optional + LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` // Animation message is an animation, information about the animation. // For backward compatibility, when this field is set, the document field will also be set; // @@ -663,10 +690,10 @@ type Message struct { // // optional SuccessfulPayment *SuccessfulPayment `json:"successful_payment,omitempty"` - // UserShared is a service message: a user was shared with the bot + // UsersShared is a service message: the users were shared with the bot // // optional - UserShared *UserShared `json:"user_shared,omitempty"` + UsersShared *UsersShared `json:"users_shared,omitempty"` // ChatShared is a service message: a chat was shared with the bot // // optional @@ -832,6 +859,7 @@ type MessageEntity struct { // “underline” (underlined text), // “strikethrough” (strikethrough text), // "spoiler" (spoiler message), + // “blockquote” (block quotation), // “code” (monowidth string), // “pre” (monowidth block), // “text_link” (for clickable text URLs), @@ -925,6 +953,214 @@ func (e MessageEntity) IsTextLink() bool { return e.Type == "text_link" } +// TextQuote contains information about the quoted part of a message +// that is replied to by the given message +type TextQuote struct { + // Text of the quoted part of a message that is replied to by the given message + Text string `json:"text"` + // Entities special entities that appear in the quote. + // Currently, only bold, italic, underline, strikethrough, spoiler, + // and custom_emoji entities are kept in quotes. + // + // optional + Entities []MessageEntity `json:"entities,omitempty"` + // Position is approximate quote position in the original message + // in UTF-16 code units as specified by the sender + Position int `json:"position"` + // IsManual True, if the quote was chosen manually by the message sender. + // Otherwise, the quote was added automatically by the server. + // + // optional + IsManual bool `json:"is_manual,omitempty"` +} + +// ExternalReplyInfo contains information about a message that is being replied to, +// which may come from another chat or forum topic. +type ExternalReplyInfo struct { + // Origin of the message replied to by the given message + Origin MessageOrigin `json:"origin"` + // Chat is the conversation the message belongs to + Chat *Chat `json:"chat"` + // MessageID is a unique message identifier inside this chat + MessageID int `json:"message_id"` + // LinkPreviewOptions used for link preview generation for the original message, + // if it is a text message + // + // Optional + LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` + // Animation message is an animation, information about the animation. + // For backward compatibility, when this field is set, the document field will also be set; + // + // optional + Animation *Animation `json:"animation,omitempty"` + // Audio message is an audio file, information about the file; + // + // optional + Audio *Audio `json:"audio,omitempty"` + // Document message is a general file, information about the file; + // + // optional + Document *Document `json:"document,omitempty"` + // Photo message is a photo, available sizes of the photo; + // + // optional + Photo []PhotoSize `json:"photo,omitempty"` + // Sticker message is a sticker, information about the sticker; + // + // optional + Sticker *Sticker `json:"sticker,omitempty"` + // Story message is a forwarded story; + // + // optional + Story *Story `json:"story,omitempty"` + // Video message is a video, information about the video; + // + // optional + Video *Video `json:"video,omitempty"` + // VideoNote message is a video note, information about the video message; + // + // optional + VideoNote *VideoNote `json:"video_note,omitempty"` + // Voice message is a voice message, information about the file; + // + // optional + Voice *Voice `json:"voice,omitempty"` + // HasMediaSpoiler True, if the message media is covered by a spoiler animation + // + // optional + HasMediaSpoiler bool `json:"has_media_spoiler,omitempty"` + // Contact message is a shared contact, information about the contact; + // + // optional + Contact *Contact `json:"contact,omitempty"` + // Dice is a dice with random value; + // + // optional + Dice *Dice `json:"dice,omitempty"` + // Game message is a game, information about the game; + // + // optional + Game *Game `json:"game,omitempty"` + // Giveaway is information about the giveaway + // + // optional + Giveaway *Giveaway `json:"giveaway,omitempty"` + // GiveawayWinners a giveaway with public winners was completed + // + // optional + GiveawayWinners *GiveawayWinners `json:"giveaway_winners,omitempty"` + // Invoice message is an invoice for a payment; + // + // optional + Invoice *Invoice `json:"invoice,omitempty"` + // Location message is a shared location, information about the location; + // + // optional + Location *Location `json:"location,omitempty"` + // Poll is a native poll, information about the poll; + // + // optional + Poll *Poll `json:"poll,omitempty"` + // Venue message is a venue, information about the venue. + // For backward compatibility, when this field is set, the location field + // will also be set; + // + // optional + Venue *Venue `json:"venue,omitempty"` +} + +// ReplyParameters describes reply parameters for the message that is being sent. +type ReplyParameters struct { + // MessageID identifier of the message that will be replied to in + // the current chat, or in the chat chat_id if it is specified + MessageID int `json:"message_id"` + // ChatID if the message to be replied to is from a different chat, + // unique identifier for the chat or username of the channel (in the format @channelusername) + // + // optional + ChatID interface{} `json:"chat_id,omitempty"` + // AllowSendingWithoutReply true if the message should be sent even + // if the specified message to be replied to is not found; + // can be used only for replies in the same chat and forum topic. + // + // optional + AllowSendingWithoutReply bool `json:"allow_sending_without_reply,omitempty"` + // Quote is a quoted part of the message to be replied to; + // 0-1024 characters after entities parsing. The quote must be + // an exact substring of the message to be replied to, + // including bold, italic, underline, strikethrough, spoiler, and custom_emoji entities. + // The message will fail to send if the quote isn't found in the original message. + // + // optional + Quote string `json:"quote,omitempty"` + // QuoteParseMode mode for parsing entities in the quote. + // + // optional + QuoteParseMode string `json:"quote_parse_mode,omitempty"` + // QuoteEntities a JSON-serialized list of special entities that appear in the quote. + // It can be specified instead of quote_parse_mode. + // + // optional + QuoteEntities []MessageEntity `json:"quote_entities,omitempty"` + // QuotePosition is a position of the quote in the original message in UTF-16 code units + // + // optional + QuotePosition int `json:"quote_position,omitempty"` +} + +const ( + MessageOriginUser = "user" + MessageOriginHiddenUser = "hidden_user" + MessageOriginChat = "chat" + MessageOriginChannel = "channel" +) + +// MessageOrigin describes the origin of a message. It can be one of: "user", "hidden_user", "origin_chat", "origin_channel" +type MessageOrigin struct { + // Type of the message origin. + Type string `json:"type"` + // Date the message was sent originally in Unix time + Date int64 `json:"date"` + // SenderUser "user" only. + // Is a user that sent the message originally + SenderUser *User `json:"sender_user,omitempty"` + // SenderUserName "hidden_user" only. + // Name of the user that sent the message originally + SenderUserName string `json:"sender_user_name,omitempty"` + // SenderChat "chat" and "channel". + // For "chat": Chat that sent the message originally + // For "channel": Channel chat to which the message was originally sent + SenderChat *Chat `json:"sender_chat,omitempty"` + // AuthorSignature "chat" and "channel". + // For "chat": For messages originally sent by an anonymous chat administrator, + // original message author signature. + // For "channel": Signature of the original post author + // + // Optional + AuthorSignature string `json:"author_signature,omitempty"` + // MessageID "channel" only. + // Unique message identifier inside the chat + // + // Optional + MessageID int `json:"message_id,omitempty"` +} + +func (m MessageOrigin) IsUser() bool { + return m.Type == MessageOriginUser +} + +func (m MessageOrigin) IsHiddenUser() bool { + return m.Type == MessageOriginHiddenUser +} + +func (m MessageOrigin) IsChat() bool { + return m.Type == MessageOriginChat +} + +func (m MessageOrigin) IsChannel() bool { + return m.Type == MessageOriginChannel +} + // PhotoSize represents one size of a photo or a file / sticker thumbnail. type PhotoSize struct { // FileID identifier for this file, which can be used to download or reuse @@ -1351,13 +1587,13 @@ type GeneralForumTopicHidden struct { type GeneralForumTopicUnhidden struct { } -// UserShared object contains information about the user whose identifier +// UsersShared object contains information about the user whose identifier // was shared with the bot using a KeyboardButtonRequestUser button. -type UserShared struct { +type UsersShared struct { // RequestID is an indentifier of the request. RequestID int `json:"request_id"` - // UserID in an identifier of the shared user. - UserID int64 `json:"user_id"` + // UserIDs are identifiers of the shared user. + UserIDs []int64 `json:"user_ids"` } // ChatShared contains information about the chat whose identifier @@ -1423,6 +1659,115 @@ type VideoChatParticipantsInvited struct { Users []User `json:"users,omitempty"` } +// Giveaway represents a message about a scheduled giveaway. +type Giveaway struct { + // Chats is the list of chats which the user must join to participate in the giveaway + Chats []Chat `json:"chats"` + // WinnersSelectionDate is point in time (Unix timestamp) when + // winners of the giveaway will be selected + WinnersSelectionDate int64 `json:"winners_selection_date"` + // WinnerCount is the number of users which are supposed + // to be selected as winners of the giveaway + WinnerCount int `json:"winner_count"` + // OnlyNewMembers True, if only users who join the chats after + // the giveaway started should be eligible to win + // + // optional + OnlyNewMembers bool `json:"only_new_members,omitempty"` + // HasPublicWinners True, if the list of giveaway winners will be visible to everyone + // + // optional + HasPublicWinners bool `json:"has_public_winners,omitempty"` + // PrizeDescription is description of additional giveaway prize + // + // optional + PrizeDescription string `json:"prize_description,omitempty"` + // CountryCodes is a list of two-letter ISO 3166-1 alpha-2 country codes + // indicating the countries from which eligible users for the giveaway must come. + // If empty, then all users can participate in the giveaway. + // + // optional + CountryCodes []string `json:"country_codes,omitempty"` + // PremiumSubscriptionMonthCount the number of months the Telegram Premium + // subscription won from the giveaway will be active for + // + // optional + PremiumSubscriptionMonthCount int `json:"premium_subscription_month_count,omitempty"` +} + +// Giveaway represents a message about a scheduled giveaway. +type GiveawayWinners struct { + // Chat that created the giveaway + Chat Chat `json:"chat"` + // GiveawayMessageID is the identifier of the messsage with the giveaway in the chat + GiveawayMessageID int `json:"giveaway_message_id"` + // WinnersSelectionDate is point in time (Unix timestamp) when + // winners of the giveaway will be selected + WinnersSelectionDate int64 `json:"winners_selection_date"` + // WinnerCount is the number of users which are supposed + // to be selected as winners of the giveaway + WinnerCount int `json:"winner_count"` + // Winners is a list of up to 100 winners of the giveaway + Winners []User `json:"winners"` + // AdditionalChatCount is the number of other chats + // the user had to join in order to be eligible for the giveaway + // + // optional + AdditionalChatCount int `json:"additional_chat_count,omitempty"` + // PremiumSubscriptionMonthCount the number of months the Telegram Premium + // subscription won from the giveaway will be active for + // + // optional + PremiumSubscriptionMonthCount int `json:"premium_subscription_month_count,omitempty"` + // UnclaimedPrizeCount is the number of undistributed prizes + // + // optional + UnclaimedPrizeCount int `json:"unclaimed_prize_count,omitempty"` + // OnlyNewMembers True, if only users who join the chats after + // the giveaway started should be eligible to win + // + // optional + OnlyNewMembers bool `json:"only_new_members,omitempty"` + // WasRefunded True, if the giveaway was canceled because the payment for it was refunded + // + // optional + WasRefunded bool `json:"was_refunded,omitempty"` + // PrizeDescription is description of additional giveaway prize + // + // optional + PrizeDescription string `json:"prize_description,omitempty"` +} + +// LinkPreviewOptions describes the options used for link preview generation. +type LinkPreviewOptions struct { + // IsDisabled True, if the link preview is disabled + // + // optional + IsDisabled bool `json:"is_disabled,omitempty"` + // URL to use for the link preview. If empty, + // then the first URL found in the message text will be used + // + // optional + URL string `json:"url,omitempty"` + // PreferSmallMedia True, if the media in the link preview is suppposed + // to be shrunk; ignored if the URL isn't explicitly specified + // or media size change isn't supported for the preview + // + // optional + PreferSmallMedia bool `json:"prefer_small_media,omitempty"` + // PreferLargeMedia True, if the media in the link preview is suppposed + // to be enlarged; ignored if the URL isn't explicitly specified + // or media size change isn't supported for the preview + // + // optional + PreferLargeMedia bool `json:"prefer_large_media,omitempty"` + // ShowAboveText True, if the link preview must be shown above the message text; + // otherwise, the link preview will be shown below the message text + // + // optional + ShowAboveText bool `json:"show_above_text,omitempty"` +} + // UserProfilePhotos contains a set of user profile photos. type UserProfilePhotos struct { // TotalCount total number of profile pictures the target user has @@ -1516,13 +1861,13 @@ type KeyboardButton struct { // Text of the button. If none of the optional fields are used, // it will be sent as a message when the button is pressed. Text string `json:"text"` - // RequestUser if specified, pressing the button will open + // RequestUsers if specified, pressing the button will open // a list of suitable users. Tapping on any user will send // their identifier to the bot in a "user_shared" service message. // Available in private chats only. // // optional - RequestUser *KeyboardButtonRequestUser `json:"request_user,omitempty"` + RequestUsers *KeyboardButtonRequestUsers `json:"request_users,omitempty"` // RequestChat if specified, pressing the button will open // a list of suitable chats. Tapping on a chat will send // its identifier to the bot in a "chat_shared" service message. @@ -1555,10 +1900,10 @@ type KeyboardButton struct { WebApp *WebAppInfo `json:"web_app,omitempty"` } -// KeyboardButtonRequestUser defines the criteria used to request +// KeyboardButtonRequestUsers defines the criteria used to request // a suitable user. The identifier of the selected user will be shared // with the bot when the corresponding button is pressed. -type KeyboardButtonRequestUser struct { +type KeyboardButtonRequestUsers struct { // RequestID is a signed 32-bit identifier of the request. RequestID int `json:"request_id"` // UserIsBot pass True to request a bot, @@ -1573,6 +1918,11 @@ type KeyboardButtonRequestUser struct { // // optional UserIsPremium bool `json:"user_is_premium,omitempty"` + // MaxQuantity is the maximum number of users to be selected. + // 1-10. Defaults to 1 + // + // optional + MaxQuantity int `json:"max_quantity,omitempty"` } // KeyboardButtonRequestChat defines the criteria used to request @@ -2242,6 +2592,72 @@ type ChatLocation struct { Address string `json:"address"` } +const ( + ReactionTypeEmoji = "emoji" + ReactionTypeCustomEmoji = "custom_emoji" +) + +// ReactionType describes the type of a reaction. Currently, it can be one of: "emoji", "custom_emoji" +type ReactionType struct { + // Type of the reaction. Can be "emoji", "custom_emoji" + Type string `json:"type"` + // Emoji type "emoji" only. Is a reaction emoji. + Emoji string `json:"emoji"` + // CustomEmoji type "custom_emoji" only. Is a custom emoji identifier. + CustomEmoji string `json:"custom_emoji"` +} + +func (r ReactionType) IsEmoji() bool { + return r.Type == ReactionTypeEmoji +} + +func (r ReactionType) IsCustomEmoji() bool { + return r.Type == ReactionTypeCustomEmoji +} + +// ReactionCount represents a reaction added to a message along with the number of times it was added. +type ReactionCount struct { + // Type of the reaction + Type ReactionType `json:"type"` + // TotalCount number of times the reaction was added + TotalCount int `json:"total_count"` +} + +// MessageReactionUpdated represents a change of a reaction on a message performed by a user. +type MessageReactionUpdated struct { + // Chat containing the message the user reacted to. + Chat Chat `json:"chat"` + // MessageID unique identifier of the message inside the chat. + MessageID int `json:"message_id"` + // User that changed the reaction, if the user isn't anonymous. + // + // optional + User *User `json:"user"` + // ActorChat the chat on behalf of which the reaction was changed, + // if the user is anonymous. + // + // optional + ActorChat *Chat `json:"actor_chat"` + // Date of the change in Unix time. + Date int64 `json:"date"` + // OldReaction is a previous list of reaction types that were set by the user. + OldReaction []ReactionType `json:"old_reaction"` + // NewReaction is a new list of reaction types that have been set by the user. + NewReaction []ReactionType `json:"new_reaction"` +} + +// MessageReactionCountUpdated represents reaction changes on a message with anonymous reactions. +type MessageReactionCountUpdated struct { + // Chat containing the message. + Chat Chat `json:"chat"` + // MessageID unique identifier of the message inside the chat. + MessageID int `json:"message_id"` + // Date of the change in Unix time. + Date int64 `json:"date"` + // Reactions is a list of reactions that are present on the message. + Reactions []ReactionCount `json:"reactions"` +} + // ForumTopic represents a forum topic. type ForumTopic struct { // MessageThreadID is the unique identifier of the forum topic @@ -2305,6 +2721,83 @@ type MenuButton struct { WebApp *WebAppInfo `json:"web_app,omitempty"` } +const ( + ChatBoostSourcePremium = "premium" + ChatBoostSourceGiftCode = "gift_code" + ChatBoostSourceGiveaway = "giveaway" +) + +// ChatBoostSource describes the source of a chat boost +type ChatBoostSource struct { + // Source of the boost, It can be one of: + // "premium", "gift_code", "giveaway" + Source string `json:"source"` + // For "premium": User that boosted the chat + // For "gift_code": User for which the gift code was created + // Optional for "giveaway": User that won the prize in the giveaway if any + User *User `json:"user,omitempty"` + // GiveawayMessageID "giveaway" only. + // Is an identifier of a message in the chat with the giveaway; + // the message could have been deleted already. May be 0 if the message isn't sent yet. + GiveawayMessageID int `json:"giveaway_message_id,omitempty"` + // IsUnclaimed "giveaway" only. + // True, if the giveaway was completed, but there was no user to win the prize + // + // optional + IsUnclaimed bool `json:"is_unclaimed,omitempty"` +} + +func (c ChatBoostSource) IsPremium() bool { + return c.Source == ChatBoostSourcePremium +} + +func (c ChatBoostSource) IsGiftCode() bool { + return c.Source == ChatBoostSourceGiftCode +} + +func (c ChatBoostSource) IsGiveaway() bool { + return c.Source == ChatBoostSourceGiveaway +} + +// ChatBoost contains information about a chat boost. +type ChatBoost struct { + // BoostID is an unique identifier of the boost + BoostID string `json:"boost_id"` + // AddDate is a point in time (Unix timestamp) when the chat was boosted + AddDate int64 `json:"add_date"` + // ExpirationDate is a point in time (Unix timestamp) when the boost will + // automatically expire, unless the booster's Telegram Premium subscription is prolonged + ExpirationDate int64 `json:"expiration_date"` + // Source of the added boost + Source ChatBoostSource `json:"source"` +} + +// ChatBoostUpdated represents a boost added to a chat or changed. +type ChatBoostUpdated struct { + // Chat which was boosted + Chat Chat `json:"chat"` + // Boost infomation about the chat boost + Boost ChatBoost `json:"boost"` +} + +// ChatBoostRemoved represents a boost removed from a chat. +type ChatBoostRemoved struct { + // Chat which was boosted + Chat Chat `json:"chat"` + // BoostID unique identifier of the boost + BoostID string `json:"boost_id"` + // RemoveDate point in time (Unix timestamp) when the boost was removed + RemoveDate int64 `json:"remove_date"` + // Source of the removed boost + Source ChatBoostSource `json:"source"` +} + +// UserChatBoosts represents a list of boosts added to a chat by a user. +type UserChatBoosts struct { + // Boosts is the list of boosts added to the chat by the user + Boosts []ChatBoost `json:"boosts"` +} + // ResponseParameters are various errors that can be returned in APIResponse. type ResponseParameters struct { // The group has been migrated to a supergroup with the specified identifier. @@ -3576,10 +4069,10 @@ type InputTextMessageContent struct { // // optional Entities []MessageEntity `json:"entities,omitempty"` - // DisableWebPagePreview disables link previews for links in the sent message + // LinkPreviewOptions used for link preview generation for the original message // - // optional - DisableWebPagePreview bool `json:"disable_web_page_preview,omitempty"` + // Optional + LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` } // InputLocationMessageContent contains a location for displaying diff --git a/types_test.go b/types_test.go index 90d01ea..4fd9e44 100644 --- a/types_test.go +++ b/types_test.go @@ -341,6 +341,7 @@ var ( _ Chattable = UnbanChatSenderChatConfig{} _ Chattable = UnpinChatMessageConfig{} _ Chattable = UpdateConfig{} + _ Chattable = SetMessageReactionConfig{} _ Chattable = UserProfilePhotosConfig{} _ Chattable = VenueConfig{} _ Chattable = VideoConfig{} @@ -359,6 +360,7 @@ var ( _ Chattable = ReopenGeneralForumTopicConfig{} _ Chattable = HideGeneralForumTopicConfig{} _ Chattable = UnhideGeneralForumTopicConfig{} + _ Chattable = UnpinAllGeneralForumTopicMessagesConfig{} _ Chattable = SetCustomEmojiStickerSetThumbnailConfig{} _ Chattable = SetStickerSetTitleConfig{} _ Chattable = DeleteStickerSetConfig{} From e06de39556c0d2b2696c8c1c148b46dffdcd2831 Mon Sep 17 00:00:00 2001 From: stdkhai Date: Sat, 6 Jan 2024 16:02:14 +0200 Subject: [PATCH 2/5] giveaway implementation --- types.go | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/types.go b/types.go index 93c7fab..b8e780c 100644 --- a/types.go +++ b/types.go @@ -741,6 +741,22 @@ type Message struct { // // optional GeneralForumTopicUnhidden *GeneralForumTopicUnhidden `json:"general_forum_topic_unhidden,omitempty"` + // Service message: a scheduled giveaway was created + // + // optional + GiveawayCreated *GiveawayCreated `json:"giveaway_created,omitempty"` + // The message is a scheduled giveaway message + // + // optional + Giveaway *Giveaway `json:"giveaway,omitempty"` + // A giveaway with public winners was completed + // + // optional + GiveawayWinners *GiveawayWinners `json:"giveaway_winners,omitempty"` + // Service message: a giveaway without public winners was completed + // + // optional + GiveawayCompleted *GiveawayCompleted `json:"giveaway_completed,omitempty"` // VideoChatScheduled is a service message: video chat scheduled. // // optional @@ -1659,6 +1675,9 @@ type VideoChatParticipantsInvited struct { Users []User `json:"users,omitempty"` } +// This object represents a service message about the creation of a scheduled giveaway. Currently holds no information. +type GiveawayCreated struct{} + // Giveaway represents a message about a scheduled giveaway. type Giveaway struct { // Chats is the list of chats which the user must join to participate in the giveaway @@ -1738,6 +1757,20 @@ type GiveawayWinners struct { PrizeDescription string `json:"prize_description,omitempty"` } +// This object represents a service message about the completion of a giveaway without public winners. +type GiveawayCompleted struct { + // Number of winners in the giveaway + WinnerCount int `json:"winner_count"` + // Number of undistributed prizes + // + // optional + UnclaimedprizeCounr int `json:"unclaimed_prize_count,omitempty"` + // Message with the giveaway that was completed, if it wasn't deleted + // + // optional + GiveawayMessage *Message `json:"giveaway_message,omitempty"` +} + // LinkPreviewOptions describes the options used for link preview generation. type LinkPreviewOptions struct { // IsDisabled True, if the link preview is disabled From 8db24a9981e18884b13b55c77f7d6e8fd4217557 Mon Sep 17 00:00:00 2001 From: stdkhai Date: Sat, 6 Jan 2024 16:11:09 +0200 Subject: [PATCH 3/5] fix typo --- types.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/types.go b/types.go index b8e780c..9ee9659 100644 --- a/types.go +++ b/types.go @@ -1764,7 +1764,7 @@ type GiveawayCompleted struct { // Number of undistributed prizes // // optional - UnclaimedprizeCounr int `json:"unclaimed_prize_count,omitempty"` + UnclaimedPrizeCount int `json:"unclaimed_prize_count,omitempty"` // Message with the giveaway that was completed, if it wasn't deleted // // optional From 92b9f7c7cf5f23b474904cf7a2006942ecc3bb75 Mon Sep 17 00:00:00 2001 From: stdkhai Date: Sat, 6 Jan 2024 17:12:42 +0200 Subject: [PATCH 4/5] other changes implementation; MaybeInaccessibleMessage not used --- types.go | 85 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/types.go b/types.go index 9ee9659..a3665d4 100644 --- a/types.go +++ b/types.go @@ -289,6 +289,28 @@ type Chat struct { // // optional AvailableReactions []ReactionType `json:"available_reactions,omitempty"` + // Identifier of the accent color for the chat name and backgrounds of the chat photo, + // reply header, and link preview. + // See accent colors for more details. Returned only in getChat. + // Always returned in getChat. + // + // optional + AccentColorID int `json:"accent_color_id,omitempty"` + // Custom emoji identifier of emoji chosen by the chat for the reply header and link preview background. + // Returned only in getChat. + // + // optional + BackgroundCustomEmojiID string `json:"background_custom_emoji_id,omitempty"` + // Identifier of the accent color for the chat's profile background. + // See profile accent colors for more details. Returned only in getChat. + // + // optional + ProfileAccentColorID int `json:"profile_accent_color_id,omitempty"` + // Custom emoji identifier of the emoji chosen by the chat for its profile background. + // Returned only in getChat. + // + // optional + ProfileBackgroundCustomEmojiID string `json:"profile_background_custom_emoji_id,omitempty"` // Custom emoji identifier of emoji status of the other party // in a private chat. Returned only in getChat. // @@ -374,6 +396,11 @@ type Chat struct { // // optional HasProtectedContent bool `json:"has_protected_content,omitempty"` + // True, if new chat members will have access to old messages; available only to chat administrators. + // Returned only in getChat. + // + // optional + HasVisibleHistory bool `json:"has_visible_history,omitempty"` // StickerSetName is for supergroups, name of group sticker set.Returned // only in getChat. // @@ -422,6 +449,26 @@ func (c Chat) ChatConfig() ChatConfig { return ChatConfig{ChatID: c.ID} } +// This object describes a message that can be inaccessible to the bot. +// It can be one of +// +// Message +// InaccessibleMessage +type MaybeInaccessibleMessage struct { + Message + InaccessibleMessage +} + +// InaccessibleMessage describes a message that was deleted or is otherwise inaccessible to the bot. +type InaccessibleMessage struct { + // Chat the message belonged to + Chat Chat `json:"chat"` + // Unique message identifier inside the chat + MessageID int `json:"message_id"` + // Always 0. The field can be used to differentiate regular and inaccessible messages. + Date int `json:"date"` +} + // Message represents a message. type Message struct { // MessageID is a unique message identifier inside this chat @@ -446,34 +493,10 @@ type Message struct { Date int `json:"date"` // Chat is the conversation the message belongs to Chat *Chat `json:"chat"` - // ForwardFrom for forwarded messages, sender of the original message; + // Information about the original message for forwarded messages // // optional - ForwardFrom *User `json:"forward_from,omitempty"` - // ForwardFromChat for messages forwarded from channels, - // information about the original channel; - // - // optional - ForwardFromChat *Chat `json:"forward_from_chat,omitempty"` - // ForwardFromMessageID for messages forwarded from channels, - // identifier of the original message in the channel; - // - // optional - ForwardFromMessageID int `json:"forward_from_message_id,omitempty"` - // ForwardSignature for messages forwarded from channels, signature of the - // post author if present - // - // optional - ForwardSignature string `json:"forward_signature,omitempty"` - // ForwardSenderName is the sender's name for messages forwarded from users - // who disallow adding a link to their account in forwarded messages - // - // optional - ForwardSenderName string `json:"forward_sender_name,omitempty"` - // ForwardDate for forwarded messages, date the original message was sent in Unix time; - // - // optional - ForwardDate int `json:"forward_date,omitempty"` + ForwardOrigin *MessageOrigin `json:"forward_origin,omitempty"` // IsTopicMessage true if the message is sent to a forum topic // // optional @@ -675,9 +698,9 @@ type Message struct { // // optional MigrateFromChatID int64 `json:"migrate_from_chat_id,omitempty"` - // PinnedMessage is a specified message was pinned. - // Note that the Message object in this field will not contain further ReplyToMessage - // fields even if it is itself a reply; + // Specified message was pinned. + // Note that the Message object in this field will not contain + // further reply_to_message fields even if it itself is a reply. // // optional PinnedMessage *Message `json:"pinned_message,omitempty"` @@ -2158,9 +2181,7 @@ type CallbackQuery struct { ID string `json:"id"` // From sender From *User `json:"from"` - // Message with the callback button that originated the query. - // Note that message content and message date will not be available if the - // message is too old. + // Message sent by the bot with the callback button that originated the query // // optional Message *Message `json:"message,omitempty"` From 678ff6fe454b136b3b34266ac183dbcf8a129ab1 Mon Sep 17 00:00:00 2001 From: OvyFlash Date: Sun, 7 Jan 2024 09:10:18 +0200 Subject: [PATCH 5/5] Finish implementing Bot API 7.0 changes --- types.go | 74 ++++++++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 34 deletions(-) diff --git a/types.go b/types.go index a3665d4..2c4d856 100644 --- a/types.go +++ b/types.go @@ -159,15 +159,15 @@ func (u *Update) CallbackData() string { func (u *Update) FromChat() *Chat { switch { case u.Message != nil: - return u.Message.Chat + return &u.Message.Chat case u.EditedMessage != nil: - return u.EditedMessage.Chat + return &u.EditedMessage.Chat case u.ChannelPost != nil: - return u.ChannelPost.Chat + return &u.ChannelPost.Chat case u.EditedChannelPost != nil: - return u.EditedChannelPost.Chat + return &u.EditedChannelPost.Chat case u.CallbackQuery != nil && u.CallbackQuery.Message != nil: - return u.CallbackQuery.Message.Chat + return &u.CallbackQuery.Message.Chat default: return nil } @@ -289,38 +289,39 @@ type Chat struct { // // optional AvailableReactions []ReactionType `json:"available_reactions,omitempty"` - // Identifier of the accent color for the chat name and backgrounds of the chat photo, - // reply header, and link preview. + // AccentColorID is an identifier of the accent color for the chat name and backgrounds of + // the chat photo, reply header, and link preview. // See accent colors for more details. Returned only in getChat. // Always returned in getChat. // // optional AccentColorID int `json:"accent_color_id,omitempty"` - // Custom emoji identifier of emoji chosen by the chat for the reply header and link preview background. + // BackgroundCustomEmojiID is a custom emoji identifier of emoji chosen by + // the chat for the reply header and link preview background. // Returned only in getChat. // // optional BackgroundCustomEmojiID string `json:"background_custom_emoji_id,omitempty"` - // Identifier of the accent color for the chat's profile background. + // ProfileAccentColorID is ani dentifier of the accent color for the chat's profile background. // See profile accent colors for more details. Returned only in getChat. // // optional ProfileAccentColorID int `json:"profile_accent_color_id,omitempty"` - // Custom emoji identifier of the emoji chosen by the chat for its profile background. - // Returned only in getChat. + // ProfileBackgroundCustomEmojiID is a custom emoji identifier of the emoji chosen by + // the chat for its profile background. Returned only in getChat. // // optional ProfileBackgroundCustomEmojiID string `json:"profile_background_custom_emoji_id,omitempty"` - // Custom emoji identifier of emoji status of the other party + // EmojiStatusCustomEmojiID is a custom emoji identifier of emoji status of the other party // in a private chat. Returned only in getChat. // // optional EmojiStatusCustomEmojiID string `json:"emoji_status_custom_emoji_id,omitempty"` - // Expiration date of the emoji status of the chat or the other party + // EmojiStatusExpirationDate is a date of the emoji status of the chat or the other party // in a private chat, in Unix time, if any. Returned only in getChat. // // optional - EmojiStatusCustomEmojiDate int64 `json:"emoji_status_expiration_date,omitempty"` + EmojiStatusExpirationDate int64 `json:"emoji_status_expiration_date,omitempty"` // Bio is the bio of the other party in a private chat. Returned only in // getChat // @@ -396,8 +397,8 @@ type Chat struct { // // optional HasProtectedContent bool `json:"has_protected_content,omitempty"` - // True, if new chat members will have access to old messages; available only to chat administrators. - // Returned only in getChat. + // HasVisibleHistory is True, if new chat members will have access to old messages; + // available only to chat administrators. Returned only in getChat. // // optional HasVisibleHistory bool `json:"has_visible_history,omitempty"` @@ -449,23 +450,13 @@ func (c Chat) ChatConfig() ChatConfig { return ChatConfig{ChatID: c.ID} } -// This object describes a message that can be inaccessible to the bot. -// It can be one of -// -// Message -// InaccessibleMessage -type MaybeInaccessibleMessage struct { - Message - InaccessibleMessage -} - // InaccessibleMessage describes a message that was deleted or is otherwise inaccessible to the bot. type InaccessibleMessage struct { // Chat the message belonged to Chat Chat `json:"chat"` - // Unique message identifier inside the chat + // MessageID is unique message identifier inside the chat MessageID int `json:"message_id"` - // Always 0. The field can be used to differentiate regular and inaccessible messages. + // Date is always 0. The field can be used to differentiate regular and inaccessible messages. Date int `json:"date"` } @@ -492,8 +483,8 @@ type Message struct { // Date of the message was sent in Unix time Date int `json:"date"` // Chat is the conversation the message belongs to - Chat *Chat `json:"chat"` - // Information about the original message for forwarded messages + Chat Chat `json:"chat"` + // ForwardOrigin is information about the original message for forwarded messages // // optional ForwardOrigin *MessageOrigin `json:"forward_origin,omitempty"` @@ -764,19 +755,19 @@ type Message struct { // // optional GeneralForumTopicUnhidden *GeneralForumTopicUnhidden `json:"general_forum_topic_unhidden,omitempty"` - // Service message: a scheduled giveaway was created + // GiveawayCreated is as service message: a scheduled giveaway was created // // optional GiveawayCreated *GiveawayCreated `json:"giveaway_created,omitempty"` - // The message is a scheduled giveaway message + // Giveaway is a scheduled giveaway message // // optional Giveaway *Giveaway `json:"giveaway,omitempty"` - // A giveaway with public winners was completed + // GiveawayWinners is a giveaway with public winners was completed // // optional GiveawayWinners *GiveawayWinners `json:"giveaway_winners,omitempty"` - // Service message: a giveaway without public winners was completed + // GiveawayCompleted is a service message: a giveaway without public winners was completed // // optional GiveawayCompleted *GiveawayCompleted `json:"giveaway_completed,omitempty"` @@ -2205,6 +2196,21 @@ type CallbackQuery struct { GameShortName string `json:"game_short_name,omitempty"` } +// IsInaccessibleMessage method that shows whether message is inaccessible +func (c CallbackQuery) IsInaccessibleMessage() bool { + return c.Message != nil && c.Message.Date == 0 +} + +func (c CallbackQuery) GetInaccessibleMessage() InaccessibleMessage { + if c.Message == nil { + return InaccessibleMessage{} + } + return InaccessibleMessage{ + Chat: c.Message.Chat, + MessageID: c.Message.MessageID, + } +} + // ForceReply when receiving a message with this object, Telegram clients will // display a reply interface to the user (act as if the user has selected the // bot's message and tapped 'Reply'). This can be extremely useful if you want