feat(platform): add audit logs and activity feed
This commit is contained in:
parent
92cb8d1286
commit
c816e9869d
34 changed files with 1592 additions and 43 deletions
|
|
@ -2,6 +2,7 @@ import logging
|
|||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Response, status
|
||||
from sqlalchemy.orm import Session
|
||||
from starlette.requests import Request
|
||||
|
||||
from app.core.rbac import get_user_permission_names, require_permission
|
||||
from app.db.database import get_db
|
||||
|
|
@ -9,6 +10,7 @@ from app.models.user import User
|
|||
from app.repositories.rbac_repository import RbacRepository
|
||||
from app.repositories.user_repository import UserRepository
|
||||
from app.schemas.user import UserCreate, UserPasswordUpdate, UserResponse, UserUpdate
|
||||
from app.services.audit_service import sanitize, write_audit_log
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -98,6 +100,7 @@ def get_user(
|
|||
)
|
||||
def create_user(
|
||||
user: UserCreate,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_permission("users.create")),
|
||||
):
|
||||
|
|
@ -113,17 +116,30 @@ def create_user(
|
|||
raise_conflict(conflict[0])
|
||||
|
||||
logger.info("users.create", extra={"actor_user_id": current_user.id})
|
||||
return UserRepository.create(db, user)
|
||||
created_user = UserRepository.create(db, user)
|
||||
write_audit_log(
|
||||
db,
|
||||
action="users.create",
|
||||
entity_type="users",
|
||||
entity_id=created_user.id,
|
||||
entity_label=created_user.username,
|
||||
actor=current_user,
|
||||
request=request,
|
||||
after_data=created_user,
|
||||
)
|
||||
return created_user
|
||||
|
||||
|
||||
@router.put("/{user_id}", response_model=UserResponse)
|
||||
def update_user(
|
||||
user_id: int,
|
||||
user: UserUpdate,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_permission("users.update")),
|
||||
):
|
||||
db_user = get_user_or_404(db, user_id)
|
||||
before_data = sanitize(db_user)
|
||||
apply_role(db, user)
|
||||
if user.role_id != db_user.role_id:
|
||||
require_actor_permission(current_user, "roles.assign")
|
||||
|
|
@ -141,28 +157,56 @@ def update_user(
|
|||
"users.update",
|
||||
extra={"actor_user_id": current_user.id, "target_user_id": user_id},
|
||||
)
|
||||
return UserRepository.update(db, db_user, user)
|
||||
updated_user = UserRepository.update(db, db_user, user)
|
||||
write_audit_log(
|
||||
db,
|
||||
action="users.update",
|
||||
entity_type="users",
|
||||
entity_id=updated_user.id,
|
||||
entity_label=updated_user.username,
|
||||
actor=current_user,
|
||||
request=request,
|
||||
before_data=before_data,
|
||||
after_data=updated_user,
|
||||
)
|
||||
return updated_user
|
||||
|
||||
|
||||
@router.put("/{user_id}/password", response_model=UserResponse)
|
||||
def update_user_password(
|
||||
user_id: int,
|
||||
password_update: UserPasswordUpdate,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_permission("users.password.update")),
|
||||
):
|
||||
db_user = get_user_or_404(db, user_id)
|
||||
before_data = sanitize(db_user)
|
||||
|
||||
logger.info(
|
||||
"users.password_update",
|
||||
extra={"actor_user_id": current_user.id, "target_user_id": user_id},
|
||||
)
|
||||
return UserRepository.update_password(db, db_user, password_update)
|
||||
updated_user = UserRepository.update_password(db, db_user, password_update)
|
||||
write_audit_log(
|
||||
db,
|
||||
action="users.password_update",
|
||||
entity_type="users",
|
||||
entity_id=updated_user.id,
|
||||
entity_label=updated_user.username,
|
||||
actor=current_user,
|
||||
request=request,
|
||||
before_data=before_data,
|
||||
after_data=updated_user,
|
||||
metadata={"password_changed": True},
|
||||
)
|
||||
return updated_user
|
||||
|
||||
|
||||
@router.delete("/{user_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
def delete_user(
|
||||
user_id: int,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_permission("users.delete")),
|
||||
):
|
||||
|
|
@ -173,10 +217,22 @@ def delete_user(
|
|||
)
|
||||
|
||||
db_user = get_user_or_404(db, user_id)
|
||||
before_data = sanitize(db_user)
|
||||
entity_label = db_user.username
|
||||
|
||||
logger.info(
|
||||
"users.delete",
|
||||
extra={"actor_user_id": current_user.id, "target_user_id": user_id},
|
||||
)
|
||||
UserRepository.delete(db, db_user)
|
||||
write_audit_log(
|
||||
db,
|
||||
action="users.delete",
|
||||
entity_type="users",
|
||||
entity_id=user_id,
|
||||
entity_label=entity_label,
|
||||
actor=current_user,
|
||||
request=request,
|
||||
before_data=before_data,
|
||||
)
|
||||
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue