52f898ca6f
Tests · Go / test (push) Successful in 7s
Tests · Integration / integration (push) Successful in 11s
Tests · UI / test (push) Successful in 20s
Tests · Go / test (pull_request) Successful in 6s
Tests · Integration / integration (pull_request) Successful in 11s
Tests · UI / test (pull_request) Successful in 19s
Link an email (confirm-code) or Telegram (web Login Widget) to the current account; if the identity already has its own account, merge the two into the one in use (the current account is primary, except a guest initiator whose durable counterpart wins). The merge runs in one transaction (internal/accountmerge): stats + hint wallet summed, paid_account ORed, identities/games/chat/complaints transferred, friends/blocks de-duplicated, the secondary kept as a merged_into tombstone so a shared finished game's no-cascade FKs hold; a shared active game blocks the merge. - migration 00009: accounts.paid_account, merged_into, merged_at (+ jetgen) - internal/link orchestrator; session.RevokeAllForAccount on merge - connector ValidateLoginWidget RPC + loginwidget HMAC validator - edge ops link.email.request/confirm/merge, link.telegram.confirm/merge; supersedes the Stage 8 email.bind.* surface (request never reveals 'taken' before the code is verified, so a probe cannot enumerate addresses) - UI Profile link section + irreversible-merge dialog; Telegram web sign-in - focused regression tests (merge core, guest inversion, active-game refusal, finished-shared-game kept), gateway transcode + connector + UI codec/e2e - docs: PLAN, ARCHITECTURE 3/4/9, FUNCTIONAL(+ru), module READMEs
205 lines
4.4 KiB
Go
205 lines
4.4 KiB
Go
package adminconsole
|
|
|
|
// The *View types are the display models the gin handlers fill and the templates
|
|
// render. Time values are pre-formatted to strings by the handlers so the
|
|
// templates stay logic-free.
|
|
|
|
// Pager is the shared list pagination state.
|
|
type Pager struct {
|
|
Page int
|
|
PageSize int
|
|
Total int
|
|
HasPrev bool
|
|
HasNext bool
|
|
PrevPage int
|
|
NextPage int
|
|
}
|
|
|
|
// NewPager builds the pagination state for a 1-based page of pageSize over total
|
|
// items.
|
|
func NewPager(page, pageSize, total int) Pager {
|
|
if page < 1 {
|
|
page = 1
|
|
}
|
|
p := Pager{Page: page, PageSize: pageSize, Total: total, PrevPage: page - 1, NextPage: page + 1}
|
|
p.HasPrev = page > 1
|
|
p.HasNext = page*pageSize < total
|
|
return p
|
|
}
|
|
|
|
// VariantVersions lists the dictionary versions resident for one variant.
|
|
type VariantVersions struct {
|
|
Variant string
|
|
Latest string
|
|
Versions []string
|
|
}
|
|
|
|
// DashboardView is the landing-page summary.
|
|
type DashboardView struct {
|
|
Accounts int
|
|
Games int
|
|
ActiveGames int
|
|
OpenComplaints int
|
|
PendingChanges int
|
|
Variants []VariantVersions
|
|
}
|
|
|
|
// UsersView is the paginated account list.
|
|
type UsersView struct {
|
|
Items []UserRow
|
|
Pager Pager
|
|
}
|
|
|
|
// UserRow is one account row in the list.
|
|
type UserRow struct {
|
|
ID string
|
|
DisplayName string
|
|
Kind string
|
|
Language string
|
|
Guest bool
|
|
CreatedAt string
|
|
}
|
|
|
|
// UserDetailView is one account with its stats, identities and recent games.
|
|
type UserDetailView struct {
|
|
ID string
|
|
DisplayName string
|
|
Language string
|
|
TimeZone string
|
|
Guest bool
|
|
NotificationsInAppOnly bool
|
|
PaidAccount bool
|
|
// MergedInto is the primary account id when this account has been retired by a
|
|
// merge (Stage 11), or empty for a live account.
|
|
MergedInto string
|
|
HintBalance int
|
|
CreatedAt string
|
|
HasStats bool
|
|
Stats StatsRow
|
|
Identities []IdentityRow
|
|
Games []GameRow
|
|
TelegramID string
|
|
ConnectorEnabled bool
|
|
}
|
|
|
|
// StatsRow is an account's lifetime statistics.
|
|
type StatsRow struct {
|
|
Wins int
|
|
Losses int
|
|
Draws int
|
|
MaxGamePoints int
|
|
MaxWordPoints int
|
|
}
|
|
|
|
// IdentityRow is one platform/email identity of an account.
|
|
type IdentityRow struct {
|
|
Kind string
|
|
ExternalID string
|
|
Confirmed bool
|
|
CreatedAt string
|
|
}
|
|
|
|
// GameRow is one game row in a list.
|
|
type GameRow struct {
|
|
ID string
|
|
Variant string
|
|
Status string
|
|
Players int
|
|
UpdatedAt string
|
|
}
|
|
|
|
// GamesView is the paginated games list, optionally filtered by status.
|
|
type GamesView struct {
|
|
Items []GameRow
|
|
Status string
|
|
Pager Pager
|
|
}
|
|
|
|
// GameDetailView is one game with its seats.
|
|
type GameDetailView struct {
|
|
ID string
|
|
Variant string
|
|
DictVersion string
|
|
Status string
|
|
Players int
|
|
ToMove int
|
|
EndReason string
|
|
MoveCount int
|
|
CreatedAt string
|
|
UpdatedAt string
|
|
FinishedAt string
|
|
Seats []SeatRow
|
|
}
|
|
|
|
// SeatRow is one seat of a game.
|
|
type SeatRow struct {
|
|
Seat int
|
|
DisplayName string
|
|
AccountID string
|
|
Score int
|
|
HintsUsed int
|
|
Winner bool
|
|
}
|
|
|
|
// ComplaintsView is the paginated complaint review queue.
|
|
type ComplaintsView struct {
|
|
Items []ComplaintRow
|
|
Status string
|
|
Pager Pager
|
|
}
|
|
|
|
// ComplaintRow is one complaint row in the queue.
|
|
type ComplaintRow struct {
|
|
ID string
|
|
Word string
|
|
Variant string
|
|
WasValid bool
|
|
Status string
|
|
Disposition string
|
|
CreatedAt string
|
|
}
|
|
|
|
// ComplaintDetailView is one complaint with its resolution state and form.
|
|
type ComplaintDetailView struct {
|
|
ID string
|
|
Word string
|
|
Variant string
|
|
DictVersion string
|
|
WasValid bool
|
|
Note string
|
|
Status string
|
|
Disposition string
|
|
ResolutionNote string
|
|
CreatedAt string
|
|
ResolvedAt string
|
|
GameID string
|
|
Resolved bool
|
|
}
|
|
|
|
// DictionaryView lists the resident versions per variant and the pending
|
|
// wordlist changes from accepted complaints.
|
|
type DictionaryView struct {
|
|
Variants []VariantVersions
|
|
Changes []DictChangeRow
|
|
}
|
|
|
|
// DictChangeRow is one pending wordlist edit.
|
|
type DictChangeRow struct {
|
|
Variant string
|
|
Word string
|
|
Action string
|
|
ResolvedAt string
|
|
}
|
|
|
|
// BroadcastView is the operator-broadcast form page.
|
|
type BroadcastView struct {
|
|
ConnectorEnabled bool
|
|
}
|
|
|
|
// MessageView is the result page shown after a POST action.
|
|
type MessageView struct {
|
|
Heading string
|
|
Body string
|
|
Back string
|
|
}
|