Skip to content

Commit

Permalink
date, settings, and notification
Browse files Browse the repository at this point in the history
  • Loading branch information
pyDez committed Nov 26, 2024
1 parent 723b697 commit e071bac
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 181 deletions.
4 changes: 3 additions & 1 deletion config/settings/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -390,14 +390,16 @@
DEMARCHES_SIMPLIFIEE = {
# Documentation API de pré-remplissage :
# https://doc.demarches-simplifiees.fr/pour-aller-plus-loin/api-de-preremplissage
"API_URL": "https://www.demarches-simplifiees.fr/api/public/v1/",
"PRE_FILL_API_URL": "https://www.demarches-simplifiees.fr/api/public/v1/",
"DEMARCHE_HAIE": {
"ID": "103363",
# Les ids des champs de la démarche peuvent être trouvés sur la page suivante:
# https://www.demarches-simplifiees.fr/preremplir/test-declaration-de-travaux-sur-haies
"PROFIL_FIELD_ID": "champ_Q2hhbXAtNDU0Mzk2MQ",
"MOULINETTE_URL_FIELD_ID": "champ_Q2hhbXAtNDU0Mzk0Mw",
},
"GRAPHQL_API_URL": "https://www.demarches-simplifiees.fr/api/v2/graphql",
"GRAPHQL_API_BEARER_TOKEN": env("DJANGO_DEMARCHE_SIMPLIFIEE_TOKEN", default=None),
}

OPS_MATTERMOST_HANDLERS = env.list("DJANGO_OPS_MATTERMOST_HANDLERS", default=[])
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
import logging
from datetime import datetime, timedelta
from textwrap import dedent

import requests
from django.conf import settings
from django.core.management.base import BaseCommand
from django.urls import reverse

from envergo.geodata.models import DEPARTMENT_CHOICES
from envergo.moulinette.models import ConfigHaie
from envergo.petitions.models import PetitionProject
from envergo.utils.mattermost import notify
from envergo.utils.urls import extract_param_from_url

logger = logging.getLogger(__name__)


class Command(BaseCommand):
help = "Fetch freshly submitted dossier on Démarches Simplifiées and notify admins."

def handle(self, *args, **options):
api_url = "https://www.demarches-simplifiees.fr/api/v2/graphql"
# get all the dossier updated in the last hour
api_url = settings.DEMARCHES_SIMPLIFIEE["GRAPHQL_API_URL"]
now_utc = datetime.utcnow()
one_hour_ago_utc = now_utc - timedelta(hours=1)
iso8601_one_hour_ago = one_hour_ago_utc.isoformat() + "Z"

handled_demarches = []

Expand All @@ -23,32 +33,19 @@ def handle(self, *args, **options):
if demarche_number in handled_demarches:
continue

project_field_id = next(
(
field
for field in activated_department.demarche_simplifiee_pre_fill_config
if field["source"] == "project_reference"
),
None,
)
if project_field_id is None:
raise # TODO

has_next_page = True
cursor = None
while has_next_page:

variables = f"""{{
"demarcheNumber":{demarche_number},
"state":"en_construction",
"updatedSince": {"2024-11-19T11:23:00+01:00"},
"updatedSince": {iso8601_one_hour_ago},
"after":{cursor if cursor else "null"}
}}""" # TODO date
}}"""

query = """
query getDemarche(
$demarcheNumber: Int!,
$state: DossierState,
$updatedSince: ISO8601DateTime,
$after: String
)
Expand All @@ -70,27 +67,36 @@ def handle(self, *args, **options):
nodes {
number
state
champs{
id
label
stringValue
prefilled
}
}
}
}
}"""

body = {
"query": query,
"variables": variables,
}
response = requests.post(
api_url,
json={"query": query, "variables": variables},
json=body,
headers={
"Content-Type": "application/json",
"Authorization": "Bearer MzE3ZmQ1ZTQtOGYwMC00ZjU5LTk2OGMtZGU1NDEyNWIyYmQ3OzFjM1ZOTUx"
"TYjk5eWJSS2NKYWVweDJneg==", # TODO
"Authorization": f"Bearer {settings.DEMARCHES_SIMPLIFIEE["GRAPHQL_API_BEARER_TOKEN"]}",
},
)

if response.status_code >= 400:
logger.error(
"Demarches simplifiees API request failed",
extra={
"response.text": response.text,
"response.status_code": response.status_code,
"request.url": api_url,
"request.body": body,
},
)
# TODO notification ?
break

data = response.json()

dossiers = (
Expand All @@ -100,7 +106,17 @@ def handle(self, *args, **options):
.get("nodes", None)
)
if dossiers is None:
raise # TODO
logger.error(
"Demarches simplifiees API response is not well formated",
extra={
"response.json": data,
"response.status_code": response.status_code,
"request.url": api_url,
"request.body": body,
},
)
# TODO notification ?
break

has_next_page = (
data.get["data"]["demarche"]["dossiers"]
Expand All @@ -115,50 +131,48 @@ def handle(self, *args, **options):

for dossier in dossiers:
dossier_number = dossier["number"]
project_field = next(
(
champ
for champ in dossier["champs"]
if champ["id"] == project_field_id
),
None,
)
if project_field is None:
raise # TODO

if not project_field["prefilled"]:
raise # TODO

project_reference = project_field["stringValue"]

project = PetitionProject.objects.filter(
reference=project_reference
demarches_simplifiees_dossier_number=dossier_number
).first()
if project is None:
raise # TODO

department = extract_param_from_url(
project.moulinette_url, "department"
)

ds_url = (
f"https://www.demarches-simplifiees.fr/procedures/{demarche_number}/dossiers/"
f"{dossier_number}"
) # TODO
admin_url = reverse(
"admin:petitions_petitionproject_change",
args=[project_reference],
)
message = dedent(
f"""\
## Nouveau dossier GUH {department}
[Démarches simplifiées]({ds_url})
[Admin django](https://haie.beta.gouv.fr/{admin_url})
Linéaire détruit : {project.hedge_data.length_to_remove()} m
"""
)
notify(message, "haie")
logger.warning(
"A demarches simplifiees dossier has no corresponding project, it may have been "
"created without the guh",
extra={
"dossier_number": dossier_number,
"demarche_number": demarche_number,
},
)
# TODO notification ?
continue

if project.demarches_simplifiees_state is None:
# first time we have some data about this dossier
department = extract_param_from_url(
project.moulinette_url, "department"
)

ds_url = (
f"https://www.demarches-simplifiees.fr/procedures/{demarche_number}/dossiers/"
f"{dossier_number}"
)
admin_url = reverse(
"admin:petitions_petitionproject_change",
args=[project.reference],
)
message = dedent(
f"""\
### Nouveau dossier GUH {dict(DEPARTMENT_CHOICES).get(department, department)}
[Démarches simplifiées]({ds_url})
[Admin django](https://haie.beta.gouv.fr/{admin_url})
Linéaire détruit : {project.hedge_data.length_to_remove()} m
"""
)
notify(message, "haie")

project.demarches_simplifiees_state = dossier["state"]
project.save()

handled_demarches.append(demarche_number)
110 changes: 1 addition & 109 deletions envergo/petitions/tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,121 +22,13 @@ def test_dossier_submission_admin_alert(mock_notify, mock_post):
"number": 103363,
"dossiers": {
"pageInfo": {
"hasNextPage": False,
"hasNextPage": True,
"endCursor": "MjAyNC0xMS0xOVQxMDoyMzowMy45NTc0NDAwMDBaOzIxMDU5Njc1",
},
"nodes": [
{
"number": 21059675,
"state": "en_construction",
"champs": [
{
"id": "Q2hhbXAtNDUzNDEzNQ==",
"label": "Identité",
"stringValue": "",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDUzNDE0NQ==",
"label": "Adresse email",
"stringValue": "[email protected]",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDU0MzkzMg==",
"label": "Numéro de téléphone",
"stringValue": "06 12 23 45 56",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDUzNDE0NA==",
"label": "Adresse postale",
"stringValue": "Rue du Puits de Tet 21160 Marsannay-la-Côte",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDU0Mzk2MQ==",
"label": "J'effectue cette demande en tant que",
"stringValue": "Autre (collectivité, aménageur, gestionnaire de réseau,"
" particulier, etc.)",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDU0MzkzNA==",
"label": "Numéro Siret",
"stringValue": "",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDUzNDE0Mw==",
"label": "Raison sociale",
"stringValue": "",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDUzNDE1Ng==",
"label": "Description du projet",
"stringValue": "",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDUzNDE0Ng==",
"label": "Expliquez le contexte et les objectifs de votre projet",
"stringValue": "dgdfg",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDU5NjU1Mw==",
"label": "Conditionnalité PAC - BCAE8",
"stringValue": "",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDU1OTU2Mw==",
"label": "(NE PAS MODIFIER) Instruction Conditionnalité PAC - BCAE8",
"stringValue": "false",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDU5NjU2NA==",
"label": "Biodiversité",
"stringValue": "",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDU1OTU2OQ==",
"label": '(NE PAS MODIFIER) Instruction dérogation "espèces protégées"',
"stringValue": "false",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDU5NzUwMw==",
"label": "(NE PAS MODIFIER) Instruction Natura 2000",
"stringValue": "true",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDU1OTU0Mw==",
"label": "Informations réservées à l'administration",
"stringValue": "",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDU1OTU0Nw==",
"label": "Cette section est réservée à l'administration",
"stringValue": "",
"prefilled": False,
},
{
"id": "Q2hhbXAtNDU0Mzk0Mw==",
"label": "(NE PAS MODIFIER) URL simulation",
"stringValue": "https://haie.incubateur.net/simulateur/resultat/?profil="
"autre&motif=autre&reimplantation=non&haies=7d9b0b87-3b9d-"
"4300-bf36-ffadfff80283&travaux=destruction&department=02&"
"element=haie",
"prefilled": True,
},
],
}
],
},
Expand Down
2 changes: 1 addition & 1 deletion envergo/petitions/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def form_valid(self, form):
"agri_pac": "Exploitant-e agricole bénéficiaire de la PAC",
}
demarche_id = settings.DEMARCHES_SIMPLIFIEE["DEMARCHE_HAIE"]["ID"]
api_url = f"{settings.DEMARCHES_SIMPLIFIEE['API_URL']}demarches/{demarche_id}/dossiers"
api_url = f"{settings.DEMARCHES_SIMPLIFIEE['PRE_FILL_API_URL']}demarches/{demarche_id}/dossiers"

body = {
settings.DEMARCHES_SIMPLIFIEE["DEMARCHE_HAIE"][
Expand Down
8 changes: 7 additions & 1 deletion envergo/utils/urls.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from urllib.parse import parse_qs, urlencode, urlsplit, urlunsplit
from urllib.parse import parse_qs, urlencode, urlparse, urlsplit, urlunsplit


def update_qs(url, params):
Expand Down Expand Up @@ -30,3 +30,9 @@ def extract_mtm_params(url):
query = parse_qs(bits.query)
mtm_params = {k: v for k, v in query.items() if k.startswith("mtm_")}
return mtm_params


def extract_param_from_url(url, param_name):
parsed_url = urlparse(url)
query_params = parse_qs(parsed_url.query)
return query_params.get(param_name, [None])[0]

0 comments on commit e071bac

Please sign in to comment.