STABLE: Final schema sync, optimized gitignore

This commit is contained in:
Kincses
2026-02-26 08:19:25 +01:00
parent 893f39fa15
commit 505543330a
203 changed files with 11590 additions and 9542 deletions

View File

@@ -1,3 +1,4 @@
# /opt/docker/dev/service_finder/backend/app/api/v1/endpoints/admin.py
from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func, text, delete
@@ -5,11 +6,12 @@ from typing import List, Any, Dict, Optional
from datetime import datetime, timedelta
from app.api import deps
from app.models.identity import User, UserRole
from app.models.identity import User, UserRole # JAVÍTVA: Központi import
from app.models.system import SystemParameter
# JAVÍTVA: Security audit modellek
from app.models.audit import SecurityAuditLog, OperationalLog
# JAVÍTVA: Ezek a modellek a security.py-ból jönnek (ha ott vannak)
from app.models.security import PendingAction, ActionStatus
from app.models.history import AuditLog, LogSeverity
from app.schemas.admin_security import PendingActionResponse, SecurityStatusResponse
from app.services.security_service import security_service
from app.services.translation_service import TranslationService
@@ -24,30 +26,23 @@ class ConfigUpdate(BaseModel):
router = APIRouter()
# --- 🛡️ ADMIN JOGOSULTSÁG ELLENŐRZŐ ---
async def check_admin_access(current_user: User = Depends(deps.get_current_active_user)):
"""Szigorú hozzáférés-ellenőrzés: Csak Admin vagy Superadmin."""
""" Csak Admin vagy Superadmin. """
if current_user.role not in [UserRole.admin, UserRole.superadmin]:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Sentinel jogosultság szükséges a művelethez!"
detail="Sentinel jogosultság szükséges!"
)
return current_user
# --- 🛰️ 1. SENTINEL: RENDSZERÁLLAPOT ÉS MONITORING ---
@router.get("/health-monitor", tags=["Sentinel Monitoring"])
async def get_system_health(
db: AsyncSession = Depends(deps.get_db),
admin: User = Depends(check_admin_access)
):
"""
Rendszer pulzusának ellenőrzése (pgAdmin nélkül).
Látod a felhasználók eloszlását, az eszközök számát és a kritikus hibákat.
"""
stats = {}
# Adatbázis statisztikák (Dynamic counts)
# Adatbázis statisztikák (Nyers SQL marad, mert hatékony)
user_stats = await db.execute(text("SELECT subscription_plan, count(*) FROM data.users GROUP BY subscription_plan"))
stats["user_distribution"] = {row[0]: row[1] for row in user_stats}
@@ -57,24 +52,24 @@ async def get_system_health(
org_count = await db.execute(text("SELECT count(*) FROM data.organizations"))
stats["total_organizations"] = org_count.scalar()
# Biztonsági státusz (Kritikus logok az elmúlt 24 órában)
# JAVÍTVA: Biztonsági státusz az új SecurityAuditLog alapján
day_ago = datetime.now() - timedelta(days=1)
crit_logs = await db.execute(select(func.count(AuditLog.id)).where(
AuditLog.severity.in_([LogSeverity.critical, LogSeverity.emergency]),
AuditLog.timestamp >= day_ago
))
crit_logs = await db.execute(
select(func.count(SecurityAuditLog.id))
.where(
SecurityAuditLog.is_critical == True,
SecurityAuditLog.created_at >= day_ago
)
)
stats["critical_alerts_24h"] = crit_logs.scalar() or 0
return stats
# --- ⚖️ 2. SENTINEL: NÉGY SZEM ELV (Approval System) ---
@router.get("/pending-actions", response_model=List[PendingActionResponse], tags=["Sentinel Security"])
@router.get("/pending-actions", response_model=List[Any], tags=["Sentinel Security"])
async def list_pending_actions(
db: AsyncSession = Depends(deps.get_db),
admin: User = Depends(check_admin_access)
):
"""Jóváhagyásra váró kritikus kérések listázása (pl. törlések, rang-emelések)."""
stmt = select(PendingAction).where(PendingAction.status == ActionStatus.pending)
result = await db.execute(stmt)
return result.scalars().all()
@@ -85,33 +80,26 @@ async def approve_action(
db: AsyncSession = Depends(deps.get_db),
admin: User = Depends(check_admin_access)
):
"""Művelet véglegesítése. Csak egy második admin hagyhatja jóvá az első kérését."""
try:
await security_service.approve_action(db, admin.id, action_id)
return {"status": "success", "message": "Művelet sikeresen végrehajtva."}
return {"status": "success", "message": "Művelet végrehajtva."}
except Exception as e:
raise HTTPException(status_code=400, detail=str(e))
# --- ⚙️ 3. DINAMIKUS KONFIGURÁCIÓ (Hierarchical Config) ---
@router.get("/parameters", tags=["Dynamic Configuration"])
async def list_all_parameters(
db: AsyncSession = Depends(deps.get_db),
admin: User = Depends(check_admin_access)
):
"""Minden globális és lokális paraméter (Limitek, XP szorzók stb.) lekérése."""
result = await db.execute(select(SystemParameter))
return result.scalars().all()
@router.post("/parameters", tags=["Dynamic Configuration"])
async def set_parameter(
config: ConfigUpdate, # <--- Most már egy objektumot várunk a Body-ban
config: ConfigUpdate,
db: AsyncSession = Depends(deps.get_db),
admin: User = Depends(check_admin_access)
):
"""
Paraméter beállítása. A Swaggerben most már látsz egy JSON ablakot a 'value' számára!
"""
query = text("""
INSERT INTO data.system_parameters (key, value, scope_level, scope_id, category, last_modified_by)
VALUES (:key, :val, :sl, :sid, :cat, :user)
@@ -125,7 +113,7 @@ async def set_parameter(
await db.execute(query, {
"key": config.key,
"val": config.value, # Itt bármilyen komplex JSON-t átadhatsz
"val": config.value,
"sl": config.scope_level,
"sid": config.scope_id,
"cat": config.category,
@@ -134,31 +122,10 @@ async def set_parameter(
await db.commit()
return {"status": "success", "message": f"'{config.key}' frissítve."}
@router.delete("/parameters/{key}", tags=["Dynamic Configuration"])
async def delete_parameter(
key: str,
scope_level: str = "global",
scope_id: Optional[str] = None,
db: AsyncSession = Depends(deps.get_db),
admin: User = Depends(check_admin_access)
):
"""Egy adott konfiguráció törlése (visszaállás az eggyel magasabb szintű alapértelmezésre)."""
stmt = delete(SystemParameter).where(
SystemParameter.key == key,
SystemParameter.scope_level == scope_level,
SystemParameter.scope_id == scope_id
)
await db.execute(stmt)
await db.commit()
return {"status": "success", "message": "Konfiguráció törölve."}
# --- 🌍 4. UTILITY: FORDÍTÁSOK ---
@router.post("/translations/sync", tags=["System Utilities"])
async def sync_translations_to_json(
db: AsyncSession = Depends(deps.get_db),
admin: User = Depends(check_admin_access)
):
"""Szinkronizálja az adatbázisban tárolt fordításokat a JSON fájlokba."""
await TranslationService.export_to_json(db)
return {"message": "JSON nyelvi fájlok frissítve a fájlrendszerben."}
return {"message": "JSON fájlok frissítve."}