DEVELOPPEMENT

Général

GeoNature a été développé par Gil Deluermoz depuis 2010 avec PHP/Symfony/ExtJS.

En 2017, les parcs nationaux français ont décidé de refondre GeoNature complètement avec une nouvelle version (V2) réalisée en Python/Flask/Angular.

Mainteneurs :

  • Gil DELUERMOZ (PnEcrins) : Base de données / SQL / Installation / Mise à jour
  • Amandine SAHL (PnCevennes) : Backend / Python Flask / API
  • Theo LECHEMIA (PnEcrins) : Frontend / Angular
  • Camille MONCHICOURT (PnEcrins) : Documentation / Gestion du projet
http://geonature.fr/docs/img/developpement/geonature-techno.png

API

GeoNature utilise :

  • l’API de TaxHub (recherche taxon, règne et groupe d’un taxon…)
  • l’API du sous-module Nomenclatures (typologies et listes déroulantes)
  • l’API du sous-module d’authentification de UsersHub (login/logout, récupération du CRUVED d’un utilisateur)
  • l’API de GeoNature (get, post, update des données des différents modules, métadonnées, intersections géographiques, exports…)
https://raw.githubusercontent.com/PnX-SI/GeoNature/develop/docs/images/api_services.png

Liste des routes

Resource Operation Description
  PUT /users/password/change  
  PUT /users/password/new  
  POST /users/login/recovery  
  GET /pypn/register/test_uh  
  GET /synthese/observation_count  
  GET /synthese/taxa_distribution  
  GET /synthese/taxa_count  
  GET /occtax/vreleveocctax  
  GET /import/bibFields  
  POST /import/mapping  
  GET /users/confirmation  
  POST /users/inscription  
  PUT /users/role  
  POST /meta/upload_canvas  
  GET /import  
  POST /import/data_checker/(import_id)/field_mapping/(int:id_field_mapping)/content_mapping/(int:id_content_mapping)  
  GET /import/data_checker/(import_id)/field_mapping/(int:id_field_mapping)/content_mapping/(int:id_content_mapping)  
  POST /import/getNomencInfo/(int:id_import)/field_mapping/(int:id_field_mapping)  
  GET /import/getNomencInfo/(int:id_import)/field_mapping/(int:id_field_mapping)  
  POST /occtax/releve/(int:id_releve)/occurrence  
  POST /occtax/only/releve/(int:id_releve)  
  GET /meta/acquisition_frameworks/export_pdf/(id_acquisition_framework)  
  POST /pypn/register/post_usershub/(string:type_action)  
  GET /meta/dataset/export_pdf/(id_dataset)  
  POST /import/create_or_update_field_mapping/(int:id_mapping)  
  POST /import/update_content_mapping/(int:id_mapping)  
  GET /import/update_content_mapping/(int:id_mapping)  
  GET /import/content_mappings/(id_mapping)  
  GET /import/columns_import/(int:id_import)  
  GET /import/field_mappings/(id_mapping)  
  POST /occtax/occurrence/(int:id_occurrence)  
  POST /import/importData/(import_id)  
  GET /import/importData/(import_id)  
  POST /import/get_errors/(import_id)  
  GET /import/get_errors/(import_id)  
  GET /import/mappings/(mapping_type)  
  DELETE /import/mapping/(int:id_mapping)  
Commons GET /gn_commons/list/parameters  
  GET /gn_commons/t_mobile_apps  
  GET /gn_commons/modules  
  PUT /gn_commons/media/(int:id_media)  
  PUT /gn_commons/media  
  POST /gn_commons/media/(int:id_media)  
  POST /gn_commons/media  
  GET /gn_commons/media/thumbnails/(int:id_media)/(int:size)  
  GET /gn_commons/medias/(string:uuid_attached_row)  
  GET /gn_commons/media/(int:id_media)  
  DELETE /gn_commons/media/(int:id_media)  
Generic GET /config  
  GET /genericview/(view_schema)/(view_name)  
Habref GET /habref/habitats/autocomplete  
  GET /habref/typo  
  GET /habref/correspondance/(int:cd_hab)  
  GET /habref/habitat/(int:cd_hab)  
  GET /habref/search/(field)/(ilike)  
Metadata GET /meta/acquisition_frameworks_metadata  
  GET /meta/acquisition_frameworks  
  POST /meta/acquisition_framework  
  GET /meta/af_datasets_metadata  
  GET /meta/datasets  
  POST /meta/dataset  
  GET /meta/acquisition_framework_details/(id_acquisition_framework)  
  POST /meta/aquisition_framework_mtd/(uuid_af)  
  GET /meta/acquisition_framework/(id_acquisition_framework)  
  GET /meta/dataset_details/(id_dataset)  
  POST /meta/dataset_mtd/(id_user)/(id_organism)  
  POST /meta/dataset_mtd/(id_user)  
  GET /meta/dataset/(id_dataset)  
Monitoring GET /gn_monitoring/siteslist  
  GET /gn_monitoring/siteslist/(int:id_site)  
  GET /gn_monitoring/siteareas/(int:id_site)  
Nomenclatures GET /nomenclatures/nomenclatures  
  GET /nomenclatures/nomenclature/(int:id_type)  
  GET /nomenclatures/nomenclature/(string:code_type)  
Occtax POST /occtax/only/releve Post one Occtax data (Releve + Occurrence + Counting)
  GET /occtax/defaultNomenclatures  
  GET /occtax/occurrences  
  GET /occtax/releves  
  POST /occtax/releve Post one Occtax data (Releve + Occurrence + Counting)
  GET /occtax/export Export data from pr_occtax.v_export_occtax
  DELETE /occtax/releve/occurrence_counting/(int:id_count)  
  DELETE /occtax/occurrence/(int:id_occ)  
  GET /occtax/counting/(int:id_counting)  
  GET /occtax/releve/(int:id_releve)  
  DELETE /occtax/releve/(int:id_releve)  
Permissions GET /permissions/logout_cruved  
  GET /permissions/cruved  
Ref Geo GET /geo/municipalities  
  POST /geo/area_size  
  POST /geo/altitude  
  POST /geo/areas  
  GET /geo/areas  
  POST /geo/info  
Synthese GET /synthese/defaultsNomenclatures  
  POST /synthese/export_observations  
  GET /synthese/taxons_autocomplete  
  POST /synthese/export_metadata  
  GET /synthese/export_metadata  
  POST /synthese/export_statuts  
  POST /synthese/export_taxons  
  GET /synthese/general_stats  
  GET /synthese/taxons_tree  
  GET /synthese/color_taxon  
  POST /synthese/for_web Get filtered observations
  GET /synthese/for_web  
  GET /synthese/sources  
  GET /synthese Deprecated
  GET /synthese/vsynthese/(id_synthese) Get one synthese
User GET /gn_auth/logout_cruved  
  POST /gn_auth/login_cas  
  GET /gn_auth/login_cas  
  GET /users/organisms_dataset_actor  
  GET /users/organisms  
  POST /users/cor_role  
  POST /users/organism  
  GET /users/roles  
  POST /users/role  
  GET /users/menu_from_code/(string:code_liste)  
  GET /users/menu/(int:id_menu)  
  GET /users/role/(int:id_role)  
View_Permission GET /permissions_backoffice/users  
  POST /permissions_backoffice/other_permissions_form/id_permission/(int:id_permission)/user/(int:id_role)/filter_type/(int:id_filter_type)  
  POST /permissions_backoffice/other_permissions_form/user/(int:id_role)/filter_type/(int:id_filter_type)  
  GET /permissions_backoffice/other_permissions_form/id_permission/(int:id_permission)/user/(int:id_role)/filter_type/(int:id_filter_type)  
  GET /permissions_backoffice/other_permissions_form/user/(int:id_role)/filter_type/(int:id_filter_type)  
  POST /permissions_backoffice/cruved_form/module/(int:id_module)/role/(int:id_role)/object/(int:id_object)  
  POST /permissions_backoffice/cruved_form/module/(int:id_module)/role/(int:id_role)  
  GET /permissions_backoffice/cruved_form/module/(int:id_module)/role/(int:id_role)/object/(int:id_object)  
  GET /permissions_backoffice/cruved_form/module/(int:id_module)/role/(int:id_role)  
  POST /permissions_backoffice/filter_form/id_filter_type/(int:id_filter_type)/id_filter/(int:id_filter)  
  POST /permissions_backoffice/filter_form/id_filter_type/(int:id_filter_type)  
  GET /permissions_backoffice/filter_form/id_filter_type/(int:id_filter_type)/id_filter/(int:id_filter)  
  GET /permissions_backoffice/filter_form/id_filter_type/(int:id_filter_type)  
  GET /permissions_backoffice/filter_list/id_filter_type/(int:id_filter_type)  
  GET /permissions_backoffice/user_other_permissions/(id_role)  
  GET /permissions_backoffice/user_cruved/(id_role)  
  POST /permissions_backoffice/filter/(id_filter)  

Documentation des routes

GET /gn_commons/list/parameters

Get all parameters from gn_commons.t_parameters

GET /habref/habitats/autocomplete

Get all habref items of a list for autocomplete

Query Parameters:
 
  • int (limit) – the id of the habref list
  • str (search_name) – the pattern to filter with
  • int – filter by typology
  • int – number of results, default = 20
Returns:

Array<AutoCompleteHabitat>

POST /occtax/only/releve

Post one Occtax data (Releve + Occurrence + Counting)

Request JSON object:

{
"geometry":
    {"type":"Point",
    "coordinates":[0.9008789062500001,47.14489748555398]},
    "properties":
        {
        "id_releve_occtax":null,"id_dataset":1,"id_digitiser":1,"date_min":"2019-05-09","date_max":"2019-05-09","hour_min":null,"hour_max":null,"altitude_min":null,"altitude_max":null,"meta_device_entry":"web","comment":null,"id_nomenclature_obs_technique":316,"observers":[1],"observers_txt":null,"id_nomenclature_grp_typ":132,
        "t_occurrences_occtax":[{
            "id_releve_occtax":null,"id_occurrence_occtax":null,"id_nomenclature_obs_technique":41,"id_nomenclature_bio_condition":157,"id_nomenclature_bio_status":29,"id_nomenclature_naturalness":160,"id_nomenclature_exist_proof":81,"id_nomenclature_observation_status":88,"id_nomenclature_blurring":175,"id_nomenclature_source_status":75,"determiner":null,"id_nomenclature_determination_method":445,"cd_nom":67111,"nom_cite":"Ablette =  <i> Alburnus alburnus (Linnaeus, 1758)</i> - [ES - 67111]","meta_v_taxref":null,"sample_number_proof":null,"comment":null,
        "cor_counting_occtax":[{
            "id_counting_occtax":null,"id_nomenclature_life_stage":1,"id_nomenclature_sex":171,"id_nomenclature_obj_count":146,"id_nomenclature_type_count":94,"id_occurrence_occtax":null,"count_min":1,"count_max":1
            }]
        }]
    }
}
Returns:GeoJson<TRelevesOccurrence>
PUT /users/password/change

Modifie le mot de passe de l’utilisateur connecté et de son ancien mdp Fait appel à l’API UsersHub

PUT /users/password/new

Modifie le mdp d’un utilisateur apres que celui-ci ai demander un renouvelement Necessite un token envoyer par mail a l’utilisateur

POST /users/login/recovery

Call UsersHub API to create a TOKEN for a user A post_action send an email with the user login and a link to reset its password Work only if ‘ENABLE_SIGN_UP’ is set to True

GET /pypn/register/test_uh

route pour tester le décorateur connect_admin ainsi que les paramètres de connexion à USERSHUB:

  • config[‘ADMIN_APPLICATION_LOGIN’]
  • config[‘ADMIN_APPLICATION_PASSWORD’]
GET /permissions_backoffice/users

Render a list with all users with their number of cruved Link to edit cruved and other permissions Only display user which have profil in GeoNature and active user

GET /nomenclatures/nomenclatures

Route : liste des termes d’un ensemble de nomenclatures Possibilité de filtrer par regne et group2Inpn

GET /gn_monitoring/siteslist

Return the sites list for an application in a dict {id_base_site, nom site} .. :quickref: Monitoring;

Parameters:
  • id_site – id of base site
  • type – int
GET /permissions/logout_cruved

Route to logout with cruved

To avoid multiples server call, we store the cruved in the session when the user logout we need clear the session to get the new cruved session

GET /permissions/cruved

Get the cruved for a user

Params: :param user: the user who ask the route, auto kwargs via @check_cruved_scope :type user: User :param module_code: the code of the requested module - as querystring :type module_code: str

Returns:dict of the CRUVED
GET /gn_commons/t_mobile_apps

Get all mobile applications

Query Parameters:
 
  • app_code (str) – the app code
Returns:

Array<dict<TMobileApps>>

GET /gn_commons/modules

Return the allowed modules of user from its cruved .. :quickref: Commons;

PUT /gn_commons/media/(int: id_media)
PUT /gn_commons/media

Insertion ou mise à jour d’un média avec prise en compte des fichiers joints

POST /gn_commons/media/(int: id_media)
POST /gn_commons/media

Insertion ou mise à jour d’un média avec prise en compte des fichiers joints

GET /synthese/defaultsNomenclatures

Get default nomenclatures

Query Parameters:
 
  • group2_inpn (str) –
  • regne (str) –
  • organism (int) –
POST /synthese/export_observations

Optimized route for observations web export.

This view is customisable by the administrator Some columns are mandatory: id_synthese, geojson and geojson_local to generate the exported files

POST parameters: Use a list of id_synthese (in POST parameters) to filter the v_synthese_for_export_view

Query Parameters:
 
  • export_format (str) – str<’csv’, ‘geojson’, ‘shapefiles’>
GET /synthese/taxons_autocomplete

Autocomplete taxon for web search (based on all taxon in Synthese).

The request use trigram algorithm to get relevent results

Query Parameters:
 
  • search_name (str) – the search name (use sql ilike statement and puts “%” for spaces)
  • regne (str) – filter with kingdom

:query str group2_inpn : filter with INPN group 2

GET /synthese/observation_count

Get observations found in a given dataset

GET /synthese/taxa_distribution

Get taxa distribution for a given dataset or acquisition framework and grouped by a certain taxa rank

POST /synthese/export_metadata

Route to export the metadata in CSV

The table synthese is join with gn_synthese.v_metadata_for_export The column jdd_id is mandatory in the view gn_synthese.v_metadata_for_export

POST parameters: Use a list of id_synthese (in POST parameters) to filter the v_synthese_for_export_view

GET /synthese/export_metadata

Route to export the metadata in CSV

The table synthese is join with gn_synthese.v_metadata_for_export The column jdd_id is mandatory in the view gn_synthese.v_metadata_for_export

POST parameters: Use a list of id_synthese (in POST parameters) to filter the v_synthese_for_export_view

POST /synthese/export_statuts

Route to get all the protection status of a synthese search

Get the CRUVED from ‘R’ action because we don’t give observations X/Y but only statuts and to be constistant with the data displayed in the web interface

Parameters:
  • HTTP-GET: the same that the /synthese endpoint (all the filter in web app)
POST /synthese/export_taxons

Optimized route for taxon web export.

This view is customisable by the administrator Some columns are mandatory: cd_ref

POST parameters: Use a list of cd_ref (in POST parameters)
to filter the v_synthese_taxon_for_export_view
Query Parameters:
 
  • export_format (str) – str<’csv’>
GET /synthese/general_stats

Return stats about synthese.

GET /synthese/taxons_tree

Get taxon tree.

GET /synthese/color_taxon

Get color of taxon in areas (table synthese.cor_area_taxon).

Query Parameters:
 
  • code_area_type (str) – Type area code (ref_geo.bib_areas_types.type_code)
  • id_area (int) – Id of area (ref_geo.l_areas.id_area)
  • cd_nom (int) – taxon code (taxonomie.taxref.cd_nom)

Those three parameters can be multiples :returns: Array<dict<VColorAreaTaxon>>

GET /synthese/taxa_count

Get taxa count in synthese filtering with generic parameters

Query Parameters:
 
  • id_dataset (int) – filter by id_dataset
Returns int:

the number of taxa found

POST /synthese/for_web

Optimized route to serve data for the frontend with all filters.

Query filtered by any filter, returning all the fields of the view v_synthese_for_export:

properties = {
    "id": r["id_synthese"],
    "date_min": str(r["date_min"]),
    "cd_nom": r["cd_nom"],
    "nom_vern_or_lb_nom": r["nom_vern"] if r["nom_vern"] else r["lb_nom"],
    "lb_nom": r["lb_nom"],
    "dataset_name": r["dataset_name"],
    "observers": r["observers"],
    "url_source": r["url_source"],
    "unique_id_sinp": r["unique_id_sinp"],
    "entity_source_pk_value": r["entity_source_pk_value"],
}
geojson = ast.literal_eval(r["st_asgeojson"])
geojson["properties"] = properties
Parameters:
  • info_role (str) – Role used to get the associated filters, TBC
Query Parameters:
 
  • limit (str) – Limit number of synthese returned. Defaults to NB_MAX_OBS_MAP.
  • cd_ref (str) – Filter by TAXREF cd_ref attribute
  • taxonomy_group2_inpn (str) – Filter by TAXREF group2_inpn attribute
  • taxonomy_id_hab (str) – Filter by TAXREF id_habitat attribute
  • taxonomy_lr (str) – Filter by TAXREF cd_ref attribute
  • taxhub_attribut* (str) – Generig TAXREF filter, given attribute & value
  • observers (str) – Filter on observer
  • id_organism (str) – Filter on organism
  • date_min (str) – Start date
  • date_max (str) – End date
  • id_acquisition_framework (str) – tbd
  • geoIntersection (str) – Intersect with the geom send from the map
  • period_start (str) – tbd
  • period_end (str) – tbd
  • area* (str) – Generic filter on area
  • * (str) – Generic filter, given by colname & value
Response JSON Array of Objects:
 
  • data (array) – Array of synthese with geojson key, see above
  • nb_total (int) – Number of observations
  • nb_obs_limited (bool) – Is number of observations capped
GET /synthese/for_web

Optimized route to serve data for the frontend with all filters.

Query filtered by any filter, returning all the fields of the view v_synthese_for_export:

properties = {
    "id": r["id_synthese"],
    "date_min": str(r["date_min"]),
    "cd_nom": r["cd_nom"],
    "nom_vern_or_lb_nom": r["nom_vern"] if r["nom_vern"] else r["lb_nom"],
    "lb_nom": r["lb_nom"],
    "dataset_name": r["dataset_name"],
    "observers": r["observers"],
    "url_source": r["url_source"],
    "unique_id_sinp": r["unique_id_sinp"],
    "entity_source_pk_value": r["entity_source_pk_value"],
}
geojson = ast.literal_eval(r["st_asgeojson"])
geojson["properties"] = properties
Parameters:
  • info_role (str) – Role used to get the associated filters, TBC
Query Parameters:
 
  • limit (str) – Limit number of synthese returned. Defaults to NB_MAX_OBS_MAP.
  • cd_ref (str) – Filter by TAXREF cd_ref attribute
  • taxonomy_group2_inpn (str) – Filter by TAXREF group2_inpn attribute
  • taxonomy_id_hab (str) – Filter by TAXREF id_habitat attribute
  • taxonomy_lr (str) – Filter by TAXREF cd_ref attribute
  • taxhub_attribut* (str) – Generig TAXREF filter, given attribute & value
  • observers (str) – Filter on observer
  • id_organism (str) – Filter on organism
  • date_min (str) – Start date
  • date_max (str) – End date
  • id_acquisition_framework (str) – tbd
  • geoIntersection (str) – Intersect with the geom send from the map
  • period_start (str) – tbd
  • period_end (str) – tbd
  • area* (str) – Generic filter on area
  • * (str) – Generic filter, given by colname & value
Response JSON Array of Objects:
 
  • data (array) – Array of synthese with geojson key, see above
  • nb_total (int) – Number of observations
  • nb_obs_limited (bool) – Is number of observations capped
GET /synthese/sources

Get all sources.

GET /gn_auth/logout_cruved

Route to logout with cruved To avoid multiples server call, we store the cruved in the session when the user logout we need clear the session to get the new cruved session

POST /gn_auth/login_cas

Login route with the INPN CAS

GET /gn_auth/login_cas

Login route with the INPN CAS

GET /occtax/defaultNomenclatures

Get default nomenclatures define in occtax module

Returns:dict: {‘MODULE_CODE’: ‘ID_NOMENCLATURE’}
GET /occtax/vreleveocctax

Deprecated

GET /occtax/occurrences

Get all Occurrences

Returns:dict<TOccurrencesOccurrence>
GET /import/bibFields

Get all synthese fields Use in field mapping steps

POST /import/mapping

Post a new mapping (value or content)

GET /occtax/releves

Route for map list web interface

POST /occtax/releve

Route utilisée depuis l’appli mobile => depreciée et non utilisée par l’appli web Post one Occtax data (Releve + Occurrence + Counting)

Request JSON object:

{
"geometry":
    {"type":"Point",
    "coordinates":[0.9008789062500001,47.14489748555398]},
    "properties":
        {
        "id_releve_occtax":null,"id_dataset":1,"id_digitiser":1,"date_min":"2019-05-09","date_max":"2019-05-09","hour_min":null,"hour_max":null,"altitude_min":null,"altitude_max":null,"meta_device_entry":"web","comment":null,"id_nomenclature_obs_technique":316,"observers":[1],"observers_txt":null,"id_nomenclature_grp_typ":132,
        "t_occurrences_occtax":[{
            "id_releve_occtax":null,"id_occurrence_occtax":null,"id_nomenclature_obs_technique":41,"id_nomenclature_bio_condition":157,"id_nomenclature_bio_status":29,"id_nomenclature_naturalness":160,"id_nomenclature_exist_proof":81,"id_nomenclature_observation_status":88,"id_nomenclature_blurring":175,"id_nomenclature_source_status":75,"determiner":null,"id_nomenclature_determination_method":445,"cd_nom":67111,"nom_cite":"Ablette =  <i> Alburnus alburnus (Linnaeus, 1758)</i> - [ES - 67111]","meta_v_taxref":null,"sample_number_proof":null,"comment":null,
        "cor_counting_occtax":[{
            "id_counting_occtax":null,"id_nomenclature_life_stage":1,"id_nomenclature_sex":171,"id_nomenclature_obj_count":146,"id_nomenclature_type_count":94,"id_occurrence_occtax":null,"count_min":1,"count_max":1
            }]
        }]
    }
}
Returns:GeoJson<TRelevesOccurrence>
GET /occtax/export

Export data from pr_occtax.v_export_occtax view (parameter)

Query Parameters:
 
  • format (str) – format of the export (‘csv’, ‘geojson’, ‘shapefile’)
GET /habref/typo

Get all typology

Query Parameters:
 
  • id_list (int) – return only the typology of a given id_list
Returns:

Array<TypoRef>

GET /users/organisms_dataset_actor

Get all organisms and the JDD where there are actor and where the current user hase autorization with its cruved

GET /users/confirmation

Validate a account after a demande (this action is triggered by the link in the email) Create a personnal JDD as post_action if the parameter AUTO_DATASET_CREATION is set to True Fait appel à l’API UsersHub

POST /users/inscription

Ajoute un utilisateur à utilisateurs.temp_user à partir de l’interface geonature Fonctionne selon l’autorisation ‘ENABLE_SIGN_UP’ dans la config. Fait appel à l’API UsersHub

GET /users/organisms

Get all organisms

POST /users/cor_role

Insert a user in a group

Parameters:
  • id_role (int) – the id user
  • id_group (int # TODO ajouter test sur les POST de données) – the id group
POST /users/organism

Insert a organism

GET /users/roles

Get all roles

POST /users/role

Insert un role

@TODO : Ne devrait pas être là mais dans UserHub Utilisé dans l’authentification du CAS INPN

PUT /users/role

Modifie le role de l’utilisateur du token en cours

GET /meta/acquisition_frameworks_metadata

Get all AF with cruved filter Use for metadata module. Add the cruved permission for each row

GET /meta/acquisition_frameworks

Get all AF with cruved filter

POST /meta/acquisition_framework

Post a dataset .. :quickref: Metadata;

GET /meta/af_datasets_metadata

Get all AF with their datasets The Cruved in only apply on dataset in order to see all the AF where the user have rights with its dataset Use in maplist Add the CRUVED permission for each row (Dataset and AD)

Parameters:
  • info_role (TRole) – add with kwargs
Returns:

dict{‘data’:list<AF with Datasets>, ‘with_erros’: <boolean>}

POST /meta/upload_canvas

Upload the canvas as a temporary image used while generating the pdf file

GET /meta/datasets

Get datasets list

Parameters:
  • info_role (TRole) – add with kwargs
Query Parameters:
 
  • active (boolean) – filter on active fiel
  • id_acquisition_framework (int) – get only dataset of given AF
Returns:

dict{‘data’:list<TDatasets>, ‘with_erros’: <boolean>}

POST /meta/dataset

Post a dataset

GET /geo/municipalities

Return the municipalities .. :quickref: Ref Geo;

POST /geo/area_size

Return the area size from a given geojson

Returns:An area size (int)
POST /geo/altitude

From a posted geojson get the altitude min/max

POST /geo/areas

From a posted geojson, the route return all the area intersected from l_areas .. :quickref: Ref Geo;

GET /geo/areas

Return the areas of ref_geo.l_areas .. :quickref: Ref Geo;

POST /geo/info

From a posted geojson, the route return the municipalities intersected and the altitude min/max

GET /synthese

Return synthese row(s) filtered by form params. NOT USED ANY MORE FOR PERFORMANCE ISSUES

Deprecated since version 2?.

Use :route: /for_web instead

Params must have same synthese fields names

Parameters:
  • info_role (str) – Role used to get the associated filters
Returns dict[dict, int, bool]:
 

See description above

GET /config

Parse and return configuration files as toml .. :quickref: Generic;

GET /import

return import list

POST /permissions_backoffice/other_permissions_form/id_permission/(int: id_permission)/user/(int: id_role)/filter_type/(int: id_filter_type)
POST /permissions_backoffice/other_permissions_form/user/(int: id_role)/filter_type/(int: id_filter_type)

Form to define permisisons for a user expect SCOPE permissions .. :quickref: View_Permission;

GET /permissions_backoffice/other_permissions_form/id_permission/(int: id_permission)/user/(int: id_role)/filter_type/(int: id_filter_type)
GET /permissions_backoffice/other_permissions_form/user/(int: id_role)/filter_type/(int: id_filter_type)

Form to define permisisons for a user expect SCOPE permissions .. :quickref: View_Permission;

POST /permissions_backoffice/cruved_form/module/(int: id_module)/role/(int: id_role)/object/(int: id_object)
POST /permissions_backoffice/cruved_form/module/(int: id_module)/role/(int: id_role)
GET /permissions_backoffice/cruved_form/module/(int: id_module)/role/(int: id_role)/object/(int: id_object)
GET /permissions_backoffice/cruved_form/module/(int: id_module)/role/(int: id_role)
POST /permissions_backoffice/filter_form/id_filter_type/(int: id_filter_type)/id_filter/(int: id_filter)
POST /permissions_backoffice/filter_form/id_filter_type/(int: id_filter_type)
GET /permissions_backoffice/filter_form/id_filter_type/(int: id_filter_type)/id_filter/(int: id_filter)
GET /permissions_backoffice/filter_form/id_filter_type/(int: id_filter_type)
POST /import/data_checker/(import_id)/field_mapping/(int: id_field_mapping)/content_mapping/(int: id_content_mapping)

Check and transform the data for field and content mapping

GET /import/data_checker/(import_id)/field_mapping/(int: id_field_mapping)/content_mapping/(int: id_content_mapping)

Check and transform the data for field and content mapping

GET /permissions_backoffice/filter_list/id_filter_type/(int: id_filter_type)
GET /gn_commons/media/thumbnails/(int: id_media)/(int: size)

Retourne le thumbnail d’un media .. :quickref: Commons;

POST /import/getNomencInfo/(int: id_import)/field_mapping/(int: id_field_mapping)

Get all nomenclature info for a mapping Use for the value mapping step

GET /import/getNomencInfo/(int: id_import)/field_mapping/(int: id_field_mapping)

Get all nomenclature info for a mapping Use for the value mapping step

DELETE /occtax/releve/occurrence_counting/(int: id_count)

Delete one counting

Params int id_count:
 ID of the counting to delete
POST /occtax/releve/(int: id_releve)/occurrence

Post one Occurrence data (Occurrence + Counting) for add to Releve

POST /occtax/only/releve/(int: id_releve)

Post one Occurrence data (Occurrence + Counting) for add to Releve

GET /meta/acquisition_frameworks/export_pdf/(id_acquisition_framework)

Get a PDF export of one acquisition

POST /pypn/register/post_usershub/(string: type_action)

route generique pour appeler les routes UsersHub en tant qu’administrateur de l’appli en cours ex : post_usershub/test_connexion appelle la route URL_USERSHUB/api_register/test_connexion

GET /meta/dataset/export_pdf/(id_dataset)

Get a PDF export of one dataset

GET /permissions_backoffice/user_other_permissions/(id_role)

Get all the permissions define for a user expect SCOPE permissions

GET /permissions_backoffice/user_cruved/(id_role)

Get all scope CRUVED (with heritage) for a user in all modules

POST /permissions_backoffice/filter/(id_filter)
GET /nomenclatures/nomenclature/(int: id_type)
=> Déprécié pour des raisons de volatilité des identifiants en BD

Route : liste des termes d’une nomenclature basées sur les identifiants de nomenclature Possibilité de filtrer par regne et group2Inpn

GET /nomenclatures/nomenclature/(string: code_type)

Route : liste des termes d’une nomenclature basées sur le code mnemonique du type de nomenclature Possibilité de filtrer par regne et group2Inpn

GET /gn_monitoring/siteslist/(int: id_site)

Get minimal information for a site {id_base_site, nom site} .. :quickref: Monitoring;

Parameters:
  • id_site – id of base site
  • type – int
GET /gn_monitoring/siteareas/(int: id_site)

Get areas of a site from cor_site_area as geojson

Parameters:
  • id_module (int) – int
  • id_area_type (int) –
GET /gn_commons/medias/(string: uuid_attached_row)

Retourne des medias .. :quickref: Commons;

GET /gn_commons/media/(int: id_media)

Retourne un media .. :quickref: Commons;

DELETE /gn_commons/media/(int: id_media)

Suppression d’un media

GET /synthese/vsynthese/(id_synthese)

Get one synthese record for web app with all decoded nomenclature

It returns a dict composed of the following:

'data' dict: Array of dict (with geojson key)
'nb_total' int: Number of observations
'nb_obs_limited' bool: Is number of observations capped

:param int id_synthese:Synthese to be queried :>jsonarr array synthese_as_dict: One synthese with geojson key, see above

POST /import/create_or_update_field_mapping/(int: id_mapping)

Create or update a field_mapping

POST /import/update_content_mapping/(int: id_mapping)

Update a content mapping (table TMappingsValues)

GET /import/update_content_mapping/(int: id_mapping)

Update a content mapping (table TMappingsValues)

GET /import/content_mappings/(id_mapping)

load source and target contents from an id_mapping

GET /habref/correspondance/(int: cd_hab)

Get all correspondances in other typo from a cd_hab

Params cd_hab:a cd_hab
GET /import/columns_import/(int: id_import)

Return all the columns of the file of an import

GET /import/field_mappings/(id_mapping)

load source and target fields from an id_mapping

POST /occtax/occurrence/(int: id_occurrence)

Post one Occurrence data (Occurrence + Counting) for add to Releve

DELETE /occtax/occurrence/(int: id_occ)

Delete one occurrence and associated counting

Params int id_occ:
 ID of the occurrence to delete
POST /import/importData/(import_id)

Run import data in synthese The route must return an import object with its mapping (use in frontend)

GET /import/importData/(import_id)

Run import data in synthese The route must return an import object with its mapping (use in frontend)

POST /import/get_errors/(import_id)

Export invalid data in CSV

GET /import/get_errors/(import_id)

Export invalid data in CSV

GET /occtax/counting/(int: id_counting)

Get one counting record, with its id_counting

Parameters:
  • id_counting (int) – the pr_occtax.cor_counting_occtax PK
Returns:

a dict representing a counting record

Rtype:

dict<CorCountingOccurrence>

GET /import/mappings/(mapping_type)

Load mapping names in frontend (select)

GET /habref/habitat/(int: cd_hab)

Get one habitat with its correspondances

Params cd_hab:a cd_hab
DELETE /import/mapping/(int: id_mapping)

Delete a mappping In order to delete temporary mapping (which are automaticaly created) we don’t check ‘Delete’ rights on ‘mapping’ object. Any user which is user of a mapping can delete it with this route

GET /habref/search/(field)/(ilike)

Get the first 20 result of Habref table for a given field with an ilike query Use trigram algo to add relevance

Params field:

a Habref column

Parameters:
  • ilike – the ilike where expression to filter

:type ilike:str

Returns:Array of dict
GET /occtax/releve/(int: id_releve)

Get one releve

Parameters:
  • id_releve (int) – the id releve from pr_occtax.t_releve_occtax
Returns:

Return a releve with its attached Cruved

Rtype:

dict{‘releve’:<TRelevesOccurrence>, ‘cruved’: Cruved}

DELETE /occtax/releve/(int: id_releve)

Delete one releve and its associated occurrences and counting

Params int id_releve:
 ID of the releve to delete
GET /users/menu_from_code/(string: code_liste)

Retourne la liste des roles associés à une liste (identifiée par son code)

Parameters:
  • code_liste (string) – the code of user list (utilisateurs.t_lists)
Query Parameters:
 
  • nom_complet (str) – begenning of complet name of the role
GET /users/menu/(int: id_menu)

Retourne la liste des roles associés à un menu

Parameters:
  • id_menu (int) – the id of user list (utilisateurs.bib_list)
Query Parameters:
 
  • nom_complet (str) – begenning of complet name of the role
GET /users/role/(int: id_role)

Get role detail

Parameters:
  • id_role (int) – the id user
GET /meta/acquisition_framework_details/(id_acquisition_framework)

Get one AF

Parameters:
  • id_acquisition_framework – the id_acquisition_framework
  • type – int
POST /meta/aquisition_framework_mtd/(uuid_af)

Post an acquisition framwork from MTD web service in XML .. :quickref: Metadata;

GET /meta/acquisition_framework/(id_acquisition_framework)

Get one AF

Parameters:
  • id_acquisition_framework – the id_acquisition_framework
  • type – int
GET /meta/dataset_details/(id_dataset)

Get one dataset with nomenclatures and af

Parameters:
  • id_dataset – the id_dataset
  • type – int
Returns:

dict<TDatasetDetails>

POST /meta/dataset_mtd/(id_user)/(id_organism)
POST /meta/dataset_mtd/(id_user)

Post a jdd from the mtd XML .. :quickref: Metadata;

GET /meta/dataset/(id_dataset)

Get one dataset

Parameters:
  • id_dataset – the id_dataset
  • type – int
Returns:

dict<TDataset>

GET /genericview/(view_schema)/(view_name)

Service générique permettant de requeter une vue .. :quickref: Generic;

limit : nombre limit de résultats à retourner offset : numéro de page geometry_field : nom de la colonne contenant la géométrie

Si elle est spécifiée les données seront retournés en geojson
FILTRES :
nom_col=val: Si nom_col fait partie des colonnes
de la vue alors filtre nom_col=val
ilikenom_col=val: Si nom_col fait partie des colonnes
de la vue et que la colonne est de type texte alors filtre nom_col ilike ‘%val%’
filter_d_up_nom_col=val: Si nom_col fait partie des colonnes
de la vue et que la colonne est de type date alors filtre nom_col >= val
filter_d_lo_nom_col=val: Si nom_col fait partie des colonnes
de la vue et que la colonne est de type date alors filtre nom_col <= val
filter_d_eq_nom_col=val: Si nom_col fait partie des colonnes
de la vue et que la colonne est de type date alors filtre nom_col == val
filter_n_up_nom_col=val: Si nom_col fait partie des colonnes
de la vue et que la colonne est de type numérique alors filtre nom_col >= val
filter_n_lo_nom_col=val: Si nom_col fait partie des colonnes
de la vue et que la colonne est de type numérique alors filtre nom_col <= val
ORDONNANCEMENT :
orderby: char
Nom du champ sur lequel baser l’ordonnancement
order: char (asc|desc)
Sens de l’ordonnancement

json {

‘total’: Nombre total de résultat, ‘total_filtered’: Nombre total de résultat après filtration, ‘page’: Numéro de la page retournée, ‘limit’: Nombre de résultats, ‘items’: données au format Json ou GeoJson

}

order by : @TODO

Release

Pour sortir une nouvelle version de GeoNature :

  • Faites les éventuelles Releases des dépendances (UsersHub, TaxHub, UsersHub-authentification-module, Nomenclature-api-module, GeoNature-atlas)
  • Mettez à jour la version de GeoNature et éventuellement des dépendances dans install/install_all/install_all.ini, config/settings.ini.sample, backend/requirements.txt
  • Complétez le fichier docs/CHANGELOG.rst (en comparant les branches https://github.com/PnX-SI/GeoNature/compare/develop) et dater la version à sortir
  • Mettez à jour le fichier VERSION
  • Remplissez le tableau de compatibilité des dépendances (docs/versions-compatibility.rst)
  • Mergez la branche develop dans la branche master
  • Faites la release (https://github.com/PnX-SI/GeoNature/releases) en la taguant X.Y.Z (sans v devant) et en copiant le contenu du Changelog
  • Dans la branche develop, modifiez le fichier VERSION en X.Y.Z.dev0 et pareil dans le fichier docs/CHANGELOG.rst

BDD

Mettre à jour le ref_geo à partir des données IGN scan express :

  • Télécharger le dernier millesime : http://professionnels.ign.fr/adminexpress
  • Intégrer le fichier Shape dans la BDD grâce à QGIS dans une table nommée ref_geo.temp_fr_municipalities
  • Générer le SQL de création de la table : pg_dump --table=ref_geo.temp_fr_municipalities --column-inserts -U <MON_USER> -h <MON_HOST> -d <MA_BASE> > fr_municipalities.sql. Le fichier en sortie doit s’appeler fr_municipalities.sql
  • Zipper le fichier SQL et le mettre sur le serveur http://geonature.fr/data
  • Adapter le script install_db.sh pour récupérer le nouveau fichier zippé

Pratiques et règles de developpement

Afin de partager des règles communes de développement et faciliter l’intégration de nouveau code, veuillez lire les recommandations et bonnes pratiques recommandées pour contribuer au projet GeoNature.

Git

  • Ne jamais faire de commit dans la branche master mais dans la branche develop ou idéalement dans une branche dédiée à la fonctionnalité (feature branch)
  • Faire des pull request vers la branche develop
  • Faire des git pull avant chaque développement et avant chaque commit
  • Les messages de commits font référence à un ticket ou le ferment (ref #12 ou fixes #23)
  • Les messages des commits sont en anglais (dans la mesure du possible)

Backend

"python.formatting.blackArgs": [
  "--line-length",
  "100"
]
  • Utiliser des doubles quotes pour les chaines de charactères.

BDD

  • Le noms des tables est préfixé par un “t” pour une table de contenu, de “bib” pour les tables de “dictionnaires” et de “cor” pour les tables de correspondance
  • Les schémas du coeur de GeoNature sont préfixés de “gn”
  • Les schémas des protocoles ou modules GeoNature sont préfixés de “pr”
  • Chaque schéma de BDD dispose de son propre fichier SQL
  • Les scripts SQL sont ordonnés en section dans l’ordre suivant : (voir https://github.com/PnX-SI/GeoNature/blob/master/data/core/synthese.sql)
    • Fonctions
    • Tables
    • Clés primaires
    • Clés étrangères
    • Contraintes
    • Triggers
    • Données nécessaires au fonctionnement du schéma
  • Les scripts de données sont écrits dans des fichiers à part
  • Ne rien écrire dans le schéma public
  • Ne pas répeter le nom des tables dans les noms des colonnes (exception faite des colonnes “id)

Typescript

  • Documenter les fonctions et classes grâce au JSDoc en français (https://jsdoc.app/)
  • Les commentaires dans le codes doivent être en anglais (ne pas s’empecher de mettre un commentaire en français sur une partie du code complexe !)
  • Les messages renvoyés aux utilisateurs sont en français
  • Installer les outils de devéloppement: npm install –only=dev
  • Utiliser prettier comme formateur de texte et activer l’autoformatage dans son éditeur de texte (VsCode dispose d’une extension Prettier : https://github.com/prettier/prettier-vscode)
  • Utiliser tslint comme linter
  • La longueur maximale pour une ligne de code est 100 caractères.

Angular

  • Suivre les recommandations définies par le styleguide Angular: https://angular.io/guide/styleguide. C’est une ressources très fournie en cas de question sur les pratiques de développement (principe de séparation des principes, organisation des services et des composants)
  • On privilegira l’utilisation des reactive forms pour la construction des formulaires (https://angular.io/guide/reactive-forms). Ce sont des formulaires piloté par le code, ce qui facilite la lisibilité et le contrôle de ceux-ci.
  • Pour l’ensemble des composants cartographiques et des formulaires (taxonomie, nomenclatures…), il est conseillé d’utiliser les composants présents dans le module ‘GN2CommonModule’.

HTML

  • La longueur maximale pour une ligne de code est 100 caractères.
  • Lorsqu’il y a plus d’un attribut sur une balise, revenir à la ligne et aligner les attributs :
<button
  mat-raised-button
  color="primary"
  class="btn-action hard-shadow uppercase ml-3"
  data-toggle="collapse"
  data-target="#collapseAvance"
>
  Filtrer
</button>
  • VsCode fournit un formatteur de HTML par défaut (Dans les options de VsCode, tapez “wrap attributes” et sélectionner “force-expand-multiline”)

Style et ergonomie

  • Boutons : On utilise les boutons d’Angular materials (https://material.angular.io/components/button/overview).
    • mat-raised-button pour les boutons contenant du texte
    • mat-fab ou mat-mini-fab pour les boutons d’actions avec seulement une icone
  • Couleur des boutons :
    • Action : primary
    • Validation: vert (n’existant pas dans material: utiliser la classe button-success)
    • Suppression: warn
    • Navigation: basic
  • Librairie d’icones :
  • Formulaire :
  • Système de grille et responsive :
    • Utiliser le système de grille de bootstrap pour assurer le responsive design sur l’application. On ne vise pas l’utilisation sur mobile, mais à minima sur ordinateur portable de petite taille.

Développer et installer un gn_module

GeoNature a été conçu pour fonctionner en briques modulaires.

Chaque protocole, répondant à une question scientifique, est amené à avoir son propre module GeoNature comportant son modèle de base de données (dans un schéma séparé), son API et son interface utilisateur.

Les modules développés s’appuieront sur le coeur de GeoNature qui est constitué d’un ensemble de briques réutilisables.

En base de données, le coeur de GeoNature est constitué de l’ensemble des référentiels (utilisateurs, taxonomique, nomenclatures géographique) et du schéma synthese regroupant l’ensemble données saisies dans les différents protocoles (voir doc administrateur pour plus de détail sur le modèle de données).

L’API du coeur permet d’interroger les schémas de la base de données “coeur” de GeoNature. Une documentation complète de l’API est disponible dans la rubrique ‘Documentation API Backend’_.

Du côté interface utilisateur, GeoNature met à disposition un ensemble de composants Angular réutilisables (http://pnx-si.github.io/GeoNature/frontend/modules/GN2CommonModule.html), pour l’affichage des cartes, des formulaires etc…

Développer un gn_module

Avant de développer un gn_module, assurez-vous d’avoir GeoNature bien installé sur votre machine (voir doc).

Afin de pouvoir connecter ce module au “coeur”, il est impératif de suivre une arborescence prédéfinie par l’équipe GeoNature. Un template GitHub a été prévu à cet effet (https://github.com/PnX-SI/gn_module_template). Il est possible de créer un nouveau dépôt GitHub à partir de ce template, ou alors de copier/coller le contenu du dépôt dans un nouveau.

Cette arborescence implique de développer le module dans les technologies du coeur de GeoNature à savoir :

  • Le backend est développé en Python grâce au framework Flask.
  • Le frontend est développé grâce au framework Angular (voir la version actuelle du coeur)

GeoNature prévoit cependant l’intégration de module “externe” dont le frontend serait développé dans d’autres technologies. La gestion de l’intégration du module est à la charge du développeur.

  • Le module se placera dans un dossier à part du dossier “GeoNature” et portera le suffixe “gn_module”. Exemple : gn_module_validation
  • La racine du module comportera les fichiers suivants :
    • install_app.sh : script bash d’installation des librairies python ou npm necessaires au module
    • install_env.sh : script bash d’installation des paquets Linux
    • requirements.txt : liste des librairies python necessaires au module
    • manifest.toml : fichier de description du module (nom, version du module, version de GeoNature compatible)
    • conf_gn_module.toml : fichier de configuration de l’application (livré en version sample)
    • conf_schema_toml.py : schéma ‘marshmallow’ (https://marshmallow.readthedocs.io/en/latest/) du fichier de configuration (permet de s’assurer la conformité des paramètres renseignés par l’utilisateur). Ce fichier doit contenir une classe GnModuleSchemaConf dans laquelle toutes les configurations sont synchronisées.
    • install_gn_module.py : script python lançant les commandes relatives à ‘installation du module (Base de données, …). Ce fichier doit comprendre une fonction gnmodule_install_app(gn_db, gn_app) qui est utilisée pour installer le module (Voir l’exemple du module CMR)
  • La racine du module comportera les dossiers suivants :
    • backend : dossier comportant l’API du module utilisant un blueprint Flask
    • Le fichier blueprint.py comprend les routes du module (ou instancie les nouveaux blueprints du module)
    • Le fichier models.py comprend les modèles SQLAlchemy des tables du module.
    • frontend : le dossier app comprend les fichiers typescript du module, et le dossier assets l’ensemble des médias (images, son).
      • Le dossier app doit comprendre le “module Angular racine”, celui-ci doit impérativement s’appeler gnModule.module.ts
      • Le dossier app doit contenir un fichier module.config.ts. Ce fichier est automatiquement synchronisé avec le fichier de configuration du module <GEONATURE_DIRECTORY>/external_modules/<nom_module>/conf_gn_module.toml` grâce à la commande geonature update_module_configuration <nom_module>. C’est à partir de ce fichier que toutes les configuration doivent pointer.
      • A la racine du dossier frontend, on retrouve également un fichier package.json qui décrit l’ensemble des librairies JS necessaires au module.
    • data : ce dossier comprenant les scripts SQL d’installation du module

Le module est ensuite installable à la manière d’un plugin grâce à la commande geonature install_gn_module de la manière suivante :

# se placer dans le répertoire backend de GeoNature
cd <GEONATURE_DIRECTORY>/backend
# activer le virtualenv python
source venv/bin/activate
# lancer la commande d'installation
geonature install_gn_module <CHEMIN_ABSOLU_DU_MODULE> <URL_API>
# example geonature install_gn_module /home/moi/gn_module_validation /validation

Bonnes pratiques Frontend

  • Pour l’ensemble des composants cartographiques et des formulaires (taxonomie, nomenclatures…), il est conseillé d’utiliser les composants présents dans le module ‘GN2CommonModule’.

    Importez ce module dans le module racine de la manière suivante

    import { GN2CommonModule } from '@geonature_common/GN2Common.module';
    
  • Les librairies JS seront installées dans le dossier node_modules de GeoNature. (Il n’est pas nécessaire de réinstaller toutes les librairies déjà présentes dans GeoNature (Angular, Leaflet, ChartJS …). Le package.json de GeoNature liste l’ensemble des librairies déjà installées et réutilisable dans le module.

  • Les fichiers d’assets sont à ranger dans le dossier assets du frontend. Angular-cli impose cependant que tous les assets soient dans le répertoire mère de l’application (celui de GeoNature). Un lien symbolique est créé à l’installation du module pour faire entre le dossier d’assets du module et celui de Geonature.

  • Utiliser node_modules présent dans GeoNature

    Pour utiliser des librairies déjà installées dans GeoNature, utilisez la syntaxe suivante

    import { TreeModule } from "@librairies/angular-tree-component";
    

    L’alias @librairies pointe en effet vers le repertoire des node_modules de GeoNature

    Pour les utiliser à l’interieur du module, utiliser la syntaxe suivante

    <img src="external_assets/<MY_MODULE_CODE>/afb.png">
    

    Exemple pour le module de validation

    <img src="external_assets/<gn_module_validation>/afb.png">
    

Installer un gn_module

Renseignez l’éventuel fichier config/settings.ini du module.

Pour installer un module, rendez vous dans le dossier backend de GeoNature.

Activer ensuite le virtualenv pour rendre disponible les commandes GeoNature

source venv/bin/activate

Lancez ensuite la commande

geonature install_gn_module <mon_chemin_absolu_vers_le_module> <url_api>

Le premier paramètre est l’emplacement absolu du module sur votre machine et le 2ème le chemin derrière lequel on retrouvera les routes de l’API du module.

Exemple pour atteindre les routes du module de validation à l’adresse ‘http://mon-geonature.fr/api/geonature/validation

Cette commande exécute les actions suivantes :

  • Vérification de la conformité de la structure du module (présence des fichiers et dossiers obligatoires)
  • Intégration du blueprint du module dans l’API de GeoNature
  • Vérification de la conformité des paramètres utilisateurs
  • Génération du routing Angular pour le frontend
  • Re-build du frontend pour une mise en production

Complétez l’éventuelle configuration du module (config/conf_gn_module.toml) à partir des paramètres présents dans config/conf_gn_module.toml.example dont vous pouvez surcoucher les valeurs par défaut. Puis relancez la mise à jour de la configuration (depuis le répertoire geonature/backend et une fois dans le venv (source venv/bin/activate) : geonature update_module_configuration nom_du_module)

Développement Backend

Démarrage du serveur de dev backend

(venv)...$ geonature dev_back

Base de données

Session sqlalchemy

  • geonature.utils.env.DB

Fournit l’instance de connexion SQLAlchemy Python

from geonature.utils.env import DB

result = DB.session.query(MyModel).get(1)

Serialisation des modèles

La sérialisation des modèles SQLAlchemy s’appuie sur deux librairies maison externalisée. Voir la doc plus complète: https://github.com/PnX-SI/Utils-Flask-SQLAlchemy

  • utils_flask_sqla.serializers.serializable

    Décorateur pour les modèles SQLA : Ajoute une méthode as_dict qui retourne un dictionnaire des données de l’objet sérialisable json

    Fichier définition modèle :

    from geonature.utils.env import DB
    from utils_flask_sqla.serializers import serializable
    
    @serializable
    class MyModel(DB.Model):
        __tablename__ = 'bla'
        ...
    

    Fichier utilisation modèle

    instance = DB.session.query(MyModel).get(1)
    result = instance.as_dict()
    
  • utils_flask_sqla_geo.serializers.geoserializable

    Décorateur pour les modèles SQLA : Ajoute une méthode as_geofeature qui retourne un dictionnaire serialisable sous forme de Feature geojson.

    Fichier définition modèle

    from geonature.utils.env import DB
    from utils_flask_sqla_geo.serializers import geoserializable
    
    
    @geoserializable
    class MyModel(DB.Model):
        __tablename__ = 'bla'
        ...
    

    Fichier utilisation modèle

    instance = DB.session.query(MyModel).get(1)
    result = instance.as_geofeature()
    
  • utils_flask_sqla_geo.serializers.shapeserializable

    Décorateur pour les modèles SQLA :

    • Ajoute une méthode as_list qui retourne l’objet sous forme de tableau (utilisé pour créer des shapefiles)
    • Ajoute une méthode de classe to_shape qui crée des shapefiles à partir des données passées en paramètre

    Fichier définition modèle

    from geonature.utils.env import DB
    from utils_flask_sqla_geo.serializers import shapeserializable
    
    
    @shapeserializable
    class MyModel(DB.Model):
        __tablename__ = 'bla'
        ...
    

    Fichier utilisation modèle:

    # utilisation de as_shape()
    data = DB.session.query(MyShapeserializableClass).all()
    MyShapeserializableClass.as_shape(
        geom_col='geom_4326',
        srid=4326,
        data=data,
        dir_path=str(ROOT_DIR / 'backend/static/shapefiles'),
        file_name=file_name
    )
    
  • utils_flask_sqla_geo.utilsgeometry.FionaShapeService

    Classe utilitaire pour créer des shapefiles.

    La classe contient 3 méthodes de classe :

  • FionaShapeService.create_shapes_struct() : crée la structure de 3 shapefiles (point, ligne, polygone) à partir des colonens et de la geométrie passée en paramètre

  • FionaShapeService.create_feature() : ajoute un enregistrement aux shapefiles

  • FionaShapeService.save_and_zip_shapefiles() : sauvegarde et zip les shapefiles qui ont au moins un enregistrement:

    data = DB.session.query(MySQLAModel).all()
    
    for d in data:
            FionaShapeService.create_shapes_struct(
                    db_cols=db_cols,
                    srid=current_app.config['LOCAL_SRID'],
                    dir_path=dir_path,
                    file_name=file_name,
                    col_mapping=current_app.config['SYNTHESE']['EXPORT_COLUMNS']
            )
    FionaShapeService.create_feature(row_as_dict, geom)
            FionaShapeService.save_and_zip_shapefiles()
    
  • utils_flask_sqla_geo.serializers.json_resp

    Décorateur pour les routes : les données renvoyées par la route sont automatiquement serialisées en json (ou geojson selon la structure des données).

    S’insère entre le décorateur de route flask et la signature de fonction

    Fichier routes

    from flask import Blueprint
    from utils_flask_sqla.response import json_resp
    
    blueprint = Blueprint(__name__)
    
    @blueprint.route('/myview')
    @json_resp
    def my_view():
        return {'result': 'OK'}
    
    
    @blueprint.route('/myerrview')
    @json_resp
    def my_err_view():
        return {'result': 'Not OK'}, 400
    

Export des données

TODO

Utilisation de la configuration

La configuration globale de l’application est controlée par le fichier config/geonature_config.toml qui contient un nombre limité de paramètres. De nombreux paramètres sont néammoins passés à l’application via un schéma Marshmallow (voir fichier backend/geonature/utils/config_schema.py).

Dans l’application flask, l’ensemble des paramètres de configuration sont utilisables via le dictionnaire config de l’application Flask

from flask import current_app
MY_PARAMETER = current_app.config['MY_PARAMETER']

Chaque module GeoNature dispose de son propre fichier de configuration, (module/config/cong_gn_module.toml) contrôlé de la même manière par un schéma Marshmallow (module/config/conf_schema_toml.py). Pour récupérer la configuration du module dans l’application Flask, il existe deux méthodes:

Dans le fichier blueprint.py

# Methode 1 :

from flask import current_app
MY_MODULE_PARAMETER = current_app.config['MY_MODULE_NAME']['MY_PARAMETER]
# ou MY_MODULE_NAME est le nom du module tel qu'il est défini dans le fichier ``manifest.toml`` et la table ``gn_commons.t_modules``

#Méthode 2 :
MY_MODULE_PARAMETER = blueprint.config['MY_MODULE_PARAMETER']

Il peut-être utile de récupérer l’ID du module GeoNature (notamment pour des questions droits). De la même manière que précédement, à l’interieur d’une route, on peut récupérer l’ID du module de la manière suivante

ID_MODULE = blueprint.config['ID_MODULE']
# ou
ID_MODULE = current_app.config['MODULE_NAME']['ID_MODULE']

Si on souhaite récupérer l’ID du module en dehors du contexte d’une route, il faut utiliser la méthode suivante

from geonature.utils.env import get_id_module
ID_MODULE = get_id_module(current_app, 'occtax')

Authentification avec pypnusershub

Vérification des droits des utilisateurs

  • pypnusershub.routes.check_auth

    Décorateur pour les routes : vérifie les droits de l’utilisateur et le redirige en cas de niveau insuffisant ou d’informations de session erronés (deprecated) Privilegier check_cruved_scope

    params :

    • level <int> : niveau de droits requis pour accéder à la vue
    • get_role <bool:False> : si True, ajoute l’id utilisateur aux kwargs de la vue
    • redirect_on_expiration <str:None> : identifiant de vue sur laquelle rediriger l’utilisateur en cas d’expiration de sa session
    • redirect_on_invalid_token <str:None> : identifiant de vue sur laquelle rediriger l’utilisateur en cas d’informations de session invalides
    from flask import Blueprint
    from pypnusershub.routes import check_auth
    from utils_flask_sqla.response import json_resp
    
    blueprint = Blueprint(__name__)
    
    @blueprint.route('/myview')
    @check_auth(
            1,
            True,
            redirect_on_expiration='my_reconnexion_handler',
            redirect_on_invalid_token='my_affreux_pirate_handler'
            )
    @json_resp
    def my_view(id_role):
            return {'result': 'id_role = {}'.format(id_role)}
    
  • geonature.core.gn_permissions.decorators.check_cruved_scope

    Décorateur pour les routes : Vérifie les droits de l’utilisateur à effectuer une action sur la donnée et le redirige en cas de niveau insuffisant ou d’informations de session erronées

    params :

    • action <str:[‘C’,’R’,’U’,’V’,’E’,’D’]> type d’action effectuée par la route (Create, Read, Update, Validate, Export, Delete)
    • get_role <bool:False>: si True, ajoute l’id utilisateur aux kwargs de la vue
    • module_code: <str:None>: Code du module (gn_commons.t_modules) sur lequel on veut récupérer le CRUVED. Si ce paramètre n’est pas passer on vérifie le cruved de GeoNature
    • redirect_on_expiration <str:None> : identifiant de vue ou URL sur laquelle rediriger l’utilisateur en cas d’expiration de sa session
    • redirect_on_invalid_token <str:None> : identifiant de vue ou URL sur laquelle rediriger l’utilisateur en cas d’informations de session invalides
    from flask import Blueprint
    from geonature.core.gn_permissions.tools import get_or_fetch_user_cruved
    from utils_flask_sqla.response import json_resp
    from geonature.core.gn_permissions import decorators as permissions
    
    blueprint = Blueprint(__name__)
    
    @blueprint.route('/mysensibleview', methods=['GET'])
    @permissions.check_cruved_scope(
            'R',
            True,
            module_code="OCCTAX"
            redirect_on_expiration='my_reconnexion_handler',
            redirect_on_invalid_token='my_affreux_pirate_handler'
    )
    @json_resp
    def my_sensible_view(info_role):
        # Récupérer l'id de l'utilisateur qui demande la route
        id_role = info_role.id_role
        # Récupérer la portée autorisée à l'utilisateur pour l'action 'R' (read)
        read_scope = info_role.value_filter
        #récupérer le CRUVED complet de l'utilisateur courant
        user_cruved = get_or_fetch_user_cruved(
                session=session,
                id_role=info_role.id_role,
                module_code=MY_MODULE_CODE,
        )
        return {'result': 'id_role = {}'.format(info_role.id_role)}
    
  • geonature.core.gn_permissions.tools.cruved_scope_for_user_in_module

    • Fonction qui retourne le CRUVED d’un utilisateur pour un module et/ou un objet donné.
    • Si aucun CRUVED n’est défini pour le module, c’est celui de GeoNature qui est retourné, sinon 0.
    • Le CRUVED du module enfant surcharge toujours celui du module parent.
    • Le CRUVED sur les objets n’est pas hérité du module parent.

    params :

    • id_role <integer:None>
    • module_code <str:None>: code du module sur lequel on veut avoir le CRUVED
    • object_code <str:’ALL’> : code de l’objet sur lequel on veut avoir le CRUVED
    • get_id <boolean: False> : retourne l’id_filter et non le code_filter si True

    Valeur retournée : tuple

    A l’indice 0 du tuple: <dict{str:str}> ou <dict{str:int}>, boolean) {‘C’: ‘1’, ‘R’:’2’, ‘U’: ‘1’, ‘V’:’2’, ‘E’:’3’, ‘D’: ‘3’} ou {‘C’: 2, ‘R’:3, ‘U’: 4, ‘V’:1, ‘E’:2, ‘D’: 2} si get_id=True

    A l’indice 1 du tuple: un booléan spécifiant si le CRUVED est hérité depuis un module parent ou non.

    from pypnusershub.db.tools import cruved_for_user_in_app
    
    # recuperer le cruved de l'utilisateur 1 dans le module OCCTAX
    cruved, herited = cruved_scope_for_user_in_module(
            id_role=1
            module_code='OCCTAX
    )
    # recupérer le cruved de l'utilisateur 1 sur GeoNature
    cruved, herited = cruved_scope_for_user_in_module(id_role=1)
    

Développement Frontend

Bonnes pratiques

  • Chaque gn_module de GeoNature doit être un module Angular indépendant https://angular.io/guide/ngmodule.
  • Ce gn_module peut s’appuyer sur une série de composants génériques intégrés dans le module GN2CommonModule et décrit ci-dessous

Les composants génériques

Un ensemble de composants décrits ci-dessous sont intégrés dans le coeur de GeoNature et permettent aux développeurs de simplifier la mise en place de formulaires ou de bloc cartographiques.

Voir la DOCUMENTATION COMPLETE sur les composants génériques.

NB: mes composants de type “formulaire” (balise input ou select) partagent une logique commune et ont des Inputs et des Outputs communs décrit ci dessous. (voir https://github.com/PnX-SI/GeoNature/blob/develop/frontend/src/app/GN2CommonModule/form/genericForm.component.ts).

Une documentation complète des composants générique est disponible ici

NB: mes composants de type “formulaire” (balise input ou select) partagent une logique commune et ont des Inputs et des Outputs communs décrit ci dessous. (voir https://github.com/PnX-SI/GeoNature/blob/develop/frontend/src/app/GN2CommonModule/form/genericForm.component.ts).

  • Inputs

    • L’input parentFormControl de type FormControl (https://angular.io/api/forms/FormControl) permet de contrôler la logique et les valeurs du formulaire depuis l’extérieur du composant. Cet input est obligatoire pour le fonctionnement du composant.
    • L’input label (string) permet d’afficher un label au dessus de l’input.
    • L’input displayAll (boolean, défaut = false) permet d’ajouter un item ‘tous’ sur les inputs de type select (Exemple : pour sélectionner tous les jeux de données de la liste)
    • L’input multiSelect (boolean, défaut = false) permet de passer les composants de type select en “multiselect” (sélection multiple sur une liste déroulante). Le parentFormControl devient par conséquent un tableau
    • L’input searchBar (boolean, défaut = false) permet de rajouter une barre de recherche sur les composants multiselect
    • L’input disabled (boolean) permet de rendre le composant non-saisissable
    • L’input debounceTime définit une durée en ms après laquelle les évenements onChange et onDelete sont déclenchés suite à un changement d’un formulaire. (Par défault à 0)
  • Outputs

    Plusieurs Output communs à ses composants permettent d’émettre des événements liés aux formulaires.

    • onChange : événement émit à chaque fois qu’un changement est effectué sur le composant. Renvoie la valeur fraiche de l’input.
    • onDelete : événement émit chaque fois que le champ du formulaire est supprimé. Renvoie un évenement vide.

Ces composants peuvent être considérés comme des “dump components” ou “presentation components”, puisque que la logique de contrôle est déporté au composant parent qui l’accueil (https://blog.angular-university.io/angular-2-smart-components-vs-presentation-components-whats-the-difference-when-to-use-each-and-why/)

Un ensemble de composant permattant de simplifier l’affichage des cartographies leaflet sont disponible. Notamment un composant “map-list” permettant de connecter une carte avec une liste d’objet décrit en détail ci dessous.

  • MapListComponent

Le composant MapList fournit une carte pouvant être synchronisé avec une liste. La liste, pouvant être spécifique à chaque module, elle n’est pas intégré dans le composant et est laissé à la responsabilité du développeur. Le service MapListService offre cependant des fonctions permettant facilement de synchroniser les deux éléments.

Fonctionnalité et comportement offert par le composant et le service :

  • Charger les données

Le service expose la fonction getData(apiEndPoint, params?) permettant de charger les données pour la carte et la liste. Cette fonction doit être utilisée dans le composant qui utilise le composant MapListComponent. Elle se charge de faire appel à l’API passé en paramètre et de rendre les données disponibles au service.

Le deuxième paramètre params est un tableau de paramètre(s) (facultatif). Il permet de filtrer les données sur n’importe quelle propriété du GeoJson, et également de gérer la pagination.

Exemple : afficher les 10 premiers relevés du cd_nom 212 :

mapListService.getData('occtax/releve',
[{'param': 'limit', 'value': 10'},
{'param': 'cd_nom', 'value': 212'}])

Exemple dans le module OccTax

L’API doit nécessairement renvoyer un objet comportant un GeoJson. La structure du l’objet doit être la suivante :

'total': nombre d'élément total,
'total_filtered': nombre d'élément filtré,
'page': numéro de page de la liste,
'limit': limite d'élément renvoyé,
'items': le GeoJson

Pour une liste simple sans pagination, seule la propriété ‘items’ est obligatoire.

  • Rafraîchir les données

La fonction refreshData(apiEndPoint, method, params?) permet de raffrachir les données en fonction de filtres personnalisés. Les paramètres apiEndPoint et params sont les mêmes que pour la fonction getData. Le paramètre method permet lui de chosir si on ajoute - append- , ou si on initialise (ou remplace) -set- un filtre.

Exemple 1 : Pour filtrer sur l’observateur 1, puis ajouter un filtre sur l’observateur 2.

mapListService.refreshData('occtax/relevé', 'append, [{'param': 'observers', 'value': 1'}])

puis

refreshData('occtax/relevé', 'append, [{'param': 'observers', 'value': 2'}])

Exemple 2: pour filtrer sur le cd_nom 212, supprimer ce filtre et filtrer sur le cd_nom 214

mapListService.refreshData('occtax/relevé', 'set, [{'param': 'cd_nom', 'value': 1'}])

puis

mapListService.refreshData('occtax/relevé', 'set, [{'param': 'cd_nom', 'value': 2'}])

  • Gestion des évenements :

    • Au clic sur un marker de la carte, le service MapListService expose la propriété selectedRow qui est un tableau contenant l’id du marker sélectionné. Il est ainsi possible de surligner l’élément séléctionné dans le liste.
    • Au clic sur une ligne du tableau, utiliser la fonction MapListService.onRowSelected(id) (id étant l’id utilisé dans le GeoJson) qui permet de zoomer sur le point séléctionner et de changer la couleur de celui-ci.

La service contient également deux propriétés publiques geoJsonData (le geojson renvoyé par l’API) et tableData (le tableau de features du Geojson) qui sont respectivement passées à la carte et à la liste. Ces deux propriétés sont utilisables pour intéragir (ajouter, supprimer) avec les données de la carte et de la liste.

Selector: pnx-map-list

Inputs:

idName:

Libellé de l’id du geojson (id_releve, id)

Type: string

height:

Taille de l’affichage de la carte Leaflet

Type: string

Exemple d’utilisation avec une liste simple :

<pnx-map-list
        idName="id_releve_occtax"
        height="80vh">
</pnx-map-list>
<table>
        <tr ngFor="let row of mapListService.tableData" [ngClass]=" {'selected': mapListService.selectedRow[0]} == row.id ">
                <td (click)="mapListService.onRowSelect(row.id)"> Zoom on map </td>
                <td > {{row.observers}} </td>
                <td > {{row.date}} </td>
        </tr>
</table>

Outils d’aide à la qualité du code

Des outils d’amélioration du code pour les développeurs peuvent être utilisés : flake8, pylint, pytest, coverage.

La documentation peut être générée avec Sphinx.

Les fichiers de configuration de ces outils se trouvent à la racine du projet :

  • .pylint

Un fichier .editorconfig permettant de définir le comportement de votre éditeur de code est également disponible à la racine du projet.

Sphinx

Sphinx est un générateur de documentation.

Pour générer la documentation HTML, se placer dans le répertoire docs et modifier les fichiers .rst:

cd docs
make html

Pylint

Pylint fait la même chose que Flake8 mais il est plus complet, plus configurable mais aussi plus exigeant.

Pour inspecter le répertoire geonature:

cd backend
pylint geonature

tslint

tslint fait la même chose que pylint mais pour la partie frontend en typescript:

cd frontend
ng lint

Pytest

Pytest permet de mettre en place des tests fonctionnels et automatisés du code Python.

Les fichiers de test sont dans le répertoire backend/tests

cd backend
pytest

Coverage

Coverage permet de donner une indication concernant la couverture du code par les tests.

cd backend
pytest --cov=geonature --cov-report=html

Ceci génénère un rapport html disponible dans backend/htmlcov/index.html.