"""Organisations-CRUD.""" from datetime import datetime, timezone from fastapi import APIRouter, Depends, HTTPException, status from models import OrgCreate, OrgUpdate, OrgResponse from auth import get_current_admin from database import db_dependency import aiosqlite router = APIRouter(prefix="/api/orgs", tags=["organizations"]) async def _enrich_org(db: aiosqlite.Connection, row: aiosqlite.Row) -> dict: org = dict(row) cursor = await db.execute( "SELECT COUNT(*) as cnt FROM users WHERE organization_id = ? AND is_active = 1", (org["id"],), ) org["user_count"] = (await cursor.fetchone())["cnt"] cursor = await db.execute( "SELECT license_type, status FROM licenses WHERE organization_id = ? AND status = 'active' ORDER BY created_at DESC LIMIT 1", (org["id"],), ) lic = await cursor.fetchone() org["license_status"] = lic["status"] if lic else "none" org["license_type"] = lic["license_type"] if lic else "" return org @router.get("", response_model=list[OrgResponse]) async def list_organizations( admin: dict = Depends(get_current_admin), db: aiosqlite.Connection = Depends(db_dependency), ): cursor = await db.execute("SELECT * FROM organizations ORDER BY created_at DESC") rows = await cursor.fetchall() return [await _enrich_org(db, row) for row in rows] @router.post("", response_model=OrgResponse, status_code=status.HTTP_201_CREATED) async def create_organization( data: OrgCreate, admin: dict = Depends(get_current_admin), db: aiosqlite.Connection = Depends(db_dependency), ): # Slug-Duplikat pruefen cursor = await db.execute("SELECT id FROM organizations WHERE slug = ?", (data.slug,)) if await cursor.fetchone(): raise HTTPException(status_code=400, detail="Slug bereits vergeben") now = datetime.now(timezone.utc).isoformat() cursor = await db.execute( "INSERT INTO organizations (name, slug, is_active, created_at, updated_at) VALUES (?, ?, 1, ?, ?)", (data.name, data.slug, now, now), ) await db.commit() cursor = await db.execute("SELECT * FROM organizations WHERE id = ?", (cursor.lastrowid,)) return await _enrich_org(db, await cursor.fetchone()) @router.get("/{org_id}", response_model=OrgResponse) async def get_organization( org_id: int, admin: dict = Depends(get_current_admin), db: aiosqlite.Connection = Depends(db_dependency), ): cursor = await db.execute("SELECT * FROM organizations WHERE id = ?", (org_id,)) row = await cursor.fetchone() if not row: raise HTTPException(status_code=404, detail="Organisation nicht gefunden") return await _enrich_org(db, row) @router.put("/{org_id}", response_model=OrgResponse) async def update_organization( org_id: int, data: OrgUpdate, admin: dict = Depends(get_current_admin), db: aiosqlite.Connection = Depends(db_dependency), ): cursor = await db.execute("SELECT * FROM organizations WHERE id = ?", (org_id,)) row = await cursor.fetchone() if not row: raise HTTPException(status_code=404, detail="Organisation nicht gefunden") updates = {} if data.name is not None: updates["name"] = data.name if data.is_active is not None: updates["is_active"] = 1 if data.is_active else 0 if updates: updates["updated_at"] = datetime.now(timezone.utc).isoformat() set_clause = ", ".join(f"{k} = ?" for k in updates) values = list(updates.values()) + [org_id] await db.execute(f"UPDATE organizations SET {set_clause} WHERE id = ?", values) await db.commit() cursor = await db.execute("SELECT * FROM organizations WHERE id = ?", (org_id,)) return await _enrich_org(db, await cursor.fetchone()) @router.delete("/{org_id}", status_code=status.HTTP_204_NO_CONTENT) async def delete_organization( org_id: int, admin: dict = Depends(get_current_admin), db: aiosqlite.Connection = Depends(db_dependency), ): cursor = await db.execute("SELECT * FROM organizations WHERE id = ?", (org_id,)) if not await cursor.fetchone(): raise HTTPException(status_code=404, detail="Organisation nicht gefunden") # Kaskadierendes Loeschen await db.execute("DELETE FROM organizations WHERE id = ?", (org_id,)) await db.commit()