feat(feedback): snapshot the sender's language and connector bot at submit

Store the sender's interface language (lang) and, for a message that arrived
through an external connector (Telegram), the bot language (channel_lang) on the
feedback row at submit time, so the operator console shows the state as it was
rather than the account's current settings (same snapshot discipline as a
suspension reason). Added additively in migration 00005. The console detail reads
these columns instead of loading the account live.
This commit is contained in:
Ilia Denisov
2026-06-15 13:25:27 +02:00
parent 49b67a0354
commit 55ed87fb11
8 changed files with 111 additions and 28 deletions
+45
View File
@@ -145,6 +145,51 @@ func TestFeedbackReplyHiddenAfterNewMessage(t *testing.T) {
}
}
func TestFeedbackSnapshotsLanguages(t *testing.T) {
ctx := context.Background()
svc := newFeedbackService()
acc := provisionAccount(t)
if _, err := testDB.ExecContext(ctx,
`UPDATE backend.accounts SET preferred_language = 'en', service_language = 'ru' WHERE account_id = $1`, acc); err != nil {
t.Fatalf("set languages: %v", err)
}
// A Telegram (connector) message snapshots both the interface language and the bot.
if err := svc.Submit(ctx, acc, "from telegram", nil, "", "telegram", ""); err != nil {
t.Fatalf("submit: %v", err)
}
id := latestFeedbackID(t, svc, acc)
if m, err := svc.AdminGet(ctx, id); err != nil {
t.Fatalf("admin get: %v", err)
} else if m.Lang != "en" || m.ChannelLang != "ru" {
t.Fatalf("snapshot = lang %q / channel_lang %q, want en / ru", m.Lang, m.ChannelLang)
}
// Changing the account afterwards must not change the stored snapshot.
if _, err := testDB.ExecContext(ctx,
`UPDATE backend.accounts SET preferred_language = 'ru', service_language = 'en' WHERE account_id = $1`, acc); err != nil {
t.Fatalf("change languages: %v", err)
}
if m, err := svc.AdminGet(ctx, id); err != nil {
t.Fatal(err)
} else if m.Lang != "en" || m.ChannelLang != "ru" {
t.Fatalf("snapshot drifted after account change = lang %q / channel_lang %q", m.Lang, m.ChannelLang)
}
// A non-connector channel records no bot language even when the account has one.
acc2 := provisionAccount(t)
if _, err := testDB.ExecContext(ctx,
`UPDATE backend.accounts SET preferred_language = 'en', service_language = 'ru' WHERE account_id = $1`, acc2); err != nil {
t.Fatalf("set languages 2: %v", err)
}
if err := svc.Submit(ctx, acc2, "from web", nil, "", "web", ""); err != nil {
t.Fatalf("submit web: %v", err)
}
if m, err := svc.AdminGet(ctx, latestFeedbackID(t, svc, acc2)); err != nil {
t.Fatal(err)
} else if m.Lang != "en" || m.ChannelLang != "" {
t.Fatalf("web snapshot = lang %q / channel_lang %q, want en / empty", m.Lang, m.ChannelLang)
}
}
func TestFeedbackBanRole(t *testing.T) {
ctx := context.Background()
svc := newFeedbackService()