feat(feedback): обратная связь от пользователей с разбором в админке и ролями #64

Merged
developer merged 7 commits from feature/feedback into development 2026-06-15 11:30:09 +00:00
4 changed files with 33 additions and 19 deletions
Showing only changes of commit 2a4ce319d9 - Show all commits
+1 -1
View File
@@ -37,7 +37,7 @@ func TestRendererRendersEveryPage(t *testing.T) {
{"complaints", ComplaintsView{Items: []ComplaintRow{{ID: "c1", Word: "qi", Status: "open"}}, Status: "open", Pager: NewPager(1, 50, 1)}, "qi"}, {"complaints", ComplaintsView{Items: []ComplaintRow{{ID: "c1", Word: "qi", Status: "open"}}, Status: "open", Pager: NewPager(1, 50, 1)}, "qi"},
{"messages", MessagesView{Items: []MessageRow{{ID: "m1", SenderID: "a1", SenderName: "Kaya", Source: "telegram", Body: "good luck", GameID: "g1"}}, Pager: NewPager(1, 50, 1)}, "good luck"}, {"messages", MessagesView{Items: []MessageRow{{ID: "m1", SenderID: "a1", SenderName: "Kaya", Source: "telegram", Body: "good luck", GameID: "g1"}}, Pager: NewPager(1, 50, 1)}, "good luck"},
{"feedback", FeedbackView{Items: []FeedbackRow{{ID: "f1", AccountID: "a1", SenderName: "Kaya", Source: "telegram", Channel: "web", HasAttachment: true, Replied: true}}, Status: "unread", Pager: NewPager(1, 50, 1)}, "replied"}, {"feedback", FeedbackView{Items: []FeedbackRow{{ID: "f1", AccountID: "a1", SenderName: "Kaya", Source: "telegram", Channel: "web", HasAttachment: true, Replied: true}}, Status: "unread", Pager: NewPager(1, 50, 1)}, "replied"},
{"feedback_detail", FeedbackDetailView{ID: "f1", AccountID: "a1", SenderName: "Kaya", Channel: "ios", Body: "please fix the board", HasAttachment: true, AttachmentName: "shot.png", IsImage: true, Banned: true}, "please fix the board"}, {"feedback_detail", FeedbackDetailView{ID: "f1", AccountID: "a1", SenderName: "Kaya", Channel: "telegram", InterfaceLanguage: "en", BotLanguage: "ru", Body: "please fix the board", HasAttachment: true, AttachmentName: "shot.png", IsImage: true, Banned: true}, "bot: ru"},
{"complaint_detail", ComplaintDetailView{ID: "c1", Word: "qi", Variant: "scrabble_en"}, "Resolve"}, {"complaint_detail", ComplaintDetailView{ID: "c1", Word: "qi", Variant: "scrabble_en"}, "Resolve"},
{"dictionary", DictionaryView{ActiveVersion: "v1.0.0", Variants: []VariantVersions{{Variant: "scrabble_en", Versions: []string{"v1.0.0"}}}, Changes: []DictChangeRow{{Variant: "scrabble_en", Word: "qi", Action: "add"}}}, "Update dictionaries"}, {"dictionary", DictionaryView{ActiveVersion: "v1.0.0", Variants: []VariantVersions{{Variant: "scrabble_en", Versions: []string{"v1.0.0"}}}, Changes: []DictChangeRow{{Variant: "scrabble_en", Word: "qi", Action: "add"}}}, "Update dictionaries"},
{"dictionary_preview", DictionaryPreviewView{Version: "v1.1.0", Token: "0123456789abcdef0123456789abcdef", ActiveVersion: "v1.0.0", Variants: []VariantDiffRow{{Variant: "scrabble_en", AddedCount: 2, RemovedCount: 1, AddedSample: []string{"qi", "za"}, RemovedSample: []string{"xqz"}, RemovedTruncated: true}}}, "v1.1.0"}, {"dictionary_preview", DictionaryPreviewView{Version: "v1.1.0", Token: "0123456789abcdef0123456789abcdef", ActiveVersion: "v1.0.0", Variants: []VariantDiffRow{{Variant: "scrabble_en", AddedCount: 2, RemovedCount: 1, AddedSample: []string{"qi", "za"}, RemovedSample: []string{"xqz"}, RemovedTruncated: true}}}, "v1.1.0"},
@@ -5,7 +5,8 @@
<section class="panel"><h2>Message</h2> <section class="panel"><h2>Message</h2>
<ul class="kv"> <ul class="kv">
<li><b>From</b> <a href="/_gm/users/{{.AccountID}}">{{.SenderName}}</a> ({{.Source}})</li> <li><b>From</b> <a href="/_gm/users/{{.AccountID}}">{{.SenderName}}</a> ({{.Source}})</li>
<li><b>Channel</b> {{.Channel}}</li> <li><b>Channel</b> {{.Channel}}{{if .BotLanguage}} (bot: {{.BotLanguage}}){{end}}</li>
<li><b>Interface language</b> {{.InterfaceLanguage}}</li>
<li><b>IP</b> {{if .IP}}<code>{{.IP}}</code>{{else}}<span class="note">none</span>{{end}}</li> <li><b>IP</b> {{if .IP}}<code>{{.IP}}</code>{{else}}<span class="note">none</span>{{end}}</li>
<li><b>Filed</b> {{.CreatedAt}}</li> <li><b>Filed</b> {{.CreatedAt}}</li>
<li><b>State</b> {{if .Archived}}archived{{else if .Read}}read{{else}}<span class="warn">unread</span>{{end}}</li> <li><b>State</b> {{if .Archived}}archived{{else if .Read}}read{{else}}<span class="warn">unread</span>{{end}}</li>
+22 -17
View File
@@ -404,21 +404,26 @@ type FeedbackRow struct {
// user-controlled and rendered as plain auto-escaped text. IsImage gates the inline // user-controlled and rendered as plain auto-escaped text. IsImage gates the inline
// <img> preview; Banned shows whether the sender already holds the feedback ban. // <img> preview; Banned shows whether the sender already holds the feedback ban.
type FeedbackDetailView struct { type FeedbackDetailView struct {
ID string ID string
AccountID string AccountID string
SenderName string SenderName string
Source string Source string
Channel string Channel string
IP string // InterfaceLanguage is the sender's interface language (account preference);
Body string // BotLanguage is the connector bot they last used (en/ru), set only for a
HasAttachment bool // message that arrived through an external connector (Telegram).
AttachmentName string InterfaceLanguage string
IsImage bool BotLanguage string
Read bool IP string
Archived bool Body string
Replied bool HasAttachment bool
ReplyBody string AttachmentName string
RepliedAt string IsImage bool
CreatedAt string Read bool
Banned bool Archived bool
Replied bool
ReplyBody string
RepliedAt string
CreatedAt string
Banned bool
} }
@@ -87,6 +87,14 @@ func (s *Server) consoleFeedbackDetail(c *gin.Context) {
if banned, err := s.accounts.HasRole(ctx, m.AccountID, account.RoleFeedbackBanned); err == nil { if banned, err := s.accounts.HasRole(ctx, m.AccountID, account.RoleFeedbackBanned); err == nil {
view.Banned = banned view.Banned = banned
} }
if acc, err := s.accounts.GetByID(ctx, m.AccountID); err == nil {
view.InterfaceLanguage = acc.PreferredLanguage
// The connector bot (the account's last service-language bot) is meaningful only
// for a message that arrived through an external connector — currently Telegram.
if m.Channel == "telegram" && acc.ServiceLanguage != "" {
view.BotLanguage = acc.ServiceLanguage
}
}
s.renderConsole(c, "feedback_detail", "feedback", "Feedback", view) s.renderConsole(c, "feedback_detail", "feedback", "Feedback", view)
} }