Skip to content

Commit d4eed5a

Browse files
committed
feat: AnswerChatJoinRequestQuery and SendChatJoinRequestWebApp
bots.setJoinChatResults: AnswerChatJoinRequestQuery maps approve/decline/queue to JoinChatBotResult{Approved,Declined,Queued}; SendChatJoinRequestWebApp opens a Web App via JoinChatBotResultWebView. Mapping confirmed against telegram-bot-api 10.1. Hermetic tests; lint clean.
1 parent 1344f22 commit d4eed5a

2 files changed

Lines changed: 139 additions & 0 deletions

File tree

chat_join_query.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+
"strconv"
6+
7+
"github.com/gotd/td/tg"
8+
)
9+
10+
// joinRequestQueryID parses a chat_join_request_query_id into the MTProto query
11+
// id.
12+
func joinRequestQueryID(id string) (int64, error) {
13+
v, err := strconv.ParseInt(id, 10, 64)
14+
if err != nil {
15+
return 0, &Error{Code: 400, Description: "Bad Request: invalid chat_join_request_query_id"}
16+
}
17+
18+
return v, nil
19+
}
20+
21+
// AnswerChatJoinRequestQuery responds to a chat join request the bot is asked to
22+
// resolve. result must be one of "approve", "decline" or "queue" (queue defers
23+
// the decision to the chat's administrators).
24+
func (b *Bot) AnswerChatJoinRequestQuery(ctx context.Context, chatJoinRequestQueryID, result string) error {
25+
queryID, err := joinRequestQueryID(chatJoinRequestQueryID)
26+
if err != nil {
27+
return err
28+
}
29+
30+
var res tg.JoinChatBotResultClass
31+
32+
switch result {
33+
case "approve":
34+
res = &tg.JoinChatBotResultApproved{}
35+
case "decline":
36+
res = &tg.JoinChatBotResultDeclined{}
37+
case "queue":
38+
res = &tg.JoinChatBotResultQueued{}
39+
default:
40+
return &Error{Code: 400, Description: "Bad Request: result must be approve, decline or queue"}
41+
}
42+
43+
if _, err := b.raw.BotsSetJoinChatResults(ctx, &tg.BotsSetJoinChatResultsRequest{
44+
QueryID: queryID,
45+
Result: res,
46+
}); err != nil {
47+
return asAPIError(err)
48+
}
49+
50+
return nil
51+
}
52+
53+
// SendChatJoinRequestWebApp opens a Web App in response to a chat join request
54+
// the bot is asked to resolve, so the user can complete a verification flow.
55+
func (b *Bot) SendChatJoinRequestWebApp(ctx context.Context, chatJoinRequestQueryID, webAppURL string) error {
56+
queryID, err := joinRequestQueryID(chatJoinRequestQueryID)
57+
if err != nil {
58+
return err
59+
}
60+
61+
if _, err := b.raw.BotsSetJoinChatResults(ctx, &tg.BotsSetJoinChatResultsRequest{
62+
QueryID: queryID,
63+
Result: &tg.JoinChatBotResultWebView{URL: webAppURL},
64+
}); err != nil {
65+
return asAPIError(err)
66+
}
67+
68+
return nil
69+
}

chat_join_query_test.go

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package botapi
2+
3+
import (
4+
"context"
5+
"testing"
6+
7+
"github.com/gotd/td/tg"
8+
)
9+
10+
func TestAnswerChatJoinRequestQuery(t *testing.T) {
11+
for _, c := range []struct {
12+
result string
13+
want tg.JoinChatBotResultClass
14+
}{
15+
{"approve", &tg.JoinChatBotResultApproved{}},
16+
{"decline", &tg.JoinChatBotResultDeclined{}},
17+
{"queue", &tg.JoinChatBotResultQueued{}},
18+
} {
19+
t.Run(c.result, func(t *testing.T) {
20+
inv := newMockInvoker()
21+
inv.reply(tg.BotsSetJoinChatResultsRequestTypeID, &tg.BoolTrue{})
22+
23+
if err := newMockBot(inv).AnswerChatJoinRequestQuery(context.Background(), "123", c.result); err != nil {
24+
t.Fatalf("AnswerChatJoinRequestQuery: %v", err)
25+
}
26+
27+
var req tg.BotsSetJoinChatResultsRequest
28+
29+
inv.decode(t, tg.BotsSetJoinChatResultsRequestTypeID, &req)
30+
31+
if req.QueryID != 123 {
32+
t.Fatalf("query id = %d", req.QueryID)
33+
}
34+
35+
if req.Result.TypeID() != c.want.TypeID() {
36+
t.Fatalf("result = %#v, want %#v", req.Result, c.want)
37+
}
38+
})
39+
}
40+
}
41+
42+
func TestAnswerChatJoinRequestQueryInvalid(t *testing.T) {
43+
inv := newMockInvoker()
44+
45+
if err := newMockBot(inv).AnswerChatJoinRequestQuery(context.Background(), "123", "maybe"); err == nil {
46+
t.Fatal("expected error for invalid result")
47+
}
48+
49+
if err := newMockBot(inv).AnswerChatJoinRequestQuery(context.Background(), "notanumber", "approve"); err == nil {
50+
t.Fatal("expected error for invalid query id")
51+
}
52+
}
53+
54+
func TestSendChatJoinRequestWebApp(t *testing.T) {
55+
inv := newMockInvoker()
56+
inv.reply(tg.BotsSetJoinChatResultsRequestTypeID, &tg.BoolTrue{})
57+
58+
if err := newMockBot(inv).SendChatJoinRequestWebApp(context.Background(), "456", "https://example.com/app"); err != nil {
59+
t.Fatalf("SendChatJoinRequestWebApp: %v", err)
60+
}
61+
62+
var req tg.BotsSetJoinChatResultsRequest
63+
64+
inv.decode(t, tg.BotsSetJoinChatResultsRequestTypeID, &req)
65+
66+
wv, ok := req.Result.(*tg.JoinChatBotResultWebView)
67+
if !ok || wv.URL != "https://example.com/app" {
68+
t.Fatalf("result = %#v", req.Result)
69+
}
70+
}

0 commit comments

Comments
 (0)