package account import ( "html/template" "net/http" "git.lohmar.co.uk/cclohmar/NextMyDay/internal/core/server" "git.lohmar.co.uk/cclohmar/NextMyDay/internal/core/users" "git.lohmar.co.uk/cclohmar/NextMyDay/internal/core/web" ) // accountData is the account template's input (SPEC-010 §4). type accountData struct { GUID string Token string Passkeys int TOTP bool OptOut bool } // usersData is the Users page template's input (SPEC-010 §5). type usersData struct { GUID string Token string Rows []userRow Roles []users.Role Notice string NoticeKind string InviteLink string } // userRow is one user's line on the Users page. type userRow struct { Name string Email string Role string Manager string Status string } // webRenderStatus draws a page inside the core shell, applying the request's // shell state (the role-gated nav + the passkey banner) with web.PageFor. Every // page is `no-store`: the account and Users pages carry a session and a CSRF // token. func webRenderStatus(w http.ResponseWriter, r *http.Request, rc *server.RequestContext, status int, title, active, token, body string) error { w.Header().Set("Cache-Control", "no-store") return web.Render(w, status, web.PageFor(r, web.Page{ Title: title, GUID: rc.Workflow, Active: active, CSRF: token, Content: web.Markup(body), })) } // accountTemplateHTML is the account page BODY only: the shell (SPEC-009 §4) // owns the document, the header and the nav; this is the content slot. // // "Add a passkey" is a LINK to the existing SPEC-006 §8 / D-041 passkey screen // (/{GUID}/auth/passkey) — the WebAuthn ceremony is never duplicated here. const accountTemplateHTML = `

Account

Your factors

Passkeys registered: {{.Passkeys}}

Authenticator app (TOTP): {{if .TOTP}}enrolled{{else}}not enrolled{{end}}

Passkey

Add a passkey to sign in without the one-time code. It is bound to this device and this site.

Add a passkey

Don't ask again

{{if .OptOut}}

You have opted out of passkey reminders.

{{else}}

Stop the "add a passkey" reminders.

{{end}}
` // usersTemplateHTML is the Users page BODY only (SPEC-010 §5). const usersTemplateHTML = `

Users

{{if .Notice}}

{{.Notice}}

{{end}} {{if .InviteLink}}

Invitation link (share it if email is not configured):
{{.InviteLink}}

{{end}} {{range .Rows}} {{end}}
NameEmailRoleManagerIdentity
{{.Name}}{{.Email}}{{.Role}}{{.Manager}}{{.Status}}

Add a user

The new user's manager defaults to you. Only roles below your own can be created.

` // Templates are parsed once; a parse failure of a constant is impossible. var ( accountTemplate = template.Must(template.New("account").Parse(accountTemplateHTML)) usersTemplate = template.Must(template.New("users").Parse(usersTemplateHTML)) )