From 9763dab1f7ed1a63c53c0974dba6f37300c69678 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Wed, 23 Dec 2020 10:46:46 +0200 Subject: Add bulk DELETE method to responses endpoint --- backend/routes/forms/responses.py | 57 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/backend/routes/forms/responses.py b/backend/routes/forms/responses.py index 54da246..d378187 100644 --- a/backend/routes/forms/responses.py +++ b/backend/routes/forms/responses.py @@ -8,7 +8,7 @@ from starlette.responses import JSONResponse from backend.models import FormResponse, ResponseList from backend.route import Route -from backend.validation import api, ErrorMessage +from backend.validation import api, ErrorMessage, OkayResponse class Responses(Route): @@ -38,3 +38,58 @@ class Responses(Route): FormResponse(**response) for response in await cursor.to_list(None) ] return JSONResponse([response.dict() for response in responses]) + + @requires(["authenticated", "admin"]) + @api.validate( + resp=Response( + HTTP_200=OkayResponse, + HTTP_404=ErrorMessage, + HTTP_400=ErrorMessage + ), + tags=["forms", "responses"] + ) + async def delete(self, request: Request) -> JSONResponse: + """Bulk deletes form responses by IDs.""" + data = await request.json() + + if "ids" not in data: + return JSONResponse({"error": "ids_not_provided"}, status_code=400) + + # Convert IDs to set to remove duplicates + ids = set(data["ids"]) + + cursor = request.state.db.responses.find( + {"_id": {"$in": list(ids)}} # Convert here back to list, may throw error. + ) + entries = [ + FormResponse(**submission) for submission in await cursor.to_list(None) + ] + actual_ids = {entry.id for entry in entries} + + if len(ids) != len(actual_ids): + return JSONResponse( + { + "error": "not_found", + "ids": list(ids - actual_ids) + }, + status_code=404 + ) + + if any(entry.form_id != request.path_params["form_id"] for entry in entries): + return JSONResponse( + { + "error": "wrong_form", + "ids": list( + entry.id for entry in entries + if entry.id != request.path_params["form_id"] + ) + }, + status_code=400 + ) + + await request.state.db.responses.delete_many( + { + "_id": {"$in": list(actual_ids)} + } + ) + return JSONResponse({"status": "ok"}) -- cgit v1.2.3 From f99dff192bd09fdbbfde448cbaf6fc6179479fa3 Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Wed, 23 Dec 2020 10:48:29 +0200 Subject: Check does form exists in responses bulk DELETE --- backend/routes/forms/responses.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/backend/routes/forms/responses.py b/backend/routes/forms/responses.py index d378187..baab856 100644 --- a/backend/routes/forms/responses.py +++ b/backend/routes/forms/responses.py @@ -50,6 +50,11 @@ class Responses(Route): ) async def delete(self, request: Request) -> JSONResponse: """Bulk deletes form responses by IDs.""" + if not await request.state.db.forms.find_one( + {"_id": request.path_params["form_id"]} + ): + return JSONResponse({"error": "not_found"}, status_code=404) + data = await request.json() if "ids" not in data: @@ -69,7 +74,7 @@ class Responses(Route): if len(ids) != len(actual_ids): return JSONResponse( { - "error": "not_found", + "error": "responses_not_found", "ids": list(ids - actual_ids) }, status_code=404 -- cgit v1.2.3 From d41140f8d935f899c9e27ef6fc230895a3e81fdf Mon Sep 17 00:00:00 2001 From: ks129 <45097959+ks129@users.noreply.github.com> Date: Thu, 24 Dec 2020 09:29:10 +0200 Subject: Let Pydantic validate bulk responses delete data --- backend/routes/forms/responses.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/backend/routes/forms/responses.py b/backend/routes/forms/responses.py index baab856..f3c4cd7 100644 --- a/backend/routes/forms/responses.py +++ b/backend/routes/forms/responses.py @@ -1,6 +1,7 @@ """ Returns all form responses by form ID. """ +from pydantic import BaseModel from spectree import Response from starlette.authentication import requires from starlette.requests import Request @@ -11,6 +12,10 @@ from backend.route import Route from backend.validation import api, ErrorMessage, OkayResponse +class ResponseIdList(BaseModel): + ids: list[str] + + class Responses(Route): """ Returns all form responses by form ID. @@ -41,6 +46,7 @@ class Responses(Route): @requires(["authenticated", "admin"]) @api.validate( + json=ResponseIdList, resp=Response( HTTP_200=OkayResponse, HTTP_404=ErrorMessage, @@ -56,12 +62,10 @@ class Responses(Route): return JSONResponse({"error": "not_found"}, status_code=404) data = await request.json() - - if "ids" not in data: - return JSONResponse({"error": "ids_not_provided"}, status_code=400) + response_ids = ResponseIdList(**data) # Convert IDs to set to remove duplicates - ids = set(data["ids"]) + ids = set(response_ids.ids) cursor = request.state.db.responses.find( {"_id": {"$in": list(ids)}} # Convert here back to list, may throw error. -- cgit v1.2.3