mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-14 00:16:38 +00:00
Bitrix24 ships the quoted message inline on reply events via REPLY_MESSAGE,
but the channel parsed a non-existent REPLY_TO_MESSAGE_ID field, so the agent
never saw what a user was replying to. Recognize replies and feed their
context to the agent (Hybrid design):
- events.go: parse data[PARAMS][REPLY_MESSAGE][ID|AUTHOR_ID|MESSAGE] (form+json)
with PARAMS[REPLY_ID] fallback into EventParams.ReplyMessage; drop the dead
ReplyToMID field + bitrix_reply_to_mid meta.
- reply_context.go (new): resolveReplyContext prepends a short note and, for
media-only originals, re-injects the quoted file(s) through the same download
pipeline as a direct upload.
text quote -> sanitize BBCode + truncate, no API call.
media quote -> im.dialog.messages.get (works for TYPE=bot bots, unlike the
blocked imbot.v2.Chat.Message.get) to recover the attachment, bounded by
media_max_mb; note-only fallback on any fetch/download failure.
- handle.go: wire resolveReplyContext into message assembly (prefix + extra media).
Covers text, image, audio, file, video quotes. Non-reply events are a no-op.
Adds unit tests for parse (form+json), sanitize, file-id extraction, result
parsing, the messages.get fetch, and both resolve branches.
Co-authored-by: DangTinh311 <dangtinh31193@gmail.com>
106 lines
3.2 KiB
Go
106 lines
3.2 KiB
Go
package bitrix24
|
|
|
|
import (
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func parseForm(t *testing.T, v interface{ Encode() string }) *Event {
|
|
t.Helper()
|
|
req := httptest.NewRequest(http.MethodPost, "/bitrix24/events", strings.NewReader(v.Encode()))
|
|
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
|
|
evt, err := ParseEvent(req)
|
|
if err != nil {
|
|
t.Fatalf("ParseEvent: %v", err)
|
|
}
|
|
return evt
|
|
}
|
|
|
|
func TestParseEvent_Form_ReplyMessage_Text(t *testing.T) {
|
|
v := buildBitrixForm()
|
|
v.Set("data[PARAMS][REPLY_MESSAGE][ID]", "315900")
|
|
v.Set("data[PARAMS][REPLY_MESSAGE][AUTHOR_ID]", "62")
|
|
v.Set("data[PARAMS][REPLY_MESSAGE][MESSAGE]", "báo giá cho anh nhé")
|
|
|
|
rm := parseForm(t, v).Params.ReplyMessage
|
|
if rm == nil {
|
|
t.Fatal("ReplyMessage nil; want parsed")
|
|
}
|
|
if rm.ID != "315900" || rm.AuthorID != "62" || rm.Text != "báo giá cho anh nhé" {
|
|
t.Errorf("ReplyMessage = %+v", rm)
|
|
}
|
|
}
|
|
|
|
func TestParseEvent_Form_ReplyMessage_MediaEmptyText(t *testing.T) {
|
|
// Media-only original: ID + AUTHOR present, MESSAGE empty (no file id inline).
|
|
v := buildBitrixForm()
|
|
v.Set("data[PARAMS][REPLY_MESSAGE][ID]", "315968")
|
|
v.Set("data[PARAMS][REPLY_MESSAGE][AUTHOR_ID]", "62")
|
|
v.Set("data[PARAMS][REPLY_MESSAGE][MESSAGE]", "")
|
|
|
|
rm := parseForm(t, v).Params.ReplyMessage
|
|
if rm == nil || rm.ID != "315968" || rm.Text != "" {
|
|
t.Errorf("ReplyMessage = %+v; want ID 315968, empty text", rm)
|
|
}
|
|
}
|
|
|
|
func TestParseEvent_Form_ReplyID_Fallback(t *testing.T) {
|
|
// Only the nested PARAMS[REPLY_ID] present (no REPLY_MESSAGE[ID]).
|
|
v := buildBitrixForm()
|
|
v.Set("data[PARAMS][PARAMS][REPLY_ID]", "315901")
|
|
|
|
rm := parseForm(t, v).Params.ReplyMessage
|
|
if rm == nil || rm.ID != "315901" {
|
|
t.Errorf("ReplyMessage = %+v; want fallback ID 315901", rm)
|
|
}
|
|
}
|
|
|
|
func TestParseEvent_Form_NoReply_NilReplyMessage(t *testing.T) {
|
|
if rm := parseForm(t, buildBitrixForm()).Params.ReplyMessage; rm != nil {
|
|
t.Errorf("non-reply event should have nil ReplyMessage, got %+v", rm)
|
|
}
|
|
}
|
|
|
|
func TestParseEvent_JSON_ReplyMessage(t *testing.T) {
|
|
body := `{
|
|
"event": "ONIMBOTMESSAGEADD",
|
|
"data": {
|
|
"PARAMS": {
|
|
"MESSAGE_ID": "500",
|
|
"DIALOG_ID": "chat9",
|
|
"FROM_USER_ID": "7",
|
|
"MESSAGE": "còn hàng không",
|
|
"REPLY_MESSAGE": {"ID": 315900, "AUTHOR_ID": 62, "MESSAGE": "áo sơ mi trắng"}
|
|
}
|
|
}
|
|
}`
|
|
req := httptest.NewRequest(http.MethodPost, "/bitrix24/events", strings.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
evt, err := ParseEvent(req)
|
|
if err != nil {
|
|
t.Fatalf("ParseEvent: %v", err)
|
|
}
|
|
rm := evt.Params.ReplyMessage
|
|
if rm == nil || rm.ID != "315900" || rm.AuthorID != "62" || rm.Text != "áo sơ mi trắng" {
|
|
t.Errorf("ReplyMessage = %+v", rm)
|
|
}
|
|
}
|
|
|
|
func TestParseEvent_JSON_ReplyID_Fallback(t *testing.T) {
|
|
body := `{
|
|
"event": "ONIMBOTMESSAGEADD",
|
|
"data": {"PARAMS": {"MESSAGE_ID": "500", "FROM_USER_ID": "7", "PARAMS": {"REPLY_ID": 315901}}}
|
|
}`
|
|
req := httptest.NewRequest(http.MethodPost, "/bitrix24/events", strings.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
evt, err := ParseEvent(req)
|
|
if err != nil {
|
|
t.Fatalf("ParseEvent: %v", err)
|
|
}
|
|
if rm := evt.Params.ReplyMessage; rm == nil || rm.ID != "315901" {
|
|
t.Errorf("ReplyMessage = %+v; want fallback ID 315901", rm)
|
|
}
|
|
}
|