3faca690dd
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 9s
CI / integration (pull_request) Successful in 16s
CI / ui (pull_request) Successful in 1m5s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m46s
- Admin /users gains a Deleted scope (between People and Robots); every other scope now hides tombstoned accounts (deleted_at filter in UserFilter). - Admin delete-user is offered for any non-deleted account (drop the not-guest gate, so a stale is_guest account can still be tombstoned). - Harden EmailService.ConfirmCode to ClearGuest — defence-in-depth so no confirmed-email path leaves is_guest set (the currently-live paths already do). - Space the delete/change dialog's action row from its input field. Integration tests: the Deleted filter scoping + ConfirmCode guest promotion.
40 lines
1.9 KiB
Go Template
40 lines
1.9 KiB
Go Template
{{define "content" -}}
|
|
<h1>Users</h1>
|
|
{{with .Data}}
|
|
<nav class="subnav">
|
|
<a href="/_gm/users"{{if and (not .Robots) (not .Deleted)}} class="active"{{end}}>People</a> ·
|
|
<a href="/_gm/users?kind=deleted"{{if .Deleted}} class="active"{{end}}>Deleted</a> ·
|
|
<a href="/_gm/users?kind=robots"{{if .Robots}} class="active"{{end}}>Robots</a>
|
|
</nav>
|
|
<form class="form" method="get" action="/_gm/users">
|
|
{{if .Robots}}<input type="hidden" name="kind" value="robots">{{end}}{{if .Deleted}}<input type="hidden" name="kind" value="deleted">{{end}}
|
|
<input name="name" value="{{.NameMask}}" placeholder="display name mask (* ?)">
|
|
<input name="ext" value="{{.ExternalIDMask}}" placeholder="external id mask (* ?)">
|
|
<input name="email" value="{{.EmailExact}}" placeholder="email (exact)" type="search">
|
|
<button type="submit">Filter</button>
|
|
</form>
|
|
<table class="list">
|
|
<thead><tr><th>Account</th><th>Display name</th><th>Kind</th><th>Lang</th><th>Created</th><th title="per-move think time across all games">Move min</th><th>avg</th><th>max</th></tr></thead>
|
|
<tbody>
|
|
{{range .Items}}
|
|
<tr>
|
|
<td><a href="/_gm/users/{{.ID}}">{{.ID}}</a></td>
|
|
<td>{{.DisplayName}}{{if .Guest}} <span class="pill">guest</span>{{end}}{{if .FlaggedHighRate}} <span class="pill">high-rate</span>{{end}}</td>
|
|
<td>{{.Kind}}</td>
|
|
<td>{{.Language}}</td>
|
|
<td>{{.CreatedAt}}</td>
|
|
{{if .HasMoveStats}}<td>{{.MoveMin}}</td><td>{{.MoveAvg}}</td><td>{{.MoveMax}}</td>{{else}}<td colspan="3"><span class="note">—</span></td>{{end}}
|
|
</tr>
|
|
{{else}}
|
|
<tr><td colspan="8"><span class="note">no users</span></td></tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
<nav class="pager">
|
|
{{if .Pager.HasPrev}}<a href="/_gm/users?{{.FilterQuery}}&page={{.Pager.PrevPage}}">« prev</a>{{end}}
|
|
<span>page {{.Pager.Page}} · {{.Pager.Total}} total</span>
|
|
{{if .Pager.HasNext}}<a href="/_gm/users?{{.FilterQuery}}&page={{.Pager.NextPage}}">next »</a>{{end}}
|
|
</nav>
|
|
{{end}}
|
|
{{- end}}
|