From 267a217a31da47e7ec3d81f75864cc4850169276 Mon Sep 17 00:00:00 2001 From: Andrew Privalov Date: Mon, 20 May 2024 12:07:43 +0300 Subject: [PATCH] support api 7.3 (#84) --- CHANGELOG.md | 4 + README.md | 2 +- examples/echo/main.go | 10 ++- methods.go | 4 +- methods_params.go | 41 +++++----- models/chat.go | 12 +++ models/chat_background.go | 141 +++++++++++++++++++++++++++++++++ models/chat_background_test.go | 102 ++++++++++++++++++++++++ models/chat_member.go | 1 + models/message.go | 1 + models/poll.go | 13 ++- 11 files changed, 303 insertions(+), 28 deletions(-) create mode 100644 models/chat_background.go create mode 100644 models/chat_background_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index e03e972..758711e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## v1.3.0 (2024-05-20) + +- support API v7.3 + ## v1.2.2 (2024-04-25) - fix race in test diff --git a/README.md b/README.md index 5306592..39c23cb 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ > [Telegram Group](https://t.me/gotelegrambotui) -> Supports Bot API version: [7.2](https://core.telegram.org/bots/api#march-31-2024) from March 31, 2024 +> Supports Bot API version: [7.3](https://core.telegram.org/bots/api#may-6-2024) from May 6, 2024 It's a Go zero-dependencies telegram bot framework diff --git a/examples/echo/main.go b/examples/echo/main.go index b280e1e..26aa947 100644 --- a/examples/echo/main.go +++ b/examples/echo/main.go @@ -30,8 +30,10 @@ func main() { } func handler(ctx context.Context, b *bot.Bot, update *models.Update) { - b.SendMessage(ctx, &bot.SendMessageParams{ - ChatID: update.Message.Chat.ID, - Text: update.Message.Text, - }) + if update.Message != nil { + b.SendMessage(ctx, &bot.SendMessageParams{ + ChatID: update.Message.Chat.ID, + Text: update.Message.Text, + }) + } } diff --git a/methods.go b/methods.go index 2335c33..dc72732 100644 --- a/methods.go +++ b/methods.go @@ -371,8 +371,8 @@ func (b *Bot) LeaveChat(ctx context.Context, params *LeaveChatParams) (bool, err } // GetChat https://core.telegram.org/bots/api#getchat -func (b *Bot) GetChat(ctx context.Context, params *GetChatParams) (*models.Chat, error) { - var result *models.Chat +func (b *Bot) GetChat(ctx context.Context, params *GetChatParams) (*models.ChatFullInfo, error) { + var result *models.ChatFullInfo err := b.rawRequest(ctx, "getChat", params, &result) return result, err } diff --git a/methods_params.go b/methods_params.go index b064e96..24c1893 100644 --- a/methods_params.go +++ b/methods_params.go @@ -237,6 +237,7 @@ type EditMessageLiveLocationParams struct { InlineMessageID string `json:"inline_message_id,omitempty"` Latitude float64 `json:"latitude"` Longitude float64 `json:"longitude"` + LivePeriod int `json:"live_period,omitempty"` HorizontalAccuracy float64 `json:"horizontal_accuracy,omitempty"` Heading int `json:"heading,omitempty"` ProximityAlertRadius int `json:"proximity_alert_radius,omitempty"` @@ -286,25 +287,27 @@ type SendContactParams struct { // SendPollParams https://core.telegram.org/bots/api#sendpoll type SendPollParams struct { - BusinessConnectionID string `json:"business_connection_id,omitempty"` - ChatID any `json:"chat_id"` - MessageThreadID int `json:"message_thread_id,omitempty"` - Question string `json:"question"` - Options []string `json:"options"` - IsAnonymous *bool `json:"is_anonymous,omitempty"` - Type string `json:"type,omitempty"` - AllowsMultipleAnswers bool `json:"allows_multiple_answers,omitempty"` - CorrectOptionID int `json:"correct_option_id"` - Explanation string `json:"explanation,omitempty"` - ExplanationParseMode string `json:"explanation_parse_mode,omitempty"` - ExplanationEntities []models.MessageEntity `json:"explanation_entities,omitempty"` - OpenPeriod int `json:"open_period,omitempty"` - CloseDate int `json:"close_date,omitempty"` - IsClosed bool `json:"is_closed,omitempty"` - DisableNotification bool `json:"disable_notification,omitempty"` - ProtectContent bool `json:"protect_content,omitempty"` - ReplyParameters *models.ReplyParameters `json:"reply_parameters,omitempty"` - ReplyMarkup models.ReplyMarkup `json:"reply_markup,omitempty"` + BusinessConnectionID string `json:"business_connection_id,omitempty"` + ChatID any `json:"chat_id"` + MessageThreadID int `json:"message_thread_id,omitempty"` + Question string `json:"question"` + QuestionParseMode models.ParseMode `json:"question_parse_mode,omitempty"` + QuestionEntities []models.MessageEntity `json:"question_entities,omitempty"` + Options []models.InputPollOption `json:"options"` + IsAnonymous *bool `json:"is_anonymous,omitempty"` + Type string `json:"type,omitempty"` + AllowsMultipleAnswers bool `json:"allows_multiple_answers,omitempty"` + CorrectOptionID int `json:"correct_option_id"` + Explanation string `json:"explanation,omitempty"` + ExplanationParseMode string `json:"explanation_parse_mode,omitempty"` + ExplanationEntities []models.MessageEntity `json:"explanation_entities,omitempty"` + OpenPeriod int `json:"open_period,omitempty"` + CloseDate int `json:"close_date,omitempty"` + IsClosed bool `json:"is_closed,omitempty"` + DisableNotification bool `json:"disable_notification,omitempty"` + ProtectContent bool `json:"protect_content,omitempty"` + ReplyParameters *models.ReplyParameters `json:"reply_parameters,omitempty"` + ReplyMarkup models.ReplyMarkup `json:"reply_markup,omitempty"` } // SendDiceParams https://core.telegram.org/bots/api#senddice diff --git a/models/chat.go b/models/chat.go index 3bf8479..029ef5a 100644 --- a/models/chat.go +++ b/models/chat.go @@ -82,6 +82,17 @@ type Birthdate struct { // Chat https://core.telegram.org/bots/api#chat type Chat struct { + ID int64 `json:"id"` + Type string `json:"type"` + Title string `json:"title,omitempty"` + Username string `json:"username,omitempty"` + FirstName string `json:"first_name,omitempty"` + LastName string `json:"last_name,omitempty"` + IsForum bool `json:"is_forum,omitempty"` +} + +// ChatFullInfo https://core.telegram.org/bots/api#chatfullinfo +type ChatFullInfo struct { ID int64 `json:"id"` Type string `json:"type"` Title string `json:"title,omitempty"` @@ -98,6 +109,7 @@ type Chat struct { PersonalChat *Chat `json:"personal_chat,omitempty"` AvailableReactions []ReactionType `json:"available_reactions,omitempty"` AccentColorID int `json:"accent_color_id,omitempty"` + MaxReactionCount int `json:"max_reaction_count"` BackgroundCustomEmojiID string `json:"background_custom_emoji_id,omitempty"` ProfileAccentColorID int `json:"profile_accent_color_id,omitempty"` ProfileBackgroundCustomEmojiID string `json:"profile_background_custom_emoji_id,omitempty"` diff --git a/models/chat_background.go b/models/chat_background.go new file mode 100644 index 0000000..ad18ddf --- /dev/null +++ b/models/chat_background.go @@ -0,0 +1,141 @@ +package models + +import ( + "encoding/json" + "fmt" +) + +// BackgroundType https://core.telegram.org/bots/api#backgroundtype +type BackgroundType string + +const ( + ChatBackgroundTypeFill BackgroundType = "fill" + ChatBackgroundTypeWallpaper BackgroundType = "wallpaper" + ChatBackgroundTypePattern BackgroundType = "pattern" + ChatBackgroundTypeChatTheme BackgroundType = "chat_theme" +) + +// ChatBackground https://core.telegram.org/bots/api#chatbackground +type ChatBackground struct { + Type BackgroundType + Fill *BackgroundTypeFill + Wallpaper *BackgroundTypeWallpaper + Pattern *BackgroundTypePattern + Theme *BackgroundTypeChatTheme +} + +func (cb *ChatBackground) UnmarshalJSON(data []byte) error { + v := struct { + Type string `json:"type"` + }{} + if err := json.Unmarshal(data, &v); err != nil { + return err + } + + switch v.Type { + case "fill": + cb.Type = ChatBackgroundTypeFill + cb.Fill = &BackgroundTypeFill{} + return json.Unmarshal(data, cb.Fill) + case "wallpaper": + cb.Type = ChatBackgroundTypeWallpaper + cb.Wallpaper = &BackgroundTypeWallpaper{} + return json.Unmarshal(data, cb.Wallpaper) + case "pattern": + cb.Type = ChatBackgroundTypePattern + cb.Pattern = &BackgroundTypePattern{} + return json.Unmarshal(data, cb.Pattern) + case "chat_theme": + cb.Type = ChatBackgroundTypeChatTheme + cb.Theme = &BackgroundTypeChatTheme{} + return json.Unmarshal(data, cb.Theme) + } + + return fmt.Errorf("unsupported ChatBackground type") +} + +// BackgroundTypeFill https://core.telegram.org/bots/api#backgroundtypefill +type BackgroundTypeFill struct { + Fill BackgroundFill `json:"fill"` + DarkThemeDimming int `json:"dark_theme_dimming"` +} + +// BackgroundTypeWallpaper https://core.telegram.org/bots/api#backgroundtypewallpaper +type BackgroundTypeWallpaper struct { + Document Document `json:"document"` + DarkThemeDimming int `json:"dark_theme_dimming"` + IsBlurred bool `json:"is_blurred,omitempty"` + IsMoving bool `json:"is_moving,omitempty"` +} + +// BackgroundTypePattern https://core.telegram.org/bots/api#backgroundtypepattern +type BackgroundTypePattern struct { + Document Document `json:"document"` + Fill BackgroundFill `json:"fill"` + Intensity int `json:"intensity"` + IsInverted bool `json:"is_inverted,omitempty"` + IsMoving bool `json:"is_moving,omitempty"` +} + +// BackgroundTypeChatTheme https://core.telegram.org/bots/api#backgroundtypechattheme +type BackgroundTypeChatTheme struct { + ThemeName string `json:"theme_name"` +} + +type BackgroundFillType string + +const ( + BackgroundFillTypeSolid BackgroundFillType = "solid" + BackgroundFillTypeGradient BackgroundFillType = "gradient" + BackgroundFillTypeFreeformGradient BackgroundFillType = "freeform_gradient" +) + +type BackgroundFill struct { + Type BackgroundFillType `json:"type"` + Solid *BackgroundFillSolid + Gradient *BackgroundFillGradient + FreeformGradient *BackgroundFillFreeformGradient +} + +func (bf *BackgroundFill) UnmarshalJSON(data []byte) error { + v := struct { + Type string `json:"type"` + }{} + if err := json.Unmarshal(data, &v); err != nil { + return err + } + + switch v.Type { + case "solid": + bf.Type = BackgroundFillTypeSolid + bf.Solid = &BackgroundFillSolid{} + return json.Unmarshal(data, bf.Solid) + case "gradient": + bf.Type = BackgroundFillTypeGradient + bf.Gradient = &BackgroundFillGradient{} + return json.Unmarshal(data, bf.Gradient) + case "freeform_gradient": + bf.Type = BackgroundFillTypeFreeformGradient + bf.FreeformGradient = &BackgroundFillFreeformGradient{} + return json.Unmarshal(data, bf.FreeformGradient) + } + + return fmt.Errorf("unsupported BackgroundFill type") +} + +// BackgroundFillSolid https://core.telegram.org/bots/api#backgroundfillsolid +type BackgroundFillSolid struct { + Color int `json:"color"` +} + +// BackgroundFillGradient https://core.telegram.org/bots/api#backgroundfillgradient +type BackgroundFillGradient struct { + TopColor int `json:"top_color"` + BottomColor int `json:"bottom_color"` + RotationAngle int `json:"rotation_angle"` +} + +// BackgroundFillFreeformGradient https://core.telegram.org/bots/api#backgroundfillfreeformgradient +type BackgroundFillFreeformGradient struct { + Colors []int `json:"colors"` +} diff --git a/models/chat_background_test.go b/models/chat_background_test.go new file mode 100644 index 0000000..8e8221f --- /dev/null +++ b/models/chat_background_test.go @@ -0,0 +1,102 @@ +package models + +import ( + "encoding/json" + "testing" +) + +func TestChatBackground_UnmarshalJSON_fill(t *testing.T) { + src := `{"type":"fill","fill":{"type":"solid","color":123},"dark_theme_dimming":2}` + + var cb ChatBackground + err := json.Unmarshal([]byte(src), &cb) + if err != nil { + t.Fatal(err) + } + + if cb.Type != ChatBackgroundTypeFill { + t.Fatal("invalid type") + } + + if cb.Fill == nil { + t.Fatal("invalid Fill") + } + + if cb.Fill.Fill.Type != BackgroundFillTypeSolid { + t.Fatal("invalid fill type") + } + + if cb.Fill.Fill.Solid.Color != 123 { + t.Fatalf("invalid color %d, expect 123", cb.Fill.Fill.Solid.Color) + } + + if cb.Fill.DarkThemeDimming != 2 { + t.Fatalf("invalid dark theme dimming %d, expect 2", cb.Fill.DarkThemeDimming) + } +} + +func TestChatBackground_UnmarshalJSON_wallpaper(t *testing.T) { + src := `{"type":"wallpaper","document":{"file_id":"test","file_unique_id":"test2"},"dark_theme_dimming":2,"is_blurred":true,"is_moving":true}` + + var cb ChatBackground + err := json.Unmarshal([]byte(src), &cb) + if err != nil { + t.Fatal(err) + } + + if cb.Type != ChatBackgroundTypeWallpaper { + t.Fatal("invalid type") + } + + if cb.Wallpaper == nil { + t.Fatal("invalid Wallpaper") + } + + if cb.Wallpaper.Document.FileID != "test" { + t.Fatal("invalid document file id") + } +} + +func TestChatBackground_UnmarshalJSON_pattern(t *testing.T) { + src := `{"type":"pattern","document":{"file_id":"test","file_unique_id":"test","file_size":123,"file_path":"test"},"fill":{"type":"solid","solid":{"color":123}},"intensity":1,"is_inverted":true,"is_moving":true}` + + var cb ChatBackground + err := json.Unmarshal([]byte(src), &cb) + if err != nil { + t.Fatal(err) + } + + if cb.Type != ChatBackgroundTypePattern { + t.Fatal("invalid type") + } + + if cb.Pattern == nil { + t.Fatal("invalid Pattern") + } + + if cb.Pattern.Document.FileID != "test" { + t.Fatal("invalid document file id") + } +} + +func TestChatBackground_UnmarshalJSON_chat_theme(t *testing.T) { + src := `{"type":"chat_theme","theme_name":"test"}` + + var cb ChatBackground + err := json.Unmarshal([]byte(src), &cb) + if err != nil { + t.Fatal(err) + } + + if cb.Type != ChatBackgroundTypeChatTheme { + t.Fatal("invalid type") + } + + if cb.Theme == nil { + t.Fatal("invalid Theme") + } + + if cb.Theme.ThemeName != "test" { + t.Fatal("invalid theme name") + } +} diff --git a/models/chat_member.go b/models/chat_member.go index d48dee6..d08671a 100644 --- a/models/chat_member.go +++ b/models/chat_member.go @@ -13,6 +13,7 @@ type ChatMemberUpdated struct { OldChatMember ChatMember `json:"old_chat_member"` NewChatMember ChatMember `json:"new_chat_member"` InviteLink *ChatInviteLink `json:"invite_link,omitempty"` + ViaJoinRequest bool `json:"via_join_request,omitempty"` ViaChatFolderInviteLink bool `json:"via_chat_folder_invite_link,omitempty"` } diff --git a/models/message.go b/models/message.go index bad420e..6eecd5b 100644 --- a/models/message.go +++ b/models/message.go @@ -122,6 +122,7 @@ type Message struct { PassportData *PassportData `json:"passport_data,omitempty"` ProximityAlertTriggered *ProximityAlertTriggered `json:"proximity_alert_triggered,omitempty"` BoostAdded *ChatBoostAdded `json:"boost_added,omitempty"` + ChatBackgroundSet *ChatBackground `json:"chat_background_set,omitempty"` ForumTopicCreated *ForumTopicCreated `json:"forum_topic_created,omitempty"` ForumTopicEdited *ForumTopicEdited `json:"forum_topic_edited,omitempty"` ForumTopicClosed *ForumTopicClosed `json:"forum_topic_closed,omitempty"` diff --git a/models/poll.go b/models/poll.go index 91ad56a..b1c9104 100644 --- a/models/poll.go +++ b/models/poll.go @@ -8,16 +8,25 @@ type PollAnswer struct { OptionIDs []int `json:"option_ids,omitempty"` } +// InputPollOption https://core.telegram.org/bots/api#inputpolloption +type InputPollOption struct { + Text string `json:"text"` + TextParseMode ParseMode `json:"text_parse_mode,omitempty"` + TextEntities []MessageEntity `json:"text_entities,omitempty"` +} + // PollOption https://core.telegram.org/bots/api#polloption type PollOption struct { - Text string `json:"text"` - VoterCount int `json:"voter_count"` + Text string `json:"text"` + TextEntities []MessageEntity `json:"text_entities,omitempty"` + VoterCount int `json:"voter_count"` } // Poll https://core.telegram.org/bots/api#poll type Poll struct { ID string `json:"id"` Question string `json:"question"` + QuestionEntities []MessageEntity `json:"question_entities,omitempty"` Options []PollOption `json:"options"` TotalVoterCount int `json:"total_voter_count"` IsClosed bool `json:"is_closed"`