Fix audit log target for deleted users + create user 500 error
1. Audit log: COALESCE target_username with detail JSON fallback so
deleted users still show their username in the target column
(target_user_id is SET NULL by FK cascade, but detail JSON
preserves the username).
2. Create/get user: add exclude={"active_sessions"} to model_dump()
calls — UserListItem defaults active_sessions=0, so model_dump()
includes it, then the explicit active_sessions=N keyword argument
causes a duplicate keyword TypeError. DB commit already happened,
so the user exists but the response was a 500.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
48e15fa677
commit
c3654dc069
@ -16,6 +16,7 @@ from typing import Optional
|
||||
|
||||
import sqlalchemy as sa
|
||||
from fastapi import APIRouter, Depends, HTTPException, Path, Query, Request
|
||||
from sqlalchemy.dialects.postgresql import JSONB
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from app.database import get_db
|
||||
@ -58,6 +59,22 @@ router = APIRouter(
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Audit log helper — resolve target username even for deleted users
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _target_username_col(target_alias, audit_model):
|
||||
"""
|
||||
COALESCE: prefer the live username from the users table,
|
||||
fall back to the username stored in the audit detail JSON
|
||||
(survives user deletion since audit_log.target_user_id → SET NULL).
|
||||
"""
|
||||
return sa.func.coalesce(
|
||||
target_alias.username,
|
||||
sa.cast(audit_model.detail, JSONB)["username"].as_string(),
|
||||
).label("target_username")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Session revocation helper (used in multiple endpoints)
|
||||
# ---------------------------------------------------------------------------
|
||||
@ -152,7 +169,7 @@ async def get_user(
|
||||
active_sessions = session_result.scalar_one()
|
||||
|
||||
return UserDetailResponse(
|
||||
**UserListItem.model_validate(user).model_dump(),
|
||||
**UserListItem.model_validate(user).model_dump(exclude={"active_sessions"}),
|
||||
active_sessions=active_sessions,
|
||||
)
|
||||
|
||||
@ -197,7 +214,7 @@ async def create_user(
|
||||
await db.commit()
|
||||
|
||||
return UserDetailResponse(
|
||||
**UserListItem.model_validate(new_user).model_dump(),
|
||||
**UserListItem.model_validate(new_user).model_dump(exclude={"active_sessions"}),
|
||||
active_sessions=0,
|
||||
)
|
||||
|
||||
@ -668,7 +685,7 @@ async def admin_dashboard(
|
||||
sa.select(
|
||||
AuditLog,
|
||||
actor_user.username.label("actor_username"),
|
||||
target_user.username.label("target_username"),
|
||||
_target_username_col(target_user, AuditLog),
|
||||
)
|
||||
.outerjoin(actor_user, AuditLog.actor_user_id == actor_user.id)
|
||||
.outerjoin(target_user, AuditLog.target_user_id == target_user.id)
|
||||
@ -722,7 +739,7 @@ async def get_audit_log(
|
||||
sa.select(
|
||||
AuditLog,
|
||||
actor_user.username.label("actor_username"),
|
||||
target_user.username.label("target_username"),
|
||||
_target_username_col(target_user, AuditLog),
|
||||
)
|
||||
.outerjoin(actor_user, AuditLog.actor_user_id == actor_user.id)
|
||||
.outerjoin(target_user, AuditLog.target_user_id == target_user.id)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user