d1ba666495
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 45s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m10s
Operator-driven hard block, the counterpart to the soft high-rate flag: permanent or until a date, with an optional reason chosen from an editable en+ru picklist (snapshotted onto the block). A block forfeits the player's active games (opponent wins, as a resignation) and cancels their open matchmaking games. A backend gate refuses a blocked account on every /api/v1/user/* route except the block-status probe with 403 account_blocked, which threads through the gateway as the Execute result_code; the UI surfaces it as a terminal blocked screen and stops all push/poll. Temporary blocks self-expire; the operator can unblock at any time (lost games stay lost). Sessions are not revoked, so the blocked client can still reach the exempt block-status endpoint. Backend: migration 00003 (account_suspensions + suspension_reasons) + jet regen; account suspension store; game.ForfeitAllForAccount; requireNotSuspended gate + block-status endpoint; admin console block/unblock + Reasons CRUD. Wire: fbs BlockStatus + account.block_status gateway op. UI: blocked screen, app state, transport/codec, i18n. Docs: ARCHITECTURE, FUNCTIONAL(+ru), PRERELEASE (AB).
28 lines
1.2 KiB
Go Template
28 lines
1.2 KiB
Go Template
{{define "content" -}}
|
|
<h1>Suspension reasons</h1>
|
|
{{with .Data}}
|
|
<p class="note">Reasons offered when blocking a user; each is shown to the blocked player in their own language. Editing or deleting a reason does not change a reason already shown to a currently-blocked player (blocks snapshot the text).</p>
|
|
<section class="panel"><h2>Add reason</h2>
|
|
<form class="form col" method="post" action="/_gm/reasons">
|
|
<label>English <input type="text" name="text_en" required></label>
|
|
<label>Russian <input type="text" name="text_ru" required></label>
|
|
<div><button type="submit">Add</button></div>
|
|
</form>
|
|
</section>
|
|
<section class="panel"><h2>Existing reasons</h2>
|
|
{{range .Items}}
|
|
<div class="row">
|
|
<form class="form" method="post" action="/_gm/reasons/{{.ID}}/update">
|
|
<input type="text" name="text_en" value="{{.TextEn}}" aria-label="English" required>
|
|
<input type="text" name="text_ru" value="{{.TextRu}}" aria-label="Russian" required>
|
|
<button type="submit">Save</button>
|
|
</form>
|
|
<form class="form" method="post" action="/_gm/reasons/{{.ID}}/delete">
|
|
<button type="submit">Delete</button>
|
|
</form>
|
|
</div>
|
|
{{else}}<p class="note">no reasons yet</p>{{end}}
|
|
</section>
|
|
{{end}}
|
|
{{- end}}
|