New GET /analytics/by-agency endpoint groups review metrics by agency. The Analytics page now shows a sortable agency performance table with pass rates, failures, errors, and legal review counts for each agency. Only visible to super_admin and oversight_admin users. Selected agency row is highlighted when the AgencyFilterBar is active. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
238 lines
5.1 KiB
Python
Executable file
238 lines
5.1 KiB
Python
Executable file
"""Pydantic schemas for API request/response validation."""
|
|
import uuid
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
|
|
from pydantic import BaseModel
|
|
|
|
|
|
# Campaign schemas
|
|
class CampaignCreate(BaseModel):
|
|
name: str
|
|
workfront_id: Optional[str] = None
|
|
client_lead: Optional[str] = None
|
|
agency_lead: Optional[str] = None
|
|
brand_guidelines: Optional[str] = None
|
|
|
|
|
|
class CampaignUpdate(BaseModel):
|
|
name: Optional[str] = None
|
|
workfront_id: Optional[str] = None
|
|
client_lead: Optional[str] = None
|
|
agency_lead: Optional[str] = None
|
|
brand_guidelines: Optional[str] = None
|
|
status: Optional[str] = None
|
|
|
|
|
|
class CampaignResponse(BaseModel):
|
|
id: uuid.UUID
|
|
name: str
|
|
workfront_id: Optional[str]
|
|
client_lead: Optional[str]
|
|
agency_lead: Optional[str]
|
|
brand_guidelines: Optional[str]
|
|
status: str
|
|
agency: Optional[str]
|
|
created_by: Optional[uuid.UUID]
|
|
created_at: datetime
|
|
updated_at: datetime
|
|
proofs: int = 0
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# Proof schemas
|
|
class ProofCreate(BaseModel):
|
|
proof_name: str
|
|
channel: Optional[str] = None
|
|
sub_channel: Optional[str] = None
|
|
proof_type: Optional[str] = None
|
|
|
|
|
|
class ProofVersionResponse(BaseModel):
|
|
id: uuid.UUID
|
|
version: int
|
|
file_storage_key: Optional[str]
|
|
thumbnail_url: Optional[str]
|
|
agent_review: Optional[dict]
|
|
overall_status: Optional[str]
|
|
workfront_id: Optional[str]
|
|
is_identical_file: Optional[bool] = False
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class ProofResponse(BaseModel):
|
|
id: uuid.UUID
|
|
proof_name: str
|
|
channel: Optional[str]
|
|
sub_channel: Optional[str]
|
|
proof_type: Optional[str]
|
|
workfront_id: Optional[str]
|
|
created_at: datetime
|
|
versions: list[ProofVersionResponse] = []
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# Audit schemas
|
|
class FlaggedItemCreate(BaseModel):
|
|
agent_flagged: str
|
|
comments: Optional[str] = None
|
|
|
|
|
|
class FlaggedItemResponse(BaseModel):
|
|
id: uuid.UUID
|
|
proof_version_id: uuid.UUID
|
|
agent_flagged: str
|
|
comments: Optional[str]
|
|
submitter_name: Optional[str]
|
|
submitter_agency: Optional[str]
|
|
campaign_name: Optional[str]
|
|
proof_name: Optional[str]
|
|
version: Optional[int]
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class ResolvedItemCreate(BaseModel):
|
|
agent: str
|
|
issue: Optional[str] = None
|
|
resolution: Optional[str] = None
|
|
|
|
|
|
class ResolvedItemResponse(BaseModel):
|
|
id: uuid.UUID
|
|
proof_version_id: uuid.UUID
|
|
agent: str
|
|
issue: Optional[str]
|
|
resolution: Optional[str]
|
|
submitter_name: Optional[str]
|
|
submitter_agency: Optional[str]
|
|
campaign_name: Optional[str]
|
|
proof_name: Optional[str]
|
|
version: Optional[int]
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class ErrorItemResponse(BaseModel):
|
|
id: uuid.UUID
|
|
proof_version_id: uuid.UUID
|
|
error_summary: Optional[str]
|
|
submitter_name: Optional[str]
|
|
submitter_agency: Optional[str]
|
|
campaign_name: Optional[str]
|
|
proof_name: Optional[str]
|
|
version: Optional[int]
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# Analytics schemas
|
|
class AnalyticsResponse(BaseModel):
|
|
total_reviews: int
|
|
passed: int
|
|
failed: int
|
|
errors: int
|
|
legal_review: int
|
|
|
|
|
|
class AgencyAnalyticsItem(BaseModel):
|
|
agency_id: uuid.UUID
|
|
agency_name: str
|
|
total_reviews: int
|
|
passed: int
|
|
failed: int
|
|
errors: int
|
|
legal_review: int
|
|
|
|
|
|
class AgencyAnalyticsResponse(BaseModel):
|
|
agencies: list[AgencyAnalyticsItem]
|
|
|
|
|
|
# Dropdown options schemas
|
|
class DropdownOptionsResponse(BaseModel):
|
|
campaigns: list[str]
|
|
channels: dict[str, dict[str, list[str]]]
|
|
brand_guidelines: list[str] = []
|
|
|
|
|
|
# Agency schemas
|
|
class AgencyResponse(BaseModel):
|
|
id: uuid.UUID
|
|
name: str
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# User schemas
|
|
class CurrentUserResponse(BaseModel):
|
|
"""Response for /api/me - the authenticated user's own profile."""
|
|
id: uuid.UUID
|
|
email: str
|
|
name: str
|
|
role: str
|
|
agency_id: Optional[uuid.UUID]
|
|
agency_name: Optional[str]
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class UserResponse(BaseModel):
|
|
id: uuid.UUID
|
|
email: str
|
|
name: str
|
|
role: str
|
|
agency: Optional[str]
|
|
agency_id: Optional[uuid.UUID] = None
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
class UserUpdate(BaseModel):
|
|
"""Request body for updating a user's role and/or agency."""
|
|
role: Optional[str] = None
|
|
agency_id: Optional[uuid.UUID] = None
|
|
|
|
|
|
class AgencyCreate(BaseModel):
|
|
"""Request body for creating a new agency."""
|
|
name: str
|
|
|
|
|
|
# User change log schemas
|
|
class UserChangeLogResponse(BaseModel):
|
|
id: uuid.UUID
|
|
change_type: str
|
|
field_changed: Optional[str]
|
|
old_value: Optional[str]
|
|
new_value: Optional[str]
|
|
changed_by_name: Optional[str]
|
|
created_at: datetime
|
|
|
|
class Config:
|
|
from_attributes = True
|
|
|
|
|
|
# Support email schemas
|
|
class SupportEmailRequest(BaseModel):
|
|
message: str
|
|
subject: str
|
|
user_name: Optional[str] = None
|
|
user_email: Optional[str] = None
|