diff --git a/config/settings.py b/config/settings.py
index 91c3751a5..20a077355 100644
--- a/config/settings.py
+++ b/config/settings.py
@@ -22,7 +22,7 @@
from sentry_sdk.integrations.django import DjangoIntegration
from sentry_sdk.integrations.redis import RedisIntegration
-OFFICIAL_VERSION = "7.3"
+OFFICIAL_VERSION = "7.4"
root = environ.Path(__file__) - 2 # get root of the project
diff --git a/home/templates/home/download.html b/home/templates/home/download.html
new file mode 100644
index 000000000..054a3e072
--- /dev/null
+++ b/home/templates/home/download.html
@@ -0,0 +1,64 @@
+{% extends "index.html" %}
+
+{% load static %}
+{% load sri %}
+
+{% block pagetitle %}Téléchargements{% endblock pagetitle %}
+
+{% block headers %}
+{% sri_static "home/css/home.css" %}
+{% endblock headers %}
+
+{% block body_class %}home{% endblock body_class %}
+
+
+{% block breadcrumbs %}
+{% endblock breadcrumbs %}
+
+{% block content %}
+
+ Mon Diagnostic Artificialisation met à disposition des DDT les trames de rapport triennal local par paquets de leurs communes au RNU
+ Trames de rapport triennal local des communes au RNU
+
+
+
+
+
+
+
+ {% for package in rnu_packages %}
+ Département
+ Nombre de communes au RNU
+ Date de création
+ Lien
+
+
+ {% endfor %}
+
+ {{ package.departement_official_id }} - {{ package.departement.name }}
+ {{ package.communes|length }}
+ {{ package.created_at }}
+ Lien de téléchargement
+
Nouveau
- Exportez une trame pour votre rapport triennal local de suivi de l'artificialisation des sols conformément à l'article L. 2231-1 du code général des collectivités territoriales
+ Exportez une trame de votre rapport triennal local de suivi de l'artificialisation des sols conformément à l'article L. 2231-1 du code général des collectivités territoriales.
+ Pour les DDT, ces trames sont disponibles en téléchargement par paquets pour les communes au RNU.
Notre équipe travaille en partenariat avec la DGALN à la production automatique d'une trame pré-remplie du rapport triennal local de suivi de l’artificialisation des sols de votre territoire.
Nouveau
+Notre équipe travaille en partenariat avec la DGALN à la production automatique d'une trame pré-remplie du rapport triennal local de suivi de l’artificialisation des sols de votre territoire.
++ Pour les DDT, ces trames sont disponibles en téléchargement par paquets pour les communes au RNU. +
++ Ce paquet de trames de rapport local s'adresse aux DDT. + Il contient un rapport local par commune au RNU du département {{ object.departement.name }} ({{ object.departement.source_id }}). +
++ Une version web de ces diagnostics est disponible. + Un lien est disponible dans le bas de page de chaque rapport. +
+ +Fichier | +Chemin | +
---|---|
Ce document | +NOTICE_{{ object.departement_official_id }}.pdf | +
Carte des communes au RNU du département | +COMM_DU_{{ object.departement_official_id }}.pdf | +
Rapport de + {{ commune.name }} + | +{{ commune.departement.source_id }}_COMM_{{ commune.insee }}.docx | +
+ Crée par Mon Diagnostic Artificialisation +
+ + + \ No newline at end of file diff --git a/public_data/management/commands/create_rnu_diagnostics.py b/public_data/management/commands/create_rnu_diagnostics.py new file mode 100644 index 000000000..78eafbaff --- /dev/null +++ b/public_data/management/commands/create_rnu_diagnostics.py @@ -0,0 +1,109 @@ +import logging + +from django.core.management.base import BaseCommand +from django.utils import timezone + +from project.models import Emprise, Project, Request +from project.models.create import trigger_async_tasks_rnu_pakage_one_off +from public_data.models import Commune, Land +from public_data.models.sudocuh import DocumentUrbanismeChoices, Sudocuh +from users.models import User +from utils.db import fix_poly + +logger = logging.getLogger("management.commands") + + +class Command(BaseCommand): + help = "create_rnu_diagnostics" + + def add_arguments(self, parser): + parser.add_argument("--departement", type=str) + + def handle(self, *args, **options): + mondiagartif_user, _ = User.objects.get_or_create( + email="rnu.package@mondiagartif.beta.gouv.fr", + first_name="Alexis", + last_name="Athlani", + organism=User.ORGANISMS.DDT, + function="Développeur", + defaults={"email_checked": timezone.now()}, + ) + + projects = [] + + communes = Commune.objects.filter( + insee__in=[Sudocuh.objects.filter(du_opposable=DocumentUrbanismeChoices.RNU).values("code_insee")], + ) + + if options["departement"]: + communes = communes.filter(departement__source_id=options["departement"]) + + logger.info(f"Found {len(communes)} RNU communes") + + projects_to_delete = Project.objects.filter( + user=mondiagartif_user, + land_id__in=[str(commune.id) for commune in communes], + ) + + request_to_delete = Request.objects.filter(project__in=projects_to_delete) + + _, detail_request_deleted = request_to_delete.delete() + _, detail_project_deleted = projects_to_delete.delete() + + logger.info(f"Deleted : {detail_request_deleted}") + logger.info(f"Deleted : {detail_project_deleted}") + + for commune in communes: + land = Land(public_key=f"COMM_{commune.id}") + project = Project.objects.create( + name=f"Diagnostic de {land.name}", + is_public=True, + analyse_start_date="2011", + analyse_end_date="2022", + level="COMM", + land_id=str(commune.id), + land_type=land.land_type, + territory_name=land.name, + user=mondiagartif_user, + import_status=Project.Status.SUCCESS, + import_date=timezone.now(), + import_error=None, + async_add_city_done=True, + first_year_ocsge=commune.first_millesime, + last_year_ocsge=commune.last_millesime, + available_millesimes=[commune.first_millesime, commune.last_millesime], + async_find_first_and_last_ocsge_done=True, + ocsge_coverage_status=Project.OcsgeCoverageStatus.COMPLETE_UNIFORM + if commune.ocsge_available + else Project.OcsgeCoverageStatus.NO_DATA, + async_ocsge_coverage_status_done=True, + async_set_combined_emprise_done=True, + async_theme_map_gpu_done=True, + async_theme_map_fill_gpu_done=True, + async_add_comparison_lands_done=True, + ) + + project.cities.add(commune) + + Emprise.objects.create( + mpoly=fix_poly(commune.mpoly), + srid_source=commune.srid_source, + project=project, + ) + + similar_lands_public_keys = [ + comparison_land.public_key for comparison_land in project.get_comparison_lands() + ] + + project.refresh_from_db() + + project.add_look_a_like(public_key=similar_lands_public_keys, many=True) + + projects.append(project) + + logger.info(f"Created {len(projects)} projects") + + for project in projects: + trigger_async_tasks_rnu_pakage_one_off(project) + + logger.info("All projects have been created and async tasks have been triggered") diff --git a/public_data/management/commands/create_rnu_packages.py b/public_data/management/commands/create_rnu_packages.py new file mode 100644 index 000000000..e409d0924 --- /dev/null +++ b/public_data/management/commands/create_rnu_packages.py @@ -0,0 +1,62 @@ +import logging + +import celery +from django.core.management.base import BaseCommand + +from project.models import Request +from project.tasks import create_zip_departement_rnu_package_one_off +from public_data.models import Commune, Departement, Sudocuh +from public_data.models.sudocuh import DocumentUrbanismeChoices +from users.models import User + +logger = logging.getLogger("management.commands") + + +class Command(BaseCommand): + help = "create_rnu_packages" + + def add_arguments(self, parser): + parser.add_argument("--departement", type=str, required=False) + + def check_requests_are_created_for_departement(self, departement): + communes = Commune.objects.filter( + insee__in=[Sudocuh.objects.filter(du_opposable=DocumentUrbanismeChoices.RNU).values("code_insee")], + departement=departement, + ) + + commune_count = communes.count() + request_for_communes_count = Request.objects.filter( + done=True, + project__land_id__in=[str(commune.id) for commune in communes], + user=User.objects.get(email="rnu.package@mondiagartif.beta.gouv.fr"), + ).count() + + if commune_count != request_for_communes_count: + logger.error( + ( + f"Commune count ({commune_count}) does not match " + f"request for communes count ({request_for_communes_count})" + ) + ) + return False + else: + logger.info( + f"Commune count ({commune_count}) matches request for communes count ({request_for_communes_count})" + ) + + return True + + def handle(self, *args, **options): + tasks = [] + + departements = Departement.objects.all() + + if options["departement"]: + departements = departements.filter(source_id=options["departement"]) + + for departement in departements: + if self.check_requests_are_created_for_departement(departement): + logger.info(f"Creating RNU package for departement {departement.source_id}") + tasks.append(create_zip_departement_rnu_package_one_off.si(departement.source_id)) + + celery.group(*tasks).apply_async(queue="long") diff --git a/users/migrations/0012_user_created_at_user_updated_at.py b/users/migrations/0012_user_created_at_user_updated_at.py new file mode 100644 index 000000000..29bd76714 --- /dev/null +++ b/users/migrations/0012_user_created_at_user_updated_at.py @@ -0,0 +1,22 @@ +# Generated by Django 4.2.13 on 2024-07-18 12:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + dependencies = [ + ("users", "0011_alter_user_organism"), + ] + + operations = [ + migrations.AddField( + model_name="user", + name="created_at", + field=models.DateTimeField(auto_now_add=True, null=True, verbose_name="Créé le"), + ), + migrations.AddField( + model_name="user", + name="updated_at", + field=models.DateTimeField(auto_now=True, null=True, verbose_name="Mis à jour le"), + ), + ] diff --git a/users/migrations/0013_auto_20240718_1408.py b/users/migrations/0013_auto_20240718_1408.py new file mode 100644 index 000000000..a186bc99d --- /dev/null +++ b/users/migrations/0013_auto_20240718_1408.py @@ -0,0 +1,16 @@ +# Generated by Django 4.2.13 on 2024-07-18 12:08 + +from django.db import migrations + + +def set_created_and_update_at_to_none(apps, schema_editor): + User = apps.get_model("users", "User") + User.objects.update(created_at=None, updated_at=None) + + +class Migration(migrations.Migration): + dependencies = [ + ("users", "0012_user_created_at_user_updated_at"), + ] + + operations = [migrations.RunPython(set_created_and_update_at_to_none)] diff --git a/users/models.py b/users/models.py index e3e84c689..999c66557 100644 --- a/users/models.py +++ b/users/models.py @@ -2,6 +2,7 @@ from django.contrib.auth.models import AbstractUser from django.db import models +from django.utils import timezone from .managers import UserManager @@ -39,6 +40,9 @@ class ORGANISMS(models.TextChoices): USERNAME_FIELD = "email" REQUIRED_FIELDS: List[str] = [] + created_at = models.DateTimeField("Créé le", auto_now_add=True, blank=True, null=True) + updated_at = models.DateTimeField("Mis à jour le", auto_now=True, blank=True, null=True) + objects = UserManager() @staticmethod @@ -72,6 +76,10 @@ def greetings(self): def __str__(self): return self.email + @property + def created_today(self): + return self.created_at.date() == timezone.now().date() + def save(self, *args, **kwargs): self.organism_group = User.get_group(self.organism) super().save(*args, **kwargs) diff --git a/users/templates/users/signin.html b/users/templates/users/signin.html index a584df398..28c6dda0e 100644 --- a/users/templates/users/signin.html +++ b/users/templates/users/signin.html @@ -8,8 +8,28 @@+ La page de téléchargement de paquet de rapports locaux est uniquement accessible aux utilisateurs enregistrés et connectés. +
++ + Vous pouvez vous connecter ci-dessous, ou créer un compte. + +
+