PnX-SI / GeoNature

Application de saisie et de synthèse des observations faune et flore
GNU General Public License v3.0
99 stars 99 forks source link

Synthèse - API post #736

Open camillemonchicourt opened 4 years ago

camillemonchicourt commented 4 years ago

Il est souhaité ajouter la possibilité de poster directement dans la synthèse depuis une application tierce grâce à une API post sécurisée et authentifiée.

gildeluermoz commented 4 years ago

Ceci existait en V1 Il y aura qq sujets à traiter en parrallèle avec des choix à faire comme faut-il créer un enregistrement dans gn_commons.t_modules générique du genre 'import direct depuis l'API'. Idem pour la source et le dataset. En gros ces données seront orphelines et ne seront généralement pas rattachées à des métadonnées; Toutes les intégrités (FK), il y en a beaucoup, devront être soit vérifiées soit utilisées des valeurs par défaut, soit rester à null (dataset, source, module, nomenclatures, observateurs) règles pour l'uuid ? Les comportements retenus pour remplir (ou pas) ces FK doivent-ils être paramétrables pour adapter le fonctionnement de l'API à chacun des contextes.

camillemonchicourt commented 4 years ago

Oui exact. Comme pour tous les autres imports de données externes, il y a différents pré-requis à respecter au niveau des métadonnées notamment.

joelclems commented 4 years ago

Avec amandine on propose une function SQL qui permet d'inserer/actualiser des lignes dans la synthèse à partir d'une vue ou d'une table

voir dc0e3ef

gn_synthese.import_row_from_table(
  select_col_name varchar,
  select_col_val varchar,
  table_name varchar
)

où l'on actualise les lignes de la synthèse correspond aux lignes de la selection de table_name filtrée par col_name = col_val

Si une ligne de la selection est présente dans la synthèse c'est une mise à jour, sinon c'est un ajout.

La fonction python import_from_table permet l'appel de la fonction sql depuis python.

Il reste à faire une fonction pour gérer les suppressions.

Testé avec le module monitoring (où les delete se font en trigger)

camillemonchicourt commented 4 years ago

Version 2.4.0 : Ajout de fonctions SQL d'insertion de données dans la Synthèse (gn_synthese.import_json_row() et gn_synthese.import_row_from_table()) et de la fonction Python associée (import_from_table(schema_name, table_name, field_name, value)) pour l'API permettant de poster dans la Synthèse.

joelclems commented 3 years ago

Je propose une réflexion sur l'api POST synthèse. C'est un peu long...

L'api POST synthèse

L'api synthèse serait conçue pour un import ponctuel et dynamique de données, en création ou modification et pour 1 ligne à la fois.

Le but ici est de donner les moyens de synchroniser les données d'une application tierce avec la synthèse de GéoNature (et de rendre possible l'intégration des données dans la synthèse quand on a pas d'accès à la base de GN en écriture)

Les Prérequis

Il faut satisfaire certains prérequis pour pouvoir envoyer des données depuis une application tierce vers la synthèse.

Module

Utilisateur de l'api POST

Medias ???

UUIDs

JDD

Source

Les données nécessaires pour la synthèse sont:

Traitement des données en backend

Documenter

Exemples d'utilisations

TheoLechemia commented 3 years ago

Salut Joel, Merci pour ce défrichage. Voilà mes retours/propositions:

Module:

Authentification:

Média:

UUID:

JDD:

Source:

Table t_applications:

Nomenclatures Je partirai du principe qu'il faut échanger des code nomenclatures (ceux du SINP). A l'API de GeoNature de faire recoller ses ID internes (fonction ref_nomenclature.get_id_nomenclature(<code_type>, <code_item>) ).

Observateurs

Pour une API de modification des données là par contre je ne sais pas trop. Quid des données entrée via un module GeoNature qui pourraient être modifié dans le Synthese par l'API et pas dans leurs tables sources ?

joelclems commented 3 years ago

Merci théo pour ces retours.

Pour ton dernier point concernant la modification. Si l'uuid fournie par l'api existe déjà dans la synthèse, c'est un modification. Sinon c'est une création. Pour cela on a la fonction gn_synthese.import_row_from_table qui gère ça très bien (utilisée dans le module monitoring)

La table t_application permettrait de reguler l'id_source. On ne renseignerai pas l'id_source directement dans les post_data de l'api. Le post_data contiendraient un champs application_code qui permettrai de faire le lien avec l'id_source. Si cette table est bien renseignée, il n'y a pas de risque de confusion.

jpm-cbna commented 3 years ago

@joelclems je suis assez d'accord avec @TheoLechemia concernant l'évolution de la table synthese.t_sources plutôt que l'ajout d'une nouvelle table t_applications. Si l'objectif de cette table est d'avoir une seule clé d'entrée (UUID ou code) a passer à l'API pour retrouver ensuite les valeurs id_source et id_dataset, peut être pourrait on plutôt lier entre elle les tables t_sources et t_datasets qui pour moi sont relativement liées ?

Sinon, j'ai travaillé sur un format d'échange de données qui permette d'importer de gros jeu de données dans GeoNature. Cela peut peut être te servir pour l'API. Pour résoudre le problème de dépendance entre Synthese, Jeu de données, Cadre d'acquisition et Source, j'ai cherché à utiliser les champs "code" (Ex. gn_metat.t_datasets.dataset_shortname). Mais il n'y en a pas de disponible dans toutes les tables. Du coup, j'ai utilisé les champs "nom" ou "libellé" dans ce dernier cas. Je n'ai pas utilisé les UUID car les fichiers doivent pouvoir être vérifié facilement par une personne. Mais pour une API comme la tienne, qui devrait être utilisé par des scripts, je pense qu'il faut privilégier l'utilisation des champs de type UUID.

joelclems commented 3 years ago

J'ai modifié le texte avec les remarques. On part sur une application qui peut avoir plusieurs jdd (les échanges se font par l'uuid) L'utilisateur de l'api doit être en mesure de fournir les bonne valeurs de l'uuid du dataset et de l'id_source

Ca a l'air très complet le liens sur l'échange de données. Je réfléchit aussi à comment l'aplication pourrait envoyer ses JDD à GéoNature (voir même les element pour renseigner t_sources)

A voir comment blinder l'api pour ne pas écrire n'importe où (par exemple si la ligne à un id_module, elle n'est pas sensée être modifiée par l'api)

camillemonchicourt commented 3 years ago

Concernant l'API Post de la Synthèse, je pense qu'il faut s'appuyer sur les réflexions qui ont été faites sur le module IMPORT, ainsi que les réflexions initiées pour les échanges automatisés de données entre instances de GeoNature : https://github.com/PnX-SI/GeoNature/issues/789

camillemonchicourt commented 3 years ago

Un premier point général à considérer est le fait qu'en postant directement dans l'API, on déroge en partie à un principe de GeoNature où toute donnée dans la Synthèse a sa donnée brute par ailleurs dans GeoNature. Dans notre cas où l'on va poster des données formatées pour la synthèse, cela n'a pas forcément de sens de les stocker brut par ailleurs, mais c'est à prendre en compte. Car la Synthèse est censée être calculable et regénérable à tout moment. Si on poste des données seulement dans la Synthèse, cela ne serait plus le cas. Et cela est renforcé si certaines données sont calculées et stockées uniquement dans la Synthèse lors du POST.

Par exemple, si on s'appuie sur ce qui a été fait dans IMPORT, il serait pertinent de pouvoir paramétrer si l'on calcule ou pas les UUID_SINP et les altitudes si elles ne sont pas fournis lors du POST. Pour les UUID, si il ne sont pas fournis depuis la BDD source, il peut être souhaitable de les générer dans GeoNature. Sinon pas de validation possible notamment. Voir aussi ce que l'on fait si une nomenclature n'est pas renseignée ou que l'on fournit une valeur de nomenclature qui n'existe pas dans GeoNature. On renseigne la valeur par défaut de la nomenclature définie dans la BDD GeoNature j'imagine ?

Je ne raisonnerai pas non plus en "applications" qui postent, c'est plus large. Source me semble mieux en effet. La notion de "source" permet actuellement surtout d'indiquer dans quelle table est rangée dans GN la donnée source brute d'une donnée présente dans la synthèse. Si on l'étend pour lister aussi des sources externes, à voir comment bien le préciser dans la table. Avec un booleen indiquant si c'est une source interne ou externe ?

Pour les nomenclatures, je suis OK pour privilégier les codes. Cependant si l'outil source n'en dispose pas, à voir si on ne permet pas de poster le libellé de la nomenclature.

Si on doit réconcilier des personnes ou des organismes, alors il faudrait passer par des UUID selon moi. Je mettrai en effet de côté pour le moment de récupérer les id_role et id_digitiser.

Pour s'authentifier je me demande si on ne pourrait pas passer par une clé, plutôt qu'un token utilisateur ? Définir dans une table de GN des URL et leur clé. Si c'est la bonne URL avec la bonne clé qui poste, alors on accepte le POST. Je ne sais pas si c'est intéressant ou pas comme solution.

lepontois commented 3 years ago

Salut tous le monde, Je vous apporte mon point de vue sans doute perfectible car encore très frais sur le sujet.

Avant tout, je voulais vous partager ma vision de cette API pour être sûr que l'on parle de la même chose: L'API "Synthèse" doit permettre l'intégration de données externes dans GN de la façon la plus souple et ouverte possible. Libre au développeur utilisant l'API de s'approcher ou non du format de données. Toutes données supplémentaires doivent être formatées dans un jsonb (géré côté application tierce). Tout champ non renseigné aura sa valeur par défaut. Le développeur peut s'appuyer intégralement sur la base de données GN ou avoir sa propre base en parallèle (au développeur de gérer une double écriture s'il le juge utile). A minima, une donnée envoyée à l'API doit avoir une date, un observateur, une localisation, un taxon et être associé à un jeu de données. Voyez-vous des choses à compléter ?

Sur ce constat, je trouve intéressante et rassurante cette notion d'une table synthèse recalculable. Il faudrait alors que l'écriture via l'API se fasse sur une table dédiée (avec un champ identifiant la source) qui alimenterait dans un second temps la synthèse par des triggers (tel que c'est pour occtax). On ne serait donc plus sur une table temporaire qui serait intégrée dans la synthèse (via gn_synthese.import_json_row) puis supprimé. Fonctionnement qui, en première lecture, me pose question sur la gestion de la modification des données.

Concernant les nomenclatures, soit l'application tierce peuple ses listes en demandant les valeurs possibles à GN, soit c'est un autre champ qui doit alors être inscrit dans un jsonb. Pour les JDD. Favoriser dans un premier temps de créer le JDD correspondant en amont sur GN (et/ou ajouter une notion de JDD par défaut). Peut-être voir dans une seconde version la possibilité de créer des JDD directement depuis des applis tierces (je ne pense pas que ce soit prioritaire).

Sur les médias, c'est peut-être encore à murir mais je pense que le besoin va vite émerger (surtout sur le volet app nomade).

Je trouve ce système de clé attribuée à une application intéressant pour autoriser la communication avec l'API. Ça force à "enregistrer" son application dans GN. Mais est-ce que ce ne doit pas être couplé avec l'authentification utilisateur ? (qui permettrait de récupérer des droits côté GN ?) Il faut également s'assurer de son fonctionnement avec des applications autres que des applis web (app sans url - app nomade / plugin qgis ...).

Si je devais soulever des questions précédemment actées, n'hésitez pas à me le faire savoir. Je ne sais pas vraiment quel est le niveau d'avancement du projet et je ne tiens pas à remettre en cause des choix déjà faits. Mon but est de vous apporter une vision utilisateur car au PNP nous serons sans aucun doute amenés à nous appuyer sur cette API. Nous y portons un fort intérêt. Bien à vous !

jpm-cbna commented 3 years ago

Concernant les droits d'accès de l'API, comme le suggère @camillemonchicourt l'utilisation d'une clé ou jeton (à distinguer du couple login/mot de passe) est préférable. La solution JWT est parfaitement adaptée à ce cas d'usage. Il me semble d'ailleurs qu'il y a des pull-request sur le sujet #662. De plus, cela n'utilise pas de cookie et est donc compatible avec les applis mobiles et surement avec Qgis car le jeton peut être transmis dans les entête HTTP ou comme paramètre (query string) de la requête.

joelclems commented 3 years ago

Merci Ludovic pour ces remarques. Le sujet est toujours en cours de réflexion, et toutes les contributions sont les bienvenues.

DonovanMaillard commented 3 years ago

Bonjour,

Ma première idée en lisant tout ça, même si je n'ai pas tous les tenants et aboutissants du projet, serait de faire passer ce mécanisme via le module d'import et pas en direct dans la synthèse.

La synthèse devrait être recalculable comme le dit camille, mais aussi et surtout, je pense que les données sont toujours destinées à être modifiées :

Stocker les données dans un format brut (comme le fait gn_imports dans son schéma archive) permettrait de garder systématiquement la donnée brute sans aucune info modifiée/recalculée. Ca permettrait de conserver l'idée d'une synthèse qui ne fait que synthétiser les données réparties ailleurs dans la base. Et de conserver le mécanisme de la t_source actuelle, à savoir la source=module d'import (+ id_import). Pour terminer sur la lisibilité, on saurait que les données de la synthèse proviennent soit d'un module de saisie, soit du module d'import pour les données venant de l'extérieur (que ca vienne en api, en fichier csv ou autre ne devrait pas forcement changer le cheminement de la donnée importée).

TheoLechemia commented 3 years ago

Juste quelques remarques en mémo pour le prochain point au tel :

joelclems commented 3 years ago

En résumé de la réunion de tout à l'heure et pour définir la suite

Les grandes lignes

Etape 1

SQL

Backend

Améliorations

les ++

DonovanMaillard commented 3 years ago

J'ai bien en tête que ca diffère un peu de l'idée vue cet aprem, mais pour répondre à la question :

    Comment définir les JDD utilisables par l'utilisateur de l'API pour la source?
    champs dans .t_source_complements ?
    table en plus ?
    utilisation de l'existant ?
    on laisse libre (ou à faire plus tard) ?

Vu qu'en quelque sorte, cette API a vocation "d'externaliser des modules de saisie" serait-il intéressant d'imaginer :

camillemonchicourt commented 3 years ago

Pour moi, en terme de concept et de vocabulaire ce ne sont pas des modules ni des applications qui vont poster dans la Synthèse mais bien des sources. Des sources externes. Je suis pas trop emballé par l'idée de les lister comme des modules.

Une table t_sources_api me semble bien.

lepontois commented 3 years ago

Merci Joël pour ce résumé très clair,

J'aurais quelques questions pour ma compréhension,

Pour le lien source / jdd, j'y vois une table cor_source_dataset car plusieurs JDD pourraient être alimentés par une même source (en remplacement de cor_module_dataset -> élargissement de cette table à des sources plutôt que des modules ?). Sélection du JDD gérée du coté de l'application externe -> Penser à permettre la récupération de la liste des JDD disponible pour une source à travers l'API (GET).

J'y pense que maintenant, mais la déclaration d'une source devrait se faire via une page d'admin. Car on n'est pas certains de nos droits d'écriture en base. On y retrouverait le rattachement aux JDD, et la configuration pour la génération des UUID et du calcul d'altitude (et + ?). Ça n'a pas été abordé hier mais c'était peut-être intuitif (je voulais m'en assurer).

camillemonchicourt commented 3 years ago

Le fait de limiter les JDD par source ne me paraît pas forcément une nécessité, du moins pas dans un premier temps.

joelclems commented 3 years ago

@ludovic l'id_role dans la table permettrai de faire le lien entre l'utilisateur et les sources (1-n) c'est pour s'assurer que cet utilisateur n'intervienne que pour des source auxquelles il est rattaché. (on peut imaginer le cas ou l'on aurait deux utilisateurs de l'api post et ou on voudrait cloisonner les sources)

pour les jdd je serai plutot pour une table cor_source_dataset ( le pendant de cor_module_dataset pour les sources)

on en a pas parlé mais effectivement il faudrait avoir une interface d'administration pour pouvoir créer / gérer les sources

DonovanMaillard commented 2 years ago

Bonjour,

Est-ce que l'API Post vers la synthèse a été implémentée ou terminée ?

La question de pose d'utiliser cette solution pour poster les données via le module d'imports, en simplifiant son backend.