Skip to content

Commit

Permalink
feat(workflows): add the endpoint to delete a workflow
Browse files Browse the repository at this point in the history
  • Loading branch information
daniel-herrero committed Oct 20, 2023
1 parent c2dd562 commit 114189c
Show file tree
Hide file tree
Showing 14 changed files with 680 additions and 58 deletions.
8 changes: 8 additions & 0 deletions python/apps/taiga/src/taiga/stories/stories/repositories.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,11 @@ def list_stories_to_reorder(filters: StoryFilters = {}) -> list[Story]:
@sync_to_async
def list_story_assignees(story: Story) -> list[User]:
return list(story.assignees.all().order_by("-story_assignments__created_at"))


async def bulk_update_workflow_to_stories(
statuses_ids: list[UUID], old_workflow_id: UUID, new_workflow_id: UUID
) -> None:
await Story.objects.filter(status_id__in=statuses_ids, workflow_id=old_workflow_id).aupdate(
workflow_id=new_workflow_id
)
45 changes: 42 additions & 3 deletions python/apps/taiga/src/taiga/workflows/api/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from taiga.workflows.api.validators import (
CreateWorkflowStatusValidator,
CreateWorkflowValidator,
DeleteWorkflowQuery,
DeleteWorkflowStatusQuery,
ReorderWorkflowStatusesValidator,
UpdateWorkflowStatusValidator,
Expand All @@ -32,6 +33,7 @@
CREATE_WORKFLOW = IsProjectAdmin()
LIST_WORKFLOWS = HasPerm("view_story")
GET_WORKFLOW = HasPerm("view_story")
DELETE_WORKFLOW = IsProjectAdmin()
UPDATE_WORKFLOW = IsProjectAdmin()
CREATE_WORKFLOW_STATUS = IsProjectAdmin()
UPDATE_WORKFLOW_STATUS = IsProjectAdmin()
Expand Down Expand Up @@ -119,7 +121,7 @@ async def get_workflow(
return await workflows_services.get_workflow_detail(project_id=project_id, workflow_slug=workflow_slug)


##########################################################
#########################################################
# update workflow
##########################################################

Expand Down Expand Up @@ -147,6 +149,44 @@ async def update_workflow(
return await workflows_services.update_workflow(project_id=project_id, workflow=workflow, values=values)


################################################
# delete workflow
################################################


@routes.workflows.delete(
"/projects/{project_id}/workflows/{workflow_slug}",
name="project.workflow.delete",
summary="Delete a workflow",
responses=ERROR_403 | ERROR_404 | ERROR_422,
status_code=status.HTTP_204_NO_CONTENT,
)
async def delete_workflow(
project_id: B64UUID,
workflow_slug: str,
request: AuthRequest,
query_params: DeleteWorkflowQuery = Depends(),
) -> None:
"""
Deletes a workflow in the given project, providing the option to move all the statuses and their stories to another
workflow.
Query params:
* **move_to:** the workflow's slug to which move the statuses from the workflow being deleted
- if not received, the workflow, statuses and its contained stories will be deleted
- if received, the workflow will be deleted but its statuses and stories won't (they will be appended to the
last status of the specified workflow).
"""
workflow = await get_workflow_or_404(project_id=project_id, workflow_slug=workflow_slug)
await check_permissions(permissions=DELETE_WORKFLOW, user=request.user, obj=workflow)

await workflows_services.delete_workflow(
workflow=workflow,
target_workflow_slug=query_params.move_to,
)


################################################
# misc
################################################
Expand Down Expand Up @@ -247,7 +287,7 @@ async def reorder_workflow_statuses(
await check_permissions(permissions=REORDER_WORKFLOW_STATUSES, user=request.user, obj=workflow)

return await workflows_services.reorder_workflow_statuses(
workflow=workflow,
target_workflow=workflow,
statuses=form.statuses,
reorder=form.get_reorder_dict(),
)
Expand Down Expand Up @@ -277,7 +317,6 @@ async def delete_workflow_status(
to any other existing workflow status in the same workflow.
Query params:
* **move_to:** the workflow status's slug to which move the stories from the status being deleted
- if not received, the workflow status and its contained stories will be deleted
- if received, the workflow status will be deleted but its contained stories won't (they will be first moved to
Expand Down
10 changes: 10 additions & 0 deletions python/apps/taiga/src/taiga/workflows/api/validators.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,16 @@ class CreateWorkflowValidator(BaseModel):
name: WorkflowName


class DeleteWorkflowQuery(BaseModel):
move_to: WorkflowName | None

@validator("move_to")
def check_move_to_slug(cls, v: WorkflowName | None) -> WorkflowName | None:
if v is None:
return None
return v


class CreateWorkflowStatusValidator(BaseModel):
name: WorkflowStatusName
color: conint(gt=0, lt=9) # type: ignore
Expand Down
15 changes: 15 additions & 0 deletions python/apps/taiga/src/taiga/workflows/events/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from taiga.workflows.events.content import (
CreateWorkflowContent,
CreateWorkflowStatusContent,
DeleteWorkflowContent,
DeleteWorkflowStatusContent,
ReorderWorkflowStatusesContent,
UpdateWorkflowContent,
Expand All @@ -20,6 +21,7 @@

CREATE_WORKFLOW = "workflows.create"
UPDATE_WORKFLOW = "workflows.update"
DELETE_WORKFLOW = "workflows.delete"
CREATE_WORKFLOW_STATUS = "workflowstatuses.create"
UPDATE_WORKFLOW_STATUS = "workflowstatuses.update"
REORDER_WORKFLOW_STATUS = "workflowstatuses.reorder"
Expand All @@ -44,6 +46,19 @@ async def emit_event_when_workflow_is_updated(project: Project, workflow: Workfl
)


async def emit_event_when_workflow_is_deleted(
project: Project, workflow: WorkflowSerializer, target_workflow: WorkflowSerializer | None
) -> None:
await events_manager.publish_on_project_channel(
project=project,
type=DELETE_WORKFLOW,
content=DeleteWorkflowContent(
workflow=workflow,
target_workflow=target_workflow,
),
)


async def emit_event_when_workflow_status_is_created(project: Project, workflow_status: WorkflowStatus) -> None:
await events_manager.publish_on_project_channel(
project=project,
Expand Down
5 changes: 5 additions & 0 deletions python/apps/taiga/src/taiga/workflows/events/content.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ class UpdateWorkflowContent(BaseModel):
workflow: WorkflowSerializer


class DeleteWorkflowContent(BaseModel):
workflow: WorkflowSerializer
target_workflow: WorkflowSerializer | None


class CreateWorkflowStatusContent(BaseModel):
workflow_status: WorkflowStatusSerializer

Expand Down
12 changes: 12 additions & 0 deletions python/apps/taiga/src/taiga/workflows/repositories.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@


class WorkflowFilters(TypedDict, total=False):
id: UUID
slug: str
project_id: UUID

Expand Down Expand Up @@ -162,6 +163,17 @@ def update_workflow(workflow: Workflow, values: dict[str, Any] = {}) -> Workflow
return workflow


##########################################################
# Workflow - delete workflow
##########################################################


async def delete_workflow(filters: WorkflowFilters = {}) -> int:
qs = _apply_filters_to_workflow_queryset(qs=DEFAULT_QUERYSET_WORKFLOW, filters=filters)
count, _ = await qs.adelete()
return count


##########################################################
# WorkflowStatus - filters and querysets
##########################################################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ class Config:
class ReorderWorkflowStatusesSerializer(BaseModel):
workflow: WorkflowNestedSerializer
statuses: list[UUIDB64]
reorder: ReorderSerializer
reorder: ReorderSerializer | None

class Config:
orm_mode = True
Loading

0 comments on commit 114189c

Please sign in to comment.