All checks were successful
Build & push Docker image / build (push) Successful in 2m22s
242 lines
11 KiB
HTML
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">· {{.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">••••••</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) · <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> · 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> · 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> · <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}} — 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}} — password: <code>{{.URLs.MumblePass}}</code>{{end}}</p>
|
|
</section>
|
|
{{end}}
|
|
|
|
<img src="/static/guitar.jpg" alt="" class="footer-art">
|
|
{{end}}
|