feat(audit): add audit logging to language QC routes
Adds audit_logger.log_action calls to all 13 write endpoints in routes_language_qc.py using existing AuditAction enum values. Also adds missing http_request: Request parameter to mark_cue_reviewed.
This commit is contained in:
parent
000e99c2d0
commit
7bba8256ce
1 changed files with 130 additions and 0 deletions
|
|
@ -8,9 +8,11 @@ from pydantic import BaseModel, Field
|
|||
|
||||
from ...core.database import get_database
|
||||
from ...core.dependencies import require_roles
|
||||
from ...models.audit_log import AuditAction
|
||||
from ...models.job import LanguageQCComment, LanguageQCState
|
||||
from ...models.user import User, UserRole
|
||||
from ...services import language_qc as lqc
|
||||
from ...services.audit_logger import audit_logger
|
||||
|
||||
router = APIRouter(tags=["language-qc"])
|
||||
|
||||
|
|
@ -131,6 +133,15 @@ async def assign_language(
|
|||
db, job_id, lang, request.linguist_user_id, current_user,
|
||||
http_request=http_request, notes=request.notes, deadline=request.deadline,
|
||||
)
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_ASSIGN,
|
||||
description=f"Language '{lang}' assigned to linguist '{request.linguist_user_id}' for job {job_id}",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={"lang": lang, "linguist_user_id": request.linguist_user_id},
|
||||
)
|
||||
return LanguageQCStateResponse(lang=lang, state=state)
|
||||
|
||||
|
||||
|
|
@ -149,6 +160,15 @@ async def reassign_language(
|
|||
db, job_id, lang, request.linguist_user_id, current_user,
|
||||
http_request=http_request, notes=request.notes, deadline=request.deadline,
|
||||
)
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_REASSIGN,
|
||||
description=f"Language '{lang}' reassigned to linguist '{request.linguist_user_id}' for job {job_id}",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={"lang": lang, "linguist_user_id": request.linguist_user_id},
|
||||
)
|
||||
return LanguageQCStateResponse(lang=lang, state=state)
|
||||
|
||||
|
||||
|
|
@ -169,6 +189,15 @@ async def assign_reviewer(
|
|||
db, job_id, lang, request.reviewer_user_id, current_user,
|
||||
http_request=http_request, notes=request.notes, deadline=request.deadline,
|
||||
)
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_REVIEWER_ASSIGN,
|
||||
description=f"Reviewer '{request.reviewer_user_id}' assigned to language '{lang}' for job {job_id}",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={"lang": lang, "reviewer_user_id": request.reviewer_user_id},
|
||||
)
|
||||
return LanguageQCStateResponse(lang=lang, state=state)
|
||||
|
||||
|
||||
|
|
@ -187,6 +216,15 @@ async def reassign_reviewer(
|
|||
db, job_id, lang, request.reviewer_user_id, current_user,
|
||||
http_request=http_request, notes=request.notes, deadline=request.deadline,
|
||||
)
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_REVIEWER_REASSIGN,
|
||||
description=f"Reviewer reassigned to '{request.reviewer_user_id}' for language '{lang}', job {job_id}",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={"lang": lang, "reviewer_user_id": request.reviewer_user_id},
|
||||
)
|
||||
return LanguageQCStateResponse(lang=lang, state=state)
|
||||
|
||||
|
||||
|
|
@ -248,6 +286,21 @@ async def bulk_assign_languages(
|
|||
|
||||
assigned.append(lang)
|
||||
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_BULK_ASSIGN,
|
||||
description=f"Bulk assignment for job {job_id}: {len(assigned)} language(s) assigned to linguist '{request.linguist_user_id}'",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={
|
||||
"languages": assigned,
|
||||
"linguist_user_id": request.linguist_user_id,
|
||||
"reviewer_user_id": request.reviewer_user_id,
|
||||
"skipped": skipped,
|
||||
"errors": errors,
|
||||
},
|
||||
)
|
||||
return BulkAssignResponse(assigned=assigned, skipped=skipped, errors=errors)
|
||||
|
||||
|
||||
|
|
@ -265,6 +318,15 @@ async def start_linguist_work(
|
|||
):
|
||||
"""Linguist opens the language — pending → in_progress."""
|
||||
state = await lqc.start_linguist_work(db, job_id, lang, current_user)
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_START_WORK,
|
||||
description=f"Linguist started work on language '{lang}' for job {job_id}",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={"lang": lang},
|
||||
)
|
||||
return LanguageQCStateResponse(lang=lang, state=state)
|
||||
|
||||
|
||||
|
|
@ -280,6 +342,15 @@ async def submit_for_review(
|
|||
):
|
||||
"""Linguist submits — in_progress → pending_review. Notifies reviewer by email."""
|
||||
state = await lqc.submit_for_review(db, job_id, lang, current_user, http_request=http_request)
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_SUBMIT,
|
||||
description=f"Language '{lang}' submitted for review for job {job_id}",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={"lang": lang},
|
||||
)
|
||||
return LanguageQCStateResponse(lang=lang, state=state)
|
||||
|
||||
|
||||
|
|
@ -295,6 +366,15 @@ async def open_review(
|
|||
):
|
||||
"""Reviewer opens the review — pending_review → in_review."""
|
||||
state = await lqc.open_review(db, job_id, lang, current_user, http_request=http_request)
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_OPEN_REVIEW,
|
||||
description=f"Reviewer opened review for language '{lang}', job {job_id}",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={"lang": lang},
|
||||
)
|
||||
return LanguageQCStateResponse(lang=lang, state=state)
|
||||
|
||||
|
||||
|
|
@ -314,6 +394,15 @@ async def approve_language(
|
|||
state = await lqc.approve_language(
|
||||
db, job_id, lang, current_user, http_request=http_request, notes=request.notes,
|
||||
)
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_APPROVE,
|
||||
description=f"Language '{lang}' approved for job {job_id}",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={"lang": lang, "notes": request.notes},
|
||||
)
|
||||
return LanguageQCStateResponse(lang=lang, state=state)
|
||||
|
||||
|
||||
|
|
@ -331,6 +420,15 @@ async def reject_language(
|
|||
state = await lqc.reject_language(
|
||||
db, job_id, lang, current_user, request.notes, category=request.category, http_request=http_request,
|
||||
)
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_REJECT,
|
||||
description=f"Language '{lang}' rejected for job {job_id}",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={"lang": lang, "notes": request.notes, "category": request.category},
|
||||
)
|
||||
return LanguageQCStateResponse(lang=lang, state=state)
|
||||
|
||||
|
||||
|
|
@ -343,6 +441,7 @@ async def mark_cue_reviewed(
|
|||
job_id: str,
|
||||
lang: str,
|
||||
request: MarkCueReviewedRequest,
|
||||
http_request: Request,
|
||||
current_user: User = Depends(require_roles(UserRole.REVIEWER, UserRole.ADMIN)),
|
||||
db: AsyncIOMotorDatabase = Depends(get_database),
|
||||
):
|
||||
|
|
@ -363,6 +462,19 @@ async def mark_cue_reviewed(
|
|||
state_dict = (updated_doc.get("language_qc") or {}).get(lang, {})
|
||||
from ...models.job import LanguageQCState
|
||||
state = LanguageQCState(**state_dict) if isinstance(state_dict, dict) else LanguageQCState()
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_MARK_CUE_REVIEWED,
|
||||
description=f"Cue marked as reviewed for language '{lang}', job {job_id}",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={
|
||||
"lang": lang,
|
||||
"reviewed_cues": state.reviewed_cues if hasattr(state, "reviewed_cues") else None,
|
||||
"total_cues": request.total_cues,
|
||||
},
|
||||
)
|
||||
return LanguageQCStateResponse(lang=lang, state=state)
|
||||
|
||||
|
||||
|
|
@ -378,6 +490,15 @@ async def reopen_language(
|
|||
state = await lqc.reopen_language(
|
||||
db, job_id, lang, current_user, http_request=http_request, notes=request.notes,
|
||||
)
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_REOPEN,
|
||||
description=f"Language '{lang}' reopened for job {job_id}",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={"lang": lang, "notes": request.notes},
|
||||
)
|
||||
return LanguageQCStateResponse(lang=lang, state=state)
|
||||
|
||||
|
||||
|
|
@ -398,6 +519,15 @@ async def add_comment(
|
|||
comment = await lqc.add_comment(
|
||||
db, job_id, lang, current_user, request.body, http_request=http_request,
|
||||
)
|
||||
await audit_logger.log_action(
|
||||
action=AuditAction.LANGUAGE_QC_COMMENT,
|
||||
description=f"Comment added to language '{lang}' for job {job_id}",
|
||||
user=current_user,
|
||||
request=http_request,
|
||||
resource_type="job",
|
||||
resource_id=job_id,
|
||||
details={"lang": lang, "comment_id": str(comment.id) if hasattr(comment, "id") else None},
|
||||
)
|
||||
return comment
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue