nexus-5/core/graphql/mutations/project_scope_template.py
2026-01-26 11:09:40 -05:00

142 lines
7.0 KiB
Python

from typing import cast
import strawberry
from strawberry.types import Info
from strawberry.scalars import JSON
from asgiref.sync import sync_to_async
from core.graphql.inputs.project_scope_template import (
ProjectScopeTemplateInput,
ProjectScopeTemplateUpdateInput,
ProjectAreaTemplateInput,
ProjectAreaTemplateUpdateInput,
ProjectTaskTemplateInput,
ProjectTaskTemplateUpdateInput,
)
from core.graphql.pubsub import pubsub
from core.graphql.types.project_scope_template import (
ProjectScopeTemplateType,
ProjectAreaTemplateType,
ProjectTaskTemplateType,
)
from core.graphql.utils import create_object, update_object, delete_object
from core.models.project_scope_template import (
ProjectScopeTemplate,
ProjectAreaTemplate,
ProjectTaskTemplate,
)
from core.services.scope_builder import build_project_scope_template
@strawberry.type
class Mutation:
@strawberry.mutation(description="Create a new Project Scope Template")
async def create_project_scope_template(self, input: ProjectScopeTemplateInput, info: Info) -> ProjectScopeTemplateType:
instance = await create_object(input, ProjectScopeTemplate)
await pubsub.publish("project_scope_template_created", instance.id)
# Note: No event publisher exists for project scope template CRUD operations yet
return cast(ProjectScopeTemplateType, instance)
@strawberry.mutation(description="Update an existing Project Scope Template")
async def update_project_scope_template(self, input: ProjectScopeTemplateUpdateInput, info: Info) -> ProjectScopeTemplateType:
instance = await update_object(input, ProjectScopeTemplate)
await pubsub.publish("project_scope_template_updated", instance.id)
# Note: No event publisher exists for project scope template CRUD operations yet
return cast(ProjectScopeTemplateType, instance)
@strawberry.mutation(description="Delete a Project Scope Template")
async def delete_project_scope_template(self, id: strawberry.ID, info: Info) -> strawberry.ID:
instance = await delete_object(id, ProjectScopeTemplate)
if not instance:
raise ValueError(f"ProjectScopeTemplate with ID {id} does not exist")
await pubsub.publish("project_scope_template_deleted", id)
# Note: No event publisher exists for project scope template CRUD operations yet
return id
@strawberry.mutation(description="Create a Project Area Template")
async def create_project_area_template(self, input: ProjectAreaTemplateInput, info: Info) -> ProjectAreaTemplateType:
instance = await create_object(input, ProjectAreaTemplate)
await pubsub.publish("project_area_template_created", instance.id)
# Note: No event publisher exists for project area template CRUD operations yet
return cast(ProjectAreaTemplateType, instance)
@strawberry.mutation(description="Update a Project Area Template")
async def update_project_area_template(self, input: ProjectAreaTemplateUpdateInput, info: Info) -> ProjectAreaTemplateType:
instance = await update_object(input, ProjectAreaTemplate)
await pubsub.publish("project_area_template_updated", instance.id)
# Note: No event publisher exists for project area template CRUD operations yet
return cast(ProjectAreaTemplateType, instance)
@strawberry.mutation(description="Delete a Project Area Template")
async def delete_project_area_template(self, id: strawberry.ID, info: Info) -> strawberry.ID:
instance = await delete_object(id, ProjectAreaTemplate)
if not instance:
raise ValueError(f"ProjectAreaTemplate with ID {id} does not exist")
await pubsub.publish("project_area_template_deleted", id)
# Note: No event publisher exists for project area template CRUD operations yet
return id
@strawberry.mutation(description="Create a Project Task Template")
async def create_project_task_template(self, input: ProjectTaskTemplateInput, info: Info) -> ProjectTaskTemplateType:
instance = await create_object(input, ProjectTaskTemplate)
await pubsub.publish("project_task_template_created", instance.id)
# Note: No event publisher exists for project task template CRUD operations yet
return cast(ProjectTaskTemplateType, instance)
@strawberry.mutation(description="Update a Project Task Template")
async def update_project_task_template(self, input: ProjectTaskTemplateUpdateInput, info: Info) -> ProjectTaskTemplateType:
instance = await update_object(input, ProjectTaskTemplate)
await pubsub.publish("project_task_template_updated", instance.id)
# Note: No event publisher exists for project task template CRUD operations yet
return cast(ProjectTaskTemplateType, instance)
@strawberry.mutation(description="Delete a Project Task Template")
async def delete_project_task_template(self, id: strawberry.ID, info: Info) -> strawberry.ID:
instance = await delete_object(id, ProjectTaskTemplate)
if not instance:
raise ValueError(f"ProjectTaskTemplate with ID {id} does not exist")
await pubsub.publish("project_task_template_deleted", id)
# Note: No event publisher exists for project task template CRUD operations yet
return id
@strawberry.mutation(description="Create a ProjectScopeTemplate (and nested Categories/Tasks) from a JSON payload")
async def create_project_scope_template_from_json(
self,
payload: JSON,
replace: bool = False,
info: Info | None = None,
) -> ProjectScopeTemplateType:
"""
Accepts a JSON object matching the builder payload shape:
{
"name": str, "description": str, "is_active": bool,
"categories": [
{"name": str, "order": int, "tasks": [
{"description": str, "checklist_description": str, "order": int, "estimated_minutes": int}
]}
]
}
If replace=True and a template with the same name exists, it will be deleted first.
"""
def _do_create_sync():
if not isinstance(payload, dict):
raise ValueError("payload must be a JSON object")
name = payload.get("name")
if not name or not isinstance(name, str):
raise ValueError("payload.name is required and must be a string")
if replace:
ProjectScopeTemplate.objects.filter(name=name).delete()
elif ProjectScopeTemplate.objects.filter(name=name).exists():
raise ValueError(
f"A ProjectScopeTemplate named '{name}' already exists (use replace=true to overwrite)"
)
tpl = build_project_scope_template(payload)
return tpl
instance = await sync_to_async(_do_create_sync)()
await pubsub.publish("project_scope_template_created", instance.id)
# Note: No event publisher exists for project scope template CRUD operations yet
return cast(ProjectScopeTemplateType, instance)