feat: add Campaign/Compliance domain entities and extract users/audit/data_sources to services (LP-2 through LP-6)

This commit is contained in:
2026-02-20 13:28:14 +01:00
parent 44621364be
commit c0c6cda11d
11 changed files with 939 additions and 319 deletions

View File

@@ -4,14 +4,17 @@ from datetime import datetime
from typing import Optional
from fastapi import APIRouter, Depends, Query
from sqlalchemy import func
from sqlalchemy.orm import Session, joinedload
from sqlalchemy.orm import Session
from app.database import get_db
from app.dependencies.auth import require_role
from app.models.audit import AuditLog
from app.models.user import User
from app.schemas.audit import AuditLogOut, AuditLogPage
from app.services.audit_query_service import (
list_distinct_actions,
list_distinct_entity_types,
list_logs,
)
router = APIRouter(prefix="/audit-logs", tags=["audit"])
@@ -29,56 +32,25 @@ def list_audit_logs(
current_user: User = Depends(require_role("admin")),
):
"""Return paginated audit logs with optional filters.
**Requires admin role.**
"""
query = db.query(AuditLog).options(joinedload(AuditLog.user))
# Apply filters
if user_id:
query = query.filter(AuditLog.user_id == user_id)
if action:
query = query.filter(AuditLog.action == action)
if entity_type:
query = query.filter(AuditLog.entity_type == entity_type)
if start_date:
query = query.filter(AuditLog.timestamp >= start_date)
if end_date:
query = query.filter(AuditLog.timestamp <= end_date)
# Get total count
total = query.count()
# Get paginated results
logs = (
query
.order_by(AuditLog.timestamp.desc())
.offset(offset)
.limit(limit)
.all()
)
# Convert to response format with username
items = []
for log in logs:
item = AuditLogOut(
id=log.id,
user_id=log.user_id,
username=log.user.username if log.user else None,
action=log.action,
entity_type=log.entity_type,
entity_id=log.entity_id,
timestamp=log.timestamp,
details=log.details,
)
items.append(item)
return AuditLogPage(
items=items,
total=total,
result = list_logs(
db,
user_id=user_id,
action=action,
entity_type=entity_type,
start_date=start_date,
end_date=end_date,
offset=offset,
limit=limit,
)
return AuditLogPage(
items=[AuditLogOut(**item) for item in result["items"]],
total=result["total"],
offset=result["offset"],
limit=result["limit"],
)
@router.get("/actions", response_model=list[str])
@@ -87,16 +59,10 @@ def list_actions(
current_user: User = Depends(require_role("admin")),
):
"""Return a list of distinct action types in the audit log.
**Requires admin role.**
"""
actions = (
db.query(AuditLog.action)
.distinct()
.order_by(AuditLog.action)
.all()
)
return [a[0] for a in actions]
return list_distinct_actions(db)
@router.get("/entity-types", response_model=list[str])
@@ -105,14 +71,7 @@ def list_entity_types(
current_user: User = Depends(require_role("admin")),
):
"""Return a list of distinct entity types in the audit log.
**Requires admin role.**
"""
types = (
db.query(AuditLog.entity_type)
.filter(AuditLog.entity_type.isnot(None))
.distinct()
.order_by(AuditLog.entity_type)
.all()
)
return [t[0] for t in types]
return list_distinct_entity_types(db)