- PostgreSQL schema: 14 tables, JSONB attributes, audit triggers, soft delete - FastAPI backend: CRUD, search/filter, relationship graph, bulk import, JWT RBAC - React frontend: CI table, detail card, force-graph, dashboard - Seed data: homelab scenario (Proxmox, Mikrotik, VMs, services) - Docker Compose + Kubernetes manifests - 20 backend tests (pytest + httpx)
49 lines
1.7 KiB
Python
49 lines
1.7 KiB
Python
from fastapi import APIRouter, Depends, HTTPException
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from sqlalchemy import select
|
|
from app.database import get_db
|
|
from app.models.models import User
|
|
from app.schemas.schemas import LoginRequest, Token, UserCreate, UserResponse
|
|
from app.middleware.auth import hash_password, verify_password, create_access_token, get_current_user, require_admin
|
|
|
|
router = APIRouter(prefix="/api/auth", tags=["auth"])
|
|
|
|
|
|
@router.post("/login", response_model=Token)
|
|
async def login(body: LoginRequest, db: AsyncSession = Depends(get_db)):
|
|
result = await db.execute(select(User).where(User.username == body.username))
|
|
user = result.scalar_one_or_none()
|
|
if not user or not verify_password(body.password, user.password_hash):
|
|
raise HTTPException(status_code=401, detail="Invalid credentials")
|
|
token = create_access_token(user.id, user.role)
|
|
return Token(access_token=token)
|
|
|
|
|
|
@router.post("/users", response_model=UserResponse)
|
|
async def create_user(
|
|
body: UserCreate,
|
|
db: AsyncSession = Depends(get_db),
|
|
_admin: User = Depends(require_admin),
|
|
):
|
|
existing = await db.execute(select(User).where(User.username == body.username))
|
|
if existing.scalar_one_or_none():
|
|
raise HTTPException(status_code=409, detail="Username already exists")
|
|
|
|
user = User(
|
|
username=body.username,
|
|
email=body.email,
|
|
full_name=body.full_name,
|
|
role=body.role,
|
|
team=body.team,
|
|
password_hash=hash_password(body.password),
|
|
)
|
|
db.add(user)
|
|
await db.flush()
|
|
await db.refresh(user)
|
|
return user
|
|
|
|
|
|
@router.get("/me", response_model=UserResponse)
|
|
async def get_me(user: User = Depends(get_current_user)):
|
|
return user
|