Initial commit

This commit is contained in:
blankhex committed 2026-10-15 23:25:46 +03:00
commit c578b91c2d
46 files changed
+3241

No files matched your search

+31
View File
@@ -0,0 +1,31 @@
{{template "header" .}}
<div class="container">
<h2 class="text-center">uPortal</h2>
{{template "alarm" .}}
<div class="row">
<div class="col-3 mx-auto">
<div class="card">
<div class="card-header">Sign in</div>
<div class="card-b">
<form method="post">
{{template "csrf" .}}
{{template "redirect" .}}
<div class="form-group"><label for="login_username">Username</label><input type="text" class="w-100" id="login_username" name="username"></div>
<div class="form-group"><label for="login_password">Password</label><input type="password" class="w-100" id="login_password" name="password"></div>
<div class="form-group"><label><input type="checkbox" id="remember" name="remember" checked> Remember me</label></div>
<div class="text-center"><button type="submit">Sign In</button></div>
</form>
{{if .Redirect}}
<p class="text-center"><a href="/signup?redirect={{.Redirect}}">Don't have an account? Sign up</a></p>
{{else}}
<p class="text-center"><a href="/signup">Don't have an account? Sign up</a></p>
{{end}}
</div>
</div>
</div>
</div>
</div>
{{template "footer" .}}
+22
View File
@@ -0,0 +1,22 @@
{{template "header" .}}
{{template "navbar" .}}
<div class="container">
<h2 class="text-center">uPortal</h2>
<div class="row">
<div class="col-3 mx-auto">
<div class="card">
<div class="card-header">Sign out</div>
<div class="card-b">
<form method="post">
{{template "csrf" .}}
<div class="text-center"><button type="submit">Confirm</button></div>
</form>
</div>
</div>
</div>
</div>
</div>
{{template "footer" .}}
+28
View File
@@ -0,0 +1,28 @@
{{template "header" .}}
<div class="container">
<h2 class="text-center">uPortal</h2>
{{template "alarm" .}}
<div class="row">
<div class="col-3 mx-auto">
<div class="card">
<div class="card-header">Sign up</div>
<div class="card-b">
<form method="post">
{{template "csrf" .}}
{{template "redirect" .}}
<div class="form-group"><label for="reg_username">Username</label><input type="text" class="w-100" id="reg_username" name="username"/></div>
<div class="form-group"><label for="reg_password">Password</label><input type="password" class="w-100" id="reg_password" name="password"/></div>
<div class="form-group"><label for="reg_confirm">Confirm Password</label><input type="password" class="w-100" id="reg_confirm" name="confirm"/></div>
<div class="form-group"><label for="reg_invite">Invite code</label><input type="text" class="w-100" id="reg_invite" name="invite"/></div>
<div class="text-center"><button type="submit">Create Account</button></div>
</form>
<p class="text-center"><a href="/signin">Already have an account? Sign in</a></p>
</div>
</div>
</div>
</div>
</div>
{{template "footer" .}}
+25
View File
@@ -0,0 +1,25 @@
{{template "header" .}}
{{template "navbar" .}}
<div class="container">
<h2>Create invite</h2>
{{template "alarm" .}}
<div class="row">
<div class="col-3 mx-auto">
<div class="card">
<div class="card-header">Create Invite</div>
<div class="card-b">
<form method="post" action="/invites/create">
{{template "csrf" .}}
<div class="form-group"><label for="uses">Uses</label><input type="number" class="w-100" id="uses" name="uses" value="1" min="1"></div>
<div class="form-group"><label for="exp_hours">Expires in (hours)</label><input type="number" class="w-100" id="exp_hours" name="expires_hours" value="24" min="1"></div>
<div class="text-center"><button type="submit">Create</button></div>
</form>
<p class="text-center"><a href="/invites">Back to invites</a></p>
</div>
</div>
</div>
</div>
</div>
{{template "footer" .}}
+49
View File
@@ -0,0 +1,49 @@
{{template "header" .}}
{{template "navbar" .}}
<div class="container">
<h2>Invites</h2>
<div class="row">
<div class="col-6">
<div class="card">
<div class="card-header">Invites</div>
<div class="card-b">
{{template "alarm" .}}
<table class="table">
<thead>
<tr><th>Token</th><th>Uses</th><th>Expires At</th><th>Created At</th><th></th></tr>
</thead>
<tbody>
{{range .Invites}}
<tr>
<td>{{.Token}}</td>
<td>{{.Uses}}</td>
<td>{{.ExpiresAt.Format "2006-01-02 15:04"}}</td>
<td>{{.CreatedAt.Format "2006-01-02 15:04"}}</td>
<td>
<form method="post" action="/invites/delete">
{{template "csrf" $}}
<input type="hidden" name="token" value="{{.Token}}">
<button type="submit">Delete</button>
</form>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
</div>
<div class="col-6">
<div class="card">
<div class="card-header">Actions</div>
<div class="card-b">
<p><a href="/invites/create">Create Invite</a></p>
</div>
</div>
</div>
</div>
</div>
{{template "footer" .}}
+23
View File
@@ -0,0 +1,23 @@
{{template "header" .}}
{{template "navbar" .}}
<div class="container">
<h2>Jitsi</h2>
{{template "alarm" .}}
<div class="row">
<div class="col-3 mx-auto">
<div class="card">
<div class="card-header">Join Jitsi</div>
<div class="card-b">
<form method="post">
{{template "csrf" .}}
<div class="form-group"><label for="jitsi_room">Room name</label><input type="text" class="w-100" id="jitsi_room" name="room" placeholder="e.g. my-meeting-room" required></div>
<div class="text-center"><button type="submit">Open in Jitsi</button></div>
</form>
</div>
</div>
</div>
</div>
</div>
{{template "footer" .}}
+26
View File
@@ -0,0 +1,26 @@
{{template "header" .}}
{{template "navbar" .}}
<div class="container">
<h2>Profile</h2>
{{template "alarm" .}}
<div class="row">
<div class="col-3 mx-auto">
<div class="card">
<div class="card-header">Edit profile</div>
<div class="card-b">
<p><img src="/avatar/{{.User.Id}}" onerror="this.src='/static/default.jpg'; this.onerror=null;" width="128" height="128" alt="Avatar" class="mx-auto"></p>
<form method="post" action="/profile/edit" enctype="multipart/form-data">
{{template "csrf" .}}
<div class="form-group"><label for="disp_name">Display name</label><input type="text" class="w-100" id="disp_name" name="display_name" value="{{.User.EffectiveDisplayName}}"></div>
<div class="form-group"><label for="avatar">Avatar</label><input type="file" class="w-100" id="avatar" name="avatar" accept="image/png,image/jpeg"></div>
<div class="text-center"><button type="submit">Save</button></div>
</form>
<p class="text-center"><a href="/profile">Back to profile</a></p>
</div>
</div>
</div>
</div>
</div>
{{template "footer" .}}
+26
View File
@@ -0,0 +1,26 @@
{{template "header" .}}
{{template "navbar" .}}
<div class="container">
<h2>Profile</h2>
{{template "alarm" .}}
<div class="row">
<div class="col-3 mx-auto">
<div class="card">
<div class="card-header">Change Password</div>
<div class="card-b">
<form method="post" action="/profile/password">
{{template "csrf" .}}
<div class="form-group"><label for="old_password">Current password</label><input type="password" class="w-100" id="old_password" name="old_password" required></div>
<div class="form-group"><label for="new_password">New password</label><input type="password" class="w-100" id="new_password" name="new_password" required minlength="6"></div>
<div class="form-group"><label for="confirm_password">Confirm new password</label><input type="password" class="w-100" id="confirm_password" name="confirm_password" required minlength="6"></div>
<div class="text-center"><button type="submit">Change Password</button></div>
</form>
<p class="text-center"><a href="/profile">Back to profile</a></p>
</div>
</div>
</div>
</div>
</div>
{{template "footer" .}}
+31
View File
@@ -0,0 +1,31 @@
{{template "header" .}}
{{template "navbar" .}}
<div class="container">
<h2>Profile</h2>
{{template "alarm" .}}
<div class="row">
<div class="col-3">
<div class="card">
<div class="card-header">Info</div>
<div class="card-b">
<p><img src="/avatar/{{.User.Id}}" onerror="this.src='/static/default.jpg'; this.onerror=null;" width="128" height="128" alt="Avatar" class="mx-auto"></p>
<p><strong>Login:</strong> {{.User.Login}}</p>
<p><strong>Display name:</strong> {{.User.EffectiveDisplayName}}</p>
{{if .User.SuperUser}}<p><strong>Super User:</strong> Yes</p>{{end}}
</div>
</div>
</div>
<div class="col-3">
<div class="card">
<div class="card-header">Actions</div>
<div class="card-b">
<p><a href="/profile/edit">Edit Profile</a></p>
<p><a href="/profile/password">Change Password</a></p>
</div>
</div>
</div>
</div>
</div>
{{template "footer" .}}
+24
View File
@@ -0,0 +1,24 @@
{{template "header" .}}
{{template "navbar" .}}
<div class="container">
<h2>External redirect</h2>
<div class="row">
<div class="col-3 mx-auto">
<div class="card">
<div class="card-header">Warning</div>
<div class="card-b">
<p>You are about to leave this site and go to:</p>
<p><strong>{{.Redirect}}</strong></p>
<p>Do you want to continue?</p>
<form method="get" action="{{.Redirect}}">
<button type="submit">Yes, go there</button>
</form>
<p><a href="/">No, stay here</a></p>
</div>
</div>
</div>
</div>
</div>
{{template "footer" .}}
+52
View File
@@ -0,0 +1,52 @@
{{template "header" .}}
{{template "navbar" .}}
<div class="container">
<h2>Sessions</h2>
<div class="row">
<div class="col-6">
<div class="card">
<div class="card-header">Your Sessions ({{len .Sessions}})</div>
<div class="card-b">
{{template "alarm" .}}
<table class="table">
<thead>
<tr><th>Token</th><th>Device</th><th>Address</th><th>Created At</th><th></th></tr>
</thead>
<tbody>
{{range .Sessions}}
<tr>
<td>{{printf "%.8s" .Token}}...</td>
<td>{{.Device}}</td>
<td>{{.Address}}</td>
<td>{{.CreatedAtLocal}}</td>
<td>
<form method="post" action="/sessions/end">
{{template "csrf" $}}
<input type="hidden" name="token" value="{{.Token}}">
<button type="submit">End</button>
</form>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
</div>
<div class="col-6">
<div class="card">
<div class="card-header">Actions</div>
<div class="card-b">
<form method="post" action="/sessions/end-all">
{{template "csrf" .}}
<div class="text-center"><button type="submit">End All Sessions</button></div>
</form>
</div>
</div>
</div>
</div>
</div>
{{template "footer" .}}
+53
View File
@@ -0,0 +1,53 @@
{{template "header" .}}
{{template "navbar" .}}
<div class="container">
{{if not .IsSuperUser}}
<div class="alert alert-err">403 Forbidden</div>
{{else}}
<h2>Users</h2>
<div class="row">
<div class="col-6">
<div class="card">
<div class="card-header">Users</div>
<div class="card-b">
{{template "alarm" .}}
<table class="table">
<thead>
<tr><th>ID</th><th>Login</th><th>Display Name</th><th>Super User</th><th>Reset Password</th><th>Sessions</th></tr>
</thead>
<tbody>
{{range .Users}}
<tr>
<td>{{.Id}}</td>
<td>{{.Login}}</td>
<td>{{.EffectiveDisplayName}}</td>
<td>{{if .SuperUser}}Yes{{else}}No{{end}}</td>
<td>
<form method="post" action="/users/reset-password" style="display:inline;">
{{template "csrf" $}}
<input type="hidden" name="user_id" value="{{.Id}}">
<input type="password" name="new_password" placeholder="New password" required minlength="6">
<button type="submit">Reset</button>
</form>
</td>
<td>
<form method="post" action="/users/end-sessions" style="display:inline;">
{{template "csrf" $}}
<input type="hidden" name="user_id" value="{{.Id}}">
<button type="submit">End Sessions</button>
</form>
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
</div>
</div>
</div>
{{end}}
</div>
{{template "footer" .}}