from typing import cast import strawberry from strawberry.types import Info from channels.db import database_sync_to_async from core.graphql.pubsub import pubsub from core.graphql.inputs.profile import ( CustomerProfileInput, CustomerProfileUpdateInput, TeamProfileInput, TeamProfileUpdateInput, ) from core.graphql.types.profile import CustomerProfileType, TeamProfileType from core.models.profile import CustomerProfile, TeamProfile from core.graphql.utils import create_object, update_object, delete_object from core.services.events import ( publish_team_profile_created, publish_team_profile_updated, publish_team_profile_deleted, publish_team_profile_role_changed, publish_customer_profile_created, publish_customer_profile_updated, publish_customer_profile_deleted, publish_customer_profile_access_granted, publish_customer_profile_access_revoked, ) @strawberry.type class Mutation: @strawberry.mutation(description="Create a new customer profile") async def create_customer_profile( self, input: CustomerProfileInput, info: Info ) -> CustomerProfileType: m2m_data = {"customers": input.customer_ids} if input.customer_ids else None instance = await create_object(input, CustomerProfile, m2m_data) await pubsub.publish(f"customer_profile_created", instance.id) # Publish event profile = getattr(info.context.request, 'profile', None) await publish_customer_profile_created(str(instance.id), triggered_by=profile) return cast(CustomerProfileType, instance) @strawberry.mutation(description="Update an existing customer profile") async def update_customer_profile( self, input: CustomerProfileUpdateInput, info: Info ) -> CustomerProfileType: # Get old profile to detect customer access changes old_profile = await database_sync_to_async(CustomerProfile.objects.get)(pk=input.id.node_id) old_customer_ids = set(str(cid) for cid in await database_sync_to_async(list)( old_profile.customers.values_list('id', flat=True) )) m2m_data = {"customers": input.customer_ids} if input.customer_ids else None instance = await update_object(input, CustomerProfile, m2m_data) await pubsub.publish(f"customer_profile_updated", instance.id) # Publish event profile = getattr(info.context.request, 'profile', None) await publish_customer_profile_updated(str(instance.id), triggered_by=profile) # Detect customer access changes if input.customer_ids is not None: new_customer_ids = set(str(cid) for cid in input.customer_ids) # Newly granted access for customer_id in new_customer_ids - old_customer_ids: await publish_customer_profile_access_granted( str(instance.id), customer_id, triggered_by=profile ) # Revoked access for customer_id in old_customer_ids - new_customer_ids: await publish_customer_profile_access_revoked( str(instance.id), customer_id, triggered_by=profile ) return cast(CustomerProfileType, instance) @strawberry.mutation(description="Delete an existing customer profile") async def delete_customer_profile(self, id: strawberry.ID, info: Info) -> strawberry.ID: instance = await delete_object(id, CustomerProfile) if not instance: raise ValueError(f"CustomerProfile with ID {id} does not exist") await pubsub.publish(f"customer_profile_deleted", id) # Publish event profile = getattr(info.context.request, 'profile', None) await publish_customer_profile_deleted(str(id), triggered_by=profile) return id @strawberry.mutation(description="Create a new team profile") async def create_team_profile(self, input: TeamProfileInput, info: Info) -> TeamProfileType: instance = await create_object(input, TeamProfile) await pubsub.publish(f"team_profile_created", instance.id) # Publish event profile = getattr(info.context.request, 'profile', None) await publish_team_profile_created(str(instance.id), triggered_by=profile) return cast(TeamProfileType, instance) @strawberry.mutation(description="Update an existing team profile") async def update_team_profile(self, input: TeamProfileUpdateInput, info: Info) -> TeamProfileType: # Get old profile to detect role changes old_profile = await database_sync_to_async(TeamProfile.objects.get)(pk=input.id.node_id) old_role = old_profile.role instance = await update_object(input, TeamProfile) await pubsub.publish(f"team_profile_updated", instance.id) # Publish event profile = getattr(info.context.request, 'profile', None) await publish_team_profile_updated(str(instance.id), triggered_by=profile) # Check for role change if input.role is not None and input.role != old_role: await publish_team_profile_role_changed( str(instance.id), old_role, input.role, triggered_by=profile ) return cast(TeamProfileType, instance) @strawberry.mutation(description="Delete an existing team profile") async def delete_team_profile(self, id: strawberry.ID, info: Info) -> strawberry.ID: instance = await delete_object(id, TeamProfile) if not instance: raise ValueError(f"TeamProfile with ID {id} does not exist") await pubsub.publish(f"team_profile_deleted", id) # Publish event profile = getattr(info.context.request, 'profile', None) await publish_team_profile_deleted(str(id), triggered_by=profile) return id