From 4a16727da16909d735809122163bcb10d6c248a5 Mon Sep 17 00:00:00 2001 From: mpeltriaux Date: Tue, 4 Nov 2025 08:58:47 +0100 Subject: [PATCH] # Refactoring revocation views * refactors views for adding, editing and removing revocations * refactors view for getting the document of a revocation * updates tests --- intervention/forms/modals/revocation.py | 10 +- intervention/tests/unit/test_forms.py | 6 +- intervention/urls.py | 12 +-- intervention/views/revocation.py | 134 ++++++++---------------- 4 files changed, 61 insertions(+), 101 deletions(-) diff --git a/intervention/forms/modals/revocation.py b/intervention/forms/modals/revocation.py index 03a0ebe2..498fa529 100644 --- a/intervention/forms/modals/revocation.py +++ b/intervention/forms/modals/revocation.py @@ -7,9 +7,10 @@ Created on: 18.08.22 """ from django import forms from django.core.exceptions import ObjectDoesNotExist +from django.shortcuts import get_object_or_404 from django.utils.translation import gettext_lazy as _ -from intervention.models import RevocationDocument +from intervention.models import RevocationDocument, Revocation from konova.forms.modals import BaseModalForm, RemoveModalForm from konova.utils import validators from konova.utils.message_templates import REVOCATION_ADDED, REVOCATION_EDITED @@ -75,7 +76,8 @@ class EditRevocationModalForm(NewRevocationModalForm): revocation = None def __init__(self, *args, **kwargs): - self.revocation = kwargs.pop("revocation", None) + revocation_id = kwargs.pop("revocation_id", None) + self.revocation = get_object_or_404(Revocation, id=revocation_id) super().__init__(*args, **kwargs) self.form_title = _("Edit revocation") try: @@ -104,8 +106,8 @@ class RemoveRevocationModalForm(RemoveModalForm): revocation = None def __init__(self, *args, **kwargs): - revocation = kwargs.pop("revocation", None) - self.revocation = revocation + revocation_id = kwargs.pop("revocation_id", None) + self.revocation = get_object_or_404(Revocation, id=revocation_id) super().__init__(*args, **kwargs) def save(self): diff --git a/intervention/tests/unit/test_forms.py b/intervention/tests/unit/test_forms.py index 20a6d749..dbf2bf90 100644 --- a/intervention/tests/unit/test_forms.py +++ b/intervention/tests/unit/test_forms.py @@ -280,7 +280,7 @@ class EditRevocationModalFormTestCase(NewRevocationModalFormTestCase): data, request=self.request, instance=self.intervention, - revocation=self.revoc + revocation_id=self.revoc.id ) self.assertTrue(form.is_valid(), msg=form.errors) obj = form.save() @@ -302,7 +302,7 @@ class RemoveRevocationModalFormTestCase(EditRevocationModalFormTestCase): form = RemoveRevocationModalForm( request=self.request, instance=self.intervention, - revocation=self.revoc, + revocation_id=self.revoc.id, ) self.assertEqual(form.instance, self.intervention) self.assertEqual(form.revocation, self.revoc) @@ -317,7 +317,7 @@ class RemoveRevocationModalFormTestCase(EditRevocationModalFormTestCase): data, request=self.request, instance=self.intervention, - revocation=self.revoc + revocation_id=self.revoc.id ) self.assertTrue(form.is_valid(), msg=form.errors) form.save() diff --git a/intervention/urls.py b/intervention/urls.py index 39024f79..10a6e5f0 100644 --- a/intervention/urls.py +++ b/intervention/urls.py @@ -20,8 +20,8 @@ from intervention.views.log import InterventionLogView from intervention.views.record import InterventionRecordView from intervention.views.report import InterventionReportView from intervention.views.resubmission import InterventionResubmissionView -from intervention.views.revocation import new_revocation_view, edit_revocation_view, remove_revocation_view, \ - get_revocation_view +from intervention.views.revocation import NewRevocationView, GetRevocationDocumentView, EditRevocationView, \ + RemoveRevocationView from intervention.views.share import InterventionShareFormView, InterventionShareByTokenView app_name = "intervention" @@ -55,10 +55,10 @@ urlpatterns = [ path('/deduction//remove', RemoveInterventionDeductionView.as_view(), name='remove-deduction'), # Revocation routes - path('/revocation/new', new_revocation_view, name='new-revocation'), - path('/revocation//edit', edit_revocation_view, name='edit-revocation'), - path('/revocation//remove', remove_revocation_view, name='remove-revocation'), - path('revocation/', get_revocation_view, name='get-doc-revocation'), + path('/revocation/new', NewRevocationView.as_view(), name='new-revocation'), + path('/revocation//edit', EditRevocationView.as_view(), name='edit-revocation'), + path('/revocation//remove', RemoveRevocationView.as_view(), name='remove-revocation'), + path('revocation/', GetRevocationDocumentView.as_view(), name='get-doc-revocation'), # Autocomplete path("atcmplt/interventions", InterventionAutocomplete.as_view(), name="autocomplete"), diff --git a/intervention/views/revocation.py b/intervention/views/revocation.py index db1dd1d2..a32bedf5 100644 --- a/intervention/views/revocation.py +++ b/intervention/views/revocation.py @@ -6,113 +6,71 @@ Created on: 19.08.22 """ from django.contrib import messages -from django.contrib.auth.decorators import login_required +from django.contrib.auth.mixins import LoginRequiredMixin from django.http import HttpRequest from django.shortcuts import get_object_or_404, redirect -from django.urls import reverse from intervention.forms.modals.revocation import NewRevocationModalForm, EditRevocationModalForm, \ RemoveRevocationModalForm -from intervention.models import Intervention, RevocationDocument, Revocation -from konova.decorators import default_group_required, shared_access_required, login_required_modal +from intervention.models import Intervention, RevocationDocument from konova.utils.documents import get_document -from konova.utils.message_templates import REVOCATION_ADDED, DATA_UNSHARED, REVOCATION_EDITED, REVOCATION_REMOVED +from konova.utils.message_templates import DATA_UNSHARED, REVOCATION_EDITED, REVOCATION_REMOVED, REVOCATION_ADDED +from konova.views.base import BaseModalFormView, BaseView -@login_required -@default_group_required -@shared_access_required(Intervention, "id") -def new_revocation_view(request: HttpRequest, id: str): - """ Renders sharing form for an intervention +class BaseRevocationView(LoginRequiredMixin, BaseModalFormView): + _MODEL_CLS = Intervention + _REDIRECT_URL = "intervention:detail" - Args: - request (HttpRequest): The incoming request - id (str): Intervention's id + class Meta: + abstract = True - Returns: + def _user_has_permission(self, user): + return user.is_default_user() - """ - intervention = get_object_or_404(Intervention, id=id) - form = NewRevocationModalForm(request.POST or None, request.FILES or None, instance=intervention, request=request) - return form.process_request( - request, - msg_success=REVOCATION_ADDED, - redirect_url=reverse("intervention:detail", args=(id,)) + "#related_data" - ) + def _get_redirect_url(self, *args, **kwargs): + url = super()._get_redirect_url(*args, **kwargs) + return f"{url}#related_data" -@login_required -@default_group_required -def get_revocation_view(request: HttpRequest, doc_id: str): - """ Returns the revocation document as downloadable file - - Wraps the generic document fetcher function from konova.utils. - - Args: - request (HttpRequest): The incoming request - doc_id (str): The document id - - Returns: - - """ - doc = get_object_or_404(RevocationDocument, id=doc_id) - # File download only possible if related instance is shared with user - if not doc.instance.legal.intervention.users.filter(id=request.user.id): - messages.info( - request, - DATA_UNSHARED - ) - return redirect("intervention:detail", id=doc.instance.id) - return get_document(doc) +class NewRevocationView(BaseRevocationView): + _FORM_CLS = NewRevocationModalForm + _MSG_SUCCESS = REVOCATION_ADDED -@login_required -@default_group_required -@shared_access_required(Intervention, "id") -def edit_revocation_view(request: HttpRequest, id: str, revocation_id: str): - """ Renders a edit view for a revocation - - Args: - request (HttpRequest): The incoming request - id (str): The intervention's id as string - revocation_id (str): The revocation's id as string - - Returns: - - """ - intervention = get_object_or_404(Intervention, id=id) - revocation = get_object_or_404(Revocation, id=revocation_id) - - form = EditRevocationModalForm(request.POST or None, request.FILES or None, instance=intervention, revocation=revocation, request=request) - return form.process_request( - request, - REVOCATION_EDITED, - redirect_url=reverse("intervention:detail", args=(intervention.id,)) + "#related_data" - ) +class EditRevocationView(BaseRevocationView): + _FORM_CLS = EditRevocationModalForm + _MSG_SUCCESS = REVOCATION_EDITED -@login_required_modal -@login_required -@default_group_required -@shared_access_required(Intervention, "id") -def remove_revocation_view(request: HttpRequest, id: str, revocation_id: str): - """ Renders a remove view for a revocation +class RemoveRevocationView(BaseRevocationView): + _FORM_CLS = RemoveRevocationModalForm + _MSG_SUCCESS = REVOCATION_REMOVED - Args: - request (HttpRequest): The incoming request - id (str): The intervention's id as string - revocation_id (str): The revocation's id as string - Returns: +class GetRevocationDocumentView(LoginRequiredMixin, BaseView): + _MODEL_CLS = RevocationDocument + _REDIRECT_URL = "intervention:detail" - """ - intervention = get_object_or_404(Intervention, id=id) - revocation = get_object_or_404(Revocation, id=revocation_id) + def get(self, request: HttpRequest, doc_id: str): + doc = get_object_or_404(RevocationDocument, id=doc_id) + # File download only possible if related instance is shared with user + if not doc.instance.legal.intervention.users.filter(id=request.user.id): + messages.info( + request, + DATA_UNSHARED + ) + return redirect("intervention:detail", id=doc.instance.id) + return get_document(doc) - form = RemoveRevocationModalForm(request.POST or None, instance=intervention, revocation=revocation, request=request) - return form.process_request( - request, - REVOCATION_REMOVED, - redirect_url=reverse("intervention:detail", args=(intervention.id,)) + "#related_data" - ) + def _user_has_permission(self, user): + return user.is_default_user() + def _user_has_shared_access(self, user, **kwargs): + obj = get_object_or_404(self._MODEL_CLS, id=kwargs.get("doc_id")) + assert obj is not None + return obj.instance.intervention.is_shared_with(user) + + def _get_redirect_url(self, *args, **kwargs): + url = super()._get_redirect_url(*args, **kwargs) + return f"{url}#related_data"