From 8984ecd9d43eed551ea3b9c9f9201c9bb8f946bd Mon Sep 17 00:00:00 2001 From: Andrew Privalov Date: Thu, 18 Jul 2024 17:37:31 +0300 Subject: [PATCH] V7.6 (#102) * add models.ParseModeMarkdownV1 const * fix typo in readme * add method SendPaidMedia * add field PaidMedia * add InvoicePayload to TransactionPartnerUser * add PaidMedia * remove comments from example * add refunded_payment * changelog, readme --- CHANGELOG.md | 5 + README.md | 4 +- build_request_form.go | 28 +++- examples/send_paid_media/images/facebook.png | Bin 0 -> 13179 bytes examples/send_paid_media/images/youtube.png | Bin 0 -> 13072 bytes examples/send_paid_media/main.go | 75 ++++++++++ methods.go | 7 + methods_params.go | 15 ++ models/chat.go | 1 + models/message.go | 2 + models/paid.go | 150 +++++++++++++++++++ models/paid_test.go | 90 +++++++++++ models/parse_mode.go | 5 +- models/reply.go | 1 + models/star.go | 10 +- models/successful_payment.go | 9 ++ 16 files changed, 390 insertions(+), 12 deletions(-) create mode 100644 examples/send_paid_media/images/facebook.png create mode 100644 examples/send_paid_media/images/youtube.png create mode 100644 examples/send_paid_media/main.go create mode 100644 models/paid.go create mode 100644 models/paid_test.go diff --git a/CHANGELOG.md b/CHANGELOG.md index b2c2411..66b62ec 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog +## v1.6.0 (2024-07-18) + +- support API v7.6, 7.7 +- add const `models.ParseModeMarkdownV1` + ## v1.5.0 (2024-06-24) - support API v7.5 diff --git a/README.md b/README.md index 2f623a6..49aed32 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ > [Telegram Group](https://t.me/gotelegrambotui) -> Supports Bot API version: [7.5](https://core.telegram.org/bots/api#june-18-2024) from June 18, 2024 +> Supports Bot API version: [7.7](https://core.telegram.org/bots/api#july-7-2024) from July 7, 2024 It's a Go zero-dependencies telegram bot framework @@ -343,7 +343,7 @@ b.SendPoll(ctx, p) Return file download link after call method `GetFile` -See [documentation(https://core.telegram.org/bots/api#getfile) +See [documentation](https://core.telegram.org/bots/api#getfile) ## Errors diff --git a/build_request_form.go b/build_request_form.go index 62c7b38..d6fd438 100644 --- a/build_request_form.go +++ b/build_request_form.go @@ -11,12 +11,18 @@ import ( "github.com/go-telegram/bot/models" ) +type inputMedia interface { + MarshalInputMedia() ([]byte, error) + Attachment() io.Reader + GetMedia() string +} + type customMarshal interface { MarshalCustom() ([]byte, error) } var customMarshalInterface = reflect.TypeOf(new(customMarshal)).Elem() -var inputMediaInterface = reflect.TypeOf(new(models.InputMedia)).Elem() +var inputMediaInterface = reflect.TypeOf(new(inputMedia)).Elem() // buildRequestForm builds form-data for request // if params contains InputFile of type InputFileUpload, it will be added to form-data ad upload file. Also, for InputMedia attachments @@ -46,7 +52,7 @@ func buildRequestForm(form *multipart.Writer, params any) (int, error) { continue } if v.Field(i).Type().Implements(inputMediaInterface) { - err := addFormFieldInputMedia(form, fieldName, v.Field(i).Interface().(models.InputMedia)) + err := addFormFieldInputMedia(form, fieldName, v.Field(i).Interface().(inputMedia)) if err != nil { return 0, err } @@ -64,7 +70,17 @@ func buildRequestForm(form *multipart.Writer, params any) (int, error) { case *models.InputFileString: err = addFormFieldString(form, fieldName, vv.Data) case []models.InputMedia: - err = addFormFieldInputMediaSlice(form, fieldName, vv) + var ss []inputMedia + for _, m := range vv { + ss = append(ss, m) + } + err = addFormFieldInputMediaSlice(form, fieldName, ss) + case []models.InputPaidMedia: + var ss []inputMedia + for _, m := range vv { + ss = append(ss, m) + } + err = addFormFieldInputMediaSlice(form, fieldName, ss) case []models.InlineQueryResult: err = addFormFieldInlineQueryResultSlice(form, fieldName, vv) default: @@ -89,7 +105,7 @@ func addFormFieldInputFileUpload(form *multipart.Writer, fieldName string, value return errCopy } -func addFormFieldInputMediaItem(form *multipart.Writer, value models.InputMedia) ([]byte, error) { +func addFormFieldInputMediaItem(form *multipart.Writer, value inputMedia) ([]byte, error) { if strings.HasPrefix(value.GetMedia(), "attach://") { filename := strings.TrimPrefix(value.GetMedia(), "attach://") mediaAttachmentField, errCreateMediaAttachmentField := form.CreateFormFile(filename, filename) @@ -117,7 +133,7 @@ func addFormFieldCustomMarshal(form *multipart.Writer, fieldName string, value c return errCopy } -func addFormFieldInputMedia(form *multipart.Writer, fieldName string, value models.InputMedia) error { +func addFormFieldInputMedia(form *multipart.Writer, fieldName string, value inputMedia) error { line, err := addFormFieldInputMediaItem(form, value) if err != nil { return err @@ -131,7 +147,7 @@ func addFormFieldInputMedia(form *multipart.Writer, fieldName string, value mode return errCopy } -func addFormFieldInputMediaSlice(form *multipart.Writer, fieldName string, value []models.InputMedia) error { +func addFormFieldInputMediaSlice(form *multipart.Writer, fieldName string, value []inputMedia) error { var lines []string for _, media := range value { line, err := addFormFieldInputMediaItem(form, media) diff --git a/examples/send_paid_media/images/facebook.png b/examples/send_paid_media/images/facebook.png new file mode 100644 index 0000000000000000000000000000000000000000..92a9a623262220d90d0977d4887e3d4d59c07c94 GIT binary patch literal 13179 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 I)v$T|e;Md2Pyhe` literal 0 HcmV?d00001 diff --git a/examples/send_paid_media/images/youtube.png b/examples/send_paid_media/images/youtube.png new file mode 100644 index 0000000000000000000000000000000000000000..ad9fc5b7ed9131220aacbd5e2c3ab7c02cd60be6 GIT binary patch literal 13072 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 literal 0 HcmV?d00001 diff --git a/examples/send_paid_media/main.go b/examples/send_paid_media/main.go new file mode 100644 index 0000000..a2d7058 --- /dev/null +++ b/examples/send_paid_media/main.go @@ -0,0 +1,75 @@ +package main + +import ( + "bytes" + "context" + "embed" + "fmt" + "os" + "os/signal" + + "github.com/go-telegram/bot" + "github.com/go-telegram/bot/models" +) + +func main() { + ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt) + defer cancel() + + opts := []bot.Option{ + bot.WithDefaultHandler(handler), + } + + b, err := bot.New(os.Getenv("EXAMPLE_TELEGRAM_BOT_TOKEN"), opts...) + if nil != err { + // panics for the sake of simplicity. + // you should handle this error properly in your code. + panic(err) + } + + b.Start(ctx) +} + +//go:embed images +var images embed.FS + +func handler(ctx context.Context, b *bot.Bot, update *models.Update) { + fileDataFacebook, _ := images.ReadFile("images/facebook.png") + fileDataYoutube, _ := images.ReadFile("images/youtube.png") + + if update.ChannelPost == nil { + fmt.Printf("expect channel post\n") + return + } + + chatID := update.ChannelPost.Chat.ID + + media1 := &models.InputPaidMediaPhoto{ + Media: "https://telegram.org/img/t_logo.png", + } + + media2 := &models.InputPaidMediaPhoto{ + Media: "attach://facebook.png", + MediaAttachment: bytes.NewReader(fileDataFacebook), + } + + media3 := &models.InputPaidMediaPhoto{ + Media: "attach://youtube.png", + MediaAttachment: bytes.NewReader(fileDataYoutube), + } + + params := &bot.SendPaidMediaParams{ + ChatID: chatID, + StarCount: 10, + Media: []models.InputPaidMedia{ + media1, + media2, + media3, + }, + } + + _, err := b.SendPaidMedia(ctx, params) + if err != nil { + fmt.Printf("%+v\n", err) + } +} diff --git a/methods.go b/methods.go index 541de4c..55277b3 100644 --- a/methods.go +++ b/methods.go @@ -132,6 +132,13 @@ func (b *Bot) SendVideoNote(ctx context.Context, params *SendVideoNoteParams) (* return result, err } +// SendPaidMedia https://core.telegram.org/bots/api#sendpaidmedia +func (b *Bot) SendPaidMedia(ctx context.Context, params *SendPaidMediaParams) (*models.Message, error) { + var result models.Message + err := b.rawRequest(ctx, "sendPaidMedia", params, &result) + return &result, err +} + // SendMediaGroup https://core.telegram.org/bots/api#sendmediagroup func (b *Bot) SendMediaGroup(ctx context.Context, params *SendMediaGroupParams) ([]*models.Message, error) { var result []*models.Message diff --git a/methods_params.go b/methods_params.go index da2fbea..d160495 100644 --- a/methods_params.go +++ b/methods_params.go @@ -215,6 +215,21 @@ type SendVideoNoteParams struct { ReplyMarkup models.ReplyMarkup `json:"reply_markup,omitempty"` } +// SendPaidMediaParams https://core.telegram.org/bots/api#sendpaidmedia +type SendPaidMediaParams struct { + ChatID any `json:"chat_id"` + StarCount int `json:"star_count"` + Media []models.InputPaidMedia `json:"media"` + Caption string `json:"caption,omitempty"` + ParseMode models.ParseMode `json:"parse_mode,omitempty"` + CaptionEntities []models.MessageEntity `json:"caption_entities,omitempty"` + ShowCaptionAboveMedia bool `json:"show_caption_above_media,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"` +} + // SendMediaGroupParams https://core.telegram.org/bots/api#sendmediagroup type SendMediaGroupParams struct { BusinessConnectionID string `json:"business_connection_id,omitempty"` diff --git a/models/chat.go b/models/chat.go index 029ef5a..4bb6208 100644 --- a/models/chat.go +++ b/models/chat.go @@ -124,6 +124,7 @@ type ChatFullInfo struct { InviteLink string `json:"invite_link,omitempty"` PinnedMessage *Message `json:"pinned_message,omitempty"` Permissions *ChatPermissions `json:"permissions,omitempty"` + CanSendPaidMedia bool `json:"can_send_paid_media,omitempty"` SlowModeDelay int `json:"slow_mode_delay,omitempty"` UnrestrictBoostCount int `json:"unrestrict_boost_count,omitempty"` MessageAutoDeleteTime int `json:"message_auto_delete_time,omitempty"` diff --git a/models/message.go b/models/message.go index f6fffb5..4b7294a 100644 --- a/models/message.go +++ b/models/message.go @@ -99,6 +99,7 @@ type Message struct { Animation *Animation `json:"animation,omitempty"` Audio *Audio `json:"audio,omitempty"` Document *Document `json:"document,omitempty"` + PaidMedia *PaidMediaInfo `json:"paid_media,omitempty"` Photo []PhotoSize `json:"photo,omitempty"` Sticker *Sticker `json:"sticker,omitempty"` Story *Story `json:"story,omitempty"` @@ -129,6 +130,7 @@ type Message struct { PinnedMessage MaybeInaccessibleMessage `json:"pinned_message,omitempty"` Invoice *Invoice `json:"invoice,omitempty"` SuccessfulPayment *SuccessfulPayment `json:"successful_payment,omitempty"` + RefundedPayment *RefundedPayment `json:"refunded_payment,omitempty"` UsersShared *UsersShared `json:"users_shared,omitempty"` ChatShared *ChatShared `json:"chat_shared,omitempty"` ConnectedWebsite string `json:"connected_website,omitempty"` diff --git a/models/paid.go b/models/paid.go new file mode 100644 index 0000000..e0d5c4c --- /dev/null +++ b/models/paid.go @@ -0,0 +1,150 @@ +package models + +import ( + "encoding/json" + "fmt" + "io" +) + +type InputPaidMedia interface { + inputPaidMediaTag() + + MarshalInputMedia() ([]byte, error) + Attachment() io.Reader + GetMedia() string +} + +// InputPaidMediaPhoto https://core.telegram.org/bots/api#inputpaidmediaphoto +type InputPaidMediaPhoto struct { + Media string `json:"media"` + + MediaAttachment io.Reader `json:"-"` +} + +func (m *InputPaidMediaPhoto) inputPaidMediaTag() {} + +func (m *InputPaidMediaPhoto) Attachment() io.Reader { + return m.MediaAttachment +} + +func (m *InputPaidMediaPhoto) GetMedia() string { + return m.Media +} + +func (m *InputPaidMediaPhoto) MarshalInputMedia() ([]byte, error) { + ret := struct { + Type string `json:"type"` + *InputPaidMediaPhoto + }{ + Type: "photo", + InputPaidMediaPhoto: m, + } + + return json.Marshal(&ret) +} + +// InputPaidMediaVideo https://core.telegram.org/bots/api#inputpaidmediavideo +type InputPaidMediaVideo struct { + Media string `json:"media"` + Thumbnail InputFile `json:"thumbnail,omitempty"` + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + Duration int `json:"duration,omitempty"` + SupportsStreaming bool `json:"supports_streaming,omitempty"` + + MediaAttachment io.Reader `json:"-"` +} + +func (m *InputPaidMediaVideo) inputPaidMediaTag() {} + +func (m *InputPaidMediaVideo) Attachment() io.Reader { + return m.MediaAttachment +} + +func (m *InputPaidMediaVideo) GetMedia() string { + return m.Media +} + +func (m *InputPaidMediaVideo) MarshalInputMedia() ([]byte, error) { + ret := struct { + Type string `json:"type"` + *InputPaidMediaVideo + }{ + Type: "video", + InputPaidMediaVideo: m, + } + + return json.Marshal(&ret) +} + +type PaidMediaType string + +const ( + PaidMediaTypePreview PaidMediaType = "preview" + PaidMediaTypePhoto PaidMediaType = "photo" + PaidMediaTypeVideo PaidMediaType = "video" +) + +// PaidMedia https://core.telegram.org/bots/api#paidmedia +type PaidMedia struct { + Type PaidMediaType + + Preview *PaidMediaPreview + Photo *PaidMediaPhoto + Video *PaidMediaVideo +} + +func (p *PaidMedia) UnmarshalJSON(data []byte) error { + v := struct { + Type PaidMediaType `json:"type"` + }{} + err := json.Unmarshal(data, &v) + if err != nil { + return err + } + + p.Type = v.Type + + switch v.Type { + case PaidMediaTypePreview: + p.Preview = &PaidMediaPreview{} + return json.Unmarshal(data, p.Preview) + case PaidMediaTypePhoto: + p.Photo = &PaidMediaPhoto{} + return json.Unmarshal(data, p.Photo) + case PaidMediaTypeVideo: + p.Video = &PaidMediaVideo{} + return json.Unmarshal(data, p.Video) + default: + return fmt.Errorf("unsupported PaidMedia type, %v", v.Type) + } +} + +// PaidMediaPreview https://core.telegram.org/bots/api#paidmediapreview +type PaidMediaPreview struct { + Type PaidMediaType + + Width int `json:"width,omitempty"` + Height int `json:"height,omitempty"` + Duration int `json:"duration,omitempty"` +} + +// PaidMediaPhoto https://core.telegram.org/bots/api#paidmediaphoto +type PaidMediaPhoto struct { + Type PaidMediaType + + Photo []PhotoSize `json:"photo"` +} + +// PaidMediaVideo https://core.telegram.org/bots/api#paidmediavideo +type PaidMediaVideo struct { + Type PaidMediaType + + Video Video `json:"video"` +} + +// PaidMediaInfo https://core.telegram.org/bots/api#paidmediainfo +type PaidMediaInfo struct { + StarCount int `json:"star_count"` + PaidMedia []PaidMedia `json:"paid_media"` +} diff --git a/models/paid_test.go b/models/paid_test.go new file mode 100644 index 0000000..775a2ea --- /dev/null +++ b/models/paid_test.go @@ -0,0 +1,90 @@ +package models + +import "testing" + +func TestPaidMedia_UnmarshalJSON_Preview(t *testing.T) { + src := `{"type":"preview","width":42,"height":43,"duration":44}` + + p := &PaidMedia{} + err := p.UnmarshalJSON([]byte(src)) + if err != nil { + t.Fatal(err) + } + + if p.Type != PaidMediaTypePreview { + t.Fatal("wrong type") + } + + if p.Preview == nil { + t.Fatal("Preview is nil") + } + + if p.Preview.Width != 42 { + t.Fatal("wrong width") + } + + if p.Preview.Height != 43 { + t.Fatal("wrong height") + } + + if p.Preview.Duration != 44 { + t.Fatal("wrong duration") + } +} + +func TestPaidMedia_UnmarshalJSON_Photo(t *testing.T) { + src := `{"type":"photo","photo":[{"width":42,"height":43}]}` + + p := &PaidMedia{} + err := p.UnmarshalJSON([]byte(src)) + if err != nil { + t.Fatal(err) + } + + if p.Type != PaidMediaTypePhoto { + t.Fatal("wrong type") + } + + if p.Photo == nil { + t.Fatal("Photo is nil") + } + + if len(p.Photo.Photo) != 1 { + t.Fatal("wrong photo length") + } + + if p.Photo.Photo[0].Width != 42 { + t.Fatal("wrong width") + } + if p.Photo.Photo[0].Height != 43 { + t.Fatal("wrong height") + } +} + +func TestPaidMedia_UnmarshalJSON_Video(t *testing.T) { + src := `{"type":"video","video":{"width":42,"height":43,"duration":44}}` + + p := &PaidMedia{} + err := p.UnmarshalJSON([]byte(src)) + if err != nil { + t.Fatal(err) + } + + if p.Type != PaidMediaTypeVideo { + t.Fatal("wrong type") + } + + if p.Video == nil { + t.Fatal("Video is nil") + } + + if p.Video.Video.Width != 42 { + t.Fatal("wrong width") + } + if p.Video.Video.Height != 43 { + t.Fatal("wrong height") + } + if p.Video.Video.Duration != 44 { + t.Fatal("wrong duration") + } +} diff --git a/models/parse_mode.go b/models/parse_mode.go index d444686..ddc664c 100644 --- a/models/parse_mode.go +++ b/models/parse_mode.go @@ -3,6 +3,7 @@ package models type ParseMode string const ( - ParseModeMarkdown ParseMode = "MarkdownV2" - ParseModeHTML ParseMode = "HTML" + ParseModeMarkdownV1 ParseMode = "Markdown" + ParseModeMarkdown ParseMode = "MarkdownV2" + ParseModeHTML ParseMode = "HTML" ) diff --git a/models/reply.go b/models/reply.go index 718c901..32ff250 100644 --- a/models/reply.go +++ b/models/reply.go @@ -22,6 +22,7 @@ type ExternalReplyInfo struct { Animation *Animation `json:"animation,omitempty"` Audio *Audio `json:"audio,omitempty"` Document *Document `json:"document,omitempty"` + PaidMedia *PaidMediaInfo `json:"paid_media,omitempty"` Photo []PhotoSize `json:"photo,omitempty"` Sticker *Sticker `json:"sticker,omitempty"` Story *Story `json:"story,omitempty"` diff --git a/models/star.go b/models/star.go index e557182..721eac0 100644 --- a/models/star.go +++ b/models/star.go @@ -57,8 +57,9 @@ type TransactionPartnerFragment struct { // TransactionPartnerUser https://core.telegram.org/bots/api#transactionpartneruser type TransactionPartnerUser struct { - Type TransactionPartnerType `json:"type"` - User User `json:"user"` + Type TransactionPartnerType `json:"type"` + User User `json:"user"` + InvoicePayload string `json:"invoice_payload,omitempty"` } // TransactionPartnerOther https://core.telegram.org/bots/api#transactionpartnerother @@ -140,3 +141,8 @@ type StarTransaction struct { type StarTransactions struct { Transactions []StarTransaction `json:"transactions"` } + +// TransactionPartnerTelegramAds https://core.telegram.org/bots/api#transactionpartnertelegramads +type TransactionPartnerTelegramAds struct { + Type string `json:"type"` +} diff --git a/models/successful_payment.go b/models/successful_payment.go index 73b8839..e35573f 100644 --- a/models/successful_payment.go +++ b/models/successful_payment.go @@ -10,3 +10,12 @@ type SuccessfulPayment struct { TelegramPaymentChargeID string `json:"telegram_payment_charge_id"` ProviderPaymentChargeID string `json:"provider_payment_charge_id"` } + +// RefundedPayment https://core.telegram.org/bots/api#refundedpayment +type RefundedPayment struct { + Currency string `json:"currency"` + TotalAmount int `json:"total_amount"` + InvoicePayload string `json:"invoice_payload"` + TelegramPaymentChargeID string `json:"telegram_payment_charge_id"` + ProviderPaymentChargeID string `json:"provider_payment_charge_id,omitempty"` +}