diff --git a/src/hope_dedup_engine/apps/api/admin/deduplicationset.py b/src/hope_dedup_engine/apps/api/admin/deduplicationset.py index 494d3a2c..1ea3377d 100644 --- a/src/hope_dedup_engine/apps/api/admin/deduplicationset.py +++ b/src/hope_dedup_engine/apps/api/admin/deduplicationset.py @@ -1,3 +1,5 @@ +from uuid import UUID + from django.contrib.admin import ModelAdmin, register from django.http import HttpRequest, HttpResponseRedirect from django.urls import reverse @@ -10,6 +12,7 @@ from hope_dedup_engine.apps.api.models import DeduplicationSet from hope_dedup_engine.apps.api.utils.process import start_processing +from hope_dedup_engine.utils.security import can_reprocess @register(DeduplicationSet) @@ -45,11 +48,12 @@ class DeduplicationSetAdmin(AdminFiltersMixin, ExtraButtonsMixin, ModelAdmin): def has_add_permission(self, request): return False - @button(label="Process") - def process(self, request: HttpRequest, pk: str) -> HttpResponseRedirect: - dd = DeduplicationSet.objects.get(pk=pk) - start_processing(dd) + @button(permission=can_reprocess) + def process(self, request: HttpRequest, pk: UUID) -> HttpResponseRedirect: + obj = self.get_object(request, pk) + start_processing(obj) self.message_user( - request, f"Processing for deduplication set '{dd}' has been started." + request, + f"Processing for deduplication set '{obj}' has been started.", ) return HttpResponseRedirect(reverse("admin:api_deduplicationset_changelist")) diff --git a/src/hope_dedup_engine/config/__init__.py b/src/hope_dedup_engine/config/__init__.py index 5f915371..7cf34eef 100644 --- a/src/hope_dedup_engine/config/__init__.py +++ b/src/hope_dedup_engine/config/__init__.py @@ -1,5 +1,6 @@ from enum import Enum from typing import TYPE_CHECKING, Any, Dict, Tuple, TypeAlias, Union +from uuid import uuid4 from smart_env import SmartEnv @@ -173,8 +174,14 @@ class Group(Enum): setting("media-root"), ), "MEDIA_URL": (str, "/media/", "/media", False, setting("media-root")), # nosec - "ROOT_TOKEN_HEADER": (str, "x-root-token", "x-root-token"), - "ROOT_TOKEN": (str, ""), + "ROOT_TOKEN": (str, uuid4().hex, uuid4().hex, False, "Root access token"), + "ROOT_TOKEN_HEADER": ( + str, + "x-root-token", + "x-root-token", + False, + "Root token header", + ), "SECRET_KEY": ( str, "", diff --git a/src/hope_dedup_engine/config/fragments/root.py b/src/hope_dedup_engine/config/fragments/root.py index 1be23052..91894b60 100644 --- a/src/hope_dedup_engine/config/fragments/root.py +++ b/src/hope_dedup_engine/config/fragments/root.py @@ -1,4 +1,4 @@ from hope_dedup_engine.config import env ROOT_TOKEN = env("ROOT_TOKEN") -ROOT_TOKEN_HEADER = env("ROOT_TOKEN_HEADER", default="x-root-token") +ROOT_TOKEN_HEADER = env("ROOT_TOKEN_HEADER") diff --git a/src/hope_dedup_engine/utils/security.py b/src/hope_dedup_engine/utils/security.py index 9ee29f33..6f404de1 100644 --- a/src/hope_dedup_engine/utils/security.py +++ b/src/hope_dedup_engine/utils/security.py @@ -2,9 +2,23 @@ from django.conf import settings +from hope_dedup_engine.apps.api.models.deduplication import DeduplicationSet + def is_root(request: Any, *args: Any, **kwargs: Any) -> bool: return ( request.user.is_superuser and request.headers.get(settings.ROOT_TOKEN_HEADER) == settings.ROOT_TOKEN != "" ) + + +def can_reprocess(request: Any, *args: Any, **kwargs: Any) -> bool: + obj = args[0] if args and isinstance(args[0], DeduplicationSet) else None + if obj: + return any( + ( + request.user.is_superuser and obj.state == DeduplicationSet.State.ERROR, + is_root(request), + ) + ) + return False diff --git a/tests/admin/test_admin_smoke.py b/tests/admin/test_admin_smoke.py index 5782b0d7..1c6fc2e8 100644 --- a/tests/admin/test_admin_smoke.py +++ b/tests/admin/test_admin_smoke.py @@ -183,7 +183,7 @@ def test_admin_delete(app, modeladmin, record, monkeypatch): pytest.skip("No 'delete' permission") -@pytest.mark.skip_buttons("security.UserAdmin:link_user_data") +@pytest.mark.skip_buttons("api.DeduplicationSetAdmin:process") def test_admin_buttons(app, modeladmin, button_handler, record, monkeypatch): from admin_extra_buttons.handlers import LinkHandler