diff --git a/backend/geonature/core/gn_commons/models/base.py b/backend/geonature/core/gn_commons/models/base.py index aa25ff0ffd..2c3bfc583e 100644 --- a/backend/geonature/core/gn_commons/models/base.py +++ b/backend/geonature/core/gn_commons/models/base.py @@ -233,6 +233,21 @@ class TValidations(DB.Model): overlaps="nomenclature_valid_status", # overlaps expected ) + def auto_validation(fct_auto_validation): + stmt = f""" + select routine_name, routine_schema + from information_schema.routines + where routine_name= '{fct_auto_validation}' + and routine_type='FUNCTION'; + """ + result = DB.session.execute(stmt).fetchall() + if len(result) == 0: + return + stmt_auto_validation = f"SELECT gn_profiles.{fct_auto_validation}()" + list_synthese_updated = DB.session.execute(stmt_auto_validation).fetchall()[0] + # DB.session.query(func.gn_profiles.fct_auto_validation()) + return list_synthese_updated + last_validation_query = ( select(TValidations) diff --git a/backend/geonature/core/gn_commons/routes.py b/backend/geonature/core/gn_commons/routes.py index a7377a1ff8..ec683fed4c 100644 --- a/backend/geonature/core/gn_commons/routes.py +++ b/backend/geonature/core/gn_commons/routes.py @@ -26,6 +26,7 @@ from geonature.core.gn_permissions.decorators import login_required from geonature.core.gn_permissions.tools import get_scope import geonature.core.gn_commons.tasks # noqa: F401 +import gn_module_validation.tasks from shapely.geometry import shape from geoalchemy2.shape import from_shape diff --git a/backend/geonature/migrations/versions/9a4b4b6f8fe6_add_fct_auto_validation.py b/backend/geonature/migrations/versions/9a4b4b6f8fe6_add_fct_auto_validation.py new file mode 100644 index 0000000000..b57fa78f70 --- /dev/null +++ b/backend/geonature/migrations/versions/9a4b4b6f8fe6_add_fct_auto_validation.py @@ -0,0 +1,102 @@ +"""add_fct_auto_validation + +Revision ID: 9a4b4b6f8fe6 +Revises: 446e902a14e7 +Create Date: 2023-10-25 17:18:04.438706 + +""" +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "9a4b4b6f8fe6" +down_revision = "446e902a14e7" +branch_labels = None +depends_on = None + +schema = "gn_profiles" +fct_name = "fct_auto_validation" + + +def upgrade(): + op.execute( + f""" +create or replace function {schema}.{fct_name} ( + new_validation_status varchar default 'Probable', + score int default 3 + ) returns integer [] language plpgsql as $function$ +declare old_validation_status text := 'En attente de validation'; +new_id_status_validation int := ( + select tn.id_nomenclature + from ref_nomenclatures.t_nomenclatures tn + where tn.mnemonique = new_validation_status +); +old_id_status_validation int := ( + select tn.id_nomenclature + from ref_nomenclatures.t_nomenclatures tn + where tn.mnemonique = old_validation_status +); +list_uuid_obs_status_updatable uuid [] := ( + select array_agg(vlv.uuid_attached_row) + from gn_commons.v_latest_validation vlv + join gn_profiles.v_consistancy_data vcd on vlv.uuid_attached_row = vcd.id_sinp + and ( + ( + vcd.valid_phenology::int + vcd.valid_altitude::int + vcd.valid_distribution::int + ) = score + ) + where vlv.id_nomenclature_valid_status = old_id_status_validation + and validation_auto = true + and id_validator is null +); +list_uuid_validation_to_update uuid [] := array ( + select t.uuid_attached_row + from ( + select distinct on (uuid_attached_row) uuid_attached_row, + id_validation, + validation_date + from gn_commons.t_validations tv + where uuid_attached_row = any (list_uuid_obs_status_updatable) + order by uuid_attached_row, + validation_date desc + ) as t +); +list_id_sythese_updated int [] := array ( + select s.id_synthese + from gn_synthese.synthese s + where s.unique_id_sinp = any (list_uuid_validation_to_update) +); +_schema_name text = 'gn_commons'; +_table_name text = 't_validations'; +indx int; +begin if array_length(list_uuid_validation_to_update, 1) > 0 then for indx in 1..array_length(list_uuid_validation_to_update, 1) loop raise notice 'Mise à jour du status % --> %, pour l''uuid_attached_row : % dans la table %.% ( id_synthese = % )', +old_validation_status, +new_validation_status, +list_uuid_validation_to_update [indx], +_schema_name, +_table_name, +list_id_sythese_updated [indx]; +execute format( + ' + INSERT INTO %I.%I (uuid_attached_row, id_nomenclature_valid_status, validation_auto, id_validator, validation_comment, validation_date) + VALUES ($1, $2 ,false, null,''auto = default value'',CURRENT_TIMESTAMP)', + _schema_name, + _table_name +) using list_uuid_validation_to_update [indx], +new_id_status_validation; +end loop; +end if; +return list_id_sythese_updated; +end; +$function$; + """ + ) + + +def downgrade(): + op.execute( + f""" + DROP FUNCTION {schema}.{fct_name} + """ + ) diff --git a/contrib/gn_module_validation/backend/gn_module_validation/conf_schema_toml.py b/contrib/gn_module_validation/backend/gn_module_validation/conf_schema_toml.py index 3503301ebf..0eeb59128e 100644 --- a/contrib/gn_module_validation/backend/gn_module_validation/conf_schema_toml.py +++ b/contrib/gn_module_validation/backend/gn_module_validation/conf_schema_toml.py @@ -83,3 +83,7 @@ class GnModuleSchemaConf(Schema): MAIL_BODY = fields.String(load_default=MAIL_BODY) MAIL_SUBJECT = fields.String(load_default=MAIL_SUBJECT) COLUMN_LIST = fields.List(fields.Nested(ColumnSchema), load_default=COLUMN_LIST) + AUTO_VALIDATION_CRONTAB = fields.String(load_default="* 1 * * *") + AUTO_VALIDATION_ENABLED = fields.Boolean(load_default=False) + AUTO_VALIDATION_SQL_FUNCTION = fields.String(load_default="fct_auto_validation") + diff --git a/contrib/gn_module_validation/backend/gn_module_validation/tasks.py b/contrib/gn_module_validation/backend/gn_module_validation/tasks.py new file mode 100644 index 0000000000..307280dd4b --- /dev/null +++ b/contrib/gn_module_validation/backend/gn_module_validation/tasks.py @@ -0,0 +1,39 @@ +from celery.schedules import crontab +from celery.utils.log import get_task_logger + +from geonature.core.gn_commons.models import TValidations +from geonature.utils.celery import celery_app +from geonature.utils.config import config + +logger = get_task_logger(__name__) + + +@celery_app.on_after_finalize.connect +def setup_periodic_tasks(sender, **kwargs): + is_enabled = config["VALIDATION"]["AUTO_VALIDATION_ENABLED"] + ct = config["VALIDATION"]["AUTO_VALIDATION_CRONTAB"] + if ct and is_enabled: + minute, hour, day_of_month, month_of_year, day_of_week = ct.split(" ") + sender.add_periodic_task( + crontab( + minute=minute, + hour=hour, + day_of_week=day_of_week, + day_of_month=day_of_month, + month_of_year=month_of_year, + ), + set_auto_validation.s(), + name="auto validation", + ) + + +@celery_app.task(bind=True) +def set_auto_validation(self): + is_enabled = config["VALIDATION"]["AUTO_VALIDATION_ENABLED"] + fct_auto_validation_name = config["VALIDATION"]['AUTO_VALIDATION_SQL_FUNCTION'] + if is_enabled: + logger.info("Set autovalidation...") + TValidations.auto_validation(fct_auto_validation_name) + logger.info("Auto validation done") + + diff --git a/contrib/gn_module_validation/setup.py b/contrib/gn_module_validation/setup.py index 893582f2f8..e1adf3dbda 100644 --- a/contrib/gn_module_validation/setup.py +++ b/contrib/gn_module_validation/setup.py @@ -30,6 +30,7 @@ "blueprint = gn_module_validation.blueprint:blueprint", "config_schema = gn_module_validation.conf_schema_toml:GnModuleSchemaConf", "migrations = gn_module_validation:migrations", + "tasks = gn_module_validation.tasks", ], }, classifiers=[ diff --git a/contrib/gn_module_validation/validation_config.toml.example b/contrib/gn_module_validation/validation_config.toml.example index 55cd31c968..d691458f15 100644 --- a/contrib/gn_module_validation/validation_config.toml.example +++ b/contrib/gn_module_validation/validation_config.toml.example @@ -1,25 +1,10 @@ -[[COLUMN_LIST]] -column_label = "Taxon" -column_name = "taxref.nom_vern_or_lb_nom" -min_width = 250 +# PARAMETRES CONFIG MODULE VALIDATION -[[COLUMN_LIST]] -column_label = "Date obs" -column_name = "date_min" -min_width = 100 +# FONCTION AUTO_VALIDATION A SURCOUCHER SI LA FONCTION DE BASE N'EST PAS ADAPATEE A VOTRE CAS D'USAGE -[[COLUMN_LIST]] -column_label = "Jeu de données" -column_name = "dataset.dataset_name" -max_width = 100 -[[COLUMN_LIST]] -column_label = "Observateur" -column_name = "observers" -min_width = 100 +#AUTO_VALIDATION_CRONTAB = "* 1 * * *" +#AUTO_VALIDATION_ENABLED = true -# Exemple d’ajout d’une colonne supplémentaire -#[[COLUMN_LIST]] -#column_label = "Stade de vie" -#column_name = "nomenclature_life_stage.label_default" -#min_width = 50 +## CUSTOM NAME FUNCTION AUTO VALIDATION +#AUTO_VALIDATION_SQL_FUNCTION = "fct_auto_validation"