mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 19:11:12 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
650
django-backend/api/v1/endpoints/companies.py
Normal file
650
django-backend/api/v1/endpoints/companies.py
Normal file
@@ -0,0 +1,650 @@
|
||||
"""
|
||||
Company endpoints for API v1.
|
||||
|
||||
Provides CRUD operations for Company entities with filtering and search.
|
||||
"""
|
||||
from typing import List, Optional
|
||||
from uuid import UUID
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.db.models import Q
|
||||
from ninja import Router, Query
|
||||
from ninja.pagination import paginate, PageNumberPagination
|
||||
|
||||
from apps.entities.models import Company
|
||||
from apps.entities.services.company_submission import CompanySubmissionService
|
||||
from apps.users.permissions import jwt_auth, require_auth
|
||||
from ..schemas import (
|
||||
CompanyCreate,
|
||||
CompanyUpdate,
|
||||
CompanyOut,
|
||||
CompanyListOut,
|
||||
ErrorResponse,
|
||||
HistoryListResponse,
|
||||
HistoryEventDetailSchema,
|
||||
HistoryComparisonSchema,
|
||||
HistoryDiffCurrentSchema,
|
||||
FieldHistorySchema,
|
||||
HistoryActivitySummarySchema,
|
||||
RollbackRequestSchema,
|
||||
RollbackResponseSchema,
|
||||
ErrorSchema
|
||||
)
|
||||
from ..services.history_service import HistoryService
|
||||
from django.core.exceptions import ValidationError
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
router = Router(tags=["Companies"])
|
||||
|
||||
|
||||
class CompanyPagination(PageNumberPagination):
|
||||
"""Custom pagination for companies."""
|
||||
page_size = 50
|
||||
|
||||
|
||||
@router.get(
|
||||
"/",
|
||||
response={200: List[CompanyOut]},
|
||||
summary="List companies",
|
||||
description="Get a paginated list of companies with optional filtering"
|
||||
)
|
||||
@paginate(CompanyPagination)
|
||||
def list_companies(
|
||||
request,
|
||||
search: Optional[str] = Query(None, description="Search by company name"),
|
||||
company_type: Optional[str] = Query(None, description="Filter by company type"),
|
||||
location_id: Optional[UUID] = Query(None, description="Filter by location"),
|
||||
ordering: Optional[str] = Query("-created", description="Sort by field (prefix with - for descending)")
|
||||
):
|
||||
"""
|
||||
List all companies with optional filters.
|
||||
|
||||
**Filters:**
|
||||
- search: Search company names (case-insensitive partial match)
|
||||
- company_type: Filter by specific company type
|
||||
- location_id: Filter by headquarters location
|
||||
- ordering: Sort results (default: -created)
|
||||
|
||||
**Returns:** Paginated list of companies
|
||||
"""
|
||||
queryset = Company.objects.all()
|
||||
|
||||
# Apply search filter
|
||||
if search:
|
||||
queryset = queryset.filter(
|
||||
Q(name__icontains=search) | Q(description__icontains=search)
|
||||
)
|
||||
|
||||
# Apply company type filter
|
||||
if company_type:
|
||||
queryset = queryset.filter(company_types__contains=[company_type])
|
||||
|
||||
# Apply location filter
|
||||
if location_id:
|
||||
queryset = queryset.filter(location_id=location_id)
|
||||
|
||||
# Apply ordering
|
||||
valid_order_fields = ['name', 'created', 'modified', 'founded_date', 'park_count', 'ride_count']
|
||||
order_field = ordering.lstrip('-')
|
||||
if order_field in valid_order_fields:
|
||||
queryset = queryset.order_by(ordering)
|
||||
else:
|
||||
queryset = queryset.order_by('-created')
|
||||
|
||||
return queryset
|
||||
|
||||
|
||||
@router.get(
|
||||
"/{company_id}",
|
||||
response={200: CompanyOut, 404: ErrorResponse},
|
||||
summary="Get company",
|
||||
description="Retrieve a single company by ID"
|
||||
)
|
||||
def get_company(request, company_id: UUID):
|
||||
"""
|
||||
Get a company by ID.
|
||||
|
||||
**Parameters:**
|
||||
- company_id: UUID of the company
|
||||
|
||||
**Returns:** Company details
|
||||
"""
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
return company
|
||||
|
||||
|
||||
@router.post(
|
||||
"/",
|
||||
response={201: CompanyOut, 202: dict, 400: ErrorResponse, 401: ErrorResponse},
|
||||
summary="Create company",
|
||||
description="Create a new company through the Sacred Pipeline (requires authentication)"
|
||||
)
|
||||
@require_auth
|
||||
def create_company(request, payload: CompanyCreate):
|
||||
"""
|
||||
Create a new company through the Sacred Pipeline.
|
||||
|
||||
**Authentication:** Required
|
||||
|
||||
**Parameters:**
|
||||
- payload: Company data (name, company_types, headquarters, etc.)
|
||||
|
||||
**Returns:** Created company (moderators) or submission confirmation (regular users)
|
||||
|
||||
**Flow:**
|
||||
- Moderators: Company created immediately (bypass moderation)
|
||||
- Regular users: Submission created, enters moderation queue
|
||||
|
||||
**Note:** All companies flow through ContentSubmission pipeline for moderation.
|
||||
"""
|
||||
try:
|
||||
user = request.auth
|
||||
|
||||
# Create company through Sacred Pipeline
|
||||
submission, company = CompanySubmissionService.create_entity_submission(
|
||||
user=user,
|
||||
data=payload.dict(),
|
||||
source='api',
|
||||
ip_address=request.META.get('REMOTE_ADDR'),
|
||||
user_agent=request.META.get('HTTP_USER_AGENT', '')
|
||||
)
|
||||
|
||||
# If moderator bypass happened, Company was created immediately
|
||||
if company:
|
||||
logger.info(f"Company created (moderator): {company.id} by {user.email}")
|
||||
return 201, company
|
||||
|
||||
# Regular user: submission pending moderation
|
||||
logger.info(f"Company submission created: {submission.id} by {user.email}")
|
||||
return 202, {
|
||||
'submission_id': str(submission.id),
|
||||
'status': submission.status,
|
||||
'message': 'Company submission pending moderation. You will be notified when it is approved.',
|
||||
}
|
||||
|
||||
except ValidationError as e:
|
||||
return 400, {'detail': str(e)}
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating company: {e}")
|
||||
return 400, {'detail': str(e)}
|
||||
|
||||
|
||||
@router.put(
|
||||
"/{company_id}",
|
||||
response={200: CompanyOut, 202: dict, 404: ErrorResponse, 400: ErrorResponse, 401: ErrorResponse},
|
||||
summary="Update company",
|
||||
description="Update an existing company through the Sacred Pipeline (requires authentication)"
|
||||
)
|
||||
@require_auth
|
||||
def update_company(request, company_id: UUID, payload: CompanyUpdate):
|
||||
"""
|
||||
Update a company through the Sacred Pipeline.
|
||||
|
||||
**Authentication:** Required
|
||||
|
||||
**Parameters:**
|
||||
- company_id: UUID of the company
|
||||
- payload: Updated company data
|
||||
|
||||
**Returns:** Updated company (moderators) or submission confirmation (regular users)
|
||||
|
||||
**Flow:**
|
||||
- Moderators: Updates applied immediately (bypass moderation)
|
||||
- Regular users: Submission created, enters moderation queue
|
||||
|
||||
**Note:** All updates flow through ContentSubmission pipeline for moderation.
|
||||
"""
|
||||
try:
|
||||
user = request.auth
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
|
||||
data = payload.dict(exclude_unset=True)
|
||||
|
||||
# Update company through Sacred Pipeline
|
||||
submission, updated_company = CompanySubmissionService.update_entity_submission(
|
||||
entity=company,
|
||||
user=user,
|
||||
update_data=data,
|
||||
source='api',
|
||||
ip_address=request.META.get('REMOTE_ADDR'),
|
||||
user_agent=request.META.get('HTTP_USER_AGENT', '')
|
||||
)
|
||||
|
||||
# If moderator bypass happened, company was updated immediately
|
||||
if updated_company:
|
||||
logger.info(f"Company updated (moderator): {updated_company.id} by {user.email}")
|
||||
return 200, updated_company
|
||||
|
||||
# Regular user: submission pending moderation
|
||||
logger.info(f"Company update submission created: {submission.id} by {user.email}")
|
||||
return 202, {
|
||||
'submission_id': str(submission.id),
|
||||
'status': submission.status,
|
||||
'message': 'Company update pending moderation. You will be notified when it is approved.',
|
||||
}
|
||||
|
||||
except ValidationError as e:
|
||||
return 400, {'detail': str(e)}
|
||||
except Exception as e:
|
||||
logger.error(f"Error updating company: {e}")
|
||||
return 400, {'detail': str(e)}
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/{company_id}",
|
||||
response={200: CompanyOut, 202: dict, 404: ErrorResponse, 400: ErrorResponse, 401: ErrorResponse},
|
||||
summary="Partial update company",
|
||||
description="Partially update an existing company through the Sacred Pipeline (requires authentication)"
|
||||
)
|
||||
@require_auth
|
||||
def partial_update_company(request, company_id: UUID, payload: CompanyUpdate):
|
||||
"""
|
||||
Partially update a company through the Sacred Pipeline.
|
||||
|
||||
**Authentication:** Required
|
||||
|
||||
**Parameters:**
|
||||
- company_id: UUID of the company
|
||||
- payload: Fields to update (only provided fields are updated)
|
||||
|
||||
**Returns:** Updated company (moderators) or submission confirmation (regular users)
|
||||
|
||||
**Flow:**
|
||||
- Moderators: Updates applied immediately (bypass moderation)
|
||||
- Regular users: Submission created, enters moderation queue
|
||||
|
||||
**Note:** All updates flow through ContentSubmission pipeline for moderation.
|
||||
"""
|
||||
try:
|
||||
user = request.auth
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
|
||||
data = payload.dict(exclude_unset=True)
|
||||
|
||||
# Update company through Sacred Pipeline
|
||||
submission, updated_company = CompanySubmissionService.update_entity_submission(
|
||||
entity=company,
|
||||
user=user,
|
||||
update_data=data,
|
||||
source='api',
|
||||
ip_address=request.META.get('REMOTE_ADDR'),
|
||||
user_agent=request.META.get('HTTP_USER_AGENT', '')
|
||||
)
|
||||
|
||||
# If moderator bypass happened, company was updated immediately
|
||||
if updated_company:
|
||||
logger.info(f"Company partially updated (moderator): {updated_company.id} by {user.email}")
|
||||
return 200, updated_company
|
||||
|
||||
# Regular user: submission pending moderation
|
||||
logger.info(f"Company partial update submission created: {submission.id} by {user.email}")
|
||||
return 202, {
|
||||
'submission_id': str(submission.id),
|
||||
'status': submission.status,
|
||||
'message': 'Company update pending moderation. You will be notified when it is approved.',
|
||||
}
|
||||
|
||||
except ValidationError as e:
|
||||
return 400, {'detail': str(e)}
|
||||
except Exception as e:
|
||||
logger.error(f"Error partially updating company: {e}")
|
||||
return 400, {'detail': str(e)}
|
||||
|
||||
|
||||
@router.delete(
|
||||
"/{company_id}",
|
||||
response={200: dict, 202: dict, 404: ErrorResponse, 400: ErrorResponse, 401: ErrorResponse},
|
||||
summary="Delete company",
|
||||
description="Delete a company through the Sacred Pipeline (requires authentication)"
|
||||
)
|
||||
@require_auth
|
||||
def delete_company(request, company_id: UUID):
|
||||
"""
|
||||
Delete a company through the Sacred Pipeline.
|
||||
|
||||
**Authentication:** Required
|
||||
|
||||
**Parameters:**
|
||||
- company_id: UUID of the company
|
||||
|
||||
**Returns:** Deletion confirmation (moderators) or submission confirmation (regular users)
|
||||
|
||||
**Flow:**
|
||||
- Moderators: Company hard-deleted immediately (removed from database)
|
||||
- Regular users: Deletion request created, enters moderation queue
|
||||
|
||||
**Deletion Strategy:**
|
||||
- Hard Delete: Removes company from database (Company has no status field for soft delete)
|
||||
|
||||
**Note:** All deletions flow through ContentSubmission pipeline for moderation.
|
||||
**Warning:** Deleting a company may affect related parks and rides.
|
||||
"""
|
||||
try:
|
||||
user = request.auth
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
|
||||
# Delete company through Sacred Pipeline (hard delete - no status field)
|
||||
submission, deleted = CompanySubmissionService.delete_entity_submission(
|
||||
entity=company,
|
||||
user=user,
|
||||
deletion_type='hard', # Company has no status field
|
||||
deletion_reason='',
|
||||
source='api',
|
||||
ip_address=request.META.get('REMOTE_ADDR'),
|
||||
user_agent=request.META.get('HTTP_USER_AGENT', '')
|
||||
)
|
||||
|
||||
# If moderator bypass happened, deletion was applied immediately
|
||||
if deleted:
|
||||
logger.info(f"Company deleted (moderator): {company_id} by {user.email}")
|
||||
return 200, {
|
||||
'message': 'Company deleted successfully',
|
||||
'entity_id': str(company_id),
|
||||
'deletion_type': 'hard'
|
||||
}
|
||||
|
||||
# Regular user: deletion pending moderation
|
||||
logger.info(f"Company deletion submission created: {submission.id} by {user.email}")
|
||||
return 202, {
|
||||
'submission_id': str(submission.id),
|
||||
'status': submission.status,
|
||||
'message': 'Company deletion request pending moderation. You will be notified when it is approved.',
|
||||
'entity_id': str(company_id)
|
||||
}
|
||||
|
||||
except ValidationError as e:
|
||||
return 400, {'detail': str(e)}
|
||||
except Exception as e:
|
||||
logger.error(f"Error deleting company: {e}")
|
||||
return 400, {'detail': str(e)}
|
||||
|
||||
|
||||
@router.get(
|
||||
"/{company_id}/parks",
|
||||
response={200: List[dict], 404: ErrorResponse},
|
||||
summary="Get company parks",
|
||||
description="Get all parks operated by a company"
|
||||
)
|
||||
def get_company_parks(request, company_id: UUID):
|
||||
"""
|
||||
Get parks operated by a company.
|
||||
|
||||
**Parameters:**
|
||||
- company_id: UUID of the company
|
||||
|
||||
**Returns:** List of parks
|
||||
"""
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
parks = company.operated_parks.all().values('id', 'name', 'slug', 'status', 'park_type')
|
||||
return list(parks)
|
||||
|
||||
|
||||
@router.get(
|
||||
"/{company_id}/rides",
|
||||
response={200: List[dict], 404: ErrorResponse},
|
||||
summary="Get company rides",
|
||||
description="Get all rides manufactured by a company"
|
||||
)
|
||||
def get_company_rides(request, company_id: UUID):
|
||||
"""
|
||||
Get rides manufactured by a company.
|
||||
|
||||
**Parameters:**
|
||||
- company_id: UUID of the company
|
||||
|
||||
**Returns:** List of rides
|
||||
"""
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
rides = company.manufactured_rides.all().values('id', 'name', 'slug', 'status', 'ride_category')
|
||||
return list(rides)
|
||||
|
||||
|
||||
# ============================================================================
|
||||
# History Endpoints
|
||||
# ============================================================================
|
||||
|
||||
@router.get(
|
||||
'/{company_id}/history/',
|
||||
response={200: HistoryListResponse, 404: ErrorSchema},
|
||||
summary="Get company history",
|
||||
description="Get historical changes for a company"
|
||||
)
|
||||
def get_company_history(
|
||||
request,
|
||||
company_id: UUID,
|
||||
page: int = Query(1, ge=1),
|
||||
page_size: int = Query(50, ge=1, le=100),
|
||||
date_from: Optional[str] = Query(None, description="Filter from date (YYYY-MM-DD)"),
|
||||
date_to: Optional[str] = Query(None, description="Filter to date (YYYY-MM-DD)")
|
||||
):
|
||||
"""Get history for a company."""
|
||||
from datetime import datetime
|
||||
|
||||
# Verify company exists
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
|
||||
# Parse dates if provided
|
||||
date_from_obj = datetime.fromisoformat(date_from).date() if date_from else None
|
||||
date_to_obj = datetime.fromisoformat(date_to).date() if date_to else None
|
||||
|
||||
# Get history
|
||||
offset = (page - 1) * page_size
|
||||
events, accessible_count = HistoryService.get_history(
|
||||
'company', str(company_id), request.user,
|
||||
date_from=date_from_obj, date_to=date_to_obj,
|
||||
limit=page_size, offset=offset
|
||||
)
|
||||
|
||||
# Format events
|
||||
formatted_events = []
|
||||
for event in events:
|
||||
formatted_events.append({
|
||||
'id': event['id'],
|
||||
'timestamp': event['timestamp'],
|
||||
'operation': event['operation'],
|
||||
'snapshot': event['snapshot'],
|
||||
'changed_fields': event.get('changed_fields'),
|
||||
'change_summary': event.get('change_summary', ''),
|
||||
'can_rollback': HistoryService.can_rollback(request.user)
|
||||
})
|
||||
|
||||
# Calculate pagination
|
||||
total_pages = (accessible_count + page_size - 1) // page_size
|
||||
|
||||
return {
|
||||
'entity_id': str(company_id),
|
||||
'entity_type': 'company',
|
||||
'entity_name': company.name,
|
||||
'total_events': accessible_count,
|
||||
'accessible_events': accessible_count,
|
||||
'access_limited': HistoryService.is_access_limited(request.user),
|
||||
'access_reason': HistoryService.get_access_reason(request.user),
|
||||
'events': formatted_events,
|
||||
'pagination': {
|
||||
'page': page,
|
||||
'page_size': page_size,
|
||||
'total_pages': total_pages,
|
||||
'total_items': accessible_count
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@router.get(
|
||||
'/{company_id}/history/{event_id}/',
|
||||
response={200: HistoryEventDetailSchema, 404: ErrorSchema},
|
||||
summary="Get specific company history event",
|
||||
description="Get detailed information about a specific historical event"
|
||||
)
|
||||
def get_company_history_event(request, company_id: UUID, event_id: int):
|
||||
"""Get a specific history event for a company."""
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
event = HistoryService.get_event('company', event_id, request.user)
|
||||
|
||||
if not event:
|
||||
return 404, {"error": "Event not found or not accessible"}
|
||||
|
||||
return {
|
||||
'id': event['id'],
|
||||
'timestamp': event['timestamp'],
|
||||
'operation': event['operation'],
|
||||
'entity_id': str(company_id),
|
||||
'entity_type': 'company',
|
||||
'entity_name': company.name,
|
||||
'snapshot': event['snapshot'],
|
||||
'changed_fields': event.get('changed_fields'),
|
||||
'metadata': event.get('metadata', {}),
|
||||
'can_rollback': HistoryService.can_rollback(request.user),
|
||||
'rollback_preview': None
|
||||
}
|
||||
|
||||
|
||||
@router.get(
|
||||
'/{company_id}/history/compare/',
|
||||
response={200: HistoryComparisonSchema, 400: ErrorSchema, 404: ErrorSchema},
|
||||
summary="Compare two company history events",
|
||||
description="Compare two historical events for a company"
|
||||
)
|
||||
def compare_company_history(
|
||||
request,
|
||||
company_id: UUID,
|
||||
event1: int = Query(..., description="First event ID"),
|
||||
event2: int = Query(..., description="Second event ID")
|
||||
):
|
||||
"""Compare two historical events for a company."""
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
|
||||
try:
|
||||
comparison = HistoryService.compare_events(
|
||||
'company', event1, event2, request.user
|
||||
)
|
||||
|
||||
if not comparison:
|
||||
return 404, {"error": "One or both events not found"}
|
||||
|
||||
return {
|
||||
'entity_id': str(company_id),
|
||||
'entity_type': 'company',
|
||||
'entity_name': company.name,
|
||||
'event1': comparison['event1'],
|
||||
'event2': comparison['event2'],
|
||||
'differences': comparison['differences'],
|
||||
'changed_field_count': comparison['changed_field_count'],
|
||||
'unchanged_field_count': comparison['unchanged_field_count'],
|
||||
'time_between': comparison['time_between']
|
||||
}
|
||||
except ValueError as e:
|
||||
return 400, {"error": str(e)}
|
||||
|
||||
|
||||
@router.get(
|
||||
'/{company_id}/history/{event_id}/diff-current/',
|
||||
response={200: HistoryDiffCurrentSchema, 404: ErrorSchema},
|
||||
summary="Compare historical event with current state",
|
||||
description="Compare a historical event with the current company state"
|
||||
)
|
||||
def diff_company_history_with_current(request, company_id: UUID, event_id: int):
|
||||
"""Compare historical event with current company state."""
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
|
||||
try:
|
||||
diff = HistoryService.compare_with_current(
|
||||
'company', event_id, company, request.user
|
||||
)
|
||||
|
||||
if not diff:
|
||||
return 404, {"error": "Event not found"}
|
||||
|
||||
return {
|
||||
'entity_id': str(company_id),
|
||||
'entity_type': 'company',
|
||||
'entity_name': company.name,
|
||||
'event': diff['event'],
|
||||
'current_state': diff['current_state'],
|
||||
'differences': diff['differences'],
|
||||
'changed_field_count': diff['changed_field_count'],
|
||||
'time_since': diff['time_since']
|
||||
}
|
||||
except ValueError as e:
|
||||
return 404, {"error": str(e)}
|
||||
|
||||
|
||||
@router.post(
|
||||
'/{company_id}/history/{event_id}/rollback/',
|
||||
response={200: RollbackResponseSchema, 400: ErrorSchema, 403: ErrorSchema},
|
||||
summary="Rollback company to historical state",
|
||||
description="Rollback company to a historical state (Moderators/Admins only)"
|
||||
)
|
||||
def rollback_company(request, company_id: UUID, event_id: int, payload: RollbackRequestSchema):
|
||||
"""
|
||||
Rollback company to a historical state.
|
||||
|
||||
**Permission:** Moderators, Admins, Superusers only
|
||||
"""
|
||||
# Check authentication
|
||||
if not request.user or not request.user.is_authenticated:
|
||||
return 401, {"error": "Authentication required"}
|
||||
|
||||
# Check rollback permission
|
||||
if not HistoryService.can_rollback(request.user):
|
||||
return 403, {"error": "Only moderators and administrators can perform rollbacks"}
|
||||
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
|
||||
try:
|
||||
result = HistoryService.rollback_to_event(
|
||||
company, 'company', event_id, request.user,
|
||||
fields=payload.fields,
|
||||
comment=payload.comment,
|
||||
create_backup=payload.create_backup
|
||||
)
|
||||
return result
|
||||
except (ValueError, PermissionError) as e:
|
||||
return 400, {"error": str(e)}
|
||||
|
||||
|
||||
@router.get(
|
||||
'/{company_id}/history/field/{field_name}/',
|
||||
response={200: FieldHistorySchema, 404: ErrorSchema},
|
||||
summary="Get field-specific history",
|
||||
description="Get history of changes to a specific company field"
|
||||
)
|
||||
def get_company_field_history(request, company_id: UUID, field_name: str):
|
||||
"""Get history of changes to a specific company field."""
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
|
||||
history = HistoryService.get_field_history(
|
||||
'company', str(company_id), field_name, request.user
|
||||
)
|
||||
|
||||
return {
|
||||
'entity_id': str(company_id),
|
||||
'entity_type': 'company',
|
||||
'entity_name': company.name,
|
||||
'field': field_name,
|
||||
'field_type': 'CharField', # Could introspect this
|
||||
**history
|
||||
}
|
||||
|
||||
|
||||
@router.get(
|
||||
'/{company_id}/history/summary/',
|
||||
response={200: HistoryActivitySummarySchema, 404: ErrorSchema},
|
||||
summary="Get company activity summary",
|
||||
description="Get activity summary for a company"
|
||||
)
|
||||
def get_company_activity_summary(request, company_id: UUID):
|
||||
"""Get activity summary for a company."""
|
||||
company = get_object_or_404(Company, id=company_id)
|
||||
|
||||
summary = HistoryService.get_activity_summary(
|
||||
'company', str(company_id), request.user
|
||||
)
|
||||
|
||||
return {
|
||||
'entity_id': str(company_id),
|
||||
'entity_type': 'company',
|
||||
'entity_name': company.name,
|
||||
**summary
|
||||
}
|
||||
Reference in New Issue
Block a user