"""Auth HTTP routes.""" from typing import List, Optional from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel, Field from backend.auth.deps import get_current_user, require_admin from backend.auth.models import ROLES, UserContext from backend.auth import database as db from backend.auth.service import ( authenticate, create_org_user, create_personal_project, delete_personal_project, get_user_context, list_accessible_projects, normalize_project_slug, update_user_projects, user_to_dict, ) from src.config import load_config router = APIRouter(prefix="/api/auth", tags=["auth"]) admin_router = APIRouter(prefix="/api/admin", tags=["admin"]) class LoginRequest(BaseModel): org_slug: str = Field(default="merakom") username: str password: str class CreateUserRequest(BaseModel): username: str password: str role: str = "user" projects: List[str] = Field(default_factory=list) class CreateProjectRequest(BaseModel): slug: str name: str class UpdateUserProjectsRequest(BaseModel): projects: List[str] = Field(default_factory=list) @router.post("/login") async def login(payload: LoginRequest): result = authenticate(payload.org_slug, payload.username, payload.password) if not result: raise HTTPException(status_code=401, detail="Неверная организация, логин или пароль") return result @router.get("/me") async def me(user: UserContext = Depends(get_current_user)): return user_to_dict(user) @router.get("/projects") async def my_projects(user: UserContext = Depends(get_current_user)): return {"projects": list_accessible_projects(user)} @router.post("/projects") async def create_my_project(payload: CreateProjectRequest, user: UserContext = Depends(get_current_user)): try: project = create_personal_project(user, payload.slug, payload.name) return {"project": project} except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) from e except Exception as e: if "UNIQUE" in str(e): raise HTTPException(status_code=409, detail="Проект уже существует") from e raise HTTPException(status_code=400, detail=str(e)) from e @router.delete("/projects/{slug}") async def delete_my_project(slug: str, user: UserContext = Depends(get_current_user)): try: delete_personal_project(user, slug) return {"deleted": slug} except PermissionError as e: raise HTTPException(status_code=403, detail=str(e)) from e except ValueError as e: raise HTTPException(status_code=404, detail=str(e)) from e @admin_router.get("/users") async def admin_list_users(admin: UserContext = Depends(require_admin)): config = load_config() rows = db.list_users(admin.org_id, config) users = [] for row in rows: ctx = get_user_context(row["id"]) if ctx: users.append(user_to_dict(ctx)) return {"users": users} @admin_router.post("/users") async def admin_create_user(payload: CreateUserRequest, admin: UserContext = Depends(require_admin)): if payload.role not in ROLES: raise HTTPException(status_code=400, detail=f"role must be one of: {', '.join(ROLES)}") try: user = create_org_user(admin, payload.username, payload.password, payload.role, payload.projects) return {"user": user} except Exception as e: if "UNIQUE" in str(e): raise HTTPException(status_code=409, detail="Пользователь уже существует") from e raise HTTPException(status_code=400, detail=str(e)) from e @admin_router.put("/users/{user_id}/projects") async def admin_set_user_projects( user_id: int, payload: UpdateUserProjectsRequest, admin: UserContext = Depends(require_admin), ): try: user = update_user_projects(admin, user_id, payload.projects) return {"user": user} except ValueError as e: raise HTTPException(status_code=404, detail=str(e)) from e @admin_router.get("/projects") async def admin_list_projects(admin: UserContext = Depends(require_admin)): config = load_config() return {"projects": db.list_projects(admin.org_id, config)} @admin_router.post("/projects") async def admin_create_project(payload: CreateProjectRequest, admin: UserContext = Depends(require_admin)): try: slug = normalize_project_slug(payload.slug) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) from e display_name = payload.name.strip() or slug try: project = db.create_project(admin.org_id, slug, display_name, owner_user_id=None, config=load_config()) return {"project": project} except Exception as e: if "UNIQUE" in str(e): raise HTTPException(status_code=409, detail="Проект уже существует") from e raise HTTPException(status_code=400, detail=str(e)) from e