Skip to content

Commit 24c36eb

Browse files
authored
🛠️ fix: models.InputSticker model handling/usage (#201)
* fix: models.InputSticker model processing * fix test, readme and example
1 parent 9f7469a commit 24c36eb

File tree

6 files changed

+207
-5
lines changed

6 files changed

+207
-5
lines changed

README.md

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,47 @@ bot.SendMediaGroup(ctx, params)
321321

322322
[Demo in examples](examples/send_media_group/main.go)
323323

324+
## InputSticker
325+
326+
For `CreateNewStickerSet` method you can send sticker by file path or file contents.
327+
328+
[Official documentation InputSticker]((https://core.telegram.org/bots/api#inputsticker)
329+
330+
> field `sticker`: The added sticker. Pass a file_id as a String to send a file that already exists on the Telegram servers, pass an HTTP URL as a String for Telegram to get a file from the Internet, or pass “attach://<file_attach_name>” to upload a new file using multipart/form-data under <file_attach_name> name. Animated and video stickers can't be uploaded via HTTP URL.
331+
332+
If you want to use `attach://` format, you should to define `StickerAttachment` field with file content reader.
333+
334+
```go
335+
fileContent, _ := os.ReadFile("/path/to/telegram.png")
336+
337+
inputSticker1 := models.InputSticker{
338+
Sticker: "https://github.com/go-telegram/bot/blob/main/examples/create_new_sticker_set/images/telegram.png?raw=true",
339+
Format: "static",
340+
EmojiList: []string{"1️⃣"},
341+
}
342+
343+
inputSticker2 := models.InputSticker{
344+
Sticker: "attach://telegram.png",
345+
Format: "static",
346+
EmojiList: []string{"2️⃣"},
347+
StickerAttachment: bytes.NewReader(fileContent),
348+
}
349+
350+
params := &bot.CreateNewStickerSetParams{
351+
UserID: update.Message.Chat.ID,
352+
Name: fmt.Sprintf("Example%d_by_%s", time.Now().Unix(), botUsername),
353+
Title: "Example sticker set",
354+
Stickers: []models.InputSticker{
355+
inputSticker1,
356+
inputSticker2,
357+
},
358+
}
359+
360+
b.CreateNewStickerSet(ctx, params)
361+
```
362+
363+
[Demo in examples](examples/create_new_sticker_set/main.go)
364+
324365
## Helpers
325366

326367
### `EscapeMarkdown(s string) string`

build_request_form.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,8 @@ func buildRequestForm(form *multipart.Writer, params any) (int, error) {
8484
err = addFormFieldInputMediaSlice(form, fieldName, ss)
8585
case []models.InlineQueryResult:
8686
err = addFormFieldInlineQueryResultSlice(form, fieldName, vv)
87+
case []models.InputSticker:
88+
err = addFormFieldInputStickerSlice(form, fieldName, vv)
8789
default:
8890
err = addFormFieldDefault(form, fieldName, v.Field(i).Interface())
8991
}
@@ -187,6 +189,35 @@ func addFormFieldInlineQueryResultSlice(form *multipart.Writer, fieldName string
187189
return errCopy
188190
}
189191

192+
func addFormFieldInputStickerSlice(form *multipart.Writer, fieldName string, value []models.InputSticker) error {
193+
var lines []string
194+
for _, sticker := range value {
195+
if strings.HasPrefix(sticker.Sticker, "attach://") {
196+
filename := strings.TrimPrefix(sticker.Sticker, "attach://")
197+
attachmentField, errCreateAttachmentField := form.CreateFormFile(filename, filename)
198+
if errCreateAttachmentField != nil {
199+
return errCreateAttachmentField
200+
}
201+
_, errCopy := io.Copy(attachmentField, sticker.StickerAttachment)
202+
if errCopy != nil {
203+
return errCopy
204+
}
205+
}
206+
line, errEncode := json.Marshal(sticker)
207+
if errEncode != nil {
208+
return errEncode
209+
}
210+
lines = append(lines, string(line))
211+
}
212+
213+
w, errCreateField := form.CreateFormField(fieldName)
214+
if errCreateField != nil {
215+
return errCreateField
216+
}
217+
_, errCopy := io.Copy(w, strings.NewReader("["+strings.Join(lines, ",")+"]"))
218+
return errCopy
219+
}
220+
190221
func addFormFieldDefault(form *multipart.Writer, fieldName string, value any) error {
191222
d, errMarshal := json.Marshal(value)
192223
if errMarshal != nil {

build_request_form_test.go

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ func Test_buildRequestForm(t *testing.T) {
2929
DefaultInt int `json:"default_int"`
3030
InputMediaInterface models.InputMedia `json:"input_media_interface"`
3131
InlineQueryResultInterface models.InlineQueryResult `json:"inline_query_result_interface"`
32+
InputStickerSlice []models.InputSticker `json:"input_sticker_slice"`
3233
NoJSONTag1 string
3334
NoJSONTag2 string `json:"-"`
3435
OmitEmptyString string `json:"omit_empty_string,omitempty"`
@@ -46,9 +47,22 @@ func Test_buildRequestForm(t *testing.T) {
4647
DefaultInt: 42,
4748
InputMediaInterface: &models.InputMediaPhoto{Media: "foo", Caption: "bar", ParseMode: "baz"},
4849
InlineQueryResultInterface: &models.InlineQueryResultArticle{Title: "foo", Description: "bar", InputMessageContent: &models.InputTextMessageContent{MessageText: "foo"}},
49-
NoJSONTag1: "foo",
50-
NoJSONTag2: "bar",
51-
OmitEmptyString: "",
50+
InputStickerSlice: []models.InputSticker{
51+
{
52+
Sticker: "attach://sticker.png",
53+
Format: "foo",
54+
EmojiList: []string{"bar"},
55+
StickerAttachment: strings.NewReader("sticker file"),
56+
},
57+
{
58+
Sticker: "foo",
59+
Format: "bar",
60+
EmojiList: []string{"baz"},
61+
},
62+
},
63+
NoJSONTag1: "foo",
64+
NoJSONTag2: "bar",
65+
OmitEmptyString: "",
5266
}
5367

5468
buf := bytes.NewBuffer(nil)
@@ -102,8 +116,17 @@ Content-Disposition: form-data; name="input_media_interface"
102116
Content-Disposition: form-data; name="inline_query_result_interface"
103117
104118
{"type":"article","id":"","title":"foo","input_message_content":{"message_text":"foo"},"description":"bar"}
119+
--XXX
120+
Content-Disposition: form-data; name="sticker.png"; filename="sticker.png"
121+
Content-Type: application/octet-stream
122+
123+
sticker file
124+
--XXX
125+
Content-Disposition: form-data; name="input_sticker_slice"
126+
127+
[{"sticker":"attach://sticker.png","format":"foo","emoji_list":["bar"]},{"sticker":"foo","format":"bar","emoji_list":["baz"]}]
105128
--XXX--
106129
`
107-
assertEqualInt(t, fieldsCount, 6)
130+
assertEqualInt(t, fieldsCount, 7)
108131
assertFormData(t, buf.String(), expect)
109132
}
23.1 KB
Loading
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package main
2+
3+
import (
4+
"bytes"
5+
"context"
6+
"embed"
7+
"fmt"
8+
"os"
9+
"os/signal"
10+
"time"
11+
12+
"github.com/go-telegram/bot"
13+
"github.com/go-telegram/bot/models"
14+
)
15+
16+
// Send any text message to the bot after the bot has been started
17+
18+
func main() {
19+
ctx, cancel := signal.NotifyContext(context.Background(), os.Interrupt)
20+
defer cancel()
21+
22+
opts := []bot.Option{
23+
bot.WithDefaultHandler(handler),
24+
bot.WithSkipGetMe(),
25+
}
26+
27+
b, err := bot.New(os.Getenv("EXAMPLE_TELEGRAM_BOT_TOKEN"), opts...)
28+
if nil != err {
29+
// panics for the sake of simplicity.
30+
// you should handle this error properly in your code.
31+
panic(err)
32+
}
33+
34+
user, err := b.GetMe(ctx)
35+
if nil != err {
36+
// panics for the sake of simplicity.
37+
// you should handle this error properly in your code.
38+
panic(err)
39+
}
40+
botUsername = user.Username
41+
42+
b.Start(ctx)
43+
}
44+
45+
//go:embed images
46+
var images embed.FS
47+
var botUsername string
48+
49+
func handler(ctx context.Context, b *bot.Bot, update *models.Update) {
50+
fileContent, _ := images.ReadFile("images/telegram.png")
51+
52+
inputSticker1 := models.InputSticker{
53+
Sticker: "https://github.com/go-telegram/bot/blob/main/examples/create_new_sticker_set/images/telegram.png?raw=true",
54+
Format: "static",
55+
EmojiList: []string{"1️⃣"},
56+
}
57+
58+
inputSticker2 := models.InputSticker{
59+
Sticker: "attach://telegram.png",
60+
Format: "static",
61+
EmojiList: []string{"2️⃣"},
62+
StickerAttachment: bytes.NewReader(fileContent),
63+
}
64+
65+
stickerSetName := fmt.Sprintf("Example%d_by_%s", time.Now().Unix(), botUsername)
66+
params := &bot.CreateNewStickerSetParams{
67+
UserID: update.Message.Chat.ID,
68+
Name: stickerSetName,
69+
Title: "Example sticker set",
70+
Stickers: []models.InputSticker{
71+
inputSticker1,
72+
inputSticker2,
73+
},
74+
}
75+
76+
_, err := b.CreateNewStickerSet(ctx, params)
77+
if nil != err {
78+
// panics for the sake of simplicity.
79+
// you should handle this error properly in your code.
80+
panic(err)
81+
}
82+
83+
stickerSet, err := b.GetStickerSet(ctx, &bot.GetStickerSetParams{Name: stickerSetName})
84+
if err != nil {
85+
// panics for the sake of simplicity.
86+
// you should handle this error properly in your code.
87+
panic(err)
88+
}
89+
_, err = b.SendSticker(
90+
ctx,
91+
&bot.SendStickerParams{
92+
ChatID: update.Message.Chat.ID,
93+
Sticker: &models.InputFileString{
94+
Data: stickerSet.Stickers[0].FileID,
95+
},
96+
},
97+
)
98+
if err != nil {
99+
// panics for the sake of simplicity.
100+
// you should handle this error properly in your code.
101+
panic(err)
102+
}
103+
}

models/sticker.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package models
22

3+
import "io"
4+
35
// MaskPosition https://core.telegram.org/bots/api#maskposition
46
type MaskPosition struct {
57
Point string `json:"point"`
@@ -29,9 +31,11 @@ type Sticker struct {
2931

3032
// InputSticker https://core.telegram.org/bots/api#inputsticker
3133
type InputSticker struct {
32-
Sticker InputFile `json:"sticker"`
34+
Sticker string `json:"sticker"`
3335
Format string `json:"format"`
3436
EmojiList []string `json:"emoji_list"`
3537
MaskPosition *MaskPosition `json:"mask_position,omitempty"`
3638
Keywords []string `json:"keywords,omitempty"`
39+
40+
StickerAttachment io.Reader `json:"-"`
3741
}

0 commit comments

Comments
 (0)