diff --git a/api/enums.gen.go b/api/enums.gen.go index fcefc0e..d5022a6 100644 --- a/api/enums.gen.go +++ b/api/enums.gen.go @@ -158,6 +158,7 @@ type InputPollOptionMediaType string const ( InputPollOptionMediaTypeAnimation InputPollOptionMediaType = "animation" + InputPollOptionMediaTypeLink InputPollOptionMediaType = "link" InputPollOptionMediaTypeLivePhoto InputPollOptionMediaType = "live_photo" InputPollOptionMediaTypeLocation InputPollOptionMediaType = "location" InputPollOptionMediaTypePhoto InputPollOptionMediaType = "photo" @@ -357,6 +358,14 @@ const ( RefundedPaymentCurrencyXTR RefundedPaymentCurrency = "XTR" ) +type Result string + +const ( + ResultApprove Result = "approve" + ResultDecline Result = "decline" + ResultQueue Result = "queue" +) + type RevenueWithdrawalStateKind string const ( @@ -365,6 +374,88 @@ const ( RevenueWithdrawalStateKindFailed RevenueWithdrawalStateKind = "failed" ) +type RichBlockListItemType string + +const ( + RichBlockListItemTypeLowerA RichBlockListItemType = "a" + RichBlockListItemTypeUpperA RichBlockListItemType = "A" + RichBlockListItemTypeLowerI RichBlockListItemType = "i" + RichBlockListItemTypeUpperI RichBlockListItemType = "I" + RichBlockListItemType1 RichBlockListItemType = "1" +) + +type RichBlockTableCellAlign string + +const ( + RichBlockTableCellAlignLeft RichBlockTableCellAlign = "left" + RichBlockTableCellAlignCenter RichBlockTableCellAlign = "center" + RichBlockTableCellAlignRight RichBlockTableCellAlign = "right" +) + +type RichBlockTableCellValign string + +const ( + RichBlockTableCellValignTop RichBlockTableCellValign = "top" + RichBlockTableCellValignMiddle RichBlockTableCellValign = "middle" + RichBlockTableCellValignBottom RichBlockTableCellValign = "bottom" +) + +type RichBlockType string + +const ( + RichBlockTypeParagraph RichBlockType = "paragraph" + RichBlockTypeHeading RichBlockType = "heading" + RichBlockTypePre RichBlockType = "pre" + RichBlockTypeFooter RichBlockType = "footer" + RichBlockTypeDivider RichBlockType = "divider" + RichBlockTypeMathematicalExpression RichBlockType = "mathematical_expression" + RichBlockTypeAnchor RichBlockType = "anchor" + RichBlockTypeList RichBlockType = "list" + RichBlockTypeBlockquote RichBlockType = "blockquote" + RichBlockTypePullquote RichBlockType = "pullquote" + RichBlockTypeCollage RichBlockType = "collage" + RichBlockTypeSlideshow RichBlockType = "slideshow" + RichBlockTypeTable RichBlockType = "table" + RichBlockTypeDetails RichBlockType = "details" + RichBlockTypeMap RichBlockType = "map" + RichBlockTypeAnimation RichBlockType = "animation" + RichBlockTypeAudio RichBlockType = "audio" + RichBlockTypePhoto RichBlockType = "photo" + RichBlockTypeVideo RichBlockType = "video" + RichBlockTypeVoiceNote RichBlockType = "voice_note" + RichBlockTypeThinking RichBlockType = "thinking" +) + +type RichTextType string + +const ( + RichTextTypeBold RichTextType = "bold" + RichTextTypeItalic RichTextType = "italic" + RichTextTypeUnderline RichTextType = "underline" + RichTextTypeStrikethrough RichTextType = "strikethrough" + RichTextTypeSpoiler RichTextType = "spoiler" + RichTextTypeDateTime RichTextType = "date_time" + RichTextTypeTextMention RichTextType = "text_mention" + RichTextTypeSubscript RichTextType = "subscript" + RichTextTypeSuperscript RichTextType = "superscript" + RichTextTypeMarked RichTextType = "marked" + RichTextTypeCode RichTextType = "code" + RichTextTypeCustomEmoji RichTextType = "custom_emoji" + RichTextTypeMathematicalExpression RichTextType = "mathematical_expression" + RichTextTypeURL RichTextType = "url" + RichTextTypeEmailAddress RichTextType = "email_address" + RichTextTypePhoneNumber RichTextType = "phone_number" + RichTextTypeBankCardNumber RichTextType = "bank_card_number" + RichTextTypeMention RichTextType = "mention" + RichTextTypeHashtag RichTextType = "hashtag" + RichTextTypeCashtag RichTextType = "cashtag" + RichTextTypeBotCommand RichTextType = "bot_command" + RichTextTypeAnchor RichTextType = "anchor" + RichTextTypeAnchorLink RichTextType = "anchor_link" + RichTextTypeReference RichTextType = "reference" + RichTextTypeReferenceLink RichTextType = "reference_link" +) + type StickerType string const ( diff --git a/api/methods.gen.go b/api/methods.gen.go index 9035f2e..6e70893 100644 --- a/api/methods.gen.go +++ b/api/methods.gen.go @@ -2483,6 +2483,40 @@ func DeclineChatJoinRequest(ctx context.Context, b *client.Bot, p *DeclineChatJo return client.Call[*DeclineChatJoinRequestParams, bool](ctx, b, "declineChatJoinRequest", p) } +// AnswerChatJoinRequestQueryParams is the parameter set for AnswerChatJoinRequestQuery. +// +// Use this method to process a received chat join request query. Returns True on success. +type AnswerChatJoinRequestQueryParams struct { + // Unique identifier of the join request query + ChatJoinRequestQueryID string `json:"chat_join_request_query_id"` + // Result of the query. Must be either “approve” to allow the user to join the chat, “decline” to disallow the user to join the chat, or “queue” to leave the decision to other administrators. + Result Result `json:"result"` +} + +// AnswerChatJoinRequestQuery calls the answerChatJoinRequestQuery Telegram Bot API method. +// +// Use this method to process a received chat join request query. Returns True on success. +func AnswerChatJoinRequestQuery(ctx context.Context, b *client.Bot, p *AnswerChatJoinRequestQueryParams) (bool, error) { + return client.Call[*AnswerChatJoinRequestQueryParams, bool](ctx, b, "answerChatJoinRequestQuery", p) +} + +// SendChatJoinRequestWebAppParams is the parameter set for SendChatJoinRequestWebApp. +// +// Use this method to process a received chat join request query by showing a Mini App to the user before deciding the outcome. Returns True on success. +type SendChatJoinRequestWebAppParams struct { + // Unique identifier of the join request query + ChatJoinRequestQueryID string `json:"chat_join_request_query_id"` + // The URL of the Mini App to be opened + WebAppURL string `json:"web_app_url"` +} + +// SendChatJoinRequestWebApp calls the sendChatJoinRequestWebApp Telegram Bot API method. +// +// Use this method to process a received chat join request query by showing a Mini App to the user before deciding the outcome. Returns True on success. +func SendChatJoinRequestWebApp(ctx context.Context, b *client.Bot, p *SendChatJoinRequestWebAppParams) (bool, error) { + return client.Call[*SendChatJoinRequestWebAppParams, bool](ctx, b, "sendChatJoinRequestWebApp", p) +} + // SetChatPhotoParams is the parameter set for SetChatPhoto. // // Use this method to set a new profile photo for the chat. Photos can't be changed for private chats. The bot must be an administrator in the chat for this to work and must have the appropriate administrator rights. Returns True on success. @@ -4004,7 +4038,7 @@ func SavePreparedKeyboardButton(ctx context.Context, b *client.Bot, p *SavePrepa // EditMessageTextParams is the parameter set for EditMessageText. // -// Use this method to edit text and game messages. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent. +// Use this method to edit text, rich and game messages. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent. type EditMessageTextParams struct { // Unique identifier of the business connection on behalf of which the message to be edited was sent BusinessConnectionID string `json:"business_connection_id,omitempty"` @@ -4014,21 +4048,23 @@ type EditMessageTextParams struct { MessageID *int64 `json:"message_id,omitempty"` // Required if chat_id and message_id are not specified. Identifier of the inline message. InlineMessageID string `json:"inline_message_id,omitempty"` - // New text of the message, 1-4096 characters after entities parsing - Text string `json:"text"` + // New text of the message, 1-4096 characters after entity parsing; required if rich_message isn't specified + Text string `json:"text,omitempty"` // Mode for parsing entities in the message text. See formatting options for more details. ParseMode ParseMode `json:"parse_mode,omitempty"` // A JSON-serialized list of special entities that appear in message text, which can be specified instead of parse_mode Entities []MessageEntity `json:"entities,omitempty"` // Link preview generation options for the message LinkPreviewOptions *LinkPreviewOptions `json:"link_preview_options,omitempty"` + // New rich content of the message; required if text isn't specified + RichMessage *InputRichMessage `json:"rich_message,omitempty"` // A JSON-serialized object for an inline keyboard ReplyMarkup *InlineKeyboardMarkup `json:"reply_markup,omitempty"` } // EditMessageText calls the editMessageText Telegram Bot API method. // -// Use this method to edit text and game messages. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent. +// Use this method to edit text, rich and game messages. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent. func EditMessageText(ctx context.Context, b *client.Bot, p *EditMessageTextParams) (*MessageOrBool, error) { return client.Call[*EditMessageTextParams, *MessageOrBool](ctx, b, "editMessageText", p) } @@ -4066,7 +4102,7 @@ func EditMessageCaption(ctx context.Context, b *client.Bot, p *EditMessageCaptio // EditMessageMediaParams is the parameter set for EditMessageMedia. // -// Use this method to edit animation, audio, document, live photo, photo, or video messages, or to add media to text messages. If a message is part of a message album, then it can be edited only to an audio for audio albums, only to a document for document albums and to a photo, a live photo, or a video otherwise. When an inline message is edited, a new file can't be uploaded; use a previously uploaded file via its file_id or specify a URL. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent. +// Use this method to edit animation, audio, document, live photo, photo, or video messages, or to replace a text or a rich message with a media. If a message is part of a message album, then it can be edited only to an audio for audio albums, only to a document for document albums and to a photo, a live photo, or a video otherwise. When an inline message is edited, a new file can't be uploaded; use a previously uploaded file via its file_id or specify a URL. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent. type EditMessageMediaParams struct { // Unique identifier of the business connection on behalf of which the message to be edited was sent BusinessConnectionID string `json:"business_connection_id,omitempty"` @@ -4121,7 +4157,7 @@ func (p *EditMessageMediaParams) MultipartFiles() []client.MultipartFile { // EditMessageMedia calls the editMessageMedia Telegram Bot API method. // -// Use this method to edit animation, audio, document, live photo, photo, or video messages, or to add media to text messages. If a message is part of a message album, then it can be edited only to an audio for audio albums, only to a document for document albums and to a photo, a live photo, or a video otherwise. When an inline message is edited, a new file can't be uploaded; use a previously uploaded file via its file_id or specify a URL. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent. +// Use this method to edit animation, audio, document, live photo, photo, or video messages, or to replace a text or a rich message with a media. If a message is part of a message album, then it can be edited only to an audio for audio albums, only to a document for document albums and to a photo, a live photo, or a video otherwise. When an inline message is edited, a new file can't be uploaded; use a previously uploaded file via its file_id or specify a URL. On success, if the edited message is not an inline message, the edited Message is returned, otherwise True is returned. Note that business messages that were not sent by the bot and do not contain an inline keyboard can only be edited within 48 hours from the time they were sent. func EditMessageMedia(ctx context.Context, b *client.Bot, p *EditMessageMediaParams) (*MessageOrBool, error) { return client.Call[*EditMessageMediaParams, *MessageOrBool](ctx, b, "editMessageMedia", p) } @@ -4795,6 +4831,64 @@ func DeleteStickerSet(ctx context.Context, b *client.Bot, p *DeleteStickerSetPar return client.Call[*DeleteStickerSetParams, bool](ctx, b, "deleteStickerSet", p) } +// SendRichMessageParams is the parameter set for SendRichMessage. +// +// Use this method to send rich messages. If the message contains a block with a media element, then the bot must have the right to send the media to the chat. On success, the sent Message is returned. +type SendRichMessageParams struct { + // Unique identifier of the business connection on behalf of which the message will be sent + BusinessConnectionID string `json:"business_connection_id,omitempty"` + // Unique identifier for the target chat or username of the target bot, supergroup or channel in the format @username + ChatID ChatID `json:"chat_id"` + // Unique identifier for the target message thread (topic) of a forum; for forum supergroups and private chats of bots with forum topic mode enabled only + MessageThreadID *int64 `json:"message_thread_id,omitempty"` + // Identifier of the direct messages topic to which the message will be sent; required if the message is sent to a direct messages chat + DirectMessagesTopicID *int64 `json:"direct_messages_topic_id,omitempty"` + // The message to be sent + RichMessage InputRichMessage `json:"rich_message"` + // Sends the message silently. Users will receive a notification with no sound. + DisableNotification *bool `json:"disable_notification,omitempty"` + // Protects the contents of the sent message from forwarding and saving + ProtectContent *bool `json:"protect_content,omitempty"` + // Pass True to allow up to 1000 messages per second, ignoring broadcasting limits for a fee of 0.1 Telegram Stars per message. The relevant Stars will be withdrawn from the bot's balance. + AllowPaidBroadcast *bool `json:"allow_paid_broadcast,omitempty"` + // Unique identifier of the message effect to be added to the message; for private chats only + MessageEffectID string `json:"message_effect_id,omitempty"` + // A JSON-serialized object containing the parameters of the suggested post to send; for direct messages chats only. If the message is sent as a reply to another suggested post, then that suggested post is automatically declined. + SuggestedPostParameters *SuggestedPostParameters `json:"suggested_post_parameters,omitempty"` + // Description of the message to reply to + ReplyParameters *ReplyParameters `json:"reply_parameters,omitempty"` + // Additional interface options. A JSON-serialized object for an inline keyboard, custom reply keyboard, instructions to remove a reply keyboard or to force a reply from the user. + ReplyMarkup any `json:"reply_markup,omitempty"` +} + +// SendRichMessage calls the sendRichMessage Telegram Bot API method. +// +// Use this method to send rich messages. If the message contains a block with a media element, then the bot must have the right to send the media to the chat. On success, the sent Message is returned. +func SendRichMessage(ctx context.Context, b *client.Bot, p *SendRichMessageParams) (*Message, error) { + return client.Call[*SendRichMessageParams, *Message](ctx, b, "sendRichMessage", p) +} + +// SendRichMessageDraftParams is the parameter set for SendRichMessageDraft. +// +// Use this method to stream a partial rich message to a user while the message is being generated. Note that the streamed draft is ephemeral and acts as a temporary 30-second preview - once the output is finalized, you must call sendRichMessage with the complete message to persist it in the user's chat. Returns True on success. +type SendRichMessageDraftParams struct { + // Unique identifier for the target private chat + ChatID int64 `json:"chat_id"` + // Unique identifier for the target message thread + MessageThreadID *int64 `json:"message_thread_id,omitempty"` + // Unique identifier of the message draft; must be non-zero. Changes to drafts with the same identifier are animated. + DraftID int64 `json:"draft_id"` + // The partial message to be streamed + RichMessage InputRichMessage `json:"rich_message"` +} + +// SendRichMessageDraft calls the sendRichMessageDraft Telegram Bot API method. +// +// Use this method to stream a partial rich message to a user while the message is being generated. Note that the streamed draft is ephemeral and acts as a temporary 30-second preview - once the output is finalized, you must call sendRichMessage with the complete message to persist it in the user's chat. Returns True on success. +func SendRichMessageDraft(ctx context.Context, b *client.Bot, p *SendRichMessageDraftParams) (bool, error) { + return client.Call[*SendRichMessageDraftParams, bool](ctx, b, "sendRichMessageDraft", p) +} + // AnswerInlineQueryParams is the parameter set for AnswerInlineQuery. // // Use this method to send answers to an inline query. On success, True is returned.No more than 50 results per query are allowed. diff --git a/api/methods_gen_test.go b/api/methods_gen_test.go index ecc7c52..af3c282 100644 --- a/api/methods_gen_test.go +++ b/api/methods_gen_test.go @@ -7427,6 +7427,294 @@ func Test_DeclineChatJoinRequest_ServerError(t *testing.T) { require.True(t, ae.IsRetryable(), "5xx must be retryable") } +func Test_AnswerChatJoinRequestQuery_Success(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.MatchedBy(func(r *http.Request) bool { + return strings.HasSuffix(r.URL.Path, "/answerChatJoinRequestQuery") + })).Return(genTestResp(200, `{"ok":true,"result":true}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &AnswerChatJoinRequestQueryParams{ + ChatJoinRequestQueryID: "test_value", + Result: ResultApprove, + } + _, err := AnswerChatJoinRequestQuery(context.Background(), bot, params) + require.NoError(t, err) +} + +func Test_AnswerChatJoinRequestQuery_APIError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":429,"description":"Too Many Requests","parameters":{"retry_after":1}}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &AnswerChatJoinRequestQueryParams{ + ChatJoinRequestQueryID: "test_value", + Result: ResultApprove, + } + _, err := AnswerChatJoinRequestQuery(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 429, ae.Code) + require.True(t, ae.IsRetryable()) +} + +func Test_AnswerChatJoinRequestQuery_NetworkError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, errors.New("dial tcp: timeout")) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &AnswerChatJoinRequestQueryParams{ + ChatJoinRequestQueryID: "test_value", + Result: ResultApprove, + } + _, err := AnswerChatJoinRequestQuery(context.Background(), bot, params) + require.Error(t, err) + var ne *client.NetworkError + require.ErrorAs(t, err, &ne) +} + +func Test_AnswerChatJoinRequestQuery_ParseError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(genTestResp(200, `not json`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &AnswerChatJoinRequestQueryParams{ + ChatJoinRequestQueryID: "test_value", + Result: ResultApprove, + } + _, err := AnswerChatJoinRequestQuery(context.Background(), bot, params) + require.Error(t, err) + var pe *client.ParseError + require.ErrorAs(t, err, &pe) +} + +func Test_AnswerChatJoinRequestQuery_ContextCanceled(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, context.Canceled).Maybe() + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &AnswerChatJoinRequestQueryParams{ + ChatJoinRequestQueryID: "test_value", + Result: ResultApprove, + } + _, err := AnswerChatJoinRequestQuery(ctx, bot, params) + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) +} + +// Test_AnswerChatJoinRequestQuery_MissingRequiredFields exercises Telegram's server-side +// validation: when a required field is omitted, Telegram returns 400 with +// a description like "Bad Request: is empty". The library must +// surface this as *APIError with the ErrBadRequest sentinel. +func Test_AnswerChatJoinRequestQuery_MissingRequiredFields(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":400,"description":"Bad Request: chat_id is empty"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + // Send a Params with all required fields zeroed — simulates a caller + // that forgot to populate them. The bot library marshals as-is and + // surfaces Telegram's 400 reply. + _, err := AnswerChatJoinRequestQuery(context.Background(), bot, &AnswerChatJoinRequestQueryParams{}) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 400, ae.Code) + require.True(t, errors.Is(err, client.ErrBadRequest)) + require.False(t, ae.IsRetryable()) +} + +// Test_AnswerChatJoinRequestQuery_Forbidden exercises the 403 path (bot blocked by user, +// removed from chat, etc.). The library must surface the ErrForbidden +// sentinel. +func Test_AnswerChatJoinRequestQuery_Forbidden(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":403,"description":"Forbidden: bot was blocked by the user"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &AnswerChatJoinRequestQueryParams{ + ChatJoinRequestQueryID: "test_value", + Result: ResultApprove, + } + _, err := AnswerChatJoinRequestQuery(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 403, ae.Code) + require.True(t, errors.Is(err, client.ErrForbidden)) + require.False(t, ae.IsRetryable()) +} + +// Test_AnswerChatJoinRequestQuery_ServerError exercises the 5xx path. The library must +// classify these as retryable so RetryDoer / user retry logic kicks in. +func Test_AnswerChatJoinRequestQuery_ServerError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":500,"description":"Internal server error"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &AnswerChatJoinRequestQueryParams{ + ChatJoinRequestQueryID: "test_value", + Result: ResultApprove, + } + _, err := AnswerChatJoinRequestQuery(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 500, ae.Code) + require.True(t, ae.IsRetryable(), "5xx must be retryable") +} + +func Test_SendChatJoinRequestWebApp_Success(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.MatchedBy(func(r *http.Request) bool { + return strings.HasSuffix(r.URL.Path, "/sendChatJoinRequestWebApp") + })).Return(genTestResp(200, `{"ok":true,"result":true}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendChatJoinRequestWebAppParams{ + ChatJoinRequestQueryID: "test_value", + WebAppURL: "test_value", + } + _, err := SendChatJoinRequestWebApp(context.Background(), bot, params) + require.NoError(t, err) +} + +func Test_SendChatJoinRequestWebApp_APIError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":429,"description":"Too Many Requests","parameters":{"retry_after":1}}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendChatJoinRequestWebAppParams{ + ChatJoinRequestQueryID: "test_value", + WebAppURL: "test_value", + } + _, err := SendChatJoinRequestWebApp(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 429, ae.Code) + require.True(t, ae.IsRetryable()) +} + +func Test_SendChatJoinRequestWebApp_NetworkError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, errors.New("dial tcp: timeout")) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendChatJoinRequestWebAppParams{ + ChatJoinRequestQueryID: "test_value", + WebAppURL: "test_value", + } + _, err := SendChatJoinRequestWebApp(context.Background(), bot, params) + require.Error(t, err) + var ne *client.NetworkError + require.ErrorAs(t, err, &ne) +} + +func Test_SendChatJoinRequestWebApp_ParseError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(genTestResp(200, `not json`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendChatJoinRequestWebAppParams{ + ChatJoinRequestQueryID: "test_value", + WebAppURL: "test_value", + } + _, err := SendChatJoinRequestWebApp(context.Background(), bot, params) + require.Error(t, err) + var pe *client.ParseError + require.ErrorAs(t, err, &pe) +} + +func Test_SendChatJoinRequestWebApp_ContextCanceled(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, context.Canceled).Maybe() + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendChatJoinRequestWebAppParams{ + ChatJoinRequestQueryID: "test_value", + WebAppURL: "test_value", + } + _, err := SendChatJoinRequestWebApp(ctx, bot, params) + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) +} + +// Test_SendChatJoinRequestWebApp_MissingRequiredFields exercises Telegram's server-side +// validation: when a required field is omitted, Telegram returns 400 with +// a description like "Bad Request: is empty". The library must +// surface this as *APIError with the ErrBadRequest sentinel. +func Test_SendChatJoinRequestWebApp_MissingRequiredFields(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":400,"description":"Bad Request: chat_id is empty"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + // Send a Params with all required fields zeroed — simulates a caller + // that forgot to populate them. The bot library marshals as-is and + // surfaces Telegram's 400 reply. + _, err := SendChatJoinRequestWebApp(context.Background(), bot, &SendChatJoinRequestWebAppParams{}) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 400, ae.Code) + require.True(t, errors.Is(err, client.ErrBadRequest)) + require.False(t, ae.IsRetryable()) +} + +// Test_SendChatJoinRequestWebApp_Forbidden exercises the 403 path (bot blocked by user, +// removed from chat, etc.). The library must surface the ErrForbidden +// sentinel. +func Test_SendChatJoinRequestWebApp_Forbidden(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":403,"description":"Forbidden: bot was blocked by the user"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendChatJoinRequestWebAppParams{ + ChatJoinRequestQueryID: "test_value", + WebAppURL: "test_value", + } + _, err := SendChatJoinRequestWebApp(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 403, ae.Code) + require.True(t, errors.Is(err, client.ErrForbidden)) + require.False(t, ae.IsRetryable()) +} + +// Test_SendChatJoinRequestWebApp_ServerError exercises the 5xx path. The library must +// classify these as retryable so RetryDoer / user retry logic kicks in. +func Test_SendChatJoinRequestWebApp_ServerError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":500,"description":"Internal server error"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendChatJoinRequestWebAppParams{ + ChatJoinRequestQueryID: "test_value", + WebAppURL: "test_value", + } + _, err := SendChatJoinRequestWebApp(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 500, ae.Code) + require.True(t, ae.IsRetryable(), "5xx must be retryable") +} + func Test_SetChatPhoto_Success(t *testing.T) { m := &genTestMockDoer{} m.On("Do", mock.MatchedBy(func(r *http.Request) bool { @@ -18587,9 +18875,7 @@ func Test_EditMessageText_Success(t *testing.T) { })).Return(genTestResp(200, `{"ok":true,"result":true}`), nil) bot := client.New("test:token", client.WithHTTPClient(m)) - params := &EditMessageTextParams{ - Text: "test_value", - } + params := &EditMessageTextParams{} _, err := EditMessageText(context.Background(), bot, params) require.NoError(t, err) } @@ -18600,9 +18886,7 @@ func Test_EditMessageText_APIError(t *testing.T) { genTestResp(200, `{"ok":false,"error_code":429,"description":"Too Many Requests","parameters":{"retry_after":1}}`), nil) bot := client.New("test:token", client.WithHTTPClient(m)) - params := &EditMessageTextParams{ - Text: "test_value", - } + params := &EditMessageTextParams{} _, err := EditMessageText(context.Background(), bot, params) require.Error(t, err) var ae *client.APIError @@ -18616,9 +18900,7 @@ func Test_EditMessageText_NetworkError(t *testing.T) { m.On("Do", mock.Anything).Return(nil, errors.New("dial tcp: timeout")) bot := client.New("test:token", client.WithHTTPClient(m)) - params := &EditMessageTextParams{ - Text: "test_value", - } + params := &EditMessageTextParams{} _, err := EditMessageText(context.Background(), bot, params) require.Error(t, err) var ne *client.NetworkError @@ -18630,9 +18912,7 @@ func Test_EditMessageText_ParseError(t *testing.T) { m.On("Do", mock.Anything).Return(genTestResp(200, `not json`), nil) bot := client.New("test:token", client.WithHTTPClient(m)) - params := &EditMessageTextParams{ - Text: "test_value", - } + params := &EditMessageTextParams{} _, err := EditMessageText(context.Background(), bot, params) require.Error(t, err) var pe *client.ParseError @@ -18647,9 +18927,7 @@ func Test_EditMessageText_ContextCanceled(t *testing.T) { cancel() bot := client.New("test:token", client.WithHTTPClient(m)) - params := &EditMessageTextParams{ - Text: "test_value", - } + params := &EditMessageTextParams{} _, err := EditMessageText(ctx, bot, params) require.Error(t, err) require.ErrorIs(t, err, context.Canceled) @@ -18686,9 +18964,7 @@ func Test_EditMessageText_Forbidden(t *testing.T) { genTestResp(200, `{"ok":false,"error_code":403,"description":"Forbidden: bot was blocked by the user"}`), nil) bot := client.New("test:token", client.WithHTTPClient(m)) - params := &EditMessageTextParams{ - Text: "test_value", - } + params := &EditMessageTextParams{} _, err := EditMessageText(context.Background(), bot, params) require.Error(t, err) var ae *client.APIError @@ -18706,9 +18982,7 @@ func Test_EditMessageText_ServerError(t *testing.T) { genTestResp(200, `{"ok":false,"error_code":500,"description":"Internal server error"}`), nil) bot := client.New("test:token", client.WithHTTPClient(m)) - params := &EditMessageTextParams{ - Text: "test_value", - } + params := &EditMessageTextParams{} _, err := EditMessageText(context.Background(), bot, params) require.Error(t, err) var ae *client.APIError @@ -22830,6 +23104,301 @@ func Test_DeleteStickerSet_ServerError(t *testing.T) { require.True(t, ae.IsRetryable(), "5xx must be retryable") } +func Test_SendRichMessage_Success(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.MatchedBy(func(r *http.Request) bool { + return strings.HasSuffix(r.URL.Path, "/sendRichMessage") + })).Return(genTestResp(200, `{"ok":true,"result":{}}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageParams{ + ChatID: ChatIDFromInt(123), + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessage(context.Background(), bot, params) + require.NoError(t, err) +} + +func Test_SendRichMessage_APIError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":429,"description":"Too Many Requests","parameters":{"retry_after":1}}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageParams{ + ChatID: ChatIDFromInt(123), + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessage(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 429, ae.Code) + require.True(t, ae.IsRetryable()) +} + +func Test_SendRichMessage_NetworkError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, errors.New("dial tcp: timeout")) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageParams{ + ChatID: ChatIDFromInt(123), + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessage(context.Background(), bot, params) + require.Error(t, err) + var ne *client.NetworkError + require.ErrorAs(t, err, &ne) +} + +func Test_SendRichMessage_ParseError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(genTestResp(200, `not json`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageParams{ + ChatID: ChatIDFromInt(123), + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessage(context.Background(), bot, params) + require.Error(t, err) + var pe *client.ParseError + require.ErrorAs(t, err, &pe) +} + +func Test_SendRichMessage_ContextCanceled(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, context.Canceled).Maybe() + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageParams{ + ChatID: ChatIDFromInt(123), + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessage(ctx, bot, params) + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) +} + +// Test_SendRichMessage_MissingRequiredFields exercises Telegram's server-side +// validation: when a required field is omitted, Telegram returns 400 with +// a description like "Bad Request: is empty". The library must +// surface this as *APIError with the ErrBadRequest sentinel. +func Test_SendRichMessage_MissingRequiredFields(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":400,"description":"Bad Request: chat_id is empty"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + // Send a Params with all required fields zeroed — simulates a caller + // that forgot to populate them. The bot library marshals as-is and + // surfaces Telegram's 400 reply. + _, err := SendRichMessage(context.Background(), bot, &SendRichMessageParams{}) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 400, ae.Code) + require.True(t, errors.Is(err, client.ErrBadRequest)) + require.False(t, ae.IsRetryable()) +} + +// Test_SendRichMessage_Forbidden exercises the 403 path (bot blocked by user, +// removed from chat, etc.). The library must surface the ErrForbidden +// sentinel. +func Test_SendRichMessage_Forbidden(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":403,"description":"Forbidden: bot was blocked by the user"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageParams{ + ChatID: ChatIDFromInt(123), + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessage(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 403, ae.Code) + require.True(t, errors.Is(err, client.ErrForbidden)) + require.False(t, ae.IsRetryable()) +} + +// Test_SendRichMessage_ServerError exercises the 5xx path. The library must +// classify these as retryable so RetryDoer / user retry logic kicks in. +func Test_SendRichMessage_ServerError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":500,"description":"Internal server error"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageParams{ + ChatID: ChatIDFromInt(123), + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessage(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 500, ae.Code) + require.True(t, ae.IsRetryable(), "5xx must be retryable") +} + +func Test_SendRichMessageDraft_Success(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.MatchedBy(func(r *http.Request) bool { + return strings.HasSuffix(r.URL.Path, "/sendRichMessageDraft") + })).Return(genTestResp(200, `{"ok":true,"result":true}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageDraftParams{ + ChatID: 42, + DraftID: 42, + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessageDraft(context.Background(), bot, params) + require.NoError(t, err) +} + +func Test_SendRichMessageDraft_APIError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":429,"description":"Too Many Requests","parameters":{"retry_after":1}}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageDraftParams{ + ChatID: 42, + DraftID: 42, + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessageDraft(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 429, ae.Code) + require.True(t, ae.IsRetryable()) +} + +func Test_SendRichMessageDraft_NetworkError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, errors.New("dial tcp: timeout")) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageDraftParams{ + ChatID: 42, + DraftID: 42, + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessageDraft(context.Background(), bot, params) + require.Error(t, err) + var ne *client.NetworkError + require.ErrorAs(t, err, &ne) +} + +func Test_SendRichMessageDraft_ParseError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(genTestResp(200, `not json`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageDraftParams{ + ChatID: 42, + DraftID: 42, + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessageDraft(context.Background(), bot, params) + require.Error(t, err) + var pe *client.ParseError + require.ErrorAs(t, err, &pe) +} + +func Test_SendRichMessageDraft_ContextCanceled(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return(nil, context.Canceled).Maybe() + + ctx, cancel := context.WithCancel(context.Background()) + cancel() + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageDraftParams{ + ChatID: 42, + DraftID: 42, + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessageDraft(ctx, bot, params) + require.Error(t, err) + require.ErrorIs(t, err, context.Canceled) +} + +// Test_SendRichMessageDraft_MissingRequiredFields exercises Telegram's server-side +// validation: when a required field is omitted, Telegram returns 400 with +// a description like "Bad Request: is empty". The library must +// surface this as *APIError with the ErrBadRequest sentinel. +func Test_SendRichMessageDraft_MissingRequiredFields(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":400,"description":"Bad Request: chat_id is empty"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + // Send a Params with all required fields zeroed — simulates a caller + // that forgot to populate them. The bot library marshals as-is and + // surfaces Telegram's 400 reply. + _, err := SendRichMessageDraft(context.Background(), bot, &SendRichMessageDraftParams{}) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 400, ae.Code) + require.True(t, errors.Is(err, client.ErrBadRequest)) + require.False(t, ae.IsRetryable()) +} + +// Test_SendRichMessageDraft_Forbidden exercises the 403 path (bot blocked by user, +// removed from chat, etc.). The library must surface the ErrForbidden +// sentinel. +func Test_SendRichMessageDraft_Forbidden(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":403,"description":"Forbidden: bot was blocked by the user"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageDraftParams{ + ChatID: 42, + DraftID: 42, + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessageDraft(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 403, ae.Code) + require.True(t, errors.Is(err, client.ErrForbidden)) + require.False(t, ae.IsRetryable()) +} + +// Test_SendRichMessageDraft_ServerError exercises the 5xx path. The library must +// classify these as retryable so RetryDoer / user retry logic kicks in. +func Test_SendRichMessageDraft_ServerError(t *testing.T) { + m := &genTestMockDoer{} + m.On("Do", mock.Anything).Return( + genTestResp(200, `{"ok":false,"error_code":500,"description":"Internal server error"}`), nil) + + bot := client.New("test:token", client.WithHTTPClient(m)) + params := &SendRichMessageDraftParams{ + ChatID: 42, + DraftID: 42, + RichMessage: InputRichMessage{}, + } + _, err := SendRichMessageDraft(context.Background(), bot, params) + require.Error(t, err) + var ae *client.APIError + require.ErrorAs(t, err, &ae) + require.Equal(t, 500, ae.Code) + require.True(t, ae.IsRetryable(), "5xx must be retryable") +} + func Test_AnswerInlineQuery_Success(t *testing.T) { m := &genTestMockDoer{} m.On("Do", mock.MatchedBy(func(r *http.Request) bool { diff --git a/api/types.gen.go b/api/types.gen.go index 71a053c..40edb6f 100644 --- a/api/types.gen.go +++ b/api/types.gen.go @@ -130,6 +130,8 @@ type User struct { AllowsUsersToCreateTopics *bool `json:"allows_users_to_create_topics,omitempty"` // Optional. True, if other bots can be created to be controlled by the bot. Returned only in getMe. CanManageBots *bool `json:"can_manage_bots,omitempty"` + // Optional. True, if the bot supports join request queries and can be assigned to process them. Returned only in getMe. + SupportsJoinRequestQueries *bool `json:"supports_join_request_queries,omitempty"` } // This object represents a chat. @@ -256,6 +258,8 @@ type ChatFullInfo struct { UniqueGiftColors *UniqueGiftColors `json:"unique_gift_colors,omitempty"` // Optional. The number of Telegram Stars a general user has to pay to send a message to the chat PaidMessageStarCount *int64 `json:"paid_message_star_count,omitempty"` + // Optional. The bot that processes join request queries in the chat. The field is only available to chat administrators. + GuardBot *User `json:"guard_bot,omitempty"` } // UnmarshalJSON decodes ChatFullInfo by dispatching union-typed fields @@ -364,6 +368,8 @@ type Message struct { SuggestedPostInfo *SuggestedPostInfo `json:"suggested_post_info,omitempty"` // Optional. Unique identifier of the message effect added to the message EffectID string `json:"effect_id,omitempty"` + // Optional. Message is a rich formatted message + RichMessage *RichMessage `json:"rich_message,omitempty"` // Optional. Message is an animation, information about the animation. For backward compatibility, when this field is set, the document field will also be set. Animation *Animation `json:"animation,omitempty"` // Optional. Message is an audio file, information about the file @@ -1293,6 +1299,12 @@ type Dice struct { Value int64 `json:"value"` } +// Represents an HTTP link. +type Link struct { + // URL of the link + URL string `json:"url"` +} + // At most one of the optional fields can be present in any given object. type PollMedia struct { // Optional. Media is an animation, information about the animation @@ -1301,6 +1313,8 @@ type PollMedia struct { Audio *Audio `json:"audio,omitempty"` // Optional. Media is a general file, information about the file; currently, can't be received in a poll option Document *Document `json:"document,omitempty"` + // Optional. The HTTP link attached to the poll option + Link *Link `json:"link,omitempty"` // Optional. Media is a live photo, information about the live photo LivePhoto *LivePhoto `json:"live_photo,omitempty"` // Optional. Media is a shared location, information about the location @@ -1356,6 +1370,7 @@ func (*InputMediaVideo) isInputPollMedia() {} // InputPollOptionMedia is a union type. The following concrete variants implement // it: // - InputMediaAnimation +// - InputMediaLink // - InputMediaLivePhoto // - InputMediaLocation // - InputMediaPhoto @@ -1369,6 +1384,9 @@ type InputPollOptionMedia interface{ isInputPollOptionMedia() } // isInputPollOptionMedia is the marker method that makes InputMediaAnimation implement InputPollOptionMedia. func (*InputMediaAnimation) isInputPollOptionMedia() {} +// isInputPollOptionMedia is the marker method that makes InputMediaLink implement InputPollOptionMedia. +func (*InputMediaLink) isInputPollOptionMedia() {} + // isInputPollOptionMedia is the marker method that makes InputMediaLivePhoto implement InputPollOptionMedia. func (*InputMediaLivePhoto) isInputPollOptionMedia() {} @@ -2933,7 +2951,7 @@ type ChatMemberRestricted struct { User User `json:"user"` // True, if the user is a member of the chat at the moment of the request IsMember bool `json:"is_member"` - // True, if the user is allowed to send text messages, contacts, giveaways, giveaway winners, invoices, locations and venues + // True, if the user is allowed to send text messages, rich messages, contacts, giveaways, giveaway winners, invoices, locations and venues CanSendMessages bool `json:"can_send_messages"` // True, if the user is allowed to send audios CanSendAudios bool `json:"can_send_audios"` @@ -3049,11 +3067,13 @@ type ChatJoinRequest struct { Bio string `json:"bio,omitempty"` // Optional. Chat invite link that was used by the user to send the join request InviteLink *ChatInviteLink `json:"invite_link,omitempty"` + // Optional. Identifier of the join request query. If present, then the bot must call sendChatJoinRequestWebApp or directly call answerChatJoinRequestQuery within 10 seconds. + QueryID string `json:"query_id,omitempty"` } // Describes actions that a non-administrator user is allowed to take in a chat. type ChatPermissions struct { - // Optional. True, if the user is allowed to send text messages, contacts, giveaways, giveaway winners, invoices, locations and venues + // Optional. True, if the user is allowed to send text messages, rich messages, contacts, giveaways, giveaway winners, invoices, locations and venues CanSendMessages *bool `json:"can_send_messages,omitempty"` // Optional. True, if the user is allowed to send audios CanSendAudios *bool `json:"can_send_audios,omitempty"` @@ -4822,6 +4842,30 @@ func (v *InputMediaDocument) MarshalJSON() ([]byte, error) { }) } +// Represents an HTTP link to be sent. +type InputMediaLink struct { + // Type of the result, must be link + Type InputPollOptionMediaType `json:"type"` + // HTTP URL of the link + URL string `json:"url"` +} + +// MarshalJSON encodes InputMediaLink with the discriminator field +// "type" forced to "link". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *InputMediaLink) MarshalJSON() ([]byte, error) { + type alias InputMediaLink + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "link", + alias: (*alias)(v), + }) +} + // Represents a live photo to be sent. type InputMediaLivePhoto struct { // Type of the result, must be live_photo @@ -5344,6 +5388,1440 @@ type InputSticker struct { Keywords []string `json:"keywords,omitempty"` } +// Rich formatted message. +type RichMessage struct { + // Content of the message + Blocks []RichBlock `json:"blocks"` + // Optional. True, if the rich message must be shown right-to-left + IsRtl *bool `json:"is_rtl,omitempty"` +} + +// Describes a rich message to be sent. Exactly one of the fields html or markdown must be used. +type InputRichMessage struct { + // Optional. Content of the rich message to send described using HTML formatting. See rich message formatting options for more details. + HTML string `json:"html,omitempty"` + // Optional. Content of the rich message to send described using Markdown formatting. See rich message formatting options for more details. + Markdown string `json:"markdown,omitempty"` + // Optional. Pass True if the rich message must be shown right-to-left + IsRtl *bool `json:"is_rtl,omitempty"` + // Optional. Pass True to skip automatic detection of entities (e.g., URLs, email addresses, username mentions, hashtags, cashtags, bot commands, or phone numbers) in the text + SkipEntityDetection *bool `json:"skip_entity_detection,omitempty"` +} + +// RichText is a union type. The following concrete variants implement +// it: +// - RichTextBold +// - RichTextItalic +// - RichTextUnderline +// - RichTextStrikethrough +// - RichTextSpoiler +// - RichTextDateTime +// - RichTextTextMention +// - RichTextSubscript +// - RichTextSuperscript +// - RichTextMarked +// - RichTextCode +// - RichTextCustomEmoji +// - RichTextMathematicalExpression +// - RichTextUrl +// - RichTextEmailAddress +// - RichTextPhoneNumber +// - RichTextBankCardNumber +// - RichTextMention +// - RichTextHashtag +// - RichTextCashtag +// - RichTextBotCommand +// - RichTextAnchor +// - RichTextAnchorLink +// - RichTextReference +// - RichTextReferenceLink +// +// This object represents a rich formatted text. Currently, it can be either a String for plain text, an Array of RichText, or any of the following types: +type RichText interface{ isRichText() } + +// isRichText is the marker method that makes RichTextBold implement RichText. +func (*RichTextBold) isRichText() {} + +// isRichText is the marker method that makes RichTextItalic implement RichText. +func (*RichTextItalic) isRichText() {} + +// isRichText is the marker method that makes RichTextUnderline implement RichText. +func (*RichTextUnderline) isRichText() {} + +// isRichText is the marker method that makes RichTextStrikethrough implement RichText. +func (*RichTextStrikethrough) isRichText() {} + +// isRichText is the marker method that makes RichTextSpoiler implement RichText. +func (*RichTextSpoiler) isRichText() {} + +// isRichText is the marker method that makes RichTextDateTime implement RichText. +func (*RichTextDateTime) isRichText() {} + +// isRichText is the marker method that makes RichTextTextMention implement RichText. +func (*RichTextTextMention) isRichText() {} + +// isRichText is the marker method that makes RichTextSubscript implement RichText. +func (*RichTextSubscript) isRichText() {} + +// isRichText is the marker method that makes RichTextSuperscript implement RichText. +func (*RichTextSuperscript) isRichText() {} + +// isRichText is the marker method that makes RichTextMarked implement RichText. +func (*RichTextMarked) isRichText() {} + +// isRichText is the marker method that makes RichTextCode implement RichText. +func (*RichTextCode) isRichText() {} + +// isRichText is the marker method that makes RichTextCustomEmoji implement RichText. +func (*RichTextCustomEmoji) isRichText() {} + +// isRichText is the marker method that makes RichTextMathematicalExpression implement RichText. +func (*RichTextMathematicalExpression) isRichText() {} + +// isRichText is the marker method that makes RichTextUrl implement RichText. +func (*RichTextUrl) isRichText() {} + +// isRichText is the marker method that makes RichTextEmailAddress implement RichText. +func (*RichTextEmailAddress) isRichText() {} + +// isRichText is the marker method that makes RichTextPhoneNumber implement RichText. +func (*RichTextPhoneNumber) isRichText() {} + +// isRichText is the marker method that makes RichTextBankCardNumber implement RichText. +func (*RichTextBankCardNumber) isRichText() {} + +// isRichText is the marker method that makes RichTextMention implement RichText. +func (*RichTextMention) isRichText() {} + +// isRichText is the marker method that makes RichTextHashtag implement RichText. +func (*RichTextHashtag) isRichText() {} + +// isRichText is the marker method that makes RichTextCashtag implement RichText. +func (*RichTextCashtag) isRichText() {} + +// isRichText is the marker method that makes RichTextBotCommand implement RichText. +func (*RichTextBotCommand) isRichText() {} + +// isRichText is the marker method that makes RichTextAnchor implement RichText. +func (*RichTextAnchor) isRichText() {} + +// isRichText is the marker method that makes RichTextAnchorLink implement RichText. +func (*RichTextAnchorLink) isRichText() {} + +// isRichText is the marker method that makes RichTextReference implement RichText. +func (*RichTextReference) isRichText() {} + +// isRichText is the marker method that makes RichTextReferenceLink implement RichText. +func (*RichTextReferenceLink) isRichText() {} + +// A bold text. +type RichTextBold struct { + // Type of the rich text, always “bold” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` +} + +// MarshalJSON encodes RichTextBold with the discriminator field +// "type" forced to "bold". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextBold) MarshalJSON() ([]byte, error) { + type alias RichTextBold + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "bold", + alias: (*alias)(v), + }) +} + +// An italicized text. +type RichTextItalic struct { + // Type of the rich text, always “italic” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` +} + +// MarshalJSON encodes RichTextItalic with the discriminator field +// "type" forced to "italic". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextItalic) MarshalJSON() ([]byte, error) { + type alias RichTextItalic + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "italic", + alias: (*alias)(v), + }) +} + +// An underlined text. +type RichTextUnderline struct { + // Type of the rich text, always “underline” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` +} + +// MarshalJSON encodes RichTextUnderline with the discriminator field +// "type" forced to "underline". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextUnderline) MarshalJSON() ([]byte, error) { + type alias RichTextUnderline + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "underline", + alias: (*alias)(v), + }) +} + +// A strikethrough text. +type RichTextStrikethrough struct { + // Type of the rich text, always “strikethrough” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` +} + +// MarshalJSON encodes RichTextStrikethrough with the discriminator field +// "type" forced to "strikethrough". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextStrikethrough) MarshalJSON() ([]byte, error) { + type alias RichTextStrikethrough + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "strikethrough", + alias: (*alias)(v), + }) +} + +// A text covered by a spoiler. +type RichTextSpoiler struct { + // Type of the rich text, always “spoiler” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` +} + +// MarshalJSON encodes RichTextSpoiler with the discriminator field +// "type" forced to "spoiler". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextSpoiler) MarshalJSON() ([]byte, error) { + type alias RichTextSpoiler + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "spoiler", + alias: (*alias)(v), + }) +} + +// Formatted date and time. +type RichTextDateTime struct { + // Type of the rich text, always “date_time” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` + // The Unix time associated with the entity + UnixTime int64 `json:"unix_time"` + // The string that defines the formatting of the date and time. See date-time entity formatting for more details. + DateTimeFormat string `json:"date_time_format"` +} + +// MarshalJSON encodes RichTextDateTime with the discriminator field +// "type" forced to "date_time". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextDateTime) MarshalJSON() ([]byte, error) { + type alias RichTextDateTime + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "date_time", + alias: (*alias)(v), + }) +} + +// A mention of a Telegram user by their identifier. +type RichTextTextMention struct { + // Type of the rich text, always “text_mention” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` + // The mentioned user + User User `json:"user"` +} + +// MarshalJSON encodes RichTextTextMention with the discriminator field +// "type" forced to "text_mention". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextTextMention) MarshalJSON() ([]byte, error) { + type alias RichTextTextMention + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "text_mention", + alias: (*alias)(v), + }) +} + +// A subscript text. +type RichTextSubscript struct { + // Type of the rich text, always “subscript” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` +} + +// MarshalJSON encodes RichTextSubscript with the discriminator field +// "type" forced to "subscript". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextSubscript) MarshalJSON() ([]byte, error) { + type alias RichTextSubscript + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "subscript", + alias: (*alias)(v), + }) +} + +// A superscript text. +type RichTextSuperscript struct { + // Type of the rich text, always “superscript” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` +} + +// MarshalJSON encodes RichTextSuperscript with the discriminator field +// "type" forced to "superscript". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextSuperscript) MarshalJSON() ([]byte, error) { + type alias RichTextSuperscript + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "superscript", + alias: (*alias)(v), + }) +} + +// A marked text. +type RichTextMarked struct { + // Type of the rich text, always “marked” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` +} + +// MarshalJSON encodes RichTextMarked with the discriminator field +// "type" forced to "marked". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextMarked) MarshalJSON() ([]byte, error) { + type alias RichTextMarked + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "marked", + alias: (*alias)(v), + }) +} + +// A monowidth text. +type RichTextCode struct { + // Type of the rich text, always “code” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` +} + +// MarshalJSON encodes RichTextCode with the discriminator field +// "type" forced to "code". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextCode) MarshalJSON() ([]byte, error) { + type alias RichTextCode + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "code", + alias: (*alias)(v), + }) +} + +// A custom emoji. +type RichTextCustomEmoji struct { + // Type of the rich text, always “custom_emoji” + Type RichTextType `json:"type"` + // Unique identifier of the custom emoji. Use getCustomEmojiStickers to get full information about the sticker. + CustomEmojiID string `json:"custom_emoji_id"` + // Alternative emoji for the custom emoji + AlternativeText string `json:"alternative_text"` +} + +// MarshalJSON encodes RichTextCustomEmoji with the discriminator field +// "type" forced to "custom_emoji". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextCustomEmoji) MarshalJSON() ([]byte, error) { + type alias RichTextCustomEmoji + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "custom_emoji", + alias: (*alias)(v), + }) +} + +// A mathematical expression. +type RichTextMathematicalExpression struct { + // Type of the rich text, always “mathematical_expression” + Type RichTextType `json:"type"` + // The expression in LaTeX format + Expression string `json:"expression"` +} + +// MarshalJSON encodes RichTextMathematicalExpression with the discriminator field +// "type" forced to "mathematical_expression". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextMathematicalExpression) MarshalJSON() ([]byte, error) { + type alias RichTextMathematicalExpression + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "mathematical_expression", + alias: (*alias)(v), + }) +} + +// A text with a link. +type RichTextUrl struct { + // Type of the rich text, always “url” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` + // URL of the link + URL string `json:"url"` +} + +// MarshalJSON encodes RichTextUrl with the discriminator field +// "type" forced to "url". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextUrl) MarshalJSON() ([]byte, error) { + type alias RichTextUrl + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "url", + alias: (*alias)(v), + }) +} + +// A text with an email address. +type RichTextEmailAddress struct { + // Type of the rich text, always “email_address” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` + // The email address + EmailAddress string `json:"email_address"` +} + +// MarshalJSON encodes RichTextEmailAddress with the discriminator field +// "type" forced to "email_address". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextEmailAddress) MarshalJSON() ([]byte, error) { + type alias RichTextEmailAddress + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "email_address", + alias: (*alias)(v), + }) +} + +// A text with a phone number. +type RichTextPhoneNumber struct { + // Type of the rich text, always “phone_number” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` + // The phone number + PhoneNumber string `json:"phone_number"` +} + +// MarshalJSON encodes RichTextPhoneNumber with the discriminator field +// "type" forced to "phone_number". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextPhoneNumber) MarshalJSON() ([]byte, error) { + type alias RichTextPhoneNumber + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "phone_number", + alias: (*alias)(v), + }) +} + +// A text with a bank card number. +type RichTextBankCardNumber struct { + // Type of the rich text, always “bank_card_number” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` + // The bank card number + BankCardNumber string `json:"bank_card_number"` +} + +// MarshalJSON encodes RichTextBankCardNumber with the discriminator field +// "type" forced to "bank_card_number". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextBankCardNumber) MarshalJSON() ([]byte, error) { + type alias RichTextBankCardNumber + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "bank_card_number", + alias: (*alias)(v), + }) +} + +// A mention by a username. +type RichTextMention struct { + // Type of the rich text, always “mention” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` + // The username + Username string `json:"username"` +} + +// MarshalJSON encodes RichTextMention with the discriminator field +// "type" forced to "mention". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextMention) MarshalJSON() ([]byte, error) { + type alias RichTextMention + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "mention", + alias: (*alias)(v), + }) +} + +// A hashtag. +type RichTextHashtag struct { + // Type of the rich text, always “hashtag” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` + // The hashtag + Hashtag string `json:"hashtag"` +} + +// MarshalJSON encodes RichTextHashtag with the discriminator field +// "type" forced to "hashtag". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextHashtag) MarshalJSON() ([]byte, error) { + type alias RichTextHashtag + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "hashtag", + alias: (*alias)(v), + }) +} + +// A cashtag. +type RichTextCashtag struct { + // Type of the rich text, always “cashtag” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` + // The cashtag + Cashtag string `json:"cashtag"` +} + +// MarshalJSON encodes RichTextCashtag with the discriminator field +// "type" forced to "cashtag". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextCashtag) MarshalJSON() ([]byte, error) { + type alias RichTextCashtag + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "cashtag", + alias: (*alias)(v), + }) +} + +// A bot command. +type RichTextBotCommand struct { + // Type of the rich text, always “bot_command” + Type RichTextType `json:"type"` + // The text + Text RichText `json:"text"` + // The bot command + BotCommand string `json:"bot_command"` +} + +// MarshalJSON encodes RichTextBotCommand with the discriminator field +// "type" forced to "bot_command". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextBotCommand) MarshalJSON() ([]byte, error) { + type alias RichTextBotCommand + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "bot_command", + alias: (*alias)(v), + }) +} + +// An anchor. +type RichTextAnchor struct { + // Type of the rich text, always “anchor” + Type RichTextType `json:"type"` + // The name of the anchor + Name string `json:"name"` +} + +// MarshalJSON encodes RichTextAnchor with the discriminator field +// "type" forced to "anchor". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextAnchor) MarshalJSON() ([]byte, error) { + type alias RichTextAnchor + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "anchor", + alias: (*alias)(v), + }) +} + +// A link to an anchor. +type RichTextAnchorLink struct { + // Type of the rich text, always “anchor_link” + Type RichTextType `json:"type"` + // The link text + Text RichText `json:"text"` + // The name of the anchor. If the name is empty, then the link brings back to the top of the message. + AnchorName string `json:"anchor_name"` +} + +// MarshalJSON encodes RichTextAnchorLink with the discriminator field +// "type" forced to "anchor_link". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextAnchorLink) MarshalJSON() ([]byte, error) { + type alias RichTextAnchorLink + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "anchor_link", + alias: (*alias)(v), + }) +} + +// A reference. +type RichTextReference struct { + // Type of the rich text, always “reference” + Type RichTextType `json:"type"` + // Text of the reference + Text RichText `json:"text"` + // The name of the reference + Name string `json:"name"` +} + +// MarshalJSON encodes RichTextReference with the discriminator field +// "type" forced to "reference". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextReference) MarshalJSON() ([]byte, error) { + type alias RichTextReference + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "reference", + alias: (*alias)(v), + }) +} + +// A link to a reference. +type RichTextReferenceLink struct { + // Type of the rich text, always “reference_link” + Type RichTextType `json:"type"` + // The link text + Text RichText `json:"text"` + // The name of the reference + ReferenceName string `json:"reference_name"` +} + +// MarshalJSON encodes RichTextReferenceLink with the discriminator field +// "type" forced to "reference_link". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichTextReferenceLink) MarshalJSON() ([]byte, error) { + type alias RichTextReferenceLink + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "reference_link", + alias: (*alias)(v), + }) +} + +// Caption of a rich formatted block. +type RichBlockCaption struct { + // Block caption + Text RichText `json:"text"` + // Optional. Block credit which corresponds to the HTML tag + Credit RichText `json:"credit,omitempty"` +} + +// Cell in a table. +type RichBlockTableCell struct { + // Optional. Text in the cell. If omitted, then the cell is invisible. + Text RichText `json:"text,omitempty"` + // Optional. True, if the cell is a header cell + IsHeader *bool `json:"is_header,omitempty"` + // Optional. The number of columns the cell spans if it is bigger than 1 + Colspan *int64 `json:"colspan,omitempty"` + // Optional. The number of rows the cell spans if it is bigger than 1 + Rowspan *int64 `json:"rowspan,omitempty"` + // Horizontal cell content alignment. Currently, must be one of “left”, “center”, or “right”. + Align RichBlockTableCellAlign `json:"align"` + // Vertical cell content alignment. Currently, must be one of “top”, “middle”, or “bottom”. + Valign RichBlockTableCellValign `json:"valign"` +} + +// An item of a list. +type RichBlockListItem struct { + // Label of the item + Label string `json:"label"` + // The content of the item + Blocks []RichBlock `json:"blocks"` + // Optional. True, if the item has a checkbox + HasCheckbox *bool `json:"has_checkbox,omitempty"` + // Optional. True, if the item has a checked checkbox + IsChecked *bool `json:"is_checked,omitempty"` + // Optional. For ordered lists, the numeric value of the item label + Value *int64 `json:"value,omitempty"` + // Optional. For ordered lists, the type of the item label; must be one of “a” for lowercase letters, “A” for uppercase letters, “i” for lowercase Roman numerals, “I” for uppercase Roman numerals, or “1” for decimal numbers + Type RichBlockListItemType `json:"type,omitempty"` +} + +// RichBlock is a union type. The following concrete variants implement +// it: +// - RichBlockParagraph +// - RichBlockSectionHeading +// - RichBlockPreformatted +// - RichBlockFooter +// - RichBlockDivider +// - RichBlockMathematicalExpression +// - RichBlockAnchor +// - RichBlockList +// - RichBlockBlockQuotation +// - RichBlockPullQuotation +// - RichBlockCollage +// - RichBlockSlideshow +// - RichBlockTable +// - RichBlockDetails +// - RichBlockMap +// - RichBlockAnimation +// - RichBlockAudio +// - RichBlockPhoto +// - RichBlockVideo +// - RichBlockVoiceNote +// - RichBlockThinking +// +// This object represents a block in a rich formatted message. Currently, it can be any of the following types: +type RichBlock interface{ isRichBlock() } + +// isRichBlock is the marker method that makes RichBlockParagraph implement RichBlock. +func (*RichBlockParagraph) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockSectionHeading implement RichBlock. +func (*RichBlockSectionHeading) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockPreformatted implement RichBlock. +func (*RichBlockPreformatted) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockFooter implement RichBlock. +func (*RichBlockFooter) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockDivider implement RichBlock. +func (*RichBlockDivider) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockMathematicalExpression implement RichBlock. +func (*RichBlockMathematicalExpression) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockAnchor implement RichBlock. +func (*RichBlockAnchor) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockList implement RichBlock. +func (*RichBlockList) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockBlockQuotation implement RichBlock. +func (*RichBlockBlockQuotation) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockPullQuotation implement RichBlock. +func (*RichBlockPullQuotation) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockCollage implement RichBlock. +func (*RichBlockCollage) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockSlideshow implement RichBlock. +func (*RichBlockSlideshow) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockTable implement RichBlock. +func (*RichBlockTable) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockDetails implement RichBlock. +func (*RichBlockDetails) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockMap implement RichBlock. +func (*RichBlockMap) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockAnimation implement RichBlock. +func (*RichBlockAnimation) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockAudio implement RichBlock. +func (*RichBlockAudio) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockPhoto implement RichBlock. +func (*RichBlockPhoto) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockVideo implement RichBlock. +func (*RichBlockVideo) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockVoiceNote implement RichBlock. +func (*RichBlockVoiceNote) isRichBlock() {} + +// isRichBlock is the marker method that makes RichBlockThinking implement RichBlock. +func (*RichBlockThinking) isRichBlock() {} + +// A text paragraph, corresponding to the HTML tag

. +type RichBlockParagraph struct { + // Type of the block, always “paragraph” + Type RichBlockType `json:"type"` + // Text of the block + Text RichText `json:"text"` +} + +// MarshalJSON encodes RichBlockParagraph with the discriminator field +// "type" forced to "paragraph". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichBlockParagraph) MarshalJSON() ([]byte, error) { + type alias RichBlockParagraph + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "paragraph", + alias: (*alias)(v), + }) +} + +// A section heading, corresponding to the HTML tags

,

,

,

,

, or
. +type RichBlockSectionHeading struct { + // Type of the block, always “heading” + Type RichBlockType `json:"type"` + // Text of the block + Text RichText `json:"text"` + // Relative size of the text font; 1-6, 1 is the largest, 6 is the smallest + Size int64 `json:"size"` +} + +// MarshalJSON encodes RichBlockSectionHeading with the discriminator field +// "type" forced to "heading". +// The hardcoded value frees callers from setting Type by hand — +// any user-supplied value on the struct literal is overridden so a typo +// can't slip through to Telegram. +func (v *RichBlockSectionHeading) MarshalJSON() ([]byte, error) { + type alias RichBlockSectionHeading + return json.Marshal(&struct { + Type string `json:"type"` + *alias + }{ + Type: "heading", + alias: (*alias)(v), + }) +} + +// A preformatted text block, corresponding to the nested HTML tags
 and .
+type RichBlockPreformatted struct {
+	// Type of the block, always “pre”
+	Type RichBlockType `json:"type"`
+	// Text of the block
+	Text RichText `json:"text"`
+	// Optional. The programming language of the text
+	Language string `json:"language,omitempty"`
+}
+
+// MarshalJSON encodes RichBlockPreformatted with the discriminator field
+// "type" forced to "pre".
+// The hardcoded value frees callers from setting Type by hand —
+// any user-supplied value on the struct literal is overridden so a typo
+// can't slip through to Telegram.
+func (v *RichBlockPreformatted) MarshalJSON() ([]byte, error) {
+	type alias RichBlockPreformatted
+	return json.Marshal(&struct {
+		Type string `json:"type"`
+		*alias
+	}{
+		Type:  "pre",
+		alias: (*alias)(v),
+	})
+}
+
+// A footer, corresponding to the HTML tag