From 2820e301493f3bdb3c1330d6c200f25b733d859c Mon Sep 17 00:00:00 2001 From: VincentCauchois Date: Thu, 31 Oct 2024 18:37:41 +0100 Subject: [PATCH] fix(mtd): handle mtd with no contact principal retrieved If not enough information could be retrieved to associate a metadata to an actor that is a "Contact Principal", then a specific user is used, and possibly created, to be associated as the "Contact principal" with the metadata. This specific user has the following information: - id_role, ID : 0 - particular positive integer value chosen to avoid conflict with other IDs, in particular those retrieved from the INPN - desc_role, description : "Contact principal for 'orphan' metadata - i.e. with no 'Contact Principal' that could be retrieved during INPN MTD synchronisation" In the case where not enough information could be retrieved to associate a metadata to an actor but the actor is not a "Contact principal", then the association is simply skipped and a warning message with details is logged. --- .../geonature/core/gn_meta/mtd/mtd_utils.py | 50 ++++++++++++++++++- 1 file changed, 49 insertions(+), 1 deletion(-) diff --git a/backend/geonature/core/gn_meta/mtd/mtd_utils.py b/backend/geonature/core/gn_meta/mtd/mtd_utils.py index 8f0768d8e3..d2fa5f6639 100644 --- a/backend/geonature/core/gn_meta/mtd/mtd_utils.py +++ b/backend/geonature/core/gn_meta/mtd/mtd_utils.py @@ -6,6 +6,7 @@ import uuid from flask import current_app +from pypnusershub.routes import insert_or_update_role from sqlalchemy import select, exists from sqlalchemy.exc import SQLAlchemyError, IntegrityError from sqlalchemy.sql import func, update @@ -237,6 +238,7 @@ def associate_actors( pk_value : str pk value: ID of the AF or DS """ + type_mtd = "AF" if pk_name == "id_acquisition_framework" else "DS" for actor in actors: id_organism = None uuid_organism = actor["uuid_organism"] @@ -293,7 +295,53 @@ def associate_actors( id_user_from_email = DB.session.scalar( select(User.id_role).filter_by(email=email_actor).where(User.groupe.is_(False)) ) - values["id_role"] = id_user_from_email + if id_user_from_email: + values["id_role"] = id_user_from_email + else: + # If actor role is "Contact Principal", i.e. cd_nomenclature_actor_role = '1' , + # then we use a dedicated user for 'orphan' metadata - metadata with no associated "Contact principal" actor that could be retrieved + # the three non-null fields for `utilisateurs.t_roles` will be set to default: + # - `groupe`: False - the role is a user and not a group + # - `id_role`: generated by the nextval sequence + # - `uuid_role`: generated by uuid_generate_v4() + # in particular: + # - we do not specify field `email` even if `email_actor` is to be set + # - only the field `dec_role` will be written to a non-default value, so as to identify this particular "Contact principal"-for-orphan-metadata user + cd_nomenclature_actor_role_for_contact_principal = "1" + if cd_nomenclature_actor_role == cd_nomenclature_actor_role_for_contact_principal: + # Retrieve the "Contact principal"-for-orphan-metadata user + desc_role_for_user_contact_principal_for_orphan_metadata = "Contact principal for 'orphan' metadata - i.e. with no 'Contact Principal' that could be retrieved during INPN MTD synchronisation" + id_user_contact_principal_for_orphan_metadata = 0 + user_contact_principal_for_orphan_metadata = DB.session.get(User, id_user_contact_principal_for_orphan_metadata) + # /!\ Assert that the user with ID 0 retrieved is actually the "Contact principal"-for-orphan-metadata user with the right "desc_role" + # If an error is raised, one must choose how to handle this situation: + # - Check for the current user with ID 0 + # - Possibly change the ID of this user to an ID other than 0 + # /!\ Be careful to the other entries associated to this user + # /!\ Be careful when choosing a new ID : positive integer should be reserved for users retrieved from the INPN + # - Eventually change the code to: + # - set an ID other than 0 for the "Contact principal"-for-orphan-metadata user + # - possibly allow to configure a different ID for different GN instances + if user_contact_principal_for_orphan_metadata: + assert user_contact_principal_for_orphan_metadata.desc_role == desc_role_for_user_contact_principal_for_orphan_metadata + # If the user does not yet exist, create it + else: + dict_data_generated_user = { + "id_role": id_user_contact_principal_for_orphan_metadata, + "desc_role": user_contact_principal_for_orphan_metadata, + } + dict_data_generated_user = insert_or_update_role( + data=dict_data_generated_user + ) + # Commit to ensure that the insert from previous statement is actually committed + DB.session.commit() + values["id_role"] = id_user_contact_principal_for_orphan_metadata + else: + logger.warning( + f"MTD - actor association impossible for {type_mtd} with UUID '{uuid_mtd}' because no id_organism nor id_role could be retrieved - with the following actor information:\n" + + format_str_dict_actor_for_logging(actor) + ) + continue try: statement = ( pg_insert(CorActor)