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 require_permission
|
||||
from app.db.database import get_db
|
||||
|
|
@ -16,6 +17,7 @@ from app.schemas.customer import (
|
|||
CustomerResponse,
|
||||
CustomerUpdate,
|
||||
)
|
||||
from app.services.audit_service import sanitize, write_audit_log
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -94,42 +96,81 @@ def get_customer(
|
|||
)
|
||||
def create_customer(
|
||||
customer: CustomerCreate,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_permission("customers.create")),
|
||||
):
|
||||
ensure_unique_customer_number(db, customer.customer_number)
|
||||
logger.info("customers.create", extra={"actor_user_id": current_user.id})
|
||||
return CustomerRepository.create(db, customer)
|
||||
created_customer = CustomerRepository.create(db, customer)
|
||||
write_audit_log(
|
||||
db,
|
||||
action="customers.create",
|
||||
entity_type="customers",
|
||||
entity_id=created_customer.id,
|
||||
entity_label=created_customer.company_name,
|
||||
actor=current_user,
|
||||
request=request,
|
||||
after_data=created_customer,
|
||||
)
|
||||
return created_customer
|
||||
|
||||
|
||||
@router.put("/{customer_id}", response_model=CustomerResponse)
|
||||
def update_customer(
|
||||
customer_id: int,
|
||||
customer: CustomerUpdate,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_permission("customers.update")),
|
||||
):
|
||||
db_customer = get_customer_or_404(db, customer_id)
|
||||
before_data = sanitize(db_customer)
|
||||
ensure_unique_customer_number(db, customer.customer_number, customer_id)
|
||||
logger.info(
|
||||
"customers.update",
|
||||
extra={"actor_user_id": current_user.id, "target_customer_id": customer_id},
|
||||
)
|
||||
return CustomerRepository.update(db, db_customer, customer)
|
||||
updated_customer = CustomerRepository.update(db, db_customer, customer)
|
||||
write_audit_log(
|
||||
db,
|
||||
action="customers.update",
|
||||
entity_type="customers",
|
||||
entity_id=updated_customer.id,
|
||||
entity_label=updated_customer.company_name,
|
||||
actor=current_user,
|
||||
request=request,
|
||||
before_data=before_data,
|
||||
after_data=updated_customer,
|
||||
)
|
||||
return updated_customer
|
||||
|
||||
|
||||
@router.delete("/{customer_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
def delete_customer(
|
||||
customer_id: int,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_permission("customers.delete")),
|
||||
):
|
||||
db_customer = get_customer_or_404(db, customer_id)
|
||||
before_data = sanitize(db_customer)
|
||||
entity_label = db_customer.company_name
|
||||
logger.info(
|
||||
"customers.delete",
|
||||
extra={"actor_user_id": current_user.id, "target_customer_id": customer_id},
|
||||
)
|
||||
CustomerRepository.delete(db, db_customer)
|
||||
write_audit_log(
|
||||
db,
|
||||
action="customers.delete",
|
||||
entity_type="customers",
|
||||
entity_id=customer_id,
|
||||
entity_label=entity_label,
|
||||
actor=current_user,
|
||||
request=request,
|
||||
before_data=before_data,
|
||||
)
|
||||
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
||||
|
||||
|
|
@ -155,15 +196,28 @@ def get_customer_contacts(
|
|||
def create_customer_contact(
|
||||
customer_id: int,
|
||||
contact: CustomerContactCreate,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_permission("customers.update")),
|
||||
):
|
||||
get_customer_or_404(db, customer_id)
|
||||
customer = get_customer_or_404(db, customer_id)
|
||||
logger.info(
|
||||
"customers.contacts.create",
|
||||
extra={"actor_user_id": current_user.id, "target_customer_id": customer_id},
|
||||
)
|
||||
return CustomerRepository.create_contact(db, customer_id, contact)
|
||||
created_contact = CustomerRepository.create_contact(db, customer_id, contact)
|
||||
write_audit_log(
|
||||
db,
|
||||
action="customer_contacts.create",
|
||||
entity_type="customer_contacts",
|
||||
entity_id=created_contact.id,
|
||||
entity_label=f"{created_contact.first_name} {created_contact.last_name}".strip(),
|
||||
actor=current_user,
|
||||
request=request,
|
||||
after_data=created_contact,
|
||||
metadata={"customer_id": customer_id, "customer_label": customer.company_name},
|
||||
)
|
||||
return created_contact
|
||||
|
||||
|
||||
@router.put("/{customer_id}/contacts/{contact_id}", response_model=CustomerContactResponse)
|
||||
|
|
@ -171,11 +225,13 @@ def update_customer_contact(
|
|||
customer_id: int,
|
||||
contact_id: int,
|
||||
contact: CustomerContactUpdate,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_permission("customers.update")),
|
||||
):
|
||||
get_customer_or_404(db, customer_id)
|
||||
customer = get_customer_or_404(db, customer_id)
|
||||
db_contact = get_contact_or_404(db, customer_id, contact_id)
|
||||
before_data = sanitize(db_contact)
|
||||
logger.info(
|
||||
"customers.contacts.update",
|
||||
extra={
|
||||
|
|
@ -184,18 +240,34 @@ def update_customer_contact(
|
|||
"target_contact_id": contact_id,
|
||||
},
|
||||
)
|
||||
return CustomerRepository.update_contact(db, db_contact, contact)
|
||||
updated_contact = CustomerRepository.update_contact(db, db_contact, contact)
|
||||
write_audit_log(
|
||||
db,
|
||||
action="customer_contacts.update",
|
||||
entity_type="customer_contacts",
|
||||
entity_id=updated_contact.id,
|
||||
entity_label=f"{updated_contact.first_name} {updated_contact.last_name}".strip(),
|
||||
actor=current_user,
|
||||
request=request,
|
||||
before_data=before_data,
|
||||
after_data=updated_contact,
|
||||
metadata={"customer_id": customer_id, "customer_label": customer.company_name},
|
||||
)
|
||||
return updated_contact
|
||||
|
||||
|
||||
@router.delete("/{customer_id}/contacts/{contact_id}", status_code=status.HTTP_204_NO_CONTENT)
|
||||
def delete_customer_contact(
|
||||
customer_id: int,
|
||||
contact_id: int,
|
||||
request: Request,
|
||||
db: Session = Depends(get_db),
|
||||
current_user: User = Depends(require_permission("customers.update")),
|
||||
):
|
||||
get_customer_or_404(db, customer_id)
|
||||
customer = get_customer_or_404(db, customer_id)
|
||||
db_contact = get_contact_or_404(db, customer_id, contact_id)
|
||||
before_data = sanitize(db_contact)
|
||||
entity_label = f"{db_contact.first_name} {db_contact.last_name}".strip()
|
||||
logger.info(
|
||||
"customers.contacts.delete",
|
||||
extra={
|
||||
|
|
@ -205,4 +277,15 @@ def delete_customer_contact(
|
|||
},
|
||||
)
|
||||
CustomerRepository.delete_contact(db, db_contact)
|
||||
write_audit_log(
|
||||
db,
|
||||
action="customer_contacts.delete",
|
||||
entity_type="customer_contacts",
|
||||
entity_id=contact_id,
|
||||
entity_label=entity_label,
|
||||
actor=current_user,
|
||||
request=request,
|
||||
before_data=before_data,
|
||||
metadata={"customer_id": customer_id, "customer_label": customer.company_name},
|
||||
)
|
||||
return Response(status_code=status.HTTP_204_NO_CONTENT)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue