Skip to content

Commit 8da2099

Browse files
committed
feat: DeleteMessageReaction and DeleteAllMessageReactions
Admin removal of a sender's reactions: messages.deleteParticipantReaction (single message) and messages.deleteParticipantReactions (whole chat). sender is a ChatID resolving to the user or chat whose reactions are removed. Mapping confirmed against the telegram-bot-api 10.1 reference. Hermetic tests; lint clean.
1 parent 8fec0a2 commit 8da2099

2 files changed

Lines changed: 88 additions & 0 deletions

File tree

reactions.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,3 +77,53 @@ func (b *Bot) SetMessageReaction(ctx context.Context, chat ChatID, messageID int
7777

7878
return nil
7979
}
80+
81+
// DeleteMessageReaction removes all reactions left by the given sender on a
82+
// single message. The bot must be an administrator with the can_delete_messages
83+
// right. sender identifies the user or chat whose reactions are removed.
84+
func (b *Bot) DeleteMessageReaction(ctx context.Context, chat ChatID, messageID int, sender ChatID) error {
85+
peer, err := b.resolveInputPeer(ctx, chat)
86+
if err != nil {
87+
return err
88+
}
89+
90+
participant, err := b.resolveInputPeer(ctx, sender)
91+
if err != nil {
92+
return err
93+
}
94+
95+
if _, err := b.raw.MessagesDeleteParticipantReaction(ctx, &tg.MessagesDeleteParticipantReactionRequest{
96+
Peer: peer,
97+
MsgID: messageID,
98+
Participant: participant,
99+
}); err != nil {
100+
return asAPIError(err)
101+
}
102+
103+
return nil
104+
}
105+
106+
// DeleteAllMessageReactions removes all reactions left by the given sender across
107+
// every message in a chat. The bot must be an administrator with the
108+
// can_delete_messages right. sender identifies the user or chat whose reactions
109+
// are removed.
110+
func (b *Bot) DeleteAllMessageReactions(ctx context.Context, chat, sender ChatID) error {
111+
peer, err := b.resolveInputPeer(ctx, chat)
112+
if err != nil {
113+
return err
114+
}
115+
116+
participant, err := b.resolveInputPeer(ctx, sender)
117+
if err != nil {
118+
return err
119+
}
120+
121+
if _, err := b.raw.MessagesDeleteParticipantReactions(ctx, &tg.MessagesDeleteParticipantReactionsRequest{
122+
Peer: peer,
123+
Participant: participant,
124+
}); err != nil {
125+
return asAPIError(err)
126+
}
127+
128+
return nil
129+
}

reactions_test.go

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,44 @@ func TestReactionToTgCustomEmoji(t *testing.T) {
7070
}
7171
}
7272

73+
func TestDeleteMessageReaction(t *testing.T) {
74+
inv := newMockInvoker()
75+
inv.reply(tg.MessagesDeleteParticipantReactionRequestTypeID, okUpdates())
76+
77+
if err := newMockBot(inv).DeleteMessageReaction(context.Background(), tdlibChannel(50), 42, userRef(60, 1)); err != nil {
78+
t.Fatalf("DeleteMessageReaction: %v", err)
79+
}
80+
81+
var req tg.MessagesDeleteParticipantReactionRequest
82+
83+
inv.decode(t, tg.MessagesDeleteParticipantReactionRequestTypeID, &req)
84+
85+
if req.MsgID != 42 {
86+
t.Fatalf("msg id = %d", req.MsgID)
87+
}
88+
89+
if _, ok := req.Participant.(*tg.InputPeerUser); !ok {
90+
t.Fatalf("participant = %#v, want user", req.Participant)
91+
}
92+
}
93+
94+
func TestDeleteAllMessageReactions(t *testing.T) {
95+
inv := newMockInvoker()
96+
inv.reply(tg.MessagesDeleteParticipantReactionsRequestTypeID, &tg.BoolTrue{})
97+
98+
if err := newMockBot(inv).DeleteAllMessageReactions(context.Background(), tdlibChannel(50), userRef(60, 1)); err != nil {
99+
t.Fatalf("DeleteAllMessageReactions: %v", err)
100+
}
101+
102+
var req tg.MessagesDeleteParticipantReactionsRequest
103+
104+
inv.decode(t, tg.MessagesDeleteParticipantReactionsRequestTypeID, &req)
105+
106+
if _, ok := req.Participant.(*tg.InputPeerUser); !ok {
107+
t.Fatalf("participant = %#v, want user", req.Participant)
108+
}
109+
}
110+
73111
func TestChatJoinRequests(t *testing.T) {
74112
for _, c := range []struct {
75113
name string

0 commit comments

Comments
 (0)