From 3911656c3ba6b2380a241c02874ec8762b25c3fa Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Thu, 5 Jan 2023 18:40:37 +0100 Subject: [PATCH 01/19] feat(db): upgrade down_revision following rebase Since rebase with develop: changed the down_revision number --- .../migrations/b53bafb13ce8_create_bib_categorie_site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/gn_module_monitoring/migrations/b53bafb13ce8_create_bib_categorie_site.py b/backend/gn_module_monitoring/migrations/b53bafb13ce8_create_bib_categorie_site.py index 610269dd5..33d6ebc8d 100644 --- a/backend/gn_module_monitoring/migrations/b53bafb13ce8_create_bib_categorie_site.py +++ b/backend/gn_module_monitoring/migrations/b53bafb13ce8_create_bib_categorie_site.py @@ -10,7 +10,7 @@ # revision identifiers, used by Alembic. revision = "b53bafb13ce8" -down_revision = "362cf9d504ec" +down_revision = "e78003460441" branch_labels = None depends_on = None From bb2378b6d99f80dd26a70657baf5baa3d303d8ae Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Thu, 5 Jan 2023 18:41:21 +0100 Subject: [PATCH 02/19] fix(db): fix bind params enabling downgrade Beforehand the downgrade was not possible... --- .../f24adb481f54_remove_id_module_from_sites_groups.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/gn_module_monitoring/migrations/f24adb481f54_remove_id_module_from_sites_groups.py b/backend/gn_module_monitoring/migrations/f24adb481f54_remove_id_module_from_sites_groups.py index 52c45d8e7..f9b7690db 100644 --- a/backend/gn_module_monitoring/migrations/f24adb481f54_remove_id_module_from_sites_groups.py +++ b/backend/gn_module_monitoring/migrations/f24adb481f54_remove_id_module_from_sites_groups.py @@ -47,8 +47,8 @@ def downgrade(): update {monitorings_schema}.t_sites_groups set id_module = (select id_module from gn_commons.t_modules tm - where module_code = '\:module_code'); + where module_code = :module_code); """ - ) - op.execute(statement, module_code=MODULE_CODE) - op.alter_column("t_sites_groups", "id_module", nullable=False) + ).bindparams(module_code=MODULE_CODE) + op.execute(statement) + op.alter_column("t_sites_groups", "id_module", nullable=False, schema=monitorings_schema) From 2ae8e5f381ec0d54f1ad8a41c5ceee8e849af663 Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Wed, 11 Jan 2023 11:08:26 +0100 Subject: [PATCH 03/19] refactor(db): removed cor_site_type_category --- ...bafb13ce8_create_cor_site_type_category.py | 47 ------------------- 1 file changed, 47 deletions(-) delete mode 100644 backend/gn_module_monitoring/migrations/e64bafb13ce8_create_cor_site_type_category.py diff --git a/backend/gn_module_monitoring/migrations/e64bafb13ce8_create_cor_site_type_category.py b/backend/gn_module_monitoring/migrations/e64bafb13ce8_create_cor_site_type_category.py deleted file mode 100644 index 2dfcf3412..000000000 --- a/backend/gn_module_monitoring/migrations/e64bafb13ce8_create_cor_site_type_category.py +++ /dev/null @@ -1,47 +0,0 @@ -"""create_cor_site_type_category - -Revision ID: e64bafb13ce8 -Revises: -Create Date: 2022-12-06 16:18:24.512562 - -""" -from alembic import op -import sqlalchemy as sa - -# revision identifiers, used by Alembic. -revision = "e64bafb13ce8" -down_revision = "a54bafb13ce8" -branch_labels = None -depends_on = None - -monitorings_schema = "gn_monitoring" -referent_schema = "ref_nomenclatures" - - -def upgrade(): - op.create_table( - "cor_site_type_categorie", - sa.Column( - "id_categorie", - sa.Integer(), - sa.ForeignKey( - f"{monitorings_schema}.bib_categorie_site.id_categorie", - name="fk_cor_site_type_categorie_id_categorie", - ondelete="CASCADE", - onupdate="CASCADE", - ), - nullable=False, - ), - sa.Column("id_nomenclature", sa.Integer(),sa.ForeignKey( - f"{referent_schema}.t_nomenclatures.id_nomenclature", - name="fk_cor_site_type_categorie_id_type", - ondelete="CASCADE", - onupdate="CASCADE", - ), nullable=False), - sa.PrimaryKeyConstraint("id_categorie", "id_nomenclature", name="pk_cor_site_type_categorie"), - schema=monitorings_schema, - ) - - -def downgrade(): - op.drop_table("cor_site_type_categorie", schema=monitorings_schema) From 710fe80587d79fc93a904adacfbd9d574866905f Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Wed, 11 Jan 2023 11:08:53 +0100 Subject: [PATCH 04/19] refactor(db): changed category into type in cor --- ...ory.py => a54bafb13ce8_create_cor_module_type.py} | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) rename backend/gn_module_monitoring/migrations/{a54bafb13ce8_create_cor_module_category.py => a54bafb13ce8_create_cor_module_type.py} (78%) diff --git a/backend/gn_module_monitoring/migrations/a54bafb13ce8_create_cor_module_category.py b/backend/gn_module_monitoring/migrations/a54bafb13ce8_create_cor_module_type.py similarity index 78% rename from backend/gn_module_monitoring/migrations/a54bafb13ce8_create_cor_module_category.py rename to backend/gn_module_monitoring/migrations/a54bafb13ce8_create_cor_module_type.py index 491198526..574a2e1b1 100644 --- a/backend/gn_module_monitoring/migrations/a54bafb13ce8_create_cor_module_category.py +++ b/backend/gn_module_monitoring/migrations/a54bafb13ce8_create_cor_module_type.py @@ -1,4 +1,4 @@ -"""create_cor_module_category +"""create_cor_module_type Revision ID: a54bafb13ce8 Revises: @@ -20,13 +20,13 @@ def upgrade(): op.create_table( - "cor_module_categorie", + "cor_module_type", sa.Column( - "id_categorie", + "id_type_site", sa.Integer(), sa.ForeignKey( - f"{monitorings_schema}.bib_categorie_site.id_categorie", - name="fk_cor_module_categorie_id_categorie", + f"{monitorings_schema}.bib_type_site.id_nomenclature", + name="fk_cor_module_type_id_nomenclature", ondelete="CASCADE", onupdate="CASCADE", ), @@ -34,7 +34,7 @@ def upgrade(): ), sa.Column("id_module", sa.Integer(),sa.ForeignKey( f"{referent_schema}.t_modules.id_module", - name="fk_cor_module_categorie_id_module", + name="fk_cor_module_type_id_module", ondelete="CASCADE", onupdate="CASCADE", ), nullable=False), From b7df3e82078214d826871fa1e16cdf79f093d1ff Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Wed, 11 Jan 2023 11:09:33 +0100 Subject: [PATCH 05/19] refactor(db): create cor_type_site --- .../ce54ba49ce5c_create_cor_type_site.py | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 backend/gn_module_monitoring/migrations/ce54ba49ce5c_create_cor_type_site.py diff --git a/backend/gn_module_monitoring/migrations/ce54ba49ce5c_create_cor_type_site.py b/backend/gn_module_monitoring/migrations/ce54ba49ce5c_create_cor_type_site.py new file mode 100644 index 000000000..41bf81aed --- /dev/null +++ b/backend/gn_module_monitoring/migrations/ce54ba49ce5c_create_cor_type_site.py @@ -0,0 +1,45 @@ + +"""create_cor_type_site + +Revision ID: ce54ba49ce5c +Revises: +Create Date: 2022-12-06 16:18:24.512562 + +""" +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = "ce54ba49ce5c" +down_revision = "b53bafb13ce8" +branch_labels = None +depends_on = None + +monitorings_schema = "gn_monitoring" +referent_schema = "gn_commons" + +def upgrade(): + op.create_table( + "cor_type_site", + sa.Column( + "id_type_site", + sa.Integer(), + sa.ForeignKey( + f"{monitorings_schema}.bib_type_site.id_nomenclature", + name="fk_cor_module_type_id_nomenclature", + ondelete="CASCADE", + onupdate="CASCADE", + ), + nullable=False, + ), + sa.Column("id_base_sites", sa.Integer(),sa.ForeignKey( + f"{referent_schema}.t_base_sites.id_base_site", + name="fk_cor_type_site_id_base_site", + ondelete="CASCADE", + onupdate="CASCADE", + ), nullable=False), + schema=monitorings_schema, + ) + +def downgrade(): + op.drop_table("cor_type_site", schema=monitorings_schema) From 1bf03c2597654a5173fc4d87f7bc335741fd18ec Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Wed, 11 Jan 2023 11:23:29 +0100 Subject: [PATCH 06/19] fix(db): renamed column --- .../migrations/ce54ba49ce5c_create_cor_type_site.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/gn_module_monitoring/migrations/ce54ba49ce5c_create_cor_type_site.py b/backend/gn_module_monitoring/migrations/ce54ba49ce5c_create_cor_type_site.py index 41bf81aed..2a50c7b5f 100644 --- a/backend/gn_module_monitoring/migrations/ce54ba49ce5c_create_cor_type_site.py +++ b/backend/gn_module_monitoring/migrations/ce54ba49ce5c_create_cor_type_site.py @@ -32,7 +32,7 @@ def upgrade(): ), nullable=False, ), - sa.Column("id_base_sites", sa.Integer(),sa.ForeignKey( + sa.Column("id_base_site", sa.Integer(),sa.ForeignKey( f"{referent_schema}.t_base_sites.id_base_site", name="fk_cor_type_site_id_base_site", ondelete="CASCADE", From 4c81b894213b8b244473c9a6c116c7d1e2d5571c Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Wed, 11 Jan 2023 11:24:25 +0100 Subject: [PATCH 07/19] refactor(api): update models to fit migrations --- .../gn_module_monitoring/monitoring/models.py | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/backend/gn_module_monitoring/monitoring/models.py b/backend/gn_module_monitoring/monitoring/models.py index 3ec76740d..9f894a464 100644 --- a/backend/gn_module_monitoring/monitoring/models.py +++ b/backend/gn_module_monitoring/monitoring/models.py @@ -22,8 +22,9 @@ from gn_module_monitoring.monitoring.queries import Query as MonitoringQuery -cor_module_categorie = DB.Table( - "cor_module_categorie", + +cor_module_type = DB.Table( + "cor_module_type", DB.Column( "id_module", DB.Integer, @@ -31,27 +32,29 @@ primary_key=True, ), DB.Column( - "id_categorie", + "id_type_site", DB.Integer, - DB.ForeignKey("gn_monitoring.bib_categorie_site.id_categorie"), + DB.ForeignKey("gn_monitoring.bib_type_site.id_nomenclature"), primary_key=True, ), schema="gn_monitoring") -cor_site_type_categorie = DB.Table( - "cor_site_type_categorie", + +cor_type_site = DB.Table( + "cor_type_site", DB.Column( - "id_nomenclature", + "id_base_site", DB.Integer, - DB.ForeignKey("ref_nomenclatures.t_nomenclatures.id_nomenclature"), + DB.ForeignKey("gn_monitoring.t_base_sites.id_base_site"), primary_key=True, ), DB.Column( - "id_categorie", + "id_type_site", DB.Integer, - DB.ForeignKey("gn_monitoring.bib_categorie_site.id_categorie"), + DB.ForeignKey("gn_monitoring.bib_type_site.id_nomenclature"), primary_key=True, ), schema="gn_monitoring") + @serializable class BibCategorieSite(DB.Model): __tablename__ = "bib_categorie_site" @@ -351,9 +354,9 @@ class TMonitoringModules(TModules): lazy="joined", ) - categories = DB.relationship( - "BibCategorieSite", - secondary=cor_module_categorie, + types = DB.relationship( + "BibTypeSite", + secondary=cor_type_site, lazy="joined" ) From 6cd3189f8c3eddac3b3d4aaea3d2eac69e51e1a9 Mon Sep 17 00:00:00 2001 From: Andria Capai Date: Wed, 11 Jan 2023 17:32:19 +0100 Subject: [PATCH 08/19] fix(db):change bib_categorie_site to bib_type_site Adding : cor_site_module cor_site_type revision alembic to create function and trigger in order to add bib_type_site but only with nomenclature 'TYPE_SITE' upgrade and downgrade works [Refs ticket]: #3 Reviewed-by: andriac --- backend/gn_module_monitoring/blueprint.py | 4 +- ...remove_id_module_from_sites_complements.py | 2 +- ...=> a54bafb13ce8_create_cor_module_type.py} | 18 ++-- .../b53bafb13ce8_create_bib_categorie_site.py | 60 ----------- .../b53bafb13ce8_create_bib_type_site.py | 99 +++++++++++++++++++ .../c54bafb13ce8_create_cor_type_site.py | 45 +++++++++ .../data/downgrade_delete_gn_monitoring.sql | 21 ++++ ...bafb13ce8_create_cor_site_type_category.py | 47 --------- .../gn_module_monitoring/monitoring/admin.py | 6 +- .../gn_module_monitoring/monitoring/models.py | 50 +++++----- .../monitoring/schemas.py | 6 +- .../gn_module_monitoring/routes/data_utils.py | 4 +- backend/gn_module_monitoring/routes/site.py | 14 +-- .../tests/fixtures/site.py | 4 +- .../tests/test_routes/test_site.py | 6 +- 15 files changed, 225 insertions(+), 161 deletions(-) rename backend/gn_module_monitoring/migrations/{a54bafb13ce8_create_cor_module_category.py => a54bafb13ce8_create_cor_module_type.py} (63%) delete mode 100644 backend/gn_module_monitoring/migrations/b53bafb13ce8_create_bib_categorie_site.py create mode 100644 backend/gn_module_monitoring/migrations/b53bafb13ce8_create_bib_type_site.py create mode 100644 backend/gn_module_monitoring/migrations/c54bafb13ce8_create_cor_type_site.py create mode 100644 backend/gn_module_monitoring/migrations/data/downgrade_delete_gn_monitoring.sql delete mode 100644 backend/gn_module_monitoring/migrations/e64bafb13ce8_create_cor_site_type_category.py diff --git a/backend/gn_module_monitoring/blueprint.py b/backend/gn_module_monitoring/blueprint.py index dabfe10de..659176009 100644 --- a/backend/gn_module_monitoring/blueprint.py +++ b/backend/gn_module_monitoring/blueprint.py @@ -7,7 +7,7 @@ from geonature.core.admin.admin import admin as flask_admin from geonature.utils.env import DB -from gn_module_monitoring.monitoring.admin import BibCategorieSiteView +from gn_module_monitoring.monitoring.admin import BibTypeSiteView from .command.cmd import commands blueprint = Blueprint("monitorings", __name__) @@ -17,4 +17,4 @@ for cmd in commands: blueprint.cli.add_command(cmd) -flask_admin.add_view(BibCategorieSiteView(DB.session, name="Catégories de sites", category="Monitorings")) +flask_admin.add_view(BibTypeSiteView(DB.session, name="Catégories de sites", category="Monitorings")) diff --git a/backend/gn_module_monitoring/migrations/6673266fb79c_remove_id_module_from_sites_complements.py b/backend/gn_module_monitoring/migrations/6673266fb79c_remove_id_module_from_sites_complements.py index ca6d04879..bfd006412 100644 --- a/backend/gn_module_monitoring/migrations/6673266fb79c_remove_id_module_from_sites_complements.py +++ b/backend/gn_module_monitoring/migrations/6673266fb79c_remove_id_module_from_sites_complements.py @@ -12,7 +12,7 @@ # revision identifiers, used by Alembic. revision = "6673266fb79c" -down_revision = "e64bafb13ce8" +down_revision = "c54bafb13ce8" branch_labels = None depends_on = None diff --git a/backend/gn_module_monitoring/migrations/a54bafb13ce8_create_cor_module_category.py b/backend/gn_module_monitoring/migrations/a54bafb13ce8_create_cor_module_type.py similarity index 63% rename from backend/gn_module_monitoring/migrations/a54bafb13ce8_create_cor_module_category.py rename to backend/gn_module_monitoring/migrations/a54bafb13ce8_create_cor_module_type.py index 491198526..9c29174da 100644 --- a/backend/gn_module_monitoring/migrations/a54bafb13ce8_create_cor_module_category.py +++ b/backend/gn_module_monitoring/migrations/a54bafb13ce8_create_cor_module_type.py @@ -1,4 +1,4 @@ -"""create_cor_module_category +"""create_cor_module_type Revision ID: a54bafb13ce8 Revises: @@ -10,7 +10,7 @@ # revision identifiers, used by Alembic. revision = "a54bafb13ce8" -down_revision = "f24adb481f54" +down_revision = "b53bafb13ce8" branch_labels = None depends_on = None @@ -20,13 +20,13 @@ def upgrade(): op.create_table( - "cor_module_categorie", + "cor_module_type", sa.Column( - "id_categorie", + "id_type_site", sa.Integer(), sa.ForeignKey( - f"{monitorings_schema}.bib_categorie_site.id_categorie", - name="fk_cor_module_categorie_id_categorie", + f"{monitorings_schema}.bib_type_site.id_type_site", + name="fk_cor_module_type_id_type_site", ondelete="CASCADE", onupdate="CASCADE", ), @@ -34,14 +34,14 @@ def upgrade(): ), sa.Column("id_module", sa.Integer(),sa.ForeignKey( f"{referent_schema}.t_modules.id_module", - name="fk_cor_module_categorie_id_module", + name="fk_cor_module_type_id_module", ondelete="CASCADE", onupdate="CASCADE", ), nullable=False), - sa.PrimaryKeyConstraint("id_categorie", "id_module", name="pk_cor_module_categorie"), + sa.PrimaryKeyConstraint("id_nomenclature", "id_module", name="pk_cor_module_type"), schema=monitorings_schema, ) def downgrade(): - op.drop_table("cor_module_categorie", schema=monitorings_schema) + op.drop_table("cor_module_type", schema=monitorings_schema) diff --git a/backend/gn_module_monitoring/migrations/b53bafb13ce8_create_bib_categorie_site.py b/backend/gn_module_monitoring/migrations/b53bafb13ce8_create_bib_categorie_site.py deleted file mode 100644 index 33d6ebc8d..000000000 --- a/backend/gn_module_monitoring/migrations/b53bafb13ce8_create_bib_categorie_site.py +++ /dev/null @@ -1,60 +0,0 @@ -"""create_bib_categorie_site - -Revision ID: b53bafb13ce8 -Revises: -Create Date: 2022-12-06 16:18:24.512562 - -""" -from alembic import op -import sqlalchemy as sa - -# revision identifiers, used by Alembic. -revision = "b53bafb13ce8" -down_revision = "e78003460441" -branch_labels = None -depends_on = None - -monitorings_schema = "gn_monitoring" - - -def upgrade(): - op.create_table( - "bib_categorie_site", - sa.Column("id_categorie", sa.Integer(), nullable=False), - sa.Column("label", sa.String(), nullable=False), - sa.Column("config", sa.JSON(), nullable=True), - sa.PrimaryKeyConstraint("id_categorie"), - schema=monitorings_schema, - ) - op.create_index( - op.f("ix_bib_categorie_site_id"), - "bib_categorie_site", - ["id_categorie"], - unique=False, - schema=monitorings_schema, - ) - op.add_column( - "t_base_sites", - sa.Column( - "id_categorie", - sa.Integer(), - sa.ForeignKey( - f"{monitorings_schema}.bib_categorie_site.id_categorie", - name="fk_t_base_sites_id_categorie", - ondelete="CASCADE", - ), - nullable=True, # TODO: see migration? nullable is conservative here - ), - schema=monitorings_schema, - ) - - -def downgrade(): - op.drop_constraint("fk_t_base_sites_id_categorie", "t_base_sites", schema=monitorings_schema) - op.drop_column("t_base_sites", "id_categorie", schema=monitorings_schema) - op.drop_index( - op.f("ix_bib_categorie_site_id"), - table_name="bib_categorie_site", - schema=monitorings_schema, - ) - op.drop_table("bib_categorie_site", schema=monitorings_schema) diff --git a/backend/gn_module_monitoring/migrations/b53bafb13ce8_create_bib_type_site.py b/backend/gn_module_monitoring/migrations/b53bafb13ce8_create_bib_type_site.py new file mode 100644 index 000000000..cb82d4624 --- /dev/null +++ b/backend/gn_module_monitoring/migrations/b53bafb13ce8_create_bib_type_site.py @@ -0,0 +1,99 @@ +"""create_bib_type_site + +Revision ID: b53bafb13ce8 +Revises: +Create Date: 2022-12-06 16:18:24.512562 + +""" +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = "b53bafb13ce8" +down_revision = "e78003460441" +branch_labels = None +depends_on = None + +monitorings_schema = "gn_monitoring" +nomenclature_schema = "ref_nomenclatures" + +# TODO : check if id_type = https://stackoverflow.com/questions/48737407/sqlalchemy-check-constraint-with-join +def upgrade(): + op.execute("DROP TABLE IF EXISTS gn_monitoring.bib_site_type;") + op.create_table( + "bib_type_site", + sa.Column("id_type_site",sa.Integer(), nullable=False), + sa.PrimaryKeyConstraint('id_type_site', name=op.f('pk_type_site')), + sa.Column("id_nomenclature", sa.Integer(), sa.ForeignKey( + f"{nomenclature_schema}.t_nomenclatures.id_nomenclature", + name="fk_t_nomenclatures_id_nomenclature", + ), + nullable=False, + unique=True), + sa.Column("config", sa.JSON(), nullable=True), + schema=monitorings_schema, + ) + op.create_index( + op.f("ix_bib_type_site_id"), + "bib_type_site", + ["id_nomenclature"], + unique=True, + schema=monitorings_schema, + ) + statement = sa.text( + f""" + CREATE OR REPLACE FUNCTION {monitorings_schema}.ck_bib_type_site_id_nomenclature() + RETURNS trigger + LANGUAGE plpgsql + AS $function$ + BEGIN + perform {nomenclature_schema}.check_nomenclature_type_by_mnemonique(NEW.id_nomenclature, :mnemonique ); + RETURN NEW; + END; + $function$ + ; + DROP TRIGGER IF EXISTS ck_bib_type_site_id_nomenclature on gn_monitoring.bib_type_site; + CREATE TRIGGER ck_bib_type_site_id_nomenclature BEFORE + INSERT + OR + UPDATE ON {monitorings_schema}.bib_type_site FOR EACH ROW EXECUTE PROCEDURE {monitorings_schema}.ck_bib_type_site_id_nomenclature(); + """ + ).bindparams(mnemonique='TYPE_SITE') + op.execute(statement) + + # op.add_column( + # "t_base_sites", + # sa.Column( + # "id_categorie", + # sa.Integer(), + # sa.ForeignKey( + # f"{monitorings_schema}.bib_type_site.id_categorie", + # name="fk_t_base_sites_id_categorie", + # ondelete="CASCADE", + # ), + # nullable=True, # TODO: see migration? nullable is conservative here + # ), + # schema=monitorings_schema, + # ) + + +def downgrade(): + + # op.drop_constraint("fk_cor_type_site_id_base_site", "t_base_sites", schema=monitorings_schema) + # op.drop_constraint("fk_cor_module_type_id_type_site", "t_modules", schema=monitorings_schema) + # op.drop_column("t_base_sites", "id_categorie", schema=monitorings_schema) + statement = sa.text( + f""" + DROP TRIGGER IF EXISTS ck_bib_type_site_id_nomenclature on gn_monitoring.bib_type_site; + DROP FUNCTION IF EXISTS {monitorings_schema}.ck_bib_type_site_id_nomenclature; + """ + ) + op.execute(statement) + op.drop_index( + op.f("ix_bib_type_site_id"), + table_name="bib_type_site", + schema=monitorings_schema, + ) + op.drop_table("bib_type_site", schema=monitorings_schema) + + diff --git a/backend/gn_module_monitoring/migrations/c54bafb13ce8_create_cor_type_site.py b/backend/gn_module_monitoring/migrations/c54bafb13ce8_create_cor_type_site.py new file mode 100644 index 000000000..937fe5df3 --- /dev/null +++ b/backend/gn_module_monitoring/migrations/c54bafb13ce8_create_cor_type_site.py @@ -0,0 +1,45 @@ +"""create_cor_type_site + +Revision ID: c54bafb13ce8 +Revises: +Create Date: 2022-12-06 16:18:24.512562 + +""" +from alembic import op +import sqlalchemy as sa + +# revision identifiers, used by Alembic. +revision = "c54bafb13ce8" +down_revision = "a54bafb13ce8" +branch_labels = None +depends_on = None + +monitorings_schema = "gn_monitoring" + +def upgrade(): + op.create_table( + "cor_type_site", + sa.Column( + "id_type_site", + sa.Integer(), + sa.ForeignKey( + f"{monitorings_schema}.bib_type_site.id_type_site", + name="fk_cor_type_site_id_type_site", + ondelete="CASCADE", + onupdate="CASCADE", + ), + nullable=False, + ), + sa.Column("id_base_site", sa.Integer(),sa.ForeignKey( + f"{monitorings_schema}.t_base_sites.id_base_site", + name="fk_cor_type_site_id_base_site", + ondelete="CASCADE", + onupdate="CASCADE", + ), nullable=False), + sa.PrimaryKeyConstraint("id_type_site", "id_base_site", name="pk_cor_type_site"), + schema=monitorings_schema, + ) + + +def downgrade(): + op.drop_table("cor_type_site", schema=monitorings_schema) diff --git a/backend/gn_module_monitoring/migrations/data/downgrade_delete_gn_monitoring.sql b/backend/gn_module_monitoring/migrations/data/downgrade_delete_gn_monitoring.sql new file mode 100644 index 000000000..e0e9ac341 --- /dev/null +++ b/backend/gn_module_monitoring/migrations/data/downgrade_delete_gn_monitoring.sql @@ -0,0 +1,21 @@ +DELETE FROM gn_commons.t_modules +WHERE module_code in ('MONITORINGS') +RETURNING *; +DELETE FROM gn_commons.bib_tables_location +WHERE schema_name in ( + 't_module_complements', + 't_observations', + 't_sites_groups' + ); +-- ATTENTION DEPENDANCES PRESENTES SI MODULE INSTALLE AVEC MONITORING BIEN SUPPRIMER LES MODULES AVANT -- +DROP TABLE IF EXISTS gn_monitoring.t_site_complements; +DROP TRIGGER IF EXISTS tri_meta_dates_change_t_sites_groups ON gn_monitoring.t_sites_groups; +DROP TABLE IF EXISTS gn_monitoring.t_module_complements; +DROP TABLE IF EXISTS gn_monitoring.t_sites_groups; +DROP TABLE IF EXISTS gn_monitoring.t_observation_details; +DELETE FROM gn_permissions.t_objects +WHERE code_object like 'GNM%'; +DROP VIEW IF EXISTS gn_monitoring.v_synthese_chiro; +DROP TABLE IF EXISTS gn_monitoring.t_observation_complements RESTRICT; +DROP TABLE IF EXISTS gn_monitoring.t_observations RESTRICT; +DROP TABLE IF EXISTS gn_monitoring.t_visit_complements; \ No newline at end of file diff --git a/backend/gn_module_monitoring/migrations/e64bafb13ce8_create_cor_site_type_category.py b/backend/gn_module_monitoring/migrations/e64bafb13ce8_create_cor_site_type_category.py deleted file mode 100644 index 2dfcf3412..000000000 --- a/backend/gn_module_monitoring/migrations/e64bafb13ce8_create_cor_site_type_category.py +++ /dev/null @@ -1,47 +0,0 @@ -"""create_cor_site_type_category - -Revision ID: e64bafb13ce8 -Revises: -Create Date: 2022-12-06 16:18:24.512562 - -""" -from alembic import op -import sqlalchemy as sa - -# revision identifiers, used by Alembic. -revision = "e64bafb13ce8" -down_revision = "a54bafb13ce8" -branch_labels = None -depends_on = None - -monitorings_schema = "gn_monitoring" -referent_schema = "ref_nomenclatures" - - -def upgrade(): - op.create_table( - "cor_site_type_categorie", - sa.Column( - "id_categorie", - sa.Integer(), - sa.ForeignKey( - f"{monitorings_schema}.bib_categorie_site.id_categorie", - name="fk_cor_site_type_categorie_id_categorie", - ondelete="CASCADE", - onupdate="CASCADE", - ), - nullable=False, - ), - sa.Column("id_nomenclature", sa.Integer(),sa.ForeignKey( - f"{referent_schema}.t_nomenclatures.id_nomenclature", - name="fk_cor_site_type_categorie_id_type", - ondelete="CASCADE", - onupdate="CASCADE", - ), nullable=False), - sa.PrimaryKeyConstraint("id_categorie", "id_nomenclature", name="pk_cor_site_type_categorie"), - schema=monitorings_schema, - ) - - -def downgrade(): - op.drop_table("cor_site_type_categorie", schema=monitorings_schema) diff --git a/backend/gn_module_monitoring/monitoring/admin.py b/backend/gn_module_monitoring/monitoring/admin.py index e7184b8ce..3a75b34cc 100644 --- a/backend/gn_module_monitoring/monitoring/admin.py +++ b/backend/gn_module_monitoring/monitoring/admin.py @@ -3,13 +3,13 @@ from geonature.utils.env import DB from pypnnomenclature.models import TNomenclatures, BibNomenclaturesTypes -from gn_module_monitoring.monitoring.models import BibCategorieSite +from gn_module_monitoring.monitoring.models import BibTypeSite SITE_TYPE = "TYPE_SITE" -class BibCategorieSiteView(CruvedProtectedMixin, ModelView): +class BibTypeSiteView(CruvedProtectedMixin, ModelView): """ Surcharge de l'administration des catégories de sites """ @@ -19,7 +19,7 @@ class BibCategorieSiteView(CruvedProtectedMixin, ModelView): def __init__(self, session, **kwargs): # Référence au model utilisé - super(BibCategorieSiteView, self).__init__(BibCategorieSite, session, **kwargs) + super(BibTypeSiteView, self).__init__(BibTypeSite, session, **kwargs) def get_only_type_site_asc(): return ( diff --git a/backend/gn_module_monitoring/monitoring/models.py b/backend/gn_module_monitoring/monitoring/models.py index 3ec76740d..3cf72967a 100644 --- a/backend/gn_module_monitoring/monitoring/models.py +++ b/backend/gn_module_monitoring/monitoring/models.py @@ -22,8 +22,8 @@ from gn_module_monitoring.monitoring.queries import Query as MonitoringQuery -cor_module_categorie = DB.Table( - "cor_module_categorie", +cor_module_type = DB.Table( + "cor_module_type", DB.Column( "id_module", DB.Integer, @@ -31,41 +31,42 @@ primary_key=True, ), DB.Column( - "id_categorie", + "id_nomenclature", DB.Integer, - DB.ForeignKey("gn_monitoring.bib_categorie_site.id_categorie"), + DB.ForeignKey("gn_monitoring.bib_type_site.id_nomenclature"), primary_key=True, ), schema="gn_monitoring") -cor_site_type_categorie = DB.Table( - "cor_site_type_categorie", +cor_type_site = DB.Table( + "cor_type_site", DB.Column( - "id_nomenclature", + "id_base_site", DB.Integer, - DB.ForeignKey("ref_nomenclatures.t_nomenclatures.id_nomenclature"), + DB.ForeignKey("gn_monitoring.t_base_sites.id_base_site"), primary_key=True, ), DB.Column( - "id_categorie", + "id_type_site", DB.Integer, - DB.ForeignKey("gn_monitoring.bib_categorie_site.id_categorie"), + DB.ForeignKey("gn_monitoring.bib_type_site.id_type_site"), primary_key=True, ), schema="gn_monitoring") + @serializable -class BibCategorieSite(DB.Model): - __tablename__ = "bib_categorie_site" +class BibTypeSite(DB.Model): + __tablename__ = "bib_type_site" __table_args__ = {"schema": "gn_monitoring"} query_class = MonitoringQuery - id_categorie = DB.Column(DB.Integer, primary_key=True, nullable=False, unique=True) - label = DB.Column(DB.String, nullable=False) - config = DB.Column(JSONB) - site_type = DB.relationship( - "TNomenclatures", - secondary=cor_site_type_categorie, - lazy="joined", + id_type_site = DB.Column( + DB.Integer, + primary_key=True, + nullable=False, + unique=True ) + id_nomenclature = DB.Column(DB.Integer,DB.ForeignKey("ref_nomenclatures.t_nomenclatures.id_nomenclature"), nullable=False, unique=True) + config = DB.Column(JSONB) @serializable @@ -240,6 +241,11 @@ class TMonitoringSites(TBaseSites): where(TBaseSites.id_base_site==id_base_site).\ correlate_except(TBaseSites) ) + type_site = DB.relationship( + "BibTypeSite", + secondary=cor_type_site, + lazy="joined" + ) @serializable class TMonitoringSitesGroups(DB.Model): @@ -351,9 +357,9 @@ class TMonitoringModules(TModules): lazy="joined", ) - categories = DB.relationship( - "BibCategorieSite", - secondary=cor_module_categorie, + type_site = DB.relationship( + "BibTypeSite", + secondary=cor_module_type, lazy="joined" ) diff --git a/backend/gn_module_monitoring/monitoring/schemas.py b/backend/gn_module_monitoring/monitoring/schemas.py index 2721de0e8..bca3a523d 100644 --- a/backend/gn_module_monitoring/monitoring/schemas.py +++ b/backend/gn_module_monitoring/monitoring/schemas.py @@ -6,7 +6,7 @@ from pypnnomenclature.schemas import NomenclatureSchema from gn_module_monitoring.monitoring.models import ( - BibCategorieSite, + BibTypeSite, TMonitoringSites, TMonitoringSitesGroups, ) @@ -46,12 +46,12 @@ def serialize_geojson(self, obj): return geojson.dumps(obj.as_geofeature().get("geometry")) -class BibCategorieSiteSchema(SQLAlchemyAutoSchema): +class BibTypeSiteSchema(SQLAlchemyAutoSchema): site_type = fields.Nested( NomenclatureSchema(only=("id_nomenclature", "label_fr")), many=True, dump_only=True ) class Meta: - model = BibCategorieSite + model = BibTypeSite include_fk = True load_instance = True diff --git a/backend/gn_module_monitoring/routes/data_utils.py b/backend/gn_module_monitoring/routes/data_utils.py index 593002934..4c4c3cc25 100644 --- a/backend/gn_module_monitoring/routes/data_utils.py +++ b/backend/gn_module_monitoring/routes/data_utils.py @@ -32,7 +32,7 @@ from ..blueprint import blueprint from ..config.repositories import get_config -from gn_module_monitoring.monitoring.models import TMonitoringSitesGroups, TMonitoringSites, BibCategorieSite +from gn_module_monitoring.monitoring.models import TMonitoringSitesGroups, TMonitoringSites, BibTypeSite model_dict = { "habitat": Habref, @@ -40,7 +40,7 @@ "user": User, "taxonomy": Taxref, "dataset": TDatasets, - "categorie": BibCategorieSite, + "type_site": BibTypeSite, "observer_list": UserList, "taxonomy_list": BibListes, "sites_group": TMonitoringSitesGroups, diff --git a/backend/gn_module_monitoring/routes/site.py b/backend/gn_module_monitoring/routes/site.py index 1a53ca316..086776f8d 100644 --- a/backend/gn_module_monitoring/routes/site.py +++ b/backend/gn_module_monitoring/routes/site.py @@ -4,7 +4,7 @@ from werkzeug.datastructures import MultiDict from gn_module_monitoring.blueprint import blueprint -from gn_module_monitoring.monitoring.models import BibCategorieSite, TMonitoringSites +from gn_module_monitoring.monitoring.models import BibTypeSite, TMonitoringSites from gn_module_monitoring.utils.routes import ( filter_params, get_limit_offset, @@ -12,7 +12,7 @@ paginate, sort, ) -from gn_module_monitoring.monitoring.schemas import MonitoringSitesSchema,BibCategorieSiteSchema +from gn_module_monitoring.monitoring.schemas import MonitoringSitesSchema,BibTypeSiteSchema @blueprint.route("/sites/categories", methods=["GET"]) @@ -23,12 +23,12 @@ def get_categories(): params=params, default_sort="id_categorie", default_direction="desc" ) - query = filter_params(query=BibCategorieSite.query, params=params) + query = filter_params(query=BibTypeSite.query, params=params) query = sort(query=query, sort=sort_label, sort_dir=sort_dir) return paginate( query=query, - schema=BibCategorieSiteSchema, + schema=BibTypeSiteSchema, limit=limit, page=page, ) @@ -36,9 +36,9 @@ def get_categories(): @blueprint.route("/sites/categories/", methods=["GET"]) def get_categories_by_id(id_categorie): - query = BibCategorieSite.query.filter_by(id_categorie=id_categorie) + query = BibTypeSite.query.filter_by(id_categorie=id_categorie) res = query.first() - schema = BibCategorieSiteSchema() + schema = BibTypeSiteSchema() return schema.dump(res) @@ -51,7 +51,7 @@ def get_sites(): params=params, default_sort="id_base_site", default_direction="desc" ) query = TMonitoringSites.query.join( - BibCategorieSite, TMonitoringSites.id_categorie == BibCategorieSite.id_categorie + BibTypeSite, TMonitoringSites.id_categorie == BibTypeSite.id_categorie ) query = filter_params(query=query, params=params) query = sort(query=query, sort=sort_label, sort_dir=sort_dir) diff --git a/backend/gn_module_monitoring/tests/fixtures/site.py b/backend/gn_module_monitoring/tests/fixtures/site.py index 415ffe321..bab6eba95 100644 --- a/backend/gn_module_monitoring/tests/fixtures/site.py +++ b/backend/gn_module_monitoring/tests/fixtures/site.py @@ -4,7 +4,7 @@ from pypnnomenclature.models import BibNomenclaturesTypes, TNomenclatures from shapely.geometry import Point -from gn_module_monitoring.monitoring.models import BibCategorieSite, TMonitoringSites +from gn_module_monitoring.monitoring.models import BibTypeSite, TMonitoringSites from gn_module_monitoring.tests.fixtures.sites_groups import sites_groups @@ -22,7 +22,7 @@ def categories(site_type): {"label": "eolienne", "config": {}, "site_type": [site_type]}, ] - categories = {cat["label"]: BibCategorieSite(**cat) for cat in categories} + categories = {cat["label"]: BibTypeSite(**cat) for cat in categories} with db.session.begin_nested(): db.session.add_all(categories.values()) diff --git a/backend/gn_module_monitoring/tests/test_routes/test_site.py b/backend/gn_module_monitoring/tests/test_routes/test_site.py index ecbbb3b68..1c7e6d323 100644 --- a/backend/gn_module_monitoring/tests/test_routes/test_site.py +++ b/backend/gn_module_monitoring/tests/test_routes/test_site.py @@ -1,7 +1,7 @@ import pytest from flask import url_for -from gn_module_monitoring.monitoring.schemas import BibCategorieSiteSchema, MonitoringSitesSchema +from gn_module_monitoring.monitoring.schemas import BibTypeSiteSchema, MonitoringSitesSchema @pytest.mark.usefixtures("client_class", "temporary_transaction") @@ -17,7 +17,7 @@ def test_get_categories_by_id(self, categories): assert r.json["label"] == cat.label def test_get_categories(self, categories): - schema = BibCategorieSiteSchema() + schema = BibTypeSiteSchema() r = self.client.get(url_for("monitorings.get_categories")) @@ -26,7 +26,7 @@ def test_get_categories(self, categories): def test_get_categories_label(self, categories): label = list(categories.keys())[0] - schema = BibCategorieSiteSchema() + schema = BibTypeSiteSchema() r = self.client.get(url_for("monitorings.get_categories"), query_string={"label": label}) assert schema.dump(categories[label]) in r.json["items"] From 2f73a35c503740aace93feb5b7b52e312e2a8b39 Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Thu, 12 Jan 2023 10:36:35 +0100 Subject: [PATCH 09/19] fix(api): updated models from migrations --- .../gn_module_monitoring/monitoring/models.py | 26 +++++++++---------- .../gn_module_monitoring/tests/conftest.py | 1 + .../tests/fixtures/type_site.py | 16 ++++++++++++ .../test_models/test_bib_type_site.py | 13 ++++++++++ 4 files changed, 42 insertions(+), 14 deletions(-) create mode 100644 backend/gn_module_monitoring/tests/fixtures/type_site.py create mode 100644 backend/gn_module_monitoring/tests/test_monitoring/test_models/test_bib_type_site.py diff --git a/backend/gn_module_monitoring/monitoring/models.py b/backend/gn_module_monitoring/monitoring/models.py index 9f894a464..843d4205c 100644 --- a/backend/gn_module_monitoring/monitoring/models.py +++ b/backend/gn_module_monitoring/monitoring/models.py @@ -19,10 +19,8 @@ from geonature.core.gn_commons.models import TModules, cor_module_dataset from pypnusershub.db.models import User from geonature.core.gn_monitoring.models import corVisitObserver - from gn_module_monitoring.monitoring.queries import Query as MonitoringQuery - cor_module_type = DB.Table( "cor_module_type", DB.Column( @@ -38,7 +36,6 @@ primary_key=True, ), schema="gn_monitoring") - cor_type_site = DB.Table( "cor_type_site", DB.Column( @@ -56,19 +53,15 @@ @serializable -class BibCategorieSite(DB.Model): - __tablename__ = "bib_categorie_site" +class BibTypeSite(DB.Model): + __tablename__ = "bib_type_site" __table_args__ = {"schema": "gn_monitoring"} query_class = MonitoringQuery - id_categorie = DB.Column(DB.Integer, primary_key=True, nullable=False, unique=True) - label = DB.Column(DB.String, nullable=False) + id_nomenclature = DB.Column(DB.ForeignKey("ref_nomenclatures.t_nomenclatures.id_nomenclature"), + nullable=False, + primary_key=True) config = DB.Column(JSONB) - site_type = DB.relationship( - "TNomenclatures", - secondary=cor_site_type_categorie, - lazy="joined", - ) @serializable @@ -243,6 +236,11 @@ class TMonitoringSites(TBaseSites): where(TBaseSites.id_base_site==id_base_site).\ correlate_except(TBaseSites) ) + type_site = DB.relationship( + "BibTypeSite", + secondary=cor_type_site, + lazy="joined" + ) @serializable class TMonitoringSitesGroups(DB.Model): @@ -354,9 +352,9 @@ class TMonitoringModules(TModules): lazy="joined", ) - types = DB.relationship( + type_site = DB.relationship( "BibTypeSite", - secondary=cor_type_site, + secondary=cor_module_type, lazy="joined" ) diff --git a/backend/gn_module_monitoring/tests/conftest.py b/backend/gn_module_monitoring/tests/conftest.py index 6b1107a1d..422312d22 100644 --- a/backend/gn_module_monitoring/tests/conftest.py +++ b/backend/gn_module_monitoring/tests/conftest.py @@ -5,4 +5,5 @@ "gn_module_monitoring.tests.fixtures.module", "gn_module_monitoring.tests.fixtures.site", "gn_module_monitoring.tests.fixtures.sites_groups", + "gn_module_monitoring.tests.fixtures.type_site", ] diff --git a/backend/gn_module_monitoring/tests/fixtures/type_site.py b/backend/gn_module_monitoring/tests/fixtures/type_site.py new file mode 100644 index 000000000..cba51e332 --- /dev/null +++ b/backend/gn_module_monitoring/tests/fixtures/type_site.py @@ -0,0 +1,16 @@ +import pytest +from geonature.utils.env import db +from pypnnomenclature.models import BibNomenclaturesTypes, TNomenclatures + +from gn_module_monitoring.monitoring.models import BibTypeSite + + +@pytest.fixture +def type_site(): + site_type = TNomenclatures.query.filter( + BibNomenclaturesTypes.mnemonique == "TYPE_SITE", TNomenclatures.mnemonique == "Grotte" + ).one() + type_site = BibTypeSite(id_nomenclature=site_type.id_nomenclature, config={}) + with db.session.begin_nested(): + db.session.add(type_site) + return type_site diff --git a/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_bib_type_site.py b/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_bib_type_site.py new file mode 100644 index 000000000..e5a455a0b --- /dev/null +++ b/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_bib_type_site.py @@ -0,0 +1,13 @@ +import pytest + +from gn_module_monitoring.monitoring.models import BibTypeSite + + +@pytest.mark.usefixtures("temporary_transaction") +class TestBibTypeSite: + def test_get_bib_type_site(self, type_site): + get_type_site = BibTypeSite.query.filter_by( + id_nomenclature=type_site.id_nomenclature + ).one() + + assert get_type_site.id_nomenclature == type_site.id_nomenclature From 1f88752856eb64267cdb553bc4303421e933d1e8 Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Thu, 12 Jan 2023 10:40:41 +0100 Subject: [PATCH 10/19] fix(api): wip: fix admin following migrations --- backend/gn_module_monitoring/blueprint.py | 4 ++-- backend/gn_module_monitoring/monitoring/admin.py | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/gn_module_monitoring/blueprint.py b/backend/gn_module_monitoring/blueprint.py index dabfe10de..cf4957a54 100644 --- a/backend/gn_module_monitoring/blueprint.py +++ b/backend/gn_module_monitoring/blueprint.py @@ -7,7 +7,7 @@ from geonature.core.admin.admin import admin as flask_admin from geonature.utils.env import DB -from gn_module_monitoring.monitoring.admin import BibCategorieSiteView +from gn_module_monitoring.monitoring.admin import BibTypeSiteView from .command.cmd import commands blueprint = Blueprint("monitorings", __name__) @@ -17,4 +17,4 @@ for cmd in commands: blueprint.cli.add_command(cmd) -flask_admin.add_view(BibCategorieSiteView(DB.session, name="Catégories de sites", category="Monitorings")) +flask_admin.add_view(BibTypeSiteView(DB.session, name="Type de sites", category="Monitorings")) diff --git a/backend/gn_module_monitoring/monitoring/admin.py b/backend/gn_module_monitoring/monitoring/admin.py index e7184b8ce..74c628a53 100644 --- a/backend/gn_module_monitoring/monitoring/admin.py +++ b/backend/gn_module_monitoring/monitoring/admin.py @@ -3,15 +3,15 @@ from geonature.utils.env import DB from pypnnomenclature.models import TNomenclatures, BibNomenclaturesTypes -from gn_module_monitoring.monitoring.models import BibCategorieSite +from gn_module_monitoring.monitoring.models import BibTypeSite SITE_TYPE = "TYPE_SITE" -class BibCategorieSiteView(CruvedProtectedMixin, ModelView): +class BibTypeSiteView(CruvedProtectedMixin, ModelView): """ - Surcharge de l'administration des catégories de sites + Surcharge de l'administration des types de sites """ module_code = "MONITORINGS" @@ -19,7 +19,7 @@ class BibCategorieSiteView(CruvedProtectedMixin, ModelView): def __init__(self, session, **kwargs): # Référence au model utilisé - super(BibCategorieSiteView, self).__init__(BibCategorieSite, session, **kwargs) + super(BibTypeSiteView, self).__init__(BibTypeSite, session, **kwargs) def get_only_type_site_asc(): return ( From 4d932a5eb08c131a5b26ae80ffd0a863539148cc Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Thu, 12 Jan 2023 11:16:59 +0100 Subject: [PATCH 11/19] fix(api): update routes and tests To match migration changes --- backend/gn_module_monitoring/routes/site.py | 26 ++++++------- .../tests/fixtures/module.py | 5 +-- .../tests/fixtures/site.py | 38 +++---------------- .../tests/fixtures/type_site.py | 24 ++++++++---- .../test_models/test_bib_type_site.py | 12 +++++- .../test_models/test_module.py | 12 +++--- .../tests/test_routes/test_site.py | 28 ++++++-------- 7 files changed, 64 insertions(+), 81 deletions(-) diff --git a/backend/gn_module_monitoring/routes/site.py b/backend/gn_module_monitoring/routes/site.py index 1a53ca316..3bbc5ba9a 100644 --- a/backend/gn_module_monitoring/routes/site.py +++ b/backend/gn_module_monitoring/routes/site.py @@ -4,7 +4,7 @@ from werkzeug.datastructures import MultiDict from gn_module_monitoring.blueprint import blueprint -from gn_module_monitoring.monitoring.models import BibCategorieSite, TMonitoringSites +from gn_module_monitoring.monitoring.models import BibTypeSite, TMonitoringSites from gn_module_monitoring.utils.routes import ( filter_params, get_limit_offset, @@ -12,33 +12,33 @@ paginate, sort, ) -from gn_module_monitoring.monitoring.schemas import MonitoringSitesSchema,BibCategorieSiteSchema +from gn_module_monitoring.monitoring.schemas import MonitoringSitesSchema,BibTypeSiteSchema -@blueprint.route("/sites/categories", methods=["GET"]) -def get_categories(): +@blueprint.route("/sites/types", methods=["GET"]) +def get_site_types(): params = MultiDict(request.args) limit, page = get_limit_offset(params=params) sort_label, sort_dir = get_sort( - params=params, default_sort="id_categorie", default_direction="desc" + params=params, default_sort="id_nomenclature", default_direction="desc" ) - query = filter_params(query=BibCategorieSite.query, params=params) + query = filter_params(query=BibTypeSite.query, params=params) query = sort(query=query, sort=sort_label, sort_dir=sort_dir) return paginate( query=query, - schema=BibCategorieSiteSchema, + schema=BibTypeSiteSchema, limit=limit, page=page, ) -@blueprint.route("/sites/categories/", methods=["GET"]) -def get_categories_by_id(id_categorie): - query = BibCategorieSite.query.filter_by(id_categorie=id_categorie) +@blueprint.route("/sites/types/", methods=["GET"]) +def get_site_types_by_id(id_site_type): + query = BibTypeSite.query.filter_by(id_nomenclature=id_site_type) res = query.first() - schema = BibCategorieSiteSchema() + schema = BibTypeSiteSchema() return schema.dump(res) @@ -50,9 +50,7 @@ def get_sites(): sort_label, sort_dir = get_sort( params=params, default_sort="id_base_site", default_direction="desc" ) - query = TMonitoringSites.query.join( - BibCategorieSite, TMonitoringSites.id_categorie == BibCategorieSite.id_categorie - ) + query = TMonitoringSites.query query = filter_params(query=query, params=params) query = sort(query=query, sort=sort_label, sort_dir=sort_dir) return paginate( diff --git a/backend/gn_module_monitoring/tests/fixtures/module.py b/backend/gn_module_monitoring/tests/fixtures/module.py index 41d946e37..32bc94787 100644 --- a/backend/gn_module_monitoring/tests/fixtures/module.py +++ b/backend/gn_module_monitoring/tests/fixtures/module.py @@ -4,18 +4,17 @@ from geonature.utils.env import db from gn_module_monitoring.monitoring.models import TMonitoringModules -from gn_module_monitoring.tests.fixtures.site import categories @pytest.fixture -def monitoring_module(categories): +def monitoring_module(types_site): t_monitoring_module = TMonitoringModules( module_code=uuid4(), module_label="test", active_frontend=True, active_backend=False, module_path="test", - categories=list(categories.values()), + type_site=list(types_site.values()), ) with db.session.begin_nested(): diff --git a/backend/gn_module_monitoring/tests/fixtures/site.py b/backend/gn_module_monitoring/tests/fixtures/site.py index 415ffe321..db242bb6d 100644 --- a/backend/gn_module_monitoring/tests/fixtures/site.py +++ b/backend/gn_module_monitoring/tests/fixtures/site.py @@ -1,45 +1,17 @@ import pytest from geoalchemy2.shape import from_shape from geonature.utils.env import db -from pypnnomenclature.models import BibNomenclaturesTypes, TNomenclatures from shapely.geometry import Point -from gn_module_monitoring.monitoring.models import BibCategorieSite, TMonitoringSites -from gn_module_monitoring.tests.fixtures.sites_groups import sites_groups +from gn_module_monitoring.monitoring.models import TMonitoringSites @pytest.fixture() -def site_type(): - return TNomenclatures.query.filter( - BibNomenclaturesTypes.mnemonique == "TYPE_SITE", TNomenclatures.mnemonique == "Grotte" - ).one() - - -@pytest.fixture() -def categories(site_type): - categories = [ - {"label": "gite", "config": {}, "site_type": [site_type]}, - {"label": "eolienne", "config": {}, "site_type": [site_type]}, - ] - - categories = {cat["label"]: BibCategorieSite(**cat) for cat in categories} - - with db.session.begin_nested(): - db.session.add_all(categories.values()) - - return categories - - -@pytest.fixture() -def sites(users, categories, sites_groups): +def sites(users, types_site, sites_groups): user = users["user"] geom_4326 = from_shape(Point(43, 24), srid=4326) sites = {} - # TODO: get_nomenclature from label - site_type = TNomenclatures.query.filter( - BibNomenclaturesTypes.mnemonique == "TYPE_SITE", TNomenclatures.mnemonique == "Grotte" - ).one() - for i, key in enumerate(categories.keys()): + for i, key in enumerate(types_site.keys()): sites[key] = TMonitoringSites( id_inventor=user.id_role, id_digitiser=user.id_role, @@ -47,8 +19,8 @@ def sites(users, categories, sites_groups): base_site_description=f"Description{i}", base_site_code=f"Code{i}", geom=geom_4326, - id_nomenclature_type_site=site_type.id_nomenclature, - id_categorie=categories[key].id_categorie, + id_nomenclature_type_site=types_site[key].id_nomenclature, + type_site=[types_site[key]], id_sites_group=sites_groups["Site_Groupe"].id_sites_group, ) with db.session.begin_nested(): diff --git a/backend/gn_module_monitoring/tests/fixtures/type_site.py b/backend/gn_module_monitoring/tests/fixtures/type_site.py index cba51e332..c77f17b24 100644 --- a/backend/gn_module_monitoring/tests/fixtures/type_site.py +++ b/backend/gn_module_monitoring/tests/fixtures/type_site.py @@ -6,11 +6,21 @@ @pytest.fixture -def type_site(): - site_type = TNomenclatures.query.filter( - BibNomenclaturesTypes.mnemonique == "TYPE_SITE", TNomenclatures.mnemonique == "Grotte" - ).one() - type_site = BibTypeSite(id_nomenclature=site_type.id_nomenclature, config={}) +def nomenclature_site_types(): + return TNomenclatures.query.filter( + BibNomenclaturesTypes.mnemonique == "TYPE_SITE", + TNomenclatures.mnemonique.in_(("Grotte", "Mine")), + ).all() + + +@pytest.fixture +def types_site(nomenclature_site_types): + types_site = { + nomenc_site_type.mnemonique: BibTypeSite( + id_nomenclature=nomenc_site_type.id_nomenclature, config={} + ) + for nomenc_site_type in nomenclature_site_types + } with db.session.begin_nested(): - db.session.add(type_site) - return type_site + db.session.add_all(types_site.values()) + return types_site diff --git a/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_bib_type_site.py b/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_bib_type_site.py index e5a455a0b..ede321732 100644 --- a/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_bib_type_site.py +++ b/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_bib_type_site.py @@ -5,9 +5,19 @@ @pytest.mark.usefixtures("temporary_transaction") class TestBibTypeSite: - def test_get_bib_type_site(self, type_site): + def test_get_bib_type_site(self, types_site): + type_site = list(types_site.values())[0] get_type_site = BibTypeSite.query.filter_by( id_nomenclature=type_site.id_nomenclature ).one() assert get_type_site.id_nomenclature == type_site.id_nomenclature + + def test_get_all_bib_type_site(self, types_site): + get_types_site = BibTypeSite.query.all() + + assert all( + type_site.id_nomenclature + in [get_type_site.id_nomenclature for get_type_site in get_types_site] + for type_site in types_site.values() + ) diff --git a/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_module.py b/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_module.py index fbf606816..a2fdc9383 100644 --- a/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_module.py +++ b/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_module.py @@ -6,14 +6,14 @@ @pytest.mark.usefixtures("temporary_transaction") class TestModule: - def test_module(self, monitoring_module, categories): - cats = monitoring_module.categories - assert cats == list(categories.values()) + def test_module(self, monitoring_module, types_site): + types = monitoring_module.type_site + assert types == list(types_site.values()) - def test_remove_categorie_from_module(self, monitoring_module, categories): + def test_remove_categorie_from_module(self, monitoring_module, types_site): with db.session.begin_nested(): - monitoring_module.categories.pop(0) + monitoring_module.type_site.pop(0) mon = TMonitoringModules.query.filter_by(id_module=monitoring_module.id_module).one() - assert len(mon.categories) == len(categories) - 1 + assert len(mon.type_site) == len(types_site) - 1 diff --git a/backend/gn_module_monitoring/tests/test_routes/test_site.py b/backend/gn_module_monitoring/tests/test_routes/test_site.py index ecbbb3b68..ff5d5291d 100644 --- a/backend/gn_module_monitoring/tests/test_routes/test_site.py +++ b/backend/gn_module_monitoring/tests/test_routes/test_site.py @@ -1,34 +1,28 @@ import pytest from flask import url_for -from gn_module_monitoring.monitoring.schemas import BibCategorieSiteSchema, MonitoringSitesSchema +from gn_module_monitoring.monitoring.schemas import BibTypeSiteSchema, MonitoringSitesSchema @pytest.mark.usefixtures("client_class", "temporary_transaction") class TestSite: - def test_get_categories_by_id(self, categories): - for cat in categories.values(): + def test_get_site_types_by_id(self, types_site): + for type_site in types_site.values(): r = self.client.get( url_for( - "monitorings.get_categories_by_id", - id_categorie=cat.id_categorie, + "monitorings.get_site_types_by_id", + id_site_type=type_site.id_nomenclature, ) ) - assert r.json["label"] == cat.label + assert r.json["id_nomenclature"] == type_site.id_nomenclature - def test_get_categories(self, categories): - schema = BibCategorieSiteSchema() + def test_get_site_types(self, types_site): + schema = BibTypeSiteSchema() - r = self.client.get(url_for("monitorings.get_categories")) + r = self.client.get(url_for("monitorings.get_site_types")) - assert r.json["count"] >= len(categories) - assert all([schema.dump(cat) in r.json["items"] for cat in categories.values()]) - - def test_get_categories_label(self, categories): - label = list(categories.keys())[0] - schema = BibCategorieSiteSchema() - r = self.client.get(url_for("monitorings.get_categories"), query_string={"label": label}) - assert schema.dump(categories[label]) in r.json["items"] + assert r.json["count"] >= len(types_site) + assert all([schema.dump(cat) in r.json["items"] for cat in types_site.values()]) def test_get_sites(self, sites): schema = MonitoringSitesSchema() From 8115dcb1ebe7e9d573ea713fea7cd5385433607e Mon Sep 17 00:00:00 2001 From: Andria Capai Date: Thu, 12 Jan 2023 11:58:19 +0100 Subject: [PATCH 12/19] feat: flask admin bib_type_site Change bib_categories to bib_type_site into flask admin Adding filtering in list label_fr of type_site to secure the unique constraint Reviewed-by: andriac [Refs ticket]: #3 --- backend/gn_module_monitoring/monitoring/admin.py | 8 +++++--- backend/gn_module_monitoring/monitoring/models.py | 6 +++++- backend/gn_module_monitoring/monitoring/schemas.py | 6 +++--- backend/gn_module_monitoring/routes/data_utils.py | 4 ++-- 4 files changed, 15 insertions(+), 9 deletions(-) diff --git a/backend/gn_module_monitoring/monitoring/admin.py b/backend/gn_module_monitoring/monitoring/admin.py index 74c628a53..5c669b1d4 100644 --- a/backend/gn_module_monitoring/monitoring/admin.py +++ b/backend/gn_module_monitoring/monitoring/admin.py @@ -22,9 +22,11 @@ def __init__(self, session, **kwargs): super(BibTypeSiteView, self).__init__(BibTypeSite, session, **kwargs) def get_only_type_site_asc(): + subquery = DB.session.query(BibTypeSite.id_nomenclature).subquery() return ( DB.session.query(TNomenclatures) .join(TNomenclatures.nomenclature_type) + .filter(TNomenclatures.id_nomenclature.notin_(subquery)) .filter(BibNomenclaturesTypes.mnemonique == SITE_TYPE) .order_by(TNomenclatures.label_fr.asc()) ) @@ -33,12 +35,12 @@ def get_label_fr_nomenclature(x): return x.label_fr def list_label_site_type_formatter(view, _context, model, _name): - return [item.label_fr for item in model.site_type] + return model.site_type.label_fr # Nom de colonne user friendly column_labels = dict(site_type="Type de site") # Description des colonnes - column_descriptions = dict(site_type="Type de site à choisir en lien avec la catégorie") + column_descriptions = dict(site_type="Nomenclature de Type de site à choisir") column_hide_backrefs = False @@ -46,5 +48,5 @@ def list_label_site_type_formatter(view, _context, model, _name): site_type=dict(query_factory=get_only_type_site_asc, get_label=get_label_fr_nomenclature) ) - column_list = ("label", "config", "site_type") + column_list = ("site_type","config") column_formatters = dict(site_type=list_label_site_type_formatter) diff --git a/backend/gn_module_monitoring/monitoring/models.py b/backend/gn_module_monitoring/monitoring/models.py index 843d4205c..a1bac6fec 100644 --- a/backend/gn_module_monitoring/monitoring/models.py +++ b/backend/gn_module_monitoring/monitoring/models.py @@ -62,7 +62,11 @@ class BibTypeSite(DB.Model): nullable=False, primary_key=True) config = DB.Column(JSONB) - + site_type = DB.relationship( + TNomenclatures, + uselist=False, + backref=DB.backref('bib_type_site', uselist=False) + ) @serializable class TMonitoringObservationDetails(DB.Model): diff --git a/backend/gn_module_monitoring/monitoring/schemas.py b/backend/gn_module_monitoring/monitoring/schemas.py index 2721de0e8..bca3a523d 100644 --- a/backend/gn_module_monitoring/monitoring/schemas.py +++ b/backend/gn_module_monitoring/monitoring/schemas.py @@ -6,7 +6,7 @@ from pypnnomenclature.schemas import NomenclatureSchema from gn_module_monitoring.monitoring.models import ( - BibCategorieSite, + BibTypeSite, TMonitoringSites, TMonitoringSitesGroups, ) @@ -46,12 +46,12 @@ def serialize_geojson(self, obj): return geojson.dumps(obj.as_geofeature().get("geometry")) -class BibCategorieSiteSchema(SQLAlchemyAutoSchema): +class BibTypeSiteSchema(SQLAlchemyAutoSchema): site_type = fields.Nested( NomenclatureSchema(only=("id_nomenclature", "label_fr")), many=True, dump_only=True ) class Meta: - model = BibCategorieSite + model = BibTypeSite include_fk = True load_instance = True diff --git a/backend/gn_module_monitoring/routes/data_utils.py b/backend/gn_module_monitoring/routes/data_utils.py index 593002934..ed90073c3 100644 --- a/backend/gn_module_monitoring/routes/data_utils.py +++ b/backend/gn_module_monitoring/routes/data_utils.py @@ -32,7 +32,7 @@ from ..blueprint import blueprint from ..config.repositories import get_config -from gn_module_monitoring.monitoring.models import TMonitoringSitesGroups, TMonitoringSites, BibCategorieSite +from gn_module_monitoring.monitoring.models import TMonitoringSitesGroups, TMonitoringSites, BibTypeSite model_dict = { "habitat": Habref, @@ -40,7 +40,7 @@ "user": User, "taxonomy": Taxref, "dataset": TDatasets, - "categorie": BibCategorieSite, + "categorie": BibTypeSite, "observer_list": UserList, "taxonomy_list": BibListes, "sites_group": TMonitoringSitesGroups, From 580d0f5219bc094842b8845a2257c74ded2289a0 Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Thu, 12 Jan 2023 12:27:17 +0100 Subject: [PATCH 13/19] fix(api): updated schema to match models --- backend/gn_module_monitoring/monitoring/schemas.py | 4 +--- .../test_schemas/test_bib_site_type_schema.py | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) create mode 100644 backend/gn_module_monitoring/tests/test_monitoring/test_schemas/test_bib_site_type_schema.py diff --git a/backend/gn_module_monitoring/monitoring/schemas.py b/backend/gn_module_monitoring/monitoring/schemas.py index bca3a523d..5083b55c7 100644 --- a/backend/gn_module_monitoring/monitoring/schemas.py +++ b/backend/gn_module_monitoring/monitoring/schemas.py @@ -47,9 +47,7 @@ def serialize_geojson(self, obj): class BibTypeSiteSchema(SQLAlchemyAutoSchema): - site_type = fields.Nested( - NomenclatureSchema(only=("id_nomenclature", "label_fr")), many=True, dump_only=True - ) + site_type = fields.Nested(NomenclatureSchema(only=("label_fr",)), dump_only=True) class Meta: model = BibTypeSite diff --git a/backend/gn_module_monitoring/tests/test_monitoring/test_schemas/test_bib_site_type_schema.py b/backend/gn_module_monitoring/tests/test_monitoring/test_schemas/test_bib_site_type_schema.py new file mode 100644 index 000000000..e3852cdb1 --- /dev/null +++ b/backend/gn_module_monitoring/tests/test_monitoring/test_schemas/test_bib_site_type_schema.py @@ -0,0 +1,14 @@ +import pytest + +from gn_module_monitoring.monitoring.models import BibTypeSite +from gn_module_monitoring.monitoring.schemas import BibTypeSiteSchema + + +@pytest.mark.usefixtures("temporary_transaction") +class TestBibSiteTypeSchema: + def test_dump(self, types_site): + one_type_site = BibTypeSite.query.first() + schema = BibTypeSiteSchema() + type_site = schema.dump(one_type_site) + + assert type_site["id_nomenclature"] == one_type_site.id_nomenclature From dfeaa2cf0708114cb69c876040ae7472134c2794 Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Thu, 12 Jan 2023 13:53:31 +0100 Subject: [PATCH 14/19] fix(api): module edition --- backend/gn_module_monitoring/monitoring/schemas.py | 7 ++++++- backend/gn_module_monitoring/routes/data_utils.py | 2 +- backend/gn_module_monitoring/routes/site.py | 1 - config/monitoring/generic/module.json | 12 ++++++------ 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/backend/gn_module_monitoring/monitoring/schemas.py b/backend/gn_module_monitoring/monitoring/schemas.py index 5083b55c7..80837b86a 100644 --- a/backend/gn_module_monitoring/monitoring/schemas.py +++ b/backend/gn_module_monitoring/monitoring/schemas.py @@ -47,7 +47,12 @@ def serialize_geojson(self, obj): class BibTypeSiteSchema(SQLAlchemyAutoSchema): - site_type = fields.Nested(NomenclatureSchema(only=("label_fr",)), dump_only=True) + label = fields.Method("get_label_from_site_type") + # See if useful in the future: + # site_type = fields.Nested(NomenclatureSchema(only=("label_fr",)), dump_only=True) + + def get_label_from_site_type(self, obj): + return obj.site_type.label_fr class Meta: model = BibTypeSite diff --git a/backend/gn_module_monitoring/routes/data_utils.py b/backend/gn_module_monitoring/routes/data_utils.py index ed90073c3..701357ff6 100644 --- a/backend/gn_module_monitoring/routes/data_utils.py +++ b/backend/gn_module_monitoring/routes/data_utils.py @@ -40,7 +40,7 @@ "user": User, "taxonomy": Taxref, "dataset": TDatasets, - "categorie": BibTypeSite, + "site_types": BibTypeSite, "observer_list": UserList, "taxonomy_list": BibListes, "sites_group": TMonitoringSitesGroups, diff --git a/backend/gn_module_monitoring/routes/site.py b/backend/gn_module_monitoring/routes/site.py index 3bbc5ba9a..8fc9760bc 100644 --- a/backend/gn_module_monitoring/routes/site.py +++ b/backend/gn_module_monitoring/routes/site.py @@ -1,6 +1,5 @@ from flask import request from flask.json import jsonify -from geonature.core.gn_monitoring.models import TBaseSites from werkzeug.datastructures import MultiDict from gn_module_monitoring.blueprint import blueprint diff --git a/config/monitoring/generic/module.json b/config/monitoring/generic/module.json index 205202274..620e455da 100644 --- a/config/monitoring/generic/module.json +++ b/config/monitoring/generic/module.json @@ -130,18 +130,18 @@ "definition": "Afficher le module dans le menu de GéoNature. (Recharger la page pour voir les modifications)." }, - "categories": { + "type_site": { "type_widget": "datalist", - "attribut_label": "Catégories de sites", - "type_util": "categorie", - "keyValue": "id_categorie", + "attribut_label": "Types de sites", + "type_util": "site_types", + "keyValue": "id_nomenclature", "keyLabel": "label", "multiple": true, - "api" : "__MONITORINGS_PATH/sites/categories", + "api" : "__MONITORINGS_PATH/sites/types", "application": "GeoNature", "required": true, "data_path": "items", - "definition": "Permet de paramétrer la compatibilité de ce module avec les catégories de sites" + "definition": "Permet de paramétrer la compatibilité de ce module avec les types de sites" }, "medias": { From b55c5b8c172454242eeb0eea8a2a50f18da0cfaa Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Thu, 12 Jan 2023 14:09:57 +0100 Subject: [PATCH 15/19] style(api): uniformize type_site --- backend/gn_module_monitoring/blueprint.py | 2 +- backend/gn_module_monitoring/monitoring/admin.py | 16 ++++++++-------- .../gn_module_monitoring/monitoring/models.py | 2 +- .../gn_module_monitoring/monitoring/schemas.py | 8 ++++---- .../gn_module_monitoring/routes/data_utils.py | 2 +- backend/gn_module_monitoring/routes/site.py | 8 ++++---- .../tests/fixtures/type_site.py | 10 +++++----- .../tests/test_routes/test_site.py | 10 +++++----- config/monitoring/generic/module.json | 2 +- 9 files changed, 30 insertions(+), 30 deletions(-) diff --git a/backend/gn_module_monitoring/blueprint.py b/backend/gn_module_monitoring/blueprint.py index cf4957a54..354791bd4 100644 --- a/backend/gn_module_monitoring/blueprint.py +++ b/backend/gn_module_monitoring/blueprint.py @@ -17,4 +17,4 @@ for cmd in commands: blueprint.cli.add_command(cmd) -flask_admin.add_view(BibTypeSiteView(DB.session, name="Type de sites", category="Monitorings")) +flask_admin.add_view(BibTypeSiteView(DB.session, name="Types de site", category="Monitorings")) diff --git a/backend/gn_module_monitoring/monitoring/admin.py b/backend/gn_module_monitoring/monitoring/admin.py index 5c669b1d4..498a2f097 100644 --- a/backend/gn_module_monitoring/monitoring/admin.py +++ b/backend/gn_module_monitoring/monitoring/admin.py @@ -21,7 +21,7 @@ def __init__(self, session, **kwargs): # Référence au model utilisé super(BibTypeSiteView, self).__init__(BibTypeSite, session, **kwargs) - def get_only_type_site_asc(): + def get_only_nomenclature_asc(): subquery = DB.session.query(BibTypeSite.id_nomenclature).subquery() return ( DB.session.query(TNomenclatures) @@ -34,19 +34,19 @@ def get_only_type_site_asc(): def get_label_fr_nomenclature(x): return x.label_fr - def list_label_site_type_formatter(view, _context, model, _name): - return model.site_type.label_fr + def list_label_nomenclature_formatter(view, _context, model, _name): + return model.nomenclature.label_fr # Nom de colonne user friendly - column_labels = dict(site_type="Type de site") + column_labels = dict(nomenclature="Types de site") # Description des colonnes - column_descriptions = dict(site_type="Nomenclature de Type de site à choisir") + column_descriptions = dict(nomenclature="Nomenclature de Type de site à choisir") column_hide_backrefs = False form_args = dict( - site_type=dict(query_factory=get_only_type_site_asc, get_label=get_label_fr_nomenclature) + nomenclature=dict(query_factory=get_only_nomenclature_asc, get_label=get_label_fr_nomenclature) ) - column_list = ("site_type","config") - column_formatters = dict(site_type=list_label_site_type_formatter) + column_list = ("nomenclature","config") + column_formatters = dict(nomenclature=list_label_nomenclature_formatter) diff --git a/backend/gn_module_monitoring/monitoring/models.py b/backend/gn_module_monitoring/monitoring/models.py index a1bac6fec..66b61481c 100644 --- a/backend/gn_module_monitoring/monitoring/models.py +++ b/backend/gn_module_monitoring/monitoring/models.py @@ -62,7 +62,7 @@ class BibTypeSite(DB.Model): nullable=False, primary_key=True) config = DB.Column(JSONB) - site_type = DB.relationship( + nomenclature = DB.relationship( TNomenclatures, uselist=False, backref=DB.backref('bib_type_site', uselist=False) diff --git a/backend/gn_module_monitoring/monitoring/schemas.py b/backend/gn_module_monitoring/monitoring/schemas.py index 80837b86a..085af2751 100644 --- a/backend/gn_module_monitoring/monitoring/schemas.py +++ b/backend/gn_module_monitoring/monitoring/schemas.py @@ -47,12 +47,12 @@ def serialize_geojson(self, obj): class BibTypeSiteSchema(SQLAlchemyAutoSchema): - label = fields.Method("get_label_from_site_type") + label = fields.Method("get_label_from_type_site") # See if useful in the future: - # site_type = fields.Nested(NomenclatureSchema(only=("label_fr",)), dump_only=True) + # type_site = fields.Nested(NomenclatureSchema(only=("label_fr",)), dump_only=True) - def get_label_from_site_type(self, obj): - return obj.site_type.label_fr + def get_label_from_type_site(self, obj): + return obj.nomenclature.label_fr class Meta: model = BibTypeSite diff --git a/backend/gn_module_monitoring/routes/data_utils.py b/backend/gn_module_monitoring/routes/data_utils.py index 701357ff6..3a160a7bc 100644 --- a/backend/gn_module_monitoring/routes/data_utils.py +++ b/backend/gn_module_monitoring/routes/data_utils.py @@ -40,7 +40,7 @@ "user": User, "taxonomy": Taxref, "dataset": TDatasets, - "site_types": BibTypeSite, + "types_site": BibTypeSite, "observer_list": UserList, "taxonomy_list": BibListes, "sites_group": TMonitoringSitesGroups, diff --git a/backend/gn_module_monitoring/routes/site.py b/backend/gn_module_monitoring/routes/site.py index 8fc9760bc..989858feb 100644 --- a/backend/gn_module_monitoring/routes/site.py +++ b/backend/gn_module_monitoring/routes/site.py @@ -15,7 +15,7 @@ @blueprint.route("/sites/types", methods=["GET"]) -def get_site_types(): +def get_types_site(): params = MultiDict(request.args) limit, page = get_limit_offset(params=params) sort_label, sort_dir = get_sort( @@ -33,9 +33,9 @@ def get_site_types(): ) -@blueprint.route("/sites/types/", methods=["GET"]) -def get_site_types_by_id(id_site_type): - query = BibTypeSite.query.filter_by(id_nomenclature=id_site_type) +@blueprint.route("/sites/types/", methods=["GET"]) +def get_type_site_by_id(id_type_site): + query = BibTypeSite.query.filter_by(id_nomenclature=id_type_site) res = query.first() schema = BibTypeSiteSchema() return schema.dump(res) diff --git a/backend/gn_module_monitoring/tests/fixtures/type_site.py b/backend/gn_module_monitoring/tests/fixtures/type_site.py index c77f17b24..936f402ad 100644 --- a/backend/gn_module_monitoring/tests/fixtures/type_site.py +++ b/backend/gn_module_monitoring/tests/fixtures/type_site.py @@ -6,7 +6,7 @@ @pytest.fixture -def nomenclature_site_types(): +def nomenclature_types_site(): return TNomenclatures.query.filter( BibNomenclaturesTypes.mnemonique == "TYPE_SITE", TNomenclatures.mnemonique.in_(("Grotte", "Mine")), @@ -14,12 +14,12 @@ def nomenclature_site_types(): @pytest.fixture -def types_site(nomenclature_site_types): +def types_site(nomenclature_types_site): types_site = { - nomenc_site_type.mnemonique: BibTypeSite( - id_nomenclature=nomenc_site_type.id_nomenclature, config={} + nomenc_type_site.mnemonique: BibTypeSite( + id_nomenclature=nomenc_type_site.id_nomenclature, config={} ) - for nomenc_site_type in nomenclature_site_types + for nomenc_type_site in nomenclature_types_site } with db.session.begin_nested(): db.session.add_all(types_site.values()) diff --git a/backend/gn_module_monitoring/tests/test_routes/test_site.py b/backend/gn_module_monitoring/tests/test_routes/test_site.py index ff5d5291d..59733d2c9 100644 --- a/backend/gn_module_monitoring/tests/test_routes/test_site.py +++ b/backend/gn_module_monitoring/tests/test_routes/test_site.py @@ -6,20 +6,20 @@ @pytest.mark.usefixtures("client_class", "temporary_transaction") class TestSite: - def test_get_site_types_by_id(self, types_site): + def test_get_type_site_by_id(self, types_site): for type_site in types_site.values(): r = self.client.get( url_for( - "monitorings.get_site_types_by_id", - id_site_type=type_site.id_nomenclature, + "monitorings.get_type_site_by_id", + id_type_site=type_site.id_nomenclature, ) ) assert r.json["id_nomenclature"] == type_site.id_nomenclature - def test_get_site_types(self, types_site): + def test_get_types_site(self, types_site): schema = BibTypeSiteSchema() - r = self.client.get(url_for("monitorings.get_site_types")) + r = self.client.get(url_for("monitorings.get_types_site")) assert r.json["count"] >= len(types_site) assert all([schema.dump(cat) in r.json["items"] for cat in types_site.values()]) diff --git a/config/monitoring/generic/module.json b/config/monitoring/generic/module.json index 620e455da..3c612dbca 100644 --- a/config/monitoring/generic/module.json +++ b/config/monitoring/generic/module.json @@ -133,7 +133,7 @@ "type_site": { "type_widget": "datalist", "attribut_label": "Types de sites", - "type_util": "site_types", + "type_util": "types_site", "keyValue": "id_nomenclature", "keyLabel": "label", "multiple": true, From b02c5919218e93ce1ae28f96e11459ccfe9182a9 Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Thu, 12 Jan 2023 14:12:58 +0100 Subject: [PATCH 16/19] style(api): change relationship name for type_site --- backend/gn_module_monitoring/monitoring/models.py | 4 ++-- backend/gn_module_monitoring/tests/fixtures/module.py | 2 +- backend/gn_module_monitoring/tests/fixtures/site.py | 2 +- .../tests/test_monitoring/test_models/test_module.py | 6 +++--- config/monitoring/generic/module.json | 2 +- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/backend/gn_module_monitoring/monitoring/models.py b/backend/gn_module_monitoring/monitoring/models.py index 66b61481c..c80223cfb 100644 --- a/backend/gn_module_monitoring/monitoring/models.py +++ b/backend/gn_module_monitoring/monitoring/models.py @@ -240,7 +240,7 @@ class TMonitoringSites(TBaseSites): where(TBaseSites.id_base_site==id_base_site).\ correlate_except(TBaseSites) ) - type_site = DB.relationship( + types_site = DB.relationship( "BibTypeSite", secondary=cor_type_site, lazy="joined" @@ -356,7 +356,7 @@ class TMonitoringModules(TModules): lazy="joined", ) - type_site = DB.relationship( + types_site = DB.relationship( "BibTypeSite", secondary=cor_module_type, lazy="joined" diff --git a/backend/gn_module_monitoring/tests/fixtures/module.py b/backend/gn_module_monitoring/tests/fixtures/module.py index 32bc94787..29f678f25 100644 --- a/backend/gn_module_monitoring/tests/fixtures/module.py +++ b/backend/gn_module_monitoring/tests/fixtures/module.py @@ -14,7 +14,7 @@ def monitoring_module(types_site): active_frontend=True, active_backend=False, module_path="test", - type_site=list(types_site.values()), + types_site=list(types_site.values()), ) with db.session.begin_nested(): diff --git a/backend/gn_module_monitoring/tests/fixtures/site.py b/backend/gn_module_monitoring/tests/fixtures/site.py index db242bb6d..397b36703 100644 --- a/backend/gn_module_monitoring/tests/fixtures/site.py +++ b/backend/gn_module_monitoring/tests/fixtures/site.py @@ -20,7 +20,7 @@ def sites(users, types_site, sites_groups): base_site_code=f"Code{i}", geom=geom_4326, id_nomenclature_type_site=types_site[key].id_nomenclature, - type_site=[types_site[key]], + types_site=[types_site[key]], id_sites_group=sites_groups["Site_Groupe"].id_sites_group, ) with db.session.begin_nested(): diff --git a/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_module.py b/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_module.py index a2fdc9383..978b9d1ca 100644 --- a/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_module.py +++ b/backend/gn_module_monitoring/tests/test_monitoring/test_models/test_module.py @@ -7,13 +7,13 @@ @pytest.mark.usefixtures("temporary_transaction") class TestModule: def test_module(self, monitoring_module, types_site): - types = monitoring_module.type_site + types = monitoring_module.types_site assert types == list(types_site.values()) def test_remove_categorie_from_module(self, monitoring_module, types_site): with db.session.begin_nested(): - monitoring_module.type_site.pop(0) + monitoring_module.types_site.pop(0) mon = TMonitoringModules.query.filter_by(id_module=monitoring_module.id_module).one() - assert len(mon.type_site) == len(types_site) - 1 + assert len(mon.types_site) == len(types_site) - 1 diff --git a/config/monitoring/generic/module.json b/config/monitoring/generic/module.json index 3c612dbca..1c60466dc 100644 --- a/config/monitoring/generic/module.json +++ b/config/monitoring/generic/module.json @@ -130,7 +130,7 @@ "definition": "Afficher le module dans le menu de GéoNature. (Recharger la page pour voir les modifications)." }, - "type_site": { + "types_site": { "type_widget": "datalist", "attribut_label": "Types de sites", "type_util": "types_site", From 3b4e29df58d94161b5129d7cc42c520570f6a832 Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Thu, 12 Jan 2023 14:44:18 +0100 Subject: [PATCH 17/19] feat(api): validator admin --- backend/gn_module_monitoring/monitoring/admin.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/backend/gn_module_monitoring/monitoring/admin.py b/backend/gn_module_monitoring/monitoring/admin.py index 498a2f097..d770a5d0d 100644 --- a/backend/gn_module_monitoring/monitoring/admin.py +++ b/backend/gn_module_monitoring/monitoring/admin.py @@ -2,6 +2,7 @@ from geonature.core.admin.admin import CruvedProtectedMixin from geonature.utils.env import DB from pypnnomenclature.models import TNomenclatures, BibNomenclaturesTypes +from wtforms.validators import ValidationError from gn_module_monitoring.monitoring.models import BibTypeSite @@ -22,11 +23,9 @@ def __init__(self, session, **kwargs): super(BibTypeSiteView, self).__init__(BibTypeSite, session, **kwargs) def get_only_nomenclature_asc(): - subquery = DB.session.query(BibTypeSite.id_nomenclature).subquery() return ( DB.session.query(TNomenclatures) .join(TNomenclatures.nomenclature_type) - .filter(TNomenclatures.id_nomenclature.notin_(subquery)) .filter(BibNomenclaturesTypes.mnemonique == SITE_TYPE) .order_by(TNomenclatures.label_fr.asc()) ) @@ -37,6 +36,10 @@ def get_label_fr_nomenclature(x): def list_label_nomenclature_formatter(view, _context, model, _name): return model.nomenclature.label_fr + def unique(form, field): + if BibTypeSite.query.filter_by(id_nomenclature=field.data.id_nomenclature).first() is not None: + raise ValidationError("The same nomenclature cannot be used twice") + # Nom de colonne user friendly column_labels = dict(nomenclature="Types de site") # Description des colonnes @@ -45,7 +48,7 @@ def list_label_nomenclature_formatter(view, _context, model, _name): column_hide_backrefs = False form_args = dict( - nomenclature=dict(query_factory=get_only_nomenclature_asc, get_label=get_label_fr_nomenclature) + nomenclature=dict(query_factory=get_only_nomenclature_asc, get_label=get_label_fr_nomenclature, validators=[unique]) ) column_list = ("nomenclature","config") From d405ee073b3798c82b3d9df313933f5c4d1449fd Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Thu, 12 Jan 2023 16:35:11 +0100 Subject: [PATCH 18/19] fix(api): make unique BibTypeSite in admin --- .../gn_module_monitoring/monitoring/admin.py | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/backend/gn_module_monitoring/monitoring/admin.py b/backend/gn_module_monitoring/monitoring/admin.py index d770a5d0d..5406513ff 100644 --- a/backend/gn_module_monitoring/monitoring/admin.py +++ b/backend/gn_module_monitoring/monitoring/admin.py @@ -10,6 +10,22 @@ SITE_TYPE = "TYPE_SITE" +class Unique: + """ validator that checks field uniqueness """ + def __init__(self, model, field, message=None): + self.model = model + self.field = field + if not message: + message = u'A type is already created with this nomenclature' + self.message = message + + def __call__(self, form, field): + if field.object_data == field.data: + return + if self.model.query.filter(getattr(self.model, self.field) == getattr(field.data, self.field)).first(): + raise ValidationError(self.message) + + class BibTypeSiteView(CruvedProtectedMixin, ModelView): """ Surcharge de l'administration des types de sites @@ -36,19 +52,16 @@ def get_label_fr_nomenclature(x): def list_label_nomenclature_formatter(view, _context, model, _name): return model.nomenclature.label_fr - def unique(form, field): - if BibTypeSite.query.filter_by(id_nomenclature=field.data.id_nomenclature).first() is not None: - raise ValidationError("The same nomenclature cannot be used twice") - # Nom de colonne user friendly column_labels = dict(nomenclature="Types de site") # Description des colonnes - column_descriptions = dict(nomenclature="Nomenclature de Type de site à choisir") + column_descriptions = dict(nomenclature="Nomenclature de type de site à choisir") column_hide_backrefs = False form_args = dict( - nomenclature=dict(query_factory=get_only_nomenclature_asc, get_label=get_label_fr_nomenclature, validators=[unique]) + nomenclature=dict(query_factory=get_only_nomenclature_asc, get_label=get_label_fr_nomenclature, + validators=[Unique(BibTypeSite, "id_nomenclature")]) ) column_list = ("nomenclature","config") From ea30c7be183ae6817a508faa00f0360fe76f36da Mon Sep 17 00:00:00 2001 From: Maxime Vergez Date: Thu, 12 Jan 2023 16:43:43 +0100 Subject: [PATCH 19/19] test(api): fix test when existing nomenclatures In database --- .../tests/fixtures/type_site.py | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/backend/gn_module_monitoring/tests/fixtures/type_site.py b/backend/gn_module_monitoring/tests/fixtures/type_site.py index 936f402ad..36d419c86 100644 --- a/backend/gn_module_monitoring/tests/fixtures/type_site.py +++ b/backend/gn_module_monitoring/tests/fixtures/type_site.py @@ -7,10 +7,24 @@ @pytest.fixture def nomenclature_types_site(): - return TNomenclatures.query.filter( - BibNomenclaturesTypes.mnemonique == "TYPE_SITE", - TNomenclatures.mnemonique.in_(("Grotte", "Mine")), - ).all() + mnemoniques = ("Test_Grotte", "Test_Mine") + nomenclatures = [] + type_site = BibNomenclaturesTypes.query.filter( + BibNomenclaturesTypes.mnemonique == "TYPE_SITE" + ).first() + for mnemo in mnemoniques: + nomenclatures.append( + TNomenclatures( + id_type=type_site.id_type, + cd_nomenclature=mnemo, + label_default=mnemo, + label_fr=mnemo, + active=True, + ) + ) + with db.session.begin_nested(): + db.session.add_all(nomenclatures) + return nomenclatures @pytest.fixture