Add public feed, admin area, self-registration, visibility & hashtags
Some checks failed
Deploy to NAS / deploy (push) Failing after 26s
Some checks failed
Deploy to NAS / deploy (push) Failing after 26s
- Public feed (/) with infinite scroll via Intersection Observer - Self-registration (/register) - Admin area (/admin/entries, /admin/users) with user management - journal_entries: visibility (public/private) + hashtags fields - users: is_admin flag - DB schema updated (recreate DB to apply) - CI: run go test via docker run (golang:1.25-alpine) — fixes 'go not found' Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
33
backend/internal/api/templates/admin/entries.html
Normal file
33
backend/internal/api/templates/admin/entries.html
Normal file
@@ -0,0 +1,33 @@
|
||||
{{define "admin_title"}}Einträge verwalten — Admin{{end}}
|
||||
|
||||
{{define "admin_content"}}
|
||||
<h1>Einträge</h1>
|
||||
<p><a href="/days">→ Neuen Eintrag anlegen (Tagesansicht)</a></p>
|
||||
|
||||
{{if .Entries}}
|
||||
<figure>
|
||||
<table>
|
||||
<thead><tr><th>Datum</th><th>Zeit</th><th>Titel</th><th>Sichtbarkeit</th><th>Hashtags</th></tr></thead>
|
||||
<tbody>
|
||||
{{range .Entries}}
|
||||
<tr>
|
||||
<td><a href="/days/{{.EntryDate}}">{{.EntryDate}}</a></td>
|
||||
<td>{{.EntryTime}}</td>
|
||||
<td>{{if .Title}}{{.Title}}{{else}}<small>—</small>{{end}}</td>
|
||||
<td>
|
||||
{{if eq .Visibility "public"}}
|
||||
<span class="badge-public">öffentlich</span>
|
||||
{{else}}
|
||||
<small>privat</small>
|
||||
{{end}}
|
||||
</td>
|
||||
<td><small>{{join .Hashtags ", "}}</small></td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</figure>
|
||||
{{else}}
|
||||
<p><small>// Noch keine Einträge</small></p>
|
||||
{{end}}
|
||||
{{end}}
|
||||
25
backend/internal/api/templates/admin/layout.html
Normal file
25
backend/internal/api/templates/admin/layout.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{{define "admin_base"}}<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<title>{{block "admin_title" .}}Admin{{end}}</title>
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@picocss/pico@2/css/pico.classless.slate.min.css">
|
||||
<link rel="stylesheet" href="/static/style.css">
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
<nav>
|
||||
<strong>Admin</strong>
|
||||
<span>
|
||||
<a href="/admin/entries">Einträge</a> ·
|
||||
<a href="/admin/users">Benutzer</a> ·
|
||||
<a href="/days">← App</a>
|
||||
</span>
|
||||
</nav>
|
||||
{{block "admin_content" .}}{{end}}
|
||||
</main>
|
||||
{{block "admin_scripts" .}}{{end}}
|
||||
</body>
|
||||
</html>
|
||||
{{end}}
|
||||
53
backend/internal/api/templates/admin/users.html
Normal file
53
backend/internal/api/templates/admin/users.html
Normal file
@@ -0,0 +1,53 @@
|
||||
{{define "admin_title"}}Benutzer verwalten — Admin{{end}}
|
||||
|
||||
{{define "admin_content"}}
|
||||
<h1>Benutzer</h1>
|
||||
|
||||
{{if .Error}}<p class="error">{{.Error}}</p>{{end}}
|
||||
|
||||
<form method="post" action="/admin/users" style="display:flex;gap:1rem;align-items:flex-end;flex-wrap:wrap">
|
||||
<div>
|
||||
<label>Benutzername</label>
|
||||
<input type="text" name="username" required autocomplete="off">
|
||||
</div>
|
||||
<div>
|
||||
<label>Passwort</label>
|
||||
<input type="password" name="password" required autocomplete="new-password">
|
||||
</div>
|
||||
<button type="submit">Anlegen</button>
|
||||
</form>
|
||||
|
||||
<figure>
|
||||
<table>
|
||||
<thead><tr><th>Benutzername</th><th>Admin</th><th>Erstellt</th><th></th></tr></thead>
|
||||
<tbody>
|
||||
{{range .Users}}
|
||||
<tr>
|
||||
<td>{{.Username}}</td>
|
||||
<td>{{if .IsAdmin}}✓{{end}}</td>
|
||||
<td><small>{{.CreatedAt.Format "2006-01-02"}}</small></td>
|
||||
<td>
|
||||
{{if ne .UserID $.User.UserID}}
|
||||
<button class="btn-delete" data-url="/admin/users/{{.UserID}}" data-name="{{.Username}}">Löschen</button>
|
||||
{{else}}
|
||||
<small>(du)</small>
|
||||
{{end}}
|
||||
</td>
|
||||
</tr>
|
||||
{{end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</figure>
|
||||
{{end}}
|
||||
|
||||
{{define "admin_scripts"}}
|
||||
<script>
|
||||
document.querySelectorAll('.btn-delete').forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
if (!confirm('Benutzer "' + btn.dataset.name + '" löschen?')) return;
|
||||
fetch(btn.dataset.url, {method: 'DELETE'})
|
||||
.then(function() { window.location.reload(); });
|
||||
});
|
||||
});
|
||||
</script>
|
||||
{{end}}
|
||||
Reference in New Issue
Block a user