misaki/tmpl/dashboard.html
q 4512570a49
All checks were successful
Build & push Docker image / build (push) Successful in 2m22s
new features and style changes
2026-11-07 12:03:59 -05:00

242 lines
11 KiB
HTML

{{template "base.html" .}}
{{define "title"}}Dashboard{{end}}
{{define "page"}}wide{{end}}
{{define "content"}}
<nav class="nav">
<a href="/dashboard">Dashboard</a>
<a href="/help">Help</a>
{{if .User.IsAdmin}}<a href="/admin">Admin</a>{{end}}
<form method="POST" action="/logout">
<button>Log out</button>
</form>
</nav>
<h1>Hi there, {{.User.Username}}!</h1>
{{if .Error}}<p class="err">{{.Error}}</p>{{end}}
{{if .Success}}<p class="ok">{{.Success}}</p>{{end}}
<div class="account">
<section>
<h2>Note</h2>
{{if .User.Note}}<div class="bio-box">{{.User.Note}}</div>{{else}}<p class="muted">No note yet.</p>{{end}}
<details class="setting">
<summary><span class="act">edit note</span></summary>
<form method="POST" action="/dashboard/note">
<textarea name="note" maxlength="2000">{{.User.Note}}</textarea>
<button type="submit">Save</button>
</form>
</details>
</section>
<section>
<h2>Account</h2>
<details class="setting">
<summary><span class="k">username</span><span class="v">{{.User.Username}}</span><span class="act">change</span></summary>
<p class="muted">Your old name stays reserved for you. IRC, XMPP and mail accounts keep the old name until an admin moves them. Once every 30 days.</p>
<form method="POST" action="/dashboard/username">
<label>New username <input type="text" name="username" required maxlength="21" pattern="[A-Za-z0-9_\-]+" autocomplete="username"></label>
<label>Current password <input type="password" name="current" required maxlength="128" autocomplete="current-password"></label>
{{if .TOTPOn}}<label>2FA code <input type="text" name="code" required autocomplete="one-time-code" maxlength="24"></label>{{end}}
<button type="submit">Change username</button>
</form>
</details>
<details class="setting">
<summary><span class="k">email</span><span class="v">{{if .Email}}{{.Email}}{{else}}<span class="dim">not set</span>{{end}}</span><span class="act">edit</span></summary>
<form method="POST" action="/dashboard/email">
<input type="email" name="email" value="{{.Email}}" maxlength="254" placeholder="only for services that need one">
<button type="submit">Save</button>
</form>
</details>
{{if or .TOTPOn .TOTPReady}}
<details class="setting">
<summary><span class="k">2FA</span><span class="v">{{if .TOTPOn}}on <span class="dim">&middot; {{.CodesLeft}} recovery codes</span>{{else}}<span class="dim">off</span>{{end}}</span><span class="act">{{if .TOTPOn}}manage{{else}}set up{{end}}</span></summary>
{{if .TOTPOn}}
<form method="POST" action="/dashboard/2fa/disable">
<label>Turn off 2FA: code or recovery code <input type="text" name="code" required autocomplete="one-time-code" maxlength="24"></label>
<button type="submit">Turn off</button>
</form>
{{else}}
<p class="muted">Ask for a code from an authenticator app at login, on every misaki service.</p>
<form method="POST" action="/dashboard/2fa/setup">
<button type="submit" class="go">Turn on 2FA</button>
</form>
{{end}}
</details>
{{end}}
<details class="setting">
<summary><span class="k">password</span><span class="v">&bull;&bull;&bull;&bull;&bull;&bull;</span><span class="act">change</span></summary>
<form method="POST" action="/dashboard/password">
<label>Current password <input type="password" name="current" required maxlength="128" autocomplete="current-password"></label>
<label>New password <input type="password" name="password" required minlength="8" maxlength="128" autocomplete="new-password"></label>
<label>Again <input type="password" name="password_confirm" required minlength="8" maxlength="128" autocomplete="new-password"></label>
{{if .TOTPOn}}<label>2FA code <input type="text" name="code" required autocomplete="one-time-code" maxlength="24"></label>{{end}}
<button type="submit">Change password</button>
</form>
</details>
</section>
</div>
{{if .Cards}}
<h2>Services</h2>
<div class="svc-grid">
{{range .Cards}}
<section class="svc-card">
<h3>{{.Label}}</h3>
{{if .Desc}}<div class="svc-desc">{{.Desc}}</div>{{end}}
{{if .InfoURL}}<p><a href="{{.InfoURL}}" target="_blank" rel="noopener">More info ↗</a></p>{{end}}
{{if .Denied}}<p class="err">Request denied{{with .DenyReason}}: {{.}}{{end}}</p>{{end}}
{{if eq .Type "form"}}
{{if .Granted}}
<p class="ok">Active</p>
<details>
<summary>Request password reset</summary>
<form method="POST" action="/dashboard/request-reset">
<input type="hidden" name="service" value="{{.Service}}">
<button type="submit">Send reset request to admin</button>
</form>
</details>
{{else if .Applied}}
<p class="muted">Applied — awaiting admin review</p>
{{else}}
<details>
<summary>Apply</summary>
<form method="POST" action="/dashboard/apply">
<input type="hidden" name="service" value="{{.Service}}">
<label>Handle <input type="text" name="handle" required maxlength="64"></label>
<label>Password <input type="password" name="password" required maxlength="128"></label>
<label>Reason <textarea name="reason" maxlength="2000"></textarea></label>
<button type="submit">Submit</button>
</form>
</details>
{{end}}
{{else if eq .Type "link"}}
{{$url := ""}}
{{if eq .Service "gancio"}}{{$url = $.URLs.GancioURL}}{{end}}
{{if eq .Service "akkoma"}}{{$url = $.URLs.AkkomaURL}}{{end}}
{{if eq .Service "forgejo"}}{{$url = $.URLs.ForgejoURL}}{{end}}
{{if .Granted}}
<p class="ok">Access confirmed</p>
{{if $url}}<p><a href="{{$url}}" target="_blank" rel="noopener">Go to service ↗</a></p>{{end}}
{{else}}
{{if $url}}
<p><a href="{{$url}}" target="_blank" rel="noopener">Register ↗</a></p>
{{else}}
<p class="muted">Registration link not configured — contact admin.</p>
{{end}}
{{end}}
{{else if eq .Type "oidc"}}
{{if .Granted}}
<p class="ok">Active — sign in with misaki</p>
{{if .URL}}<p><a href="{{.URL}}" target="_blank" rel="noopener">Open {{.Label}} ↗</a></p>{{end}}
{{else if .Applied}}
<p class="muted">Requested — awaiting admin</p>
{{else}}
<form method="POST" action="/dashboard/apply">
<input type="hidden" name="service" value="{{.Service}}">
{{if .NeedsEmail}}<label>Contact email (a thirdculture address works) <input type="email" name="email" value="{{$.Email}}" required maxlength="254"></label>{{end}}
<button type="submit">Request Access</button>
</form>
{{end}}
{{else if eq .Type "request"}}
{{if .Granted}}
{{if eq .Service "ergo"}}
<p class="ok">Active — log in with your Misaki username and password</p>
<p>IRC client: <code>irc.thirdculture.diy:6697</code> (TLS) &middot; <a href="https://irc.thirdculture.diy" target="_blank" rel="noopener">Web client ↗</a></p>
{{else if eq .Service "prosody"}}
<p class="ok">Active — log in with your Misaki username and password</p>
<p>JID: <code>{{$.User.Username}}@thirdculture.diy</code> &middot; Port: <code>5222</code> (TLS) / <code>5223</code> (Direct TLS)</p>
{{else if eq .Service "streaming"}}
{{if .Data}}
<p class="ok">Active</p>
<p>Your streaming key: <code>{{.Data}}</code></p>
{{else}}
<p class="ok">Access granted — streaming key pending from admin</p>
{{end}}
{{else if eq .Service "radio"}}
{{if .Data}}
<p class="ok">Active — broadcast with your Misaki username and password</p>
<p>Your stations: <code>{{.Data}}</code> &middot; push to <code>dj.thirdculture.diy</code></p>
{{else}}
<p class="ok">Access granted — stations pending from admin</p>
{{end}}
{{else if eq .Service "files"}}
{{if .Data}}
<p class="ok">Active</p>
<p>Your mounts: <code>{{.Data}}</code> &middot; <a href="https://files.thirdculture.diy" target="_blank" rel="noopener">Open files ↗</a></p>
{{else}}
<p class="ok">Access granted — mounts pending from admin</p>
{{end}}
{{else}}
{{if .Data}}
<p class="ok">Access granted</p>
<p>Your registration link: <a href="{{.Data}}" target="_blank" rel="noopener">{{.Data}} ↗</a></p>
{{else}}
<p class="ok">Access granted — registration link pending from admin</p>
{{end}}
<details>
<summary>Request password reset</summary>
<form method="POST" action="/dashboard/request-reset">
<input type="hidden" name="service" value="{{.Service}}">
<button type="submit">Send reset request to admin</button>
</form>
</details>
<details>
<summary>Request name change</summary>
<form method="POST" action="/dashboard/request-namechange">
<input type="hidden" name="service" value="{{.Service}}">
<label>New username <input type="text" name="new_name" required maxlength="64"></label>
<button type="submit">Submit request</button>
</form>
</details>
{{end}}
{{else if .Applied}}
<p class="muted">Requested — awaiting admin</p>
{{else}}
{{if or (eq .Service "radio") (eq .Service "streaming")}}
<details>
<summary>Request Access</summary>
<form method="POST" action="/dashboard/apply">
<input type="hidden" name="service" value="{{.Service}}">
<label>{{if eq .Service "radio"}}Which stations (or new one) / Why{{else}}Reason{{end}} <textarea name="reason" maxlength="2000" required></textarea></label>
<button type="submit">Submit</button>
</form>
</details>
{{else}}
<form method="POST" action="/dashboard/apply">
<input type="hidden" name="service" value="{{.Service}}">
<button type="submit">Request Access</button>
</form>
{{end}}
{{end}}
{{else if eq .Type "cookie"}}
<p class="ok">Available — open with your Misaki session</p>
{{if .URL}}<p><a href="{{.URL}}" target="_blank" rel="noopener">Open ↗</a></p>{{end}}
{{end}}
</section>
{{end}}
{{if $.URLs.MumbleHost}}
<section class="svc-card">
<h3>Mumble</h3>
{{with index $.SvcDescs "mumble"}}<div class="svc-desc">{{.}}</div>{{end}}
{{with index $.InfoURLs "mumble"}}<p><a href="{{.}}" target="_blank" rel="noopener">More info ↗</a></p>{{end}}
<p>Server: <code>{{$.URLs.MumbleHost}}</code>{{if $.URLs.MumblePass}} &mdash; password: <code>{{$.URLs.MumblePass}}</code>{{end}}</p>
</section>
{{end}}
</div>
{{end}}
{{if and (not .Cards) .URLs.MumbleHost}}
<section class="svc-card">
<h3>Mumble</h3>
{{with index .SvcDescs "mumble"}}<div class="svc-desc">{{.}}</div>{{end}}
{{with index .InfoURLs "mumble"}}<p><a href="{{.}}" target="_blank" rel="noopener">More info ↗</a></p>{{end}}
<p>Server: <code>{{.URLs.MumbleHost}}</code>{{if .URLs.MumblePass}} &mdash; password: <code>{{.URLs.MumblePass}}</code>{{end}}</p>
</section>
{{end}}
<img src="/static/guitar.jpg" alt="" class="footer-art">
{{end}}