From 285fc37fc66800e26dcc16ae127b87e72c0a8e9f Mon Sep 17 00:00:00 2001 From: Mike Cantelon Date: Wed, 20 Nov 2024 18:42:19 -0800 Subject: [PATCH] Add confirmation before deletion (#289) Prompt user for confirmation before deleting storage service or fetch job. --- AIPscan/Aggregator/templates/confirm.html | 8 ++++++++ AIPscan/Aggregator/tests/test_views.py | 2 +- AIPscan/Aggregator/views.py | 4 +++- AIPscan/decorators.py | 21 +++++++++++++++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) create mode 100644 AIPscan/Aggregator/templates/confirm.html create mode 100644 AIPscan/decorators.py diff --git a/AIPscan/Aggregator/templates/confirm.html b/AIPscan/Aggregator/templates/confirm.html new file mode 100644 index 00000000..fe9d13f6 --- /dev/null +++ b/AIPscan/Aggregator/templates/confirm.html @@ -0,0 +1,8 @@ +{% extends "base.html" %} + +{% block content %} +
+ + Cancel +
+{% endblock %} diff --git a/AIPscan/Aggregator/tests/test_views.py b/AIPscan/Aggregator/tests/test_views.py index b806586c..a15c0026 100644 --- a/AIPscan/Aggregator/tests/test_views.py +++ b/AIPscan/Aggregator/tests/test_views.py @@ -67,5 +67,5 @@ def test_delete_fetch_job(app_with_populated_files, mocker): mocker.patch("AIPscan.Aggregator.tasks.delete_fetch_job.delay") - response = test_client.get("/aggregator/delete_fetch_job/1") + response = test_client.get("/aggregator/delete_fetch_job/1?confirm=1") assert response.status_code == 302 diff --git a/AIPscan/Aggregator/views.py b/AIPscan/Aggregator/views.py index 619b2875..2d762d79 100644 --- a/AIPscan/Aggregator/views.py +++ b/AIPscan/Aggregator/views.py @@ -15,7 +15,7 @@ url_for, ) -from AIPscan import db, typesense_helpers +from AIPscan import db, decorators, typesense_helpers from AIPscan.Aggregator import database_helpers, tasks from AIPscan.Aggregator.forms import StorageServiceForm from AIPscan.Aggregator.task_helpers import ( @@ -171,6 +171,7 @@ def new_storage_service(): @aggregator.route("/delete_storage_service/", methods=["GET"]) +@decorators.confirm_required("Delete storage service", "aggregator.ss_default") def delete_storage_service(storage_service_id): storage_service = StorageService.query.get(storage_service_id) @@ -241,6 +242,7 @@ def new_fetch_job(fetch_job_id): @aggregator.route("/delete_fetch_job/", methods=["GET"]) +@decorators.confirm_required("Delete fetch job", "aggregator.ss_default") def delete_fetch_job(fetch_job_id): fetch_job = FetchJob.query.get(fetch_job_id) diff --git a/AIPscan/decorators.py b/AIPscan/decorators.py new file mode 100644 index 00000000..7a62d6de --- /dev/null +++ b/AIPscan/decorators.py @@ -0,0 +1,21 @@ +from functools import wraps + +from flask import render_template, request + + +def confirm_required(action, cancel_route): + def decorator(f): + @wraps(f) + def decorated_function(*args, **kwargs): + if request.args.get("confirm"): + return f(*args, **kwargs) + + return render_template( + "confirm.html", + action=action, + cancel_route=cancel_route, + ) + + return decorated_function + + return decorator