From d0a54b39c1b177a14547402c21c846572dd8154f Mon Sep 17 00:00:00 2001 From: Jean-Pascal MILCENT Date: Wed, 15 Sep 2021 16:54:54 +0200 Subject: [PATCH] Feat Synthese: add status, red lists filters Resolve #1492. --- backend/dependencies/TaxHub | 2 +- .../gn_synthese/utils/query_select_sqla.py | 90 ++++- backend/geonature/core/ref_geo/models.py | 10 +- ...f350e23bee07_link_bdc_status_to_ref_geo.py | 324 ++++++++++++++++++ backend/geonature/utils/config_schema.py | 103 ++++-- config/default_config.toml.example | 12 + .../GN2CommonModule/form/data-form.service.ts | 25 +- .../synthese-advanced-form-component.ts | 18 +- .../synthese-advanced-form-store.service.ts | 47 ++- .../synthese-advanced-form.component.html | 110 ++++-- .../synthese-form.component.html | 36 +- .../synthese-form/synthese-form.component.ts | 3 +- .../synthese-form/synthese-form.service.ts | 43 ++- 13 files changed, 718 insertions(+), 105 deletions(-) create mode 100644 backend/geonature/migrations/versions/f350e23bee07_link_bdc_status_to_ref_geo.py diff --git a/backend/dependencies/TaxHub b/backend/dependencies/TaxHub index 41b1aa2624..908b1f663e 160000 --- a/backend/dependencies/TaxHub +++ b/backend/dependencies/TaxHub @@ -1 +1 @@ -Subproject commit 41b1aa26241ea501e81599676dc2db5dddb3586d +Subproject commit 908b1f663e126d95f21b87f5b5abac4d19f6c4d1 diff --git a/backend/geonature/core/gn_synthese/utils/query_select_sqla.py b/backend/geonature/core/gn_synthese/utils/query_select_sqla.py index 6fa3bd0c55..fe8bdc4127 100644 --- a/backend/geonature/core/gn_synthese/utils/query_select_sqla.py +++ b/backend/geonature/core/gn_synthese/utils/query_select_sqla.py @@ -19,7 +19,9 @@ from utils_flask_sqla_geo.utilsgeometry import circle_from_point from geonature.utils.env import DB -from geonature.core.taxonomie.models import Taxref, CorTaxonAttribut, TaxrefLR +from geonature.core.taxonomie.models import ( + TaxrefLR +) from geonature.core.gn_synthese.models import ( Synthese, CorObserverSynthese, @@ -32,7 +34,17 @@ TDatasets, ) from geonature.utils.errors import GeonatureApiError - +from geonature.core.ref_geo.models import ( + CorAreaStatus, +) +from apptax.taxonomie.models import ( + Taxref, + CorTaxonAttribut, + TaxrefBdcStatutTaxon, + TaxrefBdcStatutCorTextValues, + TaxrefBdcStatutText, + TaxrefBdcStatutValues, +) class SyntheseQuery: """ @@ -331,6 +343,80 @@ def filter_other_filters(self): if colname.startswith("area"): self.add_join(CorAreaSynthese, CorAreaSynthese.id_synthese, self.model.id_synthese) self.query = self.query.where(CorAreaSynthese.id_area.in_(value)) + elif colname.endswith("_red_lists"): + red_list_id = colname.replace("_red_lists", "") + all_red_lists_cfg = current_app.config["SYNTHESE"]["RED_LISTS_FILTERS"] + red_list_cfg = next((item for item in all_red_lists_cfg if item["id"] == red_list_id), None) + red_list_cte = ( + select([TaxrefBdcStatutTaxon.cd_ref, CorAreaStatus.id_area]) + .select_from( + TaxrefBdcStatutTaxon.__table__ + .join( + TaxrefBdcStatutCorTextValues, + TaxrefBdcStatutCorTextValues.id_value_text == TaxrefBdcStatutTaxon.id_value_text + ) + .join( + TaxrefBdcStatutText, + TaxrefBdcStatutText.id_text == TaxrefBdcStatutCorTextValues.id_text + ) + .join( + TaxrefBdcStatutValues, + TaxrefBdcStatutValues.id_value == TaxrefBdcStatutCorTextValues.id_value + ) + .join( + CorAreaStatus, + CorAreaStatus.cd_sig == TaxrefBdcStatutText.cd_sig + ) + ) + .where(TaxrefBdcStatutValues.code_statut.in_(value)) + .where(TaxrefBdcStatutText.cd_type_statut == red_list_cfg['status_type']) + .where(TaxrefBdcStatutText.enable == True) + .cte(name=f"{red_list_id}_red_list") + ) + cas_red_list = aliased(CorAreaSynthese) + self.add_join(cas_red_list, cas_red_list.id_synthese, self.model.id_synthese) + self.add_join(Taxref, Taxref.cd_nom, self.model.cd_nom) + self.add_join_multiple_cond(red_list_cte, [ + red_list_cte.c.cd_ref == Taxref.cd_ref, + red_list_cte.c.id_area == cas_red_list.id_area, + ]) + + elif colname.endswith("_status"): + status_id = colname.replace("_status", "") + all_status_cfg = current_app.config["SYNTHESE"]["STATUS_FILTERS"] + status_cfg = next((item for item in all_status_cfg if item["id"] == status_id), None) + # Check if a checkbox was used. + if (isinstance(value, list) and value[0] == True and len(status_cfg['status_types']) == 1): + value = status_cfg['status_types'] + status_cte = ( + select([TaxrefBdcStatutTaxon.cd_ref, CorAreaStatus.id_area]) + .select_from( + TaxrefBdcStatutTaxon.__table__ + .join( + TaxrefBdcStatutCorTextValues, + TaxrefBdcStatutCorTextValues.id_value_text == TaxrefBdcStatutTaxon.id_value_text + ) + .join( + TaxrefBdcStatutText, + TaxrefBdcStatutText.id_text == TaxrefBdcStatutCorTextValues.id_text + ) + .join( + CorAreaStatus, + CorAreaStatus.cd_sig == TaxrefBdcStatutText.cd_sig + ) + ) + .where(TaxrefBdcStatutText.cd_type_statut.in_(value)) + .where(TaxrefBdcStatutText.enable == True) + .distinct() + .cte(name=f"{status_id}_status") + ) + cas_status = aliased(CorAreaSynthese) + self.add_join(cas_status, cas_status.id_synthese, self.model.id_synthese) + self.add_join(Taxref, Taxref.cd_nom, self.model.cd_nom) + self.add_join_multiple_cond(status_cte, [ + status_cte.c.cd_ref == Taxref.cd_ref, + status_cte.c.id_area == cas_status.id_area, + ]) elif colname.startswith("id_"): col = getattr(self.model.__table__.columns, colname) self.query = self.query.where(col.in_(value)) diff --git a/backend/geonature/core/ref_geo/models.py b/backend/geonature/core/ref_geo/models.py index e38937dbf6..573e5983c3 100644 --- a/backend/geonature/core/ref_geo/models.py +++ b/backend/geonature/core/ref_geo/models.py @@ -70,4 +70,12 @@ class LiMunicipalities(DB.Model): @hybrid_property def nom_com_dept(self): - return '{} ({})'.format(self.nom_com, self.insee_dep) \ No newline at end of file + return '{} ({})'.format(self.nom_com, self.insee_dep) + + +@serializable +class CorAreaStatus(DB.Model): + __tablename__ = "cor_area_status" + __table_args__ = {"schema": "ref_geo"} + cd_sig = DB.Column(DB.Unicode, primary_key=True) + id_area = DB.Column(DB.Integer, ForeignKey("ref_geo.l_areas.id_area"), primary_key=True) diff --git a/backend/geonature/migrations/versions/f350e23bee07_link_bdc_status_to_ref_geo.py b/backend/geonature/migrations/versions/f350e23bee07_link_bdc_status_to_ref_geo.py new file mode 100644 index 0000000000..a1ede1461a --- /dev/null +++ b/backend/geonature/migrations/versions/f350e23bee07_link_bdc_status_to_ref_geo.py @@ -0,0 +1,324 @@ +"""Add table to link bdc_status and ref_geo + +Revision ID: f350e23bee07 +Revises: 1eb624249f2b +Create Date: 2021-09-24 17:39:42.062506 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = 'f350e23bee07' +down_revision = '1eb624249f2b' +branch_labels = None +depends_on = None + + +def upgrade(): + op.execute(""" + CREATE TABLE ref_geo.cor_area_status ( + cd_sig varchar(25) NOT NULL, + id_area int4 NOT NULL, + CONSTRAINT pk_cor_area_status PRIMARY KEY (cd_sig, id_area), + CONSTRAINT fk_cor_area_status_id_area FOREIGN KEY (id_area) REFERENCES ref_geo.l_areas(id_area) ON UPDATE CASCADE + ) + """) + op.execute(""" + INSERT INTO ref_geo.cor_area_status ( + WITH old_regions AS ( + SELECT + '11' AS code, -- Île-de-France + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('75','77','78','91','92','93','94','95') + UNION + SELECT + '21' AS code, -- Champagne-Ardenne + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('08','10','51','52') + UNION + SELECT + '22' AS code, -- Picardie + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('02','60','80') + UNION + SELECT + '23' AS code, -- Haute-Normandie + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('27', '76') + UNION + SELECT + '24' AS code, -- Centre + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('18','28','36','37','41','45') + UNION + SELECT + '25' AS code, -- Basse-Normandie + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('14','50','61') + UNION + SELECT + '26' AS code, -- Bourgogne + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('21','58','71','89') + UNION + SELECT + '31' AS code, -- Nord-Pas-de-Calais + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('59', '62') + UNION + SELECT + '41' AS code, -- Lorraine + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('54','55','57','88') + UNION + SELECT + '42' AS code, -- Alsace + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('67', '68') + UNION + SELECT + '43' AS code, -- Franche-Comté + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('25','39','70','90') + UNION + SELECT + '52' AS code, -- Pays de la Loire + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('44','49','53','72','85') + UNION + SELECT + '53' AS code, -- Bretagne + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('22','29','35','56') + UNION + SELECT + '54' AS code, -- Poitou-Charentes + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('16','17','79','86') + UNION + SELECT + '72' AS code, -- Aquitaine + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('24','33','40','47','64') + UNION + SELECT + '73' AS code, -- Midi-Pyrénées + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('9','12','31','32','46','65','81','82') + UNION + SELECT + '74' AS code, -- Limousin + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('19','23','87') + UNION + SELECT + '82' AS code, -- Rhône-Alpes + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('01','07','26','38','42','69','73','74') + UNION + SELECT + '83' AS code, -- Auvergne + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('03', '15', '43', '63') + UNION + SELECT + '91' AS code, -- Languedoc-Roussillon + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('11','30','34','48','66') + UNION + SELECT + '93' AS code, -- Provence-Alpes-Côte d’Azur + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('04', '05', '06', '13', '83', '84') + UNION + SELECT + '94' AS code, -- Corse + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('2A', '2B') + ), + new_regions AS ( + SELECT + '11' AS code, -- Île-de-France + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('75','77','78','91','92','93','94','95') + UNION + SELECT + '24' AS code, -- Centre-Val de Loire + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('18','28','36','37','41','45') + UNION + SELECT + '27' AS code, -- Bourgogne-Franche-Comté + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('21','25','39','58','70','71','89','90') + UNION + SELECT + '28' AS code, -- Normandie + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('14','27','50','61','76') + UNION + SELECT + '32' AS code, -- Hauts-de-France + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('02', '59', '60', '62', '80') + UNION + SELECT + '44' AS code, -- Grand Est + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('08','10','51','52','54','55','57','67','68','88') + UNION + SELECT + '52' AS code, -- Pays de la Loire + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('44','49','53','72','85') + UNION + SELECT + '53' AS code, -- Bretagne + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('22','29','35','56') + UNION + SELECT + '75' AS code, -- Nouvelle-Aquitaine + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('16','17','19','23','24','33','40','47','64','79','86','87') + UNION + SELECT + '76' AS code, -- Occitanie + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('09', '11', '12', '30', '31', '32', '34', '46', '48', '65', '66', '81', '82') + UNION + SELECT + '84' AS code, -- Auvergne-Rhône-Alpes + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('01', '03', '07', '15', '26', '38', '42', '43', '63', '69', '73', '74') + UNION + SELECT + '93' AS code, -- Provence-Alpes-Côte d’Azur + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('04', '05', '06', '13', '83', '84') + UNION + SELECT + '94' AS code, -- Corse + id_area + FROM ref_geo.l_areas + WHERE id_type = ref_geo.get_id_area_type('DEP') + AND area_code IN ('2A', '2B') + ), + sig AS ( + SELECT + 'ETATFRA' AS cd_sig, + la.id_area + FROM ref_geo.l_areas AS la + WHERE la.id_type = ref_geo.get_id_area_type('DEP') + UNION + SELECT DISTINCT + cd_sig, + ( + SELECT id_area + FROM ref_geo.l_areas + WHERE area_code = REPLACE(cd_sig, 'INSEED', '') + AND id_type = ref_geo.get_id_area_type('DEP') + ) + FROM taxonomie.bdc_statut_text AS bst + WHERE cd_sig ILIKE 'INSEED%' + UNION + SELECT DISTINCT + cd_sig, + nrs.id_area + FROM taxonomie.bdc_statut_text AS bst + JOIN new_regions AS nrs ON (REPLACE(cd_sig, 'INSEENR', '') = nrs.code) + WHERE cd_sig ILIKE 'INSEENR%' + UNION + SELECT DISTINCT + cd_sig, + ors.id_area + FROM taxonomie.bdc_statut_text AS bst + JOIN old_regions AS ors ON (REPLACE(cd_sig, 'INSEER', '') = ors.code) + WHERE cd_sig ILIKE 'INSEER%' + UNION + SELECT + 'TERFXFR' AS cd_sig, + la.id_area + FROM ref_geo.l_areas AS la + WHERE la.id_type = ref_geo.get_id_area_type('DEP') + ) + SELECT s.* + FROM sig AS s + WHERE s.id_area IS NOT NULL + ORDER BY s.cd_sig, s.id_area ASC + )""") + op.execute("CREATE INDEX idx_cabs_cd_sig ON ref_geo.cor_area_status(cd_sig);") + + +def downgrade(): + op.execute("DROP TABLE ref_geo.cor_area_status") diff --git a/backend/geonature/utils/config_schema.py b/backend/geonature/utils/config_schema.py index 596b2a0564..b29a2dc695 100644 --- a/backend/geonature/utils/config_schema.py +++ b/backend/geonature/utils/config_schema.py @@ -240,9 +240,72 @@ class GnFrontEndConf(Schema): class Synthese(Schema): + #-------------------------------------------------------------------- + # SYNTHESE - SEARCH FORM AREA_FILTERS = fields.List( fields.Dict, load_default=[{"label": "Communes", "type_code": "COM"}] ) + # Nombre de résultat à afficher pour la rechercher autocompleté de taxon + TAXON_RESULT_NUMBER = fields.Integer(load_default=20) + # Afficher ou non l'arbre taxonomique + DISPLAY_TAXON_TREE = fields.Boolean(load_default=True) + # Ajouter le filtre sur l'observers_txt en ILIKE sur les portée 1 et 2 du CRUVED + CRUVED_SEARCH_WITH_OBSERVER_AS_TXT = fields.Boolean(load_default=False) + # Switch the observer form input in free text input (true) or in select input (false) + SEARCH_OBSERVER_WITH_LIST = fields.Boolean(load_default=False) + # Id of the observer list -- utilisateurs.t_menus + ID_SEARCH_OBSERVER_LIST = fields.Integer(load_default=1) + # Regulatory or not status list of fields + STATUS_FILTERS = fields.List(fields.Dict, missing=[ + { + "id": "protections", + "show": True, + "display_name": "Taxons protégés", + "status_types": ["PN", "PR", "PD"], + }, + { + "id": "regulations", + "show": True, + "display_name": "Taxons réglementés", + "status_types": ["REGLII", "REGLLUTTE", "REGL", "REGLSO"], + }, + { + "id": "znief", + "show": True, + "display_name": "Espèces déterminantes ZNIEFF", + "status_types": ["ZDET"], + }, + ]) + # Red lists list of fields + RED_LISTS_FILTERS = fields.List(fields.Dict, missing=[ + { + "id": "worldwide", + "show": True, + "display_name": "Liste rouge mondiale", + "status_type": "LRM", + }, + { + "id": "european", + "show": True, + "display_name": "Liste rouge européenne", + "status_type": "LRE", + }, + { + "id": "national", + "show": True, + "display_name": "Liste rouge nationale", + "status_type": "LRN", + }, + { + "id": "regional", + "show": True, + "display_name": "Liste rouge régionale", + "status_type": "LRR", + }, + ]) + + #-------------------------------------------------------------------- + # SYNTHESE - OBSERVATIONS LIST # Listes des champs renvoyés par l'API synthese '/synthese' # Si on veut afficher des champs personnalisés dans le frontend (paramètre LIST_COLUMNS_FRONTEND) il faut # d'abbord s'assurer que ces champs sont bien renvoyé par l'API ! @@ -250,6 +313,9 @@ class Synthese(Schema): COLUMNS_API_SYNTHESE_WEB_APP = fields.List(fields.String, load_default=DEFAULT_COLUMNS_API_SYNTHESE) # Colonnes affichées sur la liste des résultats de la sytnthese LIST_COLUMNS_FRONTEND = fields.List(fields.Dict, load_default=DEFAULT_LIST_COLUMN) + + #-------------------------------------------------------------------- + # SYNTHESE - DOWNLOADS (AKA EXPORTS) EXPORT_COLUMNS = fields.List(fields.String(), load_default=DEFAULT_EXPORT_COLUMNS) # Certaines colonnes sont obligatoires pour effectuer les filtres CRUVED EXPORT_ID_SYNTHESE_COL = fields.String(load_default="id_synthese") @@ -262,35 +328,32 @@ class Synthese(Schema): EXPORT_METADATA_ACTOR_COL = fields.String(load_default="acteurs") # Formats d'export disponibles ["csv", "geojson", "shapefile", "gpkg"] EXPORT_FORMAT = fields.List(fields.String(), load_default=["csv", "geojson", "shapefile"]) - # Nombre de résultat à afficher pour la rechercher autocompleté de taxon - TAXON_RESULT_NUMBER = fields.Integer(load_default=20) + # Nombre max d'observation dans les exports + NB_MAX_OBS_EXPORT = fields.Integer(load_default=50000) + + #-------------------------------------------------------------------- + # SYNTHESE - OBSERVATION DETAILS # Liste des id attributs Taxhub à afficher sur la fiche détaile de la synthese # et sur les filtres taxonomiques avancés ID_ATTRIBUT_TAXHUB = fields.List(fields.Integer(), load_default=[102, 103]) - # nom des colonnes de la table gn_synthese.synthese que l'on veux retirer des filres dynamiques - # et de la modale d'information détaillée d'une observation - # example = "[non_digital_proof]" + # Display email on synthese and validation info obs modal + DISPLAY_EMAIL = fields.Boolean(load_default=True) + + #-------------------------------------------------------------------- + # SYNTHESE - SHARED PARAMETERS + # Nom des colonnes de la table gn_synthese.synthese que l'on veux retirer des filtres dynamiques + # et de la modale d'information détaillée d'une observation example = "[non_digital_proof]" EXCLUDED_COLUMNS = fields.List(fields.String(), load_default=[]) - # Afficher ou non l'arbre taxonomique - DISPLAY_TAXON_TREE = fields.Boolean(load_default=True) - # rajoute le filtre sur l'observers_txt en ILIKE sur les portée 1 et 2 du CRUVED - CRUVED_SEARCH_WITH_OBSERVER_AS_TXT = fields.Boolean(load_default=False) - # Switch the observer form input in free text input (true) or in select input (false) - SEARCH_OBSERVER_WITH_LIST = fields.Boolean(load_default=False) - # id of the observer list -- utilisateurs.t_menus - ID_SEARCH_OBSERVER_LIST = fields.Integer(load_default=1) + + #-------------------------------------------------------------------- + # SYNTHESE - MAP # Nombre max d'observation à afficher sur la carte NB_MAX_OBS_MAP = fields.Integer(load_default=50000) - # clusteriser les layers sur la carte + # Clusteriser les layers sur la carte ENABLE_LEAFLET_CLUSTER = fields.Boolean(load_default=True) - # Nombre max d'observation dans les exports - NB_MAX_OBS_EXPORT = fields.Integer(load_default=50000) - # Nombre des "dernières observations" affiché à l'arrive sur la synthese + # Nombre des "dernières observations" affichées à l'arrivée sur la synthese NB_LAST_OBS = fields.Integer(load_default=100) - # Display email on synthese and validation info obs modal - DISPLAY_EMAIL = fields.Boolean(load_default=True) - # Map configuration BASEMAP = [ diff --git a/config/default_config.toml.example b/config/default_config.toml.example index 4a6b723cfc..aeca6e1096 100644 --- a/config/default_config.toml.example +++ b/config/default_config.toml.example @@ -384,6 +384,18 @@ MAIL_ON_ERROR = false "date_modification", "champs_additionnels ] + RED_LISTS_FILTERS = [ + { "id" = "worldwide", "show" = true, "display_name" = "Liste rouge mondiale", "status_type" = "LRM" }, + { "id" = "european", "show" = true, "display_name" = "Liste rouge européenne", "status_type" = "LRE" }, + { "id" = "national", "show" = true, "display_name" = "Liste rouge nationale", "status_type" = "LRN" }, + { "id" = "regional", "show" = true, "display_name" = "Liste rouge régionale", "status_type" = "LRR" }, + ] + STATUS_FILTERS = [ + { "id" = "protections", "show" = true, "display_name" = "Taxons protégés", "status_types" = ["PN", "PR", "PD"] }, + { "id" = "regulations", "show" = true, "display_name" = "Taxons réglementés", "status_types" = ["REGLII", "REGL", "REGLSO"] }, + { "id" = "invasive", "show" = true, "display_name" = "Espèces envahissantes", "status_types" = ["REGLLUTTE"] }, + { "id" = "znief", "show" = true, "display_name" = "Espèces déterminantes ZNIEFF", "status_types" = ["ZDET"] }, + ] # Configuration de l'accès sans authentication [PUBLIC_ACCESS] diff --git a/frontend/src/app/GN2CommonModule/form/data-form.service.ts b/frontend/src/app/GN2CommonModule/form/data-form.service.ts index dafb144cdf..69d02b52df 100644 --- a/frontend/src/app/GN2CommonModule/form/data-form.service.ts +++ b/frontend/src/app/GN2CommonModule/form/data-form.service.ts @@ -337,7 +337,7 @@ export class DataFormService { * * @param params: dict of paramters */ - getAcquisitionFrameworks(params = {}) { + getAcquisitionFrameworks(params = {}) { let queryString: HttpParams = new HttpParams(); for (let key in params) { queryString = queryString.set(key, params[key]) @@ -349,7 +349,7 @@ export class DataFormService { ); } - getAcquisitionFrameworksForSelect(searchTerms = {}) { + getAcquisitionFrameworksForSelect(searchTerms = {}) { let queryString: HttpParams = new HttpParams(); for (let key in searchTerms) { queryString = queryString.set(key, searchTerms[key]) @@ -366,7 +366,7 @@ export class DataFormService { * @param id_af: id of acquisition_framework * @params params : get parameters */ - getAcquisitionFramework(id_af, params?: ParamsDict) { + getAcquisitionFramework(id_af, params?: ParamsDict) { let queryString: HttpParams = new HttpParams(); for (let key in params) { if(isArray(params[key])) { @@ -598,7 +598,7 @@ export class DataFormService { } return this._http.get(`${AppConfig.API_ENDPOINT}/gn_commons/additional_fields`, {params: queryString}).map(additionalFields => { - return additionalFields.map(data => { + return additionalFields.map(data => { return { "id_field": data.id_field, "attribut_label": data.field_label, @@ -620,9 +620,11 @@ export class DataFormService { ...data.additional_attributes } }) - - }); + }); + } + getRedListValues(statusType: String) { + return this._http.get(`${AppConfig.API_TAXHUB}/bdc_statuts/red_lists/${statusType}`); } getProfile(cdRef) { @@ -651,5 +653,14 @@ export class DataFormService { ); } -} + getStatusType(statusTypes: String[]) { + let queryString: HttpParams = new HttpParams(); + if (statusTypes) { + queryString = queryString.set('codes', statusTypes.join(',')); + } + return this._http.get(`${AppConfig.API_TAXHUB}/bdc_statuts/status_types`, { + params: queryString + }); + } +} diff --git a/frontend/src/app/GN2CommonModule/form/synthese-form/advanced-form/synthese-advanced-form-component.ts b/frontend/src/app/GN2CommonModule/form/synthese-form/advanced-form/synthese-advanced-form-component.ts index d2fe4e417f..3aab6eda6c 100644 --- a/frontend/src/app/GN2CommonModule/form/synthese-form/advanced-form/synthese-advanced-form-component.ts +++ b/frontend/src/app/GN2CommonModule/form/synthese-form/advanced-form/synthese-advanced-form-component.ts @@ -1,11 +1,14 @@ -import { Component, OnInit, ViewChild, AfterContentInit } from '@angular/core'; +import { Component, OnInit, ViewChild, AfterContentInit, Inject } from '@angular/core'; +import { FormGroup } from '@angular/forms'; + import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap'; import { TreeNode, TreeComponent, IActionMapping } from 'angular-tree-component'; -import { SyntheseFormService } from '@geonature_common/form/synthese-form/synthese-form.service'; + +import { APP_CONFIG_TOKEN } from '@geonature_config/app.config'; import { DynamicFormService } from '@geonature_common/form/dynamic-form-generator/dynamic-form.service'; -import { FormGroup } from '@angular/forms'; +import { SyntheseFormService } from '@geonature_common/form/synthese-form/synthese-form.service'; import { TaxonAdvancedStoreService } from '@geonature_common/form/synthese-form/advanced-form/synthese-advanced-form-store.service'; -import { AppConfig } from '@geonature_config/app.config'; + @Component({ selector: 'pnx-validation-taxon-advanced', @@ -15,8 +18,7 @@ import { AppConfig } from '@geonature_config/app.config'; }) export class TaxonAdvancedModalComponent implements OnInit, AfterContentInit { @ViewChild('tree') treeComponent: TreeComponent; - public AppConfig = AppConfig; - public URL_AUTOCOMPLETE = AppConfig.API_TAXHUB + '/taxref/search/lb_nom'; + public URL_AUTOCOMPLETE; public taxonsTree; public treeOptions; public selectedNodes = []; @@ -28,10 +30,14 @@ export class TaxonAdvancedModalComponent implements OnInit, AfterContentInit { public showTree = false; constructor( + @Inject(APP_CONFIG_TOKEN) private cfg, public activeModal: NgbActiveModal, public formService: SyntheseFormService, public storeService: TaxonAdvancedStoreService ) { + // Set config parameters + this.URL_AUTOCOMPLETE = this.cfg.API_TAXHUB + '/taxref/search/lb_nom'; + const actionMapping: IActionMapping = { mouse: { click: (tree, node, $event) => {}, diff --git a/frontend/src/app/GN2CommonModule/form/synthese-form/advanced-form/synthese-advanced-form-store.service.ts b/frontend/src/app/GN2CommonModule/form/synthese-form/advanced-form/synthese-advanced-form-store.service.ts index 64ba78031d..3796535308 100644 --- a/frontend/src/app/GN2CommonModule/form/synthese-form/advanced-form/synthese-advanced-form-store.service.ts +++ b/frontend/src/app/GN2CommonModule/form/synthese-form/advanced-form/synthese-advanced-form-store.service.ts @@ -1,15 +1,17 @@ -import { Injectable } from '@angular/core'; +import { Inject, Injectable } from '@angular/core'; + +import { TreeModel } from 'angular-tree-component'; + +import { APP_CONFIG_TOKEN } from '@geonature_config/app.config'; import { DataFormService } from '@geonature_common/form/data-form.service'; -import { SyntheseDataService } from '@geonature_common/form/synthese-form/synthese-data.service'; -import { SyntheseFormService } from '@geonature_common/form/synthese-form/synthese-form.service'; import { DynamicFormService } from '@geonature_common/form/dynamic-form-generator/dynamic-form.service'; -import { TreeModel } from 'angular-tree-component'; -import { AppConfig } from '@geonature_config/app.config'; import { formatTaxonTree } from '@geonature_common/form/taxon-tree/taxon-tree.service'; +import { SyntheseDataService } from '@geonature_common/form/synthese-form/synthese-data.service'; +import { SyntheseFormService } from '@geonature_common/form/synthese-form/synthese-form.service'; @Injectable() export class TaxonAdvancedStoreService { - public AppConfig = AppConfig; + public displayTaxonTree: Boolean = false; public taxonTree: any; public treeModel: TreeModel; public taxonTreeState: any; @@ -18,28 +20,51 @@ export class TaxonAdvancedStoreService { public taxonomyLR: Array; public taxonomyHab: Array; public taxonomyGroup2Inpn: Array; + public redListsValues: any = {}; constructor( + @Inject(APP_CONFIG_TOKEN) private cfg, private _dataService: DataFormService, private _validationDataService: SyntheseDataService, private _formService: SyntheseFormService, private _formGen: DynamicFormService ) { - if (AppConfig.SYNTHESE.DISPLAY_TAXON_TREE) { + // Set taxon tree if needed + if (this.cfg.SYNTHESE.DISPLAY_TAXON_TREE) { + this.displayTaxonTree = true; this._validationDataService.getTaxonTree().subscribe(data => { this.taxonTree = formatTaxonTree(data); }); } + // Set protection status filters data + this._formService.statusFilters.forEach(status => { + this._dataService + .getStatusType(status.status_types) + .subscribe(data => { + status.values = data; // get taxhub attributes + }); + }); + + // Set red lists filters data + this._formService.redListsFilters.forEach(redList => { + this._dataService + .getRedListValues(redList.status_type) + .subscribe(data => { + redList.values = data; + }); + }); + + // Get TaxHub attributes this._dataService.getTaxhubBibAttributes().subscribe(attrs => { - // display only the taxhub attributes set in the config + // Display only the taxhub attributes set in the config this.taxhubAttributes = attrs .filter(attr => { - return AppConfig.SYNTHESE.ID_ATTRIBUT_TAXHUB.indexOf(attr.id_attribut) !== -1; + return this.cfg.SYNTHESE.ID_ATTRIBUT_TAXHUB.indexOf(attr.id_attribut) !== -1; }) .map(attr => { - // format attributes to fit with the GeoNature dynamicFormComponent + // Format attributes to fit with the GeoNature dynamicFormComponent attr['values'] = JSON.parse(attr['liste_valeur_attribut']).values; attr['attribut_name'] = 'taxhub_attribut_' + attr['id_attribut']; attr['required'] = attr['obligatoire']; @@ -55,7 +80,7 @@ export class TaxonAdvancedStoreService { }); this.formBuilded = true; }); - // load LR, habitat and group2inpn + // Load LR, habitat and group2inpn this._dataService.getTaxonomyLR().subscribe(data => { this.taxonomyLR = data; }); diff --git a/frontend/src/app/GN2CommonModule/form/synthese-form/advanced-form/synthese-advanced-form.component.html b/frontend/src/app/GN2CommonModule/form/synthese-form/advanced-form/synthese-advanced-form.component.html index fd1936fe95..2a4298286e 100644 --- a/frontend/src/app/GN2CommonModule/form/synthese-form/advanced-form/synthese-advanced-form.component.html +++ b/frontend/src/app/GN2CommonModule/form/synthese-form/advanced-form/synthese-advanced-form.component.html @@ -47,7 +47,7 @@
Taxon(s) recherché(s):
-
- +
Statuts
+
- + + + +
+
+ + +
+
-
- +
Listes rouges
+
- + + +
-
- - +
+
Attributs TaxRef
+
+ + +
+ +
+ + +
+ +
+ + +
-
Attributs taxhub
+
Attributs TaxHub
- Données modifiées depuis la dernière validation + > + Données modifiées depuis la dernière validation