api/routers/auth.py
2025-11-14 14:47:19 +00:00

140 lines
4.7 KiB
Python

from fastapi import APIRouter, Request, Response, HTTPException, Form, Body
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.templating import Jinja2Templates
from typing import Dict
import os
from modules.logger_tool import initialise_logger
from modules.database.services.admin_service import AdminService
from modules.database.services.auth_service import auth_service
router = APIRouter()
templates = Jinja2Templates(directory="templates")
logger = initialise_logger(__name__, os.getenv("LOG_LEVEL"), os.getenv("LOG_PATH"), 'default', True)
# Initialize services
admin_service = AdminService()
async def verify_admin(request: Request) -> Dict:
"""Verify that the user is an admin and has necessary permissions"""
session = request.cookies.get("sb-access-token")
return await auth_service.verify_admin(session)
@router.get("/admin", response_class=HTMLResponse)
async def admin_root(request: Request):
"""Root admin route - redirects to login or dashboard"""
try:
admin = await verify_admin(request)
return RedirectResponse(url="/api/admin/", status_code=303)
except HTTPException:
# Check if super admin exists
has_super_admin = await auth_service.check_super_admin_exists()
if not has_super_admin:
return RedirectResponse(url="/api/admin/login?init=true", status_code=303)
return RedirectResponse(url="/api/admin/login", status_code=303)
@router.get("/admin/login", response_class=HTMLResponse)
async def login_page(
request: Request,
error: str = None,
success: str = None,
init: bool = False
):
"""Render admin login page"""
# Check if super admin exists
has_super_admin = await auth_service.check_super_admin_exists()
# If no super admin and init flag is true, show initialization form
if not has_super_admin:
expected_email = os.getenv("ADMIN_EMAIL")
return templates.TemplateResponse(
"admin/login.html",
{
"request": request,
"error": error,
"success": success,
"init_super_admin": True,
"expected_super_admin_email": expected_email
}
)
return templates.TemplateResponse(
"admin/login.html",
{
"request": request,
"error": error,
"success": success,
"init_super_admin": False
}
)
@router.post("/admin/login")
async def login(
request: Request,
response: Response,
email: str = Form(...),
password: str = Form(...)
):
"""Handle admin login"""
try:
# Login with auth service
auth_result = await auth_service.login_admin(email, password)
# Set session cookie and redirect
response = RedirectResponse(url="/api/admin/", status_code=303)
response.set_cookie(
"sb-access-token",
auth_result["access_token"],
httponly=True,
secure=True
)
return response
except HTTPException as e:
return RedirectResponse(
url=f"/api/admin/login?error={str(e.detail)}",
status_code=303
)
except Exception as e:
logger.error(f"Login error: {str(e)}")
return RedirectResponse(
url=f"/api/admin/login?error={str(e)}",
status_code=303
)
@router.post("/admin/logout")
async def logout(response: Response):
"""Handle admin logout"""
try:
response = RedirectResponse(url="/api/admin/login", status_code=303)
response.delete_cookie("sb-access-token")
return response
except Exception as e:
logger.error(f"Logout error: {str(e)}")
raise HTTPException(status_code=500, detail="Logout failed")
@router.post("/admin/initialize-super-admin")
async def initialize_super_admin(
admin_data: Dict = Body(...),
request: Request = None
):
"""Initialize the super admin account"""
try:
# Validate required fields
required_fields = ["email", "password", "display_name"]
for field in required_fields:
if field not in admin_data:
raise HTTPException(status_code=400, detail=f"Missing required field: {field}")
# Set up super admin
admin_service = AdminService()
result = admin_service.setup_super_admin(admin_data)
return {
"status": "success",
"message": "Super admin account created successfully! Please log in with your credentials.",
"admin": result
}
except Exception as e:
logger.error(f"Error initializing super admin: {str(e)}")
raise HTTPException(status_code=500, detail=str(e))