Skip to content

Commit d794f2c

Browse files
committed
feat: SendMessageDraft
messages.setTyping with a sendMessageTypingActionDraft (SendMessageTextDraftAction) carrying the draft_id and styled text, optionally scoped to a forum topic. Mapping confirmed against telegram-bot-api 10.1. sendRichMessageDraft stays deferred: it needs a tg.RichMessage PageBlock tree built from HTML/markdown, a substantial content parser TDLib runs server-side. Hermetic test; lint clean.
1 parent d4eed5a commit d794f2c

2 files changed

Lines changed: 104 additions & 0 deletions

File tree

send_draft.go

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
package botapi
2+
3+
import (
4+
"context"
5+
6+
"github.com/gotd/td/tg"
7+
)
8+
9+
// DraftOption configures SendMessageDraft.
10+
type DraftOption func(*draftConfig)
11+
12+
type draftConfig struct {
13+
parseMode ParseMode
14+
entities []MessageEntity
15+
messageThreadID int
16+
}
17+
18+
// WithDraftParseMode selects the formatting mode for the draft text.
19+
func WithDraftParseMode(mode ParseMode) DraftOption {
20+
return func(c *draftConfig) { c.parseMode = mode }
21+
}
22+
23+
// WithDraftEntities sets explicit entities for the draft text; they take
24+
// precedence over a parse mode.
25+
func WithDraftEntities(entities []MessageEntity) DraftOption {
26+
return func(c *draftConfig) { c.entities = entities }
27+
}
28+
29+
// WithDraftMessageThread targets a specific forum topic / thread.
30+
func WithDraftMessageThread(messageThreadID int) DraftOption {
31+
return func(c *draftConfig) { c.messageThreadID = messageThreadID }
32+
}
33+
34+
// SendMessageDraft broadcasts a message draft to a chat, so its members see what
35+
// the bot is preparing. draftID is a unique client-side identifier for the draft.
36+
func (b *Bot) SendMessageDraft(ctx context.Context, chat ChatID, draftID int64, text string, opts ...DraftOption) error {
37+
var cfg draftConfig
38+
39+
for _, o := range opts {
40+
o(&cfg)
41+
}
42+
43+
peer, err := b.resolveInputPeer(ctx, chat)
44+
if err != nil {
45+
return err
46+
}
47+
48+
textWithEntities, err := b.textWithEntities(ctx, text, cfg.parseMode, cfg.entities)
49+
if err != nil {
50+
return err
51+
}
52+
53+
req := &tg.MessagesSetTypingRequest{
54+
Peer: peer,
55+
Action: &tg.SendMessageTextDraftAction{
56+
RandomID: draftID,
57+
Text: textWithEntities,
58+
},
59+
}
60+
if cfg.messageThreadID != 0 {
61+
req.SetTopMsgID(cfg.messageThreadID)
62+
}
63+
64+
if _, err := b.raw.MessagesSetTyping(ctx, req); err != nil {
65+
return asAPIError(err)
66+
}
67+
68+
return nil
69+
}

send_draft_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package botapi
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/gotd/td/tg"
8+
)
9+
10+
func TestSendMessageDraft(t *testing.T) {
11+
inv := newMockInvoker()
12+
inv.reply(tg.MessagesSetTypingRequestTypeID, &tg.BoolTrue{})
13+
14+
if err := newMockBot(inv).SendMessageDraft(context.Background(), userRef(10, 20), 999, "draft text",
15+
WithDraftMessageThread(5)); err != nil {
16+
t.Fatalf("SendMessageDraft: %v", err)
17+
}
18+
19+
var req tg.MessagesSetTypingRequest
20+
21+
inv.decode(t, tg.MessagesSetTypingRequestTypeID, &req)
22+
23+
if topMsg, ok := req.GetTopMsgID(); !ok || topMsg != 5 {
24+
t.Fatalf("top msg id = %d ok=%v", topMsg, ok)
25+
}
26+
27+
action, ok := req.Action.(*tg.SendMessageTextDraftAction)
28+
if !ok {
29+
t.Fatalf("action = %#v, want text draft", req.Action)
30+
}
31+
32+
if action.RandomID != 999 || action.Text.Text != "draft text" {
33+
t.Fatalf("action = %#v", action)
34+
}
35+
}

0 commit comments

Comments
 (0)