Skip to content

Commit

Permalink
Merge pull request #564 from maykinmedia/feature/558-endpoint-to-dele…
Browse files Browse the repository at this point in the history
…te-list

[#558] Refactor queue destruction endpoint
  • Loading branch information
SilviaAmAm authored Dec 20, 2024
2 parents 4e0eaff + 802feed commit 1fe1f25
Show file tree
Hide file tree
Showing 6 changed files with 63 additions and 47 deletions.
38 changes: 24 additions & 14 deletions backend/src/openarchiefbeheer/destruction/api/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,15 @@
description=_("Retrieve details about a destruction list."),
responses={200: DestructionListReadSerializer},
),
destroy=extend_schema(
queue_destruction=extend_schema(
tags=["Destruction list"],
summary=_("Destroy destruction list"),
summary=_("Queue destruction list destruction"),
description=_(
"Calling this endpoint will start a background process that will "
"Calling this endpoint will queue a background process that will "
"delete the cases in the list from the case system."
),
request=None,
responses={200: None},
),
make_final=extend_schema(
tags=["Destruction list"],
Expand Down Expand Up @@ -236,7 +238,7 @@ def get_permissions(self):
permission_classes = [IsAuthenticated & CanStartDestructionPermission]
elif self.action == "update":
permission_classes = [IsAuthenticated & CanUpdateDestructionList]
elif self.action == "destroy":
elif self.action == "queue_destruction":
permission_classes = [IsAuthenticated & CanTriggerDeletion]
elif self.action == "make_final":
permission_classes = [IsAuthenticated & CanMarkListAsFinal]
Expand Down Expand Up @@ -268,10 +270,13 @@ def create(self, request, *args, **kwargs):
def update(self, request, *args, **kwargs):
return super().update(request, *args, **kwargs)

def perform_destroy(self, instance: DestructionList) -> None:
@action(detail=True, methods=["post"], name="queue-destruction")
def queue_destruction(self, request, *args, **kwargs) -> None:
destruction_list = self.get_object()

today = date.today()
destruction_date = today + timedelta(days=WAITING_PERIOD)
if not instance.all_items_can_be_deleted_by_date(destruction_date):
if not destruction_list.all_items_can_be_deleted_by_date(destruction_date):
raise ValidationError(
_(
"This list contains cases with archiving date later than %(destruction_date)s, "
Expand All @@ -281,8 +286,8 @@ def perform_destroy(self, instance: DestructionList) -> None:
)

if (
instance.planned_destruction_date
and instance.planned_destruction_date > today
destruction_list.planned_destruction_date
and destruction_list.planned_destruction_date > today
):
raise ValidationError(
_(
Expand All @@ -291,15 +296,20 @@ def perform_destroy(self, instance: DestructionList) -> None:
% {"destruction_date": destruction_date.strftime("%d/%m/%Y")}
)

logevent.destruction_list_deletion_triggered(instance, self.request.user)
logevent.destruction_list_deletion_triggered(
destruction_list, self.request.user
)

if instance.processing_status == InternalStatus.new:
instance.planned_destruction_date = today + timedelta(days=WAITING_PERIOD)
instance.save()
return
if destruction_list.processing_status == InternalStatus.new:
destruction_list.planned_destruction_date = today + timedelta(
days=WAITING_PERIOD
)
destruction_list.save()
return Response()

# If it is a retry, process immediately
delete_destruction_list(instance)
delete_destruction_list(destruction_list)
return Response()

@action(detail=True, methods=["post"], name="make-final")
def make_final(self, request, *args, **kwargs):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,13 +30,14 @@ def test_plan_destruction(self):

self.client.force_authenticate(user=record_manager)
with freezegun.freeze_time("2024-01-01T21:36:00+02:00"):
response = self.client.delete(
response = self.client.post(
reverse(
"api:destructionlist-detail", kwargs={"uuid": destruction_list.uuid}
"api:destructionlist-queue-destruction",
kwargs={"uuid": destruction_list.uuid},
),
)

self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
self.assertEqual(status.HTTP_200_OK, response.status_code)

destruction_list.refresh_from_db()

Expand Down Expand Up @@ -69,13 +70,14 @@ def test_retry_destruction_after_failure_queues_immediately(
"openarchiefbeheer.destruction.api.viewsets.delete_destruction_list"
) as m_delete,
):
response = self.client.delete(
response = self.client.post(
reverse(
"api:destructionlist-detail", kwargs={"uuid": destruction_list.uuid}
"api:destructionlist-queue-destruction",
kwargs={"uuid": destruction_list.uuid},
),
)

self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
self.assertEqual(status.HTTP_200_OK, response.status_code)
m_delete.assert_called_once()
self.assertEqual(m_delete.call_args_list[0].args[0].pk, destruction_list.pk)

Expand All @@ -98,9 +100,10 @@ def test_retry_destruction_after_failure_with_planned_date_in_future_raises_erro
)
self.client.force_authenticate(user=record_manager)
with (freezegun.freeze_time("2024-01-01T21:36:00+02:00"),):
response = self.client.delete(
response = self.client.post(
reverse(
"api:destructionlist-detail", kwargs={"uuid": destruction_list.uuid}
"api:destructionlist-queue-destruction",
kwargs={"uuid": destruction_list.uuid},
),
)

Expand All @@ -122,13 +125,14 @@ def test_can_start_destruction_if_not_author(self):
with patch(
"openarchiefbeheer.destruction.api.viewsets.delete_destruction_list"
):
response = self.client.delete(
response = self.client.post(
reverse(
"api:destructionlist-detail", kwargs={"uuid": destruction_list.uuid}
"api:destructionlist-queue-destruction",
kwargs={"uuid": destruction_list.uuid},
),
)

self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
self.assertEqual(status.HTTP_200_OK, response.status_code)

def test_cannot_start_destruction_if_not_ready_to_delete(self):
record_manager = UserFactory.create(post__can_start_destruction=True)
Expand All @@ -143,9 +147,10 @@ def test_cannot_start_destruction_if_not_ready_to_delete(self):
with patch(
"openarchiefbeheer.destruction.api.viewsets.delete_destruction_list"
) as m_task:
response = self.client.delete(
response = self.client.post(
reverse(
"api:destructionlist-detail", kwargs={"uuid": destruction_list.uuid}
"api:destructionlist-queue-destruction",
kwargs={"uuid": destruction_list.uuid},
),
)

Expand Down Expand Up @@ -176,9 +181,10 @@ def test_cannot_start_destruction_if_archiefactiedatum_in_the_future(self):

self.client.force_authenticate(user=record_manager)
with freezegun.freeze_time("2024-01-01T21:36:00+02:00"):
response = self.client.delete(
response = self.client.post(
reverse(
"api:destructionlist-detail", kwargs={"uuid": destruction_list.uuid}
"api:destructionlist-queue-destruction",
kwargs={"uuid": destruction_list.uuid},
),
)

Expand Down Expand Up @@ -216,13 +222,14 @@ def test_can_start_destruction_if_archiefactiedatum_in_the_future_but_removed(se

self.client.force_authenticate(user=record_manager)
with freezegun.freeze_time("2024-01-01T21:36:00+02:00"):
response = self.client.delete(
response = self.client.post(
reverse(
"api:destructionlist-detail", kwargs={"uuid": destruction_list.uuid}
"api:destructionlist-queue-destruction",
kwargs={"uuid": destruction_list.uuid},
),
)

self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code)
self.assertEqual(status.HTTP_200_OK, response.status_code)

logs = TimelineLog.objects.for_object(destruction_list).filter(
template="logging/destruction_list_deletion_triggered.txt"
Expand Down
6 changes: 3 additions & 3 deletions frontend/.storybook/mockData.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,9 +162,9 @@ export const MOCKS = {
status: "200",
response: FIXTURE_DESTRUCTION_LIST,
},
DESTRUCTION_LIST_DELETE: {
url: "http://localhost:8000/api/v1/destruction-lists/00000000-0000-0000-0000-000000000000", // FIXME
method: "DELETE",
DESTRUCTION_LIST_QUEUE_DESTRUCTION: {
url: "http://localhost:8000/api/v1/destruction-lists/00000000-0000-0000-0000-000000000000/queue_destruction/",
method: "POST",
status: "200",
response: {},
},
Expand Down
9 changes: 4 additions & 5 deletions frontend/src/lib/api/destructionLists.ts
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,14 @@ export async function markDestructionListAsFinal(
* @param uuid
* @returns
*/
export async function destroyDestructionList(uuid: string) {
export async function destructionListQueueDestruction(uuid: string) {
const response = await request(
"DELETE",
`/destruction-lists/${uuid}/`,
"POST",
`/destruction-lists/${uuid}/queue_destruction/`,
{},
{ uuid },
);
// Check if the response is a 201 Created status code.
if (response.status === 204) {
if (response.status === 200) {
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { redirect } from "react-router-dom";
import { JsonValue, TypedAction } from "../../../hooks";
import {
abort,
destroyDestructionList,
destructionListQueueDestruction,
markDestructionListAsFinal,
markDestructionListAsReadyToReview,
updateDestructionList,
Expand All @@ -16,7 +16,7 @@ import {
import { clearZaakSelection } from "../../../lib/zaakSelection/zaakSelection";

export type UpdateDestructionListAction<P = JsonValue> = TypedAction<
| "DESTROY"
| "QUEUE_DESTRUCTION"
| "CANCEL_DESTROY"
| "MAKE_FINAL"
| "PROCESS_REVIEW"
Expand All @@ -36,8 +36,8 @@ export async function destructionListUpdateAction({
const action = data as UpdateDestructionListAction<unknown>;

switch (action.type) {
case "DESTROY":
return await destructionListDestroyAction({ request, params });
case "QUEUE_DESTRUCTION":
return await destructionListQueueDestructionAction({ request, params });
case "MAKE_FINAL":
return await destructionListMakeFinalAction({ request, params });
case "PROCESS_REVIEW":
Expand Down Expand Up @@ -73,12 +73,12 @@ export async function destructionListMakeFinalAction({
/**
* React Router action (user intents to DESTROY ALL ZAKEN ON THE DESTRUCTION LIST!).
*/
export async function destructionListDestroyAction({
export async function destructionListQueueDestructionAction({
request,
}: ActionFunctionArgs) {
const { payload } = await request.json();
try {
await destroyDestructionList(payload.uuid);
await destructionListQueueDestruction(payload.uuid);
} catch (e: unknown) {
if (e instanceof Response) {
return await (e as Response).json();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,7 @@ export function useSecondaryNavigation(): ToolbarItem[] {
*/
const handleDestroy = async () => {
submitAction({
type: "DESTROY",
type: "QUEUE_DESTRUCTION",
payload: {
uuid: destructionList.uuid,
},
Expand Down

0 comments on commit 1fe1f25

Please sign in to comment.