## Copyright © 2026 Olaf Kolkman ## SPDX-License-Identifier: GPL-3.0-or-later from uuid import uuid4 from fastapi import APIRouter, HTTPException from pydantic import BaseModel from backend.app.core.config import settings from backend.app.database import get_connection, hash_password from backend.app.services.email_service import save_smtp_settings, send_test_email router = APIRouter() class SetupRequest(BaseModel): username: str email: str password: str smtp_host: str smtp_port: int = 587 smtp_username: str = '' smtp_password: str = '' smtp_from: str smtp_use_tls: bool = True def has_administrator() -> bool: with get_connection() as conn: return conn.execute('SELECT 1 FROM users WHERE is_admin = 1 LIMIT 1').fetchone() is not None @router.post('', status_code=201) def configure_application(payload: SetupRequest): if has_administrator(): raise HTTPException(status_code=409, detail='LinkLog is already configured') username = payload.username.strip() email = payload.email.strip() smtp_host = payload.smtp_host.strip() smtp_from = payload.smtp_from.strip() if not username or not email or not smtp_host or not smtp_from or len(payload.password) < 8: raise HTTPException(status_code=422, detail='Admin credentials and SMTP settings are required') if not 1 <= payload.smtp_port <= 65535: raise HTTPException(status_code=422, detail='SMTP port must be between 1 and 65535') user_id = str(uuid4()) smtp_values = { 'smtp_host': smtp_host, 'smtp_port': payload.smtp_port, 'smtp_username': payload.smtp_username.strip(), 'smtp_password': payload.smtp_password, 'smtp_from': smtp_from, 'smtp_use_tls': payload.smtp_use_tls, } with get_connection() as conn: try: conn.execute( '''INSERT INTO users (id, username, email, password_hash, is_admin, email_verified) VALUES (?, ?, ?, ?, 1, 1)''', (user_id, username, email, hash_password(payload.password)), ) except Exception as error: raise HTTPException(status_code=409, detail='Username or email already exists') from error conn.commit() save_smtp_settings(smtp_values) try: send_test_email(email) except Exception as error: with get_connection() as conn: conn.execute('DELETE FROM users WHERE id = ?', (user_id,)) conn.execute('DELETE FROM app_settings WHERE name = ?', ('smtp',)) conn.commit() raise HTTPException(status_code=503, detail=f'SMTP test mail could not be sent: {error}') from error return {'status': 'configured', 'message': 'LinkLog is configured and the SMTP test mail was sent.'} @router.get('/status') def setup_status(): return {'configured': has_administrator()}