Feat: Implement basic web authentication and UI
This commit introduces the foundation for web-based authentication and user interface. It includes: - **Session Management**: Securely handling user sessions using cryptographically generated tokens, cookies with appropriate security flags, and server-side storage. - **Login/Logout Functionality**: Endpoints for users to log in with their credentials and log out, clearing their session. - **User Interface**: Basic templates for the login page, a list of cases, and a detailed view of a single case, allowing users to navigate and view their data. - **Authorization**: An `AuthenticatedWebUser` extractor to ensure only logged-in users can access protected web routes. - **Configuration**: Added a `cookie_secure` option to the configuration to control the `Secure` flag on session cookies, useful for local development. - **Dependencies**: Added necessary dependencies for password hashing, time handling, and TOML file manipulation. - **Helper Binary**: Included a `hash-password` binary to simplify generating bcrypt hashes for user passwords.
This commit is contained in:
@@ -0,0 +1,66 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="de">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Doctate — Meine Fälle</title>
|
||||
<style>
|
||||
body { font-family: sans-serif; max-width: 900px; margin: 2em auto; padding: 0 1em; }
|
||||
header { display: flex; justify-content: space-between; align-items: center; }
|
||||
header form { margin: 0; }
|
||||
.case { border: 1px solid #ccc; margin: 0.8em 0; padding: 0.8em 1em; border-radius: 4px; display: block; text-decoration: none; color: inherit; }
|
||||
.case:hover { background: #f6f6f6; }
|
||||
.case h2 { margin: 0 0 0.3em 0; font-size: 1em; }
|
||||
.case small { color: #666; font-family: monospace; }
|
||||
.status-open { border-left: 4px solid #4a90e2; }
|
||||
.status-done { border-left: 4px solid #7ed321; }
|
||||
.oneliner { font-size: 1em; color: #333; margin: 0.2em 0; }
|
||||
section { margin: 1.5em 0; }
|
||||
section h2 { font-size: 1.1em; color: #555; border-bottom: 1px solid #ddd; padding-bottom: 0.2em; }
|
||||
.empty { color: #888; font-style: italic; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>{{ slug }} — Meine Fälle</h1>
|
||||
<form method="post" action="/web/logout"><button type="submit">Logout</button></form>
|
||||
</header>
|
||||
|
||||
<section>
|
||||
<h2>Offen ({{ open.len() }})</h2>
|
||||
{% if open.is_empty() %}
|
||||
<p class="empty">Keine offenen Fälle.</p>
|
||||
{% else %}
|
||||
{% for case in open %}
|
||||
<a class="case status-{{ case.status }}" href="/web/cases/{{ case.case_id }}">
|
||||
<h2>{{ case.case_id_short }} — {{ case.recordings.len() }} Aufnahme(n)</h2>
|
||||
{% match case.oneliner %}
|
||||
{% when Some with (t) %}
|
||||
<div class="oneliner">{{ t }}</div>
|
||||
{% when None %}
|
||||
{% endmatch %}
|
||||
<small>{{ case.most_recent }}</small>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<h2>Abgeschlossen ({{ done.len() }})</h2>
|
||||
{% if done.is_empty() %}
|
||||
<p class="empty">Keine abgeschlossenen Fälle.</p>
|
||||
{% else %}
|
||||
{% for case in done %}
|
||||
<a class="case status-{{ case.status }}" href="/web/cases/{{ case.case_id }}">
|
||||
<h2>{{ case.case_id_short }} — {{ case.recordings.len() }} Aufnahme(n)</h2>
|
||||
{% match case.oneliner %}
|
||||
{% when Some with (t) %}
|
||||
<div class="oneliner">{{ t }}</div>
|
||||
{% when None %}
|
||||
{% endmatch %}
|
||||
<small>{{ case.most_recent }}</small>
|
||||
</a>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</section>
|
||||
</body>
|
||||
</html>
|
||||
Reference in New Issue
Block a user