247 lines
9.8 KiB
Python
247 lines
9.8 KiB
Python
from typing import cast
|
|
import strawberry
|
|
from strawberry.types import Info
|
|
from asgiref.sync import sync_to_async
|
|
from core.graphql.pubsub import pubsub
|
|
from core.graphql.utils import create_object, update_object, delete_object, _decode_global_id
|
|
from core.graphql.types.scope_template import (
|
|
ScopeTemplateType,
|
|
AreaTemplateType,
|
|
TaskTemplateType,
|
|
)
|
|
from core.graphql.types.scope import ScopeType
|
|
from core.graphql.inputs.scope_template import (
|
|
ScopeTemplateInput, ScopeTemplateUpdateInput,
|
|
AreaTemplateInput, AreaTemplateUpdateInput,
|
|
TaskTemplateInput, TaskTemplateUpdateInput,
|
|
CreateScopeFromTemplateInput,
|
|
)
|
|
from core.models.scope_template import ScopeTemplate, AreaTemplate, TaskTemplate
|
|
from core.models.account import Account, AccountAddress
|
|
from strawberry.scalars import JSON
|
|
from core.services import build_scope_template
|
|
from core.services.events import (
|
|
publish_scope_template_created, publish_scope_template_updated, publish_scope_template_deleted,
|
|
publish_scope_template_instantiated,
|
|
publish_area_template_created, publish_area_template_updated, publish_area_template_deleted,
|
|
publish_task_template_created, publish_task_template_updated, publish_task_template_deleted,
|
|
)
|
|
|
|
|
|
@strawberry.type
|
|
class Mutation:
|
|
@strawberry.mutation(description="Create a new scope template")
|
|
async def create_scope_template(self, input: ScopeTemplateInput, info: Info) -> ScopeTemplateType:
|
|
instance = await create_object(input, ScopeTemplate)
|
|
await pubsub.publish("scope_template_created", instance.id)
|
|
|
|
# Publish event
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
await publish_scope_template_created(
|
|
template_id=str(instance.id),
|
|
triggered_by=profile
|
|
)
|
|
|
|
return cast(ScopeTemplateType, instance)
|
|
|
|
@strawberry.mutation(description="Update an existing scope template")
|
|
async def update_scope_template(self, input: ScopeTemplateUpdateInput, info: Info) -> ScopeTemplateType:
|
|
instance = await update_object(input, ScopeTemplate)
|
|
await pubsub.publish("scope_template_updated", instance.id)
|
|
|
|
# Publish event
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
await publish_scope_template_updated(
|
|
template_id=str(instance.id),
|
|
triggered_by=profile
|
|
)
|
|
|
|
return cast(ScopeTemplateType, instance)
|
|
|
|
@strawberry.mutation(description="Delete an existing scope template")
|
|
async def delete_scope_template(self, id: strawberry.ID, info: Info) -> strawberry.ID:
|
|
instance = await delete_object(id, ScopeTemplate)
|
|
if not instance:
|
|
raise ValueError(f"ScopeTemplate with ID {id} does not exist")
|
|
await pubsub.publish("scope_template_deleted", id)
|
|
|
|
# Publish event
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
await publish_scope_template_deleted(
|
|
template_id=str(id),
|
|
triggered_by=profile
|
|
)
|
|
|
|
return id
|
|
|
|
@strawberry.mutation(description="Create a new area template")
|
|
async def create_area_template(self, input: AreaTemplateInput, info: Info) -> AreaTemplateType:
|
|
instance = await create_object(input, AreaTemplate)
|
|
await pubsub.publish("area_template_created", instance.id)
|
|
|
|
# Publish event
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
await publish_area_template_created(
|
|
template_id=str(instance.id),
|
|
scope_template_id=str(instance.scope_template_id),
|
|
triggered_by=profile
|
|
)
|
|
|
|
return cast(AreaTemplateType, instance)
|
|
|
|
@strawberry.mutation(description="Update an existing area template")
|
|
async def update_area_template(self, input: AreaTemplateUpdateInput, info: Info) -> AreaTemplateType:
|
|
instance = await update_object(input, AreaTemplate)
|
|
await pubsub.publish("area_template_updated", instance.id)
|
|
|
|
# Publish event
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
await publish_area_template_updated(
|
|
template_id=str(instance.id),
|
|
scope_template_id=str(instance.scope_template_id),
|
|
triggered_by=profile
|
|
)
|
|
|
|
return cast(AreaTemplateType, instance)
|
|
|
|
@strawberry.mutation(description="Delete an existing area template")
|
|
async def delete_area_template(self, id: strawberry.ID, info: Info) -> strawberry.ID:
|
|
instance = await delete_object(id, AreaTemplate)
|
|
if not instance:
|
|
raise ValueError(f"AreaTemplate with ID {id} does not exist")
|
|
await pubsub.publish("area_template_deleted", id)
|
|
|
|
# Publish event
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
await publish_area_template_deleted(
|
|
template_id=str(id),
|
|
scope_template_id=str(instance.scope_template_id),
|
|
triggered_by=profile
|
|
)
|
|
|
|
return id
|
|
|
|
@strawberry.mutation(description="Create a new task template")
|
|
async def create_task_template(self, input: TaskTemplateInput, info: Info) -> TaskTemplateType:
|
|
instance = await create_object(input, TaskTemplate)
|
|
await pubsub.publish("task_template_created", instance.id)
|
|
|
|
# Publish event
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
await publish_task_template_created(
|
|
template_id=str(instance.id),
|
|
area_template_id=str(instance.area_template_id),
|
|
triggered_by=profile
|
|
)
|
|
|
|
return cast(TaskTemplateType, instance)
|
|
|
|
@strawberry.mutation(description="Update an existing task template")
|
|
async def update_task_template(self, input: TaskTemplateUpdateInput, info: Info) -> TaskTemplateType:
|
|
instance = await update_object(input, TaskTemplate)
|
|
await pubsub.publish("task_template_updated", instance.id)
|
|
|
|
# Publish event
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
await publish_task_template_updated(
|
|
template_id=str(instance.id),
|
|
area_template_id=str(instance.area_template_id),
|
|
triggered_by=profile
|
|
)
|
|
|
|
return cast(TaskTemplateType, instance)
|
|
|
|
@strawberry.mutation(description="Delete an existing task template")
|
|
async def delete_task_template(self, id: strawberry.ID, info: Info) -> strawberry.ID:
|
|
instance = await delete_object(id, TaskTemplate)
|
|
if not instance:
|
|
raise ValueError(f"TaskTemplate with ID {id} does not exist")
|
|
await pubsub.publish("task_template_deleted", id)
|
|
|
|
# Publish event
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
await publish_task_template_deleted(
|
|
template_id=str(id),
|
|
area_template_id=str(instance.area_template_id),
|
|
triggered_by=profile
|
|
)
|
|
|
|
return id
|
|
|
|
@strawberry.mutation(description="Instantiate a Scope (with Areas and Tasks) from a ScopeTemplate")
|
|
async def create_scope_from_template(self, input: CreateScopeFromTemplateInput, info: Info) -> ScopeType:
|
|
def _do_create_sync():
|
|
template = ScopeTemplate.objects.get(pk=_decode_global_id(input.template_id))
|
|
account = Account.objects.get(pk=_decode_global_id(input.account_id))
|
|
account_address = None
|
|
if input.account_address_id:
|
|
account_address = AccountAddress.objects.get(
|
|
pk=_decode_global_id(input.account_address_id), account=account
|
|
)
|
|
scope = template.instantiate(
|
|
account=account,
|
|
account_address=account_address,
|
|
name=input.name,
|
|
description=input.description,
|
|
is_active=input.is_active if input.is_active is not None else True,
|
|
)
|
|
return scope, str(template.id), str(account.id)
|
|
|
|
# Run ORM-heavy work in a thread
|
|
instance, template_id, account_id = await sync_to_async(_do_create_sync)()
|
|
await pubsub.publish("scope_created_from_template", instance.id)
|
|
|
|
# Publish event
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
await publish_scope_template_instantiated(
|
|
scope_id=str(instance.id),
|
|
template_id=template_id,
|
|
account_id=account_id,
|
|
triggered_by=profile
|
|
)
|
|
|
|
return cast(ScopeType, instance)
|
|
|
|
@strawberry.mutation(description="Create a ScopeTemplate (and nested Areas/Tasks) from a JSON payload")
|
|
async def create_scope_template_from_json(
|
|
self,
|
|
payload: JSON,
|
|
replace: bool = False,
|
|
info: Info | None = None,
|
|
) -> ScopeTemplateType:
|
|
"""
|
|
Accepts a JSON object matching the builder payload shape.
|
|
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:
|
|
ScopeTemplate.objects.filter(name=name).delete()
|
|
elif ScopeTemplate.objects.filter(name=name).exists():
|
|
raise ValueError(
|
|
f"A ScopeTemplate named '{name}' already exists (use replace=true to overwrite)"
|
|
)
|
|
|
|
tpl = build_scope_template(payload)
|
|
return tpl
|
|
|
|
instance = await sync_to_async(_do_create_sync)()
|
|
await pubsub.publish("scope_template_created", instance.id)
|
|
|
|
# Publish event
|
|
if info:
|
|
profile = getattr(info.context.request, 'profile', None)
|
|
await publish_scope_template_created(
|
|
template_id=str(instance.id),
|
|
triggered_by=profile
|
|
)
|
|
|
|
return cast(ScopeTemplateType, instance)
|