Initial commit: AegisSight-Monitor-Verwaltung
Dieser Commit ist enthalten in:
129
src/routers/licenses.py
Normale Datei
129
src/routers/licenses.py
Normale Datei
@@ -0,0 +1,129 @@
|
||||
"""Lizenz-CRUD."""
|
||||
from datetime import datetime, timedelta, timezone
|
||||
from fastapi import APIRouter, Depends, HTTPException, status
|
||||
from models import LicenseCreate, LicenseResponse
|
||||
from auth import get_current_admin
|
||||
from database import db_dependency
|
||||
import aiosqlite
|
||||
|
||||
router = APIRouter(prefix="/api/licenses", tags=["licenses"])
|
||||
|
||||
|
||||
@router.get("", response_model=list[LicenseResponse])
|
||||
async def list_licenses(
|
||||
org_id: int = None,
|
||||
admin: dict = Depends(get_current_admin),
|
||||
db: aiosqlite.Connection = Depends(db_dependency),
|
||||
):
|
||||
if org_id:
|
||||
cursor = await db.execute(
|
||||
"SELECT * FROM licenses WHERE organization_id = ? ORDER BY created_at DESC",
|
||||
(org_id,),
|
||||
)
|
||||
else:
|
||||
cursor = await db.execute("SELECT * FROM licenses ORDER BY created_at DESC")
|
||||
return [dict(row) for row in await cursor.fetchall()]
|
||||
|
||||
|
||||
@router.post("", response_model=LicenseResponse, status_code=status.HTTP_201_CREATED)
|
||||
async def create_license(
|
||||
data: LicenseCreate,
|
||||
admin: dict = Depends(get_current_admin),
|
||||
db: aiosqlite.Connection = Depends(db_dependency),
|
||||
):
|
||||
# Org pruefen
|
||||
cursor = await db.execute(
|
||||
"SELECT id FROM organizations WHERE id = ?", (data.organization_id,)
|
||||
)
|
||||
if not await cursor.fetchone():
|
||||
raise HTTPException(status_code=404, detail="Organisation nicht gefunden")
|
||||
|
||||
# Bestehende aktive Lizenz widerrufen
|
||||
await db.execute(
|
||||
"UPDATE licenses SET status = 'revoked' WHERE organization_id = ? AND status = 'active'",
|
||||
(data.organization_id,),
|
||||
)
|
||||
|
||||
now = datetime.now(timezone.utc)
|
||||
valid_from = now.isoformat()
|
||||
valid_until = None
|
||||
|
||||
if data.license_type == "permanent":
|
||||
valid_until = None
|
||||
elif data.duration_days:
|
||||
valid_until = (now + timedelta(days=data.duration_days)).isoformat()
|
||||
elif data.license_type == "trial":
|
||||
valid_until = (now + timedelta(days=14)).isoformat()
|
||||
elif data.license_type == "annual":
|
||||
valid_until = (now + timedelta(days=365)).isoformat()
|
||||
|
||||
cursor = await db.execute(
|
||||
"""INSERT INTO licenses (organization_id, license_type, max_users, valid_from, valid_until, status)
|
||||
VALUES (?, ?, ?, ?, ?, 'active')""",
|
||||
(data.organization_id, data.license_type, data.max_users, valid_from, valid_until),
|
||||
)
|
||||
await db.commit()
|
||||
|
||||
cursor = await db.execute("SELECT * FROM licenses WHERE id = ?", (cursor.lastrowid,))
|
||||
return dict(await cursor.fetchone())
|
||||
|
||||
|
||||
@router.put("/{license_id}/revoke")
|
||||
async def revoke_license(
|
||||
license_id: int,
|
||||
admin: dict = Depends(get_current_admin),
|
||||
db: aiosqlite.Connection = Depends(db_dependency),
|
||||
):
|
||||
cursor = await db.execute("SELECT * FROM licenses WHERE id = ?", (license_id,))
|
||||
lic = await cursor.fetchone()
|
||||
if not lic:
|
||||
raise HTTPException(status_code=404, detail="Lizenz nicht gefunden")
|
||||
|
||||
await db.execute("UPDATE licenses SET status = 'revoked' WHERE id = ?", (license_id,))
|
||||
await db.commit()
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
@router.put("/{license_id}/extend")
|
||||
async def extend_license(
|
||||
license_id: int,
|
||||
days: int = 365,
|
||||
admin: dict = Depends(get_current_admin),
|
||||
db: aiosqlite.Connection = Depends(db_dependency),
|
||||
):
|
||||
cursor = await db.execute("SELECT * FROM licenses WHERE id = ?", (license_id,))
|
||||
lic = await cursor.fetchone()
|
||||
if not lic:
|
||||
raise HTTPException(status_code=404, detail="Lizenz nicht gefunden")
|
||||
|
||||
if lic["valid_until"]:
|
||||
base = datetime.fromisoformat(lic["valid_until"])
|
||||
else:
|
||||
base = datetime.now(timezone.utc)
|
||||
|
||||
new_until = (base + timedelta(days=days)).isoformat()
|
||||
await db.execute(
|
||||
"UPDATE licenses SET valid_until = ?, status = 'active' WHERE id = ?",
|
||||
(new_until, license_id),
|
||||
)
|
||||
await db.commit()
|
||||
return {"ok": True, "valid_until": new_until}
|
||||
|
||||
|
||||
@router.get("/expiring")
|
||||
async def get_expiring_licenses(
|
||||
days: int = 30,
|
||||
admin: dict = Depends(get_current_admin),
|
||||
db: aiosqlite.Connection = Depends(db_dependency),
|
||||
):
|
||||
"""Lizenzen die in den naechsten X Tagen ablaufen."""
|
||||
cursor = await db.execute(
|
||||
"""SELECT l.*, o.name as org_name FROM licenses l
|
||||
JOIN organizations o ON o.id = l.organization_id
|
||||
WHERE l.status = 'active'
|
||||
AND l.valid_until IS NOT NULL
|
||||
AND l.valid_until < datetime('now', '+' || ? || ' days')
|
||||
ORDER BY l.valid_until""",
|
||||
(days,),
|
||||
)
|
||||
return [dict(row) for row in await cursor.fetchall()]
|
||||
In neuem Issue referenzieren
Einen Benutzer sperren