feat(feedback): in-app user feedback with admin review and account roles
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 12s
CI / ui (pull_request) Successful in 47s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m12s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 12s
CI / ui (pull_request) Successful in 47s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m12s
User-facing Feedback screen (Settings -> Info, registered accounts only): a message (<=1024 runes) plus one optional attachment, an anti-spam gate (one unreviewed message at a time), and the operator's inline reply with a Settings/Info badge. Server-rendered admin console section (/_gm/feedback): unread/read/archived queue with per-user search, detail with read/reply/ archive/delete/delete-all, safe attachment serving (nosniff, images inline via <img>, others download-only). Introduces account_roles, the first per-account role table; feedback_banned blocks only feedback submission, granted/revoked from /users and the delete-with-block action. - migration 00004_feedback (feedback_messages + account_roles) + jetgen - backend internal/feedback (store+service), internal/account/roles.go - wire: FlatBuffers feedback.submit/get/unread; gateway guest gate (Op.NonGuest, is_guest via session resolve) -> guest_forbidden before any backend call - reply push reuses NotificationEvent with a new admin_reply sub-kind - UI: /feedback route + screen, attachment picker, badge, channel detection, i18n - tests: feedback unit (Go+UI), gateway guest-gate, inttest lifecycle, e2e - docs: PLAN stage 19, ARCHITECTURE s15, FUNCTIONAL(+ru), TESTING, READMEs
This commit is contained in:
@@ -42,6 +42,7 @@ type DashboardView struct {
|
||||
Games int
|
||||
ActiveGames int
|
||||
OpenComplaints int
|
||||
OpenFeedback int
|
||||
PendingChanges int
|
||||
// ActiveVersion is the dictionary version new games pin (the persisted active
|
||||
// version), distinct from the per-variant resident versions.
|
||||
@@ -142,6 +143,10 @@ type UserDetailView struct {
|
||||
// form; Reasons is the operator-editable reason picklist offered in the block form.
|
||||
Suspension SuspensionView
|
||||
Reasons []ReasonOption
|
||||
// Roles is the account's current roles (each revocable); KnownRoles is the set the
|
||||
// grant form offers. The first role is the feedback ban (see internal/account).
|
||||
Roles []string
|
||||
KnownRoles []string
|
||||
}
|
||||
|
||||
// SuspensionView is an account's current manual-block state shown on the user card: whether it
|
||||
@@ -362,3 +367,58 @@ type MessageView struct {
|
||||
Body string
|
||||
Back string
|
||||
}
|
||||
|
||||
// FeedbackView is the paginated user-feedback queue. Status is the active
|
||||
// unread/read/archived filter; NameMask/ExtMask are the sender glob filters;
|
||||
// UserID pins the list to one account (the per-user link from /users);
|
||||
// FilterQuery is the active filters URL-encoded for the pager links (already
|
||||
// escaped, hence template.URL — see UsersView.FilterQuery).
|
||||
type FeedbackView struct {
|
||||
Items []FeedbackRow
|
||||
Status string
|
||||
NameMask string
|
||||
ExtMask string
|
||||
UserID string
|
||||
Pager Pager
|
||||
FilterQuery template.URL
|
||||
}
|
||||
|
||||
// FeedbackRow is one feedback message in the queue: its sender (linked to the user
|
||||
// card), source, channel, whether it has an attachment / a reply, its state and
|
||||
// time.
|
||||
type FeedbackRow struct {
|
||||
ID string
|
||||
AccountID string
|
||||
SenderName string
|
||||
Source string
|
||||
Channel string
|
||||
HasAttachment bool
|
||||
Read bool
|
||||
Replied bool
|
||||
Archived bool
|
||||
CreatedAt string
|
||||
}
|
||||
|
||||
// FeedbackDetailView is one feedback message with its body, attachment, state and
|
||||
// the reply / archive / delete forms. Body, AttachmentName, SenderName and IP are
|
||||
// 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.
|
||||
type FeedbackDetailView struct {
|
||||
ID string
|
||||
AccountID string
|
||||
SenderName string
|
||||
Source string
|
||||
Channel string
|
||||
IP string
|
||||
Body string
|
||||
HasAttachment bool
|
||||
AttachmentName string
|
||||
IsImage bool
|
||||
Read bool
|
||||
Archived bool
|
||||
Replied bool
|
||||
ReplyBody string
|
||||
RepliedAt string
|
||||
CreatedAt string
|
||||
Banned bool
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user