From 2d22158dd95f76399f5716d556be60c77da04a46 Mon Sep 17 00:00:00 2001 From: Tom van der Lee Date: Thu, 30 Jul 2026 16:03:32 +0200 Subject: Admin ui --- authentication/endpoints.py | 10 +++++++++- authentication/templates/base.html | 18 +++++++++++++++++- authentication/templates/login.html | 21 ++++++++------------- authentication/templates/register.html | 33 ++++++++++++++------------------- 4 files changed, 48 insertions(+), 34 deletions(-) (limited to 'authentication') diff --git a/authentication/endpoints.py b/authentication/endpoints.py index 6877383..3af49fc 100644 --- a/authentication/endpoints.py +++ b/authentication/endpoints.py @@ -6,6 +6,7 @@ from uuid import uuid7 from fastapi import FastAPI, Request, Form, Query from pydantic import BaseModel, ValidationError, model_validator, EmailStr +from sqlalchemy import func from sqlmodel import select from starlette.authentication import requires from starlette.middleware.authentication import AuthenticationMiddleware @@ -106,10 +107,17 @@ class RegisterForm(BaseModel): return self +def is_first_run() -> bool: + with get_session_context() as session: + user_count = session.exec(select(func.count(User.id))) + return user_count.first() == 0 + + async def base_register(request: Request, form: RegisterForm | None = None, errors: dict[str, str] | None = None): return templates.TemplateResponse(request, 'register.html', context={ 'form': form, 'errors': errors, + 'is_first_run': is_first_run(), }) @@ -145,7 +153,7 @@ async def post_register(request: Request, email: Annotated[str, Form()] = '', pa return RedirectResponse(next, status_code=303) except ValidationError as exc: - errors.update({e['loc'][0]: e['msg'] for e in exc.errors()}) + errors.update({(e['loc'][0] if e['loc'] else 'verify_password'): e['msg'] for e in exc.errors()}) return await base_register(request, form, errors) diff --git a/authentication/templates/base.html b/authentication/templates/base.html index 9874313..ae6cb64 100644 --- a/authentication/templates/base.html +++ b/authentication/templates/base.html @@ -1,4 +1,20 @@ {% extends 'global.html' %} +{% import 'macros.html' as ui %} {% block template %} - {% block content %}{% endblock %} +
+
+
+
{{ ui.connector_icon(20) }} ttun
+
+ local:3000 + {{ ui.connector_icon(20) }} + your-app.ttun.dev +
+

Self-hosted tunnel proxy. Expose a local port through a public URL you control.

+
+
+ {% block content %}{% endblock %} +
+
+
{% endblock %} diff --git a/authentication/templates/login.html b/authentication/templates/login.html index 2db2512..dcc0efd 100644 --- a/authentication/templates/login.html +++ b/authentication/templates/login.html @@ -1,18 +1,13 @@ {% extends "./base.html" %} +{% import 'macros.html' as ui %} {% block content %} +

Sign in

+

Enter your credentials to manage this server.

- - - {% if errors and errors.username %} - {{ errors.username }} - {% endif %} - - - - {% if errors and errors.password%} - {{ errors.password }} - {% endif %} - + {{ ui.field('username', label='Username', value=form.username if form else '', error=errors.username if errors else '') }} + {{ ui.field('password', type='password', label='Password', error=errors.password if errors else '') }} + {{ ui.button('Sign in') }}
-{% endblock %} +

New here? Create an account

+{% endblock %} diff --git a/authentication/templates/register.html b/authentication/templates/register.html index 576db78..a1959eb 100644 --- a/authentication/templates/register.html +++ b/authentication/templates/register.html @@ -1,24 +1,19 @@ {% extends "./base.html" %} +{% import 'macros.html' as ui %} {% block content %} + {% if is_first_run %} +

Set up your ttun server

+

This will be the first account, with full access to manage this server.

+ {% else %} +

Create your account

+

This account will be able to sign in and manage this server.

+ {% endif %}
- - - {% if errors and errors.email%} - {{ errors.email }} - {% endif %} - - - - {% if errors and errors.password%} - {{ errors.password }} - {% endif %} - - - {% if errors and errors.password%} - {{ errors.verify_password }} - {% endif %} - - + {{ ui.field('email', type='email', label='Email', value=form.email if form else '', error=errors.email if errors else '') }} + {{ ui.field('password', type='password', label='Password', error=errors.password if errors else '') }} + {{ ui.field('verify_password', type='password', label='Confirm password', error=errors.verify_password if errors else '') }} + {{ ui.button('Create account') }}
-{% endblock %} +

Already have an account? Sign in

+{% endblock %} -- cgit v1.2.3