Skip to content

Commit

Permalink
Masque le bloc de suivi si la fiche détection est en visibité brouillon
Browse files Browse the repository at this point in the history
Côté front:
- modification du template detail de la fiche détection pour masquer le bloc de suivi et les modales utilisées dans celui-ci.
- ajout de tests bloc de suivi masqué si brouillon et affiché si local ou national

Côté serveur:
- application du mixin PreventActionIfVisibiliteBrouillonMixin dans les vues du bloc de suivi
- ajout de tests pour vérifier que les requêtes HTTP sur les différentes routes du bloc de suivi soient refusées si la fiche est en brouillon

Autres:
- modification du nom et de l'accessibilité de la méthode _add_message_url dans le mixin WithMessageUrlsMixin car besoin dans les tests sv/tests/test_fiches_message.py
- modification de sv/tests/test_fichedetection_performances.py pour que les test s'effectuent sur une fiche détection en visibilité local car BASE_NUM_QUERIES prend en compte l'affichage du bloc de suivi (14 requêtes contre 10 sans).
- modification du test test_structure_list pour que la vérification se fasse directement dans le formulaire HTML et non dans le contexte du formulaire.
  • Loading branch information
alanzirek committed Nov 28, 2024
1 parent cd80c28 commit cdd5d6e
Show file tree
Hide file tree
Showing 10 changed files with 466 additions and 84 deletions.
20 changes: 10 additions & 10 deletions core/mixins.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,35 +129,35 @@ class Meta:


class WithMessageUrlsMixin:
def _add_message_url(self, message_type):
def get_add_message_url(self, message_type):
content_type = ContentType.objects.get_for_model(self)
return reverse(
"message-add", kwargs={"message_type": message_type, "obj_type_pk": content_type.pk, "obj_pk": self.pk}
)

@property
def add_message_url(self):
return self._add_message_url(Message.MESSAGE)
return self.get_add_message_url(Message.MESSAGE)

@property
def add_note_url(self):
return self._add_message_url(Message.NOTE)
return self.get_add_message_url(Message.NOTE)

@property
def add_point_de_suivi_url(self):
return self._add_message_url(Message.POINT_DE_SITUATION)
return self.get_add_message_url(Message.POINT_DE_SITUATION)

@property
def add_demande_intervention_url(self):
return self._add_message_url(Message.DEMANDE_INTERVENTION)
return self.get_add_message_url(Message.DEMANDE_INTERVENTION)

@property
def add_compte_rendu_url(self):
return self._add_message_url(Message.COMPTE_RENDU)
return self.get_add_message_url(Message.COMPTE_RENDU)

@property
def add_fin_suivi_url(self):
return self._add_message_url(Message.FIN_SUIVI)
return self.get_add_message_url(Message.FIN_SUIVI)


class AllowVisibiliteMixin(models.Model):
Expand Down Expand Up @@ -236,11 +236,11 @@ class PreventActionIfVisibiliteBrouillonMixin:
Mixin pour empêcher des actions sur des objets ayant la visibilité 'brouillon'.
"""

def get_object(self):
raise NotImplementedError("Vous devez implémenter la méthode `get_object` pour ce mixin.")
def get_fiche_object(self):
raise NotImplementedError("Vous devez implémenter la méthode `get_fiche_object` pour ce mixin.")

def dispatch(self, request, *args, **kwargs):
obj = self.get_object()
obj = self.get_fiche_object()
if obj.visibilite == Visibilite.BROUILLON:
messages.error(request, "Action impossible car la fiche est en brouillon")
return safe_redirect(request.POST.get("next") or obj.get_absolute_url() or "/")
Expand Down
90 changes: 70 additions & 20 deletions core/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,14 @@
from .redirect import safe_redirect


class DocumentUploadView(FormView):
class DocumentUploadView(PreventActionIfVisibiliteBrouillonMixin, FormView):
form_class = DocumentUploadForm

def get_fiche_object(self):
content_type = ContentType.objects.get(id=self.request.POST.get("content_type"))
ModelClass = content_type.model_class()
return get_object_or_404(ModelClass, pk=self.request.POST.get("object_id"))

def post(self, request, *args, **kwargs):
form = DocumentUploadForm(request.POST, request.FILES)
if form.is_valid():
Expand All @@ -46,21 +51,28 @@ def post(self, request, *args, **kwargs):
return safe_redirect(self.request.POST.get("next") + "#tabpanel-documents-panel")


class DocumentDeleteView(View):
class DocumentDeleteView(PreventActionIfVisibiliteBrouillonMixin, View):
def get_fiche_object(self):
self.document = get_object_or_404(Document, pk=self.kwargs.get("pk"))
return self.document.content_object

def post(self, request, *args, **kwargs):
document = get_object_or_404(Document, pk=kwargs.get("pk"))
document.is_deleted = True
document.deleted_by = self.request.user.agent
document.save()
self.document.is_deleted = True
self.document.deleted_by = self.request.user.agent
self.document.save()
messages.success(request, "Le document a été marqué comme supprimé.", extra_tags="core documents")
return safe_redirect(request.POST.get("next") + "#tabpanel-documents-panel")


class DocumentUpdateView(UpdateView):
class DocumentUpdateView(PreventActionIfVisibiliteBrouillonMixin, UpdateView):
model = Document
form_class = DocumentEditForm
http_method_names = ["post"]

def get_fiche_object(self):
self.document = get_object_or_404(Document, pk=self.kwargs.get("pk"))
return self.document.content_object

def get_success_url(self):
return self.request.POST.get("next") + "#tabpanel-documents-panel"

Expand All @@ -70,10 +82,17 @@ def form_valid(self, form):
return response


class ContactAddFormView(FormView):
class ContactAddFormView(PreventActionIfVisibiliteBrouillonMixin, FormView):
template_name = "core/_contact_add_form.html"
form_class = ContactAddForm

def get_fiche_object(self):
content_type_id = self.request.GET.get("content_type_id") or self.request.POST.get("content_type_id")
fiche_id = self.request.GET.get("fiche_id") or self.request.POST.get("fiche_id")
content_type = ContentType.objects.get(pk=content_type_id)
ModelClass = content_type.model_class()
return get_object_or_404(ModelClass, pk=fiche_id)

def get_initial(self):
initial = super().get_initial()
initial["fiche_id"] = self.request.GET.get("fiche_id")
Expand All @@ -94,10 +113,17 @@ def form_valid(self, form):
return render(self.request, self.template_name, {"form": form, "selection_form": selection_form})


class ContactSelectionView(FormView):
class ContactSelectionView(PreventActionIfVisibiliteBrouillonMixin, FormView):
template_name = "core/_contact_add_form.html"
form_class = ContactSelectionForm

def get_fiche_object(self):
content_type_id = self.request.POST.get("content_type_id")
fiche_id = self.request.POST.get("fiche_id")
content_type = ContentType.objects.get(pk=content_type_id)
ModelClass = content_type.model_class()
return get_object_or_404(ModelClass, pk=fiche_id)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["next"] = self.request.GET.get("next")
Expand Down Expand Up @@ -147,19 +173,21 @@ def form_invalid(self, form):
)


class ContactDeleteView(View):
def post(self, request, *args, **kwargs):
content_type = ContentType.objects.get(id=request.POST.get("content_type_pk"))
class ContactDeleteView(PreventActionIfVisibiliteBrouillonMixin, View):
def get_fiche_object(self):
content_type = ContentType.objects.get(id=self.request.POST.get("content_type_pk"))
ModelClass = content_type.model_class()
fiche = get_object_or_404(ModelClass, pk=request.POST.get("fiche_pk"))
contact = Contact.objects.get(pk=self.request.POST.get("pk"))
self.fiche = get_object_or_404(ModelClass, pk=self.request.POST.get("fiche_pk"))
return self.fiche

fiche.contacts.remove(contact)
def post(self, request, *args, **kwargs):
contact = Contact.objects.get(pk=self.request.POST.get("pk"))
self.fiche.contacts.remove(contact)
messages.success(request, "Le contact a bien été supprimé de la fiche.", extra_tags="core contacts")
return safe_redirect(request.POST.get("next") + "#tabpanel-contacts-panel")


class MessageCreateView(CreateView):
class MessageCreateView(PreventActionIfVisibiliteBrouillonMixin, CreateView):
model = Message
form_class = MessageForm

Expand All @@ -169,6 +197,9 @@ def dispatch(self, request, *args, **kwargs):
self.obj = get_object_or_404(self.obj_class, pk=self.kwargs.get("obj_pk"))
return super().dispatch(request, *args, **kwargs)

def get_fiche_object(self):
return self.obj

def get_form_kwargs(self):
kwargs = super().get_form_kwargs()
kwargs.update(
Expand Down Expand Up @@ -243,14 +274,26 @@ def form_valid(self, form):
return response


class MessageDetailsView(DetailView):
class MessageDetailsView(PreventActionIfVisibiliteBrouillonMixin, DetailView):
model = Message

def get_fiche_object(self):
message = get_object_or_404(Message, pk=self.kwargs.get("pk"))
fiche = message.content_object
return fiche


class StructureAddFormView(FormView):
class StructureAddFormView(PreventActionIfVisibiliteBrouillonMixin, FormView):
template_name = "core/_structure_add_form.html"
form_class = StructureAddForm

def get_fiche_object(self):
content_type_id = self.request.GET.get("content_type_id") or self.request.POST.get("content_type_id")
fiche_id = self.request.GET.get("fiche_id") or self.request.POST.get("fiche_id")
content_type = ContentType.objects.get(pk=content_type_id)
ModelClass = content_type.model_class()
return get_object_or_404(ModelClass, pk=fiche_id)

def get_initial(self):
initial = super().get_initial()
initial["fiche_id"] = self.request.GET.get("fiche_id")
Expand All @@ -270,10 +313,17 @@ def form_valid(self, form):
return render(self.request, self.template_name, {"form": form, "selection_form": selection_form})


class StructureSelectionView(FormView):
class StructureSelectionView(PreventActionIfVisibiliteBrouillonMixin, FormView):
template_name = "core/_structure_add_form.html"
form_class = StructureSelectionForm

def get_fiche_object(self):
content_type_id = self.request.POST.get("content_type_id")
fiche_id = self.request.POST.get("fiche_id")
content_type = ContentType.objects.get(pk=content_type_id)
ModelClass = content_type.model_class()
return get_object_or_404(ModelClass, pk=fiche_id)

def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["next"] = self.request.GET.get("next")
Expand Down Expand Up @@ -343,7 +393,7 @@ def post(self, request):


class ACNotificationView(PreventActionIfVisibiliteBrouillonMixin, View):
def get_object(self):
def get_fiche_object(self):
content_type_id = self.request.POST.get("content_type_id")
content_id = self.request.POST.get("content_id")
content_type = ContentType.objects.get(pk=content_type_id).model_class()
Expand Down
5 changes: 3 additions & 2 deletions sv/templates/sv/fichedetection_detail.html
Original file line number Diff line number Diff line change
Expand Up @@ -229,8 +229,9 @@ <h2>Mesures de gestion</h2>
</div>
{% include "sv/_fichedetection_synthese.html" %}


{% include "core/_fiche_bloc_commun.html" with fiche=fichedetection %}
{% if not fichedetection.is_draft %}
{% include "core/_fiche_bloc_commun.html" with fiche=fichedetection %}
{% endif %}
</main>

{% endblock %}
33 changes: 33 additions & 0 deletions sv/tests/test_fichedetection_detail.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
from django.urls import reverse

import pytest

from core.models import Visibilite
from sv.models import Lieu, Prelevement, FicheZoneDelimitee, ZoneInfestee, FicheDetection
from model_bakery import baker
Expand Down Expand Up @@ -205,3 +207,34 @@ def test_fiche_detection_brouillon_cannot_add_zone(live_server, page, mocked_aut
# simule le fait d'effectuer la requete GET directement pour ajouter une zone
page.goto(f"{live_server.url}{reverse('rattachement-fiche-zone-delimitee', args=[fiche_detection.id])}")
expect(page.get_by_text("Action impossible car la fiche est en brouillon")).to_be_visible()


def test_fiche_detection_brouillon_does_not_have_bloc_suivi_display(live_server, page, mocked_authentification_user):
fiche_detection = baker.make(
FicheDetection, visibilite=Visibilite.BROUILLON, createur=mocked_authentification_user.agent.structure
)
page.goto(f"{live_server.url}{fiche_detection.get_absolute_url()}")
expect(page.get_by_label("Fil de suivi")).not_to_be_visible()
expect(page.get_by_label("Contacts")).not_to_be_visible()
expect(page.get_by_label("Documents")).not_to_be_visible()


@pytest.mark.parametrize(
"visibilite",
[
Visibilite.LOCAL,
Visibilite.NATIONAL,
],
)
def test_fiche_detection_local_or_national_have_bloc_suivi_display(
live_server, page, visibilite: Visibilite, mocked_authentification_user
):
fiche_detection = baker.make(
FicheDetection, visibilite=visibilite, createur=mocked_authentification_user.agent.structure
)
page.goto(f"{live_server.url}{fiche_detection.get_absolute_url()}")
expect(page.get_by_label("Fil de suivi")).to_be_visible()
expect(page.get_by_label("Contacts")).to_have_count(1)
expect(page.get_by_label("Contacts")).to_be_hidden()
expect(page.get_by_label("Documents")).to_have_count(1)
expect(page.get_by_label("Documents")).to_be_hidden()
Loading

0 comments on commit cdd5d6e

Please sign in to comment.