Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions mesads/app/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .ads_manager_administrator import * # noqa
from .ads_manager_request import * # noqa
from .ads_update_file import * # noqa
from .demande_gestion_prefecture import * # noqa
from .inscription_liste_attente import * # noqa
from .notifications import * # noqa

Expand Down
100 changes: 100 additions & 0 deletions mesads/app/admin/demande_gestion_prefecture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
from django.conf import settings
from django.contrib import admin, messages
from django.contrib.staticfiles import finders
from django.core.mail import EmailMultiAlternatives
from django.db.models import F, Q
from django.db.models.functions import Collate
from django.http import HttpResponseRedirect
from django.template.loader import render_to_string
from django.urls import reverse

from mesads.app.models import DemandeGestionPrefecture


@admin.register(DemandeGestionPrefecture)
class DemandeGestionPrefectureAdmin(admin.ModelAdmin):
list_display = ("user", "administrator", "created_at")

search_fields = ("user__email",)

change_form_template = "admin/app/demande_gestion_prefecture/change_form.html"

def response_change(self, request, obj):
# Gestion du bouton "Valider"
if "_valider" in request.POST:
self.validation_demande(obj, request)
self.message_user(request, "Demande validée.", level=messages.SUCCESS)

changelist_url = reverse(
f"admin:{obj._meta.app_label}_{obj._meta.model_name}_changelist"
)
obj.delete()
return HttpResponseRedirect(changelist_url)

return super().response_change(request, obj)

def validation_demande(self, obj, request):
obj.administrator.users.add(obj.user)
email_subject = render_to_string(
"demande_gestion_prefecture/email_demande_gestion_prefecture_result_subject.txt",
{
"demande": obj,
},
request=request,
).strip()
email_content = render_to_string(
"demande_gestion_prefecture/email_demande_gestion_prefecture_result_content.txt",
{
"request": request,
"demande": obj,
"email_contact": settings.MESADS_CONTACT_EMAIL,
},
request=request,
)
email_content_html = render_to_string(
"demande_gestion_prefecture/email_demande_gestion_prefecture_result_content.mjml",
{
"request": request,
"demande": obj,
"email_contact": settings.MESADS_CONTACT_EMAIL,
},
request=request,
)

email = EmailMultiAlternatives(
subject=email_subject,
body=email_content,
from_email=settings.MESADS_CONTACT_EMAIL,
to=[obj.user.email],
)
email.attach_alternative(email_content_html, "text/html")

file_path = finders.find("Guide d'utilisation.pdf")

with open(file_path, "rb") as f:
email.attach(
"Guide d'utilisation.pdf",
f.read(),
"application/pdf",
)

email.send(fail_silently=True)

def get_search_results(self, request, queryset, search_term):
"""The field Users.email uses a non-deterministic collation, which makes
it impossible to perform a LIKE query on it.

By overriding this method, we can specify the collation to use for the search.
"""
use_distinct = True
queryset = queryset.annotate(collated_email=Collate(F("user__email"), "C"))
queryset = queryset.filter(
Q(
collated_email__icontains=search_term,
)
| Q(administrator__prefecture__libelle=search_term)
)
return (
queryset,
use_distinct,
)
7 changes: 7 additions & 0 deletions mesads/app/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -451,3 +451,10 @@ class ListesAttentePubliquesSearchForm(forms.Form):

def is_filled(self):
return self.cleaned_data.get("departement") or self.cleaned_data.get("commune")


class DemandeGestionPrefectureForm(forms.Form):
departement = forms.ModelChoiceField(
queryset=Prefecture.objects.exclude(numero="999"),
label="Département",
)
30 changes: 30 additions & 0 deletions mesads/app/migrations/0110_demandegestionprefecture.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Generated by Django 5.2.10 on 2026-02-18 15:09

import django.db.models.deletion
from django.conf import settings
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('app', '0109_merge_20260112_1826'),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.CreateModel(
name='DemandeGestionPrefecture',
fields=[
('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('created_at', models.DateTimeField(auto_now_add=True)),
('administrator', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='demandes_gestion_prefecture', to='app.adsmanageradministrator')),
('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='demandes_gestion_prefecture', to=settings.AUTH_USER_MODEL)),
],
options={
'verbose_name': 'Demande pour devenir gestionnaire de préfecture',
'verbose_name_plural': 'Demandes pour devenir gestionnaire de préfecture',
'unique_together': {('user', 'administrator')},
},
),
]
30 changes: 30 additions & 0 deletions mesads/app/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -379,6 +379,36 @@ def ordered_adsmanager_set(self):
)


@reversion.register
class DemandeGestionPrefecture(models.Model):
"""Requête utilisateur pour devenir gestionnaire d'une préfecture.
Elle doit être accepté par un membre de l'équipe de MesADS.
"""

user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
blank=False,
related_name="demandes_gestion_prefecture",
)
administrator = models.ForeignKey(
ADSManagerAdministrator,
on_delete=models.CASCADE,
blank=False,
related_name="demandes_gestion_prefecture",
)

created_at = models.DateTimeField(auto_now_add=True, null=False)

class Meta:
unique_together = (("user", "administrator"),)
verbose_name = "Demande pour devenir gestionnaire de préfecture"
verbose_name_plural = "Demandes pour devenir gestionnaire de préfecture"

def __str__(self):
return f"Requete de {self.user} pour être gestionnaire de {self.administrator}"


def validate_siret(value):
if not value:
return
Expand Down
61 changes: 60 additions & 1 deletion mesads/app/tests/views/test_ads_manager_admin.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
from datetime import date, datetime
from http import HTTPStatus

from django.conf import settings
from django.core import mail
from django.urls import reverse

from mesads.app.models import ADS, ADSManager, ADSManagerRequest
from mesads.app.models import (
ADS,
ADSManager,
ADSManagerRequest,
DemandeGestionPrefecture,
)
from mesads.fradm.models import Prefecture
from mesads.unittest import ClientTestCase
from mesads.vehicules_relais.models import Proprietaire, Vehicule
Expand Down Expand Up @@ -403,3 +409,56 @@ def test_get_context(self):
self.ads_manager_administrator_35,
)
self.assertEqual(response.context["vehicule"], self.vehicule)


class TestDemandeGestionPrefecture(ClientTestCase):
def setUp(self):
super().setUp()
self.client, self.user = self.create_client()
self.administrator = self.ads_manager_administrator_35
self.prefecture = self.ads_manager_administrator_35.prefecture

def test_get_page_demande_gestion_prefecture(self):
response = self.client.get(
reverse("app.ads-manager-admin.demande_gestion_prefecture")
)
self.assertEqual(response.status_code, HTTPStatus.OK)
self.assertTemplateUsed(
response, "pages/ads_register/demande_gestion_prefecture.html"
)

def test_post_page_demande_gestion_prefecture(self):
assert (
DemandeGestionPrefecture.objects.filter(
user=self.user, administrator=self.administrator
).count()
== 0
)
response = self.client.post(
reverse("app.ads-manager-admin.demande_gestion_prefecture"),
{"departement": self.prefecture.id},
)
self.assertRedirects(
response,
expected_url=reverse(
"app.homepage",
),
status_code=HTTPStatus.FOUND,
target_status_code=HTTPStatus.OK,
fetch_redirect_response=True,
)
assert (
DemandeGestionPrefecture.objects.filter(
user=self.user, administrator=self.administrator
).count()
== 1
)

self.assertEqual(len(mail.outbox), 1)

email = mail.outbox[0]

self.assertEqual(
email.subject, f"Mes ADS : Demande d'accès préfecture de {self.user.email}"
)
self.assertEqual(email.to, [settings.MESADS_CONTACT_EMAIL])
5 changes: 5 additions & 0 deletions mesads/app/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@
name="app.exports.prefecture",
# A GARDER
),
path(
"registre_ads/demande_gestion_prefecture/",
login_required(views.DemandeGestionPrefectureView.as_view()),
name="app.ads-manager-admin.demande_gestion_prefecture",
),
]

url_gestionnaire = [
Expand Down
1 change: 1 addition & 0 deletions mesads/app/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
ADSManagerAdminRequestsView,
ADSManagerAdminUpdatesView,
ADSManagerExportView,
DemandeGestionPrefectureView,
PrefectureExportView,
RepertoireVehiculeRelaisView,
VehiculeView,
Expand Down
64 changes: 62 additions & 2 deletions mesads/app/views/ads_manager_admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
from django.template.loader import render_to_string
from django.urls import reverse
from django.utils.text import slugify
from django.views.generic import ListView, TemplateView, View
from django.views.generic import FormView, ListView, TemplateView, View
from reversion.views import RevisionMixin

from mesads.app.forms import SearchVehiculeForm
from mesads.app.forms import DemandeGestionPrefectureForm, SearchVehiculeForm
from mesads.fradm.models import EPCI, Aeroport, Commune, Prefecture
from mesads.utils_psql import SplitPart
from mesads.vehicules_relais.models import Vehicule
Expand All @@ -39,6 +39,7 @@
ADSManagerAdministrator,
ADSManagerRequest,
ADSUpdateLog,
DemandeGestionPrefecture,
)
from ..services import (
get_ads_data_for_excel_export,
Expand Down Expand Up @@ -543,3 +544,62 @@ def get_context_data(self, **kwargs):
"ads_manager_administrator"
)
return context


class DemandeGestionPrefectureView(FormView):
form_class = DemandeGestionPrefectureForm
template_name = "pages/ads_register/demande_gestion_prefecture.html"

def get_success_url(self):
return reverse("app.homepage")

def form_valid(self, form):
administrator = ADSManagerAdministrator.objects.filter(
prefecture=form.data.get("departement")
).first()

if administrator:
demande, _ = DemandeGestionPrefecture.objects.get_or_create(
user=self.request.user, administrator=administrator
)
messages.success(
self.request,
"Votre demande a bien été transmise à notre équipe",
)
self.envoi_email_notification(demande)
# send maiil

return super().form_valid(form)

def envoi_email_notification(self, demande):
email_subject = render_to_string(
"demande_gestion_prefecture/email_demande_gestion_prefecture_subject.txt",
{
"demande": demande,
},
request=self.request,
).strip()
email_content = render_to_string(
"demande_gestion_prefecture/email_demande_gestion_prefecture_content.txt",
{
"request": self.request,
"demande": demande,
},
request=self.request,
)
email_content_html = render_to_string(
"demande_gestion_prefecture/email_demande_gestion_prefecture_content.mjml",
{
"request": self.request,
"demande": demande,
},
request=self.request,
)
send_mail(
email_subject,
email_content,
settings.MESADS_CONTACT_EMAIL,
[settings.MESADS_CONTACT_EMAIL],
fail_silently=True,
html_message=email_content_html,
)
4 changes: 4 additions & 0 deletions mesads/html_metadata.yml
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ urls:
title: "Gestion et contrôle des accès des instructeurs ADS"
description: "Gérez les demandes d'accès au registre ADS en acceptant ou refusant les instructeurs de votre département."

app.ads-manager-admin.demande_gestion_prefecture:
title: "MesADS - Demande de gestion préfecture"
description: "MesADS - Demandez l'accès à l'espace préfecture de votre département."

app.ads-manager-admin.gestionnaires:
title: "MesADS - Administrations de votre préfecture"
description: "MesADS - Administrations de votre préfecture"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% extends "admin/change_form.html" %}
{% load i18n admin_urls %}

{% block submit_buttons_bottom %}
{% if change %}
<div class="submit-row">
<input type="submit" value="Valider la demande" class="default" name="_valider">

{# Garder la suppression possible #}
{% if has_delete_permission %}
<a href="{% url 'admin:app_demandegestionprefecture_delete' original.pk|admin_urlquote %}"
class="deletelink">
{% translate "Delete" %}
</a>
{% endif %}
</div>
{% else %}
{{ block.super }}
{% endif %}
{% endblock %}
Loading