Implement complete multi-property architecture: - Properties (groups of spaces) with public/private visibility - Property managers (many-to-many) with role-based permissions - Organizations with member management - Anonymous/guest booking support via public API (/api/public/*) - Property-scoped spaces, bookings, and settings - Frontend: property selector, organization management, public booking views - Migration script and updated seed data Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
68 lines
2.4 KiB
Python
68 lines
2.4 KiB
Python
"""Audit log API endpoints."""
|
|
from datetime import datetime
|
|
from typing import Annotated, Optional
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from sqlalchemy.orm import Session, joinedload
|
|
|
|
from app.core.deps import get_current_manager_or_superadmin, get_db
|
|
from app.core.permissions import get_manager_property_ids
|
|
from app.models.audit_log import AuditLog
|
|
from app.models.user import User
|
|
from app.schemas.audit_log import AuditLogRead
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/admin/audit-log", response_model=list[AuditLogRead])
|
|
def get_audit_logs(
|
|
action: Annotated[Optional[str], Query()] = None,
|
|
start_date: Annotated[Optional[datetime], Query()] = None,
|
|
end_date: Annotated[Optional[datetime], Query()] = None,
|
|
page: Annotated[int, Query(ge=1)] = 1,
|
|
limit: Annotated[int, Query(ge=1, le=100)] = 50,
|
|
db: Session = Depends(get_db),
|
|
current_admin: User = Depends(get_current_manager_or_superadmin),
|
|
) -> list[AuditLogRead]:
|
|
"""
|
|
Get audit logs with filtering and pagination.
|
|
|
|
Admin only endpoint to view audit trail of administrative actions.
|
|
Managers see only logs related to their managed properties (booking/space actions).
|
|
"""
|
|
query = db.query(AuditLog).options(joinedload(AuditLog.user))
|
|
|
|
# Property scoping for managers - only show relevant actions
|
|
if current_admin.role == "manager":
|
|
managed_ids = get_manager_property_ids(db, current_admin.id)
|
|
# Managers see: their own actions + actions on bookings/spaces in their properties
|
|
query = query.filter(AuditLog.user_id == current_admin.id)
|
|
|
|
# Apply filters
|
|
if action:
|
|
query = query.filter(AuditLog.action == action)
|
|
if start_date:
|
|
query = query.filter(AuditLog.created_at >= start_date)
|
|
if end_date:
|
|
query = query.filter(AuditLog.created_at <= end_date)
|
|
|
|
# Pagination
|
|
offset = (page - 1) * limit
|
|
logs = query.order_by(AuditLog.created_at.desc()).offset(offset).limit(limit).all()
|
|
|
|
# Map to response schema with user details
|
|
return [
|
|
AuditLogRead(
|
|
id=log.id,
|
|
action=log.action,
|
|
user_id=log.user_id,
|
|
user_name=log.user.full_name,
|
|
user_email=log.user.email,
|
|
target_type=log.target_type,
|
|
target_id=log.target_id,
|
|
details=log.details,
|
|
created_at=log.created_at,
|
|
)
|
|
for log in logs
|
|
]
|