fix(dingtalk): strip leading mentions in group payloads

This commit is contained in:
Alix-007 2026-03-26 22:24:55 +08:00
parent 0775914a41
commit 8e33adcf1b
2 changed files with 46 additions and 4 deletions

View file

@ -190,8 +190,12 @@ func (c *DingTalkChannel) onChatBotMessageReceived(
peer = bus.Peer{Kind: "direct", ID: peerID} peer = bus.Peer{Kind: "direct", ID: peerID}
} else { } else {
peer = bus.Peer{Kind: "group", ID: data.ConversationId} peer = bus.Peer{Kind: "group", ID: data.ConversationId}
isMentioned := data.IsInAtList
if isMentioned {
content = stripLeadingAtMentions(content)
}
// In group chats, apply unified group trigger filtering // In group chats, apply unified group trigger filtering
respond, cleaned := c.ShouldRespondInGroup(data.IsInAtList, content) respond, cleaned := c.ShouldRespondInGroup(isMentioned, content)
if !respond { if !respond {
return nil, nil return nil, nil
} }
@ -253,3 +257,19 @@ func (c *DingTalkChannel) SendDirectReply(ctx context.Context, sessionWebhook, c
return nil return nil
} }
func stripLeadingAtMentions(content string) string {
fields := strings.Fields(content)
if len(fields) == 0 {
return ""
}
i := 0
for i < len(fields) && strings.HasPrefix(fields[i], "@") {
i++
}
if i == 0 {
return strings.TrimSpace(content)
}
return strings.Join(fields[i:], " ")
}

View file

@ -40,13 +40,13 @@ func mustReceiveInbound(t *testing.T, msgBus *bus.MessageBus) bus.InboundMessage
} }
} }
func TestOnChatBotMessageReceived_GroupMentionOnlyUsesIsInAtList(t *testing.T) { func TestOnChatBotMessageReceived_GroupMentionOnlyUsesIsInAtListAndStripsMention(t *testing.T) {
ch, msgBus := newTestDingTalkChannel(t, config.DingTalkConfig{ ch, msgBus := newTestDingTalkChannel(t, config.DingTalkConfig{
GroupTrigger: config.GroupTriggerConfig{MentionOnly: true}, GroupTrigger: config.GroupTriggerConfig{MentionOnly: true},
}) })
_, err := ch.onChatBotMessageReceived(context.Background(), &chatbot.BotCallbackDataModel{ _, err := ch.onChatBotMessageReceived(context.Background(), &chatbot.BotCallbackDataModel{
Text: chatbot.BotCallbackDataTextModel{Content: " @bot hello "}, Text: chatbot.BotCallbackDataTextModel{Content: " @bot /help "},
SenderStaffId: "staff-123", SenderStaffId: "staff-123",
SenderNick: "Alice", SenderNick: "Alice",
ConversationType: "2", ConversationType: "2",
@ -68,7 +68,7 @@ func TestOnChatBotMessageReceived_GroupMentionOnlyUsesIsInAtList(t *testing.T) {
if inbound.Peer.Kind != "group" || inbound.Peer.ID != "group-abc" { if inbound.Peer.Kind != "group" || inbound.Peer.ID != "group-abc" {
t.Fatalf("peer=%+v", inbound.Peer) t.Fatalf("peer=%+v", inbound.Peer)
} }
if inbound.Content != "@bot hello" { if inbound.Content != "/help" {
t.Fatalf("content=%q", inbound.Content) t.Fatalf("content=%q", inbound.Content)
} }
} }
@ -107,3 +107,25 @@ func TestOnChatBotMessageReceived_DirectFallbackSenderIDUsesConversationID(t *te
t.Fatal("unexpected empty chat_id webhook key") t.Fatal("unexpected empty chat_id webhook key")
} }
} }
func TestStripLeadingAtMentions(t *testing.T) {
tests := []struct {
name string
input string
wantOut string
}{
{name: "single mention and command", input: "@bot /help", wantOut: "/help"},
{name: "multiple mentions", input: "@bot @alice /new", wantOut: "/new"},
{name: "no mention", input: "/help", wantOut: "/help"},
{name: "mention only", input: "@bot", wantOut: ""},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := stripLeadingAtMentions(tt.input)
if got != tt.wantOut {
t.Fatalf("stripLeadingAtMentions(%q)=%q want=%q", tt.input, got, tt.wantOut)
}
})
}
}