from typing import cast import strawberry from strawberry.types import Info from core.graphql.pubsub import pubsub from core.graphql.inputs.report import ReportInput, ReportUpdateInput from core.graphql.types.report import ReportType from core.models.report import Report from core.graphql.utils import create_object, update_object, delete_object from core.services.events import publish_report_submitted, publish_report_updated, publish_report_deleted @strawberry.type class Mutation: @strawberry.mutation(description="Create a new report") async def create_report(self, input: ReportInput, info: Info) -> ReportType: # Exclude m2m id fields from model constructor payload = {k: v for k, v in input.__dict__.items() if k not in {"service_ids", "project_ids"}} m2m_data = { "services": input.service_ids, "projects": input.project_ids, } instance = await create_object(payload, Report, m2m_data) await pubsub.publish("report_created", instance.id) # Publish event for notifications (report creation = report submission) profile = getattr(info.context.request, 'profile', None) await publish_report_submitted( report_id=str(instance.id), triggered_by=profile, metadata={'team_member_id': str(instance.team_member_id)} ) return cast(ReportType, instance) @strawberry.mutation(description="Update an existing report") async def update_report(self, input: ReportUpdateInput, info: Info) -> ReportType: # Keep id and non-m2m fields; drop m2m *_ids from the update payload payload = {k: v for k, v in input.__dict__.items() if k not in {"service_ids", "project_ids"}} m2m_data = { "services": getattr(input, "service_ids", None), "projects": getattr(input, "project_ids", None), } instance = await update_object(payload, Report, m2m_data) await pubsub.publish("report_updated", instance.id) # Publish event for notifications profile = getattr(info.context.request, 'profile', None) await publish_report_updated( report_id=str(instance.id), triggered_by=profile, metadata={'team_member_id': str(instance.team_member_id)} ) return cast(ReportType, instance) @strawberry.mutation(description="Delete an existing report") async def delete_report(self, id: strawberry.ID, info: Info) -> strawberry.ID: instance = await delete_object(id, Report) if not instance: raise ValueError(f"Report with ID {id} does not exist") await pubsub.publish("report_deleted", id) # Publish event for notifications profile = getattr(info.context.request, 'profile', None) await publish_report_deleted( report_id=str(id), triggered_by=profile ) return id