From 181fabcb67136724d06fc7e310e9cf3010d29ef8 Mon Sep 17 00:00:00 2001 From: alhyss <55992003+alhyss@users.noreply.github.com> Date: Tue, 21 May 2024 15:07:44 +0200 Subject: [PATCH 01/11] refactor: initialisation PlumePg v0.3.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Initialisation de plume_pg--0.3.1.sql avec le code de PlumePg 0.3.0, script de mise à jour vierge et modification de la version de référence dans plume_pg.control. --- postgresql/plume_pg--0.3.0--0.3.1.sql | 51 + postgresql/plume_pg--0.3.1.sql | 2254 +++++++++++++++++++++++++ postgresql/plume_pg.control | 2 +- 3 files changed, 2306 insertions(+), 1 deletion(-) create mode 100644 postgresql/plume_pg--0.3.0--0.3.1.sql create mode 100644 postgresql/plume_pg--0.3.1.sql diff --git a/postgresql/plume_pg--0.3.0--0.3.1.sql b/postgresql/plume_pg--0.3.0--0.3.1.sql new file mode 100644 index 00000000..98b8d7a7 --- /dev/null +++ b/postgresql/plume_pg--0.3.0--0.3.1.sql @@ -0,0 +1,51 @@ +\echo Use "ALTER EXTENSION plume_pg UPDATE TO '0.3.1'" to load this file. \quit +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +-- +-- PlumePg - Système de gestion des métadonnées locales, version 0.3.1 +-- > Script de mise à jour depuis la version 0.3.0 +-- +-- Copyright République Française, 2024. +-- Secrétariat général du Ministère de la Transition écologique et +-- de la Cohésion des territoires. +-- Direction du numérique. +-- +-- contributeurs : Leslie Lemaire (SNUM/UNI/DRC). +-- +-- mél : drc.uni.dnum.sg@developpement-durable.gouv.fr +-- +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +-- +-- Documentation : +-- https://mtes-mct.github.io/metadata-postgresql/usage/gestion_plume_pg.html +-- https://snum.scenari-community.org/Plume/Documentation/ (en cours de rédaction) +-- +-- GitHub : +-- https://github.com/MTES-MCT/metadata-postgresql +-- +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +-- +-- Ce logiciel est un programme informatique complémentaire au système de +-- gestion de base de données PosgreSQL ("https://www.postgresql.org/"). Il +-- met en place côté serveur les objets nécessaires à la gestion des +-- métadonnées, en complément du plugin QGIS Plume. +-- +-- Ce logiciel est régi par la licence GNU Affero General Public License v3.0 +-- or later. Lien SPDX : https://spdx.org/licenses/AGPL-3.0-or-later.html. +-- +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +-- +-- dépendances : pgcrypto +-- +-- schéma contenant les objets : z_plume +-- +-- objets créés par le script : +-- Néant. +-- +-- objets modifiés par le script : +-- Néant. +-- +-- objets supprimés par le script : +-- Néant. +-- +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/postgresql/plume_pg--0.3.1.sql b/postgresql/plume_pg--0.3.1.sql new file mode 100644 index 00000000..ad1117d2 --- /dev/null +++ b/postgresql/plume_pg--0.3.1.sql @@ -0,0 +1,2254 @@ +\echo Use "CREATE EXTENSION plume_pg" to load this file. \quit +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +-- +-- PlumePg - Système de gestion des métadonnées locales, version 0.3.1 +-- +-- Copyright République Française, 2023-2024. +-- Secrétariat général du Ministère de la Transition écologique et +-- de la Cohésion des territoires. +-- Direction du numérique. +-- +-- contributeurs : Leslie Lemaire (SNUM/UNI/DRC). +-- +-- mél : drc.uni.dnum.sg@developpement-durable.gouv.fr +-- +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +-- +-- Documentation : +-- https://mtes-mct.github.io/metadata-postgresql/usage/gestion_plume_pg.html +-- https://snum.scenari-community.org/Plume/Documentation/ (en cours de rédaction) +-- +-- GitHub : +-- https://github.com/MTES-MCT/metadata-postgresql +-- +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +-- +-- Ce logiciel est un programme informatique complémentaire au système de +-- gestion de base de données PosgreSQL ("https://www.postgresql.org/"). Il +-- met en place côté serveur les objets nécessaires à la gestion des +-- métadonnées, en complément du plugin QGIS Plume. +-- +-- Ce logiciel est régi par la licence GNU Affero General Public License v3.0 +-- or later. Lien SPDX : https://spdx.org/licenses/AGPL-3.0-or-later.html. +-- +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +-- +-- dépendances : pgcrypto +-- +-- schéma contenant les objets : z_plume +-- +-- objets créés par le script : +-- - Schema: z_plume +-- - Type: z_plume.meta_special +-- - Type: z_plume.meta_datatype +-- - Type: z_plume.meta_geo_tool +-- - Type: z_plume.meta_compute +-- - Table: z_plume.meta_categorie +-- - Table: z_plume.meta_shared_categorie +-- - Function: z_plume.meta_shared_categorie_before_insert() +-- - Trigger: meta_shared_categorie_before_insert +-- - Table: z_plume.meta_local_categorie +-- - Sequence: z_plume.meta_template_tpl_id_seq +-- - Table: z_plume.meta_template +-- - Sequence: z_plume.meta_tab_tab_id_seq +-- - Table: z_plume.meta_tab +-- - Sequence: z_plume.meta_template_categories_tplcat_id_seq +-- - Table: z_plume.meta_template_categories +-- - View: z_plume.meta_template_categories_full +-- - Function: z_plume.meta_import_sample_template(text) +-- - Function: z_plume.meta_execute_sql_filter(text, text, text) +-- - Function: z_plume.meta_ante_post_description(oid, text) +-- - Function: z_plume.meta_description(oid, text) +-- - Function: z_plume.meta_regexp_matches(text, text, text) +-- - Function: z_plume.is_relowner(oid) +-- - Table: z_plume.stamp_timestamp +-- - Function: stamp_timestamp_access_control() +-- - Trigger: stamp_timestamp_access_control +-- - Function: stamp_timestamp_to_metadata() +-- - Trigger: stamp_timestamp_to_metadata +-- - Function: z_plume.stamp_data_edit() +-- - Function: z_plume.stamp_create_trigger(oid) +-- - Function: z_plume.stamp_new_entry() +-- - Event trigger: plume_stamp_new_entry +-- - Function: z_plume.stamp_table_creation() +-- - Event trigger: plume_stamp_table_creation +-- - Function: z_plume.stamp_table_modification() +-- - Event trigger: plume_stamp_table_modification +-- - Function: z_plume.stamp_table_drop() +-- - Event trigger: plume_stamp_table_drop +-- - Function: z_plume.stamp_clean_timestamp() +-- - Function: z_plume.stamp_create_triggers(text, text[], text[]) +-- +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +/* 0 - SCHEMA z_plume + 1 - MODELES DE FORMULAIRES + 2 - FONCTIONS UTILITAIRES + 3 - DATES DE MODIFICATION */ + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +-------------------------------- +------ 0 - SCHEMA z_plume ------ +-------------------------------- + +-- Schema: z_plume + +DO +$$ +BEGIN + + IF NOT EXISTS ( + SELECT * FROM pg_namespace + WHERE nspname = 'z_plume' + ) + THEN + + CREATE SCHEMA z_plume ; + + COMMENT ON SCHEMA z_plume IS 'Utilitaires pour la gestion des métadonnées.' ; + + -- si le schéma existe déjà, il ne sera pas marqué comme + -- dépendant de l'extension + + -- si l'extension asgard est présente, on déclare g_admin + -- comme producteur et le pseudo-rôle public comme lecteur + -- pour le nouveau schéma + IF EXISTS ( + SELECT * FROM pg_available_extensions + WHERE name = 'asgard' + AND installed_version IS NOT NULL + ) + THEN + BEGIN + UPDATE z_asgard.gestion_schema_usr + SET producteur = 'g_admin', + lecteur = 'public' + WHERE nom_schema = 'z_plume' ; + EXCEPTION WHEN OTHERS THEN NULL ; + END ; + END IF ; + + END IF ; + + -- si le schéma existe déjà, il ne sera pas marqué comme + -- dépendant de l'extension + +END +$$ ; + +GRANT USAGE ON SCHEMA z_plume TO public ; + +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +---------------------------------------- +------ 1 - MODELES DE FORMULAIRES ------ +---------------------------------------- + +/* 1.1 - TABLE DE CATEGORIES + 1.2 - TABLE DES MODELES + 1.3 - TABLE DES ONGLETS + 1.4 - ASSOCIATION DES CATEGORIES AUX MODELES + 1.5 - IMPORT DE MODELES PRE-CONFIGURES */ + + +------ 1.1 - TABLE DE CATEGORIES ------ + +-- Type: z_plume.meta_special + +CREATE TYPE z_plume.meta_special AS ENUM ('url', 'email', 'phone') ; + +COMMENT ON TYPE z_plume.meta_special IS 'Valeurs admises pour les mises en forme particulières.' ; + + +-- Type: z_plume.meta_datatype + +CREATE TYPE z_plume.meta_datatype AS ENUM ( + 'xsd:string', 'xsd:integer', 'xsd:decimal', 'xsd:boolean', + 'xsd:date', 'xsd:time', 'xsd:dateTime', 'xsd:duration', + 'gsp:wktLiteral', 'rdf:langString' + ) ; + +COMMENT ON TYPE z_plume.meta_datatype IS 'Types de valeurs supportés par Plume.' ; + + +-- Type: z_plume.meta_geo_tool + +CREATE TYPE z_plume.meta_geo_tool AS ENUM ( + 'show', 'point', 'linestring', 'rectangle', 'polygon', + 'bbox', 'centroid', 'circle' + ) ; + +COMMENT ON TYPE z_plume.meta_geo_tool IS 'Types de fonctionnalités d''aide à la saisie des géométries supportées par Plume.' ; + +CREATE CAST (text[] AS z_plume.meta_geo_tool[]) + WITH INOUT + AS IMPLICIT ; + + +-- Type: z_plume.meta_compute + +CREATE TYPE z_plume.meta_compute AS ENUM ( + 'auto', 'empty', 'new', 'manual' + ) ; + +COMMENT ON TYPE z_plume.meta_compute IS 'Types de fonctionnalités de calcul des métadonnées supportées par Plume.' ; + +CREATE CAST (text[] AS z_plume.meta_compute[]) + WITH INOUT + AS IMPLICIT ; + + +--Table: z_plume.meta_categorie + +CREATE TABLE z_plume.meta_categorie ( + path text NOT NULL DEFAULT format('uuid:%s', gen_random_uuid()), + origin text NOT NULL DEFAULT 'local', + label text NOT NULL, + description text, + special z_plume.meta_special, + is_node boolean NOT NULL DEFAULT False, + datatype z_plume.meta_datatype, + is_long_text boolean, + rowspan int, + placeholder text, + input_mask text, + is_multiple boolean, + unilang boolean, + is_mandatory boolean, + sources text[], + geo_tools z_plume.meta_geo_tool[], + compute z_plume.meta_compute[], + template_order int, + compute_params jsonb, + CONSTRAINT meta_categorie_origin_check CHECK (origin IN ('local', 'shared')), + CONSTRAINT meta_categorie_rowspan_check CHECK (rowspan BETWEEN 1 AND 99) + ) + PARTITION BY LIST (origin) ; + +GRANT SELECT ON TABLE z_plume.meta_categorie TO public ; + +COMMENT ON TABLE z_plume.meta_categorie IS 'Catégories de métadonnées disponibles pour les modèles de formulaires.' ; + +COMMENT ON COLUMN z_plume.meta_categorie.path IS 'Chemin N3 de la catégorie (identifiant unique). CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_categorie.origin IS 'Origine de la catégorie : ''shared'' pour une catégorie commune, ''local'' pour une catégorie locale supplémentaire. CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_categorie.label IS 'Libellé de la catégorie.' ; +COMMENT ON COLUMN z_plume.meta_categorie.description IS 'Description de la catégorie. Sera affiché sous la forme d''un texte d''aide dans le formulaire.' ; +COMMENT ON COLUMN z_plume.meta_categorie.special IS 'Le cas échéant, mise en forme spécifique à appliquer au champ. Valeurs autorisées : ''url'', ''email'', ''phone''. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_categorie.is_node IS 'True si la catégorie est le nom d''un groupe qui contiendra lui-même d''autres catégories et non une catégorie à laquelle sera directement associée une valeur. Par exemple, is_node vaut True pour la catégorie correspondant au point de contact (dcat:contactPoint) et False pour le nom du point de contact (dcat:contactPoint / vcard:fn). CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_categorie.datatype IS 'Type de valeur attendu pour la catégorie. Cette information détermine notamment la nature des widgets utilisés par Plume pour afficher et éditer les valeurs, ainsi que les validateurs appliqués. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_categorie.is_long_text IS 'True pour une catégorie appelant un texte de plusieurs lignes. Cette information ne sera prise en compte que si le type de valeur (datatype) est ''xsd:string'' ou ''rdf:langString''.' ; +COMMENT ON COLUMN z_plume.meta_categorie.rowspan IS 'Nombre de lignes occupées par le widget de saisie, s''il y a lieu de modifier le comportement par défaut de Plume. La valeur ne sera considérée que si is_long_text vaut True.' ; +COMMENT ON COLUMN z_plume.meta_categorie.placeholder IS 'Valeur fictive pré-affichée en tant qu''exemple dans le widget de saisie, s''il y a lieu.' ; +COMMENT ON COLUMN z_plume.meta_categorie.input_mask IS 'Masque de saisie, s''il y a lieu. La valeur sera ignorée si le widget utilisé pour la catégorie ne prend pas en charge ce mécanisme.' ; +COMMENT ON COLUMN z_plume.meta_categorie.is_multiple IS 'True si la catégorie admet plusieurs valeurs. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_categorie.unilang IS 'True si la catégorie n''admet plusieurs valeurs que si elles sont dans des langues différentes (par exemple un jeu de données n''a en principe qu''un seul titre, mais il peut être traduit). is_multiple est ignoré quand unilang vaut True. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_categorie.is_mandatory IS 'True si une valeur doit obligatoirement être saisie pour cette catégorie. À noter que ce champ permet de rendre obligatoire une catégorie commune optionnelle, pas l''inverse.' ; +COMMENT ON COLUMN z_plume.meta_categorie.sources IS 'Pour une catégorie prenant ses valeurs dans un ou plusieurs thésaurus, liste des sources admises. Cette information n''est considérée que pour les catégories communes. Il n''est pas possible d''ajouter des sources ni de les retirer toutes - Plume reviendrait alors à la liste initiale -, mais ce champ permet de restreindre la liste à un ou plusieurs thésaurus jugés les mieux adaptés.' ; +COMMENT ON COLUMN z_plume.meta_categorie.geo_tools IS 'Pour une catégorie prenant pour valeurs des géométries, liste des fonctionnalités d''aide à la saisie à proposer. Cette information ne sera considérée que si le type (datatype) est ''gsp:wktLiteral''. Pour retirer toutes les fonctionnalités proposées par défaut pour une catégorie commune, on saisira une liste vide.' ; +COMMENT ON COLUMN z_plume.meta_categorie.compute IS 'Liste des fonctionnalités de calcul à proposer. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie. Pour retirer toutes les fonctionnalités proposées par défaut pour une catégorie commune, on saisira une liste vide.' ; +COMMENT ON COLUMN z_plume.meta_categorie.template_order IS 'Ordre d''apparence de la catégorie dans le formulaire. Les plus petits numéros sont affichés en premier.' ; +COMMENT ON COLUMN z_plume.meta_categorie.compute_params IS 'Paramètres des fonctionnalités de calcul, le cas échéant, sous une forme clé-valeur. La clé est le nom du paramètre, la valeur sa valeur. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie et qu''elle attend un ou plusieurs paramètres.' ; + + +-- Table: z_plume.meta_shared_categorie + +CREATE TABLE z_plume.meta_shared_categorie + PARTITION OF z_plume.meta_categorie ( + CONSTRAINT meta_shared_categorie_pkey PRIMARY KEY (path) + ) + FOR VALUES IN ('shared') ; + +GRANT SELECT ON TABLE z_plume.meta_shared_categorie TO public ; + +COMMENT ON TABLE z_plume.meta_shared_categorie IS 'Catégories de métadonnées communes.' ; + +COMMENT ON COLUMN z_plume.meta_shared_categorie.path IS 'Chemin SPARQL de la catégorie (identifiant unique). CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.origin IS 'Origine de la catégorie. Toujours ''shared''. CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.label IS 'Libellé de la catégorie.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.description IS 'Description de la catégorie. Sera affiché sous la forme d''un texte d''aide dans le formulaire.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.special IS 'Le cas échéant, mise en forme spécifique à appliquer au champ. Valeurs autorisées : ''url'', ''email'', ''phone''. Les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.is_node IS 'True si la catégorie est le nom d''un groupe qui contiendra lui-même d''autres catégories et non une catégorie à laquelle sera directement associée une valeur. Par exemple, is_node vaut True pour la catégorie correspondant au point de contact (dcat:contactPoint) et False pour le nom du point de contact (dcat:contactPoint / vcard:fn). CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.datatype IS 'Type de valeur attendu pour la catégorie. Cette information détermine notamment la nature des widgets utilisés par Plume pour afficher et éditer les valeurs, ainsi que les validateurs appliqués. Les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.is_long_text IS 'True pour une catégorie appelant un texte de plusieurs lignes. Cette information ne sera prise en compte que si le type de valeur (datatype) est ''xsd:string'' ou ''rdf:langString''.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.rowspan IS 'Nombre de lignes occupées par le widget de saisie, s''il y a lieu de modifier le comportement par défaut de Plume. La valeur ne sera considérée que si is_long_text vaut True.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.placeholder IS 'Valeur fictive pré-affichée en tant qu''exemple dans le widget de saisie, s''il y a lieu.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.input_mask IS 'Masque de saisie, s''il y a lieu. La valeur sera ignorée si le widget utilisé pour la catégorie ne prend pas en charge ce mécanisme.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.is_multiple IS 'True si la catégorie admet plusieurs valeurs. Les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.unilang IS 'True si la catégorie n''admet plusieurs valeurs que si elles sont dans des langues différentes (par exemple un jeu de données n''a en principe qu''un seul titre, mais il peut être traduit). is_multiple est ignoré quand unilang vaut True. Les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.is_mandatory IS 'True si une valeur doit obligatoirement être saisie pour cette catégorie. À noter que ce champ permet de rendre obligatoire une catégorie commune optionnelle, pas l''inverse.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.sources IS 'Pour une catégorie prenant ses valeurs dans un ou plusieurs thésaurus, liste des sources admises. Il n''est pas possible d''ajouter des sources ni de les retirer toutes - Plume reviendrait alors à la liste initiale -, mais ce champ permet de restreindre la liste à un ou plusieurs thésaurus jugés les mieux adaptés.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.geo_tools IS 'Pour une catégorie prenant pour valeurs des géométries, liste des fonctionnalités d''aide à la saisie à proposer. Cette information ne sera considérée que si le type (datatype) est ''gsp:wktLiteral''. Pour retirer toutes les fonctionnalités proposées par défaut pour la catégorie commune, on saisira une liste vide.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.compute IS 'Liste des fonctionnalités de calcul à proposer. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie. Pour retirer toutes les fonctionnalités proposées par défaut pour une catégorie commune, on saisira une liste vide.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.template_order IS 'Ordre d''apparence de la catégorie dans le formulaire. Les plus petits numéros sont affichés en premier.' ; +COMMENT ON COLUMN z_plume.meta_shared_categorie.compute_params IS 'Paramètres des fonctionnalités de calcul, le cas échéant, sous une forme clé-valeur. La clé est le nom du paramètre, la valeur sa valeur. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie et qu''elle attend un ou plusieurs paramètres.' ; + +-- la table est marquée comme table de configuration de l'extension +SELECT pg_extension_config_dump('z_plume.meta_shared_categorie'::regclass, '') ; + +-- extraction du schéma SHACL +INSERT INTO z_plume.meta_categorie ( + path, origin, label, description, special, + is_node, datatype, is_long_text, rowspan, + placeholder, input_mask, is_multiple, unilang, + is_mandatory, sources, geo_tools, compute, + template_order + ) VALUES + ('dct:title', 'shared', 'Libellé', 'Nom explicite du jeu de données.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, true, NULL, NULL, NULL, 0), + ('owl:versionInfo', 'shared', 'Version', 'Numéro de version ou millésime du jeu de données.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 1), + ('dct:description', 'shared', 'Description', 'Description du jeu de données.', NULL, false, 'rdf:langString', true, 15, NULL, NULL, true, true, true, NULL, NULL, NULL, 2), + ('plume:isExternal', 'shared', 'Donnée externe', 'Ce jeu de données est-il la reproduction de données produites par un tiers ? Une donnée issue d''une source externe mais ayant fait l''objet d''améliorations notables n''est plus une donnée externe.', NULL, false, 'xsd:boolean', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 3), + ('dcat:theme', 'shared', 'Thèmes', 'Classification thématique du jeu de données.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://publications.europa.eu/resource/authority/data-theme','http://inspire.ec.europa.eu/theme','http://inspire.ec.europa.eu/metadata-codelist/TopicCategory','http://registre.data.developpement-durable.gouv.fr/ecospheres/themes-ecospheres','http://inspire.ec.europa.eu/metadata-codelist/SpatialScope','http://inspire.ec.europa.eu/metadata-codelist/PriorityDataset'], NULL, NULL, 4), + ('dcat:keyword', 'shared', 'Mots-clés libres', 'Mots ou très brèves expressions représentatives du jeu de données, à l''usage des moteurs de recherche.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 6), + ('dct:spatial', 'shared', 'Couverture géographique', 'Territoire·s décrit·s par le jeu de données.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/EuAdministrativeTerritoryUnitFrance','http://id.insee.fr/geo/departement','http://id.insee.fr/geo/region','http://registre.data.developpement-durable.gouv.fr/plume/InseeIndividualTerritory','http://publications.europa.eu/resource/authority/atu','http://id.insee.fr/geo/commune'], NULL, NULL, 9), + ('dct:spatial / skos:inScheme', 'shared', 'Index géographique', 'Type de lieu, index de référence pour l''identifiant (commune, département...).', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/InseeGeoIndex','http://registre.data.developpement-durable.gouv.fr/plume/ISO3166CodesCollection'], NULL, NULL, 0), + ('dct:spatial / dct:identifier', 'shared', 'Code géographique', 'Code du département, code INSEE de la commune, etc.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 1), + ('dct:spatial / skos:prefLabel', 'shared', 'Libellé', 'Dénomination explicite du lieu.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 2), + ('dct:spatial / dcat:bbox', 'shared', 'Rectangle d''emprise', 'Rectangle d''emprise (BBox), au format textuel WKT.', NULL, false, 'gsp:wktLiteral', true, NULL, ' POLYGON((646417.3289 6857521.1356, 657175.3272 6857521.1356, 657175.3272 6867076.0360, 646417.3289 6867076.0360, 646417.3289 6857521.1356))', NULL, false, false, false, NULL, ARRAY['show','bbox','rectangle']::z_plume.meta_geo_tool[], NULL, 3), + ('dct:spatial / dcat:centroid', 'shared', 'Centroïde', 'Localisant du centre géographique des données, au format textuel WKT.', NULL, false, 'gsp:wktLiteral', true, NULL, ' POINT(651796.3281 6862298.5858)', NULL, false, false, false, NULL, ARRAY['show','centroid','point']::z_plume.meta_geo_tool[], NULL, 4), + ('dct:spatial / locn:geometry', 'shared', 'Géométrie', 'Emprise géométrique, au format textuel WKT.', NULL, false, 'gsp:wktLiteral', true, NULL, ' POLYGON((646417.3289 6857521.1356, 657175.3272 6857521.1356, 657175.3272 6867076.0360, 646417.3289 6867076.0360, 646417.3289 6857521.1356))', NULL, false, false, false, NULL, ARRAY['show','point','linestring','polygon','circle']::z_plume.meta_geo_tool[], NULL, 5), + ('dct:temporal', 'shared', 'Couverture temporelle', 'Période·s décrite·s par le jeu de données. La date de début et la date de fin peuvent être confondues, par exemple dans le cas de l''extraction ponctuelle d''une base mise à jour au fil de l''eau.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 10), + ('dct:temporal / dcat:startDate', 'shared', 'Date de début', 'Date de début de la période.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 0), + ('dct:temporal / dcat:endDate', 'shared', 'Date de fin', 'Date de fin de la période.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 1), + ('dct:created', 'shared', 'Date de création', 'Date de création du jeu de données. Il peut par exemple s''agir de la date de création de la table PostgreSQL ou de la date de la première saisie de données dans cette table.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 11), + ('dct:modified', 'shared', 'Date de dernière modification', 'Date de la dernière modification du jeu de données. Cette date est présumée tenir compte tant des modifications de fond, tels que les ajouts d''enregistrements, que des modification purement formelles (corrections de coquilles dans les données, changement de nom d''un champ, etc.). L''absence de date de dernière modification signifie que la donnée n''a jamais été modifiée depuis sa création.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 12), + ('dct:issued', 'shared', 'Date de publication', 'Date à laquelle le jeu de données a été diffusé. Cette date ne devrait être renseignée que pour un jeu de données effectivement mis à disposition du public ou d''utilisateur tiers via un catalogue de données ou un site internet. Pour un jeu de données mis à jour en continu, il s''agit de la date de publication initiale.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 13), + ('dct:accrualPeriodicity', 'shared', 'Fréquence de mise à jour', 'Fréquence de mise à jour des données.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://inspire.ec.europa.eu/metadata-codelist/MaintenanceFrequency','http://publications.europa.eu/resource/authority/frequency'], NULL, NULL, 14), + ('adms:status', 'shared', 'Statut', 'Maturité du jeu de données.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://publications.europa.eu/resource/authority/dataset-status','http://registre.data.developpement-durable.gouv.fr/plume/ISO19139ProgressCode'], NULL, NULL, 15), + ('dct:provenance', 'shared', 'Généalogie', 'Sources et méthodes mises en œuvre pour produire les données.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 20), + ('dct:provenance / rdfs:label', 'shared', 'Texte', 'Informations sur l''origine des données : sources, méthodes de recueil ou de traitement...', NULL, false, 'rdf:langString', true, 20, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('adms:versionNotes', 'shared', 'Note de version', 'Différences entre la version courante des données et les versions antérieures.', NULL, false, 'rdf:langString', true, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 21), + ('dct:conformsTo', 'shared', 'Conforme à', 'Standard, schéma, référentiel de coordonnées, etc. auquel se conforment les données.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/OgcEpsgFrance','http://www.opengis.net/def/crs/EPSG/0','http://registre.data.developpement-durable.gouv.fr/plume/IgnCrs'], NULL, ARRAY['manual']::z_plume.meta_compute[], 22), + ('dct:conformsTo / skos:inScheme', 'shared', 'Registre', 'Registre de référence auquel appartient le standard.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/StandardsRegister'], NULL, NULL, 0), + ('dct:conformsTo / dct:identifier', 'shared', 'Identifiant', 'Identifiant du standard, s''il y a lieu. Pour un système de coordonnées géographiques, il s''agit du code EPSG.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 1), + ('dct:conformsTo / dct:title', 'shared', 'Libellé', 'Libellé explicite du standard.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 2), + ('dct:conformsTo / owl:versionInfo', 'shared', 'Version', 'Numéro ou code de la version du standard à laquelle se conforment les données.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 3), + ('dct:conformsTo / dct:description', 'shared', 'Description', 'Description sommaire de l''objet du standard.', NULL, false, 'rdf:langString', true, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 4), + ('dct:conformsTo / dct:issued', 'shared', 'Date de publication', 'Date de publication du standard.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 5), + ('dct:conformsTo / dct:modified', 'shared', 'Date de modification', 'Date de la dernière modification du standard.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 6), + ('dct:conformsTo / dct:created', 'shared', 'Date de création', 'Date de création du standard.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 7), + ('dct:conformsTo / foaf:page', 'shared', 'Page internet', 'Chemin d''accès au standard ou URL d''une page contenant des informations sur le standard.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 8), + ('dcat:spatialResolutionInMeters', 'shared', 'Résolution spatiale en mètres', 'Plus petite distance significative dans le contexte du jeu de données, exprimée en mètres.', NULL, false, 'xsd:decimal', false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 24), + ('dqv:hasQualityMeasurement', 'shared', 'Résolution spatiale', 'Spécification du niveau de détail des données.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 25), + ('dqv:hasQualityMeasurement / dqv:isMeasurementOf', 'shared', 'Indicateur', 'Critère d''évaluation de la résolution.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/GeoDCATMetric'], NULL, NULL, 0), + ('dqv:hasQualityMeasurement / dqv:value', 'shared', 'Valeur', 'Valeur de la résolution.', NULL, false, 'xsd:decimal', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 1), + ('dqv:hasQualityMeasurement / sdmx-attribute:unitMeasure', 'shared', 'Unité de mesure', 'Unité dans laquelle est exprimée la résolution, le cas échéant.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://publications.europa.eu/resource/authority/measurement-unit','http://qudt.org/vocab/unit'], NULL, NULL, 2), + ('dcat:temporalResolution', 'shared', 'Résolution temporelle', 'Plus petit pas de temps significatif dans le contexte du jeu de données.', NULL, false, 'xsd:duration', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 26), + ('dct:accessRights', 'shared', 'Conditions d''accès', 'Contraintes réglementaires limitant l''accès aux données.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://inspire.ec.europa.eu/metadata-codelist/LimitationsOnPublicAccess','http://publications.europa.eu/resource/authority/access-right','http://registre.data.developpement-durable.gouv.fr/plume/CrpaAccessLimitations','http://registre.data.developpement-durable.gouv.fr/plume/ISO19139ClassificationCode','http://registre.data.developpement-durable.gouv.fr/plume/ISO19139RestrictionCode'], NULL, NULL, 30), + ('dct:accessRights / rdfs:label', 'shared', 'Mention', 'Description des contraintes réglementaires et des modalités pratiques pour s''y conformer.', NULL, false, 'rdf:langString', true, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 1), + ('dcat:contactPoint', 'shared', 'Point de contact', 'Entité à contacter pour obtenir des informations sur les données.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 40), + ('dcat:contactPoint / vcard:fn', 'shared', 'Nom', 'Nom du point de contact.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, false, false, true, NULL, NULL, NULL, 1), + ('dcat:contactPoint / vcard:hasEmail', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('dcat:contactPoint / vcard:hasTelephone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('dcat:contactPoint / vcard:hasURL', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('dcat:contactPoint / vcard:organization-name', 'shared', 'Appartient à', 'Le cas échéant, organisation dont le point de contact fait partie.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 5), + ('dct:publisher', 'shared', 'Éditeur', 'Organisme ou personne qui assure la publication des données.', NULL, true, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 41), + ('dct:publisher / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('dct:publisher / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('dct:publisher / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('dct:publisher / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('dct:publisher / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('dct:creator', 'shared', 'Auteur', 'Principal responsable de la production des données.', NULL, true, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 42), + ('dct:creator / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('dct:creator / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('dct:creator / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('dct:creator / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('dct:creator / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('dct:rightsHolder', 'shared', 'Propriétaire', 'Organisme ou personne qui détient des droits sur les données.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 43), + ('dct:rightsHolder / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('dct:rightsHolder / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('dct:rightsHolder / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('dct:rightsHolder / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('dct:rightsHolder / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('geodcat:custodian', 'shared', 'Gestionnaire', 'Organisme ou personne qui assume la maintenance des données.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 44), + ('geodcat:custodian / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('geodcat:custodian / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('geodcat:custodian / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('geodcat:custodian / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('geodcat:custodian / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('geodcat:distributor', 'shared', 'Distributeur', 'Organisme ou personne qui assure la distribution des données.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 45), + ('geodcat:distributor / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('geodcat:distributor / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('geodcat:distributor / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('geodcat:distributor / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('geodcat:distributor / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('geodcat:originator', 'shared', 'Commanditaire', 'Organisme ou personne qui est à l''origine de la création des données.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 46), + ('geodcat:originator / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('geodcat:originator / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('geodcat:originator / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('geodcat:originator / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('geodcat:originator / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('geodcat:principalInvestigator', 'shared', 'Maître d''œuvre', 'Organisme ou personne chargée du recueil des informations.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 47), + ('geodcat:principalInvestigator / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('geodcat:principalInvestigator / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('geodcat:principalInvestigator / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('geodcat:principalInvestigator / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('geodcat:principalInvestigator / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('geodcat:processor', 'shared', 'Intégrateur', 'Organisation ou personne qui a retraité les données.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 48), + ('geodcat:processor / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('geodcat:processor / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('geodcat:processor / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('geodcat:processor / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('geodcat:processor / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('geodcat:resourceProvider', 'shared', 'Fournisseur de la ressource', 'Organisme ou personne qui diffuse les données, soit directement soit par l''intermédiaire d''un distributeur.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 49), + ('geodcat:resourceProvider / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('geodcat:resourceProvider / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('geodcat:resourceProvider / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('geodcat:resourceProvider / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('geodcat:resourceProvider / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('geodcat:user', 'shared', 'Utilisateur', 'Organisme ou personne qui utilise les données.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 50), + ('geodcat:user / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('geodcat:user / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('geodcat:user / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('geodcat:user / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('geodcat:user / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('dcat:distribution', 'shared', 'Distribution', 'Distribution.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 59), + ('dcat:distribution / dcat:accessURL', 'shared', 'URL d''accès', 'URL de la page où est publiée cette distribution des données.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 1), + ('dcat:distribution / dct:title', 'shared', 'Libellé', 'Nom de la distribution.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 2), + ('dcat:distribution / dct:description', 'shared', 'Description', 'Description de la distribution.', NULL, false, 'rdf:langString', true, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 3), + ('dcat:distribution / dcat:downloadURL', 'shared', 'Lien de téléchargement direct', 'URL de téléchargement direct du ou des fichiers de la distribution.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 4), + ('dcat:distribution / dct:issued', 'shared', 'Date de publication', 'Date à laquelle la distribution a été diffusée.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 5), + ('dcat:distribution / dct:modified', 'shared', 'Date de dernière modification', 'Date de la dernière modification de la distribution.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 12), + ('dcat:distribution / dcatap:availability', 'shared', 'Disponibilité', 'Niveau de disponibilité prévu pour la distribution, permettant d''apprécier le temps pendant lequel elle est susceptible de rester accessible.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://publications.europa.eu/resource/authority/planned-availability'], NULL, NULL, 7), + ('dcat:distribution / adms:status', 'shared', 'Statut', 'Maturité de la distribution.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://publications.europa.eu/resource/authority/dataset-status','http://registre.data.developpement-durable.gouv.fr/plume/ISO19139ProgressCode'], NULL, NULL, 8), + ('dcat:distribution / dct:type', 'shared', 'Type de distribution', 'Type de distribution.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://publications.europa.eu/resource/authority/distribution-type'], NULL, NULL, 10), + ('dcat:distribution / dct:format', 'shared', 'Format de fichier', 'Format de fichier ou extension.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://publications.europa.eu/resource/authority/file-type','http://registre.data.developpement-durable.gouv.fr/plume/IanaMediaType'], NULL, NULL, 11), + ('dcat:distribution / dct:format / rdfs:label', 'shared', 'Nom', 'Libellé du format.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('dcat:distribution / dcat:compressFormat', 'shared', 'Format de compression', 'Format du fichier contenant les données sous une forme compressée, afin de réduire leur volume.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://publications.europa.eu/resource/authority/file-type','http://registre.data.developpement-durable.gouv.fr/plume/IanaMediaType'], NULL, NULL, 12), + ('dcat:distribution / dcat:compressFormat / rdfs:label', 'shared', 'Nom', 'Libellé du format.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('dcat:distribution / dcat:packageFormat', 'shared', 'Format d''empaquatage', 'Format du fichier rassemblant les différents fichiers contenant les données pour permettre leur téléchargement conjoint.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://publications.europa.eu/resource/authority/file-type','http://registre.data.developpement-durable.gouv.fr/plume/IanaMediaType'], NULL, NULL, 13), + ('dcat:distribution / dcat:packageFormat / rdfs:label', 'shared', 'Nom', 'Libellé du format.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('dcat:distribution / dcat:accessService', 'shared', 'Service', 'Service donnant accès aux données.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 14), + ('dcat:distribution / dcat:accessService / dct:title', 'shared', 'Libellé', 'Nom explicite du service de données.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, true, NULL, NULL, NULL, 0), + ('dcat:distribution / dcat:accessService / dcat:endpointURL', 'shared', 'URL de base', 'URL de base du service de données, sans aucun paramètre.', 'url', false, NULL, false, NULL, 'https://services.data.shom.fr/INSPIRE/wms/r', NULL, true, false, false, NULL, NULL, NULL, 1), + ('dcat:distribution / dcat:accessService / dct:conformsTo', 'shared', 'Conforme à', 'Standard ou référentiel de coordonnées auquel se conforme le service.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/OgcEpsgFrance','http://www.opengis.net/def/crs/EPSG/0','http://registre.data.developpement-durable.gouv.fr/plume/DataServiceStandard','http://registre.data.developpement-durable.gouv.fr/plume/IgnCrs'], NULL, NULL, 2), + ('dcat:distribution / dcat:accessService / dct:conformsTo / skos:inScheme', 'shared', 'Registre', 'Registre de référence auquel appartient le standard.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/StandardsRegister'], NULL, NULL, 0), + ('dcat:distribution / dcat:accessService / dct:conformsTo / dct:identifier', 'shared', 'Identifiant', 'Identifiant du standard, s''il y a lieu. Pour un système de coordonnées géographiques, il s''agit du code EPSG.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 1), + ('dcat:distribution / dcat:accessService / dct:conformsTo / dct:title', 'shared', 'Libellé', 'Libellé explicite du standard.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 2), + ('dcat:distribution / dcat:accessService / dct:conformsTo / owl:versionInfo', 'shared', 'Version', 'Numéro ou code de la version du standard à laquelle se conforment les données.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 3), + ('dcat:distribution / dcat:accessService / dct:conformsTo / dct:description', 'shared', 'Description', 'Description sommaire de l''objet du standard.', NULL, false, 'rdf:langString', true, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 4), + ('dcat:distribution / dcat:accessService / dct:conformsTo / dct:issued', 'shared', 'Date de publication', 'Date de publication du standard.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 5), + ('dcat:distribution / dcat:accessService / dct:conformsTo / dct:modified', 'shared', 'Date de modification', 'Date de la dernière modification du standard.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 6), + ('dcat:distribution / dcat:accessService / dct:conformsTo / dct:created', 'shared', 'Date de création', 'Date de création du standard.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 7), + ('dcat:distribution / dcat:accessService / dct:conformsTo / foaf:page', 'shared', 'Page internet', 'Chemin d''accès au standard ou URL d''une page contenant des informations sur le standard.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 8), + ('dcat:distribution / dcat:accessService / dcat:endpointDescription', 'shared', 'URL de la description', 'URL de la description technique du service, par exemple le GetCapabilities d''un service WMS.', 'url', false, NULL, false, NULL, 'https://services.data.shom.fr/INSPIRE/wms/r?service=WMS&version=1.3.0&request=GetCapabilities', NULL, true, false, false, NULL, NULL, NULL, 3), + ('dcat:distribution / dcat:accessService / dct:description', 'shared', 'Description', 'Description libre du service.', NULL, false, 'rdf:langString', true, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 4), + ('dcat:distribution / dcat:accessService / dcat:keyword', 'shared', 'Mots-clés libres', 'Mots ou très brèves expressions représentatives du service.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 5), + ('dcat:distribution / dcat:accessService / dct:type', 'shared', 'Type de service de données', 'Type de service de données.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://publications.europa.eu/resource/authority/data-service-type','http://inspire.ec.europa.eu/metadata-codelist/SpatialDataServiceType'], NULL, NULL, 6), + ('dcat:distribution / dcat:accessService / dct:accessRights', 'shared', 'Conditions d''accès', 'Contraintes réglementaires limitant l''accès au service.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://inspire.ec.europa.eu/metadata-codelist/LimitationsOnPublicAccess','http://publications.europa.eu/resource/authority/access-right','http://registre.data.developpement-durable.gouv.fr/plume/CrpaAccessLimitations','http://registre.data.developpement-durable.gouv.fr/plume/ISO19139ClassificationCode','http://registre.data.developpement-durable.gouv.fr/plume/ISO19139RestrictionCode'], NULL, NULL, 20), + ('dcat:distribution / dcat:accessService / dct:accessRights / rdfs:label', 'shared', 'Mention', 'Description des contraintes réglementaires et des modalités pratiques pour s''y conformer.', NULL, false, 'rdf:langString', true, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 1), + ('dcat:distribution / dcat:accessService / dct:license', 'shared', 'Licence', 'Licence de mise à diposition des données via le service, ou conditions d''utilisation du service.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/CrpaAuthorizedLicense','http://publications.europa.eu/resource/authority/licence'], NULL, NULL, 21), + ('dcat:distribution / dcat:accessService / dct:license / dct:type', 'shared', 'Type', 'Caractéristiques de la licence.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://purl.org/adms/licencetype/1.1'], NULL, NULL, 1), + ('dcat:distribution / dcat:accessService / dct:license / rdfs:label', 'shared', 'Termes', 'Termes de la licence.', NULL, false, 'rdf:langString', true, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 2), + ('dcat:distribution / dcat:accessService / dcat:contactPoint', 'shared', 'Point de contact', 'Entité à contacter pour obtenir des informations sur le service.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 40), + ('dcat:distribution / dcat:accessService / dcat:contactPoint / vcard:fn', 'shared', 'Nom', 'Nom du point de contact.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, false, false, true, NULL, NULL, NULL, 1), + ('dcat:distribution / dcat:accessService / dcat:contactPoint / vcard:hasEmail', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('dcat:distribution / dcat:accessService / dcat:contactPoint / vcard:hasTelephone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('dcat:distribution / dcat:accessService / dcat:contactPoint / vcard:hasURL', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('dcat:distribution / dcat:accessService / dcat:contactPoint / vcard:organization-name', 'shared', 'Appartient à', 'Le cas échéant, organisation dont le point de contact fait partie.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 5), + ('dcat:distribution / dcat:accessService / dct:publisher', 'shared', 'Éditeur', 'Organisme ou personne responsable de la mise à disposition du service.', NULL, true, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 41), + ('dcat:distribution / dcat:accessService / dct:publisher / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('dcat:distribution / dcat:accessService / dct:publisher / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('dcat:distribution / dcat:accessService / dct:publisher / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('dcat:distribution / dcat:accessService / dct:publisher / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('dcat:distribution / dcat:accessService / dct:publisher / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('dcat:distribution / dcat:accessService / dct:creator', 'shared', 'Auteur', 'Principal acteur de la création du service.', NULL, true, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 42), + ('dcat:distribution / dcat:accessService / dct:creator / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('dcat:distribution / dcat:accessService / dct:creator / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('dcat:distribution / dcat:accessService / dct:creator / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('dcat:distribution / dcat:accessService / dct:creator / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('dcat:distribution / dcat:accessService / dct:creator / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('dcat:distribution / dcat:accessService / dct:rightsHolder', 'shared', 'Propriétaire', 'Organisme ou personne qui détient des droits sur le service.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 43), + ('dcat:distribution / dcat:accessService / dct:rightsHolder / foaf:name', 'shared', 'Nom', 'Nom de l''organisation.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 0), + ('dcat:distribution / dcat:accessService / dct:rightsHolder / dct:type', 'shared', 'Type', 'Type d''organisation.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://purl.org/adms/publishertype/1.0'], NULL, NULL, 1), + ('dcat:distribution / dcat:accessService / dct:rightsHolder / foaf:mbox', 'shared', 'Courriel', 'Adresse mél.', 'email', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 2), + ('dcat:distribution / dcat:accessService / dct:rightsHolder / foaf:phone', 'shared', 'Téléphone', 'Numéro de téléphone.', 'phone', false, NULL, false, NULL, '+33-1-23-45-67-89', NULL, true, false, false, NULL, NULL, NULL, 3), + ('dcat:distribution / dcat:accessService / dct:rightsHolder / foaf:workplaceHomepage', 'shared', 'Site internet', 'Site internet.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 4), + ('dcat:distribution / dcat:accessService / dct:issued', 'shared', 'Date d''ouverture', 'Date d''ouverture du service.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 70), + ('dcat:distribution / dcat:accessService / dct:language', 'shared', 'Langues', 'Langue·s prises en charge par le service.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://publications.europa.eu/resource/authority/language'], NULL, NULL, 80), + ('dcat:distribution / dcat:accessService / dct:spatial', 'shared', 'Couverture géographique', 'Territoire couvert par le service.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/EuAdministrativeTerritoryUnitFrance','http://id.insee.fr/geo/departement','http://id.insee.fr/geo/region','http://registre.data.developpement-durable.gouv.fr/plume/InseeIndividualTerritory','http://publications.europa.eu/resource/authority/atu','http://id.insee.fr/geo/commune'], NULL, NULL, 81), + ('dcat:distribution / dcat:accessService / dct:spatial / skos:inScheme', 'shared', 'Index géographique', 'Type de lieu, index de référence pour l''identifiant (commune, département...).', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/InseeGeoIndex','http://registre.data.developpement-durable.gouv.fr/plume/ISO3166CodesCollection'], NULL, NULL, 0), + ('dcat:distribution / dcat:accessService / dct:spatial / dct:identifier', 'shared', 'Code géographique', 'Code du département, code INSEE de la commune, etc.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 1), + ('dcat:distribution / dcat:accessService / dct:spatial / skos:prefLabel', 'shared', 'Libellé', 'Dénomination explicite du lieu.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 2), + ('dcat:distribution / dcat:accessService / dct:spatial / dcat:bbox', 'shared', 'Rectangle d''emprise', 'Rectangle d''emprise (BBox), au format textuel WKT.', NULL, false, 'gsp:wktLiteral', true, NULL, ' POLYGON((646417.3289 6857521.1356, 657175.3272 6857521.1356, 657175.3272 6867076.0360, 646417.3289 6867076.0360, 646417.3289 6857521.1356))', NULL, false, false, false, NULL, ARRAY['show','bbox','rectangle']::z_plume.meta_geo_tool[], NULL, 3), + ('dcat:distribution / dcat:accessService / dct:spatial / dcat:centroid', 'shared', 'Centroïde', 'Localisant du centre géographique des données, au format textuel WKT.', NULL, false, 'gsp:wktLiteral', true, NULL, ' POINT(651796.3281 6862298.5858)', NULL, false, false, false, NULL, ARRAY['show','centroid','point']::z_plume.meta_geo_tool[], NULL, 4), + ('dcat:distribution / dcat:accessService / dct:spatial / locn:geometry', 'shared', 'Géométrie', 'Emprise géométrique, au format textuel WKT.', NULL, false, 'gsp:wktLiteral', true, NULL, ' POLYGON((646417.3289 6857521.1356, 657175.3272 6857521.1356, 657175.3272 6867076.0360, 646417.3289 6867076.0360, 646417.3289 6857521.1356))', NULL, false, false, false, NULL, ARRAY['show','point','linestring','polygon','circle']::z_plume.meta_geo_tool[], NULL, 5), + ('dcat:distribution / dcat:accessService / dcat:spatialResolutionInMeters', 'shared', 'Résolution spatiale en mètres', 'Résolution des données mises à disposition par le service, exprimée en mètres.', NULL, false, 'xsd:decimal', false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 82), + ('dcat:distribution / dcat:accessService / dqv:hasQualityMeasurement', 'shared', 'Résolution spatiale', 'Spécification du niveau de détail des données mises à disposition par le service.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 83), + ('dcat:distribution / dcat:accessService / dqv:hasQualityMeasurement / dqv:isMeasurementOf', 'shared', 'Indicateur', 'Critère d''évaluation de la résolution.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/GeoDCATMetric'], NULL, NULL, 0), + ('dcat:distribution / dcat:accessService / dqv:hasQualityMeasurement / dqv:value', 'shared', 'Valeur', 'Valeur de la résolution.', NULL, false, 'xsd:decimal', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 1), + ('dcat:distribution / dcat:accessService / dqv:hasQualityMeasurement / sdmx-attribute:unitMeasure', 'shared', 'Unité de mesure', 'Unité dans laquelle est exprimée la résolution, le cas échéant.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://publications.europa.eu/resource/authority/measurement-unit','http://qudt.org/vocab/unit'], NULL, NULL, 2), + ('dcat:distribution / dcat:accessService / dct:temporal', 'shared', 'Couverture temporelle', 'Période pour laquelle des données sont mises à disposition par le service.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 85), + ('dcat:distribution / dcat:accessService / dct:temporal / dcat:startDate', 'shared', 'Date de début', 'Date de début de la période.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 0), + ('dcat:distribution / dcat:accessService / dct:temporal / dcat:endDate', 'shared', 'Date de fin', 'Date de fin de la période.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 1), + ('dcat:distribution / dcat:accessService / dcat:temporalResolution', 'shared', 'Résolution temporelle', 'Résolution temporelle des données mises à disposition par le service.', NULL, false, 'xsd:duration', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 86), + ('dcat:distribution / adms:representationTechnique', 'shared', 'Mode de représentation géographique', 'Type de représentation technique de l''information géographique présentée par la distribution, le cas échéant.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://inspire.ec.europa.eu/metadata-codelist/SpatialRepresentationType'], NULL, NULL, 15), + ('dcat:distribution / foaf:page', 'shared', 'Documentation', 'Documentation ou page internet contenant des informations relative à la distribution.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 16), + ('dcat:distribution / dct:conformsTo', 'shared', 'Conforme à', 'Standard, schéma, référentiel de coordonnées, etc. auquel se conforment les données de la distribution.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/OgcEpsgFrance','http://www.opengis.net/def/crs/EPSG/0','http://registre.data.developpement-durable.gouv.fr/plume/IgnCrs'], NULL, NULL, 17), + ('dcat:distribution / dct:conformsTo / skos:inScheme', 'shared', 'Registre', 'Registre de référence auquel appartient le standard.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/StandardsRegister'], NULL, NULL, 0), + ('dcat:distribution / dct:conformsTo / dct:identifier', 'shared', 'Identifiant', 'Identifiant du standard, s''il y a lieu. Pour un système de coordonnées géographiques, il s''agit du code EPSG.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 1), + ('dcat:distribution / dct:conformsTo / dct:title', 'shared', 'Libellé', 'Libellé explicite du standard.', NULL, false, 'rdf:langString', false, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 2), + ('dcat:distribution / dct:conformsTo / owl:versionInfo', 'shared', 'Version', 'Numéro ou code de la version du standard à laquelle se conforment les données.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 3), + ('dcat:distribution / dct:conformsTo / dct:description', 'shared', 'Description', 'Description sommaire de l''objet du standard.', NULL, false, 'rdf:langString', true, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 4), + ('dcat:distribution / dct:conformsTo / dct:issued', 'shared', 'Date de publication', 'Date de publication du standard.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 5), + ('dcat:distribution / dct:conformsTo / dct:modified', 'shared', 'Date de modification', 'Date de la dernière modification du standard.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 6), + ('dcat:distribution / dct:conformsTo / dct:created', 'shared', 'Date de création', 'Date de création du standard.', NULL, false, 'xsd:date', false, NULL, NULL, '9999-99-99', false, false, false, NULL, NULL, NULL, 7), + ('dcat:distribution / dct:conformsTo / foaf:page', 'shared', 'Page internet', 'Chemin d''accès au standard ou URL d''une page contenant des informations sur le standard.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 8), + ('dcat:distribution / dct:language', 'shared', 'Langue', 'Langue·s des données de la distribution.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://publications.europa.eu/resource/authority/language'], NULL, NULL, 21), + ('dcat:distribution / dcat:byteSize', 'shared', 'Taille en bytes', 'Taille en bytes de la distribution.', NULL, false, 'xsd:decimal', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 22), + ('dcat:distribution / dcat:temporalResolution', 'shared', 'Résolution temporelle', 'Plus petit pas de temps significatif dans le contexte de la distribution.', NULL, false, 'xsd:duration', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 23), + ('dcat:distribution / dcat:spatialResolutionInMeters', 'shared', 'Résolution spatiale en mètres', 'Résolution des données de la distribution, exprimée en mètres.', NULL, false, 'xsd:decimal', false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 24), + ('dcat:distribution / dqv:hasQualityMeasurement', 'shared', 'Résolution spatiale', 'Spécification du niveau de détail de la distribution.', NULL, true, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 25), + ('dcat:distribution / dqv:hasQualityMeasurement / dqv:isMeasurementOf', 'shared', 'Indicateur', 'Critère d''évaluation de la résolution.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/GeoDCATMetric'], NULL, NULL, 0), + ('dcat:distribution / dqv:hasQualityMeasurement / dqv:value', 'shared', 'Valeur', 'Valeur de la résolution.', NULL, false, 'xsd:decimal', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 1), + ('dcat:distribution / dqv:hasQualityMeasurement / sdmx-attribute:unitMeasure', 'shared', 'Unité de mesure', 'Unité dans laquelle est exprimée la résolution, le cas échéant.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://publications.europa.eu/resource/authority/measurement-unit','http://qudt.org/vocab/unit'], NULL, NULL, 2), + ('dcat:distribution / dct:accessRights', 'shared', 'Conditions d''accès', 'Contraintes réglementaires limitant l''accès à la distribution.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://inspire.ec.europa.eu/metadata-codelist/LimitationsOnPublicAccess','http://publications.europa.eu/resource/authority/access-right','http://registre.data.developpement-durable.gouv.fr/plume/CrpaAccessLimitations','http://registre.data.developpement-durable.gouv.fr/plume/ISO19139ClassificationCode','http://registre.data.developpement-durable.gouv.fr/plume/ISO19139RestrictionCode'], NULL, NULL, 30), + ('dcat:distribution / dct:accessRights / rdfs:label', 'shared', 'Mention', 'Description des contraintes réglementaires et des modalités pratiques pour s''y conformer.', NULL, false, 'rdf:langString', true, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 1), + ('dcat:distribution / dct:license', 'shared', 'Licence', 'Licence sous laquelle est publiée la distribution ou conditions d''utilisation de la distribution.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/CrpaAuthorizedLicense','http://publications.europa.eu/resource/authority/licence','http://registre.data.developpement-durable.gouv.fr/plume/SpdxLicense'], NULL, NULL, 31), + ('dcat:distribution / dct:license / dct:type', 'shared', 'Type', 'Caractéristiques de la licence.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://purl.org/adms/licencetype/1.1'], NULL, NULL, 1), + ('dcat:distribution / dct:license / rdfs:label', 'shared', 'Termes', 'Termes de la licence.', NULL, false, 'rdf:langString', true, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 2), + ('dcat:distribution / dct:rights', 'shared', 'Contraintes légales', 'Autre contrainte d''ordre juridique applicable à la distribution (propriété intellectuelle, etc.).', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/ISO19139RestrictionCode'], NULL, NULL, 32), + ('dcat:distribution / dct:rights / rdfs:label', 'shared', 'Mention', 'Description des contraintes réglementaires et des modalités pratiques pour s''y conformer.', NULL, false, 'rdf:langString', true, NULL, NULL, NULL, true, true, false, NULL, NULL, NULL, 1), + ('dcat:landingPage', 'shared', 'Page internet', 'URL de la fiche de métadonnées sur internet.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 60), + ('foaf:page', 'shared', 'Documentation', 'URL d''accès à une documentation rédigée décrivant la donnée.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 61), + ('dct:isReferencedBy', 'shared', 'Cité par', 'URL d''une publication qui utilise ou évoque les données.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 62), + ('dct:relation', 'shared', 'Ressource liée', 'URL d''accès à une ressource en rapport avec les données.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, NULL, NULL, NULL, 63), + ('dct:language', 'shared', 'Langue des données', 'Langue·s des données.', 'url', false, NULL, false, NULL, NULL, NULL, true, false, false, ARRAY['http://publications.europa.eu/resource/authority/language'], NULL, NULL, 80), + ('plume:relevanceScore', 'shared', 'Score', 'Niveau de pertinence de la donnée. Plus le score est élevé plus la donnée sera mise en avant dans les résultats de recherche.', NULL, false, 'xsd:integer', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 81), + ('dct:type', 'shared', 'Type de jeu de données', 'Type de jeu de données.', 'url', false, NULL, false, NULL, NULL, NULL, false, false, false, ARRAY['http://publications.europa.eu/resource/authority/dataset-type'], NULL, NULL, 82), + ('dct:identifier', 'shared', 'Identifiant interne', 'Identifiant du jeu de données, attribué automatiquement par Plume.', NULL, false, 'xsd:string', false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 83), + ('plume:linkedRecord', 'shared', 'Fiche distante', 'Configuration d''import des métadonnées depuis une fiche de catalogue INSPIRE.', NULL, true, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 84), + ('plume:linkedRecord / dcat:endpointURL', 'shared', 'Service CSW', 'URL de base du service CSW, sans aucun paramètre.', 'url', false, NULL, false, NULL, 'http://ogc.geo-ide.developpement-durable.gouv.fr/csw/dataset-harvestable', NULL, false, false, false, NULL, NULL, NULL, 0), + ('plume:linkedRecord / dct:identifier', 'shared', 'Identifiant de la fiche', 'Identifiant de la fiche de métadonnées (et non de la ressource).', NULL, false, 'xsd:string', false, NULL, 'fr-120066022-jdd-d3d794eb-76ba-450a-9f03-6eb84662f297', NULL, false, false, false, NULL, NULL, NULL, 1), + ('foaf:isPrimaryTopicOf', 'shared', 'Informations sur les métadonnées', 'Métadonnées des métadonnées.', NULL, true, NULL, false, NULL, NULL, NULL, false, false, false, NULL, NULL, NULL, 85), + ('foaf:isPrimaryTopicOf / dct:modified', 'shared', 'Date de modification des métadonnées', 'Date et heure de la dernière modification des métadonnées. Cette propriété est renseignée automatiquement par Plume lors de la sauvegarde de la fiche de métadonnées.', NULL, false, 'xsd:dateTime', false, NULL, NULL, '9999-99-99T99:99:99', false, false, false, NULL, NULL, NULL, 0) ; + +-- Function: z_plume.meta_shared_categorie_before_insert() + +CREATE OR REPLACE FUNCTION z_plume.meta_shared_categorie_before_insert() + RETURNS trigger + LANGUAGE plpgsql + AS $BODY$ +/* Fonction exécutée par le trigger meta_shared_categorie_before_insert. + + Elle supprime les lignes pré-existantes (même valeur de "path") faisant l'objet + de commandes INSERT. Autrement dit, elle permet d'utiliser des commandes INSERT + pour réaliser des UPDATE. + + Ne vaut que pour les catégories des métadonnées communes (les seules stockées + dans z_plume.meta_shared_categorie). + + Cette fonction est nécessaire pour que l'extension PlumePg puisse initialiser + la table avec les catégories partagées, et que les modifications faites par + l'administrateur sur ces enregistrements puissent ensuite être préservées en cas + de sauvegarde/restauration (table marquée comme table de configuration de + l'extension). + +*/ +BEGIN + + DELETE FROM z_plume.meta_shared_categorie + WHERE meta_shared_categorie.path = NEW.path ; + + RETURN NEW ; + +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.meta_shared_categorie_before_insert() IS 'Fonction exécutée par le trigger meta_shared_categorie_before_insert, qui supprime les lignes pré-existantes (même valeur de "path") faisant l''objet de commandes INSERT.' ; + + +-- Trigger: meta_shared_categorie_before_insert + +CREATE TRIGGER meta_shared_categorie_before_insert + BEFORE INSERT + ON z_plume.meta_shared_categorie + FOR EACH ROW + EXECUTE PROCEDURE z_plume.meta_shared_categorie_before_insert() ; + +COMMENT ON TRIGGER meta_shared_categorie_before_insert ON z_plume.meta_shared_categorie IS 'Supprime les lignes pré-existantes (même valeur de "path") faisant l''objet de commandes INSERT.' ; + + +-- Table: z_plume.meta_local_categorie + +CREATE TABLE z_plume.meta_local_categorie + PARTITION OF z_plume.meta_categorie ( + CONSTRAINT meta_local_categorie_pkey PRIMARY KEY (path), + CONSTRAINT meta_local_categorie_path_check CHECK (path ~ '^uuid[:][0-9a-z-]{36}$'), + CONSTRAINT meta_local_categorie_is_node_check CHECK (NOT is_node), + CONSTRAINT meta_local_categorie_sources_check CHECK (sources IS NULL) + ) + FOR VALUES IN ('local') ; + +GRANT SELECT ON TABLE z_plume.meta_local_categorie TO public ; + +COMMENT ON TABLE z_plume.meta_local_categorie IS 'Catégories de métadonnées supplémentaires (ajouts locaux).' ; + +COMMENT ON COLUMN z_plume.meta_local_categorie.path IS 'Chemin SPARQL de la catégorie (identifiant unique). CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.origin IS 'Origine de la catégorie. Toujours ''local''. CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.label IS 'Libellé de la catégorie.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.description IS 'Description de la catégorie. Sera affiché sous la forme d''un texte d''aide dans le formulaire.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.special IS 'Le cas échéant, mise en forme spécifique à appliquer au champ. Valeurs autorisées : ''url'', ''email'', ''phone''.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.is_node IS 'True si la catégorie est le nom d''un groupe qui contiendra lui-même d''autres catégories et non une catégorie à laquelle sera directement associée une valeur. Par exemple, is_node vaut True pour la catégorie correspondant au point de contact (dcat:contactPoint) et False pour le nom du point de contact (dcat:contactPoint / vcard:fn). CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.datatype IS 'Type de valeur attendu pour la catégorie. Cette information détermine notamment la nature des widgets utilisés par Plume pour afficher et éditer les valeurs, ainsi que les validateurs appliqués.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.is_long_text IS 'True pour une catégorie appelant un texte de plusieurs lignes. Cette information ne sera prise en compte que si le type de valeur (datatype) est ''xsd:string'' ou ''rdf:langString''.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.rowspan IS 'Nombre de lignes occupées par le widget de saisie, s''il y a lieu de modifier le comportement par défaut de Plume. La valeur ne sera considérée que si is_long_text vaut True.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.placeholder IS 'Valeur fictive pré-affichée en tant qu''exemple dans le widget de saisie, s''il y a lieu.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.input_mask IS 'Masque de saisie, s''il y a lieu. La valeur sera ignorée si le widget utilisé pour la catégorie ne prend pas en charge ce mécanisme.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.is_multiple IS 'True si la catégorie admet plusieurs valeurs.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.unilang IS 'True si la catégorie n''admet plusieurs valeurs que si elles sont dans des langues différentes (par exemple un jeu de données n''a en principe qu''un seul titre, mais il peut être traduit). is_multiple est ignoré quand unilang vaut True.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.is_mandatory IS 'True si une valeur doit obligatoirement être saisie pour cette catégorie.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.sources IS 'Pour une catégorie prenant ses valeurs dans un ou plusieurs thésaurus, liste des sources admises. Cette information n''est pas considérée que pour les catégories locales.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.geo_tools IS 'Pour une catégorie prenant pour valeurs des géométries, liste des fonctionnalités d''aide à la saisie à proposer. Cette information ne sera considérée que si le type (datatype) est ''gsp:wktLiteral''.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.compute IS 'Ignoré pour les catégories locales.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.template_order IS 'Ordre d''apparence de la catégorie dans le formulaire. Les plus petits numéros sont affichés en premier.' ; +COMMENT ON COLUMN z_plume.meta_local_categorie.compute_params IS 'Ignoré pour les catégories locales.' ; + +-- la table est marquée comme table de configuration de l'extension +SELECT pg_extension_config_dump('z_plume.meta_local_categorie'::regclass, '') ; + + +------ 1.2 - TABLE DES MODELES ------ + +-- Sequence: z_plume.meta_template_tpl_id_seq + +CREATE SEQUENCE z_plume.meta_template_tpl_id_seq AS int ; + +-- la séquence est marquée comme table de configuration de l'extension +SELECT pg_extension_config_dump('z_plume.meta_template_tpl_id_seq'::regclass, '') ; + + +-- Table: z_plume.meta_template + +CREATE TABLE z_plume.meta_template ( + tpl_label varchar(48) NOT NULL, + sql_filter text, + md_conditions jsonb, + priority int, + comment text, + enabled boolean NOT NULL DEFAULT True, + tpl_id int PRIMARY KEY DEFAULT nextval('z_plume.meta_template_tpl_id_seq'), + CONSTRAINT meta_template_tpl_label_uni UNIQUE (tpl_label) + ) ; + +ALTER SEQUENCE z_plume.meta_template_tpl_id_seq OWNED BY z_plume.meta_template.tpl_id ; + +GRANT SELECT ON TABLE z_plume.meta_template TO public ; + +COMMENT ON TABLE z_plume.meta_template IS 'Modèles de formulaires définis pour le plugin QGIS.' ; + +COMMENT ON COLUMN z_plume.meta_template.tpl_label IS 'Nom du modèle (limité à 48 caractères).' ; +COMMENT ON COLUMN z_plume.meta_template.sql_filter IS 'Condition à remplir pour que ce modèle soit appliqué par défaut à une fiche de métadonnées, sous la forme d''un filtre SQL. On pourra utiliser $1 pour représenter le nom du schéma et $2 le nom de la table. +Par exemple : +- ''$1 ~ ANY(ARRAY[''''^r_'''', ''''^e_'''']'' appliquera le modèle aux tables des schémas des blocs "données référentielles" (préfixe ''r_'') et "données externes" (préfixe ''e_'') de la nomenclature nationale ; +- ''pg_has_role(''''g_admin'''', ''''USAGE'''')'' appliquera le modèle pour toutes les fiches de métadonnées dès lors que l''utilisateur est membre du rôle g_admin.' ; +COMMENT ON COLUMN z_plume.meta_template.md_conditions IS 'Ensemble de conditions sur les métadonnées appelant l''usage de ce modèle. Prend la forme d''une liste de dictionnaires JSON, où chaque clé est le chemin d''une catégorie et la valeur l''une des valeur prises par la catégorie. Les éléments de la liste sont joints par l''opérateur OR, chaque item des dictionnaires par l''opérateur AND. Ainsi, dans l''exemple suivant, le modèle sera retenu pour une donnée externe avec le mot-clé "IGN" (premier ensemble de conditions) ou pour une donnée publiée par l''IGN (second ensemble de conditions) : +[ + { + "plume:isExternal": True, + "dcat:keyword": "IGN" + }, + { + "dct:publisher / foaf:name": "Institut national de l''information géographique et forestière (IGN-F)" + } +]' ; +COMMENT ON COLUMN z_plume.meta_template.priority IS 'Niveau de priorité du modèle. Si un jeu de données remplit les conditions de plusieurs modèles, celui dont la priorité est la plus élevée sera retenu comme modèle par défaut.' ; +COMMENT ON COLUMN z_plume.meta_template.comment IS 'Commentaire libre.' ; +COMMENT ON COLUMN z_plume.meta_template.enabled IS 'Booléen indiquant si le modèle est actif. Les modèles désactivés n''apparaîtront pas dans la liste de modèles du plugin QGIS, même si leurs conditions d''application automatique sont remplies.' ; +COMMENT ON COLUMN z_plume.meta_template.tpl_id IS 'Identifiant unique.' ; + +-- la table est marquée comme table de configuration de l'extension +SELECT pg_extension_config_dump('z_plume.meta_template'::regclass, '') ; + + +---- 1.3 - TABLE DES ONGLETS ------ + +-- Sequence: z_plume.meta_tab_tab_id_seq + +CREATE SEQUENCE z_plume.meta_tab_tab_id_seq AS int ; + +-- la séquence est marquée comme table de configuration de l'extension +SELECT pg_extension_config_dump('z_plume.meta_tab_tab_id_seq'::regclass, '') ; + + +-- Table: z_plume.meta_tab + +CREATE TABLE z_plume.meta_tab ( + tab_label varchar(48) NOT NULL, + tab_num int, + tab_id int PRIMARY KEY DEFAULT nextval('z_plume.meta_tab_tab_id_seq'), + CONSTRAINT meta_tab_tab_label_uni UNIQUE (tab_label) + ) ; + +ALTER SEQUENCE z_plume.meta_tab_tab_id_seq OWNED BY z_plume.meta_tab.tab_id ; + +GRANT SELECT ON TABLE z_plume.meta_tab TO public ; + +COMMENT ON TABLE z_plume.meta_tab IS 'Onglets des modèles.' ; + +COMMENT ON COLUMN z_plume.meta_tab.tab_label IS 'Nom de l''onglet.' ; +COMMENT ON COLUMN z_plume.meta_tab.tab_num IS 'Numéro de l''onglet. Les onglets sont affichés du plus petit numéro au plus grand (NULL à la fin), puis par ordre alphabétique en cas d''égalité. Les numéros n''ont pas à se suivre et peuvent être répétés.' ; +COMMENT ON COLUMN z_plume.meta_tab.tab_id IS 'Identifiant unique.' ; + +-- la table est marquée comme table de configuration de l'extension +SELECT pg_extension_config_dump('z_plume.meta_tab'::regclass, '') ; + + +---- 1.4 - ASSOCIATION DES CATEGORIES AUX MODELES ------ + +-- Sequence: z_plume.meta_template_categories_tplcat_id_seq + +CREATE SEQUENCE z_plume.meta_template_categories_tplcat_id_seq AS int ; + +-- la séquence est marquée comme table de configuration de l'extension +SELECT pg_extension_config_dump('z_plume.meta_template_categories_tplcat_id_seq'::regclass, '') ; + + +-- Table: z_plume.meta_template_categories + +CREATE TABLE z_plume.meta_template_categories ( + tplcat_id int PRIMARY KEY DEFAULT nextval('z_plume.meta_template_categories_tplcat_id_seq'), + shrcat_path text, + loccat_path text, + label text, + description text, + special z_plume.meta_special, + datatype z_plume.meta_datatype, + is_long_text boolean, + rowspan int, + placeholder text, + input_mask text, + is_multiple boolean, + unilang boolean, + is_mandatory boolean, + sources text[], + geo_tools z_plume.meta_geo_tool[], + compute z_plume.meta_compute[], + template_order int, + is_read_only boolean, + compute_params jsonb, + tpl_id int NOT NULL, + tab_id int, + CONSTRAINT meta_template_categories_tpl_cat_uni UNIQUE (tpl_id, shrcat_path, loccat_path), + CONSTRAINT meta_template_categories_tpl_id_fkey FOREIGN KEY (tpl_id) + REFERENCES z_plume.meta_template (tpl_id) + ON UPDATE RESTRICT ON DELETE CASCADE, + CONSTRAINT meta_template_categories_shrcat_path_fkey FOREIGN KEY (shrcat_path) + REFERENCES z_plume.meta_shared_categorie (path) + ON UPDATE CASCADE ON DELETE CASCADE, + CONSTRAINT meta_template_categories_loccat_path_fkey FOREIGN KEY (loccat_path) + REFERENCES z_plume.meta_local_categorie (path) + ON UPDATE CASCADE ON DELETE CASCADE, + CONSTRAINT meta_template_categories_tab_id_fkey FOREIGN KEY (tab_id) + REFERENCES z_plume.meta_tab (tab_id) + ON UPDATE CASCADE ON DELETE SET NULL, + CONSTRAINT meta_template_categories_path_check CHECK ( + shrcat_path IS NULL OR loccat_path IS NULL + AND shrcat_path IS NOT NULL OR loccat_path IS NOT NULL + ), + CONSTRAINT meta_template_categories_rowspan_check CHECK (rowspan BETWEEN 1 AND 99) + ) ; + +ALTER SEQUENCE z_plume.meta_template_categories_tplcat_id_seq OWNED BY z_plume.meta_template_categories.tplcat_id ; + +GRANT SELECT ON TABLE z_plume.meta_template_categories TO public ; + +COMMENT ON TABLE z_plume.meta_template_categories IS 'Désignation des catégories utilisées par chaque modèle de formulaire. +Les autres champs permettent de personnaliser la présentation des catégories pour le modèle considéré. S''ils ne sont pas renseignés, les valeurs saisies dans meta_categorie seront utilisées. À défaut, le plugin s''appuyera sur le schéma des catégories communes (évidemment pour les catégories communes uniquement).' ; + +COMMENT ON COLUMN z_plume.meta_template_categories.tplcat_id IS 'Identifiant unique.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.tpl_id IS 'Identifiant du modèle de formulaire.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.shrcat_path IS 'Chemin N3 / identifiant de la catégorie de métadonnées (si catégorie commune).' ; +COMMENT ON COLUMN z_plume.meta_template_categories.loccat_path IS 'Chemin N3 / identifiant de la catégorie de métadonnées (si catégorie supplémentaire locale).' ; +COMMENT ON COLUMN z_plume.meta_template_categories.label IS 'Libellé de la catégorie. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.description IS 'Description de la catégorie. Sera affiché sous la forme d''un texte d''aide dans le formulaire. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.special IS 'Le cas échéant, mise en forme spécifique à appliquer au champ. Valeurs autorisées : ''url'', ''email'', ''phone''. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.datatype IS 'Type de valeur attendu pour la catégorie. Cette information détermine notamment la nature des widgets utilisés par Plume pour afficher et éditer les valeurs, ainsi que les validateurs appliqués. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.is_long_text IS 'True pour une catégorie appelant un texte de plusieurs lignes. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie. Cette information ne sera prise en compte que si le type de valeur (datatype) est ''xsd:string'' ou ''rdf:langString''.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.rowspan IS 'Nombre de lignes occupées par le widget de saisie, s''il y a lieu de modifier le comportement par défaut de Plume. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie. La valeur ne sera considérée que si is_long_text vaut True.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.placeholder IS 'Valeur fictive pré-affichée en tant qu''exemple dans le widget de saisie, s''il y a lieu. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.input_mask IS 'Masque de saisie, s''il y a lieu. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie. La valeur sera ignorée si le widget utilisé pour la catégorie ne prend pas en charge ce mécanisme.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.is_multiple IS 'True si la catégorie admet plusieurs valeurs. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.unilang IS 'True si la catégorie n''admet plusieurs valeurs que si elles sont dans des langues différentes (par exemple un jeu de données n''a en principe qu''un seul titre, mais il peut être traduit). Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie. is_multiple est ignoré quand unilang vaut True. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.is_mandatory IS 'True si une valeur doit obligatoirement être saisie pour cette catégorie. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie. À noter que ce champ permet de rendre obligatoire une catégorie commune optionnelle, pas l''inverse.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.sources IS 'Pour une catégorie prenant ses valeurs dans un ou plusieurs thésaurus, liste des sources admises. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie. Cette information n''est considérée que pour les catégories communes. Il n''est pas possible d''ajouter des sources ni de les retirer toutes - Plume reviendrait alors à la liste initiale -, mais ce champ permet de restreindre la liste à un ou plusieurs thésaurus jugés les mieux adaptés.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.geo_tools IS 'Pour une catégorie prenant pour valeurs des géométries, liste des fonctionnalités d''aide à la saisie à proposer. Cette information ne sera considérée que si le type (datatype) est ''gsp:wktLiteral''. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie. Pour retirer toutes les fonctionnalités proposées par défaut pour une catégorie commune, on saisira une liste vide.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.compute IS 'Liste des fonctionnalités de calcul à proposer. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie. Pour retirer toutes les fonctionnalités proposées par défaut pour une catégorie commune, on saisira une liste vide.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.template_order IS 'Ordre d''apparence de la catégorie dans le formulaire. Les plus petits numéros sont affichés en premier. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.is_read_only IS 'True si la catégorie est en lecture seule.' ; +COMMENT ON COLUMN z_plume.meta_template_categories.tab_id IS 'Identifiant de l''onglet du formulaire où placer la catégorie. Cette information n''est considérée que pour les catégories locales et les catégories communes de premier niveau (par exemple "dcat:distribution / dct:issued" ira nécessairement dans le même onglet que "dcat:distribution"). Pour celles-ci, si aucun onglet n''est fourni, la catégorie ira toujours dans le premier onglet cité pour le modèle dans la présente table ou, à défaut, dans un onglet "Général".' ; +COMMENT ON COLUMN z_plume.meta_template_categories.compute_params IS 'Paramètres des fonctionnalités de calcul, le cas échéant, sous une forme clé-valeur. La clé est le nom du paramètre, la valeur sa valeur. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie et qu''elle attend un ou plusieurs paramètres. Si présente, cette valeur se substitue pour le modèle considéré à la valeur renseignée dans le champ éponyme de meta_categorie.' ; + +-- la table est marquée comme table de configuration de l'extension +SELECT pg_extension_config_dump('z_plume.meta_template_categories'::regclass, '') ; + + +-- View: z_plume.meta_template_categories_full + +CREATE VIEW z_plume.meta_template_categories_full AS ( + SELECT + tc.tplcat_id, + t.tpl_label, + coalesce(tc.shrcat_path, tc.loccat_path) AS path, + c.origin, + coalesce(tc.label, c.label) AS label, + coalesce(tc.description, c.description) AS description, + coalesce(tc.special, c.special) AS special, + c.is_node, + coalesce(tc.datatype, c.datatype) AS datatype, + coalesce(tc.is_long_text, c.is_long_text) AS is_long_text, + coalesce(tc.rowspan, c.rowspan) AS rowspan, + coalesce(tc.placeholder, c.placeholder) AS placeholder, + coalesce(tc.input_mask, c.input_mask) AS input_mask, + coalesce(tc.is_multiple, c.is_multiple) AS is_multiple, + coalesce(tc.unilang, c.unilang) AS unilang, + coalesce(tc.is_mandatory, c.is_mandatory) AS is_mandatory, + coalesce(tc.sources, c.sources) AS sources, + coalesce(tc.geo_tools, c.geo_tools) AS geo_tools, + coalesce(tc.compute, c.compute) AS compute, + coalesce(tc.template_order, c.template_order) AS template_order, + tc.is_read_only, + tb.tab_label AS tab, + coalesce(tc.compute_params, c.compute_params) AS compute_params + FROM z_plume.meta_template_categories AS tc + LEFT JOIN z_plume.meta_categorie AS c + ON coalesce(tc.shrcat_path, tc.loccat_path) = c.path + LEFT JOIN z_plume.meta_template AS t + ON tc.tpl_id = t.tpl_id + LEFT JOIN z_plume.meta_tab AS tb + ON tc.tab_id = tb.tab_id + WHERE t.enabled + ) ; + +GRANT SELECT ON TABLE z_plume.meta_template_categories_full TO public ; + +COMMENT ON VIEW z_plume.meta_template_categories_full IS 'Description complète des modèles de formulaire (rassemble les informations de meta_categorie et meta_template_categories).' ; + +COMMENT ON COLUMN z_plume.meta_template_categories_full.tplcat_id IS 'Identifiant unique.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.tpl_label IS 'Nom du modèle.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.path IS 'Chemin N3 / identifiant de la catégorie.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.origin IS 'Origine de la catégorie : ''shared'' pour une catégorie commune, ''local'' pour une catégorie locale supplémentaire.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.label IS 'Libellé de la catégorie. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.description IS 'Description de la catégorie. Sera affiché sous la forme d''un texte d''aide dans le formulaire. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.special IS 'Le cas échéant, mise en forme spécifique à appliquer au champ. Valeurs autorisées : ''url'', ''email'', ''phone''. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.is_node IS 'True si la catégorie est le nom d''un groupe qui contiendra lui-même d''autres catégories et non une catégorie à laquelle sera directement associée une valeur. Par exemple, is_node vaut True pour la catégorie correspondant au point de contact (dcat:contactPoint) et False pour le nom du point de contact (dcat:contactPoint / vcard:fn).' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.datatype IS 'Type de valeur attendu pour la catégorie. Cette information détermine notamment la nature des widgets utilisés par Plume pour afficher et éditer les valeurs, ainsi que les validateurs appliqués. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.is_long_text IS 'True pour une catégorie appelant un texte de plusieurs lignes. Cette information ne sera prise en compte que si le type de valeur (datatype) est ''xsd:string'' ou ''rdf:langString''. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.rowspan IS 'Nombre de lignes occupées par le widget de saisie, s''il y a lieu de modifier le comportement par défaut de Plume. La valeur ne sera considérée que si is_long_text vaut True. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.placeholder IS 'Valeur fictive pré-affichée en tant qu''exemple dans le widget de saisie, s''il y a lieu. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.input_mask IS 'Masque de saisie, s''il y a lieu. La valeur sera ignorée si le widget utilisé pour la catégorie ne prend pas en charge ce mécanisme. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.is_multiple IS 'True si la catégorie admet plusieurs valeurs. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.unilang IS 'True si la catégorie n''admet plusieurs valeurs que si elles sont dans des langues différentes (par exemple un jeu de données n''a en principe qu''un seul titre, mais il peut être traduit). is_multiple est ignoré quand unilang vaut True. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.is_mandatory IS 'True si une valeur doit obligatoirement être saisie pour cette catégorie. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes. À noter que ce champ permet de rendre obligatoire une catégorie commune optionnelle, pas l''inverse.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.sources IS 'Pour une catégorie prenant ses valeurs dans un ou plusieurs thésaurus, liste des sources admises. Cette information n''est considérée que pour les catégories communes. Il n''est pas possible d''ajouter des sources ni de les retirer toutes - Plume reviendrait alors à la liste initiale -, mais ce champ permet de restreindre la liste à un ou plusieurs thésaurus jugés les mieux adaptés.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.geo_tools IS 'Pour une catégorie prenant pour valeurs des géométries, liste des fonctionnalités d''aide à la saisie à proposer. Cette information ne sera considérée que si le type (datatype) est ''gsp:wktLiteral''. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.compute IS 'Liste des fonctionnalités de calcul à proposer. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.template_order IS 'Ordre d''apparence de la catégorie dans le formulaire. Les plus petits numéros sont affichés en premier. Plume classe les catégories selon l''ordre spécifié par le présent modèle, puis selon l''ordre défini par le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.is_read_only IS 'True si la catégorie est en lecture seule.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.tab IS 'Nom de l''onglet du formulaire où placer la catégorie. Cette information n''est considérée que pour les catégories locales et les catégories communes de premier niveau (par exemple "dcat:distribution / dct:issued" ira nécessairement dans le même onglet que "dcat:distribution"). Pour celles-ci, si aucun onglet n''est fourni, la catégorie ira toujours dans le premier onglet cité pour le modèle ou, à défaut, dans un onglet "Général".' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.compute_params IS 'Paramètres des fonctionnalités de calcul, le cas échéant, sous une forme clé-valeur. La clé est le nom du paramètre, la valeur sa valeur. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie et qu''elle attend un ou plusieurs paramètres. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; + + +------ 1.5 - IMPORT DE MODELES PRE-CONFIGURES ------- + +-- Function: z_plume.meta_import_sample_template(text) + +CREATE OR REPLACE FUNCTION z_plume.meta_import_sample_template( + tpl_label text default NULL::text + ) + RETURNS TABLE (label text, summary text) + LANGUAGE plpgsql + AS $BODY$ +/* Importe l'un des modèles de formulaires pré-configurés (ou tous si l'argument n'est pas renseigné). + + Réexécuter la fonction sur un modèle déjà répertorié aura + pour effet de le réinitialiser. + + Si le nom de modèle fourni en argument est inconnu, la + fonction n'a aucun effet et renverra une table vide. + + Parameters + ---------- + tpl_label : text, optional + Nom du modèle à importer. + + Returns + ------- + table (label : text, summary : text) + La fonction renvoie une table listant les modèles + effectivement importés. + Le champ "label" contient le nom du modèle. + Le champ "summary" fournit un résumé des opérations + réalisées. À ce stade, il vaudra 'created' pour un modèle + qui n'était pas encore répertorié et 'updated' pour un + modèle déjà répertorié. + +*/ +DECLARE + tpl record ; + tplcat record ; + tab record ; +BEGIN + + -- boucle sur les modèles : + FOR tpl IN SELECT * FROM ( + VALUES + ( + 'Donnée externe', + '$1 ~ ANY(ARRAY[''^r_'', ''^e_''])', + '[{"plume:isExternal": true}]'::jsonb, + 10, + format( + 'Modèle pré-configuré importé via z_plume.meta_import_sample_template() le %s à %s. Appliqué automatiquement à toutes les tables et vues préfixées de ''r_'' ou ''e_'' (référentiels et données externes).', + now()::date, + left(now()::time::text, 8) + ) + ), + ( + 'Classique', + NULL, + NULL, + 5, + format( + 'Modèle pré-configuré importé via z_plume.meta_import_sample_template() le %s à %s.', + now()::date, + left(now()::time::text, 8) + ) + ), + ( + 'Basique', + '$1 ~ ''^c_''', + NULL, + 0, + format( + 'Modèle pré-configuré importé via z_plume.meta_import_sample_template() le %s à %s. Appliqué automatiquement à toutes les tables et vues préfixées de ''c_'' (consultation).', + now()::date, + left(now()::time::text, 8) + ) + ), + ( + 'INSPIRE', + NULL, + NULL, + 4, + format( + 'Modèle pré-configuré importé via z_plume.meta_import_sample_template() le %s à %s. Métadonnées obligatoires INSPIRE prises en charge par Plume.', + now()::date, + left(now()::time::text, 8) + ) + ) + ) AS t (tpl_label, sql_filter, md_conditions, priority, comment) + WHERE meta_import_sample_template.tpl_label IS NULL + OR meta_import_sample_template.tpl_label = t.tpl_label + LOOP + + -- suppression du modèle s'il existe : + DELETE FROM z_plume.meta_template + WHERE meta_template.tpl_label = tpl.tpl_label ; + + IF FOUND + THEN + RETURN QUERY SELECT tpl.tpl_label, 'updated' ; + ELSE + RETURN QUERY SELECT tpl.tpl_label, 'created' ; + END IF ; + + -- création du modèle : + INSERT INTO z_plume.meta_template + (tpl_label, sql_filter, md_conditions, priority, comment) + VALUES (tpl.tpl_label, tpl.sql_filter, tpl.md_conditions, tpl.priority, tpl.comment) ; + + -- boucle sur les onglets du modèle : + FOR tab IN SELECT * FROM ( + VALUES + -- (nom du modèle, nom de l'onglet) + ('INSPIRE', 'Général', 10), + ('INSPIRE', 'Distributions', 40), + ('INSPIRE', 'Responsables', 60) + ) AS t (tpl_label, tab_label, tab_num) + WHERE t.tpl_label = tpl.tpl_label + LOOP + + IF NOT EXISTS ( + SELECT * FROM z_plume.meta_tab + WHERE meta_tab.tab_label = tab.tab_label + ) + THEN + INSERT INTO z_plume.meta_tab + (tab_label, tab_num) VALUES (tab.tab_label, tab.tab_num) ; + END IF ; + + END LOOP ; + + -- boucle sur les associations modèle-catégories : + FOR tplcat IN SELECT * FROM ( + VALUES + -- (nom du modèle, chemin de la catégorie, vocabulaires à utiliser + -- s'il y a lieu de restreindre la liste, onglet) + ('Basique', 'adms:status', NULL, NULL), + ('Basique', 'dct:accessRights', NULL, NULL), + ('Basique', 'dct:accessRights / rdfs:label', NULL, NULL), + ('Basique', 'dct:description', NULL, NULL), + ('Basique', 'dct:modified', NULL, NULL), + ('Basique', 'dct:temporal', NULL, NULL), + ('Basique', 'dct:temporal / dcat:startDate', NULL, NULL), + ('Basique', 'dct:temporal / dcat:endDate', NULL, NULL), + ('Basique', 'dct:title', NULL, NULL), + ('Basique', 'owl:versionInfo', NULL, NULL), + + ('Classique', 'adms:versionNotes', NULL, NULL), + ('Classique', 'adms:status', NULL, NULL), + ('Classique', 'dcat:contactPoint', NULL, NULL), + ('Classique', 'dcat:contactPoint / vcard:fn', NULL, NULL), + ('Classique', 'dcat:contactPoint / vcard:hasEmail', NULL, NULL), + ('Classique', 'dcat:contactPoint / vcard:hasTelephone', NULL, NULL), + ('Classique', 'dcat:contactPoint / vcard:hasURL', NULL, NULL), + ('Classique', 'dcat:contactPoint / vcard:organization-name', NULL, NULL), + ('Classique', 'dcat:distribution', NULL, NULL), + ('Classique', 'dcat:distribution / dct:rights', NULL, NULL), + ('Classique', 'dcat:distribution / dct:rights / rdfs:label', NULL, NULL), + ('Classique', 'dcat:keyword', NULL, NULL), + ('Classique', 'dcat:landingPage', NULL, NULL), + ('Classique', 'dcat:spatialResolutionInMeters', NULL, NULL), + ('Classique', 'dcat:theme', NULL, NULL), + ('Classique', 'dct:accessRights', NULL, NULL), + ('Classique', 'dct:accessRights / rdfs:label', NULL, NULL), + ('Classique', 'dct:accrualPeriodicity', NULL, NULL), + ('Classique', 'dct:conformsTo', ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/OgcEpsgFrance', 'http://registre.data.developpement-durable.gouv.fr/plume/IgnCrs'], NULL), + ('Classique', 'dct:conformsTo / dct:description', NULL, NULL), + ('Classique', 'dct:conformsTo / dct:title', NULL, NULL), + ('Classique', 'dct:conformsTo / dct:issued', NULL, NULL), + ('Classique', 'dct:conformsTo / foaf:page', NULL, NULL), + ('Classique', 'dct:conformsTo / owl:versionInfo', NULL, NULL), + ('Classique', 'dct:created', NULL, NULL), + ('Classique', 'dct:description', NULL, NULL), + ('Classique', 'dct:identifier', NULL, NULL), + ('Classique', 'dct:modified', NULL, NULL), + ('Classique', 'dct:provenance', NULL, NULL), + ('Classique', 'dct:provenance / rdfs:label', NULL, NULL), + ('Classique', 'dct:spatial', ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/EuAdministrativeTerritoryUnitFrance', 'http://id.insee.fr/geo/departement', 'http://id.insee.fr/geo/region', 'http://registre.data.developpement-durable.gouv.fr/plume/InseeIndividualTerritory'], NULL), + ('Classique', 'dct:spatial / dct:identifier', NULL, NULL), + ('Classique', 'dct:spatial / skos:inScheme', NULL, NULL), + ('Classique', 'dct:spatial / skos:prefLabel', NULL, NULL), + ('Classique', 'dct:temporal', NULL, NULL), + ('Classique', 'dct:temporal / dcat:startDate', NULL, NULL), + ('Classique', 'dct:temporal / dcat:endDate', NULL, NULL), + ('Classique', 'dct:title', NULL, NULL), + ('Classique', 'foaf:page', NULL, NULL), + ('Classique', 'owl:versionInfo', NULL, NULL), + ('Classique', 'plume:isExternal', NULL, NULL), + + ('Donnée externe', 'adms:versionNotes', NULL, NULL), + ('Donnée externe', 'adms:status', NULL, NULL), + ('Donnée externe', 'dcat:contactPoint', NULL, NULL), + ('Donnée externe', 'dcat:contactPoint / vcard:fn', NULL, NULL), + ('Donnée externe', 'dcat:contactPoint / vcard:hasEmail', NULL, NULL), + ('Donnée externe', 'dcat:contactPoint / vcard:hasTelephone', NULL, NULL), + ('Donnée externe', 'dcat:contactPoint / vcard:hasURL', NULL, NULL), + ('Donnée externe', 'dcat:contactPoint / vcard:organization-name', NULL, NULL), + ('Donnée externe', 'dcat:distribution', NULL, NULL), + ('Donnée externe', 'dcat:distribution / dcat:accessURL', NULL, NULL), + ('Donnée externe', 'dcat:distribution / dct:issued', NULL, NULL), + ('Donnée externe', 'dcat:distribution / dct:license', NULL, NULL), + ('Donnée externe', 'dcat:distribution / dct:license / rdfs:label', NULL, NULL), + ('Donnée externe', 'dcat:distribution / dct:rights', NULL, NULL), + ('Donnée externe', 'dcat:distribution / dct:rights / rdfs:label', NULL, NULL), + ('Donnée externe', 'dcat:keyword', NULL, NULL), + ('Donnée externe', 'dcat:landingPage', NULL, NULL), + ('Donnée externe', 'dcat:theme', NULL, NULL), + ('Donnée externe', 'dct:accessRights', NULL, NULL), + ('Donnée externe', 'dct:accessRights / rdfs:label', NULL, NULL), + ('Donnée externe', 'dct:accrualPeriodicity', NULL, NULL), + ('Donnée externe', 'dct:description', NULL, NULL), + ('Donnée externe', 'dct:modified', NULL, NULL), + ('Donnée externe', 'dct:provenance', NULL, NULL), + ('Donnée externe', 'dct:provenance / rdfs:label', NULL, NULL), + ('Donnée externe', 'dct:publisher', NULL, NULL), + ('Donnée externe', 'dct:publisher / foaf:name', NULL, NULL), + ('Donnée externe', 'dct:temporal', NULL, NULL), + ('Donnée externe', 'dct:temporal / dcat:startDate', NULL, NULL), + ('Donnée externe', 'dct:temporal / dcat:endDate', NULL, NULL), + ('Donnée externe', 'dct:title', NULL, NULL), + ('Donnée externe', 'dct:spatial', ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/EuAdministrativeTerritoryUnitFrance', 'http://id.insee.fr/geo/departement', 'http://id.insee.fr/geo/region', 'http://registre.data.developpement-durable.gouv.fr/plume/InseeIndividualTerritory'], NULL), + ('Donnée externe', 'dct:spatial / dct:identifier', NULL, NULL), + ('Donnée externe', 'dct:spatial / skos:inScheme', NULL, NULL), + ('Donnée externe', 'dct:spatial / skos:prefLabel', NULL, NULL), + ('Donnée externe', 'foaf:page', NULL, NULL), + ('Donnée externe', 'owl:versionInfo', NULL, NULL), + ('Donnée externe', 'plume:isExternal', NULL, NULL), + + ('INSPIRE', 'adms:status', NULL, 'Général'), + ('INSPIRE', 'dcat:contactPoint', NULL, 'Responsables'), + ('INSPIRE', 'dcat:contactPoint / vcard:fn', NULL, NULL), + ('INSPIRE', 'dcat:contactPoint / vcard:hasEmail', NULL, NULL), + ('INSPIRE', 'dcat:contactPoint / vcard:hasTelephone', NULL, NULL), + ('INSPIRE', 'dcat:contactPoint / vcard:hasURL', NULL, NULL), + ('INSPIRE', 'dcat:contactPoint / vcard:organization-name', NULL, NULL), + ('INSPIRE', 'dcat:distribution', NULL, 'Distributions'), + ('INSPIRE', 'dcat:distribution / adms:representationTechnique', ARRAY['http://inspire.ec.europa.eu/metadata-codelist/SpatialRepresentationType'], NULL), + ('INSPIRE', 'dcat:distribution / dcat:accessService', NULL, NULL), + ('INSPIRE', 'dcat:distribution / dcat:accessService / dcat:endpointDescription', NULL, NULL), + ('INSPIRE', 'dcat:distribution / dcat:accessService / dcat:endpointURL', NULL, NULL), + ('INSPIRE', 'dcat:distribution / dcat:accessService / dct:conformsTo', ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/DataServiceStandard'], NULL), + ('INSPIRE', 'dcat:distribution / dcat:accessService / dct:type', ARRAY['http://inspire.ec.europa.eu/metadata-codelist/SpatialDataServiceType'], NULL), + ('INSPIRE', 'dcat:distribution / dcat:accessURL', ARRAY['http://inspire.ec.europa.eu/metadata-codelist/LimitationsOnPublicAccess', 'http://registre.data.developpement-durable.gouv.fr/plume/ISO19139ClassificationCode', 'http://registre.data.developpement-durable.gouv.fr/plume/ISO19139RestrictionCode'], NULL), + ('INSPIRE', 'dcat:distribution / dct:description', NULL, NULL), + ('INSPIRE', 'dcat:distribution / dct:format', NULL, NULL), + ('INSPIRE', 'dcat:distribution / dct:format / rdfs:label', NULL, NULL), + ('INSPIRE', 'dcat:distribution / dct:license', NULL, NULL), + ('INSPIRE', 'dcat:distribution / dct:license / rdfs:label', NULL, NULL), + ('INSPIRE', 'dcat:distribution / dct:rights', ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/ISO19139RestrictionCode'], NULL), + ('INSPIRE', 'dcat:distribution / dct:rights / rdfs:label', NULL, NULL), + ('INSPIRE', 'dcat:distribution / dct:title', NULL, NULL), + ('INSPIRE', 'dcat:keyword', NULL, 'Général'), + ('INSPIRE', 'dcat:spatialResolutionInMeters', NULL, 'Général'), + ('INSPIRE', 'dcat:theme', NULL, 'Général'), + ('INSPIRE', 'dct:accessRights', NULL, 'Général'), + ('INSPIRE', 'dct:accessRights / rdfs:label', NULL, NULL), + ('INSPIRE', 'dct:accrualPeriodicity', NULL, 'Général'), + ('INSPIRE', 'dct:creator', NULL, 'Responsables'), + ('INSPIRE', 'dct:creator / foaf:mbox', NULL, NULL), + ('INSPIRE', 'dct:creator / foaf:name', NULL, NULL), + ('INSPIRE', 'dct:creator / foaf:phone', NULL, NULL), + ('INSPIRE', 'dct:creator / foaf:workplaceHomepage', NULL, NULL), + ('INSPIRE', 'dct:conformsTo', ARRAY['http://registre.data.developpement-durable.gouv.fr/plume/OgcEpsgFrance', 'http://registre.data.developpement-durable.gouv.fr/plume/IgnCrs', 'http://www.opengis.net/def/crs/EPSG/0'], 'Général'), + ('INSPIRE', 'dct:conformsTo / dct:created', NULL, NULL), + ('INSPIRE', 'dct:conformsTo / dct:title', NULL, NULL), + ('INSPIRE', 'dct:conformsTo / dct:issued', NULL, NULL), + ('INSPIRE', 'dct:conformsTo / dct:modified', NULL, NULL), + ('INSPIRE', 'dct:conformsTo / foaf:page', NULL, NULL), + ('INSPIRE', 'dct:created', NULL, 'Général'), + ('INSPIRE', 'dct:description', NULL, 'Général'), + ('INSPIRE', 'dct:identifier', NULL, 'Général'), + ('INSPIRE', 'dct:issued', NULL, 'Général'), + ('INSPIRE', 'dct:language', NULL, 'Général'), + ('INSPIRE', 'dct:modified', NULL, 'Général'), + ('INSPIRE', 'dct:provenance', NULL, 'Général'), + ('INSPIRE', 'dct:provenance / rdfs:label', NULL, NULL), + ('INSPIRE', 'dct:publisher', NULL, 'Responsables'), + ('INSPIRE', 'dct:publisher / foaf:mbox', NULL, NULL), + ('INSPIRE', 'dct:publisher / foaf:name', NULL, NULL), + ('INSPIRE', 'dct:publisher / foaf:phone', NULL, NULL), + ('INSPIRE', 'dct:publisher / foaf:workplaceHomepage', NULL, NULL), + ('INSPIRE', 'dct:rightsHolder', NULL, 'Responsables'), + ('INSPIRE', 'dct:rightsHolder / foaf:mbox', NULL, NULL), + ('INSPIRE', 'dct:rightsHolder / foaf:name', NULL, NULL), + ('INSPIRE', 'dct:rightsHolder / foaf:phone', NULL, NULL), + ('INSPIRE', 'dct:rightsHolder / foaf:workplaceHomepage', NULL, NULL), + ('INSPIRE', 'dct:spatial', NULL, 'Général'), + ('INSPIRE', 'dct:spatial / dcat:bbox', NULL, NULL), + ('INSPIRE', 'dct:spatial / dct:identifier', NULL, NULL), + ('INSPIRE', 'dct:spatial / skos:inScheme', NULL, NULL), + ('INSPIRE', 'dct:spatial / skos:prefLabel', NULL, NULL), + ('INSPIRE', 'dct:temporal', NULL, 'Général'), + ('INSPIRE', 'dct:temporal / dcat:startDate', NULL, NULL), + ('INSPIRE', 'dct:temporal / dcat:endDate', NULL, NULL), + ('INSPIRE', 'dct:title', NULL, 'Général'), + ('INSPIRE', 'dqv:hasQualityMeasurement', NULL, 'Général'), + ('INSPIRE', 'dqv:hasQualityMeasurement / dqv:isMeasurementOf', NULL, NULL), + ('INSPIRE', 'dqv:hasQualityMeasurement / dqv:value', NULL, NULL), + ('INSPIRE', 'foaf:page', NULL, NULL), + ('INSPIRE', 'geodcat:custodian', NULL, 'Responsables'), + ('INSPIRE', 'geodcat:custodian / foaf:mbox', NULL, NULL), + ('INSPIRE', 'geodcat:custodian / foaf:name', NULL, NULL), + ('INSPIRE', 'geodcat:custodian / foaf:phone', NULL, NULL), + ('INSPIRE', 'geodcat:custodian / foaf:workplaceHomepage', NULL, NULL), + ('INSPIRE', 'geodcat:distributor', NULL, 'Responsables'), + ('INSPIRE', 'geodcat:distributor / foaf:mbox', NULL, NULL), + ('INSPIRE', 'geodcat:distributor / foaf:name', NULL, NULL), + ('INSPIRE', 'geodcat:distributor / foaf:phone', NULL, NULL), + ('INSPIRE', 'geodcat:distributor / foaf:workplaceHomepage', NULL, NULL), + ('INSPIRE', 'geodcat:originator', NULL, 'Responsables'), + ('INSPIRE', 'geodcat:originator / foaf:mbox', NULL, NULL), + ('INSPIRE', 'geodcat:originator / foaf:name', NULL, NULL), + ('INSPIRE', 'geodcat:originator / foaf:phone', NULL, NULL), + ('INSPIRE', 'geodcat:originator / foaf:workplaceHomepage', NULL, NULL), + ('INSPIRE', 'geodcat:principalInvestigator', NULL, 'Responsables'), + ('INSPIRE', 'geodcat:principalInvestigator / foaf:mbox', NULL, NULL), + ('INSPIRE', 'geodcat:principalInvestigator / foaf:name', NULL, NULL), + ('INSPIRE', 'geodcat:principalInvestigator / foaf:phone', NULL, NULL), + ('INSPIRE', 'geodcat:principalInvestigator / foaf:workplaceHomepage', NULL, NULL), + ('INSPIRE', 'geodcat:processor', NULL, 'Responsables'), + ('INSPIRE', 'geodcat:processor / foaf:mbox', NULL, NULL), + ('INSPIRE', 'geodcat:processor / foaf:name', NULL, NULL), + ('INSPIRE', 'geodcat:processor / foaf:phone', NULL, NULL), + ('INSPIRE', 'geodcat:processor / foaf:workplaceHomepage', NULL, NULL), + ('INSPIRE', 'geodcat:resourceProvider', NULL, 'Responsables'), + ('INSPIRE', 'geodcat:resourceProvider / foaf:mbox', NULL, NULL), + ('INSPIRE', 'geodcat:resourceProvider / foaf:name', NULL, NULL), + ('INSPIRE', 'geodcat:resourceProvider / foaf:phone', NULL, NULL), + ('INSPIRE', 'geodcat:resourceProvider / foaf:workplaceHomepage', NULL, NULL), + ('INSPIRE', 'geodcat:user', NULL, 'Responsables'), + ('INSPIRE', 'geodcat:user / foaf:mbox', NULL, NULL), + ('INSPIRE', 'geodcat:user / foaf:name', NULL, NULL), + ('INSPIRE', 'geodcat:user / foaf:phone', NULL, NULL), + ('INSPIRE', 'geodcat:user / foaf:workplaceHomepage', NULL, NULL), + ('INSPIRE', 'owl:versionInfo', NULL, 'Général') + + ) AS t (tpl_label, shrcat_path, sources, tab_label) + WHERE t.tpl_label = tpl.tpl_label + LOOP + + INSERT INTO z_plume.meta_template_categories + (tpl_id, shrcat_path, sources, tab_id) ( + SELECT + meta_template.tpl_id, + tplcat.shrcat_path, + tplcat.sources, + (SELECT meta_tab.tab_id FROM z_plume.meta_tab WHERE meta_tab.tab_label = tplcat.tab_label) + FROM z_plume.meta_template + WHERE meta_template.tpl_label = tpl.tpl_label + ) ; + + END LOOP ; + + END LOOP ; + + RETURN ; + +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.meta_import_sample_template(text) IS 'Importe l''un des modèles de formulaires pré-configurés (ou tous si l''argument n''est pas renseigné).' ; + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +--------------------------------------- +------ 2 - FONCTIONS UTILITAIRES ------ +--------------------------------------- + +-- Function: z_plume.meta_execute_sql_filter(text, text, text) + +CREATE OR REPLACE FUNCTION z_plume.meta_execute_sql_filter( + sql_filter text, schema_name text, table_name text + ) + RETURNS boolean + LANGUAGE plpgsql + AS $BODY$ +/* Détermine si un filtre SQL est vérifié. + + Le filtre peut faire référence au nom du schéma avec $1 + et au nom de la table avec $2. + + Parameters + ---------- + sql_filter : text + Un filtre SQL exprimé sous la forme d'une + chaîne de caractères. + schema_name : text + Le nom du schéma considéré. + table_name : text + Le nom de la table ou vue considérée. + + Returns + ------- + boolean + True si la condition du filtre est vérifiée. + Si le filtre n'est pas valide, la fonction renvoie NULL, + avec un message d'alerte. S'il n'y a pas de filtre, la + fonction renvoie NULL. Si le filtre est valide mais non + vérifié, la fonction renvoie False. + +*/ +DECLARE + b boolean ; +BEGIN + + IF nullif(sql_filter, '') IS NULL + THEN + RETURN NULL ; + END IF ; + + EXECUTE format('SELECT %s', sql_filter) + INTO b + USING schema_name, coalesce(table_name, '') ; + RETURN b ; + +EXCEPTION WHEN OTHERS +THEN + RAISE NOTICE 'Filtre invalide : %', sql_filter ; + RETURN NULL ; +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.meta_execute_sql_filter(text, text, text) IS 'Détermine si un filtre SQL est vérifié.' ; + + +-- Function: z_plume.meta_ante_post_description(oid, text) + +CREATE OR REPLACE FUNCTION z_plume.meta_ante_post_description( + object_oid oid, catalog_name text + ) + RETURNS text + LANGUAGE plpgsql + AS $BODY$ +/* Extrait du descriptif de l'objet ce qui précède et suit les métadonnées. + + Parameters + ---------- + object_oid : oid + L'identifiant de l'objet considéré. + catalog_name : text + Le catalogue auquel appartient l'objet. + + Returns + ------- + text + Le descriptif de l'objet expurgé de ses métadonnées, + c'est-à-dire sans les éventuelles balises + et et leur contenu. Concrètement, cette + partie du descriptif, si elle existait, est remplacée + par une chaîne de caractères vide. + + Examples + -------- + SELECT z_plume.meta_ante_post_description( + 'schema_name.table_name'::regclass, 'pg_class') ; + + Notes + ----- + L'expression régulière utilisée par cette fonction est + identique à celle du constructeur de la classe + plume.pg.description.PgDescription du plugin QGIS. Il est + impératif qu'elle le reste. + +*/ +BEGIN + + RETURN regexp_replace( + obj_description(object_oid, catalog_name), + '\n{0,2}(.*)\n{0,1}', + '' + ) ; + +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.meta_ante_post_description(oid, text) IS 'Extrait du descriptif de l''objet ce qui précède et suit les métadonnées.' ; + + +-- Function: z_plume.meta_description(oid, text) + +CREATE OR REPLACE FUNCTION z_plume.meta_description( + object_oid oid, catalog_name text + ) + RETURNS jsonb + LANGUAGE plpgsql + AS $BODY$ +/* Extrait les métadonnées du descriptif de l'objet. + + Parameters + ---------- + object_oid : oid + L'identifiant de l'objet considéré. + catalog_name : text + Le catalogue auquel appartient l'objet. + + Returns + ------- + jsonb + Les métadonnées, soit le contenu désérialisé des + éventuelles balises et . + NULL en l'absence des balises ou si leur contenu + n'était pas un JSON valide. + + Examples + -------- + SELECT z_plume.meta_description( + 'schema_name.table_name'::regclass, 'pg_class') ; + + Notes + ----- + L'expression régulière utilisée par cette fonction est + identique à celle du constructeur de la classe + plume.pg.description.PgDescription du plugin QGIS. Il est + impératif qu'elle le reste. + +*/ +BEGIN + + RETURN substring(obj_description(object_oid, catalog_name), + '\n{0,2}(.*)\n{0,1}')::jsonb ; + +EXCEPTION WHEN OTHERS THEN RETURN NULL ; +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.meta_description(oid, text) IS 'Extrait les métadonnées du descriptif de l''objet.' ; + + +-- Function: z_plume.meta_regexp_matches(text, text, text) + +CREATE OR REPLACE FUNCTION z_plume.meta_regexp_matches( + string text, pattern text, flags text DEFAULT NULL + ) + RETURNS TABLE (fragment text) + LANGUAGE plpgsql + AS $BODY$ +/* Exécute la fonction regexp_matches avec le contrôle d'erreur adéquat. + + En particulier, elle renvoie une table vide (et un + message d'alerte) au lieu d'échouer si l'expression + régulière n'était pas valide. + + Cette fonction a aussi pour effet notable d'éclater + les fragments capturés sur des lignes distinctes. + + Parameters + ---------- + string : text + Le texte dont on souhaite capturer un ou + plusieurs fragments. + pattern : text + L'expression régulière délimitant les + fragments. + flags : text, optional + Paramètres associés à l'expression régulière. + + Returns + ------- + table (fragment : text) + Une table avec un unique champ "fragment" de type + text et autant de lignes que de fragments de texte + extraits. + +*/ +DECLARE + e_mssg text ; +BEGIN + + IF nullif(pattern, '') IS NULL OR nullif(string, '') IS NULL + THEN + RETURN ; + END IF ; + + RETURN QUERY + EXECUTE 'WITH a AS (SELECT unnest(regexp_matches($1, $2, $3)) AS b) + SELECT * FROM a WHERE b IS NOT NULL' + USING string, pattern, coalesce(flags, '') ; + +EXCEPTION WHEN OTHERS +THEN + GET STACKED DIAGNOSTICS e_mssg = MESSAGE_TEXT ; + RAISE NOTICE '%', e_mssg ; + RETURN ; +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.meta_regexp_matches(text, text, text) IS 'Exécute la fonction regexp_matches avec le contrôle d''erreur adéquat' ; + + +-- Function: z_plume.is_relowner(oid) + +CREATE OR REPLACE FUNCTION z_plume.is_relowner(relid oid) + RETURNS boolean + LANGUAGE plpgsql + AS $BODY$ +/* Le rôle courant est-il propriétaire de la table ? + + Parameters + ---------- + relid : oid + L'identifiant d'une relation. S'il s'agit d'un OID + non référencé, la fonction renverra False. + + Returns + ------- + boolean + True si le rôle courant est membre du rôle propriétaire + de la table et hérite de ses privilèges. + +*/ +DECLARE + b boolean ; +BEGIN + + SELECT pg_has_role(relowner, 'USAGE') + INTO b + FROM pg_catalog.pg_class + WHERE oid = relid ; + + IF FOUND + THEN + RETURN b ; + ELSE + RETURN False ; + END IF ; + +END +$BODY$ ; + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + +--------------------------------------- +------ 3 - DATES DE MODIFICATION ------ +--------------------------------------- + +/* 3.1 - TABLE DE STOCKAGE DES DATES + 3.2 - MISE À JOUR DES DATES + 3.3 - MAINTENANCE */ + + +------ 3.1 - TABLE DE STOCKAGE DES DATES ------ + +-- Table: z_plume.stamp_timestamp + +CREATE TABLE z_plume.stamp_timestamp ( + relid oid PRIMARY KEY, + created timestamp with time zone, + modified timestamp with time zone + ) ; + +COMMENT ON TABLE z_plume.stamp_timestamp IS 'Suivi des dates de modification des tables.' ; + +COMMENT ON COLUMN z_plume.stamp_timestamp.relid IS 'Identifiant système de la table.' ; +COMMENT ON COLUMN z_plume.stamp_timestamp.created IS 'Date de création.' ; +COMMENT ON COLUMN z_plume.stamp_timestamp.modified IS 'Date de dernière modification.' ; + + +-- Function: z_plume.stamp_timestamp_access_control() + +CREATE OR REPLACE FUNCTION z_plume.stamp_timestamp_access_control() + RETURNS TRIGGER + LANGUAGE plpgsql + AS $BODY$ +/* Fonction exécutée par le déclencheur stamp_timestamp_access_control qui empêche les utilisateurs non habilités de modifier les données de stamp_timestamp. + + Elle provoque une erreur si le rôle qui exécute la + fonction n'est pas le propriétaire de la table dont + l'OID est NEW.relid / OLD.relid. + + Notes + ----- + Cette fonction et le déclencheur qui l'appelle font office + de substituts temporaires à des politiques de sécurité + niveau ligne, celles-ci n'étant pas correctement prises en + charge par PostgreSQL dans les extensions à ce stade. + + Raises + ------ + insufficient_privilege + Lorsque le rôle courant n'est pas habilité à modifier + l'enregistrement considéré de stamp_timestamp. + +*/ +BEGIN + + IF TG_OP IN ('DELETE', 'UPDATE') + THEN + IF NOT z_plume.is_relowner(OLD.relid) + THEN + RAISE EXCEPTION 'Opération interdite. Seul le propriétaire de la table est habilité à modifier ou supprimer l''enregistrement qui la concerne.' + USING ERRCODE = 'insufficient_privilege' ; + END IF ; + END IF ; + + IF TG_OP IN ('INSERT', 'UPDATE') + THEN + IF NOT z_plume.is_relowner(NEW.relid) + THEN + RAISE EXCEPTION 'Opération interdite. Seul le propriétaire de la table est habilité à modifier ou supprimer l''enregistrement qui la concerne.' + USING ERRCODE = 'insufficient_privilege' ; + END IF ; + END IF ; + + IF TG_OP = 'DELETE' + THEN + RETURN OLD ; + ELSE + RETURN NEW ; + END IF ; + +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.stamp_timestamp_access_control() IS 'Fonction exécutée par le déclencheur stamp_timestamp_access_control qui empêche les utilisateurs non habilités de modifier les données de stamp_timestamp.' ; + +-- Trigger: stamp_timestamp_access_control + +CREATE TRIGGER stamp_timestamp_access_control + BEFORE INSERT OR UPDATE OR DELETE + ON z_plume.stamp_timestamp + FOR EACH ROW + WHEN (NOT z_plume.is_relowner('z_plume.stamp_timestamp'::regclass)) + EXECUTE PROCEDURE z_plume.stamp_timestamp_access_control() ; + +COMMENT ON TRIGGER stamp_timestamp_access_control ON z_plume.stamp_timestamp IS 'Empêche les utilisateurs non habilités de modifier les données de stamp_timestamp.' ; + +GRANT SELECT, INSERT, UPDATE, DELETE ON TABLE z_plume.stamp_timestamp TO public ; + +-- Function: z_plume.stamp_timestamp_to_metadata() + +CREATE OR REPLACE FUNCTION z_plume.stamp_timestamp_to_metadata() + RETURNS trigger + LANGUAGE plpgsql + SECURITY DEFINER + AS $BODY$ +/* Fonction exécutée par le déclencheur stamp_timestamp_to_metadata qui met à jour la date de dernière modification dans les métadonnées de la table concernée. + + Cette fonction ne provoque pas d'erreur, sauf si elle est + appelée par un autre déclencheur que stamp_timestamp_to_metadata. + En cas d'échec, elle se contente d'un message de notification. Elle + n'aura pas d'effet si le descriptif de la table ne contient pas encore + de fiche de métadonnées. + + Pour qu'elle fonctionne de manière optimale, il faut que le + propriétaire de la fonction (vraisemblablement le rôle qui a + installé l'extension) soit un super-utilisateur ou qu'il soit + membre des rôles propriétaires de toutes les tables - comme c'est + le cas avec le rôle g_admin d'Asgard. + + Raises + ------ + trigger_protocol_violated + Lorsque la fonction est utilisée dans un contexte + autre que celui prévu par Plume. + +*/ +DECLARE + old_metadata jsonb ; + new_metadata jsonb := '[]'::jsonb ; + r record ; + e_mssg text ; + e_hint text ; + e_detl text ; +BEGIN + + -- comme il s'agit d'une fonction SECURITY DEFINER, on s'assure qu'elle + -- est bien appelée dans le seul contexte autorisé, à savoir par un trigger + -- stamp_timestamp_to_metadata défini sur la table z_plume.stamp_timestamp. + IF NOT TG_TABLE_NAME = 'stamp_timestamp' OR NOT TG_TABLE_SCHEMA = 'z_plume' + OR NOT TG_NAME = 'stamp_timestamp_to_metadata' + THEN + RAISE EXCEPTION 'Opération interdite. La fonction stamp_timestamp_to_metadata() ne peut être appelée que par le déclencheur stamp_timestamp_to_metadata défini sur la table z_plume.stamp_timestamp.' + USING ERRCODE = 'trigger_protocol_violated' ; + END IF ; + + BEGIN + old_metadata := z_plume.meta_description(NEW.relid, 'pg_class') ; + + IF old_metadata IS NULL + THEN + RETURN NULL ; + END IF ; + + -- boucle sur les éléments de premier niveau du JSON-LD + FOR r IN ( + SELECT + item + FROM jsonb_array_elements(old_metadata) AS t (item) + ) + LOOP + + IF r.item @> '{"@type": ["http://www.w3.org/ns/dcat#Dataset"]}' + THEN + new_metadata := new_metadata || jsonb_build_array(jsonb_set( + r.item, '{http://purl.org/dc/terms/modified}', + jsonb_build_array(jsonb_build_object('@type', + 'http://www.w3.org/2001/XMLSchema#dateTime', + '@value', NEW.modified)), + create_if_missing := True + )) ; + ELSE + new_metadata := new_metadata || jsonb_build_array(r.item) ; + END IF ; + + END LOOP ; + + EXECUTE format( + 'COMMENT ON TABLE %s IS %L ;', + NEW.relid::regclass, + regexp_replace( + obj_description(NEW.relid, 'pg_class'), + '\n{0,2}(.*)\n{0,1}', + format(' + + +%s + +', + jsonb_pretty(new_metadata) + ) + ) + ) ; + + EXCEPTION WHEN OTHERS THEN + + GET STACKED DIAGNOSTICS + e_mssg = MESSAGE_TEXT, + e_hint = PG_EXCEPTION_HINT, + e_detl = PG_EXCEPTION_DETAIL ; + + RAISE NOTICE '%', e_mssg + USING DETAIL = e_detl, + HINT = e_hint ; + END ; + + RETURN NULL ; + +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.stamp_timestamp_to_metadata() IS 'Fonction exécutée par le déclencheur stamp_timestamp_to_metadata qui enregistre la date de dernière modification dans les métadonnées de la table.' ; + +-- Trigger: stamp_timestamp_to_metadata + +CREATE TRIGGER stamp_timestamp_to_metadata + AFTER INSERT OR UPDATE + ON z_plume.stamp_timestamp + FOR EACH ROW + WHEN (NEW.modified IS NOT NULL) + EXECUTE PROCEDURE z_plume.stamp_timestamp_to_metadata() ; + +COMMENT ON TRIGGER stamp_timestamp_to_metadata ON z_plume.stamp_timestamp + IS 'Enregistre les dates de dernière modification dans les métadonnées des tables.' ; + +ALTER TABLE z_plume.stamp_timestamp DISABLE TRIGGER stamp_timestamp_to_metadata ; + + +------ 3.2 - MISE À JOUR DES DATES ------ + +-- Function: z_plume.stamp_data_edit() + +CREATE OR REPLACE FUNCTION z_plume.stamp_data_edit() + RETURNS trigger + LANGUAGE plpgsql + SECURITY DEFINER + AS $BODY$ +/* Fonction exécutée par les déclencheurs plume_stamp_data_edit qui mettent à jour la date de dernière modification des tables. + + Elle enregistre la nouvelle date de dernière modification + de la table dans la table stamp_timestamp. + + Cette fonction ne provoque pas d'erreur, sauf si elle est + appelée par un autre déclencheur que plume_stamp_data_edit. + En cas d'échec, elle se contente d'un message de notification. + + Raises + ------ + trigger_protocol_violated + Lorsque la fonction est utilisée dans un contexte + autre que celui prévu par Plume. + +*/ +DECLARE + e_mssg text ; + e_hint text ; + e_detl text ; +BEGIN + + -- comme il s'agit d'une fonction SECURITY DEFINER, on s'assure qu'elle + -- est bien appelée dans le seul contexte autorisé, à savoir par un trigger + -- plume_stamp_data_edit. + IF NOT TG_NAME = 'plume_stamp_data_edit' + THEN + RAISE EXCEPTION 'Opération interdite. La fonction stamp_data_edit() ne peut être appelée que par un déclencheur plume_stamp_data_edit.' + USING ERRCODE = 'trigger_protocol_violated' ; + END IF ; + + BEGIN + UPDATE z_plume.stamp_timestamp + SET modified = now() + WHERE relid = TG_RELID ; + + IF NOT FOUND + THEN + INSERT INTO z_plume.stamp_timestamp (relid, modified) + VALUES (TG_RELID, now()) ; + END IF ; + + EXCEPTION WHEN OTHERS THEN + + GET STACKED DIAGNOSTICS + e_mssg = MESSAGE_TEXT, + e_hint = PG_EXCEPTION_HINT, + e_detl = PG_EXCEPTION_DETAIL ; + + RAISE NOTICE '%', e_mssg + USING DETAIL = e_detl, + HINT = e_hint ; + END ; + + RETURN NULL ; + +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.stamp_data_edit() IS 'Fonction exécutée par les déclencheurs plume_stamp_data_edit qui mettent à jour la date de dernière modification des tables.' ; + + +-- Function: z_plume.stamp_create_trigger(oid) + +CREATE OR REPLACE FUNCTION z_plume.stamp_create_trigger(relid oid) + RETURNS boolean + LANGUAGE plpgsql + AS $BODY$ +/* Crée sur la table cible un déclencheur qui assurera la mise à jour de sa date de modification. + + Elle ajoute également une entrée pour la table dans + z_plume.stamp_timestamp. + + Cette fonction doit être exécutée par un rôle membre du + propriétaire de la table et disposant de droits d'écriture + sur z_plume.stamp_timestamp pour donner un résultat probant. + Néanmoins, elle ne provoque pas d'erreur. En cas d'échec, + elle se contente d'un message de notification. + + Parameters + ---------- + relid : oid + L'identifiant de la table sur laquelle le déclencheur + doit être créé. + + Returns + ------- + boolean + True si la création du déclencheur a réussi. + En cas d'échec, elle renvoie False et le détail + de l'erreur sera précisé par un message. + +*/ +DECLARE + e_mssg text ; + e_hint text ; + e_detl text ; +BEGIN + + EXECUTE format(' + CREATE TRIGGER plume_stamp_data_edit + AFTER INSERT OR DELETE OR UPDATE OR TRUNCATE + ON %1$s + FOR EACH STATEMENT + EXECUTE PROCEDURE z_plume.stamp_data_edit() ; + ALTER TRIGGER plume_stamp_data_edit ON %1$s DEPENDS ON EXTENSION plume_pg ; + COMMENT ON TRIGGER plume_stamp_data_edit ON %1$s + IS ''Mise à jour de la date de dernière modification de la table.'' ; + ', relid::regclass) ; + + -- La création du déclencheur entraîne l'exécution de + -- stamp_new_entry() qui insère une ligne dans + -- stamp_timestamp pour la table. + + RETURN True ; + +EXCEPTION WHEN OTHERS THEN + + GET STACKED DIAGNOSTICS + e_mssg = MESSAGE_TEXT, + e_hint = PG_EXCEPTION_HINT, + e_detl = PG_EXCEPTION_DETAIL ; + + RAISE NOTICE '%', e_mssg + USING DETAIL = e_detl, + HINT = e_hint ; + + RETURN False ; + +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.stamp_create_trigger(oid) IS 'Crée sur la table cible un déclencheur qui assurera la mise à jour de sa date de modification.' ; + + +-- Function: z_plume.stamp_new_entry() + +CREATE OR REPLACE FUNCTION z_plume.stamp_new_entry() + RETURNS event_trigger + LANGUAGE plpgsql + SECURITY DEFINER + AS $BODY$ +/* Référence dans stamp_timestamp la table sur laquelle un déclencheur plume_stamp_data_edit vient d'être créé. + + Cette fonction ne provoque pas d'erreur. En cas d'échec, + elle se contente d'un message de notification. + +*/ +DECLARE + obj record ; + tabid oid ; + e_mssg text ; + e_hint text ; + e_detl text ; +BEGIN + + FOR obj IN SELECT DISTINCT objid, objsubid, object_identity + FROM pg_event_trigger_ddl_commands() + WHERE object_type = 'trigger' + AND object_identity ~ '^plume_stamp_data_edit[[:space:]]on' + LOOP + + SELECT tgrelid INTO STRICT tabid + FROM pg_catalog.pg_trigger + WHERE oid = obj.objid ; + + INSERT INTO z_plume.stamp_timestamp (relid) + VALUES (tabid) + ON CONFLICT (relid) DO NOTHING ; + + END LOOP ; + +EXCEPTION WHEN OTHERS THEN + + GET STACKED DIAGNOSTICS + e_mssg = MESSAGE_TEXT, + e_hint = PG_EXCEPTION_HINT, + e_detl = PG_EXCEPTION_DETAIL ; + + RAISE NOTICE '%', e_mssg + USING DETAIL = e_detl, + HINT = e_hint ; +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.stamp_new_entry() IS 'Fonction exécutée par le déclencheur sur évènement plume_stamp_new_entry qui référence dans stamp_timestamp la table sur laquelle un déclencheur plume_stamp_data_edit vient d''être créé.' ; + +-- Event trigger: plume_stamp_new_entry + +CREATE EVENT TRIGGER plume_stamp_new_entry ON ddl_command_end + WHEN TAG IN ('CREATE TRIGGER') + EXECUTE PROCEDURE z_plume.stamp_new_entry() ; + +COMMENT ON EVENT TRIGGER plume_stamp_new_entry IS 'Référence dans stamp_timestamp la table sur laquelle un déclencheur plume_stamp_data_edit vient d''être créé.' ; + + +-- Function: z_plume.stamp_table_creation() + +CREATE OR REPLACE FUNCTION z_plume.stamp_table_creation() + RETURNS event_trigger + LANGUAGE plpgsql + SECURITY DEFINER + AS $BODY$ +/* Fonction exécutée par le déclencheur sur évènement plume_stamp_table_creation, activé sur les créations de tables. + + Elle enregistre la date de création de la table dans la + table stamp_timestamp et crée un déclencheur sur la table + créée qui permettra de suivre ses modifications. + + Elle n'a pas d'effet sur les vues et plus généralement + tous les types de relations qui ne sont pas de + simples tables. + + Cette fonction ne provoque pas d'erreur. En cas d'échec, + elle se contente d'un message de notification. + +*/ +DECLARE + obj record ; + e_mssg text ; + e_hint text ; + e_detl text ; +BEGIN + + FOR obj IN SELECT DISTINCT objid + FROM pg_event_trigger_ddl_commands() + WHERE object_type = 'table' + LOOP + + PERFORM z_plume.stamp_create_trigger(obj.objid) ; + + UPDATE z_plume.stamp_timestamp + SET created = now() + WHERE relid = obj.objid ; + + END LOOP ; + +EXCEPTION WHEN OTHERS THEN + + GET STACKED DIAGNOSTICS + e_mssg = MESSAGE_TEXT, + e_hint = PG_EXCEPTION_HINT, + e_detl = PG_EXCEPTION_DETAIL ; + + RAISE NOTICE '%', e_mssg + USING DETAIL = e_detl, + HINT = e_hint ; +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.stamp_table_creation() IS 'Fonction exécutée par le déclencheur sur évènement plume_stamp_table_creation, activé sur les créations de tables.' ; + + +-- Event trigger: plume_stamp_table_creation + +CREATE EVENT TRIGGER plume_stamp_table_creation ON ddl_command_end + WHEN TAG IN ('CREATE TABLE', 'CREATE TABLE AS', 'CREATE SCHEMA', 'SELECT INTO') + EXECUTE PROCEDURE z_plume.stamp_table_creation() ; + +ALTER EVENT TRIGGER plume_stamp_table_creation DISABLE ; + +COMMENT ON EVENT TRIGGER plume_stamp_table_creation IS 'Enregistrement des dates de création des tables et mise en place des déclencheurs assurant la mise à jour de la date de dernière modification des données.' ; + + +-- Function: z_plume.stamp_table_modification() + +CREATE OR REPLACE FUNCTION z_plume.stamp_table_modification() + RETURNS event_trigger + LANGUAGE plpgsql + SECURITY DEFINER + AS $BODY$ +/* Fonction exécutée par le déclencheur sur évènement plume_stamp_table_modification, activé par les commandes qui modifient la structure des tables. + + Elle enregistre la nouvelle date de dernière modification + de la table dans la table stamp_timestamp. + + Elle n'a pas d'effet sur les vues et plus généralement + tous les types de relations qui ne sont pas de + simples tables. + + Elle n'a pas non plus d'effet si la table modifiée n'était + pas référencée dans stamp_timestamp. + + Cette fonction ne provoque pas d'erreur. En cas d'échec, + elle se contente d'un message de notification. + +*/ +DECLARE + obj record ; + e_mssg text ; + e_hint text ; + e_detl text ; +BEGIN + + FOR obj IN SELECT DISTINCT objid + FROM pg_event_trigger_ddl_commands() + WHERE object_type = 'table' + LOOP + + UPDATE z_plume.stamp_timestamp + SET modified = now() + WHERE relid = obj.objid ; + + END LOOP ; + +EXCEPTION WHEN OTHERS THEN + + GET STACKED DIAGNOSTICS + e_mssg = MESSAGE_TEXT, + e_hint = PG_EXCEPTION_HINT, + e_detl = PG_EXCEPTION_DETAIL ; + + RAISE NOTICE '%', e_mssg + USING DETAIL = e_detl, + HINT = e_hint ; +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.stamp_table_modification() IS 'Fonction exécutée par le déclencheur sur évènement plume_stamp_table_modification, activé par les commandes qui modifient la structure des tables.' ; + + +-- Event trigger: plume_stamp_table_modification + +CREATE EVENT TRIGGER plume_stamp_table_modification ON ddl_command_end + WHEN TAG IN ('ALTER TABLE') + EXECUTE PROCEDURE z_plume.stamp_table_modification() ; + +ALTER EVENT TRIGGER plume_stamp_table_modification DISABLE ; + +COMMENT ON EVENT TRIGGER plume_stamp_table_modification IS 'Mise à jour des dates de dernière modification des tables.' ; + + +-- Function: z_plume.stamp_table_drop() + +CREATE OR REPLACE FUNCTION z_plume.stamp_table_drop() + RETURNS event_trigger + LANGUAGE plpgsql + SECURITY DEFINER + AS $BODY$ +/* Fonction exécutée par le déclencheur sur évènement plume_stamp_table_drop, activé par les commandes de suppression de tables. + + Elle supprime de la table stamp_timestamp Les + enregistrements correspondant aux tables + supprimées, s'il y en avait. + + Cette fonction ne provoque pas d'erreur. En cas d'échec, + elle se contente d'un message de notification. + +*/ +DECLARE + obj record ; + e_mssg text ; + e_hint text ; + e_detl text ; +BEGIN + + FOR obj IN SELECT DISTINCT objid + FROM pg_event_trigger_dropped_objects() + WHERE object_type = 'table' + LOOP + + DELETE FROM z_plume.stamp_timestamp + WHERE relid = obj.objid ; + + END LOOP ; + +EXCEPTION WHEN OTHERS THEN + + GET STACKED DIAGNOSTICS + e_mssg = MESSAGE_TEXT, + e_hint = PG_EXCEPTION_HINT, + e_detl = PG_EXCEPTION_DETAIL ; + + RAISE NOTICE '%', e_mssg + USING DETAIL = e_detl, + HINT = e_hint ; +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.stamp_table_drop() IS 'Fonction exécutée par le déclencheur sur évènement plume_stamp_table_drop, activé par les commandes de suppression de tables.' ; + + +-- Event trigger: plume_stamp_table_drop + +CREATE EVENT TRIGGER plume_stamp_table_drop ON sql_drop + WHEN TAG IN ('DROP TABLE', 'DROP SCHEMA', 'DROP OWNED') + EXECUTE PROCEDURE z_plume.stamp_table_drop() ; + +ALTER EVENT TRIGGER plume_stamp_table_drop DISABLE ; + +COMMENT ON EVENT TRIGGER plume_stamp_table_drop IS 'Suppression du suivi des dates de modification sur les tables supprimées.' ; + + +----- 3.3 - MAINTENANCE ------ + +-- Function: z_plume.stamp_clean_timestamp() + +CREATE OR REPLACE FUNCTION z_plume.stamp_clean_timestamp() + RETURNS int + LANGUAGE plpgsql + AS $BODY$ +/* Supprime les enregistrements de la table stamp_timestamp correspondant à des tables qui n'existent plus. + + Cette fonction doit être exécutée par le rôle + propriétaire de stamp_timestamp. + + Returns + ------- + int + Nombre de lignes supprimées. + +*/ +DECLARE + n int ; +BEGIN + + DELETE FROM z_plume.stamp_timestamp + WHERE NOT relid IN (SELECT oid FROM pg_class) ; + + GET DIAGNOSTICS n = ROW_COUNT ; + RETURN n ; + +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.stamp_clean_timestamp() IS 'Supprime les enregistrements de la table stamp_timestamp correspondant à des tables qui n''existent plus.' ; + + +-- Function: z_plume.stamp_create_triggers(text, text[], text[]) + +CREATE OR REPLACE FUNCTION z_plume.stamp_create_triggers( + target_schema text DEFAULT NULL, + schemas_include text[] DEFAULT NULL, + schemas_exclude text[] DEFAULT NULL + ) + RETURNS TABLE (schema_name name, table_name name, result text) + LANGUAGE plpgsql + AS $BODY$ +/* Crée sur les tables des schémas cibles des déclencheurs qui assureront la mise à jour de leurs dates de modification. + + Concrètement, cette fonction exécute z_plume.stamp_create_trigger(oid) + sur une sélection de schémas spécifiés par l'opérateur. Si aucun + paramètre n'est fourni, tous les schémas sont considérés à l'exception + des schémas système (dont le nom commence par 'pg_') et du schéma + information_schema. + + Si le rôle qui exécute la fonction n'est pas propriétaire + de certaines des tables de ces schémas, leurs triggers ne seront + pas créés. La fonction n'échoue pas, mais renverra False avec + des messages explicitant les erreurs rencontrées. + + La fonction ne considère que les tables simples. + + Parameters + ---------- + target_schema : text, optional + L'identifiant d'un schéma sur les tables duquel des déclencheurs + doivent être créés. + schemas_include : text[], optional + Une liste d'identifiants de schémas sur les tables desquels des + déclencheurs doivent être créés. Ce paramètre n'est pas considéré + si target_schema est fourni. + schemas_exclude : text[], optional + Si spécifié, la fonction crée des déclencheurs sur tous les schémas + hors schémas système, information_schema et les schémas qu'il liste. + Ce paramètre n'est pas considéré si target_schema ou schemas_include est + fourni. + + Returns + ------- + table (schema_name : text, table_name : text, result : text) + Une table avec trois attributs : + + * "schema_name" est le nom du schéma. + * "table_name" est le nom de la table. + * "result" est le résultat de la tentative de création du + déclencheur. Il peut valoir 'success' si la création a réussi, + 'failure' si elle a échoué (le détail de l'erreur sera alors + précisé par des messages) ou 'trigger already exists' si le + déclencheur existait déjà, la fonction n'ayant alors aucun effet. + + Exemples + -------- + SELECT * FROM z_plume.stamp_create_triggers() + SELECT * FROM z_plume.stamp_create_triggers('c_bibliotheque') + SELECT * FROM z_plume.stamp_create_triggers(schemas_exclude := 'c_bibliotheque') + +*/ +DECLARE + rel record ; + res boolean ; +BEGIN + + FOR rel in ( + SELECT nspname AS schema_name, pg_class.relname, pg_class.oid + FROM pg_catalog.pg_namespace + LEFT JOIN pg_catalog.pg_class + ON pg_namespace.oid = pg_class.relnamespace + WHERE ( + target_schema IS NOT NULL AND target_schema = nspname::text + OR schemas_include IS NOT NULL AND nspname = ANY(schemas_include) + OR schemas_exclude IS NOT NULL AND NOT nspname = ANY(schemas_exclude) + ) + AND NOT nspname ~ '^pg_' AND NOT nspname = 'information_schema' + AND relkind = 'r' + ) + LOOP + IF rel.oid IN ( + SELECT tgrelid FROM pg_catalog.pg_trigger + WHERE tgname = 'plume_stamp_data_edit' + ) + THEN + RETURN QUERY + SELECT rel.schema_name, rel.relname, 'trigger already exists' ; + ELSE + SELECT z_plume.stamp_create_trigger(rel.oid) INTO res ; + RETURN QUERY + SELECT rel.schema_name, rel.relname, + CASE WHEN res THEN 'success' ELSE 'failure' END ; + END IF ; + END LOOP ; + +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.stamp_create_triggers(text, text[], text[]) IS 'Crée sur les tables des schémas cibles des déclencheurs qui assureront la mise à jour de leurs dates de modification.' ; + + +-- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + diff --git a/postgresql/plume_pg.control b/postgresql/plume_pg.control index 69b9a514..274935f9 100644 --- a/postgresql/plume_pg.control +++ b/postgresql/plume_pg.control @@ -1,5 +1,5 @@ # extension plume_pg -default_version = '0.3.0' +default_version = '0.3.1' comment = 'PlumePg - Gestion des métadonnées du patrimoine local.' superuser = true encoding = 'UTF8' From c9198620c6ab5d8caa51f1900adc6c71eaed58ac Mon Sep 17 00:00:00 2001 From: alhyss <55992003+alhyss@users.noreply.github.com> Date: Tue, 21 May 2024 19:12:26 +0200 Subject: [PATCH 02/11] refactor: archivage PlumePg v0.3.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Le script de PlumePg v0.3.0 et le script de mise à jour depuis la version 0.2.0 sont déplacés dans le dossier "archives". --- postgresql/{ => archives}/plume_pg--0.2.0--0.3.0.sql | 0 postgresql/{ => archives}/plume_pg--0.3.0.sql | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename postgresql/{ => archives}/plume_pg--0.2.0--0.3.0.sql (100%) rename postgresql/{ => archives}/plume_pg--0.3.0.sql (100%) diff --git a/postgresql/plume_pg--0.2.0--0.3.0.sql b/postgresql/archives/plume_pg--0.2.0--0.3.0.sql similarity index 100% rename from postgresql/plume_pg--0.2.0--0.3.0.sql rename to postgresql/archives/plume_pg--0.2.0--0.3.0.sql diff --git a/postgresql/plume_pg--0.3.0.sql b/postgresql/archives/plume_pg--0.3.0.sql similarity index 100% rename from postgresql/plume_pg--0.3.0.sql rename to postgresql/archives/plume_pg--0.3.0.sql From 528c228954cf93c3d7b5b55715f86122a776461f Mon Sep 17 00:00:00 2001 From: alhyss <55992003+alhyss@users.noreply.github.com> Date: Tue, 21 May 2024 19:18:38 +0200 Subject: [PATCH 03/11] =?UTF-8?q?fix:=20suppression=20de=20la=20table=20pa?= =?UTF-8?q?rtitionn=C3=A9e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit La table partitionnée "meta_categorie" devient une vue alimentée par les deux tables "meta_shared_categorie" et "meta_local_categorie", avec un déclencheur qui répercute sur ces tables les commandes de modification sur la vue. En termes de fonctionnalités, ce changement est quasi transparent. Petits ajustements en conséquence dans un test du module plume.pg.queries et dans la fonction admin.plume_pg.query_from_shape. --- admin/plume_pg.py | 7 +- plume/pg/tests/queries_test.py | 18 +- postgresql/plume_pg--0.3.0--0.3.1.sql | 262 +++++++++++++++++++++++++- postgresql/plume_pg--0.3.1.sql | 245 +++++++++++++++++++----- 4 files changed, 467 insertions(+), 65 deletions(-) diff --git a/admin/plume_pg.py b/admin/plume_pg.py index d2356a61..00247c09 100644 --- a/admin/plume_pg.py +++ b/admin/plume_pg.py @@ -111,9 +111,8 @@ def query_from_shape(do_not_print=False): Returns ------- str - Requête ``INSERT`` sur la table ``z_plume.meta_categorie`` - de l'extension (qui mettra à jour la partition - ``z_plume.meta_shared_categorie``). + Requête ``INSERT`` sur la table ``z_plume.meta_shared_categorie`` + de l'extension. """ connection_string = ConnectionString() @@ -121,7 +120,7 @@ def query_from_shape(do_not_print=False): t = table_from_shape() conn = connect(connection_string) - s = sql.SQL("""INSERT INTO z_plume.meta_categorie ( + s = sql.SQL("""INSERT INTO z_plume.meta_shared_categorie ( path, origin, label, description, special, is_node, datatype, is_long_text, rowspan, placeholder, input_mask, is_multiple, unilang, diff --git a/plume/pg/tests/queries_test.py b/plume/pg/tests/queries_test.py index 19ad0b08..62736335 100644 --- a/plume/pg/tests/queries_test.py +++ b/plume/pg/tests/queries_test.py @@ -181,12 +181,6 @@ def test_query_get_relation_kind(self): ) ) kind_r = cur.fetchone() - cur.execute( - *query_get_relation_kind( - 'z_plume', 'meta_categorie' - ) - ) - kind_p = cur.fetchone() cur.execute( *query_get_relation_kind( 'z_plume', 'meta_template_categories_full' @@ -215,6 +209,11 @@ def test_query_get_relation_kind(self): ) SERVER serveur_bidon OPTIONS (schema_name 'schema_bidon', table_name 'table_bidon') ; + + CREATE TABLE z_plume.p_test ( + somekey text + ) + PARTITION BY LIST (somekey) ; """) cur.execute( *query_get_relation_kind( @@ -222,7 +221,14 @@ def test_query_get_relation_kind(self): ) ) kind_f = cur.fetchone() + cur.execute( + *query_get_relation_kind( + 'z_plume', 'p_test' + ) + ) + kind_p = cur.fetchone() cur.execute(""" + DROP TABLE z_plume.p_test ; DROP FOREIGN TABLE z_plume.f_test ; DROP SERVER serveur_bidon ; """) diff --git a/postgresql/plume_pg--0.3.0--0.3.1.sql b/postgresql/plume_pg--0.3.0--0.3.1.sql index 98b8d7a7..a6972015 100644 --- a/postgresql/plume_pg--0.3.0--0.3.1.sql +++ b/postgresql/plume_pg--0.3.0--0.3.1.sql @@ -39,13 +39,269 @@ -- schéma contenant les objets : z_plume -- -- objets créés par le script : --- Néant. +-- - View: z_plume.meta_categorie +-- - Function: z_plume.meta_categorie_instead_of_action() +-- - Trigger: meta_categorie_instead_of_action on z_plume.meta_categorie -- -- objets modifiés par le script : --- Néant. +-- - Table: z_plume.meta_shared_categorie +-- - Table: z_plume.meta_local_categorie -- -- objets supprimés par le script : --- Néant. +-- -Table: z_plume.meta_categorie -- -- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + +--Table: z_plume.meta_categorie + +ALTER TABLE z_plume.meta_categorie + DETACH PARTITION z_plume.meta_shared_categorie ; + +ALTER TABLE z_plume.meta_categorie + DETACH PARTITION z_plume.meta_local_categorie ; + +DROP VIEW z_plume.meta_template_categories_full ; +-- sera recréée à l'identique + +DROP TABLE z_plume.meta_categorie ; + +-- Table: z_plume.meta_shared_categorie + +ALTER TABLE z_plume.meta_shared_categorie + ALTER COLUMN path DROP DEFAULT, + ALTER COLUMN origin SET DEFAULT 'shared', + DROP CONSTRAINT meta_categorie_origin_check ; + +ALTER TABLE z_plume.meta_shared_categorie + ADD CONSTRAINT meta_categorie_origin_check CHECK (origin = 'shared') ; + +-- Table: z_plume.meta_local_categorie + +ALTER TABLE z_plume.meta_local_categorie + ALTER COLUMN origin SET DEFAULT 'local', + DROP CONSTRAINT meta_categorie_origin_check ; + +ALTER TABLE z_plume.meta_local_categorie + ADD CONSTRAINT meta_categorie_origin_check CHECK (origin = 'local') ; + +-- View: z_plume.meta_categorie + +CREATE VIEW z_plume.meta_categorie AS ( + SELECT * FROM z_plume.meta_shared_categorie + UNION + SELECT * FROM z_plume.meta_local_categorie + ORDER BY path + ) ; + +GRANT SELECT ON TABLE z_plume.meta_categorie TO public ; + +COMMENT ON VIEW z_plume.meta_categorie IS 'Catégories de métadonnées disponibles pour les modèles de formulaires.' ; + +COMMENT ON COLUMN z_plume.meta_categorie.path IS 'Chemin N3 de la catégorie (identifiant unique). CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_categorie.origin IS 'Origine de la catégorie : ''shared'' pour une catégorie commune, ''local'' pour une catégorie locale supplémentaire. CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_categorie.label IS 'Libellé de la catégorie.' ; +COMMENT ON COLUMN z_plume.meta_categorie.description IS 'Description de la catégorie. Sera affiché sous la forme d''un texte d''aide dans le formulaire.' ; +COMMENT ON COLUMN z_plume.meta_categorie.special IS 'Le cas échéant, mise en forme spécifique à appliquer au champ. Valeurs autorisées : ''url'', ''email'', ''phone''. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_categorie.is_node IS 'True si la catégorie est le nom d''un groupe qui contiendra lui-même d''autres catégories et non une catégorie à laquelle sera directement associée une valeur. Par exemple, is_node vaut True pour la catégorie correspondant au point de contact (dcat:contactPoint) et False pour le nom du point de contact (dcat:contactPoint / vcard:fn). CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_categorie.datatype IS 'Type de valeur attendu pour la catégorie. Cette information détermine notamment la nature des widgets utilisés par Plume pour afficher et éditer les valeurs, ainsi que les validateurs appliqués. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_categorie.is_long_text IS 'True pour une catégorie appelant un texte de plusieurs lignes. Cette information ne sera prise en compte que si le type de valeur (datatype) est ''xsd:string'' ou ''rdf:langString''.' ; +COMMENT ON COLUMN z_plume.meta_categorie.rowspan IS 'Nombre de lignes occupées par le widget de saisie, s''il y a lieu de modifier le comportement par défaut de Plume. La valeur ne sera considérée que si is_long_text vaut True.' ; +COMMENT ON COLUMN z_plume.meta_categorie.placeholder IS 'Valeur fictive pré-affichée en tant qu''exemple dans le widget de saisie, s''il y a lieu.' ; +COMMENT ON COLUMN z_plume.meta_categorie.input_mask IS 'Masque de saisie, s''il y a lieu. La valeur sera ignorée si le widget utilisé pour la catégorie ne prend pas en charge ce mécanisme.' ; +COMMENT ON COLUMN z_plume.meta_categorie.is_multiple IS 'True si la catégorie admet plusieurs valeurs. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_categorie.unilang IS 'True si la catégorie n''admet plusieurs valeurs que si elles sont dans des langues différentes (par exemple un jeu de données n''a en principe qu''un seul titre, mais il peut être traduit). is_multiple est ignoré quand unilang vaut True. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_categorie.is_mandatory IS 'True si une valeur doit obligatoirement être saisie pour cette catégorie. À noter que ce champ permet de rendre obligatoire une catégorie commune optionnelle, pas l''inverse.' ; +COMMENT ON COLUMN z_plume.meta_categorie.sources IS 'Pour une catégorie prenant ses valeurs dans un ou plusieurs thésaurus, liste des sources admises. Cette information n''est considérée que pour les catégories communes. Il n''est pas possible d''ajouter des sources ni de les retirer toutes - Plume reviendrait alors à la liste initiale -, mais ce champ permet de restreindre la liste à un ou plusieurs thésaurus jugés les mieux adaptés.' ; +COMMENT ON COLUMN z_plume.meta_categorie.geo_tools IS 'Pour une catégorie prenant pour valeurs des géométries, liste des fonctionnalités d''aide à la saisie à proposer. Cette information ne sera considérée que si le type (datatype) est ''gsp:wktLiteral''. Pour retirer toutes les fonctionnalités proposées par défaut pour une catégorie commune, on saisira une liste vide.' ; +COMMENT ON COLUMN z_plume.meta_categorie.compute IS 'Liste des fonctionnalités de calcul à proposer. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie. Pour retirer toutes les fonctionnalités proposées par défaut pour une catégorie commune, on saisira une liste vide.' ; +COMMENT ON COLUMN z_plume.meta_categorie.template_order IS 'Ordre d''apparence de la catégorie dans le formulaire. Les plus petits numéros sont affichés en premier.' ; +COMMENT ON COLUMN z_plume.meta_categorie.compute_params IS 'Paramètres des fonctionnalités de calcul, le cas échéant, sous une forme clé-valeur. La clé est le nom du paramètre, la valeur sa valeur. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie et qu''elle attend un ou plusieurs paramètres.' ; + +-- Function: z_plume.meta_categorie_instead_of_action() + +CREATE OR REPLACE FUNCTION z_plume.meta_categorie_instead_of_action() + RETURNS trigger + LANGUAGE plpgsql + AS $BODY$ +/* Fonction exécutée par le trigger meta_categorie_instead_of_action. + + Elle répercute la commande de l'utilisateur sur la table des + métadonnées communes ou la table des métadonnées locales, selon + la valeur du champ "origin". + +*/ +BEGIN + + IF TG_OP = 'DELETE' + THEN + + IF OLD.origin = 'shared' + THEN + DELETE FROM z_plume.meta_shared_categorie + WHERE meta_shared_categorie.path = OLD.path ; + ELSE + DELETE FROM z_plume.meta_local_categorie + WHERE meta_local_categorie.path = OLD.path ; + END IF ; + + RETURN OLD ; + + END IF ; + + IF TG_OP = 'UPDATE' + THEN + + IF OLD.origin = 'shared' + THEN + UPDATE z_plume.meta_shared_categorie + SET ( + path, origin, label, description, special, is_node, datatype, + is_long_text, rowspan, placeholder, input_mask, is_multiple, + unilang, is_mandatory, sources, geo_tools, compute, template_order, + compute_params + ) = ( + NEW.path, NEW.origin, NEW.label, NEW.description, NEW.special, NEW.is_node, NEW.datatype, + NEW.is_long_text, NEW.rowspan, NEW.placeholder, NEW.input_mask, NEW.is_multiple, + NEW.unilang, NEW.is_mandatory, NEW.sources, NEW.geo_tools, NEW.compute, NEW.template_order, + NEW.compute_params + ) + WHERE meta_shared_categorie.path = OLD.path ; + ELSE + UPDATE z_plume.meta_local_categorie + SET ( + path, origin, label, description, special, is_node, datatype, + is_long_text, rowspan, placeholder, input_mask, is_multiple, + unilang, is_mandatory, sources, geo_tools, compute, template_order, + compute_params + ) = ( + NEW.path, NEW.origin, NEW.label, NEW.description, NEW.special, NEW.is_node, NEW.datatype, + NEW.is_long_text, NEW.rowspan, NEW.placeholder, NEW.input_mask, NEW.is_multiple, + NEW.unilang, NEW.is_mandatory, NEW.sources, NEW.geo_tools, NEW.compute, NEW.template_order, + NEW.compute_params + ) + WHERE meta_local_categorie.path = OLD.path ; + END IF ; + + RETURN NEW ; + + END IF ; + + IF TG_OP = 'INSERT' + THEN + + IF NEW.origin = 'shared' + THEN + INSERT INTO z_plume.meta_shared_categorie + ( + path, origin, label, description, special, is_node, datatype, + is_long_text, rowspan, placeholder, input_mask, is_multiple, + unilang, is_mandatory, sources, geo_tools, compute, template_order, + compute_params + ) VALUES ( + NEW.path, coalesce(NEW.origin, 'shared'), NEW.label, NEW.description, NEW.special, + coalesce(NEW.is_node, False), NEW.datatype, NEW.is_long_text, NEW.rowspan, NEW.placeholder, + NEW.input_mask, NEW.is_multiple, NEW.unilang, NEW.is_mandatory, NEW.sources, NEW.geo_tools, + NEW.compute, NEW.template_order, NEW.compute_params + ) ; + ELSE + INSERT INTO z_plume.meta_local_categorie + ( + path, origin, label, description, special, is_node, datatype, + is_long_text, rowspan, placeholder, input_mask, is_multiple, + unilang, is_mandatory, sources, geo_tools, compute, template_order, + compute_params + ) VALUES ( + coalesce(NEW.path, format('uuid:%s', gen_random_uuid())), coalesce(NEW.origin, 'local'), + NEW.label, NEW.description, NEW.special, coalesce(NEW.is_node, False), NEW.datatype, + NEW.is_long_text, NEW.rowspan, NEW.placeholder, NEW.input_mask, NEW.is_multiple, + NEW.unilang, NEW.is_mandatory, NEW.sources, NEW.geo_tools, NEW.compute, NEW.template_order, + NEW.compute_params + ) ; + END IF ; + + RETURN NEW ; + + END IF ; + +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.meta_categorie_instead_of_action() IS 'Fonction exécutée par le trigger meta_categorie_instead_of_action, qui répercute l''action sur la table des métadonnées locales ou communes, selon "origin".' ; + +-- Trigger: meta_categorie_instead_of_action on z_plume.meta_categorie + +CREATE TRIGGER meta_categorie_instead_of_action + INSTEAD OF INSERT OR UPDATE OR DELETE + ON z_plume.meta_categorie + FOR EACH ROW + EXECUTE PROCEDURE z_plume.meta_categorie_instead_of_action() ; + +COMMENT ON TRIGGER meta_categorie_instead_of_action ON z_plume.meta_categorie IS 'Répercute l''action sur la table des métadonnées locales ou communes, selon "origin".' ; + + +-- View: z_plume.meta_template_categories_full + +CREATE VIEW z_plume.meta_template_categories_full AS ( + SELECT + tc.tplcat_id, + t.tpl_label, + coalesce(tc.shrcat_path, tc.loccat_path) AS path, + c.origin, + coalesce(tc.label, c.label) AS label, + coalesce(tc.description, c.description) AS description, + coalesce(tc.special, c.special) AS special, + c.is_node, + coalesce(tc.datatype, c.datatype) AS datatype, + coalesce(tc.is_long_text, c.is_long_text) AS is_long_text, + coalesce(tc.rowspan, c.rowspan) AS rowspan, + coalesce(tc.placeholder, c.placeholder) AS placeholder, + coalesce(tc.input_mask, c.input_mask) AS input_mask, + coalesce(tc.is_multiple, c.is_multiple) AS is_multiple, + coalesce(tc.unilang, c.unilang) AS unilang, + coalesce(tc.is_mandatory, c.is_mandatory) AS is_mandatory, + coalesce(tc.sources, c.sources) AS sources, + coalesce(tc.geo_tools, c.geo_tools) AS geo_tools, + coalesce(tc.compute, c.compute) AS compute, + coalesce(tc.template_order, c.template_order) AS template_order, + tc.is_read_only, + tb.tab_label AS tab, + coalesce(tc.compute_params, c.compute_params) AS compute_params + FROM z_plume.meta_template_categories AS tc + LEFT JOIN z_plume.meta_categorie AS c + ON coalesce(tc.shrcat_path, tc.loccat_path) = c.path + LEFT JOIN z_plume.meta_template AS t + ON tc.tpl_id = t.tpl_id + LEFT JOIN z_plume.meta_tab AS tb + ON tc.tab_id = tb.tab_id + WHERE t.enabled + ) ; + +GRANT SELECT ON TABLE z_plume.meta_template_categories_full TO public ; + +COMMENT ON VIEW z_plume.meta_template_categories_full IS 'Description complète des modèles de formulaire (rassemble les informations de meta_categorie et meta_template_categories).' ; + +COMMENT ON COLUMN z_plume.meta_template_categories_full.tplcat_id IS 'Identifiant unique.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.tpl_label IS 'Nom du modèle.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.path IS 'Chemin N3 / identifiant de la catégorie.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.origin IS 'Origine de la catégorie : ''shared'' pour une catégorie commune, ''local'' pour une catégorie locale supplémentaire.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.label IS 'Libellé de la catégorie. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.description IS 'Description de la catégorie. Sera affiché sous la forme d''un texte d''aide dans le formulaire. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.special IS 'Le cas échéant, mise en forme spécifique à appliquer au champ. Valeurs autorisées : ''url'', ''email'', ''phone''. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.is_node IS 'True si la catégorie est le nom d''un groupe qui contiendra lui-même d''autres catégories et non une catégorie à laquelle sera directement associée une valeur. Par exemple, is_node vaut True pour la catégorie correspondant au point de contact (dcat:contactPoint) et False pour le nom du point de contact (dcat:contactPoint / vcard:fn).' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.datatype IS 'Type de valeur attendu pour la catégorie. Cette information détermine notamment la nature des widgets utilisés par Plume pour afficher et éditer les valeurs, ainsi que les validateurs appliqués. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.is_long_text IS 'True pour une catégorie appelant un texte de plusieurs lignes. Cette information ne sera prise en compte que si le type de valeur (datatype) est ''xsd:string'' ou ''rdf:langString''. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.rowspan IS 'Nombre de lignes occupées par le widget de saisie, s''il y a lieu de modifier le comportement par défaut de Plume. La valeur ne sera considérée que si is_long_text vaut True. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.placeholder IS 'Valeur fictive pré-affichée en tant qu''exemple dans le widget de saisie, s''il y a lieu. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.input_mask IS 'Masque de saisie, s''il y a lieu. La valeur sera ignorée si le widget utilisé pour la catégorie ne prend pas en charge ce mécanisme. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.is_multiple IS 'True si la catégorie admet plusieurs valeurs. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.unilang IS 'True si la catégorie n''admet plusieurs valeurs que si elles sont dans des langues différentes (par exemple un jeu de données n''a en principe qu''un seul titre, mais il peut être traduit). is_multiple est ignoré quand unilang vaut True. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.is_mandatory IS 'True si une valeur doit obligatoirement être saisie pour cette catégorie. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes. À noter que ce champ permet de rendre obligatoire une catégorie commune optionnelle, pas l''inverse.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.sources IS 'Pour une catégorie prenant ses valeurs dans un ou plusieurs thésaurus, liste des sources admises. Cette information n''est considérée que pour les catégories communes. Il n''est pas possible d''ajouter des sources ni de les retirer toutes - Plume reviendrait alors à la liste initiale -, mais ce champ permet de restreindre la liste à un ou plusieurs thésaurus jugés les mieux adaptés.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.geo_tools IS 'Pour une catégorie prenant pour valeurs des géométries, liste des fonctionnalités d''aide à la saisie à proposer. Cette information ne sera considérée que si le type (datatype) est ''gsp:wktLiteral''. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.compute IS 'Liste des fonctionnalités de calcul à proposer. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.template_order IS 'Ordre d''apparence de la catégorie dans le formulaire. Les plus petits numéros sont affichés en premier. Plume classe les catégories selon l''ordre spécifié par le présent modèle, puis selon l''ordre défini par le schéma des métadonnées communes.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.is_read_only IS 'True si la catégorie est en lecture seule.' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.tab IS 'Nom de l''onglet du formulaire où placer la catégorie. Cette information n''est considérée que pour les catégories locales et les catégories communes de premier niveau (par exemple "dcat:distribution / dct:issued" ira nécessairement dans le même onglet que "dcat:distribution"). Pour celles-ci, si aucun onglet n''est fourni, la catégorie ira toujours dans le premier onglet cité pour le modèle ou, à défaut, dans un onglet "Général".' ; +COMMENT ON COLUMN z_plume.meta_template_categories_full.compute_params IS 'Paramètres des fonctionnalités de calcul, le cas échéant, sous une forme clé-valeur. La clé est le nom du paramètre, la valeur sa valeur. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie et qu''elle attend un ou plusieurs paramètres. Le cas échéant, cette valeur se substituera pour le modèle considéré à la valeur renseignée dans le schéma des métadonnées communes.' ; + diff --git a/postgresql/plume_pg--0.3.1.sql b/postgresql/plume_pg--0.3.1.sql index ad1117d2..bc81c7f9 100644 --- a/postgresql/plume_pg--0.3.1.sql +++ b/postgresql/plume_pg--0.3.1.sql @@ -43,11 +43,13 @@ -- - Type: z_plume.meta_datatype -- - Type: z_plume.meta_geo_tool -- - Type: z_plume.meta_compute --- - Table: z_plume.meta_categorie -- - Table: z_plume.meta_shared_categorie -- - Function: z_plume.meta_shared_categorie_before_insert() --- - Trigger: meta_shared_categorie_before_insert +-- - Trigger: meta_shared_categorie_before_insert on z_plume.meta_shared_categorie -- - Table: z_plume.meta_local_categorie +-- - View: z_plume.meta_categorie +-- - Function: z_plume.meta_categorie_instead_of_action() +-- - Trigger: meta_categorie_instead_of_action on z_plume.meta_categorie -- - Sequence: z_plume.meta_template_tpl_id_seq -- - Table: z_plume.meta_template -- - Sequence: z_plume.meta_tab_tab_id_seq @@ -63,7 +65,7 @@ -- - Function: z_plume.is_relowner(oid) -- - Table: z_plume.stamp_timestamp -- - Function: stamp_timestamp_access_control() --- - Trigger: stamp_timestamp_access_control +-- - Trigger: stamp_timestamp_access_control on z_plume.stamp_timestamp -- - Function: stamp_timestamp_to_metadata() -- - Trigger: stamp_timestamp_to_metadata -- - Function: z_plume.stamp_data_edit() @@ -202,11 +204,11 @@ CREATE CAST (text[] AS z_plume.meta_compute[]) AS IMPLICIT ; ---Table: z_plume.meta_categorie +-- Table: z_plume.meta_shared_categorie -CREATE TABLE z_plume.meta_categorie ( - path text NOT NULL DEFAULT format('uuid:%s', gen_random_uuid()), - origin text NOT NULL DEFAULT 'local', +CREATE TABLE z_plume.meta_shared_categorie ( + path text PRIMARY KEY, + origin text NOT NULL DEFAULT 'shared', label text NOT NULL, description text, special z_plume.meta_special, @@ -224,43 +226,9 @@ CREATE TABLE z_plume.meta_categorie ( compute z_plume.meta_compute[], template_order int, compute_params jsonb, - CONSTRAINT meta_categorie_origin_check CHECK (origin IN ('local', 'shared')), + CONSTRAINT meta_categorie_origin_check CHECK (origin = 'shared'), CONSTRAINT meta_categorie_rowspan_check CHECK (rowspan BETWEEN 1 AND 99) - ) - PARTITION BY LIST (origin) ; - -GRANT SELECT ON TABLE z_plume.meta_categorie TO public ; - -COMMENT ON TABLE z_plume.meta_categorie IS 'Catégories de métadonnées disponibles pour les modèles de formulaires.' ; - -COMMENT ON COLUMN z_plume.meta_categorie.path IS 'Chemin N3 de la catégorie (identifiant unique). CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; -COMMENT ON COLUMN z_plume.meta_categorie.origin IS 'Origine de la catégorie : ''shared'' pour une catégorie commune, ''local'' pour une catégorie locale supplémentaire. CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; -COMMENT ON COLUMN z_plume.meta_categorie.label IS 'Libellé de la catégorie.' ; -COMMENT ON COLUMN z_plume.meta_categorie.description IS 'Description de la catégorie. Sera affiché sous la forme d''un texte d''aide dans le formulaire.' ; -COMMENT ON COLUMN z_plume.meta_categorie.special IS 'Le cas échéant, mise en forme spécifique à appliquer au champ. Valeurs autorisées : ''url'', ''email'', ''phone''. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; -COMMENT ON COLUMN z_plume.meta_categorie.is_node IS 'True si la catégorie est le nom d''un groupe qui contiendra lui-même d''autres catégories et non une catégorie à laquelle sera directement associée une valeur. Par exemple, is_node vaut True pour la catégorie correspondant au point de contact (dcat:contactPoint) et False pour le nom du point de contact (dcat:contactPoint / vcard:fn). CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; -COMMENT ON COLUMN z_plume.meta_categorie.datatype IS 'Type de valeur attendu pour la catégorie. Cette information détermine notamment la nature des widgets utilisés par Plume pour afficher et éditer les valeurs, ainsi que les validateurs appliqués. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; -COMMENT ON COLUMN z_plume.meta_categorie.is_long_text IS 'True pour une catégorie appelant un texte de plusieurs lignes. Cette information ne sera prise en compte que si le type de valeur (datatype) est ''xsd:string'' ou ''rdf:langString''.' ; -COMMENT ON COLUMN z_plume.meta_categorie.rowspan IS 'Nombre de lignes occupées par le widget de saisie, s''il y a lieu de modifier le comportement par défaut de Plume. La valeur ne sera considérée que si is_long_text vaut True.' ; -COMMENT ON COLUMN z_plume.meta_categorie.placeholder IS 'Valeur fictive pré-affichée en tant qu''exemple dans le widget de saisie, s''il y a lieu.' ; -COMMENT ON COLUMN z_plume.meta_categorie.input_mask IS 'Masque de saisie, s''il y a lieu. La valeur sera ignorée si le widget utilisé pour la catégorie ne prend pas en charge ce mécanisme.' ; -COMMENT ON COLUMN z_plume.meta_categorie.is_multiple IS 'True si la catégorie admet plusieurs valeurs. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; -COMMENT ON COLUMN z_plume.meta_categorie.unilang IS 'True si la catégorie n''admet plusieurs valeurs que si elles sont dans des langues différentes (par exemple un jeu de données n''a en principe qu''un seul titre, mais il peut être traduit). is_multiple est ignoré quand unilang vaut True. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; -COMMENT ON COLUMN z_plume.meta_categorie.is_mandatory IS 'True si une valeur doit obligatoirement être saisie pour cette catégorie. À noter que ce champ permet de rendre obligatoire une catégorie commune optionnelle, pas l''inverse.' ; -COMMENT ON COLUMN z_plume.meta_categorie.sources IS 'Pour une catégorie prenant ses valeurs dans un ou plusieurs thésaurus, liste des sources admises. Cette information n''est considérée que pour les catégories communes. Il n''est pas possible d''ajouter des sources ni de les retirer toutes - Plume reviendrait alors à la liste initiale -, mais ce champ permet de restreindre la liste à un ou plusieurs thésaurus jugés les mieux adaptés.' ; -COMMENT ON COLUMN z_plume.meta_categorie.geo_tools IS 'Pour une catégorie prenant pour valeurs des géométries, liste des fonctionnalités d''aide à la saisie à proposer. Cette information ne sera considérée que si le type (datatype) est ''gsp:wktLiteral''. Pour retirer toutes les fonctionnalités proposées par défaut pour une catégorie commune, on saisira une liste vide.' ; -COMMENT ON COLUMN z_plume.meta_categorie.compute IS 'Liste des fonctionnalités de calcul à proposer. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie. Pour retirer toutes les fonctionnalités proposées par défaut pour une catégorie commune, on saisira une liste vide.' ; -COMMENT ON COLUMN z_plume.meta_categorie.template_order IS 'Ordre d''apparence de la catégorie dans le formulaire. Les plus petits numéros sont affichés en premier.' ; -COMMENT ON COLUMN z_plume.meta_categorie.compute_params IS 'Paramètres des fonctionnalités de calcul, le cas échéant, sous une forme clé-valeur. La clé est le nom du paramètre, la valeur sa valeur. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie et qu''elle attend un ou plusieurs paramètres.' ; - - --- Table: z_plume.meta_shared_categorie - -CREATE TABLE z_plume.meta_shared_categorie - PARTITION OF z_plume.meta_categorie ( - CONSTRAINT meta_shared_categorie_pkey PRIMARY KEY (path) - ) - FOR VALUES IN ('shared') ; + ) ; GRANT SELECT ON TABLE z_plume.meta_shared_categorie TO public ; @@ -290,7 +258,7 @@ COMMENT ON COLUMN z_plume.meta_shared_categorie.compute_params IS 'Paramètres d SELECT pg_extension_config_dump('z_plume.meta_shared_categorie'::regclass, '') ; -- extraction du schéma SHACL -INSERT INTO z_plume.meta_categorie ( +INSERT INTO z_plume.meta_shared_categorie ( path, origin, label, description, special, is_node, datatype, is_long_text, rowspan, placeholder, input_mask, is_multiple, unilang, @@ -574,14 +542,32 @@ COMMENT ON TRIGGER meta_shared_categorie_before_insert ON z_plume.meta_shared_ca -- Table: z_plume.meta_local_categorie -CREATE TABLE z_plume.meta_local_categorie - PARTITION OF z_plume.meta_categorie ( - CONSTRAINT meta_local_categorie_pkey PRIMARY KEY (path), - CONSTRAINT meta_local_categorie_path_check CHECK (path ~ '^uuid[:][0-9a-z-]{36}$'), - CONSTRAINT meta_local_categorie_is_node_check CHECK (NOT is_node), - CONSTRAINT meta_local_categorie_sources_check CHECK (sources IS NULL) - ) - FOR VALUES IN ('local') ; +CREATE TABLE z_plume.meta_local_categorie ( + path text PRIMARY KEY DEFAULT format('uuid:%s', gen_random_uuid()), + origin text NOT NULL DEFAULT 'local', + label text NOT NULL, + description text, + special z_plume.meta_special, + is_node boolean NOT NULL DEFAULT False, + datatype z_plume.meta_datatype, + is_long_text boolean, + rowspan int, + placeholder text, + input_mask text, + is_multiple boolean, + unilang boolean, + is_mandatory boolean, + sources text[], + geo_tools z_plume.meta_geo_tool[], + compute z_plume.meta_compute[], + template_order int, + compute_params jsonb, + CONSTRAINT meta_categorie_origin_check CHECK (origin = 'local'), + CONSTRAINT meta_categorie_rowspan_check CHECK (rowspan BETWEEN 1 AND 99), + CONSTRAINT meta_local_categorie_path_check CHECK (path ~ '^uuid[:][0-9a-z-]{36}$'), + CONSTRAINT meta_local_categorie_is_node_check CHECK (NOT is_node), + CONSTRAINT meta_local_categorie_sources_check CHECK (sources IS NULL) + ) ; GRANT SELECT ON TABLE z_plume.meta_local_categorie TO public ; @@ -611,6 +597,161 @@ COMMENT ON COLUMN z_plume.meta_local_categorie.compute_params IS 'Ignoré pour l SELECT pg_extension_config_dump('z_plume.meta_local_categorie'::regclass, '') ; +-- View: z_plume.meta_categorie + +CREATE VIEW z_plume.meta_categorie AS ( + SELECT * FROM z_plume.meta_shared_categorie + UNION + SELECT * FROM z_plume.meta_local_categorie + ORDER BY path + ) ; + +GRANT SELECT ON TABLE z_plume.meta_categorie TO public ; + +COMMENT ON VIEW z_plume.meta_categorie IS 'Catégories de métadonnées disponibles pour les modèles de formulaires.' ; + +COMMENT ON COLUMN z_plume.meta_categorie.path IS 'Chemin N3 de la catégorie (identifiant unique). CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_categorie.origin IS 'Origine de la catégorie : ''shared'' pour une catégorie commune, ''local'' pour une catégorie locale supplémentaire. CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_categorie.label IS 'Libellé de la catégorie.' ; +COMMENT ON COLUMN z_plume.meta_categorie.description IS 'Description de la catégorie. Sera affiché sous la forme d''un texte d''aide dans le formulaire.' ; +COMMENT ON COLUMN z_plume.meta_categorie.special IS 'Le cas échéant, mise en forme spécifique à appliquer au champ. Valeurs autorisées : ''url'', ''email'', ''phone''. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_categorie.is_node IS 'True si la catégorie est le nom d''un groupe qui contiendra lui-même d''autres catégories et non une catégorie à laquelle sera directement associée une valeur. Par exemple, is_node vaut True pour la catégorie correspondant au point de contact (dcat:contactPoint) et False pour le nom du point de contact (dcat:contactPoint / vcard:fn). CE CHAMP EST GENERE AUTOMATIQUEMENT, NE PAS MODIFIER MANUELLEMENT.' ; +COMMENT ON COLUMN z_plume.meta_categorie.datatype IS 'Type de valeur attendu pour la catégorie. Cette information détermine notamment la nature des widgets utilisés par Plume pour afficher et éditer les valeurs, ainsi que les validateurs appliqués. Pour les catégories communes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_categorie.is_long_text IS 'True pour une catégorie appelant un texte de plusieurs lignes. Cette information ne sera prise en compte que si le type de valeur (datatype) est ''xsd:string'' ou ''rdf:langString''.' ; +COMMENT ON COLUMN z_plume.meta_categorie.rowspan IS 'Nombre de lignes occupées par le widget de saisie, s''il y a lieu de modifier le comportement par défaut de Plume. La valeur ne sera considérée que si is_long_text vaut True.' ; +COMMENT ON COLUMN z_plume.meta_categorie.placeholder IS 'Valeur fictive pré-affichée en tant qu''exemple dans le widget de saisie, s''il y a lieu.' ; +COMMENT ON COLUMN z_plume.meta_categorie.input_mask IS 'Masque de saisie, s''il y a lieu. La valeur sera ignorée si le widget utilisé pour la catégorie ne prend pas en charge ce mécanisme.' ; +COMMENT ON COLUMN z_plume.meta_categorie.is_multiple IS 'True si la catégorie admet plusieurs valeurs. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_categorie.unilang IS 'True si la catégorie n''admet plusieurs valeurs que si elles sont dans des langues différentes (par exemple un jeu de données n''a en principe qu''un seul titre, mais il peut être traduit). is_multiple est ignoré quand unilang vaut True. Pour les catégories commnes, les modifications apportées à ce champ ne seront pas prises en compte.' ; +COMMENT ON COLUMN z_plume.meta_categorie.is_mandatory IS 'True si une valeur doit obligatoirement être saisie pour cette catégorie. À noter que ce champ permet de rendre obligatoire une catégorie commune optionnelle, pas l''inverse.' ; +COMMENT ON COLUMN z_plume.meta_categorie.sources IS 'Pour une catégorie prenant ses valeurs dans un ou plusieurs thésaurus, liste des sources admises. Cette information n''est considérée que pour les catégories communes. Il n''est pas possible d''ajouter des sources ni de les retirer toutes - Plume reviendrait alors à la liste initiale -, mais ce champ permet de restreindre la liste à un ou plusieurs thésaurus jugés les mieux adaptés.' ; +COMMENT ON COLUMN z_plume.meta_categorie.geo_tools IS 'Pour une catégorie prenant pour valeurs des géométries, liste des fonctionnalités d''aide à la saisie à proposer. Cette information ne sera considérée que si le type (datatype) est ''gsp:wktLiteral''. Pour retirer toutes les fonctionnalités proposées par défaut pour une catégorie commune, on saisira une liste vide.' ; +COMMENT ON COLUMN z_plume.meta_categorie.compute IS 'Liste des fonctionnalités de calcul à proposer. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie. Pour retirer toutes les fonctionnalités proposées par défaut pour une catégorie commune, on saisira une liste vide.' ; +COMMENT ON COLUMN z_plume.meta_categorie.template_order IS 'Ordre d''apparence de la catégorie dans le formulaire. Les plus petits numéros sont affichés en premier.' ; +COMMENT ON COLUMN z_plume.meta_categorie.compute_params IS 'Paramètres des fonctionnalités de calcul, le cas échéant, sous une forme clé-valeur. La clé est le nom du paramètre, la valeur sa valeur. Cette information ne sera considérée que si une méthode de calcul est effectivement disponible pour la catégorie et qu''elle attend un ou plusieurs paramètres.' ; + +-- Function: z_plume.meta_categorie_instead_of_action() + +CREATE OR REPLACE FUNCTION z_plume.meta_categorie_instead_of_action() + RETURNS trigger + LANGUAGE plpgsql + AS $BODY$ +/* Fonction exécutée par le trigger meta_categorie_instead_of_action. + + Elle répercute la commande de l'utilisateur sur la table des + métadonnées communes ou la table des métadonnées locales, selon + la valeur du champ "origin". + +*/ +BEGIN + + IF TG_OP = 'DELETE' + THEN + + IF OLD.origin = 'shared' + THEN + DELETE FROM z_plume.meta_shared_categorie + WHERE meta_shared_categorie.path = OLD.path ; + ELSE + DELETE FROM z_plume.meta_local_categorie + WHERE meta_local_categorie.path = OLD.path ; + END IF ; + + RETURN OLD ; + + END IF ; + + IF TG_OP = 'UPDATE' + THEN + + IF OLD.origin = 'shared' + THEN + UPDATE z_plume.meta_shared_categorie + SET ( + path, origin, label, description, special, is_node, datatype, + is_long_text, rowspan, placeholder, input_mask, is_multiple, + unilang, is_mandatory, sources, geo_tools, compute, template_order, + compute_params + ) = ( + NEW.path, NEW.origin, NEW.label, NEW.description, NEW.special, NEW.is_node, NEW.datatype, + NEW.is_long_text, NEW.rowspan, NEW.placeholder, NEW.input_mask, NEW.is_multiple, + NEW.unilang, NEW.is_mandatory, NEW.sources, NEW.geo_tools, NEW.compute, NEW.template_order, + NEW.compute_params + ) + WHERE meta_shared_categorie.path = OLD.path ; + ELSE + UPDATE z_plume.meta_local_categorie + SET ( + path, origin, label, description, special, is_node, datatype, + is_long_text, rowspan, placeholder, input_mask, is_multiple, + unilang, is_mandatory, sources, geo_tools, compute, template_order, + compute_params + ) = ( + NEW.path, NEW.origin, NEW.label, NEW.description, NEW.special, NEW.is_node, NEW.datatype, + NEW.is_long_text, NEW.rowspan, NEW.placeholder, NEW.input_mask, NEW.is_multiple, + NEW.unilang, NEW.is_mandatory, NEW.sources, NEW.geo_tools, NEW.compute, NEW.template_order, + NEW.compute_params + ) + WHERE meta_local_categorie.path = OLD.path ; + END IF ; + + RETURN NEW ; + + END IF ; + + IF TG_OP = 'INSERT' + THEN + + IF NEW.origin = 'shared' + THEN + INSERT INTO z_plume.meta_shared_categorie + ( + path, origin, label, description, special, is_node, datatype, + is_long_text, rowspan, placeholder, input_mask, is_multiple, + unilang, is_mandatory, sources, geo_tools, compute, template_order, + compute_params + ) VALUES ( + NEW.path, coalesce(NEW.origin, 'shared'), NEW.label, NEW.description, NEW.special, + coalesce(NEW.is_node, False), NEW.datatype, NEW.is_long_text, NEW.rowspan, NEW.placeholder, + NEW.input_mask, NEW.is_multiple, NEW.unilang, NEW.is_mandatory, NEW.sources, NEW.geo_tools, + NEW.compute, NEW.template_order, NEW.compute_params + ) ; + ELSE + INSERT INTO z_plume.meta_local_categorie + ( + path, origin, label, description, special, is_node, datatype, + is_long_text, rowspan, placeholder, input_mask, is_multiple, + unilang, is_mandatory, sources, geo_tools, compute, template_order, + compute_params + ) VALUES ( + coalesce(NEW.path, format('uuid:%s', gen_random_uuid())), coalesce(NEW.origin, 'local'), + NEW.label, NEW.description, NEW.special, coalesce(NEW.is_node, False), NEW.datatype, + NEW.is_long_text, NEW.rowspan, NEW.placeholder, NEW.input_mask, NEW.is_multiple, + NEW.unilang, NEW.is_mandatory, NEW.sources, NEW.geo_tools, NEW.compute, NEW.template_order, + NEW.compute_params + ) ; + END IF ; + + RETURN NEW ; + + END IF ; + +END +$BODY$ ; + +COMMENT ON FUNCTION z_plume.meta_categorie_instead_of_action() IS 'Fonction exécutée par le trigger meta_categorie_instead_of_action, qui répercute l''action sur la table des métadonnées locales ou communes, selon "origin".' ; + +-- Trigger: meta_categorie_instead_of_action on z_plume.meta_categorie + +CREATE TRIGGER meta_categorie_instead_of_action + INSTEAD OF INSERT OR UPDATE OR DELETE + ON z_plume.meta_categorie + FOR EACH ROW + EXECUTE PROCEDURE z_plume.meta_categorie_instead_of_action() ; + +COMMENT ON TRIGGER meta_categorie_instead_of_action ON z_plume.meta_categorie IS 'Répercute l''action sur la table des métadonnées locales ou communes, selon "origin".' ; + + ------ 1.2 - TABLE DES MODELES ------ -- Sequence: z_plume.meta_template_tpl_id_seq From a681f00e813df56f9c4fd72423b69a18c7efbac7 Mon Sep 17 00:00:00 2001 From: alhyss <55992003+alhyss@users.noreply.github.com> Date: Thu, 23 May 2024 09:15:58 +0200 Subject: [PATCH 04/11] test: trigger sur meta_categorie MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajout de deux tests t024 et t025 pour le trigger meta_categorie_instead_of_action qui répercute les commandes de modification des données de meta_categorie sur les tables sources. --- postgresql/tests/plume_pg_test.sql | 117 +++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) diff --git a/postgresql/tests/plume_pg_test.sql b/postgresql/tests/plume_pg_test.sql index 258617b2..65d9ca7e 100644 --- a/postgresql/tests/plume_pg_test.sql +++ b/postgresql/tests/plume_pg_test.sql @@ -2029,3 +2029,120 @@ $_$; COMMENT ON FUNCTION z_plume_recette.t023() IS 'PlumePg (recette). TEST : Modèle pré-configuré avec onglets.' ; + +-- Function: z_plume_recette.t024() + +CREATE OR REPLACE FUNCTION z_plume_recette.t024() + RETURNS boolean + LANGUAGE plpgsql + AS $_$ +DECLARE + e_mssg text ; + e_detl text ; + att record ; + src text ; +BEGIN + + SELECT prosrc INTO src + FROM pg_proc + WHERE oid = 'z_plume.meta_categorie_instead_of_action()'::regprocedure ; + + FOR att IN ( + SELECT attname, attrelid, attnum + FROM pg_attribute + WHERE attrelid = 'z_plume.meta_shared_categorie'::regclass + AND attnum > 0 + ) + LOOP + ASSERT src LIKE format('%%NEW.%s%%', att.attname), + format('échec assertion #1 - champ %s manquant', att.attname) ; + + IF (att.attnum, att.attrelid) IN (SELECT adnum, adrelid FROM pg_attrdef) + THEN + ASSERT src LIKE format('%%coalesce(NEW.%s%%', att.attname), + format('échec assertion #2 - valeur par défaut manquante pour le champ %s', att.attname) ; + END IF ; + END LOOP ; + + RETURN True ; + +EXCEPTION WHEN OTHERS OR ASSERT_FAILURE THEN + GET STACKED DIAGNOSTICS e_mssg = MESSAGE_TEXT, + e_detl = PG_EXCEPTION_DETAIL ; + RAISE NOTICE '%', e_mssg + USING DETAIL = e_detl ; + + RETURN False ; + +END +$_$; + +COMMENT ON FUNCTION z_plume_recette.t024() IS 'PlumePg (recette). TEST : Vérifie que le trigger de mise à jour de la vue "meta_categorie" considère bien tous les champs.' ; + + +-- Function: z_plume_recette.t025() + +CREATE OR REPLACE FUNCTION z_plume_recette.t025() + RETURNS boolean + LANGUAGE plpgsql + AS $_$ +DECLARE + e_mssg text ; + e_detl text ; +BEGIN + + INSERT INTO z_plume.meta_categorie (label) + VALUES ('Une catégorie locale') ; + + ASSERT 'Une catégorie locale' IN (SELECT label FROM z_plume.meta_local_categorie), + 'échec assertion #1' ; + + INSERT INTO z_plume.meta_categorie (path, origin, label) + VALUES ('plume:chose', 'shared', 'Chose') ; + + ASSERT ('plume:chose', 'Chose') IN (SELECT path, label FROM z_plume.meta_shared_categorie), + 'échec assertion #2' ; + + UPDATE z_plume.meta_categorie + SET label = 'Une autre catégorie locale' + WHERE label = 'Une catégorie locale' AND origin = 'local' ; + + ASSERT 'Une autre catégorie locale' IN (SELECT label FROM z_plume.meta_local_categorie), + 'échec assertion #3a' ; + + ASSERT NOT 'Une catégorie locale' IN (SELECT label FROM z_plume.meta_local_categorie), + 'échec assertion #3b' ; + + UPDATE z_plume.meta_categorie + SET label = 'Autre chose' + WHERE path = 'plume:chose' ; + + ASSERT 'Autre chose' = (SELECT label FROM z_plume.meta_shared_categorie WHERE path = 'plume:chose'), + 'échec assertion #4' ; + + DELETE FROM z_plume.meta_categorie + WHERE label = 'Une autre catégorie locale' AND origin = 'local' ; + + ASSERT NOT 'Une autre catégorie locale' IN (SELECT label FROM z_plume.meta_local_categorie), + 'échec assertion #5' ; + + DELETE FROM z_plume.meta_categorie + WHERE path = 'plume:chose' ; + + ASSERT NOT 'plume:chose' IN (SELECT path FROM z_plume.meta_shared_categorie) ; + + RETURN True ; + +EXCEPTION WHEN OTHERS OR ASSERT_FAILURE THEN + GET STACKED DIAGNOSTICS e_mssg = MESSAGE_TEXT, + e_detl = PG_EXCEPTION_DETAIL ; + RAISE NOTICE '%', e_mssg + USING DETAIL = e_detl ; + + RETURN False ; + +END +$_$; + +COMMENT ON FUNCTION z_plume_recette.t025() IS 'PlumePg (recette). TEST : Contrôle de l''exécution du trigger sur "meta_categorie" qui répercute les modifications sur les tables sources de la vue.' ; + From 2819d9b137e47ec9d704d3a0361748327996f186 Mon Sep 17 00:00:00 2001 From: alhyss <55992003+alhyss@users.noreply.github.com> Date: Thu, 23 May 2024 09:51:27 +0200 Subject: [PATCH 05/11] =?UTF-8?q?refactor:=20num=C3=A9ro=20de=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mise à jour des numéros de version dans les fichiers de configuration. --- plume/config.py | 6 +++--- plume/metadata.txt | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/plume/config.py b/plume/config.py index 2427e7a0..dc824c62 100644 --- a/plume/config.py +++ b/plume/config.py @@ -4,13 +4,13 @@ # à actualiser à chaque nouvelle version, d'autant que de besoin : -PLUME_VERSION = 'v1.2.0' +PLUME_VERSION = 'v1.2.1' """Version courante de Plume, sous forme litérale.""" -PLUME_VERSION_TPL = (1, 2, 0) +PLUME_VERSION_TPL = (1, 2, 1) """Version courante de Plume, sous forme de tuple (version majeure, version mineure, correctif).""" -PLUME_PG_MIN_VERSION = '0.3.0' +PLUME_PG_MIN_VERSION = '0.3.1' """Plus petite version de l'extension PlumePg compatible avec la version courante de Plume.""" PLUME_PG_MAX_VERSION = '1.0.0' diff --git a/plume/metadata.txt b/plume/metadata.txt index f1f13012..86c9f08b 100644 --- a/plume/metadata.txt +++ b/plume/metadata.txt @@ -13,7 +13,7 @@ about=Plume, pour PLUgin MÉtadonnées, est un plugin de consultation tout en permettant une large personnalisation des catégories de métadonnées présentées à l'utilisateur lorsqu'il est couplé avec l'extension PostgreSQL PlumePg. -version=1.2.0 +version=1.2.1 qgisMinimumVersion=3.10 # Optional items: changelog=https://mtes-mct.github.io/metadata-postgresql/changelog/changelog.html From 091e7a95dab42e4783fc9cd6b264f46bdef99c2f Mon Sep 17 00:00:00 2001 From: alhyss <55992003+alhyss@users.noreply.github.com> Date: Thu, 23 May 2024 09:53:08 +0200 Subject: [PATCH 06/11] =?UTF-8?q?test:=20coh=C3=A9rence=20num=C3=A9ros=20d?= =?UTF-8?q?e=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajout de deux tests qui contrôlent la cohérence des numéros de versions renseignés dans config.py et metadata.txt. --- admin/consistency.py | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/admin/consistency.py b/admin/consistency.py index fa24c102..c2ac528a 100644 --- a/admin/consistency.py +++ b/admin/consistency.py @@ -17,7 +17,7 @@ from plume.pg import queries from plume.pg.template import dump_template_data from plume.rdf.utils import abspath, data_from_file -from plume.config import SAMPLE_TEMPLATES +from plume.config import SAMPLE_TEMPLATES, PLUME_VERSION, PLUME_VERSION_TPL from plume import __path__ as plume_path from plume import mapping_templates @@ -171,5 +171,19 @@ def test_mapping_templates_attributes(self): with self.subTest(loc_attname=loc_attname): self.assertTrue(loc_attname in pg_attnames) + def test_plume_config_versions_consistency(self): + """Vérifie que les numéros de version de Plume renseignés dans le fichier de configuration sont cohérents entre eux.""" + v = f'v{PLUME_VERSION_TPL[0]}.{PLUME_VERSION_TPL[1]}.{PLUME_VERSION_TPL[2]}' + self.assertTrue(PLUME_VERSION == v or PLUME_VERSION.startswith(f'{v}-')) + + def test_plume_metadata_version_consistency(self): + """Vérifie que le numéro de version renseigné dans le fichier metadata.txt est cohérent avec celui du fichier de configuration.""" + metadata = data_from_file(abspath('metadata.txt')) + v = PLUME_VERSION.lstrip('v') + self.assertIn( + f'version={v}', + metadata + ) + if __name__ == '__main__': unittest.main() \ No newline at end of file From 74dc7a2322a2f7b8998d3a6125d2f463e8b01a55 Mon Sep 17 00:00:00 2001 From: alhyss <55992003+alhyss@users.noreply.github.com> Date: Thu, 23 May 2024 17:02:10 +0200 Subject: [PATCH 07/11] =?UTF-8?q?refactor:=20CSW=20de=20la=20G=C3=A9oplate?= =?UTF-8?q?forme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remplacement du CSW du Géoportail par celui de la Géoplateforme dans la liste des services CSW pré-définis de config.py. Ref: #199 --- plume/config.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plume/config.py b/plume/config.py index dc824c62..ca50955a 100644 --- a/plume/config.py +++ b/plume/config.py @@ -24,8 +24,8 @@ VALUEDEFAUTFILEHELPPDF = "https://snum.scenari-community.org/Asgard/PDF/GuideAsgardManager" VALUEDEFAUTFILEHELPHTML = "https://snum.scenari-community.org/Plume/Documentation" # - -LIBURLCSWDEFAUT = "GéoIDE ,Géoportail IGN " -URLCSWDEFAUT = "http://ogc.geo-ide.developpement-durable.gouv.fr/csw/dataset-harvestable,https://wxs.ign.fr/catalogue/csw" -URLCSWIDDEFAUT = "fr-120066022-jdd-23d6b4cd-5a3b-4e10-83ae-d8fdad9b04ab,IGNF_ADMIN_EXPRESS_3-1.xml" +LIBURLCSWDEFAUT = "Géo-IDE,Géoplateforme IGN" +URLCSWDEFAUT = "http://ogc.geo-ide.developpement-durable.gouv.fr/csw/dataset-harvestable,https://data.geopf.fr/csw" +URLCSWIDDEFAUT = "fr-120066022-jdd-23d6b4cd-5a3b-4e10-83ae-d8fdad9b04ab,IGNF_GEOFLAr_2-2.xml" # - pour les items des imports des modèles pré-configurés SAMPLE_TEMPLATES = ['Basique', 'Classique', 'Donnée externe', 'INSPIRE'] From b72aaf54baf70da41c0599bad9ab3ba548bb3619 Mon Sep 17 00:00:00 2001 From: alhyss <55992003+alhyss@users.noreply.github.com> Date: Thu, 23 May 2024 17:54:01 +0200 Subject: [PATCH 08/11] doc: note de version Plume v1.2.1 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajout d'une note de version pour Plume v1.2.1. Ajustements mineurs dans la documentation technique suite aux évolutions de cette version, et surtout de son module PlumePg v0.3.1. --- docs/changelog/changelog.rst | 1 + docs/changelog/v1_2_1.md | 31 +++++++++++++++++++++++++++++ docs/mechanism/memo.md | 4 ++-- docs/usage/gestion_plume_pg.md | 18 ++++++++--------- docs/usage/metadonnees_calculees.md | 2 +- docs/usage/modeles_de_formulaire.md | 18 ++++++++--------- 6 files changed, 53 insertions(+), 21 deletions(-) create mode 100644 docs/changelog/v1_2_1.md diff --git a/docs/changelog/changelog.rst b/docs/changelog/changelog.rst index ef42d2b5..829873f3 100644 --- a/docs/changelog/changelog.rst +++ b/docs/changelog/changelog.rst @@ -4,6 +4,7 @@ Notes de version .. toctree:: :maxdepth: 1 + v1_2_1 v1_2_0 v1_1_1 v1_1_0 diff --git a/docs/changelog/v1_2_1.md b/docs/changelog/v1_2_1.md new file mode 100644 index 00000000..17d26b76 --- /dev/null +++ b/docs/changelog/v1_2_1.md @@ -0,0 +1,31 @@ +# Version corrective 1.2.1 + +*Date de publication : 23 mai 2024.* + +*Sur GitHub : [https://github.com/MTES-MCT/metadata-postgresql/releases/tag/v1.2.1](https://github.com/MTES-MCT/metadata-postgresql/releases/tag/v1.2.1).* + +Plume v1.2.1 est une version corrective, accompagnée d'une nouvelle version de l'extension PostgreSQL PlumePg. + +**La mise à jour de PlumePg en version 0.3.1 est très fortement recommandée,** et obligatoire pour que le plugin QGIS Plume continue à détecter les modèles personnalisés. + +## PlumePg v1.3.1 + +La table partitionnée `z_plume.meta_categorie` de l'extension PlumePg (catégories de métadonnées) devient une vue éditable, alimentée par les deux tables `z_plume.meta_shared_categorie` (catégories communes) et `z_plume.meta_local_categorie` (catégories locales). + +Toutes les opérations antérieurement possibles sur la table partitionnée restent réalisables via la vue. + +Cette évolution vise à éliminer l'une des conditions d'apparition d'une erreur de segmentation qui, dans certaines conditions, pouvait se produire lors des sauvegardes de bases. Elle avait notamment été constatée sur les serveurs EOLE PostgreSQL 12 où PlumePg était active, et elle empêchait la sauvegarde des bases concernées. + +*Référence : [issue #198](https://github.com/MTES-MCT/metadata-postgresql/issues/198).* + +## Service CSW de la Géoplateforme + +Mise à jour de la liste des services présentés par défaut dans l'interface d'import d'une fiche de métadonnée via un service CSW INSPIRE. Le [service du Géoportail IGN](https://geoservices.ign.fr/documentation/services/services-deprecies/services-de-recherche-csw-ogc), désormais déprécié, est remplacé par [celui de la Géoplateforme](https://geoservices.ign.fr/documentation/services/services-geoplateforme/metadonnees). + +*Référence : [issue #199](https://github.com/MTES-MCT/metadata-postgresql/issues/199).* + +## Tests + +Le tests de PlumePg v0.3.1 et des packages `plume.iso`, `plume.rdf`, `plume.pg` de Plume v1.2.1 ont été réalisés avec [Python](https://www.python.org/) 3.10.5, [psycopg2](https://pypi.org/project/psycopg2/) 2.9.3, [RDFLib](https://pypi.org/project/rdflib/) 7.0.0, [pyparsing](https://pypi.org/project/pyparsing/) 3.0.9, [Asgard](https://github.com/MTES-MCT/asgard-postgresql) 1.4.0, [pgcrypto](https://www.postgresql.org/docs/current/pgcrypto.html) 1.3, [isodate](https://pypi.org/project/isodate/) 0.6.1, [six](https://pypi.org/project/six/) 1.16.0 et [PostgreSQL](https://www.postgresql.org/) 10.12, 11.9, 12.4, 13.0, 14.2, 15.0 et 16.0. + +Les contrôles manuels de l'interface du plugin QGIS ont été effectués sous QGIS 3.34.2. diff --git a/docs/mechanism/memo.md b/docs/mechanism/memo.md index 6ea5fa2c..8415b2a3 100644 --- a/docs/mechanism/memo.md +++ b/docs/mechanism/memo.md @@ -129,7 +129,7 @@ La liste des métadonnées communes présentée dans le fichier [`/docs/usage/me ### Mise à jour des catégories communes dans les scripts de *PlumePg* -La commande suivante permet de générer la commande `INSERT` qui ajoute toutes les métadonnées communes à la table `z_plume.meta_categorie` : +La commande suivante permet de générer la commande `INSERT` qui ajoute toutes les métadonnées communes à la table `z_plume.meta_shared_categorie` : ```python @@ -225,7 +225,7 @@ La valeur est un tuple dont le premier élément est le nom qui sera systématiq ### Extension *PlumePg* -Le plus souvent, une nouvelle option de configuration se manifestera dans *PlumePg* par un champ supplémentaire dans les tables `z_plume.meta_categorie` (ainsi que ses partitions `z_plume.meta_shared_categorie` et `z_plume.meta_local_categorie`) et `z_plume.meta_template_categories`, ainsi que la vue `z_plume.meta_template_categories_full`. Autant que possible, le nom du champ sera identique au nom python de l'option de configuration correspondante (le premier élément du tuple de `prop_map` évoqué dans le paragraphe précédent), soit `geo_tools` pour l'exemple considéré. +Le plus souvent, une nouvelle option de configuration se manifestera dans *PlumePg* par un champ supplémentaire dans la vue `z_plume.meta_categorie` (ainsi que ses tables sources `z_plume.meta_shared_categorie` et `z_plume.meta_local_categorie`) et `z_plume.meta_template_categories`, ainsi que la vue `z_plume.meta_template_categories_full`. Autant que possible, le nom du champ sera identique au nom python de l'option de configuration correspondante (le premier élément du tuple de `prop_map` évoqué dans le paragraphe précédent), soit `geo_tools` pour l'exemple considéré. Si le champ n'admet que des valeurs pré-déterminées, on pourra définir un type énuméré semblable à `z_plume.meta_datatype`. Si le champ admet un tableau de valeurs pré-déterminées, alors il importe de définir non seulement le type énuméré, mais aussi de créer un cast implicite permettant de convertir un tableau de valeur textuel en tableau de ce type : diff --git a/docs/usage/gestion_plume_pg.md b/docs/usage/gestion_plume_pg.md index fb6e0d57..c9ecafd0 100644 --- a/docs/usage/gestion_plume_pg.md +++ b/docs/usage/gestion_plume_pg.md @@ -8,15 +8,15 @@ L'extension PostgreSQL *PlumePg* est un composant optionnel de Plume, qui ouvre | Version | Compatibilité | Remarques | Modalités de test | | --- | --- | --- | --- | -| PostgreSQL <= 9.6 | non | *PlumePg* requiert la prise en charge des tables partitionnées, introduites par PostgreSQL 10. | | -| PostgreSQL 10 | oui | Nécessite l'extension `pgcrypto`. | 2023.06.16. PostgreSQL 10.12 + PlumePg 0.3.0 + pgcrypto 1.3 + Asgard 1.4.0[^withasgard]. | -| PostgreSQL 11 | oui | Nécessite l'extension `pgcrypto`. | 2023.06.16. PostgreSQL 11.9 + PlumePg 0.3.0 + pgcrypto 1.3 + Asgard 1.4.0. | -| PostgreSQL 12 | oui | Nécessite l'extension `pgcrypto`. | 2023.06.16. PostgreSQL 12.4 + PlumePg 0.3.0 + pgcrypto 1.3 + Asgard 1.4.0. | -| PostgreSQL 13 | oui | | 2023.06.16. PostgreSQL 13.0 + PlumePg 0.3.0 + pgcrypto 1.3[^withcrypto] + Asgard 1.4.0. | -| PostgreSQL 14 | oui | | 2023.06.16. PostgreSQL 14.2 + PlumePg 0.3.0 + pgcrypto 1.3 + Asgard 1.4.0. | -| PostgreSQL 15 | oui | | 2023.06.16. PostgreSQL 15.0 + PlumePg 0.3.0 + pgcrypto 1.3 + Asgard 1.4.0. | - -[^withasgard]: L'extension PostgreSQL *Asgard* n'est en aucune façon requise pour utiliser Plume et *PlumePg*. Les tests faisant intervenir *Asgard* s'assure simplement que, dans le cas où les deux extensions sont présentes, *Asgard* gère correctement les droits sur les objets de *PlumePg*. Cf. [Cohabitation avec *Asgard*](#cohabitation-avec-asgard) +| PostgreSQL 10 | oui | Nécessite l'extension `pgcrypto`. | 2024.05.23. PostgreSQL 10.12 + PlumePg 0.3.1 + pgcrypto 1.3 + Asgard 1.4.0[^withasgard]. | +| PostgreSQL 11 | oui | Nécessite l'extension `pgcrypto`. | 2024.05.23. PostgreSQL 11.9 + PlumePg 0.3.1 + pgcrypto 1.3 + Asgard 1.4.0. | +| PostgreSQL 12 | oui | Nécessite l'extension `pgcrypto`. | 2024.05.23. PostgreSQL 12.4 + PlumePg 0.3.1 + pgcrypto 1.3 + Asgard 1.4.0. | +| PostgreSQL 13 | oui | | 2024.05.23. PostgreSQL 13.0 + PlumePg 0.3.1 + pgcrypto 1.3[^withcrypto] + Asgard 1.4.0. | +| PostgreSQL 14 | oui | | 2024.05.23. PostgreSQL 14.2 + PlumePg 0.3.1 + pgcrypto 1.3 + Asgard 1.4.0. | +| PostgreSQL 15 | oui | | 2024.05.23. PostgreSQL 15.0 + PlumePg 0.3.1 + pgcrypto 1.3 + Asgard 1.4.0. | +| PostgreSQL 16 | oui | *Asgard* n'est à ce jour pas disponible sous PostgreSQL 16. | 2024.05.23. PostgreSQL 16.0 + PlumePg 0.3.1 + pgcrypto 1.3 | + +[^withasgard]: L'extension PostgreSQL *Asgard* n'est en aucune façon requise pour utiliser Plume et *PlumePg*. Les tests faisant intervenir *Asgard* s'assure simplement que, dans le cas où les deux extensions sont présentes, *Asgard* gère correctement les droits sur les objets de *PlumePg*. Cf. [Cohabitation avec *Asgard*](#cohabitation-avec-asgard). [^withcrypto]: Les tests sont réalisés avec le fichier de contrôle standard de *PlumePg*, unique pour toutes les versions de PostgreSQL et qui requiert `pgcrypto`. Il est donc vérifié que celui-ci peut être installé pour toutes les versions, y compris PostgreSQL 13, 14 et 15, pour lesquelles *PlumePg* n'utilise ensuite aucune de ses fonctionnalités. diff --git a/docs/usage/metadonnees_calculees.md b/docs/usage/metadonnees_calculees.md index 21c18f33..ef31063c 100644 --- a/docs/usage/metadonnees_calculees.md +++ b/docs/usage/metadonnees_calculees.md @@ -25,7 +25,7 @@ Les catégories pour lesquelles le calcul est proposé sont, à ce stade : [^activation-suivi-dates]: Il est également recommandé d'avoir [activé les fonctionnalités d'enregistrement des dates](#activation-de-lenregistrement-des-dates), sans quoi le calcul ne renverra jamais rien. -Les paramètres optionnels sont spécifiés via le champ `compute_params` des tables `z_plume.meta_categorie` et `z_plume.meta_template_categories`. Il s'agit d'un champ de type `jsonb`, qui attend un dictionnaire dont les clés sont les noms des paramètres et dont les valeurs sont les valeurs des paramètres. +Les paramètres optionnels sont spécifiés via le champ `compute_params` de `z_plume.meta_categorie` et `z_plume.meta_template_categories`. Il s'agit d'un champ de type `jsonb`, qui attend un dictionnaire dont les clés sont les noms des paramètres et dont les valeurs sont les valeurs des paramètres. Par exemple : diff --git a/docs/usage/modeles_de_formulaire.md b/docs/usage/modeles_de_formulaire.md index 96d20436..88cdf51e 100644 --- a/docs/usage/modeles_de_formulaire.md +++ b/docs/usage/modeles_de_formulaire.md @@ -30,7 +30,7 @@ L'extension PostgreSQL *PlumePg* crée une structure de données adaptée au sto Cf. [Installation et gestion de l'extension PostgreSQL *PlumePg*](./gestion_plume_pg.md) pour plus de détails sur l'installation et la maintenance de cette extension. -*PlumePg* crée dans le schéma `z_plume` un ensemble de tables permettant de définir les modèles de formulaires : +*PlumePg* crée dans le schéma `z_plume` un ensemble de tables et vues permettant de définir les modèles de formulaires : - `meta_template` liste les modèles. - `meta_categorie` liste les catégories de métadonnées disponibles, qu'il s'agisse des catégories du schéma commun ou de catégories locales, et paramètre leur affichage dans les formulaires. - `meta_tab` liste des noms d'onglets de formulaires dans lesquels pourront être classées les catégories. @@ -78,7 +78,7 @@ D'une manière générale, toute commande renvoyant un booléen peut être utili Les ensembles sont combinés entre eux avec l'opérateur `OR`. Au sein d'un ensemble, les conditions sont combinées avec l'opérateur `AND`. -Les clés des conditions sont les chemins des catégories de métadonnées (champ `path` de la table `meta_categorie` évoquée ci-après) et les valeurs des valeurs qui doivent apparaître dans les métadonnées pour les catégories considérées. +Les clés des conditions sont les chemins des catégories de métadonnées (champ `path` de la vue `meta_categorie` évoquée ci-après) et les valeurs des valeurs qui doivent apparaître dans les métadonnées pour les catégories considérées. Dans l'exemple ci-avant, une table validera les conditions du modèle si : - il s'agit d'une donnée externe (valeur `True` pour la catégorie `plume:isExternal`) **ET** l'un de ses mots-clés (`dcat:keyword`) est `'IGN'` ; @@ -124,15 +124,15 @@ Avant d'y affecter des catégories, les onglets doivent être définis dans la t ### Catégories de métadonnées -La table `z_plume.meta_categorie` répertorie toutes les catégories de métadonnées disponibles, à la fois celle qui sont décrites par le schéma SHACL des catégories communes (fichier [shape.ttl](../../plume/rdf/data/shape.ttl)) et les catégories supplémentaires locales définies par l'ADL pour le seul usage de son service. +La vue éditable `z_plume.meta_categorie` répertorie toutes les catégories de métadonnées disponibles, à la fois celle qui sont décrites par le schéma SHACL des catégories communes (fichier [shape.ttl](../../plume/rdf/data/shape.ttl)) et les catégories supplémentaires locales définies par l'ADL pour le seul usage de son service. -Il s'agit en fait d'une table partitionnée avec deux tables filles : +Cette vue correspond en fait à la concaténation de deux tables sources : - `z_plume.meta_shared_categorie` pour les catégories communes (`origin` vaut `shared`) ; - `z_plume.meta_local_categorie` pour les catégories supplémentaires locales (`origin` vaut `local`). -L'utilisateur peut évidemment écrire directement dans `meta_categorie` sans se préoccuper de là où sont effectivement stockées les données. +L'utilisateur peut écrire soit dans les tables `meta_shared_categorie` et `meta_local_categorie`, soit dans la vue `meta_categorie` sans se préoccuper de là où sont effectivement stockées les données. -Concrètement, la table `meta_categorie` a deux fonctions : +Concrètement, la vue `meta_categorie` a deux fonctions : - elle permet de créer les catégories supplémentaires locales, en ajoutant une ligne à la table par nouvelle catégorie. Il est a minima nécessaire de renseigner un libellé, histoire de savoir de quoi il est question ; - elle permet de modifier la manière dont les catégories communes sont présentées par le plugin QGIS (nouveau label, nouveau texte d'aide, etc.), en jouant sur les nombreux champs de paramétrage. @@ -161,7 +161,7 @@ Les champs sur lesquels l'ADL peut intervenir sont : Les champs `path` (chemin SPARQL identifiant la catégorie), `origin` et `is_node` sont calculés automatiquement. Il est fortement recommandé de ne pas les modifier à la main. -Les caractéristiques spécifiées dans la table `meta_categorie` seront utilisées pour tous les modèles, sauf -- cette possibilité sera détaillée par la suite -- à avoir prévu des valeurs spécifiques au modèle via la table `meta_template_categories`. Pour les catégories partagées, elles se substitueront au paramétrage par défaut défini par le schéma des catégories communes, qui est repris dans `meta_categorie` lors de l'initialisation de l'extension. +Les caractéristiques spécifiées dans la vue `meta_categorie` seront utilisées pour tous les modèles, sauf -- cette possibilité sera détaillée par la suite -- à avoir prévu des valeurs spécifiques au modèle via la table `meta_template_categories`. Pour les catégories partagées, elles se substitueront au paramétrage par défaut défini par le schéma des catégories communes, qui est repris dans `meta_categorie` lors de l'initialisation de l'extension. ### Association de catégories à un modèle @@ -522,7 +522,7 @@ Les données des modèles sont stockées en base dans une structure de données | Insertion & Mise à jour | `query_insert_or_update_meta_template` | | Suppression | `query_delete_meta_template` | -* Objet "catégorie de métadonnée" (table `z_plume.meta_categorie`) : +* Objet "catégorie de métadonnée" (vue éditable `z_plume.meta_categorie`) : | Action | Fonction pour générer la requête | | --- | --- | @@ -736,7 +736,7 @@ from plume.rdf.thesaurus import source_label label = source_label(uri, langlist) ``` -*`uri` est l'URI de la source considérée. Elle peut notamment être saisie sous la forme d'une chaîne de caractères, soit telle que renvoyée par {py:func}`~plume.rdf.properties.property_sources` ou récupérée dans les champs `sources` des tables des `meta_categorie` et `meta_template_categories`. `langlist` est la liste des langues autorisées pour les traductions. On utilisera de préférence l'attribut {py:attr}`plume.rdf.widgetsdict.WidgetsDict.langlist` du dictionnaire de widgets qui a servi à générer la fiche de métadonnées courante.* +*`uri` est l'URI de la source considérée. Elle peut notamment être saisie sous la forme d'une chaîne de caractères, soit telle que renvoyée par {py:func}`~plume.rdf.properties.property_sources` ou récupérée dans les champs `sources` de `meta_categorie` et `meta_template_categories`. `langlist` est la liste des langues autorisées pour les traductions. On utilisera de préférence l'attribut {py:attr}`plume.rdf.widgetsdict.WidgetsDict.langlist` du dictionnaire de widgets qui a servi à générer la fiche de métadonnées courante.* En jouant sur l'argument optionnel `linked`, il est possible d'obtenir non une simple chaîne de caractères mais un élément HTML avec hyperlien : From 1aed938f53d68dd9ec1b0715db26038f2f68898f Mon Sep 17 00:00:00 2001 From: alhyss <55992003+alhyss@users.noreply.github.com> Date: Thu, 23 May 2024 18:13:34 +0200 Subject: [PATCH 09/11] =?UTF-8?q?docs:=20mise=20=C3=A0=20jour=20du=20readm?= =?UTF-8?q?e?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Mise à jour du fichier README.md + actualisation du nom du ministère dans metadata.txt. --- README.md | 10 +++++----- plume/metadata.txt | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 47637b84..f885ba67 100644 --- a/README.md +++ b/README.md @@ -62,16 +62,16 @@ Documentation utilisateur : https://snum.scenari-community.org/Plume/Documentati ## Crédits -© République Française, 2022-2023. +© République Française, 2022-2024. ### Éditeur -Direction du numérique du Ministère de la Transition écologique et de la Cohésion des territoires, du Ministère de la Transition énergétique et du Secrétariat d'État chargé de la Mer. +Direction du numérique du Ministère de la Transition écologique et de la Cohésion des territoires. -### Équipe +### Auteurs -- Didier LECLERC (DNUM/UNI/DRC) : intégration, développement de l'interface utilisateur et de l'interface avec le serveur PostgreSQL, rédaction de la documentation utilisateur. -- Leslie LEMAIRE (DNUM/UNI/DRC) : conception et développement des mécaniques sous-jacentes (modules [plume.rdf](plume/rdf), [plume.pg](plume/pg) et [plume.iso](plume/iso)), création des logos et icônes, rédaction de la documentation technique et de la documentation utilisateur. +- Didier Leclerc : intégration, développement de l'interface utilisateur et de l'interface avec le serveur PostgreSQL, rédaction de la documentation utilisateur. +- Leslie Lemaire : conception et développement des mécaniques sous-jacentes (modules [plume.rdf](plume/rdf), [plume.pg](plume/pg) et [plume.iso](plume/iso)), création des logos et icônes, rédaction de la documentation technique et de la documentation utilisateur. ## Contact diff --git a/plume/metadata.txt b/plume/metadata.txt index 86c9f08b..784d95c4 100644 --- a/plume/metadata.txt +++ b/plume/metadata.txt @@ -27,5 +27,5 @@ experimental = False deprecated = False # Author contact information -author=Direction du numérique du Ministère de la Transition écologique et de la Cohésion des territoires, du Ministère de la Transition énergétique et du Secrétariat d'État chargé de la Mer - Didier LECLERC / Leslie LEMAIRE. +author=Direction du numérique du Ministère de la Transition écologique et de la Cohésion des territoires - Didier LECLERC / Leslie LEMAIRE. email=leslie.lemaire@developpement-durable.gouv.fr, didier.leclerc@developpement-durable.gouv.fr From 228998fb49540612a88583ffc1d52fa321899b75 Mon Sep 17 00:00:00 2001 From: alhyss <55992003+alhyss@users.noreply.github.com> Date: Thu, 23 May 2024 19:14:14 +0200 Subject: [PATCH 10/11] =?UTF-8?q?refactor:=20unification=20de=20m=C3=A9tad?= =?UTF-8?q?onn=C3=A9es?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ajout de trois paramètres de configuration à plume.py pour gérer de manière unifiée le nom de l'application, le copyright et le nom de l'éditeur dans la documentation technique et dans l'à propos de l'interface QGIS. Mise en cohérence manuelle dans README.md et metadata.txt. --- README.md | 4 ++-- docs/conf.py | 8 ++++---- plume/about.py | 15 ++++----------- plume/config.py | 19 +++++++++++++++++++ plume/metadata.txt | 2 +- 5 files changed, 30 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index f885ba67..5fd166ab 100644 --- a/README.md +++ b/README.md @@ -62,11 +62,11 @@ Documentation utilisateur : https://snum.scenari-community.org/Plume/Documentati ## Crédits -© République Française, 2022-2024. +© République française, 2022-2024. ### Éditeur -Direction du numérique du Ministère de la Transition écologique et de la Cohésion des territoires. +Direction du numérique du ministère de la Transition écologique et de la Cohésion des territoires. ### Auteurs diff --git a/docs/conf.py b/docs/conf.py index fb853ad1..4c27febc 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -14,14 +14,14 @@ import sys sys.path.insert(0, os.path.abspath('../.')) -from plume.config import PLUME_VERSION +from plume.config import PLUME_VERSION, PUBLISHER, COPYRIGHT, APP_NAME # -- Project information ----------------------------------------------------- -project = 'Plume' -copyright = '2023, République française' -author = "Didier Leclerc et Leslie Lemaire, Direction du numérique du Ministère de la Transition écologique et de la Cohésion des territoires, du Ministère de la Transition énergétique et du Secrétariat d'État chargé de la Mer" +project = APP_NAME +copyright = COPYRIGHT +author = PUBLISHER # The full version, including alpha/beta/rc tags release = PLUME_VERSION diff --git a/plume/about.py b/plume/about.py index cbf3a685..9770b2de 100644 --- a/plume/about.py +++ b/plume/about.py @@ -4,7 +4,8 @@ import os.path from PyQt5 import QtCore, QtGui, QtWidgets -from plume.bibli_plume import ( returnAndSaveDialogParam, returnVersion, executeSql ) +from plume.bibli_plume import ( returnAndSaveDialogParam, returnVersion ) +from plume.config import COPYRIGHT, PUBLISHER class Ui_Dialog(object): def setupUi(self, Dialog): @@ -158,16 +159,8 @@ def retranslateUi(self, Dialog): MonHtmlLL = "" + QtWidgets.QApplication.translate("about", "Leslie LEMAIRE: design and development of the underlying mechanics (plume.rdf, plume.pg et plume.iso.), creation of logos and icons.", None) + "

" mLinkLL = '' + MonHtmlLL + '' - MonHtml += "" - MonHtml4 = QtWidgets.QApplication.translate("about", "MTECT/MTE/Mer", None) - MonHtml += MonHtml4 - MonHtml += "
" - MonHtml6 = QtWidgets.QApplication.translate("about", "digital service SG/DNUM/UNI/DRC", None) - MonHtml += MonHtml6 - MonHtml += "

" - MonHtml7 = QtWidgets.QApplication.translate("about", "Development in 2021/2022/2023", None) - MonHtml += MonHtml7 - MonHtml += "

" + MonHtml += f'© {COPYRIGHT}
{PUBLISHER}' + MonHtml += "

" Dialog.setWindowTitle(QtWidgets.QApplication.translate("about", "PLUME (Metadata storage in PostGreSQL)", None) + " (" + str(returnVersion()) + ")") self.label_2.setText(QtWidgets.QApplication.translate("about", "Plume", None)) diff --git a/plume/config.py b/plume/config.py index ca50955a..0eeff917 100644 --- a/plume/config.py +++ b/plume/config.py @@ -16,6 +16,25 @@ PLUME_PG_MAX_VERSION = '1.0.0' """Plus petite version de l'extension PlumePg présumée non rétro-compatible avec la version courante de Plume.""" +APP_NAME = 'Plume' +"""Nom de l'application.""" + +COPYRIGHT = 'République française, 2022-2024' +"""Copyright de l'application. + +Cette information apparaît aussi dans le fichier README.md, où elle doit être mise +à jour manuellement à chaque modification de la présente variable. + +""" + +PUBLISHER = 'Direction du numérique du ministère de la Transition écologique et de la Cohésion des territoires' +"""Editeur de l'application. + +Cette information apparaît aussi dans les fichiers README.md et plume/metadata.txt, +où elle doit être mise à jour manuellement à chaque modification de la présente variable. + +""" + # =================== # = for Plugin PLUME # - DL diff --git a/plume/metadata.txt b/plume/metadata.txt index 784d95c4..5a5df093 100644 --- a/plume/metadata.txt +++ b/plume/metadata.txt @@ -27,5 +27,5 @@ experimental = False deprecated = False # Author contact information -author=Direction du numérique du Ministère de la Transition écologique et de la Cohésion des territoires - Didier LECLERC / Leslie LEMAIRE. +author=Direction du numérique du ministère de la Transition écologique et de la Cohésion des territoires - Didier LECLERC / Leslie LEMAIRE. email=leslie.lemaire@developpement-durable.gouv.fr, didier.leclerc@developpement-durable.gouv.fr From 78a61fb07ac4f4d92e3b780684907aec164d13e2 Mon Sep 17 00:00:00 2001 From: alhyss <55992003+alhyss@users.noreply.github.com> Date: Fri, 24 May 2024 10:02:35 +0200 Subject: [PATCH 11/11] docs: note de version Debian MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Note de version du paquet Debian. Mise en cohérence des métadonnées (suite). --- README.md | 2 +- admin/debian/DEBIAN/control | 4 ++-- admin/debian/doc/changelog | 13 ++++--------- admin/debian/doc/copyright | 2 +- docs/changelog/v1_2_1.md | 2 +- plume/config.py | 12 +++++++----- plume/metadata.txt | 4 ++-- postgresql/plume_pg--0.3.0--0.3.1.sql | 7 +++---- postgresql/plume_pg--0.3.1.sql | 7 +++---- 9 files changed, 24 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 5fd166ab..efdb171a 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ Documentation utilisateur : https://snum.scenari-community.org/Plume/Documentati ### Éditeur -Direction du numérique du ministère de la Transition écologique et de la Cohésion des territoires. +Direction du Numérique du ministère de la Transition écologique et de la Cohésion des territoires. ### Auteurs diff --git a/admin/debian/DEBIAN/control b/admin/debian/DEBIAN/control index 7470967b..134b9a48 100644 --- a/admin/debian/DEBIAN/control +++ b/admin/debian/DEBIAN/control @@ -4,9 +4,9 @@ Version: #PKG_VERSION# Section: libs Priority: optional Architecture: all -Depends: postgresql-10|postgresql-11|postgresql-12|postgresql-13|postgresql-14|postgresql-15 +Depends: postgresql-10|postgresql-11|postgresql-12|postgresql-13|postgresql-14|postgresql-15|postgresql-16 Installed-Size: 500 -Maintainer: Leslie Lemaire (MTECT-MTE-SEMer/SG/DNUM/UNI/DRC) +Maintainer: Leslie Lemaire (MTECT/SG/DNUM/UNI/DRC) Description: Extension PostgreSQL PlumePg PlumePg complète le plugin QGIS Plume, outil de consultation et saisie des métadonnées du patrimoine en base PostgreSQL. Elle permet notamment à l'administrateur du serveur diff --git a/admin/debian/doc/changelog b/admin/debian/doc/changelog index 9fb49648..3b7a0133 100644 --- a/admin/debian/doc/changelog +++ b/admin/debian/doc/changelog @@ -1,11 +1,6 @@ -plume_pg (0.3.0) stable; urgency=high +plume_pg (0.3.1) stable; urgency=critical - * Compatibilité avec Plume v1.0.0 et son schéma de métadonnées communes. + * Remplacement de la table partitionnée z_plume.meta_categorie par une vue pour prévenir des erreurs de segmentation à la sauvegarde. + Pour plus de détails : - * Nouveau modèle pré-configuré "INSPIRE" et amélioration des modèles existants. - - * Ajout d'une fonction z_plume.stamp_create_triggers pour activer massivement l'enregistrement des dates de modification des tables d'un ou plusieurs schémas. - - Pour plus de détails : - - -- Leslie Lemaire (MTECT-MTE-SEMer/SG/DNUM/UNI/DRC) Mon, 19 Jun 2023 08:10:00 +0200 + -- Leslie Lemaire (MTECT/SG/DNUM/UNI/DRC) Fri, 24 May 2024 10:00:00 +0200 diff --git a/admin/debian/doc/copyright b/admin/debian/doc/copyright index 9af80ead..250dda6e 100644 --- a/admin/debian/doc/copyright +++ b/admin/debian/doc/copyright @@ -4,7 +4,7 @@ Upstream-Contact: Source: https://github.com/MTES-MCT/metadata-postgresql Files: * -Copyright: 2020-2023, République Française, Secrétariat général du Ministère de la Transition écologique et de la Cohésion des territoires, du Ministère de la Transition énergétique et du Secrétariat d'Etat à la Mer, Direction du numérique +Copyright: 2020-2024, République française, direction du Numérique du ministère de la Transition écologique et de la Cohésion des territoires License: AGPL-3.0-or-later GNU AFFERO GENERAL PUBLIC LICENSE Version 3, 19 November 2007 diff --git a/docs/changelog/v1_2_1.md b/docs/changelog/v1_2_1.md index 17d26b76..4bc209ee 100644 --- a/docs/changelog/v1_2_1.md +++ b/docs/changelog/v1_2_1.md @@ -1,6 +1,6 @@ # Version corrective 1.2.1 -*Date de publication : 23 mai 2024.* +*Date de publication : 24 mai 2024.* *Sur GitHub : [https://github.com/MTES-MCT/metadata-postgresql/releases/tag/v1.2.1](https://github.com/MTES-MCT/metadata-postgresql/releases/tag/v1.2.1).* diff --git a/plume/config.py b/plume/config.py index 0eeff917..a3971608 100644 --- a/plume/config.py +++ b/plume/config.py @@ -22,16 +22,18 @@ COPYRIGHT = 'République française, 2022-2024' """Copyright de l'application. -Cette information apparaît aussi dans le fichier README.md, où elle doit être mise -à jour manuellement à chaque modification de la présente variable. +Cette information apparaît aussi dans les fichiers README.md et admin/debian/doc/copyright, +ainsi que dans les en-têtes des scripts de PlumePg, où elle doit être mise à jour manuellement +à chaque modification de la présente variable. """ -PUBLISHER = 'Direction du numérique du ministère de la Transition écologique et de la Cohésion des territoires' +PUBLISHER = 'Direction du Numérique du ministère de la Transition écologique et de la Cohésion des territoires' """Editeur de l'application. -Cette information apparaît aussi dans les fichiers README.md et plume/metadata.txt, -où elle doit être mise à jour manuellement à chaque modification de la présente variable. +Cette information apparaît aussi dans les fichiers README.md, plume/metadata.txt et +admin/debian/doc/copyright, ainsi que dans les en-têtes des scripts de PlumePg, où +elle doit être mise à jour manuellement à chaque modification de la présente variable. """ diff --git a/plume/metadata.txt b/plume/metadata.txt index 5a5df093..3b42f282 100644 --- a/plume/metadata.txt +++ b/plume/metadata.txt @@ -27,5 +27,5 @@ experimental = False deprecated = False # Author contact information -author=Direction du numérique du ministère de la Transition écologique et de la Cohésion des territoires - Didier LECLERC / Leslie LEMAIRE. -email=leslie.lemaire@developpement-durable.gouv.fr, didier.leclerc@developpement-durable.gouv.fr +author=Direction du Numérique du ministère de la Transition écologique et de la Cohésion des territoires - Didier Leclerc / Leslie Lemaire. +email=leslie.lemaire@developpement-durable.gouv.fr, didier.leclerc@developpement-durable.gouv.fr diff --git a/postgresql/plume_pg--0.3.0--0.3.1.sql b/postgresql/plume_pg--0.3.0--0.3.1.sql index a6972015..f2c79d5d 100644 --- a/postgresql/plume_pg--0.3.0--0.3.1.sql +++ b/postgresql/plume_pg--0.3.0--0.3.1.sql @@ -4,12 +4,11 @@ -- PlumePg - Système de gestion des métadonnées locales, version 0.3.1 -- > Script de mise à jour depuis la version 0.3.0 -- --- Copyright République Française, 2024. --- Secrétariat général du Ministère de la Transition écologique et +-- Copyright République française, 2022-2024. +-- Direction du numérique du ministère de la Transition écologique et -- de la Cohésion des territoires. --- Direction du numérique. -- --- contributeurs : Leslie Lemaire (SNUM/UNI/DRC). +-- contributeurs : Leslie Lemaire (DNUM/UNI/DRC). -- -- mél : drc.uni.dnum.sg@developpement-durable.gouv.fr -- diff --git a/postgresql/plume_pg--0.3.1.sql b/postgresql/plume_pg--0.3.1.sql index bc81c7f9..37430a64 100644 --- a/postgresql/plume_pg--0.3.1.sql +++ b/postgresql/plume_pg--0.3.1.sql @@ -3,12 +3,11 @@ -- -- PlumePg - Système de gestion des métadonnées locales, version 0.3.1 -- --- Copyright République Française, 2023-2024. --- Secrétariat général du Ministère de la Transition écologique et +-- Copyright République française, 2022-2024. +-- Direction du numérique du ministère de la Transition écologique et -- de la Cohésion des territoires. --- Direction du numérique. -- --- contributeurs : Leslie Lemaire (SNUM/UNI/DRC). +-- contributeurs : Leslie Lemaire (DNUM/UNI/DRC). -- -- mél : drc.uni.dnum.sg@developpement-durable.gouv.fr --