From e9083dec2fba187979fe1063433f2ecc932fe3aa Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Tue, 21 Jan 2025 17:53:22 +0100 Subject: [PATCH 01/14] feat: move dataset selection to fieldmapping exlusively --- .../geonature/core/gn_meta/models/datasets.py | 2 +- .../core/gn_synthese/imports/actions.py | 25 +- backend/geonature/core/gn_synthese/models.py | 2 +- .../core/imports/checks/dataframe/cast.py | 8 + .../core/imports/checks/dataframe/core.py | 144 +++--- .../core/imports/checks/sql/extra.py | 27 +- .../core/imports/checks/sql/nomenclature.py | 9 +- .../geonature/core/imports/config_schema.py | 6 - backend/geonature/core/imports/models.py | 5 - .../geonature/core/imports/routes/imports.py | 42 +- .../templates/import_template_pdf.html | 11 +- ...7ac1_monitorings_adjust_gn_imports_bib_.py | 85 ++++ .../a81f74d0a518_insert_import_sample_data.py | 19 +- .../imports/files/occhab/no_default_uuid.csv | 58 +-- .../tests/imports/files/occhab/valid_file.csv | 72 +-- .../files/synthese/jdd_to_import_file.csv | 12 +- backend/geonature/tests/imports/fixtures.py | 459 +++++++++++++++++- .../tests/imports/jsonschema_definitions.py | 2 - .../geonature/tests/imports/test_fields.py | 12 +- .../tests/imports/test_imports_occhab.py | 239 +++------ .../tests/imports/test_imports_synthese.py | 435 +++++------------ .../geonature/tests/imports/test_mappings.py | 29 +- backend/geonature/tests/test_gn_meta.py | 4 + .../gn_module_occhab/imports/actions.py | 5 +- .../fixtures/import/occhab/valid_file.csv | 12 +- .../dynamic-form/dynamic-form.component.html | 3 +- .../delete-modal/delete-modal.component.html | 2 +- .../import_errors.component.html | 4 - .../import_list/import-list.component.html | 12 +- .../import_list/import-list.component.ts | 6 - .../header-stepper.component.html | 7 - .../header-stepper.component.scss | 5 - .../header-stepper.component.ts | 18 +- .../upload-file-step.component.html | 15 - .../upload-file-step.component.ts | 20 +- .../import_report.component.html | 9 - .../import_report/import_report.component.ts | 10 - .../import-modal-destination.component.html | 2 +- .../import-modal-destination.component.scss | 2 +- .../modules/imports/models/import.model.ts | 11 - .../modules/imports/services/data.service.ts | 10 +- .../mappings/field-mapping.service.ts | 4 + 42 files changed, 982 insertions(+), 882 deletions(-) create mode 100644 backend/geonature/migrations/versions/imports/a43842db7ac1_monitorings_adjust_gn_imports_bib_.py diff --git a/backend/geonature/core/gn_meta/models/datasets.py b/backend/geonature/core/gn_meta/models/datasets.py index eacb7785e8..417abe70a3 100644 --- a/backend/geonature/core/gn_meta/models/datasets.py +++ b/backend/geonature/core/gn_meta/models/datasets.py @@ -19,7 +19,6 @@ from geonature.core.gn_permissions.tools import get_scopes_by_action from geonature.core.gn_commons.models import cor_field_dataset, cor_module_dataset -from ref_geo.models import LAreas from .commons import * @@ -346,6 +345,7 @@ def filter_by_creatable(cls, module_code, *, query, user=None, object_code=None) @qfilter(query=True) def filter_by_areas(cls, areas, *, query): from geonature.core.gn_synthese.models import Synthese + from ref_geo.models import LAreas areaFilter = [] for id_area in areas: diff --git a/backend/geonature/core/gn_synthese/imports/actions.py b/backend/geonature/core/gn_synthese/imports/actions.py index 6b8b7d356f..dbc87fb46d 100644 --- a/backend/geonature/core/gn_synthese/imports/actions.py +++ b/backend/geonature/core/gn_synthese/imports/actions.py @@ -89,6 +89,7 @@ def check_transient_data(task, logger, imprt: TImports): field_name: fields[field_name] for field_name, source_field in imprt.fieldmapping.items() if source_field.get("column_src", None) in imprt.columns + or source_field.get("default_value", None) is not None } init_rows_validity(imprt) task.update_state(state="PROGRESS", meta={"progress": 0.05}) @@ -246,7 +247,6 @@ def update_batch_progress(batch, step): entity, fields["id_nomenclature_blurring"], fields["id_dataset"], - fields["unique_dataset_id"], ) if current_app.config["IMPORT"]["CHECK_REF_BIBLIO_LITTERATURE"]: check_nomenclature_source_status( @@ -276,15 +276,18 @@ def update_batch_progress(batch, step): if "unique_id_sinp" in selected_fields: check_duplicate_uuid(imprt, entity, selected_fields["unique_id_sinp"]) if current_app.config["IMPORT"]["PER_DATASET_UUID_CHECK"]: - whereclause = Synthese.id_dataset == imprt.id_dataset + check_existing_uuid( + imprt, + entity, + selected_fields["unique_id_sinp"], + id_dataset_field=selected_fields["id_dataset"], + ) else: - whereclause = sa.true() - check_existing_uuid( - imprt, - entity, - selected_fields["unique_id_sinp"], - whereclause=whereclause, - ) + check_existing_uuid( + imprt, + entity, + selected_fields["unique_id_sinp"], + ) if imprt.fieldmapping.get( "unique_id_sinp_generate", current_app.config["IMPORT"]["DEFAULT_GENERATE_MISSING_UUID"], @@ -358,14 +361,11 @@ def import_data_to_destination(imprt: TImports) -> None: ): insert_fields |= {field} - insert_fields -= {fields["unique_dataset_id"]} # Column only used for filling `id_dataset` - select_stmt = ( sa.select( *[transient_table.c[field.dest_field] for field in insert_fields], sa.literal(source.id_source), sa.literal(source.module.id_module), - sa.literal(imprt.id_dataset), sa.literal(imprt.id_import), sa.literal("I"), ) @@ -375,7 +375,6 @@ def import_data_to_destination(imprt: TImports) -> None: names = [field.dest_field for field in insert_fields] + [ "id_source", "id_module", - "id_dataset", "id_import", "last_action", ] diff --git a/backend/geonature/core/gn_synthese/models.py b/backend/geonature/core/gn_synthese/models.py index 9a572c9a75..e991a5d0c5 100644 --- a/backend/geonature/core/gn_synthese/models.py +++ b/backend/geonature/core/gn_synthese/models.py @@ -434,7 +434,7 @@ class Synthese(DB.Model): meta_update_date = DB.Column(DB.DateTime, server_default=FetchedValue()) last_action = DB.Column(DB.Unicode) - areas = relationship(LAreas, secondary=corAreaSynthese, backref="synthese_obs") + # areas = relationship(LAreas, secondary=corAreaSynthese, backref="synthese_obs") area_attachment = relationship(LAreas, foreign_keys=[id_area_attachment]) validations = relationship(TValidations, backref="attached_row") last_validation = relationship(last_validation, uselist=False, viewonly=True) diff --git a/backend/geonature/core/imports/checks/dataframe/cast.py b/backend/geonature/core/imports/checks/dataframe/cast.py index d946f754c3..72ad16cec0 100644 --- a/backend/geonature/core/imports/checks/dataframe/cast.py +++ b/backend/geonature/core/imports/checks/dataframe/cast.py @@ -74,6 +74,14 @@ def convert_to_uuid(value): return None +def is_valid_uuid(value): + try: + uuid_obj = UUID(value) + except Exception as e: + return False + return str(uuid_obj) == value + + def convert_to_integer(value): try: return int(value) diff --git a/backend/geonature/core/imports/checks/dataframe/core.py b/backend/geonature/core/imports/checks/dataframe/core.py index f20c1f6b14..df6dd18f43 100644 --- a/backend/geonature/core/imports/checks/dataframe/core.py +++ b/backend/geonature/core/imports/checks/dataframe/core.py @@ -12,7 +12,7 @@ from geonature.core.imports.models import BibFields, TImports from .utils import dataframe_check, error_replace - +from .cast import is_valid_uuid __all__ = ["check_required_values", "check_counts", "check_datasets"] @@ -194,7 +194,7 @@ def check_datasets( ) -> Set[str]: """ Check if datasets exist and are authorized for the user and import. - + It also fill the id_field based on the content of uuid_field Parameters ---------- imprt : TImports @@ -222,72 +222,92 @@ def check_datasets( """ updated_cols = set() - uuid_col = uuid_field.dest_field - id_col = id_field.dest_field + uuid_col = uuid_field.source_column - if uuid_col in df: - has_uuid_mask = df[uuid_col].notnull() - uuid = df.loc[has_uuid_mask, uuid_col].unique().tolist() + if uuid_col not in df: + yield { + "error_code": ImportCodeError.MISSING_VALUE, + "column": uuid_field.name_field, + } + uuid = df[uuid_col].unique().tolist() + + # check uuid format + valid_uuid_mask = df[uuid_col].apply(lambda x: is_valid_uuid(x)) + invalid_uuid_mask = ~valid_uuid_mask + if invalid_uuid_mask.any(): + yield { + "error_code": ImportCodeError.INVALID_UUID, + "column": uuid_field.name_field, + "invalid_rows": df[invalid_uuid_mask], + } - datasets = { - ds.unique_dataset_id.hex: ds - for ds in TDatasets.query.filter(TDatasets.unique_dataset_id.in_(uuid)) - .options(sa.orm.joinedload(TDatasets.nomenclature_data_origin)) - .options(sa.orm.raiseload("*")) - .all() + filtered_ds_mask = valid_uuid_mask + uuid = df[filtered_ds_mask][uuid_col].unique().tolist() + + # check dataset existance + datasets = { + str(ds.unique_dataset_id): ds + for ds in TDatasets.query.filter(TDatasets.unique_dataset_id.in_(uuid)) + .options(sa.orm.joinedload(TDatasets.nomenclature_data_origin)) + .options(sa.orm.raiseload("*")) + .all() + } + valid_ds_mask = df[uuid_col].isin(datasets.keys()) + invalid_ds_mask = ~valid_ds_mask & filtered_ds_mask + if invalid_ds_mask.any(): + yield { + "error_code": ImportCodeError.DATASET_NOT_FOUND, + "column": uuid_field.name_field, + "invalid_rows": df[invalid_ds_mask], } - valid_ds_mask = df[uuid_col].isin(datasets.keys()) - invalid_ds_mask = has_uuid_mask & ~valid_ds_mask - if invalid_ds_mask.any(): - yield { - "error_code": ImportCodeError.DATASET_NOT_FOUND, - "column": uuid_field.name_field, - "invalid_rows": df[invalid_ds_mask], - } - - inactive_dataset = [uuid for uuid, ds in datasets.items() if not ds.active] - inactive_dataset_mask = df[uuid_col].isin(inactive_dataset) - if inactive_dataset_mask.any(): - yield { - "error_code": ImportCodeError.DATASET_NOT_ACTIVE, - "column": uuid_field.name_field, - "invalid_rows": df[inactive_dataset_mask], - } - - # Warning: we check only permissions of first author, but currently there it only one author per import. - authorized_datasets = { - ds.unique_dataset_id.hex: ds - for ds in db.session.execute( - TDatasets.filter_by_creatable( - user=imprt.authors[0], module_code=module_code, object_code=object_code - ) - .where(TDatasets.unique_dataset_id.in_(uuid)) - .options(sa.orm.raiseload("*")) - ) - .scalars() - .all() + + filtered_ds_mask = filtered_ds_mask & valid_ds_mask + uuid = df[filtered_ds_mask][uuid_col].unique().tolist() + + # check dataset active status + active_ds = [uuid for uuid, ds in datasets.items() if ds.active] + active_ds_mask = df[uuid_col].isin(active_ds) + inactive_ds_mask = ~active_ds_mask & filtered_ds_mask + + if inactive_ds_mask.any(): + yield { + "error_code": ImportCodeError.DATASET_NOT_ACTIVE, + "column": uuid_field.name_field, + "invalid_rows": df[inactive_ds_mask], } - authorized_ds_mask = df[uuid_col].isin(authorized_datasets.keys()) - unauthorized_ds_mask = valid_ds_mask & ~authorized_ds_mask - if unauthorized_ds_mask.any(): - yield { - "error_code": ImportCodeError.DATASET_NOT_AUTHORIZED, - "column": uuid_field.name_field, - "invalid_rows": df[unauthorized_ds_mask], - } - - if authorized_ds_mask.any(): - df.loc[authorized_ds_mask, id_col] = df[authorized_ds_mask][uuid_col].apply( - lambda uuid: authorized_datasets[uuid].id_dataset + filtered_ds_mask = filtered_ds_mask & active_ds_mask + uuid = df[filtered_ds_mask][uuid_col].unique().tolist() + + # check dataset authorized + # Warning: we check only permissions of first author, but currently there it only one author per import. + authorized_datasets = { + str(ds.unique_dataset_id): ds + for ds in db.session.execute( + TDatasets.filter_by_creatable( + user=imprt.authors[0], module_code=module_code, object_code=object_code ) - updated_cols = {id_col} - - else: - has_uuid_mask = pd.Series(False, index=df.index) + .where(TDatasets.unique_dataset_id.in_(uuid)) + .options(sa.orm.raiseload("*")) + ) + .scalars() + .all() + } + authorized_ds_mask = active_ds_mask & df[uuid_col].isin(authorized_datasets.keys()) + unauthorized_ds_mask = ~authorized_ds_mask & filtered_ds_mask + if unauthorized_ds_mask.any(): + yield { + "error_code": ImportCodeError.DATASET_NOT_AUTHORIZED, + "column": uuid_field.name_field, + "invalid_rows": df[unauthorized_ds_mask], + } + filtered_ds_mask = filtered_ds_mask & authorized_ds_mask - if (~has_uuid_mask).any(): - # Set id_dataset from import for empty cells: - df.loc[~has_uuid_mask, id_col] = imprt.id_dataset + # compute id_col based on uuid_col + if filtered_ds_mask.any(): + id_col = id_field.dest_field + df.loc[filtered_ds_mask, id_col] = df[filtered_ds_mask][uuid_col].apply( + lambda uuid: authorized_datasets[uuid].id_dataset + ) updated_cols = {id_col} return updated_cols diff --git a/backend/geonature/core/imports/checks/sql/extra.py b/backend/geonature/core/imports/checks/sql/extra.py index 80959e5332..1d1d7ed7a7 100644 --- a/backend/geonature/core/imports/checks/sql/extra.py +++ b/backend/geonature/core/imports/checks/sql/extra.py @@ -241,7 +241,7 @@ def check_existing_uuid( imprt: TImports, entity: Entity, uuid_field: BibFields, - whereclause: Any = sa.true(), + id_dataset_field: BibFields = None, skip=False, ): """ @@ -254,25 +254,34 @@ def check_existing_uuid( entity : Entity The entity to check. uuid_field : BibFields - The field to check. - whereclause : BooleanClause - The WHERE clause to apply to the check. + The field to check + id_dataset_field : BibFields + if defnied, the uuid existence is checked for the given dataset. Otherwise, it is checked globally + skip: Boolean Raise SKIP_EXISTING_UUID instead of EXISTING_UUID and set row validity to None (do not import) """ transient_table = imprt.destination.get_transient_table() dest_table = entity.get_destination_table() error_type = "SKIP_EXISTING_UUID" if skip else "EXISTING_UUID" + + whereclause = sa.and_( + transient_table.c[uuid_field.dest_field] == dest_table.c[uuid_field.dest_field], + transient_table.c[entity.validity_column].is_(True), + ) + + if id_dataset_field: + whereclause = ( + whereclause & transient_table.c[id_dataset_field.dest_field] + == dest_table.c[id_dataset_field.dest_field] + ) + report_erroneous_rows( imprt, entity, error_type=error_type, error_column=uuid_field.name_field, - whereclause=sa.and_( - transient_table.c[uuid_field.dest_field] == dest_table.c[uuid_field.dest_field], - transient_table.c[entity.validity_column].is_(True), - whereclause, - ), + whereclause=whereclause, level_validity_mapping={"ERROR": False, "WARNING": None}, ) diff --git a/backend/geonature/core/imports/checks/sql/nomenclature.py b/backend/geonature/core/imports/checks/sql/nomenclature.py index 83b2b8e32c..c8ffa5a6dc 100644 --- a/backend/geonature/core/imports/checks/sql/nomenclature.py +++ b/backend/geonature/core/imports/checks/sql/nomenclature.py @@ -176,9 +176,7 @@ def check_nomenclature_exist_proof( ) -def check_nomenclature_blurring( - imprt, entity, blurring_field, id_dataset_field, uuid_dataset_field -): +def check_nomenclature_blurring(imprt, entity, blurring_field, id_dataset_field): """ Raise an error if blurring not set. Required if the dataset is private. @@ -196,10 +194,7 @@ def check_nomenclature_blurring( error_type=ImportCodeError.CONDITIONAL_MANDATORY_FIELD_ERROR, error_column=blurring_field.name_field, whereclause=sa.and_( - sa.or_( - transient_table.c[id_dataset_field.name_field] == TDatasets.id_dataset, - transient_table.c[uuid_dataset_field.name_field] == TDatasets.unique_dataset_id, - ), + transient_table.c[id_dataset_field.name_field] == TDatasets.id_dataset, TDatasets.id_nomenclature_data_origin == id_nomenclature_private, transient_table.c[blurring_field.dest_field] == None, ), diff --git a/backend/geonature/core/imports/config_schema.py b/backend/geonature/core/imports/config_schema.py index 2a77982e3f..5b5164b670 100644 --- a/backend/geonature/core/imports/config_schema.py +++ b/backend/geonature/core/imports/config_schema.py @@ -18,12 +18,6 @@ "show": True, "filter": True, }, - { - "prop": "dataset.dataset_name", - "name": "Jeu de données", - "show": True, - "filter": False, - }, { "prop": "statistics_rows", "name": "Lignes importées", diff --git a/backend/geonature/core/imports/models.py b/backend/geonature/core/imports/models.py index 3e2b599141..8e71a03000 100644 --- a/backend/geonature/core/imports/models.py +++ b/backend/geonature/core/imports/models.py @@ -29,7 +29,6 @@ from geonature.utils.celery import celery_app from geonature.core.gn_permissions.tools import get_scopes_by_action from geonature.core.gn_commons.models import TModules -from geonature.core.gn_meta.models import TDatasets from pypnnomenclature.models import BibNomenclaturesTypes from pypnusershub.db.models import User @@ -319,8 +318,6 @@ def get_instance_permissions(self, scopes, user=None): @serializable( fields=[ "authors.nom_complet", - "dataset.dataset_name", - "dataset.active", "destination.code", "destination.label", "destination.statistics_labels", @@ -352,7 +349,6 @@ class TImports(InstancePermissionMixin, db.Model): detected_encoding = db.Column(db.Unicode, nullable=True) # import_table = db.Column(db.Unicode, nullable=True) full_file_name = db.Column(db.Unicode, nullable=True) - id_dataset = db.Column(db.Integer, ForeignKey("gn_meta.t_datasets.id_dataset"), nullable=True) date_create_import = db.Column(db.DateTime, default=datetime.now) date_update_import = db.Column(db.DateTime, default=datetime.now, onupdate=datetime.now) date_end_import = db.Column(db.DateTime, nullable=True) @@ -372,7 +368,6 @@ class TImports(InstancePermissionMixin, db.Model): ) loaded = db.Column(db.Boolean, nullable=False, default=False) processed = db.Column(db.Boolean, nullable=False, default=False) - dataset = db.relationship(TDatasets, lazy="joined") source_file = deferred(db.Column(db.LargeBinary)) columns = db.Column(ARRAY(db.Unicode)) # keys are target names, values are source names diff --git a/backend/geonature/core/imports/routes/imports.py b/backend/geonature/core/imports/routes/imports.py index 92b1dbb819..63840f373b 100644 --- a/backend/geonature/core/imports/routes/imports.py +++ b/backend/geonature/core/imports/routes/imports.py @@ -23,7 +23,6 @@ from geonature.core.gn_permissions import decorators as permissions from geonature.core.gn_permissions.decorators import login_required from geonature.core.gn_permissions.tools import get_scopes_by_action -from geonature.core.gn_meta.models import TDatasets from pypnnomenclature.models import TNomenclatures @@ -85,11 +84,6 @@ def get_import_list(scope, destination=None): filters = [] if search: filters.append(TImports.full_file_name.ilike(f"%{search}%")) - filters.append( - TImports.dataset.has( - func.lower(TDatasets.dataset_name).contains(func.lower(search)), - ) - ) filters.append( TImports.authors.any( or_( @@ -114,11 +108,9 @@ def get_import_list(scope, destination=None): query = ( select(TImports) .options( - contains_eager(TImports.dataset), contains_eager(TImports.authors), contains_eager(TImports.destination).contains_eager(Destination.module), ) - .join(TImports.dataset, isouter=True) .join(TImports.authors, isouter=True) .join(Destination) .join(TModules) @@ -165,13 +157,10 @@ def upload_file(scope, imprt, destination=None): # destination is set when impr Add an import or update an existing import. :form file: file to import - :form int datasetId: dataset ID to which import data """ if imprt: if not imprt.has_instance_permission(scope, action_code="C"): raise Forbidden - if not imprt.dataset.active: - raise Forbidden("Le jeu de données est fermé.") destination = imprt.destination else: assert destination @@ -187,22 +176,7 @@ def upload_file(scope, imprt, destination=None): # destination is set when impr if size == 0: raise BadRequest(description="Impossible to upload empty files") if imprt is None: - try: - dataset_id = int(request.form["datasetId"]) - except ValueError: - raise BadRequest(description="'datasetId' must be an integer.") - dataset = db.session.get(TDatasets, dataset_id) - if dataset is None: - raise BadRequest(description=f"Dataset '{dataset_id}' does not exist.") - ds_scope = get_scopes_by_action( - module_code=destination.module.module_code, - object_code="ALL", # TODO object_code should be configurable by destination - )["C"] - if not dataset.has_instance_permission(ds_scope): - raise Forbidden(description="Vous n’avez pas les permissions sur ce jeu de données.") - if not dataset.active: - raise Forbidden("Le jeu de données est fermé.") - imprt = TImports(destination=destination, dataset=dataset) + imprt = TImports(destination=destination) imprt.authors.append(author) db.session.add(imprt) else: @@ -226,8 +200,6 @@ def upload_file(scope, imprt, destination=None): # destination is set when impr def decode_file(scope, imprt): if not imprt.has_instance_permission(scope, action_code="C"): raise Forbidden - if not imprt.dataset.active: - raise Forbidden("Le jeu de données est fermé.") if imprt.source_file is None: raise BadRequest(description="A file must be first uploaded.") if "encoding" not in request.json: @@ -292,8 +264,6 @@ def decode_file(scope, imprt): def set_import_field_mapping(scope, imprt): if not imprt.has_instance_permission(scope, action_code="C"): raise Forbidden - if not imprt.dataset.active: - raise Forbidden("Le jeu de données est fermé.") try: FieldMapping.validate_values(request.json) except ValueError as e: @@ -309,8 +279,6 @@ def set_import_field_mapping(scope, imprt): def load_import(scope, imprt): if not imprt.has_instance_permission(scope, action_code="C"): raise Forbidden - if not imprt.dataset.active: - raise Forbidden("Le jeu de données est fermé.") if imprt.source_file is None: raise BadRequest(description="A file must be first uploaded.") if imprt.fieldmapping is None: @@ -404,8 +372,6 @@ def get_import_values(scope, imprt): def set_import_content_mapping(scope, imprt): if not imprt.has_instance_permission(scope, action_code="C"): raise Forbidden - if not imprt.dataset.active: - raise Forbidden("Le jeu de données est fermé.") try: ContentMapping.validate_values(request.json) except ValueError as e: @@ -424,8 +390,6 @@ def prepare_import(scope, imprt): """ if not imprt.has_instance_permission(scope, action_code="C"): raise Forbidden - if not imprt.dataset.active: - raise Forbidden("Le jeu de données est fermé.") # Check preconditions to execute this action if not imprt.loaded: @@ -627,8 +591,6 @@ def import_valid_data(scope, imprt): """ if not imprt.has_instance_permission(scope, action_code="C"): raise Forbidden - if not imprt.dataset.active: - raise Forbidden("Le jeu de données est fermé.") if not imprt.processed: raise Forbidden("L’import n’a pas été préalablement vérifié.") transient_table = imprt.destination.get_transient_table() @@ -662,8 +624,6 @@ def delete_import(scope, imprt): """ if not imprt.has_instance_permission(scope, action_code="C"): raise Forbidden - if not imprt.dataset.active: - raise Forbidden("Le jeu de données est fermé.") ImportUserError.query.filter_by(imprt=imprt).delete() transient_table = imprt.destination.get_transient_table() db.session.execute( diff --git a/backend/geonature/core/imports/templates/import_template_pdf.html b/backend/geonature/core/imports/templates/import_template_pdf.html index 467849f33b..093034fb4b 100644 --- a/backend/geonature/core/imports/templates/import_template_pdf.html +++ b/backend/geonature/core/imports/templates/import_template_pdf.html @@ -47,9 +47,6 @@

{% endfor %} - {% if data.dataset: %} -
  • Jeu de données : {{ data.dataset.dataset_name }}
  • - {% endif %} {% if data.keywords: %}
    @@ -74,7 +71,7 @@

    {% endif %} - + {% if data.date_end_import is not none %}
    @@ -97,7 +94,7 @@

    {% endfor %} - +

    - +
    {% endif %} {% if data.processed %} @@ -137,7 +134,7 @@

    - + {% endif %} diff --git a/backend/geonature/migrations/versions/imports/a43842db7ac1_monitorings_adjust_gn_imports_bib_.py b/backend/geonature/migrations/versions/imports/a43842db7ac1_monitorings_adjust_gn_imports_bib_.py new file mode 100644 index 0000000000..e50086b726 --- /dev/null +++ b/backend/geonature/migrations/versions/imports/a43842db7ac1_monitorings_adjust_gn_imports_bib_.py @@ -0,0 +1,85 @@ +"""[monitorings] Adjust gn.imports bib_fields id_dataset and unique_id_dataset values + +Revision ID: a43842db7ac1 +Revises: 2b0b3bd0248c +Create Date: 2024-12-17 11:18:07.806852 + +""" + +from alembic import op +import sqlalchemy as sa + + +# revision identifiers, used by Alembic. +revision = "a43842db7ac1" +down_revision = "2b0b3bd0248c" +branch_labels = None +depends_on = None + + +def upgrade(): + op.execute( + """ + UPDATE gn_imports.bib_fields + SET display = TRUE, + mandatory = TRUE, + type_field = 'dataset', + type_field_params = '{"bind_value": "unique_dataset_id"}', + source_field = 'src_unique_dataset_id', + dest_field = NULL + WHERE name_field = 'unique_dataset_id' + """ + ) + op.execute( + """ + UPDATE gn_imports.bib_fields + SET display = FALSE, + mandatory = FALSE, + dest_field = 'id_dataset', + source_field = NULL + WHERE name_field = 'id_dataset' + """ + ) + op.execute( + """ + DO $$ + BEGIN + -- Vérifier si la colonne existe dans la table + IF EXISTS (SELECT 1 + FROM information_schema.columns + WHERE + table_name = 't_imports' + AND column_name = 'id_dataset') THEN + -- Supprimer la colonne si elle existe + ALTER TABLE gn_imports.t_imports DROP COLUMN id_dataset; + END IF; + END $$; + """ + ) + + +def downgrade(): + op.execute( + """ + UPDATE gn_imports.bib_fields + SET display = FALSE, + mandatory = FALSE, + optional_conditions = NULL, + type_field = 'text', + type_field_params = NULL, + dest_field = 'unique_dataset_id' + WHERE name_field = 'unique_dataset_id' + """ + ) + op.execute( + """ + UPDATE gn_imports.bib_fields + SET dest_field = NULL + WHERE name_field = 'id_dataset' + """ + ) + op.add_column( + schema="gn_imports", + table_name="t_imports", + column=sa.Column("id_dataset", sa.INTEGER), + ) diff --git a/backend/geonature/migrations/versions/imports/a81f74d0a518_insert_import_sample_data.py b/backend/geonature/migrations/versions/imports/a81f74d0a518_insert_import_sample_data.py index 386116d6fa..b061650e66 100644 --- a/backend/geonature/migrations/versions/imports/a81f74d0a518_insert_import_sample_data.py +++ b/backend/geonature/migrations/versions/imports/a81f74d0a518_insert_import_sample_data.py @@ -164,7 +164,7 @@ def downgrade(): op.execute( """ DELETE FROM gn_permissions.t_permissions - WHERE id_role = (SELECT id_role FROM utilisateurs.t_roles WHERE identifiant = 'agent-test-import'); + WHERE id_role = (SELECT id_role FROM utilisateurs.t_roles WHERE identifiant = 'agent-test-import'); """ ) @@ -184,6 +184,23 @@ def downgrade(): """ ) + ## Clean Rol Provider + # admin-test-import + op.execute( + """ + DELETE FROM utilisateurs.cor_role_provider + WHERE id_role = (SELECT id_role FROM utilisateurs.t_roles WHERE identifiant = 'admin-test-import'); + """ + ) + + # agent-test-import + op.execute( + """ + DELETE FROM utilisateurs.cor_role_provider + WHERE id_role = (SELECT id_role FROM utilisateurs.t_roles WHERE identifiant = 'agent-test-import'); + """ + ) + # Delete the roles op.execute( """ diff --git a/backend/geonature/tests/imports/files/occhab/no_default_uuid.csv b/backend/geonature/tests/imports/files/occhab/no_default_uuid.csv index 56b632dddb..ccd396e050 100644 --- a/backend/geonature/tests/imports/files/occhab/no_default_uuid.csv +++ b/backend/geonature/tests/imports/files/occhab/no_default_uuid.csv @@ -1,9 +1,9 @@ Objectif du test;Erreur station;Erreur habitat;id_station_source;unique_id_sinp_station;unique_dataset_id;date_min;date_max;observers;id_nomenclature_area_surface_calculation;WKT;id_nomenclature_geographic_object;unique_id_sinp_habitat;nom_cite;cd_hab;technical_precision -Station + habitat sur la même ligne;OK !;OK !;Station 8;afa81c29-c75d-408d-bf48-53cce02d5561;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;4ee53579-b09b-408f-aa1f-d62495a66667;prairie;24; -Station uniquement;OK !;Pas d’habitat;;9d3fb1bd-6148-45c4-aa13-ff9212155afe;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;;; -Habitat uniquement dans une station existante en base.;Pas de station;OK !;;EXISTING_STATION_UUID;;;;Toto;;;;05f0163a-ab14-4045-84b9-b513188092ae;prairie;24; -Habitat uniquement dans une station existante en base, mais l’habitat n’a pas d’UUID alors qu’il n’est pas généré.;Pas de station;MISSING_VALUE(unique_id_sinp_habitat);;EXISTING_STATION_UUID;;;;Toto;;;;;prairie;24; -Habitat uniquement dans une station existante en base, mais l’UUID est invalide.;Pas de station;INVALID_UUID(unique_id_sinp_habitat);;EXISTING_STATION_UUID;;;;Toto;;;;erroneous;prairie;24; +Station + habitat sur la même ligne;OK !;OK !;Station 8;afa81c29-c75d-408d-bf48-53cce02d5561;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;4ee53579-b09b-408f-aa1f-d62495a66667;prairie;24; +Station uniquement;OK !;Pas d’habitat;;9d3fb1bd-6148-45c4-aa13-ff9212155afe;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;;; +Habitat uniquement dans une station existante en base.;Pas de station;OK !;;@EXISTING_STATION_UUID@;;;;Toto;;;;05f0163a-ab14-4045-84b9-b513188092ae;prairie;24; +Habitat uniquement dans une station existante en base, mais l’habitat n’a pas d’UUID alors qu’il n’est pas généré.;Pas de station;MISSING_VALUE(unique_id_sinp_habitat);;@EXISTING_STATION_UUID@;;;;Toto;;;;;prairie;24; +Habitat uniquement dans une station existante en base, mais l’UUID est invalide.;Pas de station;INVALID_UUID(unique_id_sinp_habitat);;@EXISTING_STATION_UUID@;;;;Toto;;;;erroneous;prairie;24; ;;;;;;;;Toto;;;;;;; ;;;;;;;;Toto;;;;;;; ;;;;;;;;Toto;;;;;;; @@ -11,30 +11,30 @@ Habitat mais pas de station référencée;Pas de station;MISSING_VALUE(unique_id Uniquement un uuid station, mais on ne sait pas s’il appartient à une station ou s’il sert à indiquer le parent d’un habitat;ORPHAN_ROW(unique_id_sinp_station);ORPHAN_ROW(unique_id_sinp_station);;258a2478-8a0e-4321-83df-c2313ad3040e;;;;Toto;;;;;;; Uniquement un id station source, mais on ne sait pas s’il appartient à une station ou s’il sert à indiquer le parent d’un habitat;ORPHAN_ROW(id_station_source);ORPHAN_ROW(id_station_source);Station -1;;;;;Toto;;;;;;; Uniquement UUID station + id station source, mais on ne sait pas s’ils appartiennent à une station ou s’ils servent à indiquer le parent d’un habitat;ORPHAN_ROW(unique_id_sinp_station, id_station_source);ORPHAN_ROW(unique_id_sinp_station,id_station_source);Station -2;54e54935-982b-4da3-9aaf-e87e49a1fdf1;;;;Toto;;;;;;; -On importe 2 habitats dans une même nouvelle station dont les données sont répétées. Les lignes contenant la station sont rapproché par UUID.;OK !;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;e5e7a184-3e92-4adb-a721-5bd004b3397f;forêt;24; -;OK !;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;8f52f122-b9ae-45b3-b947-2c9f7934b823;prairie;24; -On importe 2 habitats dans une même nouvelle station dont les données sont répétées MAIS AVEC DES DIFFÉRENCES (date). Les lignes contenant la station sont rapproché par UUID.;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;17/11/2023;;Toto;;COORD_STATION;St;d91496e9-d904-45a8-9e18-cb8acbbb6ea6;prairie;24; -;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;18/11/2023;;Toto;;COORD_STATION;St;8b25ede6-b65a-4a85-98d6-0c813bcae3bf;prairie;24; -On importe 2 habitats dans une même nouvelle station dont les données sont répétées mais avec des différences (date INVALIDE). Les lignes contenant la station sont rapproché par UUID. On vérifie qu’on a pas d’erreur sur la date car les contrôles ne doivent pas être lancé si les données sont incohérentes. En revanche, les contrôles des habitats doivent bien être lancés.;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;17/11/2023;;Toto;;COORD_STATION;St;8235a358-3bc0-4ade-8f60-eb5d9e8ac453;prairie;24; -NO_PARENT_ENTITY(id_station) non levé sur l’habitat en raison de l’implémentation du check qui ignore les lignes erronées. À voir s’il faut le faire évoluer.;INCOHERENT_DATA(unique_id_sinp_station);INVALID_INTEGER(cd_hab);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;date invalide;;Toto;;COORD_STATION;St;0a53de31-be5a-4ad9-a8f8-511e85d50ace;prairie;invalide; -On importe 2 habitats dans une même nouvelle station dont les données sont répétées. Les lignes contenant la station sont rapproché par id origine. Mais les UUID ne sont pas spécifier alors au’ils ne sont pas générés.;MISSING_VALUE(unique_id_sinp_station);MISSING_VALUE(unique_id_sinp_station),ERRONEOUS_PARENT_ENTITY;Station 1;;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;d6050c44-88c0-45c6-bb2c-02f7e72f57aa;prairie;24; -;La station étant dupliqué, elle est ignorée;MISSING_VALUE(unique_id_sinp_station),ERRONEOUS_PARENT_ENTITY;Station 1;;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;f2678b4c-5092-4f6f-902a-b5d21f0d7a88;prairie;24; -On importe 2 habitats dans une même nouvelle station dont les données sont répétées MAIS AVEC DES DIFFÉRENCES (date). Les lignes contenant la station sont rapproché par id origine.;INCOHERENT_DATA(id_station_source);MISSING_VALUE(unique_id_sinp_station);Station 2;;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;2eba7b82-e987-4ea8-bca8-a34de063db87;prairie;24; -;INCOHERENT_DATA(id_station_source);MISSING_VALUE(unique_id_sinp_station);Station 2;;;invalide;17/11/2023;Toto;;COORD_STATION;St;c68163bd-b45d-436b-87ce-389ad7f18572;prairie;24; -Un UUID station invalide lève une erreur sur la station ET sur l’habitat;INVALID_UUID(unique_id_sinp_station);INVALID_UUID(unique_id_sinp_station),ERRONEOUS_PARENT_ENTITY;;Erroneous 1;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;6c02ef80-2e78-4c2c-b8b5-1c75e2349fc2;prairie;24; -Un UUID station invalide lève une erreur sur la station uniquement si pas d’habitat;INVALID_UUID(unique_id_sinp_station),MISSING_VALUE(date_min);Pas d’habitat;;Erroneous 2;;;17/11/2024;Toto;;COORD_STATION;;;;; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées. Les lignes contenant la station sont rapproché par UUID.;OK !;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;e5e7a184-3e92-4adb-a721-5bd004b3397f;forêt;24; +;OK !;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;8f52f122-b9ae-45b3-b947-2c9f7934b823;prairie;24; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées MAIS AVEC DES DIFFÉRENCES (date). Les lignes contenant la station sont rapproché par UUID.;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;@VALID_DATASET_UUID@;17/11/2023;;Toto;;@COORD_STATION@;St;d91496e9-d904-45a8-9e18-cb8acbbb6ea6;prairie;24; +;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;@VALID_DATASET_UUID@;18/11/2023;;Toto;;@COORD_STATION@;St;8b25ede6-b65a-4a85-98d6-0c813bcae3bf;prairie;24; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées mais avec des différences (date INVALIDE). Les lignes contenant la station sont rapproché par UUID. On vérifie qu’on a pas d’erreur sur la date car les contrôles ne doivent pas être lancé si les données sont incohérentes. En revanche, les contrôles des habitats doivent bien être lancés.;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;@VALID_DATASET_UUID@;17/11/2023;;Toto;;@COORD_STATION@;St;8235a358-3bc0-4ade-8f60-eb5d9e8ac453;prairie;24; +NO_PARENT_ENTITY(id_station) non levé sur l’habitat en raison de l’implémentation du check qui ignore les lignes erronées. À voir s’il faut le faire évoluer.;INCOHERENT_DATA(unique_id_sinp_station);INVALID_INTEGER(cd_hab);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;@VALID_DATASET_UUID@;date invalide;;Toto;;@COORD_STATION@;St;0a53de31-be5a-4ad9-a8f8-511e85d50ace;prairie;invalide; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées. Les lignes contenant la station sont rapproché par id origine. Mais les UUID ne sont pas spécifier alors au’ils ne sont pas générés.;MISSING_VALUE(unique_id_sinp_station);MISSING_VALUE(unique_id_sinp_station),ERRONEOUS_PARENT_ENTITY;Station 1;;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;d6050c44-88c0-45c6-bb2c-02f7e72f57aa;prairie;24; +;La station étant dupliqué, elle est ignorée;MISSING_VALUE(unique_id_sinp_station),ERRONEOUS_PARENT_ENTITY;Station 1;;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;f2678b4c-5092-4f6f-902a-b5d21f0d7a88;prairie;24; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées MAIS AVEC DES DIFFÉRENCES (date). Les lignes contenant la station sont rapproché par id origine.;INCOHERENT_DATA(id_station_source);MISSING_VALUE(unique_id_sinp_station);Station 2;;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;2eba7b82-e987-4ea8-bca8-a34de063db87;prairie;24; +;INCOHERENT_DATA(id_station_source);MISSING_VALUE(unique_id_sinp_station);Station 2;;@VALID_DATASET_UUID@;invalide;17/11/2023;Toto;;@COORD_STATION@;St;c68163bd-b45d-436b-87ce-389ad7f18572;prairie;24; +Un UUID station invalide lève une erreur sur la station ET sur l’habitat;INVALID_UUID(unique_id_sinp_station);INVALID_UUID(unique_id_sinp_station),ERRONEOUS_PARENT_ENTITY;;Erroneous 1;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;6c02ef80-2e78-4c2c-b8b5-1c75e2349fc2;prairie;24; +Un UUID station invalide lève une erreur sur la station uniquement si pas d’habitat;INVALID_UUID(unique_id_sinp_station),MISSING_VALUE(date_min);Pas d’habitat;;Erroneous 2;@VALID_DATASET_UUID@;;17/11/2024;Toto;;@COORD_STATION@;;;;; Un UUID station invalide lève une erreur sur l’habitat uniquement si pas de station. Comme pour un précédent test d’incohérence,, NO PARENT_ENTITY n’est pas levé en raison d’un choix d’implémentation qui peut être modifié.;Pas de station;INVALID_UUID(unique_id_sinp_station);;Erroneous 3;;;;Toto;;;;0f8b2ae0-df5f-4d66-9c0b-5ccbb0baa7f2;prairie;24; -Les UUID ≠ mais les id origine sont identique !;INCOHERENT_DATA [UUID ≠];NO_PARENT_ENTITY(id_station);Station 3;dd0d12fc-bb85-4029-9c72-14fd8583f9bb;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;791438ee-aeae-4983-9d23-1ae86208128e;prairie;24; -;INCOHERENT_DATA [UUID ≠];NO_PARENT_ENTITY(id_station);Station 3;330bb0f5-dc1c-431a-af1a-d70138b8c99d;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;745743a3-d5e2-4f43-a791-cd4bcf9a06d5;prairie;24; -Les UUID sont égaux mais les id origine ≠ !;INCOHERENT_DATA [id_station_source ≠];NO_PARENT_ENTITY(id_station);Station 4;a5c37acb-c966-4024-bea6-71ec125b51c8;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;fc6b3757-7c6e-4619-a509-8d964135596b;prairie;24; -;INCOHERENT_DATA [id_station_source ≠];NO_PARENT_ENTITY(id_station);Station 5;a5c37acb-c966-4024-bea6-71ec125b51c8;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;de898fc8-8ef7-47ff-8cc0-5a463022fda4;prairie;24; -Les id origine sont identique, mais les UUID ne sont pas toujours renseignés.;INCOHERENT_DATA [UUID ≠];NO_PARENT_ENTITY(id_station);Station 6;7ed90696-4e74-4ed5-98a4-518eea009a7f;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;e63b9d13-73bf-4a2a-9539-d26eb74633ec;prairie;24; -;INCOHERENT_DATA [UUID ≠];MISSING_VALUE(unique_id_sinp_station);Station 6;;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;d8268ad3-cc6a-47a9-80b8-460a98ff3bab;prairie;24; -Les UUID sont égaux mais les id origine ne sont pas toujours renseignés.;INCOHERENT_DATA [id_station_source ≠];NO_PARENT_ENTITY(id_station);Station 7;c4262f95-0b19-422a-848b-8f83c292d27a;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;51ef110f-5f38-414e-8820-6bee9930e46d;prairie;24; -;INCOHERENT_DATA [id_station_source ≠];NO_PARENT_ENTITY(id_station);;c4262f95-0b19-422a-848b-8f83c292d27a;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;e5c4fcb2-2bd1-44e9-a2d1-87888d3da246;prairie;24; -Il y a ni UUID, ni id_origine, or les UUID ne sont pas générés.;MISSING_VALUE(unique_id_sinp_station);MISSING_VALUE(unique_id_sinp_station);;;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;7aa27e0b-680e-466e-940a-97dd7fd7715a;prairie;24; +Les UUID ≠ mais les id origine sont identique !;INCOHERENT_DATA [UUID ≠];NO_PARENT_ENTITY(id_station);Station 3;dd0d12fc-bb85-4029-9c72-14fd8583f9bb;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;791438ee-aeae-4983-9d23-1ae86208128e;prairie;24; +;INCOHERENT_DATA [UUID ≠];NO_PARENT_ENTITY(id_station);Station 3;330bb0f5-dc1c-431a-af1a-d70138b8c99d;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;745743a3-d5e2-4f43-a791-cd4bcf9a06d5;prairie;24; +Les UUID sont égaux mais les id origine ≠ !;INCOHERENT_DATA [id_station_source ≠];NO_PARENT_ENTITY(id_station);Station 4;a5c37acb-c966-4024-bea6-71ec125b51c8;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;fc6b3757-7c6e-4619-a509-8d964135596b;prairie;24; +;INCOHERENT_DATA [id_station_source ≠];NO_PARENT_ENTITY(id_station);Station 5;a5c37acb-c966-4024-bea6-71ec125b51c8;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;de898fc8-8ef7-47ff-8cc0-5a463022fda4;prairie;24; +Les id origine sont identique, mais les UUID ne sont pas toujours renseignés.;INCOHERENT_DATA [UUID ≠];NO_PARENT_ENTITY(id_station);Station 6;7ed90696-4e74-4ed5-98a4-518eea009a7f;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;e63b9d13-73bf-4a2a-9539-d26eb74633ec;prairie;24; +;INCOHERENT_DATA [UUID ≠];MISSING_VALUE(unique_id_sinp_station);Station 6;;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;d8268ad3-cc6a-47a9-80b8-460a98ff3bab;prairie;24; +Les UUID sont égaux mais les id origine ne sont pas toujours renseignés.;INCOHERENT_DATA [id_station_source ≠];NO_PARENT_ENTITY(id_station);Station 7;c4262f95-0b19-422a-848b-8f83c292d27a;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;51ef110f-5f38-414e-8820-6bee9930e46d;prairie;24; +;INCOHERENT_DATA [id_station_source ≠];NO_PARENT_ENTITY(id_station);;c4262f95-0b19-422a-848b-8f83c292d27a;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;e5c4fcb2-2bd1-44e9-a2d1-87888d3da246;prairie;24; +Il y a ni UUID, ni id_origine, or les UUID ne sont pas générés.;MISSING_VALUE(unique_id_sinp_station);MISSING_VALUE(unique_id_sinp_station);;;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;7aa27e0b-680e-466e-940a-97dd7fd7715a;prairie;24; Import d’un habitat dans une station existante ailleurs dans le fichier, référencé par UUID.;Pas de station;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;;;;Toto;;;;3adb0b26-97ba-436e-923e-8a1b4f4d41ea;prairie;24; Import d’un habitat dans une station existante ailleurs dans le fichier, référencé par id origine.;Pas de station;MISSING_VALUE(unique_id_sinp_station);Station 8;;;;;Toto;;;;4bed57d7-2569-4e49-9b82-14b6b847d5f7;prairie;24; -On importe une station qui existe déjà en base : elle est ignorée;SKIP_EXISTING_UUID;Pas d’habitat;;EXISTING_STATION_UUID;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;;; -On importe une station qui existe déjà en base et un nouvel habitat, seul l’habitat est importé;SKIP_EXISTING_UUID;OK !;;EXISTING_STATION_UUID;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;33153ba5-8773-4ffc-8e69-7be3e008208a;prairie;24; -On importe une station et un habitat existant déjà en base;SKIP_EXISTING_UUID;SKIP_EXISTING_UUID;;EXISTING_STATION_UUID;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;EXISTING_HABITAT_UUID;prairie;24; +On importe une station qui existe déjà en base : elle est ignorée;SKIP_EXISTING_UUID;Pas d’habitat;;@EXISTING_STATION_UUID@;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;;; +On importe une station qui existe déjà en base et un nouvel habitat, seul l’habitat est importé;SKIP_EXISTING_UUID;OK !;;@EXISTING_STATION_UUID@;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;33153ba5-8773-4ffc-8e69-7be3e008208a;prairie;24; +On importe une station et un habitat existant déjà en base;SKIP_EXISTING_UUID;SKIP_EXISTING_UUID;;@EXISTING_STATION_UUID@;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;@EXISTING_HABITAT_UUID@;prairie;24; diff --git a/backend/geonature/tests/imports/files/occhab/valid_file.csv b/backend/geonature/tests/imports/files/occhab/valid_file.csv index 543730d7ea..173f233a2e 100644 --- a/backend/geonature/tests/imports/files/occhab/valid_file.csv +++ b/backend/geonature/tests/imports/files/occhab/valid_file.csv @@ -1,44 +1,44 @@ Objectif du test;Erreur station;Erreur habitat;id_station_source;unique_id_sinp_station;unique_dataset_id;date_min;date_max;observers;id_nomenclature_area_surface_calculation;WKT;id_nomenclature_geographic_object;unique_id_sinp_habitat;nom_cite;cd_hab;technical_precision;id_nomenclature_collection_technique -Station + habitat sur la même ligne;OK !;OK !;;afa81c29-c75d-408d-bf48-53cce02d5561;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;4ee53579-b09b-408f-aa1f-d62495a66667;prairie;24;; -Station uniquement;OK !;Pas d’habitat;;9d3fb1bd-6148-45c4-aa13-ff9212155afe;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;;;; -Habitat uniquement dans une station existante en base.;Pas de station;OK !;;EXISTING_STATION_UUID;;;;Toto;;;;05f0163a-ab14-4045-84b9-b513188092ae;prairie;24;; -Dataset innexistant, habitat valide mais pas le parent;DATASET_NOT_FOUND(unique_dataset_id), INCOHERENT_DATA;ERRONEOUS_PARENT_ENTITY;;bdc3346d-0fc3-40fa-b787-be927e4dd82e;050d613c-543f-47fd-800a-13931b2721c7;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;2ff4867d-6943-45d8-873d-187fbc6d67a7;prairie;24;; -Dataset interdit, habitat valide mais pas le parent;DATASET_NOT_AUTHORIZED(unique_dataset_id);ERRONEOUS_PARENT_ENTITY;;f5f031a3-cf1b-419c-9817-69c39f51aef4;FORBIDDEN_DATASET_UUID;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;5dfb9930-4795-4e6f-baae-3dd86abb3b70;prairie;24;; -Dataset UUID invalide;INVALID_UUID(unique_dataset_id);Pas d’habitat;;;erroneous;17/11/2023;17/11/2023;Toto;;COORD_STATION;;;;;; -Champs géométrique manquant;NO-GEOM(Champs géométriques);Pas d’habitat;;;;17/11/2023;17/11/2023;Toto;;;;;;;; -Champs requis manquant;MISSING_VALUE(date_min);ERRONEOUS_PARENT_ENTITY;;4ee7728d-387d-49c5-b9a3-4162b0987fa5;;;;Toto;;COORD_STATION;St;aeb10ac4-6d69-4fa6-8df6-14d9304911df;prairie;24;; +Station + habitat sur la même ligne;OK !;OK !;;afa81c29-c75d-408d-bf48-53cce02d5561;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;4ee53579-b09b-408f-aa1f-d62495a66667;prairie;24;; +Station uniquement;OK !;Pas d’habitat;;9d3fb1bd-6148-45c4-aa13-ff9212155afe;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;;;; +Habitat uniquement dans une station existante en base.;Pas de station;OK !;;@EXISTING_STATION_UUID@;;;;Toto;;;;05f0163a-ab14-4045-84b9-b513188092ae;prairie;24;; +Dataset innexistant, habitat valide mais pas le parent;DATASET_NOT_FOUND(unique_dataset_id), INCOHERENT_DATA;ERRONEOUS_PARENT_ENTITY;;bdc3346d-0fc3-40fa-b787-be927e4dd82e;@DATASET_NOT_FOUND@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;2ff4867d-6943-45d8-873d-187fbc6d67a7;prairie;24;; +Dataset interdit, habitat valide mais pas le parent;DATASET_NOT_AUTHORIZED(unique_dataset_id);ERRONEOUS_PARENT_ENTITY;;f5f031a3-cf1b-419c-9817-69c39f51aef4;@FORBIDDEN_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;5dfb9930-4795-4e6f-baae-3dd86abb3b70;prairie;24;; +Dataset UUID invalide;INVALID_UUID(unique_dataset_id);Pas d’habitat;;;erroneous;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;;;;;; +Champs géométrique manquant;NO-GEOM(Champs géométriques);Pas d’habitat;;;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;;;;;;; +Champs requis manquant;MISSING_VALUE(date_min);ERRONEOUS_PARENT_ENTITY;;4ee7728d-387d-49c5-b9a3-4162b0987fa5;@VALID_DATASET_UUID@;;;Toto;;@COORD_STATION@;St;aeb10ac4-6d69-4fa6-8df6-14d9304911df;prairie;24;; Habitat mais pas de station référencée;Pas de station;NO_PARENT_ENTITY(id_station);;;;;;Toto;;;;;prairie;24;; Uniquement un uuid station, mais on ne sait pas s’il appartient à une station ou s’il sert à indiquer le parent d’un habitat;ORPHAN_ROW(unique_id_sinp_station);ORPHAN_ROW(unique_id_sinp_station);;258a2478-8a0e-4321-83df-c2313ad3040e;;;;Toto;;;;;;;; Uniquement un id station source, mais on ne sait pas s’il appartient à une station ou s’il sert à indiquer le parent d’un habitat;ORPHAN_ROW(id_station_source);ORPHAN_ROW(id_station_source);Station -1;;;;;Toto;;;;;;;; Uniquement UUID station + id station source, mais on ne sait pas s’ils appartiennent à une station ou s’ils servent à indiquer le parent d’un habitat;ORPHAN_ROW(unique_id_sinp_station, id_station_source);ORPHAN_ROW(unique_id_sinp_station,id_station_source);Station -2;54e54935-982b-4da3-9aaf-e87e49a1fdf1;;;;Toto;;;;;;;; -On importe 2 habitats dans une même nouvelle station dont les données sont répétées. Les lignes contenant la station sont rapproché par UUID.;OK !;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;e5e7a184-3e92-4adb-a721-5bd004b3397f;forêt;24;; -;OK !;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;8f52f122-b9ae-45b3-b947-2c9f7934b823;prairie;24;; -On importe 2 habitats dans une même nouvelle station dont les données sont répétées MAIS AVEC DES DIFFÉRENCES (date). Les lignes contenant la station sont rapproché par UUID.;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;17/11/2023;;Toto;;COORD_STATION;St;d91496e9-d904-45a8-9e18-cb8acbbb6ea6;prairie;24;; -;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;18/11/2023;;Toto;;COORD_STATION;St;;prairie;24;; -On importe 2 habitats dans une même nouvelle station dont les données sont répétées mais avec des différences (date INVALIDE). Les lignes contenant la station sont rapproché par UUID. On vérifie qu’on a pas d’erreur sur la date car les contrôles ne doivent pas être lancé si les données sont incohérentes. En revanche, les contrôles des habitats doivent bien être lancés.;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;17/11/2023;;Toto;;COORD_STATION;St;;prairie;24;; -NO_PARENT_ENTITY(id_station) non levé sur l’habitat en raison de l’implémentation du check qui ignore les lignes erronées. À voir s’il faut le faire évoluer.;INCOHERENT_DATA(unique_id_sinp_station);INVALID_INTEGER(cd_hab);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;date invalide;;Toto;;COORD_STATION;St;;prairie;invalide;; -On importe 2 habitats dans une même nouvelle station dont les données sont répétées. Les lignes contenant la station sont rapproché par id origine.;OK !;OK !;Station 1;;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -;OK !;OK !;Station 1;;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -On importe 2 habitats dans une même nouvelle station dont les données sont répétées MAIS AVEC DES DIFFÉRENCES (date). Les lignes contenant la station sont rapproché par id origine.;INCOHERENT_DATA(id_station_source);NO_PARENT_ENTITY(id_station);Station 2;;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -;INCOHERENT_DATA(id_station_source);NO_PARENT_ENTITY(id_station);Station 2;;;invalide;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -Un UUID station invalide lève une erreur sur la station ET sur l’habitat;INVALID_UUID(unique_id_sinp_station);INVALID_UUID(unique_id_sinp_station),ERRONEOUS_PARENT_ENTITY;;Erroneous 1;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;6c02ef80-2e78-4c2c-b8b5-1c75e2349fc2;prairie;24;; -Un UUID station invalide lève une erreur sur la station uniquement si pas d’habitat;INVALID_UUID(unique_id_sinp_station),MISSING_VALUE(date_min);Pas d’habitat;;Erroneous 2;;;17/11/2024;Toto;;COORD_STATION;;;;;; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées. Les lignes contenant la station sont rapproché par UUID.;OK !;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;e5e7a184-3e92-4adb-a721-5bd004b3397f;forêt;24;; +;OK !;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;8f52f122-b9ae-45b3-b947-2c9f7934b823;prairie;24;; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées MAIS AVEC DES DIFFÉRENCES (date). Les lignes contenant la station sont rapproché par UUID.;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;@VALID_DATASET_UUID@;17/11/2023;;Toto;;@COORD_STATION@;St;d91496e9-d904-45a8-9e18-cb8acbbb6ea6;prairie;24;; +;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;@VALID_DATASET_UUID@;18/11/2023;;Toto;;@COORD_STATION@;St;;prairie;24;; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées mais avec des différences (date INVALIDE). Les lignes contenant la station sont rapproché par UUID. On vérifie qu’on a pas d’erreur sur la date car les contrôles ne doivent pas être lancé si les données sont incohérentes. En revanche, les contrôles des habitats doivent bien être lancés.;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;17/11/2023;;Toto;;@COORD_STATION@;St;;prairie;24;; +NO_PARENT_ENTITY(id_station) non levé sur l’habitat en raison de l’implémentation du check qui ignore les lignes erronées. À voir s’il faut le faire évoluer.;INCOHERENT_DATA(unique_id_sinp_station);INVALID_INTEGER(cd_hab);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;@VALID_DATASET_UUID@;date invalide;;Toto;;@COORD_STATION@;St;;prairie;invalide;; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées. Les lignes contenant la station sont rapproché par id origine.;OK !;OK !;Station 1;;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +;OK !;OK !;Station 1;;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées MAIS AVEC DES DIFFÉRENCES (date). Les lignes contenant la station sont rapproché par id origine.;INCOHERENT_DATA(id_station_source);NO_PARENT_ENTITY(id_station);Station 2;;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +;INCOHERENT_DATA(id_station_source);NO_PARENT_ENTITY(id_station);Station 2;;@VALID_DATASET_UUID@;invalide;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +Un UUID station invalide lève une erreur sur la station ET sur l’habitat;INVALID_UUID(unique_id_sinp_station);INVALID_UUID(unique_id_sinp_station),ERRONEOUS_PARENT_ENTITY;;Erroneous 1;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;6c02ef80-2e78-4c2c-b8b5-1c75e2349fc2;prairie;24;; +Un UUID station invalide lève une erreur sur la station uniquement si pas d’habitat;INVALID_UUID(unique_id_sinp_station),MISSING_VALUE(date_min);Pas d’habitat;;Erroneous 2;@VALID_DATASET_UUID@;;17/11/2024;Toto;;@COORD_STATION@;;;;;; Un UUID station invalide lève une erreur sur l’habitat uniquement si pas de station. Comme pour un précédent test d’incohérence,, NO PARENT_ENTITY n’est pas levé en raison d’un choix d’implémentation qui peut être modifié.;Pas de station;INVALID_UUID(unique_id_sinp_station);;Erroneous 3;;;;Toto;;;;;prairie;24;; -Les UUID ≠ mais les id origine sont identique !;INCOHERENT_DATA [UUID ≠];ERRONEOUS_PARENT_ENTITY;Station 3;dd0d12fc-bb85-4029-9c72-14fd8583f9bb;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -;INCOHERENT_DATA [UUID ≠];ERRONEOUS_PARENT_ENTITY;Station 3;330bb0f5-dc1c-431a-af1a-d70138b8c99d;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -Les UUID sont égaux mais les id origine ≠ !;INCOHERENT_DATA [id_station_source ≠];ERRONEOUS_PARENT_ENTITY;Station 4;a5c37acb-c966-4024-bea6-71ec125b51c8;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -;INCOHERENT_DATA [id_station_source ≠];ERRONEOUS_PARENT_ENTITY;Station 5;a5c37acb-c966-4024-bea6-71ec125b51c8;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -Les id origine sont identique, mais les UUID ne sont pas toujours renseignés.;INCOHERENT_DATA [UUID ≠];ERRONEOUS_PARENT_ENTITY;Station 6;7ed90696-4e74-4ed5-98a4-518eea009a7f;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -;INCOHERENT_DATA [UUID ≠];ERRONEOUS_PARENT_ENTITY;Station 6;;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -Les UUID sont égaux mais les id origine ne sont pas toujours renseignés.;INCOHERENT_DATA [id_station_source ≠];ERRONEOUS_PARENT_ENTITY;Station 7;c4262f95-0b19-422a-848b-8f83c292d27a;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -;INCOHERENT_DATA [id_station_source ≠];ERRONEOUS_PARENT_ENTITY;;c4262f95-0b19-422a-848b-8f83c292d27a;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -Il y a ni UUID, ni id_origine : l’UUID sera généré.;OK !;OK !;;;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; +Les UUID ≠ mais les id origine sont identique !;INCOHERENT_DATA [UUID ≠];ERRONEOUS_PARENT_ENTITY;Station 3;dd0d12fc-bb85-4029-9c72-14fd8583f9bb;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +;INCOHERENT_DATA [UUID ≠];ERRONEOUS_PARENT_ENTITY;Station 3;330bb0f5-dc1c-431a-af1a-d70138b8c99d;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +Les UUID sont égaux mais les id origine ≠ !;INCOHERENT_DATA [id_station_source ≠];ERRONEOUS_PARENT_ENTITY;Station 4;a5c37acb-c966-4024-bea6-71ec125b51c8;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +;INCOHERENT_DATA [id_station_source ≠];ERRONEOUS_PARENT_ENTITY;Station 5;a5c37acb-c966-4024-bea6-71ec125b51c8;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +Les id origine sont identique, mais les UUID ne sont pas toujours renseignés.;INCOHERENT_DATA [UUID ≠];ERRONEOUS_PARENT_ENTITY;Station 6;7ed90696-4e74-4ed5-98a4-518eea009a7f;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +;INCOHERENT_DATA [UUID ≠];ERRONEOUS_PARENT_ENTITY;Station 6;;;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +Les UUID sont égaux mais les id origine ne sont pas toujours renseignés.;INCOHERENT_DATA [id_station_source ≠];ERRONEOUS_PARENT_ENTITY;Station 7;c4262f95-0b19-422a-848b-8f83c292d27a;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +;INCOHERENT_DATA [id_station_source ≠];ERRONEOUS_PARENT_ENTITY;;c4262f95-0b19-422a-848b-8f83c292d27a;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +Il y a ni UUID, ni id_origine : l’UUID sera généré.;OK !;OK !;;;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; Import d’un habitat dans une station existante ailleurs dans le fichier, référencé par UUID.;Pas de station;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;;;;Toto;;;;;prairie;24;; Import d’un habitat dans une station existante ailleurs dans le fichier, référencé par id origine.;Pas de station;OK !;Station 1;;;;;Toto;;;;;prairie;24;; -On importe une station qui existe déjà en base : elle est ignorée;SKIP_EXISTING_UUID;Pas d’habitat;;EXISTING_STATION_UUID;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;;;; -On importe une station qui existe déjà en base et un nouvel habitat, seul l’habitat est importé;SKIP_EXISTING_UUID;OK !;;EXISTING_STATION_UUID;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;; -On importe une station et un habitat existant déjà en base;SKIP_EXISTING_UUID;SKIP_EXISTING_UUID;;EXISTING_STATION_UUID;;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;EXISTING_HABITAT_UUID;prairie;24;; -technique collect vaut « autre » mais pas de précision fournise;OK !;CONDITIONAL_MANDATORY_FIELD_ERROR;;;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;;10 -technique collect vaut « autre » et une précision est bien fournies;OK !;OK !;;;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;moyen précis;10 -L’habitat est crée dans une station que existe en base mais sur laquelle nous n’avons pas les droits;DATASET_NOT_AUTHORIZED(unique_dataset_id);OK ! ;;STRANGER_STATION_UUID;;;;;;;;;prairie;24;moyen précis;10 -jeu de données pas actif;DATASET_NOT_ACTIVE;ERRONEOUS_PARENT_ENTITY;;;INACTIVE_DATASET_UUID;17/11/2023;17/11/2023;Toto;;COORD_STATION;St;;prairie;24;moyen précis;10 +On importe une station qui existe déjà en base : elle est ignorée;SKIP_EXISTING_UUID;Pas d’habitat;;@EXISTING_STATION_UUID@;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;;;; +On importe une station qui existe déjà en base et un nouvel habitat, seul l’habitat est importé;SKIP_EXISTING_UUID;OK !;;@EXISTING_STATION_UUID@;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;; +On importe une station et un habitat existant déjà en base;SKIP_EXISTING_UUID;SKIP_EXISTING_UUID;;@EXISTING_STATION_UUID@;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;@EXISTING_HABITAT_UUID@;prairie;24;; +technique collect vaut « autre » mais pas de précision fournise;OK !;CONDITIONAL_MANDATORY_FIELD_ERROR;;;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;;10 +technique collect vaut « autre » et une précision est bien fournies;OK !;OK !;;;@VALID_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;moyen précis;10 +L’habitat est crée dans une station que existe en base mais sur laquelle nous n’avons pas les droits;DATASET_NOT_AUTHORIZED(unique_dataset_id);OK !;;@STRANGER_STATION_UUID@;;;;;;;;;prairie;24;moyen précis;10 +jeu de données pas actif;DATASET_NOT_ACTIVE;ERRONEOUS_PARENT_ENTITY;;;@INACTIVE_DATASET_UUID@;17/11/2023;17/11/2023;Toto;;@COORD_STATION@;St;;prairie;24;moyen précis;10 diff --git a/backend/geonature/tests/imports/files/synthese/jdd_to_import_file.csv b/backend/geonature/tests/imports/files/synthese/jdd_to_import_file.csv index 396ee835e9..eecbae1f90 100644 --- a/backend/geonature/tests/imports/files/synthese/jdd_to_import_file.csv +++ b/backend/geonature/tests/imports/files/synthese/jdd_to_import_file.csv @@ -1,6 +1,8 @@ error;id_synthese;id_origine;comment_releve;comment_occurrence;date_debut;date_fin;heure_debut;heure_fin;cd_nom;cd_ref;nom_valide;nom_vernaculaire;nom_cite;regne;group1_inpn;group2_inpn;classe;ordre;famille;rang_taxo;nombre_min;nombre_max;alti_min;alti_max;prof_min;prof_max;observateurs;determinateur;communes;geometrie_wkt_4326;x_centroid_4326;y_centroid_4326;nom_lieu;validateur;niveau_validation;date_validation;comment_validation;preuve_numerique_url;preuve_non_numerique;jdd_nom;jdd_uuid;jdd_id;ca_nom;ca_uuid;ca_id;cd_habref;cd_habitat;nom_habitat;precision_geographique;nature_objet_geo;type_regroupement;methode_regroupement;technique_observation;biologique_statut;etat_biologique;biogeographique_statut;naturalite;preuve_existante;niveau_precision_diffusion;stade_vie;sexe;objet_denombrement;type_denombrement;niveau_sensibilite;statut_observation;statut_source;type_info_geo;methode_determination;comportement;reference_biblio;uuid_perm_sinp;uuid_perm_grp_sinp;date_creation;date_modification;unique_dataset_id -valid;1;1;Relevé n°1;Occurrence n°1;2017-01-01;2017-01-01;12:05:02;12:05:02;60612;60612;Lynx lynx (Linnaeus, 1758);;Lynx Boréal;Animalia;Chordés;Mammifères;Mammalia;Carnivora;Felidae;ES;5;5;1500;1565;;;Administrateur test;Gil;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poil;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Adulte;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;b4f85a2e-dd88-4cdd-aa86-f1c7370faf3f;5b427c76-bd8c-4103-a33c-884c7037aa2b;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497;VALID_DATASET_UUID -valid;2;2;Relevé n°2;Occurrence n°2;2017-01-01;2017-01-02;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1500;1565;;;Administrateur test;Théo;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Immature;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;830c93c7-288e-40f0-a17f-15fbb50e643a;5b427c76-bd8c-4103-a33c-884c7037aa2b;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497; -DATASET_NOT_AUTHORIZED(unique_dataset_id);3;3;Relevé n°3;Occurrence n°3;2017-01-08;;;;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e3;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497;FORBIDDEN_DATASET_UUID -INVALID_UUID(unique_dataset_id);6;6;Relevé n°6;Occurrence n°6;2017-01-01;2017-01-01;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;f5515e2a-b30d-11eb-8cc8-af8c2d0867b4;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497;050d613c-543f-47fd-800a-13931b2721c7 -CONDITIONAL_MANDATORY_FIELD_ERROR(id_nomenclature_blurring);7;7;Relevé n°7;Occurrence n°7;2017-01-01;2017-01-01;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;;;;;;;;;;;;;;;;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;;;;;;050d613c-543f-47fd-800a-13931b2721c7;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497;PRIVATE_DATASET_UUID +valid;1;1;Relevé n°1;Occurrence n°1;2017-01-01;2017-01-01;12:05:02;12:05:02;60612;60612;Lynx lynx (Linnaeus, 1758);;Lynx Boréal;Animalia;Chordés;Mammifères;Mammalia;Carnivora;Felidae;ES;5;5;1500;1565;;;Administrateur test;Gil;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poil;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Adulte;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497;@USER_DATASET_UUID@ +valid;2;2;Relevé n°2;Occurrence n°2;2017-01-01;2017-01-02;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1500;1565;;;Administrateur test;Théo;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Immature;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497; +INVALID_UUID(unique_dataset_id);3;3;Relevé n°3;Occurrence n°3;2017-01-01;2017-01-01;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497;this-is-not-a-valid-uuid +DATASET_NOT_FOUND(unique_dataset_id;4;4;Relevé n°4;Occurrence n°4;2017-01-01;2017-01-02;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1500;1565;;;Administrateur test;Théo;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Immature;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497;@DATASET_NOT_FOUND@ +DATASET_INACTIVE(unique_dataset_id);5;5;Relevé n°3;Occurrence n°3;2017-01-01;2017-01-01;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497;@DATASET_INACTIVE@ +DATASET_NOT_AUTHORIZED(unique_dataset_id);6;6;Relevé n°5;Occurrence n°5;2017-01-08;;;;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497;@DATASET_NOT_AUTHORIZED@ +DATASET_PRIVATE(unique_dataset_id);7;7;Relevé n°7;Occurrence n°7;2017-01-08;;;;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497;@PRIVATE_DATASET_UUID@ diff --git a/backend/geonature/tests/imports/fixtures.py b/backend/geonature/tests/imports/fixtures.py index a28ebe84d5..3e3d7f6f22 100644 --- a/backend/geonature/tests/imports/fixtures.py +++ b/backend/geonature/tests/imports/fixtures.py @@ -1,11 +1,28 @@ import pytest from flask import g import sqlalchemy as sa +from pathlib import Path from geonature.core.gn_commons.models import TModules from geonature.utils.env import db -from geonature.core.imports.models import BibFields, Destination +from geonature.core.imports.models import BibFields, Destination, FieldMapping + +tests_path = Path(__file__).parent + +# ###################################################################################### +# Fixtures -- destination +# ###################################################################################### + + +@pytest.fixture(scope="class") +def module_code(): # provide with a default value - should bve overriden + return "SYNTHESE" + + +@pytest.fixture(scope="class") +def testfiles_folder(): # provide with a default value - should bve overriden + return "synthese" @pytest.fixture(scope="session") @@ -24,16 +41,16 @@ def set_default_destination(endpoint, values): values["destination"] = g.default_destination.code -@pytest.fixture(scope="session") -def synthese_destination(): +@pytest.fixture(scope="class") +def import_destination(module_code): return Destination.query.filter( - Destination.module.has(TModules.module_code == "SYNTHESE") + Destination.module.has(TModules.module_code == module_code) ).one() @pytest.fixture(scope="class") -def default_synthese_destination(app, default_destination, synthese_destination): - g.default_destination = synthese_destination +def default_import_destination(app, default_destination, import_destination): + g.default_destination = import_destination yield del g.default_destination @@ -65,13 +82,431 @@ def all_modules_destination(list_all_module_dest_code): return dict_modules_dest +# ###################################################################################### +# Fixtures -- datasets +# ###################################################################################### + +from geonature.tests.utils import set_logged_user, unset_logged_user +from flask import g, url_for +from geonature.core.gn_meta.models import TDatasets, TAcquisitionFramework +from pypnnomenclature.models import TNomenclatures, BibNomenclaturesTypes +from geonature.core.imports.models import ( + TImports, + BibFields, +) + + +@pytest.fixture() +def import_file_name(): + return "valid_file.csv" + + +@pytest.fixture() +def import_dataset(import_datasets): + return import_datasets["user"] + + +def create_dataset(client, module_code, user, active=True, private=False): + """ """ + set_logged_user(client, user) + + # Generate acquisition framework + r_af = client.post( + url_for("gn_meta.create_acquisition_framework"), + json={ + "acquisition_framework_name": "import_AF", + "acquisition_framework_desc": "import_AF description", + }, + ) + assert r_af.status_code == 200, r_af.data + new_acquisition_framework = db.session.get( + TAcquisitionFramework, r_af.get_json()["id_acquisition_framework"] + ) + + # Get module + r_module = client.get(url_for("gn_commons.get_module", module_code=module_code)) + assert r_module.status_code == 200 + + modules = [ + r_module.get_json(), + ] + + # Get principal actor + id_principal_actor_role = db.session.execute( + sa.select(TNomenclatures.id_nomenclature) + .join(BibNomenclaturesTypes, BibNomenclaturesTypes.mnemonique == "ROLE_ACTEUR") + .where( + TNomenclatures.mnemonique == "Contact principal", + ) + ).scalar_one() + cor_dataset_actor = [ + { + "id_nomenclature_actor_role": id_principal_actor_role, + "id_role": user.id_role, + } + ] + + # Get default data origin + id_nomenclature_data_origin = None + if private: + id_nomenclature_data_origin = db.session.execute( + sa.select(TNomenclatures.id_nomenclature).where( + TNomenclatures.nomenclature_type.has( + BibNomenclaturesTypes.mnemonique == "DS_PUBLIQUE" + ), + TNomenclatures.mnemonique == "Privée", + ) + ).scalar_one() + + # Get territory metropole + territory_metropole = db.session.execute( + sa.select(TNomenclatures).where( + TNomenclatures.nomenclature_type.has(BibNomenclaturesTypes.mnemonique == "TERRITOIRE"), + TNomenclatures.cd_nomenclature == "METROP", + ) + ).scalar_one() + + json = { + "id_acquisition_framework": new_acquisition_framework.id_acquisition_framework, + "dataset_name": "import_dataset", + "dataset_shortname": "import_dataset", + "dataset_desc": "import_dataset description", + "keywords": None, + "terrestrial_domain": True, + "marine_domain": False, + "id_nomenclature_data_origin": id_nomenclature_data_origin, + "validable": True, + "active": active, + "id_taxa_list": None, + "modules": modules, + "cor_territories": [territory_metropole.as_dict()], + "cor_dataset_actor": cor_dataset_actor, + } + + response = client.post( + url_for("gn_meta.create_dataset"), + json=json, + ) + + return db.session.get(TDatasets, response.get_json()["id_dataset"]) + + +@pytest.fixture() +def import_datasets(client, module_code, users): + datasets = { + "user": create_dataset(client, module_code, users["user"]), + "user--private": create_dataset(client, module_code, users["user"], private=True), + "user--inactive": create_dataset(client, module_code, users["user"], active=False), + "admin": create_dataset(client, module_code, users["admin_user"]), + } + return datasets + + +# ###################################################################################### +# Fixtures -- fieldmapping +# ###################################################################################### + + @pytest.fixture() -def display_unique_dataset_id(): +def fieldmapping_unique_dataset_id(import_dataset): + None + + +@pytest.fixture(scope="class") +def fieldmapping_preset_name(): + return "Synthese GeoNature" + + +@pytest.fixture() +def fieldmapping( + import_file_name, + autogenerate, + import_dataset, + fieldmapping_unique_dataset_id, + fieldmapping_preset_name, +): + fieldmapping = {} + if fieldmapping_preset_name: + fieldmapping = ( + db.session.execute( + sa.select(FieldMapping).filter_by( + label=fieldmapping_preset_name, + ) + ) + .unique() + .scalar_one() + .values + ) + else: + bib_fields = db.session.scalars(sa.select(BibFields).filter_by(display=True)).unique().all() + fieldmapping = { + field.name_field: { + "column_src": ( + autogenerate + if field.autogenerated + else ( + [field.name_field, "additional_data2"] if field.multi else field.name_field + ) + ) + } + for field in bib_fields + } + + if fieldmapping_unique_dataset_id: + fieldmapping["unique_dataset_id"] = fieldmapping_unique_dataset_id + + return fieldmapping + + +# ###################################################################################### +# Fixtures -- contentmapping +# ###################################################################################### +from sqlalchemy.orm import joinedload + + +@pytest.fixture(scope="class") +def contentmapping_preset_name(): + return "Nomenclatures SINP (labels)" + + +@pytest.fixture(scope="function") +def add_in_contentmapping(): + return {"STADE_VIE": {"": "17"}} # Alevin + + +@pytest.fixture(scope="function") +def contentmapping(add_in_contentmapping, import_destination, contentmapping_preset_name): + contentmapping = {} + if contentmapping_preset_name is not None: + contentmapping = ( + db.session.scalars( + sa.select(ContentMapping).filter_by(label=contentmapping_preset_name) + ) + .unique() + .one() + .values + ) + else: + fields = ( + db.session.scalars( + sa.select(BibFields) + .filter_by(destination=import_destination, display=True) + .filter(BibFields.nomenclature_type != None) + .options( + joinedload(BibFields.nomenclature_type).joinedload( + BibNomenclaturesTypes.nomenclatures + ), + ) + ) + .unique() + .all() + ) + contentmapping = { + field.nomenclature_type.mnemonique: { + **{ + nomenclature.mnemonique: nomenclature.cd_nomenclature + for nomenclature in field.nomenclature_type.nomenclatures + }, + **{ + nomenclature.cd_nomenclature: nomenclature.cd_nomenclature + for nomenclature in field.nomenclature_type.nomenclatures + }, + } + for field in fields + } + + for entry, value in add_in_contentmapping.items(): + if contentmapping[entry]: + contentmapping[entry].update(value) + + return contentmapping + + +# ###################################################################################### +# Fixtures -- override config value +# ###################################################################################### +from apptax.taxonomie.models import BibListes, Taxref + + +@pytest.fixture() +def small_batch(monkeypatch): + monkeypatch.setitem(current_app.config["IMPORT"], "DATAFRAME_BATCH_SIZE", 10) + + +@pytest.fixture +def check_private_jdd(monkeypatch): + monkeypatch.setitem(current_app.config["IMPORT"], "CHECK_PRIVATE_JDD_BLURING", True) + + +@pytest.fixture() +def no_default_nomenclatures(monkeypatch): + monkeypatch.setitem( + current_app.config["IMPORT"], "FILL_MISSING_NOMENCLATURE_WITH_DEFAULT_VALUE", False + ) + + +@pytest.fixture() +def area_restriction(monkeypatch, sample_area): + monkeypatch.setitem(current_app.config["IMPORT"], "ID_AREA_RESTRICTION", sample_area.id_area) + + +@pytest.fixture(scope="function") +def g_permissions(): """ - This fixture is temporary and must be removed when the UUID of a JDD can be mapped in the - fieldmapping step ! + Fixture to initialize flask g variable + Mandatory if we want to run this test file standalone """ - query = ( - sa.update(BibFields).where(BibFields.name_field == "unique_dataset_id").values(display=True) + g._permissions_by_user = {} + g._permissions = {} + + +@pytest.fixture() +def sample_taxhub_list(): + nom = Taxref.query.filter_by(cd_nom=67111).one() + with db.session.begin_nested(): + taxa_list = BibListes(nom_liste="test", code_liste="test", noms=[nom]) + db.session.add(taxa_list) + return taxa_list + + +@pytest.fixture() +def change_id_list_conf(monkeypatch, sample_taxhub_list): + monkeypatch.setitem( + current_app.config["IMPORT"], "ID_LIST_TAXA_RESTRICTION", sample_taxhub_list.id_liste ) - db.session.execute(query) + + +# ###################################################################################### +# Fixtures -- immport +# ###################################################################################### + + +from flask import g, url_for, current_app +from werkzeug.datastructures import Headers +from geonature.core.imports.utils import insert_import_data_in_transient_table +from geonature.core.imports.models import ( + TImports, + FieldMapping, + ContentMapping, + BibFields, +) +from ref_geo.models import LAreas + + +@pytest.fixture() +def sample_area(): + return LAreas.query.filter(LAreas.area_name == "Bouches-du-Rhône").one() + + +@pytest.fixture() +def autogenerate(): + return True + + +@pytest.fixture(scope="function") +def override_in_importfile(): + return {} + + +@pytest.fixture(scope="class") +def imports(import_destination, users): + def create_import(authors=[]): + with db.session.begin_nested(): + imprt = TImports(destination=import_destination, authors=authors) + db.session.add(imprt) + return imprt + + return { + "own_import": create_import(authors=[users["user"]]), + "associate_import": create_import(authors=[users["associate_user"]]), + "stranger_import": create_import(authors=[users["stranger_user"]]), + "orphan_import": create_import(), + } + + +@pytest.fixture() +def uploaded_import(client, import_file_name, override_in_importfile, users, testfiles_folder): + set_logged_user(client, users["user"]) + + with open(tests_path / "files" / testfiles_folder / import_file_name, "rb") as f: + f.seek(0) + data = {"file": (f, import_file_name)} + r = client.post( + url_for("import.upload_file"), + data=data, + headers=Headers({"Content-Type": "multipart/form-data"}), + ) + assert r.status_code == 200, r.data + imprt = db.session.get(TImports, r.get_json()["id_import"]) + + for before, after in override_in_importfile.items(): + imprt.source_file = imprt.source_file.replace( + before.encode("ascii"), + after.encode("ascii"), + ) + return imprt + + +@pytest.fixture() +def decoded_import(client, uploaded_import): + set_logged_user(client, uploaded_import.authors[0]) + r = client.post( + url_for( + "import.decode_file", + import_id=uploaded_import.id_import, + ), + data={ + "encoding": "utf-8", + "format": "csv", + "srid": 4326, + "separator": ";", + }, + ) + assert r.status_code == 200, r.data + unset_logged_user(client) + db.session.refresh(uploaded_import) + return uploaded_import + + +@pytest.fixture() +def field_mapped_import(client, decoded_import, fieldmapping): + with db.session.begin_nested(): + decoded_import.fieldmapping = fieldmapping + return decoded_import + + +@pytest.fixture() +def loaded_import(client, field_mapped_import): + with db.session.begin_nested(): + field_mapped_import.source_count = insert_import_data_in_transient_table( + field_mapped_import + ) + field_mapped_import.loaded = True + return field_mapped_import + + +@pytest.fixture() +def content_mapped_import(loaded_import, contentmapping): + loaded_import.contentmapping = contentmapping + db.session.flush() + return loaded_import + + +@pytest.fixture() +def prepared_import(client, content_mapped_import, small_batch, check_private_jdd): + set_logged_user(client, content_mapped_import.authors[0]) + r = client.post(url_for("import.prepare_import", import_id=content_mapped_import.id_import)) + assert r.status_code == 200, r.data + unset_logged_user(client) + db.session.refresh(content_mapped_import) + return content_mapped_import + + +@pytest.fixture() +def imported_import(client, g_permissions, prepared_import): + set_logged_user(client, prepared_import.authors[0]) + r = client.post(url_for("import.import_valid_data", import_id=prepared_import.id_import)) + assert r.status_code == 200, r.data + unset_logged_user(client) + db.session.refresh(prepared_import) + return prepared_import diff --git a/backend/geonature/tests/imports/jsonschema_definitions.py b/backend/geonature/tests/imports/jsonschema_definitions.py index edf268dff0..e453525bff 100644 --- a/backend/geonature/tests/imports/jsonschema_definitions.py +++ b/backend/geonature/tests/imports/jsonschema_definitions.py @@ -209,7 +209,6 @@ "detected_encoding": {"type": ["string", "null"]}, # "import_table": {"type": ["string", "null"]}, "full_file_name": {"type": ["string", "null"]}, - "id_dataset": {"type": ["integer", "null"]}, "date_create_import": {"type": "string"}, "date_update_import": {"type": "string"}, "source_count": {"type": ["integer", "null"]}, @@ -245,7 +244,6 @@ "detected_encoding", # "import_table", "full_file_name", - "id_dataset", "date_create_import", "date_update_import", "source_count", diff --git a/backend/geonature/tests/imports/test_fields.py b/backend/geonature/tests/imports/test_fields.py index 76ae983dc5..4096d17b1a 100644 --- a/backend/geonature/tests/imports/test_fields.py +++ b/backend/geonature/tests/imports/test_fields.py @@ -14,14 +14,14 @@ from .jsonschema_definitions import jsonschema_definitions -@pytest.fixture() -def dest(): - return Destination.query.filter( - Destination.module.has(TModules.module_code == "SYNTHESE") - ).one() +@pytest.fixture(scope="class") +def module_code(): + return "SYNTHESE" -@pytest.mark.usefixtures("client_class", "temporary_transaction", "default_synthese_destination") +@pytest.mark.usefixtures( + "client_class", "temporary_transaction", "default_import_destination", "module_code" +) class TestFields: def test_fields(self, users): assert self.client.get(url_for("import.get_fields")).status_code == Unauthorized.code diff --git a/backend/geonature/tests/imports/test_imports_occhab.py b/backend/geonature/tests/imports/test_imports_occhab.py index 4865cde719..16c08db7fb 100644 --- a/backend/geonature/tests/imports/test_imports_occhab.py +++ b/backend/geonature/tests/imports/test_imports_occhab.py @@ -26,6 +26,7 @@ from geonature.core.imports.models import Destination, TImports, BibFields from geonature.tests.imports.utils import assert_import_errors +from geonature.tests.utils import set_logged_user, unset_logged_user occhab = pytest.importorskip("gn_module_occhab") @@ -33,199 +34,69 @@ from gn_module_occhab.models import Station, OccurenceHabitat -test_files_path = Path(__file__).parent / "files" / "occhab" +# ###################################################################################### +# Fixtures -- override default values +# ###################################################################################### -@pytest.fixture(scope="session") -def occhab_destination(): - return Destination.query.filter(Destination.module.has(TModules.module_code == "OCCHAB")).one() +@pytest.fixture(scope="class") +def testfiles_folder(): # provide with a default value - should bve overriden + return "occhab" @pytest.fixture(scope="class") -def default_occhab_destination(app, default_destination, occhab_destination): - """ - This fixture set "occhab" as default destination when not specified in call to url_for. - """ - g.default_destination = occhab_destination - yield - del g.default_destination +def module_code(): + return "OCCHAB" -@pytest.fixture() -def fieldmapping(occhab_destination): - fields = ( - db.session.scalars( - sa.select(BibFields).filter_by(destination=occhab_destination, display=True) - ) - .unique() - .all() - ) - return {field.name_field: {"column_src": field.name_field} for field in fields} +@pytest.fixture(scope="class") +def fieldmapping_preset_name(): + return "" @pytest.fixture() -def contentmapping(occhab_destination): - """ - This content mapping matches cd_nomenclature AND mnemonique. - """ - fields = ( - db.session.scalars( - sa.select(BibFields) - .filter_by(destination=occhab_destination, display=True) - .filter(BibFields.nomenclature_type != None) - .options( - joinedload(BibFields.nomenclature_type).joinedload( - BibNomenclaturesTypes.nomenclatures - ), - ) - ) - .unique() - .all() - ) - return { - field.nomenclature_type.mnemonique: { - **{ - nomenclature.mnemonique: nomenclature.cd_nomenclature - for nomenclature in field.nomenclature_type.nomenclatures - }, - **{ - nomenclature.cd_nomenclature: nomenclature.cd_nomenclature - for nomenclature in field.nomenclature_type.nomenclatures - }, - } - for field in fields - } +def autogenerate(): + return False -@pytest.fixture() -def uploaded_import( - client, - users, - datasets, +@pytest.fixture(scope="function") +def override_in_importfile( + import_datasets, station, station_stranger_dataset, - habitat, - import_file_name, - display_unique_dataset_id, coord_station_test_file, + habitat, ): - with open(test_files_path / import_file_name, "rb") as f: - test_file_line_count = sum(1 for line in f) - 1 # remove headers - f.seek(0) - content = f.read() - content = content.replace( - b"EXISTING_STATION_UUID", - station.unique_id_sinp_station.hex.encode("ascii"), - ) - content = content.replace( - b"STRANGER_STATION_UUID", - station_stranger_dataset.unique_id_sinp_station.hex.encode("ascii"), - ) - content = content.replace( - b"EXISTING_HABITAT_UUID", - habitat.unique_id_sinp_hab.hex.encode("ascii"), - ) - content = content.replace( - b"VALID_DATASET_UUID", - datasets["own_dataset"].unique_dataset_id.hex.encode("ascii"), - ) - content = content.replace( - b"FORBIDDEN_DATASET_UUID", - datasets["orphan_dataset"].unique_dataset_id.hex.encode("ascii"), - ) - content = content.replace( - b"INACTIVE_DATASET_UUID", - datasets["own_dataset_not_activated"].unique_dataset_id.hex.encode("ascii"), - ) - content = content.replace( - b"COORD_STATION", - to_wkt(coord_station_test_file[0]).encode("ascii"), - ) - - f = BytesIO(content) - data = { - "file": (f, import_file_name), - "datasetId": datasets["own_dataset"].id_dataset, - } - with logged_user(client, users["user"]): - r = client.post( - url_for("import.upload_file"), - data=data, - headers=Headers({"Content-Type": "multipart/form-data"}), - ) - assert r.status_code == 200, r.data - return TImports.query.get(r.json["id_import"]) - - -@pytest.fixture() -def decoded_import(client, uploaded_import): - imprt = uploaded_import - with logged_user(client, imprt.authors[0]): - r = client.post( - url_for("import.decode_file", import_id=imprt.id_import), - data={"encoding": "utf-8", "format": "csv", "srid": 4326, "separator": ";"}, - ) - assert r.status_code == 200, r.data - db.session.refresh(imprt) - return imprt - - -@pytest.fixture() -def field_mapped_import(client, decoded_import, fieldmapping): - imprt = decoded_import - with logged_user(client, imprt.authors[0]): - r = client.post( - url_for("import.set_import_field_mapping", import_id=imprt.id_import), - data=fieldmapping, - ) - assert r.status_code == 200, r.data - db.session.refresh(imprt) - return imprt + return { + "@EXISTING_STATION_UUID@": str(station.unique_id_sinp_station), + "@STRANGER_STATION_UUID@": str(station_stranger_dataset.unique_id_sinp_station), + "@EXISTING_HABITAT_UUID@": str(habitat.unique_id_sinp_hab), + "@VALID_DATASET_UUID@": str(import_datasets["user"].unique_dataset_id), + "@FORBIDDEN_DATASET_UUID@": str(import_datasets["admin"].unique_dataset_id), + "@INACTIVE_DATASET_UUID@": str(import_datasets["user--inactive"].unique_dataset_id), + "@DATASET_NOT_FOUND@": "03905a03-c7fa-4642-b143-5005fa805377", + "@COORD_STATION@": to_wkt(coord_station_test_file[0]), + } -@pytest.fixture() -def loaded_import(client, field_mapped_import, fieldmapping): - imprt = field_mapped_import - with logged_user(client, imprt.authors[0]): - r = client.post(url_for("import.load_import", import_id=imprt.id_import)) - assert r.status_code == 200, r.data - db.session.refresh(imprt) - return imprt +@pytest.fixture(scope="class") +def contentmapping_preset_name(): + return None -@pytest.fixture() -def content_mapped_import(client, loaded_import, contentmapping): - imprt = loaded_import - with logged_user(client, imprt.authors[0]): - r = client.post( - url_for("import.set_import_content_mapping", import_id=imprt.id_import), - data=contentmapping, - ) - assert r.status_code == 200, r.data - db.session.refresh(imprt) - return imprt +@pytest.fixture(scope="function") +def add_in_contentmapping(): + return {} @pytest.fixture() -def prepared_import(client, content_mapped_import): - imprt = content_mapped_import - with logged_user(client, imprt.authors[0]): - r = client.post(url_for("import.prepare_import", import_id=imprt.id_import)) - assert r.status_code == 200, r.data - db.session.refresh(imprt) - assert imprt.processed is True - return imprt +def no_default_uuid(monkeypatch): + monkeypatch.setitem(current_app.config["IMPORT"], "DEFAULT_GENERATE_MISSING_UUID", False) -@pytest.fixture() -def imported_import(client, prepared_import): - imprt = prepared_import - - with logged_user(client, imprt.authors[0]): - r = client.post(url_for("import.import_valid_data", import_id=imprt.id_import)) - assert r.status_code == 200, r.data - db.session.refresh(imprt) - return imprt +# ###################################################################################### +# Fixtures -- station +# ###################################################################################### @pytest.fixture(scope="function") @@ -239,9 +110,9 @@ def coord_station(): @pytest.fixture(scope="function") -def station(datasets, coord_station): +def station(import_datasets, coord_station): station = Station( - id_dataset=datasets["own_dataset"].id_dataset, + id_dataset=import_datasets["user"].id_dataset, date_min=datetime.strptime("17/11/2023", "%d/%m/%Y"), geom_4326=from_shape(*coord_station), ) @@ -251,9 +122,9 @@ def station(datasets, coord_station): @pytest.fixture(scope="function") -def station_stranger_dataset(datasets, coord_station): +def station_stranger_dataset(import_datasets, coord_station): station = Station( - id_dataset=datasets["stranger_dataset"].id_dataset, + id_dataset=import_datasets["admin"].id_dataset, date_min=datetime.strptime("17/11/2023", "%d/%m/%Y"), geom_4326=from_shape(*coord_station), ) @@ -262,6 +133,11 @@ def station_stranger_dataset(datasets, coord_station): return station +# ###################################################################################### +# Fixtures -- habitat +# ###################################################################################### + + @pytest.fixture(scope="function") def habitat(station): habitat = OccurenceHabitat( @@ -277,21 +153,25 @@ def habitat(station): return habitat -@pytest.fixture() -def no_default_uuid(monkeypatch): - monkeypatch.setitem(current_app.config["IMPORT"], "DEFAULT_GENERATE_MISSING_UUID", False) +# ###################################################################################### +# TestImportsOcchab +# ###################################################################################### @pytest.mark.usefixtures( "client_class", "temporary_transaction", "celery_eager", - "default_occhab_destination", + "import_destination", + "default_import_destination", + "module_code", + "fieldmapping_preset_name", + "testfiles_folder", + "contentmapping_preset_name", ) class TestImportsOcchab: - @pytest.mark.parametrize("import_file_name", ["valid_file.csv"]) - def test_import_valid_file(self, imported_import): + def test_import_valid_file(self, datasets, imported_import): assert_import_errors( imported_import, { @@ -562,7 +442,6 @@ def test_import_without_default_uuid(self, no_default_uuid, imported_import): == imported_import.statistics["habitat_count"] ) - @pytest.mark.parametrize("import_file_name", ["valid_file.csv"]) def test_remove_import_with_manual_children(self, client, users, imported_import): """ This test verifies that it is not possible to remove an import if an imported entity @@ -586,7 +465,6 @@ def test_remove_import_with_manual_children(self, client, users, imported_import assert str(station.id_station) in r.json["description"] assert str(habitat.id_habitat) in r.json["description"] - @pytest.mark.parametrize("import_file_name", ["valid_file.csv"]) def test_bbox_computation( self, imported_import, @@ -610,7 +488,6 @@ def test_bbox_computation( ], } - @pytest.mark.parametrize("import_file_name", ["valid_file.csv"]) def test_bbox_computation_transient( self, prepared_import, diff --git a/backend/geonature/tests/imports/test_imports_synthese.py b/backend/geonature/tests/imports/test_imports_synthese.py index b7308bd313..fd986c9093 100644 --- a/backend/geonature/tests/imports/test_imports_synthese.py +++ b/backend/geonature/tests/imports/test_imports_synthese.py @@ -23,7 +23,7 @@ ) from geonature.core.gn_permissions.models import PermAction, Permission, PermObject from geonature.core.gn_commons.models import TModules -from geonature.core.gn_meta.models import TDatasets +from geonature.core.gn_meta.models import TDatasets, TAcquisitionFramework from geonature.core.gn_synthese.models import Synthese from geonature.tests.fixtures import synthese_data, celery_eager @@ -34,16 +34,12 @@ from geonature.core.imports.models import ( TImports, - FieldMapping, ContentMapping, - BibFields, ) -from geonature.core.imports.utils import insert_import_data_in_transient_table from .jsonschema_definitions import jsonschema_definitions from .utils import assert_import_errors as _assert_import_errors - tests_path = Path(__file__).parent valid_file_expected_errors = { @@ -60,249 +56,68 @@ def assert_import_errors(imprt, expected_errors): return _assert_import_errors(imprt, expected_errors, entity_code="observation") -@pytest.fixture(scope="class") -def g_permissions(): - """ - Fixture to initialize flask g variable - Mandatory if we want to run this test file standalone - """ - g._permissions_by_user = {} - g._permissions = {} - - -@pytest.fixture() -def sample_area(): - return LAreas.query.filter(LAreas.area_name == "Bouches-du-Rhône").one() - - -@pytest.fixture(scope="function") -def imports(synthese_destination, users): - def create_import(authors=[]): - with db.session.begin_nested(): - imprt = TImports(destination=synthese_destination, authors=authors) - db.session.add(imprt) - return imprt - - return { - "own_import": create_import(authors=[users["user"]]), - "associate_import": create_import(authors=[users["associate_user"]]), - "stranger_import": create_import(authors=[users["stranger_user"]]), - "orphan_import": create_import(), - } - - -@pytest.fixture() -def small_batch(monkeypatch): - monkeypatch.setitem(current_app.config["IMPORT"], "DATAFRAME_BATCH_SIZE", 3) - +# ###################################################################################### +# Fixtures -- default values to be overriden +# ###################################################################################### -@pytest.fixture -def check_private_jdd(monkeypatch): - monkeypatch.setitem(current_app.config["IMPORT"], "CHECK_PRIVATE_JDD_BLURING", True) - -@pytest.fixture() -def no_default_nomenclatures(monkeypatch): - monkeypatch.setitem( - current_app.config["IMPORT"], "FILL_MISSING_NOMENCLATURE_WITH_DEFAULT_VALUE", False - ) - - -@pytest.fixture() -def area_restriction(monkeypatch, sample_area): - monkeypatch.setitem(current_app.config["IMPORT"], "ID_AREA_RESTRICTION", sample_area.id_area) - - -@pytest.fixture() -def import_file_name(): - return "valid_file.csv" - - -@pytest.fixture() -def autogenerate(): - return True +@pytest.fixture(scope="class") +def fieldmapping_preset_name(): + return "Synthese GeoNature" -@pytest.fixture() -def import_dataset(datasets, import_file_name): - ds = datasets["own_dataset"] - if import_file_name == "nomenclatures_file.csv": - previous_data_origin = ds.nomenclature_data_origin - ds.nomenclature_data_origin = TNomenclatures.query.filter( - TNomenclatures.nomenclature_type.has(BibNomenclaturesTypes.mnemonique == "DS_PUBLIQUE"), - TNomenclatures.mnemonique == "Privée", - ).one() - yield ds - if import_file_name == "nomenclatures_file.csv": - ds.nomenclature_data_origin = previous_data_origin - - -@pytest.fixture() -def new_import(synthese_destination, users, import_dataset): - with db.session.begin_nested(): - imprt = TImports( - destination=synthese_destination, - authors=[users["user"]], - id_dataset=import_dataset.id_dataset, - ) - db.session.add(imprt) - return imprt +@pytest.fixture(scope="class") +def contentmapping_preset_name(): + return "Nomenclatures SINP (labels)" -@pytest.fixture() -def uploaded_import(new_import, datasets, import_file_name): - with db.session.begin_nested(): - with open(tests_path / "files" / "synthese" / import_file_name, "rb") as f: - f.seek(0) - content = f.read() - if import_file_name == "jdd_to_import_file.csv": - content = content.replace( - b"VALID_DATASET_UUID", - datasets["own_dataset"].unique_dataset_id.hex.encode("ascii"), - ) - content = content.replace( - b"FORBIDDEN_DATASET_UUID", - datasets["orphan_dataset"].unique_dataset_id.hex.encode("ascii"), - ) - content = content.replace( - b"PRIVATE_DATASET_UUID", - datasets["private"].unique_dataset_id.hex.encode("ascii"), - ) - new_import.full_file_name = "jdd_to_import_file.csv" - else: - new_import.full_file_name = "valid_file.csv" - new_import.source_file = content - return new_import - - -@pytest.fixture() -def decoded_import(client, uploaded_import): - set_logged_user(client, uploaded_import.authors[0]) - r = client.post( - url_for( - "import.decode_file", - import_id=uploaded_import.id_import, - ), - data={ - "encoding": "utf-8", - "format": "csv", - "srid": 4326, - "separator": ";", - }, - ) - assert r.status_code == 200, r.data - unset_logged_user(client) - db.session.refresh(uploaded_import) - return uploaded_import +@pytest.fixture(scope="class") +def module_code(): + return "SYNTHESE" -@pytest.fixture() -def fieldmapping(import_file_name, autogenerate): - if import_file_name in ["valid_file.csv", "jdd_to_import_file.csv"]: - return ( - db.session.execute(sa.select(FieldMapping).filter_by(label="Synthese GeoNature")) - .unique() - .scalar_one() - .values - ) - else: - bib_fields = db.session.scalars(sa.select(BibFields).filter_by(display=True)).unique().all() - return { - field.name_field: { - "column_src": ( - autogenerate - if field.autogenerated - else ( - [field.name_field, "additional_data2"] if field.multi else field.name_field - ) - ) - } - for field in bib_fields - } +@pytest.fixture(scope="class") +def testfiles_folder(): # provide with a default value - should bve overriden + return "synthese" -@pytest.fixture() -def field_mapped_import(client, decoded_import, fieldmapping): - with db.session.begin_nested(): - decoded_import.fieldmapping = fieldmapping - return decoded_import +@pytest.fixture(scope="function") +def fieldmapping_unique_dataset_id(import_dataset): + return { + "default_value": str(import_dataset.unique_dataset_id), + "column_src": "unique_dataset_id", + } -@pytest.fixture() -def loaded_import(client, field_mapped_import): - with db.session.begin_nested(): - field_mapped_import.source_count = insert_import_data_in_transient_table( - field_mapped_import - ) - field_mapped_import.loaded = True - return field_mapped_import +@pytest.fixture(scope="function") +def override_in_importfile(import_datasets): + return { + "@USER_DATASET_UUID@": str(import_datasets["user"].unique_dataset_id), + "@DATASET_NOT_FOUND@": "03905a03-c7fa-4642-b143-5005fa805377", + "@DATASET_NOT_AUTHORIZED@": str(import_datasets["admin"].unique_dataset_id), + "@DATASET_INACTIVE@": str(import_datasets["user--inactive"].unique_dataset_id), + "@PRIVATE_DATASET_UUID@": str(import_datasets["user--private"].unique_dataset_id), + } -@pytest.fixture() -def content_mapped_import(client, import_file_name, loaded_import): - with db.session.begin_nested(): - loaded_import.contentmapping = ( - db.session.scalars( - sa.select(ContentMapping).filter_by(label="Nomenclatures SINP (labels)") - ) - .unique() - .one() - .values - ) - if import_file_name == "empty_nomenclatures_file.csv": - loaded_import.contentmapping["STADE_VIE"].update( - { - "": "17", # Alevin - } - ) - return loaded_import - - -@pytest.fixture() -def prepared_import(client, content_mapped_import, small_batch, check_private_jdd): - set_logged_user(client, content_mapped_import.authors[0]) - r = client.post(url_for("import.prepare_import", import_id=content_mapped_import.id_import)) - assert r.status_code == 200, r.data - unset_logged_user(client) - db.session.refresh(content_mapped_import) - return content_mapped_import - - -@pytest.fixture() -def imported_import(client, prepared_import): - set_logged_user(client, prepared_import.authors[0]) - r = client.post(url_for("import.import_valid_data", import_id=prepared_import.id_import)) - assert r.status_code == 200, r.data - unset_logged_user(client) - db.session.refresh(prepared_import) - return prepared_import - - -@pytest.fixture() -def sample_taxhub_list(): - nom = Taxref.query.filter_by(cd_nom=67111).one() - with db.session.begin_nested(): - taxa_list = BibListes(nom_liste="test", code_liste="test", noms=[nom]) - db.session.add(taxa_list) - return taxa_list - - -@pytest.fixture() -def change_id_list_conf(monkeypatch, sample_taxhub_list): - monkeypatch.setitem( - current_app.config["IMPORT"], "ID_LIST_TAXA_RESTRICTION", sample_taxhub_list.id_liste - ) +# ###################################################################################### +# Tests -- imports +# ###################################################################################### @pytest.mark.usefixtures( "client_class", "temporary_transaction", "celery_eager", - "default_synthese_destination", - "display_unique_dataset_id", + "import_destination", + "default_import_destination", + "module_code", + "fieldmapping_preset_name", + "testfiles_folder", + "contentmapping_preset_name", ) class TestImportsSynthese: - def test_import_permissions(self, g_permissions, synthese_destination): + def test_import_permissions(self, g_permissions, import_destination): with db.session.begin_nested(): organisme = Organisme(nom_organisme="test_import") db.session.add(organisme) @@ -319,7 +134,7 @@ def test_import_permissions(self, g_permissions, synthese_destination): user.groups.append(group) - imprt = TImports(destination=synthese_destination) + imprt = TImports(destination=import_destination) db.session.add(imprt) get_scopes_by_action = partial( @@ -416,7 +231,7 @@ def test_import_permissions(self, g_permissions, synthese_destination): assert scope == 3 assert imprt.has_instance_permission(scope, user=user, action_code="U") is True - # Should be always true + # Should be always True assert imprt.has_instance_permission(scope, user=user, action_code="R") is True def test_list_imports(self, imports, users): @@ -460,16 +275,6 @@ def test_order_import(self, users, imports, uploaded_import): import_ids_asc = [imprt["id_import"] for imprt in r_asc.get_json()["imports"]] assert import_ids_des == import_ids_asc[-1::-1] - def test_order_import_foreign(self, users, imports, uploaded_import): - set_logged_user(self.client, users["user"]) - response = self.client.get(url_for("import.get_import_list") + "?sort=dataset.dataset_name") - assert response.status_code == 200, response.data - imports = response.get_json()["imports"] - for a, b in zip(imports[:1], imports[1:]): - assert (a["dataset"] is None) or ( - a["dataset"]["dataset_name"] <= b["dataset"]["dataset_name"] - ) - def test_get_import(self, users, imports): def get(import_name): return self.client.get( @@ -511,11 +316,11 @@ def test_delete_import(self, users, imported_import): ) assert transient_rows_count == 0 - def test_import_upload(self, users, datasets): + def test_import_upload(self, users): + with open(tests_path / "files" / "synthese" / "simple_file.csv", "rb") as f: data = { "file": (f, "simple_file.csv"), - "datasetId": datasets["own_dataset"].id_dataset, } r = self.client.post( url_for("import.upload_file"), @@ -528,7 +333,6 @@ def test_import_upload(self, users, datasets): with open(tests_path / "files" / "synthese" / "simple_file.csv", "rb") as f: data = { "file": (f, "simple_file.csv"), - "datasetId": datasets["own_dataset"].id_dataset, } r = self.client.post( url_for("import.upload_file"), @@ -539,39 +343,8 @@ def test_import_upload(self, users, datasets): assert "has no permissions to C in IMPORT" in r.json["description"] set_logged_user(self.client, users["user"]) - - unexisting_id = db.session.query(func.max(TDatasets.id_dataset)).scalar() + 1 - with open(tests_path / "files" / "synthese" / "simple_file.csv", "rb") as f: - data = { - "file": (f, "simple_file.csv"), - "datasetId": unexisting_id, - } - r = self.client.post( - url_for("import.upload_file"), - data=data, - headers=Headers({"Content-Type": "multipart/form-data"}), - ) - assert r.status_code == BadRequest.code, r.data - assert r.json["description"] == f"Dataset '{unexisting_id}' does not exist." - - with open(tests_path / "files" / "synthese" / "simple_file.csv", "rb") as f: - data = { - "file": (f, "simple_file.csv"), - "datasetId": datasets["stranger_dataset"].id_dataset, - } - r = self.client.post( - url_for("import.upload_file"), - data=data, - headers=Headers({"Content-Type": "multipart/form-data"}), - ) - assert r.status_code == Forbidden.code, r.data - assert "jeu de données" in r.json["description"] # this is a DS issue - with open(tests_path / "files" / "synthese" / "simple_file.csv", "rb") as f: - data = { - "file": (f, "simple_file.csv"), - "datasetId": datasets["own_dataset"].id_dataset, - } + data = {"file": (f, "simple_file.csv")} r = self.client.post( url_for("import.upload_file"), data=data, @@ -583,13 +356,10 @@ def test_import_upload(self, users, datasets): assert imprt.source_file is not None assert imprt.full_file_name == "simple_file.csv" - def test_import_error(self, users, datasets): + def test_import_error(self, users, import_datasets): set_logged_user(self.client, users["user"]) with open(tests_path / "files" / "synthese" / "empty.csv", "rb") as f: - data = { - "file": (f, "empty.csv"), - "datasetId": datasets["own_dataset"].id_dataset, - } + data = {"file": (f, "empty.csv")} r = self.client.post( url_for("import.upload_file"), data=data, @@ -597,11 +367,9 @@ def test_import_error(self, users, datasets): ) assert r.status_code == 400, r.data assert r.json["description"] == "Impossible to upload empty files" + with open(tests_path / "files" / "synthese" / "starts_with_empty_line.csv", "rb") as f: - data = { - "file": (f, "starts_with_empty_line.csv"), - "datasetId": datasets["own_dataset"].id_dataset, - } + data = {"file": (f, "starts_with_empty_line.csv")} r = self.client.post( url_for("import.upload_file"), data=data, @@ -618,7 +386,6 @@ def test_import_upload_after_preparation(self, prepared_import): with open(tests_path / "files" / "synthese" / "utf8_file.csv", "rb") as f: data = { "file": (f, "utf8_file.csv"), - "datasetId": imprt.id_dataset, } r = self.client.put( url_for("import.upload_file", import_id=imprt.id_import), @@ -635,8 +402,9 @@ def test_import_upload_after_preparation(self, prepared_import): assert imprt.columns == None assert len(imprt.errors) == 0 - def test_import_decode(self, users, new_import): - imprt = new_import + def test_import_decode(self, users, uploaded_import): + + imprt = uploaded_import data = { "encoding": "utf-16", "format": "csv", @@ -644,6 +412,8 @@ def test_import_decode(self, users, new_import): "separator": ";", } + unset_logged_user(self.client) + db.session.flush() r = self.client.post(url_for("import.decode_file", import_id=imprt.id_import), data=data) assert r.status_code == Unauthorized.code, r.data @@ -651,10 +421,13 @@ def test_import_decode(self, users, new_import): r = self.client.post(url_for("import.decode_file", import_id=imprt.id_import), data=data) assert r.status_code == Forbidden.code, r.data - set_logged_user(self.client, users["user"]) + set_logged_user(self.client, imprt.authors[0]) r = self.client.post(url_for("import.decode_file", import_id=imprt.id_import), data=data) assert r.status_code == BadRequest.code, r.data - assert "first upload" in r.json["description"] + assert ( + "Erreur d’encodage lors de la lecture du fichier source. Avez-vous sélectionné le bon encodage de votre fichier ?" + == r.json["description"] + ) imprt.full_file_name = "import.csv" imprt.detected_encoding = "utf-8" @@ -692,6 +465,7 @@ def test_import_decode(self, users, new_import): with open(tests_path / "files" / "synthese" / "utf8_file.csv", "rb") as f: imprt.source_file = f.read() + db.session.flush() r = self.client.post(url_for("import.decode_file", import_id=imprt.id_import), data=data) assert r.status_code == 200, r.data @@ -868,17 +642,15 @@ def test_import_errors(self, users, prepared_import): ) assert len(r.json) == len(valid_file_expected_errors) - def test_import_valid_file(self, users, datasets): + def test_import_valid_file(self, users, fieldmapping, import_file_name): set_logged_user(self.client, users["user"]) # Upload step - test_file_name = "valid_file.csv" - with open(tests_path / "files" / "synthese" / test_file_name, "rb") as f: + with open(tests_path / "files" / "synthese" / import_file_name, "rb") as f: test_file_line_count = sum(1 for line in f) - 1 # remove headers f.seek(0) data = { - "file": (f, test_file_name), - "datasetId": datasets["own_dataset"].id_dataset, + "file": (f, import_file_name), } r = self.client.post( url_for("import.upload_file"), @@ -894,8 +666,7 @@ def test_import_valid_file(self, users, datasets): assert imprt_json["detected_encoding"] == "utf-8" assert imprt_json["detected_format"] == "csv" assert imprt_json["detected_separator"] == ";" - assert imprt_json["full_file_name"] == test_file_name - assert imprt_json["id_dataset"] == datasets["own_dataset"].id_dataset + assert imprt_json["full_file_name"] == import_file_name # Decode step data = { @@ -926,12 +697,7 @@ def test_import_valid_file(self, users, datasets): assert transient_rows_count == 0 # Field mapping step - fieldmapping = ( - db.session.execute(sa.select(FieldMapping).filter_by(label="Synthese GeoNature")) - .unique() - .scalar_one() - ) - fieldmapping_values = fieldmapping.values.copy() + fieldmapping_values = fieldmapping.copy() fieldmapping_values.update( {"count_max": fieldmapping_values.get("count_max", {}) | {"default_value": 5}} ) @@ -1036,8 +802,9 @@ def test_import_valid_file(self, users, datasets): r = self.client.delete(url_for("import.delete_import", import_id=imprt.id_import)) assert r.status_code == 200, r.data - @pytest.mark.parametrize("import_file_name", ["geom_file.csv"]) - @pytest.mark.parametrize("autogenerate", [False]) + @pytest.mark.parametrize( + "autogenerate, import_file_name,fieldmapping_preset_name", [(False, "geom_file.csv", None)] + ) def test_import_geometry_file(self, area_restriction, prepared_import): assert_import_errors( prepared_import, @@ -1059,7 +826,7 @@ def test_import_geometry_file(self, area_restriction, prepared_import): }, ) - @pytest.mark.parametrize("import_file_name", ["cd_file.csv"]) + @pytest.mark.parametrize("import_file_name,fieldmapping_preset_name", [("cd_file.csv", None)]) def test_import_cd_file(self, change_id_list_conf, prepared_import): assert_import_errors( prepared_import, @@ -1072,7 +839,9 @@ def test_import_cd_file(self, change_id_list_conf, prepared_import): }, ) - @pytest.mark.parametrize("import_file_name", ["source_pk_file.csv"]) + @pytest.mark.parametrize( + "import_file_name,fieldmapping_preset_name", [("source_pk_file.csv", None)] + ) def test_import_source_pk_file(self, prepared_import): assert_import_errors( prepared_import, @@ -1085,7 +854,9 @@ def test_import_source_pk_file(self, prepared_import): }, ) - @pytest.mark.parametrize("import_file_name", ["altitude_file.csv"]) + @pytest.mark.parametrize( + "import_file_name,fieldmapping_preset_name", [("altitude_file.csv", None)] + ) def test_import_altitude_file(self, prepared_import): french_dem = has_french_dem() if french_dem: @@ -1122,8 +893,8 @@ def test_import_altitude_file(self, prepared_import): ] assert altitudes == expected_altitudes - @pytest.mark.parametrize("import_file_name", ["uuid_file.csv"]) - def test_import_uuid_file(self, synthese_data, prepared_import): + @pytest.mark.parametrize("import_file_name,fieldmapping_preset_name", [("uuid_file.csv", None)]) + def test_import_uuid_file(self, import_datasets, synthese_data, prepared_import): assert_import_errors( prepared_import, { @@ -1140,7 +911,7 @@ def test_import_uuid_file(self, synthese_data, prepared_import): ).scalar() assert unique_id_sinp != None - @pytest.mark.parametrize("import_file_name", ["dates.csv"]) + @pytest.mark.parametrize("import_file_name,fieldmapping_preset_name", [("dates.csv", None)]) def test_import_dates_file(self, prepared_import): assert_import_errors( prepared_import, @@ -1156,7 +927,9 @@ def test_import_dates_file(self, prepared_import): }, ) - @pytest.mark.parametrize("import_file_name", ["digital_proof.csv"]) + @pytest.mark.parametrize( + "import_file_name,fieldmapping_preset_name", [("digital_proof.csv", None)] + ) def test_import_digital_proofs_file(self, prepared_import): assert_import_errors( prepared_import, @@ -1170,7 +943,7 @@ def test_import_digital_proofs_file(self, prepared_import): }, ) - @pytest.mark.parametrize("import_file_name", ["depth.csv"]) + @pytest.mark.parametrize("import_file_name,fieldmapping_preset_name", [("depth.csv", None)]) def test_import_depth_file(self, prepared_import): assert_import_errors( prepared_import, @@ -1179,7 +952,9 @@ def test_import_depth_file(self, prepared_import): }, ) - @pytest.mark.parametrize("import_file_name", ["nomenclatures_file.csv"]) + @pytest.mark.parametrize( + "import_file_name,fieldmapping_preset_name", [("nomenclatures_file.csv", None)] + ) def test_import_nomenclatures_file(self, prepared_import): assert_import_errors( prepared_import, @@ -1202,7 +977,9 @@ def test_import_nomenclatures_file(self, prepared_import): }, ) - @pytest.mark.parametrize("import_file_name", ["additional_data.csv"]) + @pytest.mark.parametrize( + "import_file_name,fieldmapping_preset_name", [("additional_data.csv", None)] + ) def test_import_additional_data(self, imported_import): assert_import_errors( imported_import, @@ -1228,7 +1005,9 @@ def test_import_additional_data(self, imported_import): {"a": "A", "additional_data2": ""}, ] - @pytest.mark.parametrize("import_file_name", ["empty_nomenclatures_file.csv"]) + @pytest.mark.parametrize( + "import_file_name,fieldmapping_preset_name", [("empty_nomenclatures_file.csv", None)] + ) def test_import_empty_nomenclatures_file(self, imported_import): assert_import_errors( imported_import, @@ -1252,7 +1031,9 @@ def test_import_empty_nomenclatures_file(self, imported_import): # et ne pas l’écraser avec la valeur par défaut assert obs3.nomenclature_life_stage.label_default == "Alevin" - @pytest.mark.parametrize("import_file_name", ["empty_nomenclatures_file.csv"]) + @pytest.mark.parametrize( + "import_file_name,fieldmapping_preset_name", [("empty_nomenclatures_file.csv", None)] + ) def test_import_empty_nomenclatures_file_no_default( self, no_default_nomenclatures, imported_import ): @@ -1279,7 +1060,9 @@ def test_import_empty_nomenclatures_file_no_default( # et ne pas l’écraser avec la valeur par défaut assert obs3.nomenclature_life_stage.label_default == "Alevin" - @pytest.mark.parametrize("import_file_name", ["multiline_comment_file.csv"]) + @pytest.mark.parametrize( + "import_file_name,fieldmapping_preset_name", [("multiline_comment_file.csv", None)] + ) def test_import_multiline_comment_file(self, users, imported_import): assert_import_errors( imported_import, @@ -1327,6 +1110,9 @@ def test_export_pdf_forbidden(self, users, imports): def test_get_import_source_file(self, users, uploaded_import): url = url_for("import.get_import_source_file", import_id=uploaded_import.id_import) + unset_logged_user(self.client) + db.session.flush() + resp = self.client.get(url) assert resp.status_code == Unauthorized.code @@ -1334,7 +1120,7 @@ def test_get_import_source_file(self, users, uploaded_import): resp = self.client.get(url) assert resp.status_code == Forbidden.code - set_logged_user(self.client, users["user"]) + set_logged_user(self.client, uploaded_import.authors[0]) resp = self.client.get(url) assert resp.status_code == 200 assert resp.content_length > 0 @@ -1351,7 +1137,9 @@ def test_get_nomenclatures(self): for nomenclature in resp.json.values() ) - @pytest.mark.parametrize("import_file_name", ["multiline_comment_file.csv"]) + @pytest.mark.parametrize( + "import_file_name,fieldmapping_preset_name", [("multiline_comment_file.csv", None)] + ) def test_import_compare_error_line_with_csv(self, users, imported_import, import_file_name): """ This test verify generated errors csv file contains right rows from source file. @@ -1383,19 +1171,22 @@ def test_import_compare_error_line_with_csv(self, users, imported_import, import # and this is the test purpose assert: assert error_row == source_row - @pytest.mark.parametrize("import_file_name", ["jdd_to_import_file.csv"]) + @pytest.mark.parametrize( + "import_file_name", + [("jdd_to_import_file.csv")], + ) def test_import_jdd_file(self, imported_import, users): assert_import_errors( imported_import, { - # id_dataset errors - # The line 2 should not be error (should be the one selected jdd default) - (ImportCodeError.DATASET_NOT_AUTHORIZED, "unique_dataset_id", frozenset({2, 4, 6})), + (ImportCodeError.INVALID_UUID, "unique_dataset_id", frozenset({4})), (ImportCodeError.DATASET_NOT_FOUND, "unique_dataset_id", frozenset({5})), + (ImportCodeError.DATASET_NOT_ACTIVE, "unique_dataset_id", frozenset({6})), + (ImportCodeError.DATASET_NOT_AUTHORIZED, "unique_dataset_id", frozenset({7})), ( ImportCodeError.CONDITIONAL_MANDATORY_FIELD_ERROR, "floutage_dee", - frozenset({6}), + frozenset({8}), ), }, ) diff --git a/backend/geonature/tests/imports/test_mappings.py b/backend/geonature/tests/imports/test_mappings.py index 38dbab98d7..dd1171ff5d 100644 --- a/backend/geonature/tests/imports/test_mappings.py +++ b/backend/geonature/tests/imports/test_mappings.py @@ -25,12 +25,12 @@ @pytest.fixture() -def mappings(synthese_destination, users): +def mappings(import_destination, users): mappings = {} bib_fields = ( db.session.execute( sa.select(BibFields.name_field, BibFields.autogenerated, BibFields.multi).filter_by( - destination=synthese_destination, display=True + destination=import_destination, display=True ) ) .unique() @@ -50,9 +50,7 @@ def mappings(synthese_destination, users): nomenc_bib_fields = ( db.session.scalars( sa.select(BibFields) - .where( - BibFields.destination == synthese_destination, BibFields.nomenclature_type != None - ) + .where(BibFields.destination == import_destination, BibFields.nomenclature_type != None) .options( joinedload(BibFields.nomenclature_type).joinedload( BibNomenclaturesTypes.nomenclatures @@ -72,47 +70,47 @@ def mappings(synthese_destination, users): } with db.session.begin_nested(): mappings["content_public"] = ContentMapping( - destination=synthese_destination, + destination=import_destination, label="Content Mapping", active=True, public=True, values=contentmapping_values, ) mappings["field_public"] = FieldMapping( - destination=synthese_destination, + destination=import_destination, label="Public Field Mapping", active=True, public=True, values=fieldmapping_values, ) mappings["field"] = FieldMapping( - destination=synthese_destination, + destination=import_destination, label="Private Field Mapping", active=True, public=False, ) mappings["field_public_disabled"] = FieldMapping( - destination=synthese_destination, + destination=import_destination, label="Disabled Public Field Mapping", active=False, public=True, ) mappings["self"] = FieldMapping( - destination=synthese_destination, + destination=import_destination, label="Self’s Mapping", active=True, public=False, owners=[users["self_user"]], ) mappings["stranger"] = FieldMapping( - destination=synthese_destination, + destination=import_destination, label="Stranger’s Mapping", active=True, public=False, owners=[users["stranger_user"]], ) mappings["associate"] = FieldMapping( - destination=synthese_destination, + destination=import_destination, label="Associate’s Mapping", active=True, public=False, @@ -122,7 +120,9 @@ def mappings(synthese_destination, users): return mappings -@pytest.mark.usefixtures("client_class", "temporary_transaction", "default_synthese_destination") +@pytest.mark.usefixtures( + "client_class", "temporary_transaction", "default_import_destination", "module_code" +) class TestMappings: def test_list_mappings(self, users, mappings): set_logged_user(self.client, users["noright_user"]) @@ -302,11 +302,12 @@ def test_add_field_mapping(self, users, mappings): assert r.status_code == BadRequest.code r = self.client.post(url, data=fieldmapping) - assert r.status_code == BadRequest.code # missing date_min + assert r.status_code == BadRequest.code # missing date_min and unique_dataset_id fieldmapping.update( { "date_min": {"column_src": "date_debut"}, + "unique_dataset_id": {"column_src": "jdd_uuid"}, } ) r = self.client.post(url, data=fieldmapping) diff --git a/backend/geonature/tests/test_gn_meta.py b/backend/geonature/tests/test_gn_meta.py index a32f83cc12..6e8a499747 100644 --- a/backend/geonature/tests/test_gn_meta.py +++ b/backend/geonature/tests/test_gn_meta.py @@ -612,6 +612,10 @@ def test_datasets_permissions(self, app, datasets, users): ) assert set(sc(dsc.filter_by_scope(2, query=qs)).unique().all()) == set( [ + # The code is attempting to access a dataset named "own_dataset" from a dictionary or list + # named "datasets" in Python. However, the code snippet provided is incomplete and lacks + # context, so it is difficult to determine the exact functionality or purpose of this code + # without additional information. datasets["own_dataset"], datasets["own_dataset_not_activated"], datasets["associate_dataset"], diff --git a/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py b/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py index a0fd94a8a0..35bab7a234 100644 --- a/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py +++ b/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py @@ -325,7 +325,8 @@ def check_station_sql(imprt): geom_4326_field=fields["geom_4326"], geom_local_field=fields["geom_local"], ) - if imprt.fieldmapping.get("altitudes_generate", False): + autogenerate_field = imprt.fieldmapping.get("altitudes_generate", False) + if autogenerate_field and autogenerate_field["column_src"]: # TODO@TestImportsOcchab.test_import_valid_file: add testcase generate_altitudes( imprt, @@ -491,7 +492,7 @@ def import_data_to_destination(imprt: TImports) -> None: insert_fields |= {field} if entity.code == "station": # unique_dataset_id is replaced with id_dataset - insert_fields -= {fields["unique_dataset_id"]} + # insert_fields -= {fields["unique_dataset_id"]} insert_fields |= {fields["id_dataset"]} insert_fields |= {fields["geom_4326"], fields["geom_local"]} # TODO@TestImportsOcchab.test_import_valid_file: add testcase diff --git a/frontend/cypress/fixtures/import/occhab/valid_file.csv b/frontend/cypress/fixtures/import/occhab/valid_file.csv index d9285de36e..4894c952ea 100644 --- a/frontend/cypress/fixtures/import/occhab/valid_file.csv +++ b/frontend/cypress/fixtures/import/occhab/valid_file.csv @@ -1,6 +1,6 @@ -Erreur station;Erreur habitat;id_station_source;unique_id_sinp_station;unique_dataset_id;date_min;date_max;observers_txt;id_nomenclature_area_surface_calculation;WKT;id_nomenclature_geographic_object;unique_id_sinp_habitat;nom_cite;cd_hab;technical_precision -OK !;OK !;;afa81c29-c75d-408d-bf48-53cce02d5561;VALID_DATASET_UUID;17/11/2023;17/11/2023;;;POINT(3.634 44.399);St;4ee53579-b09b-408f-aa1f-d62495a66667;prairie;24; -OK !;OK !;;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;17/11/2023;;;;POINT(3.634 44.399);St;d91496e9-d904-45a8-9e18-cb8acbbb6ea6;prairie;24; +Erreur station;Erreur habitat;id_station;unique_id_sinp_station;unique_dataset_id;date_debut;date_fin;observateurs;methode_calcul_surface;geometry;nature_objet_geo;unique_id_sinp_habitat;nom_cite;cd_hab;precision_technique +OK !;OK !;;afa81c29-c75d-408d-bf48-53cce02d5561;VALID_DATASET_UUID;17/11/2023;17/11/2023;;;POINT(3.634 44.399);St;4ee53579-b09b-408f-aa1f-d62495a66667;prairie;24; +OK !;OK !;;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;17/11/2023;;;;POINT(3.634 44.399);St;d91496e9-d904-45a8-9e18-cb8acbbb6ea6;prairie;24; DUPLICATE_UUID(unique_id_sinp_station);ERRONEOUS_PARENT_ENTITY;;462d385f-489a-436b-babb-8cca5fc62e1d;;17/11/2023;17/11/2023;;;POINT(3.634 44.399);St;e5e7a184-3e92-4adb-a721-5bd004b3397f;forêt;24; DUPLICATE_UUID(unique_id_sinp_station);ERRONEOUS_PARENT_ENTITY;;462d385f-489a-436b-babb-8cca5fc62e1d;;17/11/2023;17/11/2023;;;POINT(3.634 44.399);St;8f52f122-b9ae-45b3-b947-2c9f7934b823;prairie;24; DATASET_NOT_FOUND(unique_dataset_id);ERRONEOUS_PARENT_ENTITY;;bdc3346d-0fc3-40fa-b787-be927e4dd82e;050d613c-543f-47fd-800a-13931b2721c7;17/11/2023;17/11/2023;;;POINT(3.634 44.399);St;2ff4867d-6943-45d8-873d-187fbc6d67a7;prairie;24; @@ -13,9 +13,9 @@ ORPHAN_ROW(unique_id_sinp_station);ORPHAN_ROW(unique_id_sinp_station);;258a2478- ORPHAN_ROW(id_station_source);ORPHAN_ROW(id_station_source);Station 0;;;;;;;;;;;; DUPLICATE_SOURCE_ENTITY_PK(id_station_source);ERRONEOUS_PARENT_ENTITY;Station 1;;;17/11/2023;17/11/2023;;;POINT(3.634 44.399);St;;prairie;24; DUPLICATE_SOURCE_ENTITY_PK(id_station_source);ERRONEOUS_PARENT_ENTITY;Station 1;;;17/11/2023;17/11/2023;;;POINT(3.634 44.399);St;;prairie;24; -OK !;OK !;Station 2;;;17/11/2023;17/11/2023;;;POINT(3.634 44.399);St;;prairie;24; -Pas de station;OK !;Station 2;;;;;;;;;;prairie;24; -Pas de station;OK !;;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;;;;;;;;prairie;24; +OK !;OK !;Station 2;;;17/11/2023;17/11/2023;;;POINT(3.634 44.399);St;;prairie;24; +Pas de station;OK !;Station 2;;;;;;;;;;prairie;24; +Pas de station;OK !;;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;;;;;;;;prairie;24; Pas de station;ERRONEOUS_PARENT_ENTITY;;bdc3346d-0fc3-40fa-b787-be927e4dd82e;;;;;;;;;prairie;24; INVALID_UUID(unique_id_sinp_station);INVALID_UUID(unique_id_sinp_station),ERRONEOUS_PARENT_ENTITY;;erroneous;;17/11/2023;17/11/2023;;;POINT(3.634 44.399);St;6c02ef80-2e78-4c2c-b8b5-1c75e2349fc2;prairie;24; Pas de station;INVALID_UUID(unique_id_sinp_station);;erroneous;;;;;;;;;prairie;24; diff --git a/frontend/src/app/GN2CommonModule/form/dynamic-form/dynamic-form.component.html b/frontend/src/app/GN2CommonModule/form/dynamic-form/dynamic-form.component.html index f023e1aa0d..cc661a40e9 100644 --- a/frontend/src/app/GN2CommonModule/form/dynamic-form/dynamic-form.component.html +++ b/frontend/src/app/GN2CommonModule/form/dynamic-form/dynamic-form.component.html @@ -11,7 +11,7 @@ 'number', 'file', 'medias', - 'bool_radio' + 'bool_radio', ].includes(formDefComp['type_widget']) " > @@ -308,6 +308,7 @@ [multiSelect]="formDef.multi_select" [moduleCode]="formDef.module_code" [creatableInModule]="formDef.creatable_in_module" + [bindValue]="formDef.bind_value" > Suppression

    -
    - -
    - -
    -
    Description de l'import
    -

    - Jeu de données : - - {{ datasetName }} - -

    Fichier : = []; public importWarnings: Array = []; public nbTotalErrors: number = 0; - public datasetName: string = ''; public rank: string = null; public loadingChart: boolean; public options: any = { @@ -94,7 +93,6 @@ export class ImportReportComponent implements OnInit { this.importData = this.importProcessService.getImportData(); // Load additionnal data if imported data this.loadValidData(this.importData); - this.loadDatasetName(); // Add property to show errors lines. Need to do this to // show line per line... this.loadErrors(); @@ -130,14 +128,6 @@ export class ImportReportComponent implements OnInit { } } - loadDatasetName() { - if (this.importData) { - this._dataService.getDatasetFromId(this.importData.id_dataset).subscribe((data) => { - this.datasetName = data.dataset_name; - }); - } - } - loadErrors() { if (this.importData) { this._dataService.getImportErrors(this.importData.id_import).subscribe((errors) => { diff --git a/frontend/src/app/modules/imports/components/modal_destination/import-modal-destination.component.html b/frontend/src/app/modules/imports/components/modal_destination/import-modal-destination.component.html index ce6540c857..d602fb57e5 100644 --- a/frontend/src/app/modules/imports/components/modal_destination/import-modal-destination.component.html +++ b/frontend/src/app/modules/imports/components/modal_destination/import-modal-destination.component.html @@ -28,7 +28,7 @@

    *ngIf="isUserDestinationError" > warning diff --git a/frontend/src/app/modules/imports/components/modal_destination/import-modal-destination.component.scss b/frontend/src/app/modules/imports/components/modal_destination/import-modal-destination.component.scss index 75342dd005..23feb336d1 100644 --- a/frontend/src/app/modules/imports/components/modal_destination/import-modal-destination.component.scss +++ b/frontend/src/app/modules/imports/components/modal_destination/import-modal-destination.component.scss @@ -1,4 +1,4 @@ -#warningDataset { +#warningDestination { color: red; } diff --git a/frontend/src/app/modules/imports/models/import.model.ts b/frontend/src/app/modules/imports/models/import.model.ts index 0a67f06c72..f2a74ca296 100644 --- a/frontend/src/app/modules/imports/models/import.model.ts +++ b/frontend/src/app/modules/imports/models/import.model.ts @@ -21,10 +21,6 @@ export interface ImportError { show?: boolean; } -export interface Dataset { - dataset_name: string; - active: boolean; -} export interface ImportStatistics { import_count: number; [propName: string]: any; @@ -40,7 +36,6 @@ export interface Import { detected_encoding: string; import_table: string; full_file_name: string; - id_dataset: number; date_create_import: string; date_update_import: string; date_end_import: null | string; @@ -65,7 +60,6 @@ export interface Import { task_progress?: number; task_id?: string; errors?: [ImportError]; - dataset?: Dataset; id_source?: number; id_destination: number; destination?: Destination; @@ -141,11 +135,6 @@ export interface TaxaDistribution { group: string; } -// minimal dataset model -export interface Dataset { - dataset_name: string; -} - export interface ImportPreview { valid_bbox: any; entities: [ diff --git a/frontend/src/app/modules/imports/services/data.service.ts b/frontend/src/app/modules/imports/services/data.service.ts index 8d799f2c7f..03e6dd779a 100644 --- a/frontend/src/app/modules/imports/services/data.service.ts +++ b/frontend/src/app/modules/imports/services/data.service.ts @@ -2,7 +2,6 @@ import { Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { HttpClient, HttpParams } from '@angular/common/http'; import { - Dataset, Import, ImportError, ImportValues, @@ -55,10 +54,9 @@ export class ImportDataService { return this._http.get(`${this.getUrlApiForADestination()}/imports/${id_import}/`); } - addFile(datasetId: number, file: File): Observable { - let fd = new FormData(); + addFile(file: File): Observable { + const fd = new FormData(); fd.append('file', file, file.name); - fd.append('datasetId', String(datasetId)); const url = `${this.getUrlApiForADestination()}/imports/upload`; return this._http.post(url, fd); } @@ -288,10 +286,6 @@ export class ImportDataService { ); } - getDatasetFromId(datasetId: number) { - return this._http.get(`${this.config.API_ENDPOINT}/meta/dataset/${datasetId}`); - } - getPdf(importId, mapImg, chartImg) { const formData = new FormData(); if (mapImg) { diff --git a/frontend/src/app/modules/imports/services/mappings/field-mapping.service.ts b/frontend/src/app/modules/imports/services/mappings/field-mapping.service.ts index f1f4903e1c..c97a4d27b2 100644 --- a/frontend/src/app/modules/imports/services/mappings/field-mapping.service.ts +++ b/frontend/src/app/modules/imports/services/mappings/field-mapping.service.ts @@ -510,6 +510,10 @@ export class FieldMappingService { type_widget: 'textarea', }; } + if(field.type_field == 'dataset'){ + const module_code = this._importProcessService.getImportData().destination?.module.module_code; + def.creatable_in_module = module_code; + } return { ...def, From bbd37c8cef39df7162c6d9f4456430b76ac4d0de Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Tue, 21 Jan 2025 18:29:27 +0100 Subject: [PATCH 02/14] feat: setup frontend test --- .../e2e/import/constants/fieldsContent.js | 5 -- .../cypress/e2e/import/constants/filters.js | 5 -- .../cypress/e2e/import/constants/selectors.js | 9 +++- .../list-table-jdd-modify-delete-spec.js | 15 +++--- .../import/list-table-refer-to-jdd-spec.js | 40 --------------- .../navigation-check-back-each-steps-spec.js | 9 ---- .../navigation-mappings-cancel-save-spec.js | 14 +++--- .../propcess-import-in-synthese-spec.js | 3 +- .../cypress/e2e/import/step1-upload-spec.js | 32 ------------ .../e2e/import/step3-field-mapping-spec.js | 49 +++++++++---------- .../e2e/import/step4-content-mapping-spec.js | 29 +++++++---- .../e2e/import/step5-recaptiulatif-spec.js | 3 +- .../cypress/e2e/import/step6-report-spec.js | 3 +- .../import/configureImportFieldMapping.js | 18 ++++++- frontend/cypress/support/import/index.js | 1 - .../cypress/support/import/pickDataset.js | 11 ----- .../dynamic-form/dynamic-form.component.html | 2 +- .../mapping-theme.component.html | 1 + 18 files changed, 87 insertions(+), 162 deletions(-) delete mode 100644 frontend/cypress/e2e/import/list-table-refer-to-jdd-spec.js delete mode 100644 frontend/cypress/support/import/pickDataset.js diff --git a/frontend/cypress/e2e/import/constants/fieldsContent.js b/frontend/cypress/e2e/import/constants/fieldsContent.js index f37b212512..e6ff931b1b 100644 --- a/frontend/cypress/e2e/import/constants/fieldsContent.js +++ b/frontend/cypress/e2e/import/constants/fieldsContent.js @@ -1,9 +1,4 @@ export const FIELDS_CONTENT_STEP_UPLOAD = { - datasetField: { - defaultValue: 'JDD-TEST-IMPORT-ADMIN', - newValue: 'JDD-TEST-IMPORT-2', - selector: 'ng-select', - }, fileUploadField: { defaultValue: 'import/synthese/valid_file_test_link_list_import_synthese.csv', newValue: 'import/synthese/valid_file_import_synthese_test_changed.csv', diff --git a/frontend/cypress/e2e/import/constants/filters.js b/frontend/cypress/e2e/import/constants/filters.js index a3a6f48c41..f827566a15 100644 --- a/frontend/cypress/e2e/import/constants/filters.js +++ b/frontend/cypress/e2e/import/constants/filters.js @@ -1,9 +1,4 @@ export const FILTERS_TABLE = [ - { - columnName: 'Jeu de données', - searchTerm: ['JDD-TEST', 'JDD-TEST-IMPORT-ADMIN', 'JDD-INVALID'], - expectedRowsCount: [4, 1, 0], - }, { columnName: 'Fichier', searchTerm: ['valid_file_test_import', 'invalid_file.csv'], diff --git a/frontend/cypress/e2e/import/constants/selectors.js b/frontend/cypress/e2e/import/constants/selectors.js index 2993fb258a..0839c916f6 100644 --- a/frontend/cypress/e2e/import/constants/selectors.js +++ b/frontend/cypress/e2e/import/constants/selectors.js @@ -48,13 +48,19 @@ export const getSelectorsForStep = (stepName) => { export const SELECTOR_IMPORT_MODAL_DELETE = '[data-qa=import-modal-delete]'; export const SELECTOR_IMPORT_MODAL_DELETE_VALIDATE = '[data-qa=modal-delete-validate]'; + export const SELECTOR_IMPORT_MODAL_DESTINATION_START = '[data-qa=import-modal-destination-start]'; export const SELECTOR_IMPORT_FIELDMAPPING_DATE_MIN = '[data-qa=import-fieldmapping-theme-date_min]'; export const SELECTOR_IMPORT_FIELDMAPPING_OBSERVERS = '[data-qa=import-fieldmapping-theme-observers]'; export const SELECTOR_IMPORT_FIELDMAPPING_NOM_CITE = '[data-qa=import-fieldmapping-theme-nom_cite]'; export const SELECTOR_IMPORT_FIELDMAPPING_WKT = '[data-qa=import-fieldmapping-theme-WKT]'; +export const SELECTOR_IMPORT_FIELDMAPPING_CD_HAB = '[data-qa=import-fieldmapping-theme-cd_hab]'; export const SELECTOR_IMPORT_FIELDMAPPING_CD_NOM = '[data-qa=import-fieldmapping-theme-cd_nom]'; +export const SELECTOR_IMPORT_FIELDMAPPING_DATASET = + '[data-qa=import-fieldmapping-theme-unique_dataset_id]'; +export const SELECTOR_IMPORT_FIELDMAPPING_DEFAULT_DATASET = + '[data-qa=import-fieldmapping-theme-default-unique_dataset_id] ng-select'; export const SELECTOR_IMPORT_FIELDMAPPING_VALIDATE = '[data-qa=import-new-fieldmapping-model-validate]'; export const SELECTOR_IMPORT_FIELDMAPPING_BUTTON_DELETE = @@ -70,6 +76,8 @@ export const SELECTOR_IMPORT_FIELDMAPPING_SELECTION_RENAME_OK = export const SELECTOR_IMPORT_FIELDMAPPING_SELECTION_RENAME_TEXT = '[data-qa=import-fieldmapping-selection-rename-text]'; export const SELECTOR_IMPORT_FIELDMAPPING_MODAL = '[data-qa=import-fieldmapping-saving-modal]'; +export const SELECTOR_IMPORT_FIELDMAPPING_MODAL_CANCEL = + '[data-qa=import-fieldmapping-saving-modal-cancel]'; export const SELECTOR_IMPORT_FIELDMAPPING_MODAL_CLOSE = '[data-qa=import-fieldmapping-saving-modal-close]'; export const SELECTOR_IMPORT_FIELDMAPPING_MODAL_OK = @@ -88,7 +96,6 @@ export const SELECTOR_IMPORT_LIST_TOOLBAR_DESTINATIONS = export const SELECTOR_IMPORT_LIST_TOOLBAR_SEARCH = '[data-qa=import-list-toolbar-search]'; export const SELECTOR_DESTINATIONS = '[data-qa=destinations]'; export const SELECTOR_IMPORT = '[data-qa=gn-sidenav-link-IMPORT]'; -export const SELECTOR_IMPORT_UPLOAD_DATASET = '[data-qa=import-new-upload-datasets]'; export const SELECTOR_IMPORT_UPLOAD_FILE = '[data-qa=import-new-upload-file]'; export const SELECTOR_IMPORT_UPLOAD_VALIDATE = '[data-qa=import-new-upload-validate]'; export const SELECTOR_IMPORT_CONTENTMAPPING_STEP_BUTTON = diff --git a/frontend/cypress/e2e/import/list-table-jdd-modify-delete-spec.js b/frontend/cypress/e2e/import/list-table-jdd-modify-delete-spec.js index 4c26312171..56b362a2ae 100644 --- a/frontend/cypress/e2e/import/list-table-jdd-modify-delete-spec.js +++ b/frontend/cypress/e2e/import/list-table-jdd-modify-delete-spec.js @@ -44,7 +44,7 @@ describe('Tests actions on active/inactive list JDD ', () => { }); JDD_LIST.forEach((jdd_item) => { - it(`should verify actions for ${jdd_item.jdd_name} (${ + it.skip(`should verify actions for ${jdd_item.jdd_name} (${ jdd_item.jdd_is_active ? 'active' : 'inactive' })`, () => { cy.getRowIndexByCellValue( @@ -58,19 +58,18 @@ describe('Tests actions on active/inactive list JDD ', () => { }); }); - it('Should be able to modify a finished import, but still active JDD', () => { + it.skip('Should be able to modify a finished import, but still active JDD', () => { cy.startImport(); cy.pickDestination(); - cy.pickDataset(user.dataset); cy.loadImportFile(FILES.synthese.valid.fixture); cy.configureImportFile(); - cy.configureImportFieldMapping(); + cy.configureImportFieldMapping(user.dataset); cy.configureImportContentMapping(); cy.verifyImport(); cy.executeImport(); cy.backToImportList(); - cy.get(getSelectorImportListTableRowEdit(0)) + cy.get(getSelectorImportListTableRowEdit.skip(0)) .should('exist') .should('be.visible') .should('not.be.disabled'); @@ -80,7 +79,7 @@ describe('Tests actions on active/inactive list JDD ', () => { }); cy.reload(); - cy.get(getSelectorImportListTableRowEdit(0)) + cy.get(getSelectorImportListTableRowEdit.skip(0)) .should('exist') .should('be.visible') .should('be.disabled'); @@ -90,7 +89,7 @@ describe('Tests actions on active/inactive list JDD ', () => { }); cy.reload(); - cy.get(getSelectorImportListTableRowEdit(0)) + cy.get(getSelectorImportListTableRowEdit.skip(0)) .should('exist') .should('be.visible') .should('not.be.disabled'); @@ -104,7 +103,7 @@ describe('Tests actions on active/inactive list JDD ', () => { function verifyEditAction(rowIndex, jdd_item) { const actionStatus = jdd_item.jdd_is_active ? 'not.be.disabled' : 'be.disabled'; - cy.get(getSelectorImportListTableRowEdit(rowIndex)) + cy.get(getSelectorImportListTableRowEdit.skip(rowIndex)) .should('exist') .should('be.visible') .should(actionStatus) diff --git a/frontend/cypress/e2e/import/list-table-refer-to-jdd-spec.js b/frontend/cypress/e2e/import/list-table-refer-to-jdd-spec.js deleted file mode 100644 index f087441105..0000000000 --- a/frontend/cypress/e2e/import/list-table-refer-to-jdd-spec.js +++ /dev/null @@ -1,40 +0,0 @@ -import { USERS } from './constants/users'; -import { TIMEOUT_WAIT, VIEWPORTS } from './constants/common'; -import { SELECTOR_IMPORT_LIST_TABLE } from './constants/selectors'; - -const COLUMN_NAME = 'Jeu de données'; -const JDD_LIST = ['JDD-TEST-IMPORT-ADMIN', 'JDD-TEST-IMPORT-2', 'JDD-TEST-IMPORT-3']; - -// //////////////////////////////////////////////////////////////////////////// -// -// //////////////////////////////////////////////////////////////////////////// - -describe('Test List import - Refer to JDD page', () => { - VIEWPORTS.forEach((viewport) => { - context(`viewport: ${viewport.width}x${viewport.height}`, () => { - const user = USERS[0]; - context(`user: ${user.login.username}`, () => { - beforeEach(() => { - cy.viewport(viewport.width, viewport.height); - cy.geonatureLogin(user.login.username, user.login.password); - cy.visitImport(); - }); - - JDD_LIST.forEach((cellValue) => - it('Should be redirected to page Metada dataset with dataset name: ' + cellValue, () => { - cy.getCellValueByColumnName(SELECTOR_IMPORT_LIST_TABLE, COLUMN_NAME, cellValue).then( - () => { - cy.get('@targetLink').click(); - cy.wait(TIMEOUT_WAIT); - } - ); - cy.location().then((loc) => { - cy.log('Current URL: ' + loc.href); - expect(loc.href).to.include('metadata/dataset_detail/'); - }); - }) - ); - }); - }); - }); -}); diff --git a/frontend/cypress/e2e/import/navigation-check-back-each-steps-spec.js b/frontend/cypress/e2e/import/navigation-check-back-each-steps-spec.js index 880fcfd40f..581fd22a77 100644 --- a/frontend/cypress/e2e/import/navigation-check-back-each-steps-spec.js +++ b/frontend/cypress/e2e/import/navigation-check-back-each-steps-spec.js @@ -69,7 +69,6 @@ describe('Import Process Navigation', () => { cy.pickDestination(DESTINATION); // STEP 1 - UPLOAD - cy.pickDataset(FIELDS_CONTENT_STEP_UPLOAD.datasetField.defaultValue); cy.loadImportFile(FIELDS_CONTENT_STEP_UPLOAD.fileUploadField.defaultValue); cy.wait(TIMEOUT_WAIT); cy.url().then((url) => { @@ -103,13 +102,6 @@ describe('Import Process Navigation', () => { cy.get(SELECTOR_NAVIGATION_STEP_DECODE_FILE.back_btn_selector) .should('be.visible') .click(); - // Verify the selected value in the ng-select input - cy.get(FIELDS_CONTENT_STEP_UPLOAD.datasetField.selector).within(() => { - cy.get('.ng-value').should( - 'contain.text', - FIELDS_CONTENT_STEP_UPLOAD.datasetField.defaultValue - ); - }); cy.get(FIELDS_CONTENT_STEP_UPLOAD.fileUploadField.selector).then(($el) => { const expectedValue = $el .text() @@ -119,7 +111,6 @@ describe('Import Process Navigation', () => { expect(defaultValue).to.include(expectedValue); }); // Change values in upload step - cy.pickDataset(FIELDS_CONTENT_STEP_UPLOAD.datasetField.newValue); cy.loadImportFile(FIELDS_CONTENT_STEP_UPLOAD.fileUploadField.newValue); cy.get(SELECTOR_NAVIGATION_STEP_DECODE_FILE.back_btn_selector) .should('be.visible') diff --git a/frontend/cypress/e2e/import/navigation-mappings-cancel-save-spec.js b/frontend/cypress/e2e/import/navigation-mappings-cancel-save-spec.js index 003cffe2b4..29c8fbf763 100644 --- a/frontend/cypress/e2e/import/navigation-mappings-cancel-save-spec.js +++ b/frontend/cypress/e2e/import/navigation-mappings-cancel-save-spec.js @@ -7,6 +7,7 @@ import { SELECTOR_IMPORT_CONTENTMAPPING_STEP_BUTTON, SELECTOR_IMPORT_FIELDMAPPING_CD_NOM, SELECTOR_IMPORT_FIELDMAPPING_DATE_MIN, + SELECTOR_IMPORT_FIELDMAPPING_DEFAULT_DATASET, SELECTOR_IMPORT_FIELDMAPPING_NOM_CITE, SELECTOR_IMPORT_FIELDMAPPING_OBSERVERS, SELECTOR_IMPORT_FIELDMAPPING_WKT, @@ -22,14 +23,13 @@ function runTheProcessUntilFieldMapping(user) { cy.visitImport(); cy.startImport(); cy.pickDestination(); - cy.pickDataset(user.dataset); cy.loadImportFile(FILES.synthese.valid.fixture); cy.configureImportFile(); } function runTheProcessUntilContentMapping(user) { runTheProcessUntilFieldMapping(user); - cy.configureImportFieldMapping(); + cy.configureImportFieldMapping(user.dataset); cy.wait(500); } @@ -67,14 +67,14 @@ function selectContentMappingField(dataQa, value) { cy.get(`[data-qa=import-contentmapping-theme-${dataQa}]`).should('exist').select(value); } -function fillTheFieldMappingFormRaw() { +function fillTheFieldMappingFormRaw(datasetName) { selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_DATE_MIN, 'date_debut'); selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_OBSERVERS, 'date_debut'); selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_NOM_CITE, 'date_debut'); selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_WKT, 'date_debut'); selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_CD_NOM, 'date_debut'); + selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_DEFAULT_DATASET, datasetName); } - // //////////////////////////////////////////////////////////////////////////// // Create a mapping with dummy values // //////////////////////////////////////////////////////////////////////////// @@ -97,7 +97,7 @@ describe('Navigation - cancel and save', () => { const parts = url.split('/'); const importID = parts[parts.length - 2]; // Get the penultimate element - fillTheFieldMappingFormRaw(); + fillTheFieldMappingFormRaw(user.dataset); cy.get(SELECTOR_IMPORT_FOOTER_DELETE).should('be.enabled').click(); cy.wait(TIMEOUT_WAIT); cy.checkCurrentPageIsImport(); @@ -112,7 +112,7 @@ describe('Navigation - cancel and save', () => { const parts = url.split('/'); const importID = parts[parts.length - 2]; // Get the penultimate element - fillTheFieldMappingFormRaw(); + fillTheFieldMappingFormRaw(user.dataset); cy.visitImport(); checkImportIsFirstInList(importID); clickOnFirstLineEdit(); @@ -133,7 +133,7 @@ describe('Navigation - cancel and save', () => { // Extract the ID using string manipulation const parts = url.split('/'); const importID = parts[parts.length - 2]; // Get the penultimate element - fillTheFieldMappingFormRaw(); + fillTheFieldMappingFormRaw(user.dataset); cy.get(SELECTOR_IMPORT_FOOTER_SAVE).should('be.enabled').click(); checkImportIsFirstInList(importID); clickOnFirstLineEdit(); diff --git a/frontend/cypress/e2e/import/propcess-import-in-synthese-spec.js b/frontend/cypress/e2e/import/propcess-import-in-synthese-spec.js index c1e2f5d20b..b3cfea90b1 100644 --- a/frontend/cypress/e2e/import/propcess-import-in-synthese-spec.js +++ b/frontend/cypress/e2e/import/propcess-import-in-synthese-spec.js @@ -23,10 +23,9 @@ describe('Import - create a new import', () => { it('Should be able to import a valid-file in synthese', () => { cy.startImport(); cy.pickDestination(); - cy.pickDataset(USER.dataset); cy.loadImportFile(FILES.synthese.valid.fixture); cy.configureImportFile(); - cy.configureImportFieldMapping(); + cy.configureImportFieldMapping(USER.dataset); cy.configureImportContentMapping(); cy.verifyImport(); cy.executeImport(); diff --git a/frontend/cypress/e2e/import/step1-upload-spec.js b/frontend/cypress/e2e/import/step1-upload-spec.js index b2ec1e5aac..e22d9a7f2f 100644 --- a/frontend/cypress/e2e/import/step1-upload-spec.js +++ b/frontend/cypress/e2e/import/step1-upload-spec.js @@ -2,7 +2,6 @@ import { USERS } from './constants/users'; import { VIEWPORTS } from './constants/common'; import { FILES } from './constants/files'; import { - SELECTOR_IMPORT_UPLOAD_DATASET, SELECTOR_IMPORT_UPLOAD_FILE, SELECTOR_IMPORT_UPLOAD_VALIDATE, } from './constants/selectors'; @@ -29,38 +28,8 @@ describe('Import - Upload step', () => { cy.get(SELECTOR_IMPORT_UPLOAD_VALIDATE).should('exist').should('be.disabled'); }); - it('Should be able to select a jdd', () => { - cy.pickDataset(USER.dataset); - cy.get(`${SELECTOR_IMPORT_UPLOAD_DATASET} > ng-select`) - .should('have.class', 'ng-valid') - .find('.ng-value-label') - .should('exist') - .should('contains.text', USER.dataset); - - cy.get(SELECTOR_IMPORT_UPLOAD_DATASET).find('.ng-clear-wrapper').should('exist').click(); - - cy.get(`${SELECTOR_IMPORT_UPLOAD_DATASET} > ng-select`).should('have.class', 'ng-invalid'); - - cy.pickDataset(USER.dataset); - - cy.get(`${SELECTOR_IMPORT_UPLOAD_DATASET} > ng-select`) - .should('have.class', 'ng-valid') - .find('.ng-value-label') - .should('exist') - .should('contains.text', USER.dataset); - }); - - it('Should access jdd only filtered based on permissions ', () => { - cy.get(`${SELECTOR_IMPORT_UPLOAD_DATASET} > ng-select`) - .click() - .get('.ng-option') - .should('have.length', 1) - .should('contain', USER.dataset); - }); - it('Should throw error if file is empty', () => { // required to trigger file validation - cy.pickDataset(USER.dataset); const file = FILES.synthese.empty; cy.get(file.formErrorElement).should('not.exist'); cy.loadImportFile(file.fixture); @@ -70,7 +39,6 @@ describe('Import - Upload step', () => { it('Should throw error if csv is not valid', () => { // required to trigger file validation - cy.pickDataset(USER.dataset); const file = FILES.synthese.bad; cy.get(file.formErrorElement).should('not.exist'); cy.fixture(file.fixture, null).as('import_file'); diff --git a/frontend/cypress/e2e/import/step3-field-mapping-spec.js b/frontend/cypress/e2e/import/step3-field-mapping-spec.js index 79317eb885..035e2acd8e 100644 --- a/frontend/cypress/e2e/import/step3-field-mapping-spec.js +++ b/frontend/cypress/e2e/import/step3-field-mapping-spec.js @@ -7,6 +7,8 @@ import { SELECTOR_IMPORT_FIELDMAPPING_BUTTON_DELETE, SELECTOR_IMPORT_FIELDMAPPING_BUTTON_DELETE_OK, SELECTOR_IMPORT_FIELDMAPPING_CD_NOM, + SELECTOR_IMPORT_FIELDMAPPING_DEFAULT_DATASET, + SELECTOR_IMPORT_FIELDMAPPING_DATASET, SELECTOR_IMPORT_FIELDMAPPING_DATE_MIN, SELECTOR_IMPORT_FIELDMAPPING_MODAL, SELECTOR_IMPORT_FIELDMAPPING_MODAL_CLOSE, @@ -76,25 +78,14 @@ function fillTheFormRaw() { selectField(SELECTOR_IMPORT_FIELDMAPPING_NOM_CITE, 'date_debut'); selectField(SELECTOR_IMPORT_FIELDMAPPING_WKT, 'date_debut'); selectField(SELECTOR_IMPORT_FIELDMAPPING_CD_NOM, 'date_debut'); + selectField(SELECTOR_IMPORT_FIELDMAPPING_DATASET, 'date_debut'); } function fillTheForm() { // Fill in the form with mandatory field cy.get(SELECTOR_IMPORT_FIELDMAPPING_VALIDATE).should('exist'); - selectField(SELECTOR_IMPORT_FIELDMAPPING_DATE_MIN, 'date_debut'); - cy.get(SELECTOR_IMPORT_FIELDMAPPING_VALIDATE).should('exist').should('not.be.enabled'); - - selectField(SELECTOR_IMPORT_FIELDMAPPING_OBSERVERS, 'date_debut'); - cy.get(SELECTOR_IMPORT_FIELDMAPPING_VALIDATE).should('exist').should('not.be.enabled'); - selectField; - selectField(SELECTOR_IMPORT_FIELDMAPPING_NOM_CITE, 'date_debut'); - cy.get(SELECTOR_IMPORT_FIELDMAPPING_VALIDATE).should('exist').should('not.be.enabled'); - - selectField(SELECTOR_IMPORT_FIELDMAPPING_WKT, 'date_debut'); - cy.get(SELECTOR_IMPORT_FIELDMAPPING_VALIDATE).should('exist').should('not.be.enabled'); - - selectField(SELECTOR_IMPORT_FIELDMAPPING_CD_NOM, 'date_debut'); + fillTheFormRaw(); // Every mandatory field is filled: should be able to validate cy.get(SELECTOR_IMPORT_FIELDMAPPING_VALIDATE).should('exist').should('be.enabled').click(); @@ -113,20 +104,19 @@ function fillTheForm() { cy.wait(TIMEOUT_WAIT); } -function runTheProcess(user) { +function runTheProcess() { cy.visitImport(); cy.startImport(); cy.pickDestination(); - cy.pickDataset(user.dataset); cy.loadImportFile(FILES.synthese.valid.fixture); cy.configureImportFile(); } -function restartTheProcess(user) { +function restartTheProcess() { cy.wait(TIMEOUT_WAIT); cy.deleteCurrentImport(); cy.wait(TIMEOUT_WAIT); - runTheProcess(user); + runTheProcess(); } function checkThatMappingCanBeSaved() { @@ -169,10 +159,19 @@ describe('Import - Field mapping step', () => { beforeEach(() => { cy.viewport(VIEWPORT.width, VIEWPORT.height); cy.geonatureLogin(USER_ADMIN.login.username, USER_ADMIN.login.password); - runTheProcess(USER_ADMIN); + runTheProcess(); cy.get('[data-qa="import-new-fieldmapping-form"]').should('exist'); }); + it('Should access jdd only filtered based on permissions ', () => { + cy.get(`${SELECTOR_IMPORT_FIELDMAPPING_DEFAULT_DATASET}`) + .click() + .get('.ng-option') + .should('have.length', 2) + .should('contain', USER_ADMIN.dataset) + .should('contain', USER_AGENT.dataset); + }); + it('Should be able to create a new field mapping, rename it, and delete it', () => { fillTheForm(); restartTheProcess(USER_ADMIN); @@ -253,7 +252,7 @@ describe('Import - Field mapping step', () => { cy.deleteCurrentImport(); cy.geonatureLogout(); cy.geonatureLogin(USER_AGENT.login.username, USER_AGENT.login.password); - runTheProcess(USER_AGENT); + runTheProcess(); // Check that field mapping does not exist cy.get(SELECTOR_IMPORT_FIELDMAPPING_SELECTION) @@ -268,7 +267,7 @@ describe('Import - Field mapping step', () => { cy.deleteCurrentImport(); cy.geonatureLogout(); cy.geonatureLogin(USER_ADMIN.login.username, USER_ADMIN.login.password); - runTheProcess(USER_ADMIN); + runTheProcess(); // Check that field mapping does exist cy.get(SELECTOR_IMPORT_FIELDMAPPING_SELECTION) @@ -289,7 +288,7 @@ describe('Import - Field mapping step', () => { cy.deleteCurrentImport(); cy.geonatureLogout(); cy.geonatureLogin(USER_AGENT.login.username, USER_AGENT.login.password); - runTheProcess(USER_AGENT); + runTheProcess(); // Create a mapping fillTheForm(); @@ -298,7 +297,7 @@ describe('Import - Field mapping step', () => { cy.deleteCurrentImport(); cy.geonatureLogout(); cy.geonatureLogin(USER_ADMIN.login.username, USER_ADMIN.login.password); - runTheProcess(USER_ADMIN); + runTheProcess(); // Check that field mapping does exist cy.get(SELECTOR_IMPORT_FIELDMAPPING_SELECTION) @@ -317,7 +316,7 @@ describe('Import - Field mapping step', () => { it('Should be able to modifiy the default mapping if user got rights. A save to alternative should be offered to the user.', () => { // Mapping Synthese selectMapping(DEFAULT_FIELDMAPPINGS[0]); - selectField(SELECTOR_IMPORT_FIELDMAPPING_DATE_MIN, 'date_fin'); + selectField(SELECTOR_IMPORT_FIELDMAPPING_DATASET, 'date_fin'); checkThatMappingCanBeSaved(); restartTheProcess(USER_ADMIN); @@ -328,9 +327,9 @@ describe('Import - Field mapping step', () => { it('Should not be able to modifiy the default mapping if user does not got rights', () => { cy.geonatureLogout(); cy.geonatureLogin(USER_AGENT.login.username, USER_AGENT.login.password); - runTheProcess(USER_AGENT); + runTheProcess(); selectMapping(DEFAULT_FIELDMAPPINGS[0]); - selectField(SELECTOR_IMPORT_FIELDMAPPING_DATE_MIN, 'date_fin'); + selectField(SELECTOR_IMPORT_FIELDMAPPING_DATASET, 'date_fin'); checkThatMappingCanNotBeSaved(); }); diff --git a/frontend/cypress/e2e/import/step4-content-mapping-spec.js b/frontend/cypress/e2e/import/step4-content-mapping-spec.js index 352dc0ae82..28ff53fb9b 100644 --- a/frontend/cypress/e2e/import/step4-content-mapping-spec.js +++ b/frontend/cypress/e2e/import/step4-content-mapping-spec.js @@ -19,6 +19,16 @@ import { SELECTOR_IMPORT_CONTENTMAPPING_SELECTION_TEXT, SELECTOR_IMPORT_CONTENTMAPPING_VALIDATE, SELECTOR_IMPORT_NEW_VERIFICATION_START, + SELECTOR_IMPORT_FIELDMAPPING_DEFAULT_DATASET, + SELECTOR_IMPORT_FIELDMAPPING_DATE_MIN, + SELECTOR_IMPORT_FIELDMAPPING_WKT, + SELECTOR_IMPORT_FIELDMAPPING_NOM_CITE, + SELECTOR_IMPORT_FIELDMAPPING_CD_HAB, + SELECTOR_IMPORT_FIELDMAPPING_VALIDATE, + SELECTOR_IMPORT_FIELDMAPPING_MODAL_CLOSE, + SELECTOR_IMPORT_FIELDMAPPING_MODAL_NAME, + SELECTOR_IMPORT_FIELDMAPPING_MODAL_NEW_OK, + SELECTOR_IMPORT_FIELDMAPPING_MODAL_OK, } from './constants/selectors'; // //////////////////////////////////////////////////////////////////////////// @@ -114,28 +124,27 @@ function runTheProcess(user) { cy.visitImport(); cy.startImport(); cy.pickDestination(); - cy.pickDataset(user.dataset); cy.loadImportFile(FILES.synthese.valid.fixture); cy.configureImportFile(); - cy.configureImportFieldMapping(); + cy.configureImportFieldMapping(user.dataset); } function runTheProcessForOcchab(user) { cy.visitImport(); cy.startImport(); cy.pickDestination('Occhab'); - cy.pickDataset(user.dataset); cy.loadImportFile(FILES.synthese.valid.fixture); cy.configureImportFile(); - // cy.configureImportFieldMapping(); - selectFieldMappingField('import-fieldmapping-theme-date_min', 'error'); - selectFieldMappingField('import-fieldmapping-theme-WKT', 'error'); + // cy.configureImportFieldMapping(user.dataset); + selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_DATE_MIN, 'error'); + selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_WKT, 'error'); cy.get('#mat-tab-label-0-1').click(); - selectFieldMappingField('import-fieldmapping-theme-nom_cite', 'error'); - selectFieldMappingField('import-fieldmapping-theme-cd_hab', 'error'); + selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_NOM_CITE, 'error'); + selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_CD_HAB, 'error'); + selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_DEFAULT_DATASET, 'error'); - cy.get('[data-qa="import-new-fieldmapping-model-validate"]').click(); - cy.get('[data-qa="import-fieldmapping-saving-modal-cancel"]', { force: true }).click(); + cy.get(SELECTOR_IMPORT_FIELDMAPPING_VALIDATE).click(); + cy.get(SELECTOR_IMPORT_FIELDMAPPING_MODAL_CANCEL, { force: true }).click(); } function restartTheProcess(user) { diff --git a/frontend/cypress/e2e/import/step5-recaptiulatif-spec.js b/frontend/cypress/e2e/import/step5-recaptiulatif-spec.js index 1ff9303e8e..999bacae31 100644 --- a/frontend/cypress/e2e/import/step5-recaptiulatif-spec.js +++ b/frontend/cypress/e2e/import/step5-recaptiulatif-spec.js @@ -17,10 +17,9 @@ function runTheProcess(user) { cy.visitImport(); cy.startImport(); cy.pickDestination(); - cy.pickDataset(user.dataset); cy.loadImportFile(FILES.synthese.valid.fixture); cy.configureImportFile(); - cy.configureImportFieldMapping(); + cy.configureImportFieldMapping(user.dataset); cy.configureImportContentMapping(); cy.triggerImportVerification(); } diff --git a/frontend/cypress/e2e/import/step6-report-spec.js b/frontend/cypress/e2e/import/step6-report-spec.js index 47c056db9a..0fd870d3d7 100644 --- a/frontend/cypress/e2e/import/step6-report-spec.js +++ b/frontend/cypress/e2e/import/step6-report-spec.js @@ -23,10 +23,9 @@ function runTheProcess(user) { cy.visitImport(); cy.startImport(); cy.pickDestination(); - cy.pickDataset(user.dataset); cy.loadImportFile(FILES.synthese.valid.fixture); cy.configureImportFile(); - cy.configureImportFieldMapping(); + cy.configureImportFieldMapping(user.dataset); cy.configureImportContentMapping(); cy.triggerImportVerification(); cy.executeImport(); diff --git a/frontend/cypress/support/import/configureImportFieldMapping.js b/frontend/cypress/support/import/configureImportFieldMapping.js index 53335b251a..88baae4974 100644 --- a/frontend/cypress/support/import/configureImportFieldMapping.js +++ b/frontend/cypress/support/import/configureImportFieldMapping.js @@ -1,6 +1,7 @@ const DEFAULT_MAPPING = 'Synthese GeoNature'; +const DEFAULT_DATASET = ''; -Cypress.Commands.add('configureImportFieldMapping', () => { +Cypress.Commands.add('configureImportFieldMapping', (datasetName) => { cy.get('[data-qa="import-fieldmapping-selection-select"]') .should('exist') .click() @@ -11,9 +12,24 @@ Cypress.Commands.add('configureImportFieldMapping', () => { cy.wrap(v).should('exist').click(); }); + cy.get('[data-qa="import-fieldmapping-theme-default-unique_dataset_id"] ng-select') + .should('exist') + .click() + .get('ng-dropdown-panel') + .get('.ng-option') + .contains(datasetName) + .then((dataset) => { + cy.wrap(dataset).should('exist').click(); + }); + // Every mandatory field is filled: should be able to validate cy.get('[data-qa="import-new-fieldmapping-model-validate"]') .should('exist') .should('be.enabled') .click(); + + cy.get('[data-qa="import-fieldmapping-saving-modal-cancel"]') + .should('exist') + .should('be.enabled') + .click(); }); diff --git a/frontend/cypress/support/import/index.js b/frontend/cypress/support/import/index.js index aac0a74e1e..867cf09f00 100644 --- a/frontend/cypress/support/import/index.js +++ b/frontend/cypress/support/import/index.js @@ -17,7 +17,6 @@ import './getGlobalConfig'; import './getRowIndexByCellValue'; import './hasToastError'; import './loadImportFile'; -import './pickDataset'; import './pickDestination'; import './removeFirstImportInList'; import './startImport'; diff --git a/frontend/cypress/support/import/pickDataset.js b/frontend/cypress/support/import/pickDataset.js deleted file mode 100644 index 33ac7265a2..0000000000 --- a/frontend/cypress/support/import/pickDataset.js +++ /dev/null @@ -1,11 +0,0 @@ -Cypress.Commands.add('pickDataset', (datasetName) => { - cy.get('[data-qa="import-new-upload-datasets"]') - .should('exist') - .click() - .get('ng-dropdown-panel') - .get('.ng-option') - .contains(datasetName) - .then((dataset) => { - cy.wrap(dataset).should('exist').click(); - }); -}); diff --git a/frontend/src/app/GN2CommonModule/form/dynamic-form/dynamic-form.component.html b/frontend/src/app/GN2CommonModule/form/dynamic-form/dynamic-form.component.html index cc661a40e9..6cac2ecb1b 100644 --- a/frontend/src/app/GN2CommonModule/form/dynamic-form/dynamic-form.component.html +++ b/frontend/src/app/GN2CommonModule/form/dynamic-form/dynamic-form.component.html @@ -11,7 +11,7 @@ 'number', 'file', 'medias', - 'bool_radio', + 'bool_radio' ].includes(formDefComp['type_widget']) " > diff --git a/frontend/src/app/modules/imports/components/import_process/fields-mapping-step/mapping-theme/mapping-theme.component.html b/frontend/src/app/modules/imports/components/import_process/fields-mapping-step/mapping-theme/mapping-theme.component.html index a1ec086102..399467f20b 100644 --- a/frontend/src/app/modules/imports/components/import_process/fields-mapping-step/mapping-theme/mapping-theme.component.html +++ b/frontend/src/app/modules/imports/components/import_process/fields-mapping-step/mapping-theme/mapping-theme.component.html @@ -91,6 +91,7 @@ class="d-block mt-2" [formDef]="defaultValueFormDefs[field.name_field]" [form]="_fm.mappingFormGroup" + [attr.data-qa]="'import-fieldmapping-theme-default-' + field.name_field" >
    Date: Thu, 23 Jan 2025 12:34:27 +0100 Subject: [PATCH 03/14] fix: remove debnug patch --- backend/geonature/core/gn_meta/models/datasets.py | 2 +- backend/geonature/core/gn_synthese/models.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/geonature/core/gn_meta/models/datasets.py b/backend/geonature/core/gn_meta/models/datasets.py index 417abe70a3..eacb7785e8 100644 --- a/backend/geonature/core/gn_meta/models/datasets.py +++ b/backend/geonature/core/gn_meta/models/datasets.py @@ -19,6 +19,7 @@ from geonature.core.gn_permissions.tools import get_scopes_by_action from geonature.core.gn_commons.models import cor_field_dataset, cor_module_dataset +from ref_geo.models import LAreas from .commons import * @@ -345,7 +346,6 @@ def filter_by_creatable(cls, module_code, *, query, user=None, object_code=None) @qfilter(query=True) def filter_by_areas(cls, areas, *, query): from geonature.core.gn_synthese.models import Synthese - from ref_geo.models import LAreas areaFilter = [] for id_area in areas: diff --git a/backend/geonature/core/gn_synthese/models.py b/backend/geonature/core/gn_synthese/models.py index e991a5d0c5..9a572c9a75 100644 --- a/backend/geonature/core/gn_synthese/models.py +++ b/backend/geonature/core/gn_synthese/models.py @@ -434,7 +434,7 @@ class Synthese(DB.Model): meta_update_date = DB.Column(DB.DateTime, server_default=FetchedValue()) last_action = DB.Column(DB.Unicode) - # areas = relationship(LAreas, secondary=corAreaSynthese, backref="synthese_obs") + areas = relationship(LAreas, secondary=corAreaSynthese, backref="synthese_obs") area_attachment = relationship(LAreas, foreign_keys=[id_area_attachment]) validations = relationship(TValidations, backref="attached_row") last_validation = relationship(last_validation, uselist=False, viewonly=True) From 5c5bef333bccf0f96e2f6fbfd92b91a7a6a31dd6 Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Fri, 24 Jan 2025 12:56:26 +0100 Subject: [PATCH 04/14] feat: adjust id_dataset and import relation in frontend testing alembic branch --- .../migrations/data/imports/sample_data.sql | 59 ++++++++----------- .../a81f74d0a518_insert_import_sample_data.py | 27 ++------- ...alid_file_import_synthese_test_changed.csv | 12 ++-- ...id_file_test_link_list_import_synthese.csv | 14 ++--- 4 files changed, 43 insertions(+), 69 deletions(-) diff --git a/backend/geonature/migrations/data/imports/sample_data.sql b/backend/geonature/migrations/data/imports/sample_data.sql index bc81e25297..9bdd365401 100644 --- a/backend/geonature/migrations/data/imports/sample_data.sql +++ b/backend/geonature/migrations/data/imports/sample_data.sql @@ -20,6 +20,7 @@ FROM utilisateurs.bib_organismes WHERE nom_organisme = 'Autre'; -- Step 2: Insert data INSERT INTO utilisateurs.t_roles ( + id_role, groupe, identifiant, nom_role, @@ -34,6 +35,7 @@ INSERT INTO utilisateurs.t_roles ( pass_plus ) VALUES ( + 9999, false, 'admin-test-import', 'Administrateur-test-import', @@ -49,6 +51,7 @@ VALUES ( '$2y$13$TMuRXgvIg6/aAez0lXLLFu0lyPk4m8N55NDhvLoUHh/Ar3rFzjFT.' ), ( + 9998, false, 'agent-test-import', 'Agent-test-import', @@ -894,7 +897,6 @@ VALUES ( -- #On peuple la liste d'import INSERT INTO gn_imports.t_imports ( id_import, - id_dataset, id_destination, format_source_file, srid, @@ -914,11 +916,6 @@ INSERT INTO gn_imports.t_imports ( ) VALUES ( 1000, - ( - SELECT id_dataset - FROM gn_meta.t_datasets - WHERE unique_dataset_id = '2f543d86-ec4e-4f1a-b4d9-123456789abc' - ), ( SELECT id_destination FROM gn_imports.bib_destinations @@ -942,11 +939,6 @@ VALUES ( ), ( 1001, - ( - SELECT id_dataset - FROM gn_meta.t_datasets - WHERE unique_dataset_id = '9f86d081-8292-466e-9e7b-16f3960d255f' - ), ( SELECT id_destination FROM gn_imports.bib_destinations @@ -970,11 +962,6 @@ VALUES ( ), ( 1002, - ( - SELECT id_dataset - FROM gn_meta.t_datasets - WHERE unique_dataset_id = 'a1b2c3d4-e5f6-4a3b-2c1d-e6f5a4b3c2d1' - ), ( SELECT id_destination FROM gn_imports.bib_destinations @@ -998,11 +985,6 @@ VALUES ( ), ( 1003, - ( - SELECT id_dataset - FROM gn_meta.t_datasets - WHERE unique_dataset_id = '5f45d560-1ce3-420c-b45c-3d589eedaee1' - ), ( SELECT id_destination FROM gn_imports.bib_destinations @@ -1024,17 +1006,26 @@ VALUES ( NULL, '{5}' ); --- On peuple les tables de correspondances - Ajout des roles lié aux imports -CREATE TEMP TABLE temp_filtered_imports AS -SELECT ti.id_import, - ti.id_dataset -FROM gn_imports.t_imports ti - JOIN gn_meta.t_datasets td ON ti.id_dataset = td.id_dataset -WHERE td.dataset_name ILIKE '%JDD-TEST-IMPORT%'; INSERT INTO gn_imports.cor_role_import (id_role, id_import) -SELECT cda.id_role, - tfi.id_import -FROM temp_filtered_imports tfi - JOIN gn_meta.cor_dataset_actor cda ON tfi.id_dataset = cda.id_dataset -WHERE cda.id_role IS NOT NULL; -DROP TABLE temp_filtered_imports; +VALUES + ( + 9999, + 1000 + ), + ( + 9998, + 1000 + ), + ( + 9999, + 1001 + ), + ( + 9999, + 1002 + ), + ( + 9999, + 1003 + ); + diff --git a/backend/geonature/migrations/versions/imports/a81f74d0a518_insert_import_sample_data.py b/backend/geonature/migrations/versions/imports/a81f74d0a518_insert_import_sample_data.py index b061650e66..abe6e77a6a 100644 --- a/backend/geonature/migrations/versions/imports/a81f74d0a518_insert_import_sample_data.py +++ b/backend/geonature/migrations/versions/imports/a81f74d0a518_insert_import_sample_data.py @@ -31,11 +31,8 @@ def downgrade(): op.execute( """ DELETE FROM gn_imports.t_imports - WHERE id_dataset IN ( - (SELECT id_dataset FROM gn_meta.t_datasets WHERE unique_dataset_id = 'a1b2c3d4-e5f6-4a3b-2c1d-e6f5a4b3c2d1'), - (SELECT id_dataset FROM gn_meta.t_datasets WHERE unique_dataset_id = '9f86d081-8292-466e-9e7b-16f3960d255f'), - (SELECT id_dataset FROM gn_meta.t_datasets WHERE unique_dataset_id = '2f543d86-ec4e-4f1a-b4d9-123456789abc'), - (SELECT id_dataset FROM gn_meta.t_datasets WHERE unique_dataset_id = '5f45d560-1ce3-420c-b45c-3d589eedaee1') + WHERE id_import IN ( + 1000,1001,1002,1003 ); """ ) @@ -128,29 +125,15 @@ def downgrade(): """ ) - # Step 1: Create a temporary table to hold the filtered imports - op.execute( - """ - CREATE TEMP TABLE temp_filtered_imports AS - SELECT ti.id_import - FROM gn_imports.t_imports ti - JOIN gn_meta.t_datasets td ON ti.id_dataset = td.id_dataset - WHERE td.dataset_name ILIKE '%JDD-TEST-IMPORT%'; - """ - ) - # Step 2: Delete the relevant records from cor_role_import + # Delete the relevant records from cor_role_import op.execute( - """ + """ DELETE FROM gn_imports.cor_role_import cri - USING temp_filtered_imports tfi - WHERE cri.id_import in (tfi.id_import); + WHERE cri.id_import in (1000, 1001, 1002, 1003); """ ) - # Clean up temporary table - op.execute("DROP TABLE temp_filtered_imports;") - ## Clean users test # Delete permissions for admin-test-import op.execute( diff --git a/frontend/cypress/fixtures/import/synthese/valid_file_import_synthese_test_changed.csv b/frontend/cypress/fixtures/import/synthese/valid_file_import_synthese_test_changed.csv index 1c12d057f1..c5354abbac 100644 --- a/frontend/cypress/fixtures/import/synthese/valid_file_import_synthese_test_changed.csv +++ b/frontend/cypress/fixtures/import/synthese/valid_file_import_synthese_test_changed.csv @@ -1,7 +1,7 @@ error;id_synthese;id_origine;comment_releve;comment_occurrence;date_debut;date_fin;heure_debut;heure_fin;cd_nom;cd_ref;nom_valide;nom_vernaculaire;nom_cite;regne;group1_inpn;group2_inpn;classe;ordre;famille;rang_taxo;nombre_min;nombre_max;alti_min;alti_max;prof_min;prof_max;observateurs;determinateur;communes;geometrie_wkt_4326;x_centroid_4326;y_centroid_4326;nom_lieu;validateur;niveau_validation;date_validation;comment_validation;preuve_numerique_url;preuve_non_numerique;jdd_nom;jdd_uuid;jdd_id;ca_nom;ca_uuid;ca_id;cd_habref;cd_habitat;nom_habitat;precision_geographique;nature_objet_geo;type_regroupement;methode_regroupement;technique_observation;biologique_statut;etat_biologique;biogeographique_statut;naturalite;preuve_existante;niveau_precision_diffusion;stade_vie;sexe;objet_denombrement;type_denombrement;niveau_sensibilite;statut_observation;floutage_dee;statut_source;type_info_geo;methode_determination;comportement;reference_biblio;uuid_perm_sinp;uuid_perm_grp_sinp;date_creation;date_modification -valid;1;1;Relevé n°1;Occurrence n°1;2017-01-01;2017-01-01;12:05:02;12:05:02;60612;60612;Lynx lynx (Linnaeus, 1758);;Lynx Boréal;Animalia;Chordés;Mammifères;Mammalia;Carnivora;Felidae;ES;5;5;1500;1565;;;Administrateur test;Gil;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poil;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Adulte;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;b4f85a2e-dd88-4cdd-aa86-f1c7370faf3f;5b427c76-bd8c-4103-a33c-884c7037aa2b;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -valid;2;2;Relevé n°2;Occurrence n°2;2017-01-01;2017-01-02;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1500;1565;;;Administrateur test;Théo;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Immature;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;830c93c7-288e-40f0-a17f-15fbb50e643a;5b427c76-bd8c-4103-a33c-884c7037aa2b;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -duplicate id;3;3;Relevé n°3;Occurrence n°3;2017-01-08;;;;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e3;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -duplicate id;3;4;Relevé n°4;Occurrence n°4;2017-01-08;2017-01-08;20:00:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e4;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -count min > count max;5;5;Relevé n°5;Occurrence n°5;2017-01-08;2017/01/08;20:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;20;5;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e5;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -valid;6;6;Relevé n°6;Occurrence n°6;2017-01-01;2017-01-01;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;f5515e2a-b30d-11eb-8cc8-af8c2d0867b4;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +valid;1;1;Relevé n°1;Occurrence n°1;2017-01-01;2017-01-01;12:05:02;12:05:02;60612;60612;Lynx lynx (Linnaeus, 1758);;Lynx Boréal;Animalia;Chordés;Mammifères;Mammalia;Carnivora;Felidae;ES;5;5;1500;1565;;;Administrateur test;Gil;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poil;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Adulte;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +valid;2;2;Relevé n°2;Occurrence n°2;2017-01-01;2017-01-02;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1500;1565;;;Administrateur test;Théo;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Immature;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +duplicate id;3;3;Relevé n°3;Occurrence n°3;2017-01-08;;;;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +duplicate id;3;4;Relevé n°4;Occurrence n°4;2017-01-08;2017-01-08;20:00:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +count min > count max;5;5;Relevé n°5;Occurrence n°5;2017-01-08;2017/01/08;20:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;20;5;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +valid;6;6;Relevé n°6;Occurrence n°6;2017-01-01;2017-01-01;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 diff --git a/frontend/cypress/fixtures/import/synthese/valid_file_test_link_list_import_synthese.csv b/frontend/cypress/fixtures/import/synthese/valid_file_test_link_list_import_synthese.csv index 1c12d057f1..a076624950 100644 --- a/frontend/cypress/fixtures/import/synthese/valid_file_test_link_list_import_synthese.csv +++ b/frontend/cypress/fixtures/import/synthese/valid_file_test_link_list_import_synthese.csv @@ -1,7 +1,7 @@ -error;id_synthese;id_origine;comment_releve;comment_occurrence;date_debut;date_fin;heure_debut;heure_fin;cd_nom;cd_ref;nom_valide;nom_vernaculaire;nom_cite;regne;group1_inpn;group2_inpn;classe;ordre;famille;rang_taxo;nombre_min;nombre_max;alti_min;alti_max;prof_min;prof_max;observateurs;determinateur;communes;geometrie_wkt_4326;x_centroid_4326;y_centroid_4326;nom_lieu;validateur;niveau_validation;date_validation;comment_validation;preuve_numerique_url;preuve_non_numerique;jdd_nom;jdd_uuid;jdd_id;ca_nom;ca_uuid;ca_id;cd_habref;cd_habitat;nom_habitat;precision_geographique;nature_objet_geo;type_regroupement;methode_regroupement;technique_observation;biologique_statut;etat_biologique;biogeographique_statut;naturalite;preuve_existante;niveau_precision_diffusion;stade_vie;sexe;objet_denombrement;type_denombrement;niveau_sensibilite;statut_observation;floutage_dee;statut_source;type_info_geo;methode_determination;comportement;reference_biblio;uuid_perm_sinp;uuid_perm_grp_sinp;date_creation;date_modification -valid;1;1;Relevé n°1;Occurrence n°1;2017-01-01;2017-01-01;12:05:02;12:05:02;60612;60612;Lynx lynx (Linnaeus, 1758);;Lynx Boréal;Animalia;Chordés;Mammifères;Mammalia;Carnivora;Felidae;ES;5;5;1500;1565;;;Administrateur test;Gil;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poil;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Adulte;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;b4f85a2e-dd88-4cdd-aa86-f1c7370faf3f;5b427c76-bd8c-4103-a33c-884c7037aa2b;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -valid;2;2;Relevé n°2;Occurrence n°2;2017-01-01;2017-01-02;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1500;1565;;;Administrateur test;Théo;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Immature;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;830c93c7-288e-40f0-a17f-15fbb50e643a;5b427c76-bd8c-4103-a33c-884c7037aa2b;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -duplicate id;3;3;Relevé n°3;Occurrence n°3;2017-01-08;;;;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e3;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -duplicate id;3;4;Relevé n°4;Occurrence n°4;2017-01-08;2017-01-08;20:00:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e4;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -count min > count max;5;5;Relevé n°5;Occurrence n°5;2017-01-08;2017/01/08;20:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;20;5;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e5;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -valid;6;6;Relevé n°6;Occurrence n°6;2017-01-01;2017-01-01;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;f5515e2a-b30d-11eb-8cc8-af8c2d0867b4;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +error;id_synthese;id_origine;comment_releve;comment_occurrence;date_debut;date_fin;heure_debut;heure_fin;cd_nom;cd_ref;nom_valide;nom_vernaculaire;nom_cite;regne;group1_inpn;group2_inpn;classe;ordre;famille;rang_taxo;nombre_min;nombre_max;alti_min;alti_max;prof_min;prof_max;observateurs;determinateur;communes;geometrie_wkt_4326;x_centroid_4326;y_centroid_4326;nom_lieu;validateur;niveau_validation;date_validation;comment_validation;preuve_numerique_url;preuve_non_numerique;cd_habref;cd_habitat;nom_habitat;precision_geographique;nature_objet_geo;type_regroupement;methode_regroupement;technique_observation;biologique_statut;etat_biologique;biogeographique_statut;naturalite;preuve_existante;niveau_precision_diffusion;stade_vie;sexe;objet_denombrement;type_denombrement;niveau_sensibilite;statut_observation;floutage_dee;statut_source;type_info_geo;methode_determination;comportement;reference_biblio;uuid_perm_sinp;uuid_perm_grp_sinp;date_creation;date_modification +valid;1;1;Relevé n°1;Occurrence n°1;2017-01-01;2017-01-01;12:05:02;12:05:02;60612;60612;Lynx lynx (Linnaeus, 1758);;Lynx Boréal;Animalia;Chordés;Mammifères;Mammalia;Carnivora;Felidae;ES;5;5;1500;1565;;;Administrateur test;Gil;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poil;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Adulte;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +valid;2;2;Relevé n°2;Occurrence n°2;2017-01-01;2017-01-02;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1500;1565;;;Administrateur test;Théo;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Immature;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +duplicate id;3;3;Relevé n°3;Occurrence n°3;2017-01-08;;;;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +duplicate id;3;4;Relevé n°4;Occurrence n°4;2017-01-08;2017-01-08;20:00:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +count min > count max;5;5;Relevé n°5;Occurrence n°5;2017-01-08;2017/01/08;20:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;20;5;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +valid;6;6;Relevé n°6;Occurrence n°6;2017-01-01;2017-01-01;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 From 4b525d386a7639bd57379cb060043cb6aa3422ca Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Fri, 24 Jan 2025 13:42:48 +0100 Subject: [PATCH 05/14] fix: content mapping step --- .../e2e/import/step4-content-mapping-spec.js | 22 ++++++++----------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/frontend/cypress/e2e/import/step4-content-mapping-spec.js b/frontend/cypress/e2e/import/step4-content-mapping-spec.js index 28ff53fb9b..61488aac6b 100644 --- a/frontend/cypress/e2e/import/step4-content-mapping-spec.js +++ b/frontend/cypress/e2e/import/step4-content-mapping-spec.js @@ -19,16 +19,13 @@ import { SELECTOR_IMPORT_CONTENTMAPPING_SELECTION_TEXT, SELECTOR_IMPORT_CONTENTMAPPING_VALIDATE, SELECTOR_IMPORT_NEW_VERIFICATION_START, - SELECTOR_IMPORT_FIELDMAPPING_DEFAULT_DATASET, + SELECTOR_IMPORT_FIELDMAPPING_DATASET, SELECTOR_IMPORT_FIELDMAPPING_DATE_MIN, SELECTOR_IMPORT_FIELDMAPPING_WKT, SELECTOR_IMPORT_FIELDMAPPING_NOM_CITE, SELECTOR_IMPORT_FIELDMAPPING_CD_HAB, SELECTOR_IMPORT_FIELDMAPPING_VALIDATE, - SELECTOR_IMPORT_FIELDMAPPING_MODAL_CLOSE, - SELECTOR_IMPORT_FIELDMAPPING_MODAL_NAME, - SELECTOR_IMPORT_FIELDMAPPING_MODAL_NEW_OK, - SELECTOR_IMPORT_FIELDMAPPING_MODAL_OK, + SELECTOR_IMPORT_FIELDMAPPING_MODAL_CANCEL, } from './constants/selectors'; // //////////////////////////////////////////////////////////////////////////// @@ -133,15 +130,14 @@ function runTheProcessForOcchab(user) { cy.visitImport(); cy.startImport(); cy.pickDestination('Occhab'); - cy.loadImportFile(FILES.synthese.valid.fixture); + cy.loadImportFile(FILES.occhab.valid.fixture); cy.configureImportFile(); - // cy.configureImportFieldMapping(user.dataset); - selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_DATE_MIN, 'error'); - selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_WKT, 'error'); + selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_DATE_MIN, 'date_debut'); + selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_WKT, 'date_debut'); + selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_DATASET, 'date_debut'); cy.get('#mat-tab-label-0-1').click(); - selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_NOM_CITE, 'error'); - selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_CD_HAB, 'error'); - selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_DEFAULT_DATASET, 'error'); + selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_NOM_CITE, 'date_debut'); + selectFieldMappingField(SELECTOR_IMPORT_FIELDMAPPING_CD_HAB, 'date_debut'); cy.get(SELECTOR_IMPORT_FIELDMAPPING_VALIDATE).click(); cy.get(SELECTOR_IMPORT_FIELDMAPPING_MODAL_CANCEL, { force: true }).click(); @@ -155,7 +151,7 @@ function restartTheProcess(user) { // Occhab dedicated function selectFieldMappingField(dataQa, value) { - cy.get(`[data-qa="${dataQa}"]`) + cy.get(dataQa) .should('exist') .click() .get('ng-dropdown-panel >') From c1f743e80c197f92a7044f0338ce8cc09817a11a Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Fri, 24 Jan 2025 13:48:25 +0100 Subject: [PATCH 06/14] feat: dix some frontend tests lint --- .../a81f74d0a518_insert_import_sample_data.py | 3 +-- .../cypress/e2e/import/step6-report-spec.js | 25 +++++++------------ .../fixtures/import/synthese/invalid_data.csv | 8 +++--- 3 files changed, 14 insertions(+), 22 deletions(-) diff --git a/backend/geonature/migrations/versions/imports/a81f74d0a518_insert_import_sample_data.py b/backend/geonature/migrations/versions/imports/a81f74d0a518_insert_import_sample_data.py index abe6e77a6a..50c6ac4999 100644 --- a/backend/geonature/migrations/versions/imports/a81f74d0a518_insert_import_sample_data.py +++ b/backend/geonature/migrations/versions/imports/a81f74d0a518_insert_import_sample_data.py @@ -125,10 +125,9 @@ def downgrade(): """ ) - # Delete the relevant records from cor_role_import op.execute( - """ + """ DELETE FROM gn_imports.cor_role_import cri WHERE cri.id_import in (1000, 1001, 1002, 1003); """ diff --git a/frontend/cypress/e2e/import/step6-report-spec.js b/frontend/cypress/e2e/import/step6-report-spec.js index 0fd870d3d7..58bac4c25f 100644 --- a/frontend/cypress/e2e/import/step6-report-spec.js +++ b/frontend/cypress/e2e/import/step6-report-spec.js @@ -67,23 +67,16 @@ describe('Import - Report step', () => { cy.deleteFile(FILENAME_INVALID_DATA, DOWNLOADS_FOLDER); }); - cy.url().then((url) => { - // Extract the ID using string manipulation - const parts = url.split('/'); - const importID = parts[parts.length - 2]; // Get the penultimate element - const destination = parts[parts.length - 3]; - - // PDF report - cy.get(SELECTOR_IMPORT_REPORT_DOWNLOAD_PDF).click({ - force: true, - }); + // PDF report + cy.get(SELECTOR_IMPORT_REPORT_DOWNLOAD_PDF).click({ + force: true, + }); - cy.wait(TIMEOUT_WAIT); - // https://github.com/cypress-io/cypress/issues/25443 - cy.task('getLastDownloadFileName', DOWNLOADS_FOLDER).then((filename) => { - cy.verifyDownload(filename, DOWNLOADS_FOLDER); - cy.deleteFile(filename, DOWNLOADS_FOLDER); - }); + cy.wait(TIMEOUT_WAIT); + // https://github.com/cypress-io/cypress/issues/25443 + cy.task('getLastDownloadFileName', DOWNLOADS_FOLDER).then((filename) => { + cy.verifyDownload(filename, DOWNLOADS_FOLDER); + cy.deleteFile(filename, DOWNLOADS_FOLDER); }); }); diff --git a/frontend/cypress/fixtures/import/synthese/invalid_data.csv b/frontend/cypress/fixtures/import/synthese/invalid_data.csv index 82e9687ad6..4d358c967f 100644 --- a/frontend/cypress/fixtures/import/synthese/invalid_data.csv +++ b/frontend/cypress/fixtures/import/synthese/invalid_data.csv @@ -1,4 +1,4 @@ -error;id_synthese;id_origine;comment_releve;comment_occurrence;date_debut;date_fin;heure_debut;heure_fin;cd_nom;cd_ref;nom_valide;nom_vernaculaire;nom_cite;regne;group1_inpn;group2_inpn;classe;ordre;famille;rang_taxo;nombre_min;nombre_max;alti_min;alti_max;prof_min;prof_max;observateurs;determinateur;communes;geometrie_wkt_4326;x_centroid_4326;y_centroid_4326;nom_lieu;validateur;niveau_validation;date_validation;comment_validation;preuve_numerique_url;preuve_non_numerique;jdd_nom;jdd_uuid;jdd_id;ca_nom;ca_uuid;ca_id;cd_habref;cd_habitat;nom_habitat;precision_geographique;nature_objet_geo;type_regroupement;methode_regroupement;technique_observation;biologique_statut;etat_biologique;biogeographique_statut;naturalite;preuve_existante;niveau_precision_diffusion;stade_vie;sexe;objet_denombrement;type_denombrement;niveau_sensibilite;statut_observation;floutage_dee;statut_source;type_info_geo;methode_determination;comportement;reference_biblio;uuid_perm_sinp;uuid_perm_grp_sinp;date_creation;date_modification -duplicate id;3;3;Relevé n°3;Occurrence n°3;2017-01-08;;;;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e3;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -duplicate id;3;4;Relevé n°4;Occurrence n°4;2017-01-08;2017-01-08;20:00:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e4;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -count min > count max;5;5;Relevé n°5;Occurrence n°5;2017-01-08;2017/01/08;20:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;20;5;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e5;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +error;id_synthese;id_origine;comment_releve;comment_occurrence;date_debut;date_fin;heure_debut;heure_fin;cd_nom;cd_ref;nom_valide;nom_vernaculaire;nom_cite;regne;group1_inpn;group2_inpn;classe;ordre;famille;rang_taxo;nombre_min;nombre_max;alti_min;alti_max;prof_min;prof_max;observateurs;determinateur;communes;geometrie_wkt_4326;x_centroid_4326;y_centroid_4326;nom_lieu;validateur;niveau_validation;date_validation;comment_validation;preuve_numerique_url;preuve_non_numerique;cd_habref;cd_habitat;nom_habitat;precision_geographique;nature_objet_geo;type_regroupement;methode_regroupement;technique_observation;biologique_statut;etat_biologique;biogeographique_statut;naturalite;preuve_existante;niveau_precision_diffusion;stade_vie;sexe;objet_denombrement;type_denombrement;niveau_sensibilite;statut_observation;floutage_dee;statut_source;type_info_geo;methode_determination;comportement;reference_biblio;uuid_perm_sinp;uuid_perm_grp_sinp;date_creation;date_modification +duplicate id;3;3;Relevé n°3;Occurrence n°3;2017-01-08;;;;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +duplicate id;3;4;Relevé n°4;Occurrence n°4;2017-01-08;2017-01-08;20:00:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +count min > count max;5;5;Relevé n°5;Occurrence n°5;2017-01-08;2017/01/08;20:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;20;5;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 From 274908cf4b0be0756b2715cb4d8a6a7098ad1209 Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Fri, 24 Jan 2025 14:51:49 +0100 Subject: [PATCH 07/14] fix: some backend tests by removing default uuid for sinp data --- .../tests/imports/files/synthese/valid_file.csv | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/geonature/tests/imports/files/synthese/valid_file.csv b/backend/geonature/tests/imports/files/synthese/valid_file.csv index 1c12d057f1..c5354abbac 100644 --- a/backend/geonature/tests/imports/files/synthese/valid_file.csv +++ b/backend/geonature/tests/imports/files/synthese/valid_file.csv @@ -1,7 +1,7 @@ error;id_synthese;id_origine;comment_releve;comment_occurrence;date_debut;date_fin;heure_debut;heure_fin;cd_nom;cd_ref;nom_valide;nom_vernaculaire;nom_cite;regne;group1_inpn;group2_inpn;classe;ordre;famille;rang_taxo;nombre_min;nombre_max;alti_min;alti_max;prof_min;prof_max;observateurs;determinateur;communes;geometrie_wkt_4326;x_centroid_4326;y_centroid_4326;nom_lieu;validateur;niveau_validation;date_validation;comment_validation;preuve_numerique_url;preuve_non_numerique;jdd_nom;jdd_uuid;jdd_id;ca_nom;ca_uuid;ca_id;cd_habref;cd_habitat;nom_habitat;precision_geographique;nature_objet_geo;type_regroupement;methode_regroupement;technique_observation;biologique_statut;etat_biologique;biogeographique_statut;naturalite;preuve_existante;niveau_precision_diffusion;stade_vie;sexe;objet_denombrement;type_denombrement;niveau_sensibilite;statut_observation;floutage_dee;statut_source;type_info_geo;methode_determination;comportement;reference_biblio;uuid_perm_sinp;uuid_perm_grp_sinp;date_creation;date_modification -valid;1;1;Relevé n°1;Occurrence n°1;2017-01-01;2017-01-01;12:05:02;12:05:02;60612;60612;Lynx lynx (Linnaeus, 1758);;Lynx Boréal;Animalia;Chordés;Mammifères;Mammalia;Carnivora;Felidae;ES;5;5;1500;1565;;;Administrateur test;Gil;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poil;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Adulte;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;b4f85a2e-dd88-4cdd-aa86-f1c7370faf3f;5b427c76-bd8c-4103-a33c-884c7037aa2b;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -valid;2;2;Relevé n°2;Occurrence n°2;2017-01-01;2017-01-02;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1500;1565;;;Administrateur test;Théo;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Immature;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;830c93c7-288e-40f0-a17f-15fbb50e643a;5b427c76-bd8c-4103-a33c-884c7037aa2b;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -duplicate id;3;3;Relevé n°3;Occurrence n°3;2017-01-08;;;;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e3;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -duplicate id;3;4;Relevé n°4;Occurrence n°4;2017-01-08;2017-01-08;20:00:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e4;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -count min > count max;5;5;Relevé n°5;Occurrence n°5;2017-01-08;2017/01/08;20:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;20;5;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e5;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 -valid;6;6;Relevé n°6;Occurrence n°6;2017-01-01;2017-01-01;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;f5515e2a-b30d-11eb-8cc8-af8c2d0867b4;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +valid;1;1;Relevé n°1;Occurrence n°1;2017-01-01;2017-01-01;12:05:02;12:05:02;60612;60612;Lynx lynx (Linnaeus, 1758);;Lynx Boréal;Animalia;Chordés;Mammifères;Mammalia;Carnivora;Felidae;ES;5;5;1500;1565;;;Administrateur test;Gil;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poil;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Adulte;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +valid;2;2;Relevé n°2;Occurrence n°2;2017-01-01;2017-01-02;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1500;1565;;;Administrateur test;Théo;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Immature;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +duplicate id;3;3;Relevé n°3;Occurrence n°3;2017-01-08;;;;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +duplicate id;3;4;Relevé n°4;Occurrence n°4;2017-01-08;2017-01-08;20:00:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +count min > count max;5;5;Relevé n°5;Occurrence n°5;2017-01-08;2017/01/08;20:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;20;5;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +valid;6;6;Relevé n°6;Occurrence n°6;2017-01-01;2017-01-01;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;;;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 From 60cb87b90ab99d899633b128464e21daaacd946f Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Fri, 24 Jan 2025 16:23:32 +0100 Subject: [PATCH 08/14] try fix: conditional removal of unqieu_dataset_id --- .../backend/gn_module_occhab/imports/actions.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py b/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py index 35bab7a234..b57502294d 100644 --- a/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py +++ b/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py @@ -492,6 +492,8 @@ def import_data_to_destination(imprt: TImports) -> None: insert_fields |= {field} if entity.code == "station": # unique_dataset_id is replaced with id_dataset + if "unique_dataset_id" in fields and fields["unique_dataset_id"] in insert_fields: + insert_fields -= {fields["unique_dataset_id"]} # insert_fields -= {fields["unique_dataset_id"]} insert_fields |= {fields["id_dataset"]} insert_fields |= {fields["geom_4326"], fields["geom_local"]} From 03e61af1c528a934a9b57457ba3ec32333ebd150 Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Fri, 24 Jan 2025 16:42:11 +0100 Subject: [PATCH 09/14] try fix: move revision to geonature branch --- ...572f71f_import_monitorings_adjust_gn_imports_.py} | 12 ++++++------ .../backend/gn_module_occhab/imports/actions.py | 3 --- 2 files changed, 6 insertions(+), 9 deletions(-) rename backend/geonature/migrations/versions/{imports/a43842db7ac1_monitorings_adjust_gn_imports_bib_.py => 51ee1572f71f_import_monitorings_adjust_gn_imports_.py} (89%) diff --git a/backend/geonature/migrations/versions/imports/a43842db7ac1_monitorings_adjust_gn_imports_bib_.py b/backend/geonature/migrations/versions/51ee1572f71f_import_monitorings_adjust_gn_imports_.py similarity index 89% rename from backend/geonature/migrations/versions/imports/a43842db7ac1_monitorings_adjust_gn_imports_bib_.py rename to backend/geonature/migrations/versions/51ee1572f71f_import_monitorings_adjust_gn_imports_.py index e50086b726..7b3188512c 100644 --- a/backend/geonature/migrations/versions/imports/a43842db7ac1_monitorings_adjust_gn_imports_bib_.py +++ b/backend/geonature/migrations/versions/51ee1572f71f_import_monitorings_adjust_gn_imports_.py @@ -1,8 +1,8 @@ -"""[monitorings] Adjust gn.imports bib_fields id_dataset and unique_id_dataset values +"""[import.monitorings] Adjust gn.imports bib_fields id_dataset and unique_id_dataset values -Revision ID: a43842db7ac1 -Revises: 2b0b3bd0248c -Create Date: 2024-12-17 11:18:07.806852 +Revision ID: 51ee1572f71f +Revises: df277299fdda +Create Date: 2025-01-24 16:38:46.007151 """ @@ -11,8 +11,8 @@ # revision identifiers, used by Alembic. -revision = "a43842db7ac1" -down_revision = "2b0b3bd0248c" +revision = "51ee1572f71f" +down_revision = "df277299fdda" branch_labels = None depends_on = None diff --git a/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py b/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py index b57502294d..ab8962fcd2 100644 --- a/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py +++ b/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py @@ -491,9 +491,6 @@ def import_data_to_destination(imprt: TImports) -> None: ): insert_fields |= {field} if entity.code == "station": - # unique_dataset_id is replaced with id_dataset - if "unique_dataset_id" in fields and fields["unique_dataset_id"] in insert_fields: - insert_fields -= {fields["unique_dataset_id"]} # insert_fields -= {fields["unique_dataset_id"]} insert_fields |= {fields["id_dataset"]} insert_fields |= {fields["geom_4326"], fields["geom_local"]} From 3c7bb34130acb77dab1d2630286cc7fa4789ed30 Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Fri, 24 Jan 2025 16:53:28 +0100 Subject: [PATCH 10/14] feat: split migrations in two parts: synthese and occhab --- ...f_import_monitorings_adjust_gn_imports_.py | 93 ++++++++++++------- .../gn_module_occhab/imports/actions.py | 1 - ...f_adjust_occhab_to_datasate_management_.py | 88 ++++++++++++++++++ 3 files changed, 147 insertions(+), 35 deletions(-) create mode 100644 contrib/gn_module_occhab/backend/gn_module_occhab/migrations/65f77e9d4c6f_adjust_occhab_to_datasate_management_.py diff --git a/backend/geonature/migrations/versions/51ee1572f71f_import_monitorings_adjust_gn_imports_.py b/backend/geonature/migrations/versions/51ee1572f71f_import_monitorings_adjust_gn_imports_.py index 7b3188512c..adeed3a04d 100644 --- a/backend/geonature/migrations/versions/51ee1572f71f_import_monitorings_adjust_gn_imports_.py +++ b/backend/geonature/migrations/versions/51ee1572f71f_import_monitorings_adjust_gn_imports_.py @@ -1,4 +1,4 @@ -"""[import.monitorings] Adjust gn.imports bib_fields id_dataset and unique_id_dataset values +"""[import.monitorings] Adjust gn.imports bib_fields id_dataset and unique_id_dataset values for syntehse destination Revision ID: 51ee1572f71f Revises: df277299fdda @@ -9,6 +9,7 @@ from alembic import op import sqlalchemy as sa +from geonature.core.imports.models import BibFields, Destination # revision identifiers, used by Alembic. revision = "51ee1572f71f" @@ -19,27 +20,42 @@ def upgrade(): op.execute( - """ - UPDATE gn_imports.bib_fields - SET display = TRUE, - mandatory = TRUE, - type_field = 'dataset', - type_field_params = '{"bind_value": "unique_dataset_id"}', - source_field = 'src_unique_dataset_id', - dest_field = NULL - WHERE name_field = 'unique_dataset_id' - """ + sa.update(BibFields) + .where( + BibFields.name_field == "unique_dataset_id", + BibFields.id_destination == Destination.id_destination, + Destination.code == "synthese", + ) + .values( + dict( + display=True, + mandatory=True, + type_field="dataset", + type_field_params=dict(bind_value="unique_dataset_id"), + source_field="src_unique_dataset_id", + dest_field=None, + ) + ) ) + op.execute( - """ - UPDATE gn_imports.bib_fields - SET display = FALSE, - mandatory = FALSE, - dest_field = 'id_dataset', - source_field = NULL - WHERE name_field = 'id_dataset' - """ + sa.update(BibFields) + .where( + BibFields.name_field == "id_dataset", + BibFields.id_destination == Destination.id_destination, + Destination.code == "synthese", + ) + .values( + dict( + display=False, + type_field="textarea", + mandatory=False, + dest_field="id_dataset", + source_field=None, + ) + ) ) + op.execute( """ DO $$ @@ -60,23 +76,32 @@ def upgrade(): def downgrade(): op.execute( - """ - UPDATE gn_imports.bib_fields - SET display = FALSE, - mandatory = FALSE, - optional_conditions = NULL, - type_field = 'text', - type_field_params = NULL, - dest_field = 'unique_dataset_id' - WHERE name_field = 'unique_dataset_id' - """ + sa.update(BibFields) + .where( + BibFields.name_field == "unique_dataset_id", + BibFields.id_destination == Destination.id_destination, + Destination.code == "synthese", + ) + .values( + dict( + display=False, + mandatory=False, + optional_conditions=None, + type_field="text", + type_field_params=None, + dest_field="unique_dataset_id", + ) + ) ) + op.execute( - """ - UPDATE gn_imports.bib_fields - SET dest_field = NULL - WHERE name_field = 'id_dataset' - """ + sa.update(BibFields) + .where( + BibFields.name_field == "id_dataset", + BibFields.id_destination == Destination.id_destination, + Destination.code == "synthese", + ) + .values(dict(dest_field=None)) ) op.add_column( schema="gn_imports", diff --git a/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py b/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py index ab8962fcd2..8331bf7904 100644 --- a/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py +++ b/contrib/gn_module_occhab/backend/gn_module_occhab/imports/actions.py @@ -491,7 +491,6 @@ def import_data_to_destination(imprt: TImports) -> None: ): insert_fields |= {field} if entity.code == "station": - # insert_fields -= {fields["unique_dataset_id"]} insert_fields |= {fields["id_dataset"]} insert_fields |= {fields["geom_4326"], fields["geom_local"]} # TODO@TestImportsOcchab.test_import_valid_file: add testcase diff --git a/contrib/gn_module_occhab/backend/gn_module_occhab/migrations/65f77e9d4c6f_adjust_occhab_to_datasate_management_.py b/contrib/gn_module_occhab/backend/gn_module_occhab/migrations/65f77e9d4c6f_adjust_occhab_to_datasate_management_.py new file mode 100644 index 0000000000..06159e0a6a --- /dev/null +++ b/contrib/gn_module_occhab/backend/gn_module_occhab/migrations/65f77e9d4c6f_adjust_occhab_to_datasate_management_.py @@ -0,0 +1,88 @@ +"""Adjust occhab to datasate management modification in import + +Revision ID: 65f77e9d4c6f +Revises: e43f039b5ff1 +Create Date: 2025-01-28 11:28:51.311696 + +""" + +from alembic import op +import sqlalchemy as sa + +from geonature.core.imports.models import BibFields, Destination + +# revision identifiers, used by Alembic. +revision = "65f77e9d4c6f" +down_revision = "e43f039b5ff1" +branch_labels = None +depends_on = None + + +def upgrade(): + op.execute( + sa.update(BibFields) + .where( + BibFields.name_field == "unique_dataset_id", + BibFields.id_destination == Destination.id_destination, + Destination.code == "occhab", + ) + .values( + dict( + display=True, + mandatory=True, + type_field="dataset", + type_field_params=dict(bind_value="unique_dataset_id"), + source_field="src_unique_dataset_id", + dest_field=None, + ) + ) + ) + + op.execute( + sa.update(BibFields) + .where( + BibFields.name_field == "id_dataset", + BibFields.id_destination == Destination.id_destination, + Destination.code == "occhab", + ) + .values( + dict( + display=False, + type_field="textarea", + mandatory=False, + dest_field="id_dataset", + source_field=None, + ) + ) + ) + + +def downgrade(): + op.execute( + sa.update(BibFields) + .where( + BibFields.name_field == "unique_dataset_id", + BibFields.id_destination == Destination.id_destination, + Destination.code == "occhab", + ) + .values( + dict( + display=False, + mandatory=False, + optional_conditions=None, + type_field="text", + type_field_params=None, + dest_field="unique_dataset_id", + ) + ) + ) + + op.execute( + sa.update(BibFields) + .where( + BibFields.name_field == "id_dataset", + BibFields.id_destination == Destination.id_destination, + Destination.code == "occhab", + ) + .values(dict(dest_field=None)) + ) From 490b868b24d7d17a0abfc3315a54c976f374e386 Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Tue, 28 Jan 2025 17:41:01 +0100 Subject: [PATCH 11/14] fix: remove useless and untestable check in check_datasets --- backend/geonature/core/imports/checks/dataframe/core.py | 6 ------ 1 file changed, 6 deletions(-) diff --git a/backend/geonature/core/imports/checks/dataframe/core.py b/backend/geonature/core/imports/checks/dataframe/core.py index df6dd18f43..bf9d15cfb6 100644 --- a/backend/geonature/core/imports/checks/dataframe/core.py +++ b/backend/geonature/core/imports/checks/dataframe/core.py @@ -223,12 +223,6 @@ def check_datasets( """ updated_cols = set() uuid_col = uuid_field.source_column - - if uuid_col not in df: - yield { - "error_code": ImportCodeError.MISSING_VALUE, - "column": uuid_field.name_field, - } uuid = df[uuid_col].unique().tolist() # check uuid format From 7b3a8b39959fc27d7497e6113aa342f8a676eb6c Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Tue, 28 Jan 2025 17:41:26 +0100 Subject: [PATCH 12/14] feat: fix per_dataset_uuid_check and add test case --- .../core/gn_synthese/imports/actions.py | 2 +- .../core/imports/checks/sql/extra.py | 4 ++-- .../tests/imports/test_imports_synthese.py | 24 +++++++++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/backend/geonature/core/gn_synthese/imports/actions.py b/backend/geonature/core/gn_synthese/imports/actions.py index dbc87fb46d..dc800d814d 100644 --- a/backend/geonature/core/gn_synthese/imports/actions.py +++ b/backend/geonature/core/gn_synthese/imports/actions.py @@ -280,7 +280,7 @@ def update_batch_progress(batch, step): imprt, entity, selected_fields["unique_id_sinp"], - id_dataset_field=selected_fields["id_dataset"], + id_dataset_field=fields["id_dataset"], ) else: check_existing_uuid( diff --git a/backend/geonature/core/imports/checks/sql/extra.py b/backend/geonature/core/imports/checks/sql/extra.py index 1d1d7ed7a7..750b8deb52 100644 --- a/backend/geonature/core/imports/checks/sql/extra.py +++ b/backend/geonature/core/imports/checks/sql/extra.py @@ -271,8 +271,8 @@ def check_existing_uuid( ) if id_dataset_field: - whereclause = ( - whereclause & transient_table.c[id_dataset_field.dest_field] + whereclause = whereclause & ( + transient_table.c[id_dataset_field.dest_field] == dest_table.c[id_dataset_field.dest_field] ) diff --git a/backend/geonature/tests/imports/test_imports_synthese.py b/backend/geonature/tests/imports/test_imports_synthese.py index fd986c9093..f8cac9b1a2 100644 --- a/backend/geonature/tests/imports/test_imports_synthese.py +++ b/backend/geonature/tests/imports/test_imports_synthese.py @@ -100,6 +100,11 @@ def override_in_importfile(import_datasets): } +@pytest.fixture() +def per_dataset_uuid_check(monkeypatch): + monkeypatch.setitem(current_app.config["IMPORT"], "PER_DATASET_UUID_CHECK", True) + + # ###################################################################################### # Tests -- imports # ###################################################################################### @@ -893,6 +898,25 @@ def test_import_altitude_file(self, prepared_import): ] assert altitudes == expected_altitudes + @pytest.mark.parametrize("import_file_name,fieldmapping_preset_name", [("uuid_file.csv", None)]) + def test_import_uuid_file_per_dataset_uuid( + self, per_dataset_uuid_check, import_datasets, synthese_data, prepared_import + ): + assert_import_errors( + prepared_import, + { + (ImportCodeError.DUPLICATE_UUID, "unique_id_sinp", frozenset([3, 4])), + (ImportCodeError.INVALID_UUID, "unique_id_sinp", frozenset([6])), + }, + ) + transient_table = prepared_import.destination.get_transient_table() + unique_id_sinp = db.session.execute( + select([transient_table.c.unique_id_sinp]) + .where(transient_table.c.id_import == prepared_import.id_import) + .where(transient_table.c.line_no == 7) + ).scalar() + assert unique_id_sinp != None + @pytest.mark.parametrize("import_file_name,fieldmapping_preset_name", [("uuid_file.csv", None)]) def test_import_uuid_file(self, import_datasets, synthese_data, prepared_import): assert_import_errors( From c34ca753fdf8514c6a32e22e7cbc3090f6833c21 Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Sat, 8 Feb 2025 23:51:50 +0100 Subject: [PATCH 13/14] fix: add missing id_dataset to insert field . remove unique_dataset_id columns from t_imports_XXX --- .../geonature/core/gn_synthese/imports/actions.py | 1 + ...72f71f_import_monitorings_adjust_gn_imports_.py | 14 +++++++++++++- ...9d4c6f_adjust_occhab_to_datasate_management_.py | 11 +++++++++++ 3 files changed, 25 insertions(+), 1 deletion(-) diff --git a/backend/geonature/core/gn_synthese/imports/actions.py b/backend/geonature/core/gn_synthese/imports/actions.py index dc800d814d..55e4350acb 100644 --- a/backend/geonature/core/gn_synthese/imports/actions.py +++ b/backend/geonature/core/gn_synthese/imports/actions.py @@ -337,6 +337,7 @@ def import_data_to_destination(imprt: TImports) -> None: fields["the_geom_local"], fields["the_geom_point"], fields["id_area_attachment"], # XXX sure? + fields["id_dataset"], } if imprt.fieldmapping.get( "unique_id_sinp_generate", diff --git a/backend/geonature/migrations/versions/51ee1572f71f_import_monitorings_adjust_gn_imports_.py b/backend/geonature/migrations/versions/51ee1572f71f_import_monitorings_adjust_gn_imports_.py index adeed3a04d..baa6564ee0 100644 --- a/backend/geonature/migrations/versions/51ee1572f71f_import_monitorings_adjust_gn_imports_.py +++ b/backend/geonature/migrations/versions/51ee1572f71f_import_monitorings_adjust_gn_imports_.py @@ -1,4 +1,4 @@ -"""[import.monitorings] Adjust gn.imports bib_fields id_dataset and unique_id_dataset values for syntehse destination +"""[import.monitorings] Adjust gn.imports bib_fields id_dataset and unique_id_dataset values for synthese destination Revision ID: 51ee1572f71f Revises: df277299fdda @@ -10,6 +10,7 @@ import sqlalchemy as sa from geonature.core.imports.models import BibFields, Destination +from sqlalchemy.dialects.postgresql import UUID # revision identifiers, used by Alembic. revision = "51ee1572f71f" @@ -19,6 +20,10 @@ def upgrade(): + op.drop_column( + schema="gn_imports", table_name="t_imports_synthese", column_name="unique_dataset_id" + ) + op.execute( sa.update(BibFields) .where( @@ -103,8 +108,15 @@ def downgrade(): ) .values(dict(dest_field=None)) ) + op.add_column( schema="gn_imports", table_name="t_imports", column=sa.Column("id_dataset", sa.INTEGER), ) + + op.add_column( + schema="gn_imports", + table_name="t_imports_synthese", + column=sa.Column("unique_dataset_id", UUID(as_uuid=True)), + ) diff --git a/contrib/gn_module_occhab/backend/gn_module_occhab/migrations/65f77e9d4c6f_adjust_occhab_to_datasate_management_.py b/contrib/gn_module_occhab/backend/gn_module_occhab/migrations/65f77e9d4c6f_adjust_occhab_to_datasate_management_.py index 06159e0a6a..dfce135c57 100644 --- a/contrib/gn_module_occhab/backend/gn_module_occhab/migrations/65f77e9d4c6f_adjust_occhab_to_datasate_management_.py +++ b/contrib/gn_module_occhab/backend/gn_module_occhab/migrations/65f77e9d4c6f_adjust_occhab_to_datasate_management_.py @@ -10,6 +10,7 @@ import sqlalchemy as sa from geonature.core.imports.models import BibFields, Destination +from sqlalchemy.dialects.postgresql import UUID # revision identifiers, used by Alembic. revision = "65f77e9d4c6f" @@ -19,6 +20,10 @@ def upgrade(): + op.drop_column( + schema="gn_imports", table_name="t_imports_occhab", column_name="unique_dataset_id" + ) + op.execute( sa.update(BibFields) .where( @@ -86,3 +91,9 @@ def downgrade(): ) .values(dict(dest_field=None)) ) + + op.add_column( + schema="gn_imports", + table_name="t_imports_occhab", + column=sa.Column("unique_dataset_id", UUID(as_uuid=True)), + ) From 495a02fbd66065d7c51812de6c7bd866b5e1d65f Mon Sep 17 00:00:00 2001 From: Etienne Delclaux Date: Sun, 9 Feb 2025 00:17:10 +0100 Subject: [PATCH 14/14] update test files to have more correct names --- .../files/occhab/valid_file_importable.csv | 44 +++++++++++++++++++ .../files/synthese/valid_file_etienne.csv | 7 --- .../files/synthese/valid_file_importable.csv | 7 +++ 3 files changed, 51 insertions(+), 7 deletions(-) create mode 100644 backend/geonature/tests/imports/files/occhab/valid_file_importable.csv delete mode 100644 backend/geonature/tests/imports/files/synthese/valid_file_etienne.csv create mode 100644 backend/geonature/tests/imports/files/synthese/valid_file_importable.csv diff --git a/backend/geonature/tests/imports/files/occhab/valid_file_importable.csv b/backend/geonature/tests/imports/files/occhab/valid_file_importable.csv new file mode 100644 index 0000000000..c3336df62c --- /dev/null +++ b/backend/geonature/tests/imports/files/occhab/valid_file_importable.csv @@ -0,0 +1,44 @@ +Objectif du test;Erreur station;Erreur habitat;id_station_source;unique_id_sinp_station;unique_dataset_id;date_min;date_max;observers;id_nomenclature_area_surface_calculation;WKT;id_nomenclature_geographic_object;unique_id_sinp_habitat;nom_cite;cd_hab;technical_precision;id_nomenclature_collection_technique +Station + habitat sur la même ligne;OK !;OK !;;afa81c29-c75d-408d-bf48-53cce02d5561;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;4ee53579-b09b-408f-aa1f-d62495a66667;prairie;24;; +Station uniquement;OK !;Pas d’habitat;;9d3fb1bd-6148-45c4-aa13-ff9212155afe;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;;;; +Habitat uniquement dans une station existante en base.;Pas de station;OK !;;EXISTING_STATION_UUID;;;;Toto;;;;05f0163a-ab14-4045-84b9-b513188092ae;prairie;24;; +Dataset innexistant, habitat valide mais pas le parent;DATASET_NOT_FOUND(unique_dataset_id), INCOHERENT_DATA;ERRONEOUS_PARENT_ENTITY;;bdc3346d-0fc3-40fa-b787-be927e4dd82e;050d613c-543f-47fd-800a-13931b2721c7;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;2ff4867d-6943-45d8-873d-187fbc6d67a7;prairie;24;; +Dataset interdit, habitat valide mais pas le parent;DATASET_NOT_AUTHORIZED(unique_dataset_id);ERRONEOUS_PARENT_ENTITY;;f5f031a3-cf1b-419c-9817-69c39f51aef4;FORBIDDEN_DATASET_UUID;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;5dfb9930-4795-4e6f-baae-3dd86abb3b70;prairie;24;; +Dataset UUID invalide;INVALID_UUID(unique_dataset_id);Pas d’habitat;;;erroneous;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);;;;;; +Champs géométrique manquant;NO-GEOM(Champs géométriques);Pas d’habitat;;;;17/11/2023;17/11/2023;Toto;;;;;;;; +Champs requis manquant;MISSING_VALUE(date_min);ERRONEOUS_PARENT_ENTITY;;4ee7728d-387d-49c5-b9a3-4162b0987fa5;;;;Toto;;POINT(6.6 44.85);St;aeb10ac4-6d69-4fa6-8df6-14d9304911df;prairie;24;; +Habitat mais pas de station référencée;Pas de station;NO_PARENT_ENTITY(id_station);;;;;;Toto;;;;;prairie;24;; +Uniquement un uuid station, mais on ne sait pas s’il appartient à une station ou s’il sert à indiquer le parent d’un habitat;ORPHAN_ROW(unique_id_sinp_station);ORPHAN_ROW(unique_id_sinp_station);;258a2478-8a0e-4321-83df-c2313ad3040e;;;;Toto;;;;;;;; +Uniquement un id station source, mais on ne sait pas s’il appartient à une station ou s’il sert à indiquer le parent d’un habitat;ORPHAN_ROW(id_station_source);ORPHAN_ROW(id_station_source);Station -1;;;;;Toto;;;;;;;; +Uniquement UUID station + id station source, mais on ne sait pas s’ils appartiennent à une station ou s’ils servent à indiquer le parent d’un habitat;ORPHAN_ROW(unique_id_sinp_station, id_station_source);ORPHAN_ROW(unique_id_sinp_station,id_station_source);Station -2;54e54935-982b-4da3-9aaf-e87e49a1fdf1;;;;Toto;;;;;;;; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées. Les lignes contenant la station sont rapproché par UUID.;OK !;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;e5e7a184-3e92-4adb-a721-5bd004b3397f;forêt;24;; +;OK !;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;8f52f122-b9ae-45b3-b947-2c9f7934b823;prairie;24;; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées MAIS AVEC DES DIFFÉRENCES (date). Les lignes contenant la station sont rapproché par UUID.;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;17/11/2023;;Toto;;POINT(6.6 44.85);St;d91496e9-d904-45a8-9e18-cb8acbbb6ea6;prairie;24;; +;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;18/11/2023;;Toto;;POINT(6.6 44.85);St;;prairie;24;; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées mais avec des différences (date INVALIDE). Les lignes contenant la station sont rapproché par UUID. On vérifie qu’on a pas d’erreur sur la date car les contrôles ne doivent pas être lancé si les données sont incohérentes. En revanche, les contrôles des habitats doivent bien être lancés.;INCOHERENT_DATA(unique_id_sinp_station);NO_PARENT_ENTITY(id_station);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;17/11/2023;;Toto;;POINT(6.6 44.85);St;;prairie;24;; +NO_PARENT_ENTITY(id_station) non levé sur l’habitat en raison de l’implémentation du check qui ignore les lignes erronées. À voir s’il faut le faire évoluer.;INCOHERENT_DATA(unique_id_sinp_station);INVALID_INTEGER(cd_hab);;74be5e79-72e7-42a8-ba2e-d5e27c9caddb;;date invalide;;Toto;;POINT(6.6 44.85);St;;prairie;invalide;; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées. Les lignes contenant la station sont rapproché par id origine.;OK !;OK !;Station 1;;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +;OK !;OK !;Station 1;;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +On importe 2 habitats dans une même nouvelle station dont les données sont répétées MAIS AVEC DES DIFFÉRENCES (date). Les lignes contenant la station sont rapproché par id origine.;INCOHERENT_DATA(id_station_source);NO_PARENT_ENTITY(id_station);Station 2;;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +;INCOHERENT_DATA(id_station_source);NO_PARENT_ENTITY(id_station);Station 2;;;invalide;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +Un UUID station invalide lève une erreur sur la station ET sur l’habitat;INVALID_UUID(unique_id_sinp_station);INVALID_UUID(unique_id_sinp_station),ERRONEOUS_PARENT_ENTITY;;Erroneous 1;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;6c02ef80-2e78-4c2c-b8b5-1c75e2349fc2;prairie;24;; +Un UUID station invalide lève une erreur sur la station uniquement si pas d’habitat;INVALID_UUID(unique_id_sinp_station),MISSING_VALUE(date_min);Pas d’habitat;;Erroneous 2;;;17/11/2024;Toto;;POINT(6.6 44.85);;;;;; +Un UUID station invalide lève une erreur sur l’habitat uniquement si pas de station. Comme pour un précédent test d’incohérence,, NO PARENT_ENTITY n’est pas levé en raison d’un choix d’implémentation qui peut être modifié.;Pas de station;INVALID_UUID(unique_id_sinp_station);;Erroneous 3;;;;Toto;;;;;prairie;24;; +Les UUID ≠ mais les id origine sont identique !;INCOHERENT_DATA [UUID ≠];ERRONEOUS_PARENT_ENTITY;Station 3;dd0d12fc-bb85-4029-9c72-14fd8583f9bb;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +;INCOHERENT_DATA [UUID ≠];ERRONEOUS_PARENT_ENTITY;Station 3;330bb0f5-dc1c-431a-af1a-d70138b8c99d;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +Les UUID sont égaux mais les id origine ≠ !;INCOHERENT_DATA [id_station_source ≠];ERRONEOUS_PARENT_ENTITY;Station 4;a5c37acb-c966-4024-bea6-71ec125b51c8;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +;INCOHERENT_DATA [id_station_source ≠];ERRONEOUS_PARENT_ENTITY;Station 5;a5c37acb-c966-4024-bea6-71ec125b51c8;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +Les id origine sont identique, mais les UUID ne sont pas toujours renseignés.;INCOHERENT_DATA [UUID ≠];ERRONEOUS_PARENT_ENTITY;Station 6;7ed90696-4e74-4ed5-98a4-518eea009a7f;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +;INCOHERENT_DATA [UUID ≠];ERRONEOUS_PARENT_ENTITY;Station 6;;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +Les UUID sont égaux mais les id origine ne sont pas toujours renseignés.;INCOHERENT_DATA [id_station_source ≠];ERRONEOUS_PARENT_ENTITY;Station 7;c4262f95-0b19-422a-848b-8f83c292d27a;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +;INCOHERENT_DATA [id_station_source ≠];ERRONEOUS_PARENT_ENTITY;;c4262f95-0b19-422a-848b-8f83c292d27a;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +Il y a ni UUID, ni id_origine : l’UUID sera généré.;OK !;OK !;;;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +Import d’un habitat dans une station existante ailleurs dans le fichier, référencé par UUID.;Pas de station;OK !;;462d385f-489a-436b-babb-8cca5fc62e1d;;;;Toto;;;;;prairie;24;; +Import d’un habitat dans une station existante ailleurs dans le fichier, référencé par id origine.;Pas de station;OK !;Station 1;;;;;Toto;;;;;prairie;24;; +On importe une station qui existe déjà en base : elle est ignorée;SKIP_EXISTING_UUID;Pas d’habitat;;EXISTING_STATION_UUID;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;;;; +On importe une station qui existe déjà en base et un nouvel habitat, seul l’habitat est importé;SKIP_EXISTING_UUID;OK !;;EXISTING_STATION_UUID;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;; +On importe une station et un habitat existant déjà en base;SKIP_EXISTING_UUID;SKIP_EXISTING_UUID;;EXISTING_STATION_UUID;;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;EXISTING_HABITAT_UUID;prairie;24;; +technique collect vaut « autre » mais pas de précision fournise;OK !;CONDITIONAL_MANDATORY_FIELD_ERROR;;;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;;10 +technique collect vaut « autre » et une précision est bien fournies;OK !;OK !;;;VALID_DATASET_UUID;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;moyen précis;10 +L’habitat est crée dans une station que existe en base mais sur laquelle nous n’avons pas les droits;DATASET_NOT_AUTHORIZED(unique_dataset_id);OK ! ;;STRANGER_STATION_UUID;;;;;;;;;prairie;24;moyen précis;10 +jeu de données pas actif;DATASET_NOT_ACTIVE;ERRONEOUS_PARENT_ENTITY;;;INACTIVE_DATASET_UUID;17/11/2023;17/11/2023;Toto;;POINT(6.6 44.85);St;;prairie;24;moyen précis;10 diff --git a/backend/geonature/tests/imports/files/synthese/valid_file_etienne.csv b/backend/geonature/tests/imports/files/synthese/valid_file_etienne.csv deleted file mode 100644 index 66063b8c6e..0000000000 --- a/backend/geonature/tests/imports/files/synthese/valid_file_etienne.csv +++ /dev/null @@ -1,7 +0,0 @@ -error ;id_synthese ;id_origine ;comment_releve ;comment_occurrence ;date_debut ;date_fin ;heure_debut ;heure_fin ;cd_nom ;cd_ref ;nom_valide ;nom_vernaculaire ;nom_cite ;regne ;group1_inpn ;group2_inpn ;classe ;ordre ;famille ;rang_taxo ;nombre_min ;nombre_max ;alti_min ;alti_max ;prof_min ;prof_max ;observateurs ;determinateur ;communes ;geometrie_wkt_4326 ;x_centroid_4326 ;y_centroid_4326 ;nom_lieu ;validateur ;niveau_validation ;date_validation ;comment_validation ;preuve_numerique_url ;preuve_non_numerique ;jdd_nom ;jdd_uuid ;jdd_id ;ca_nom ;ca_uuid ;ca_id ;cd_habref ;cd_habitat ;nom_habitat ;precision_geographique ;nature_objet_geo ;type_regroupement ;methode_regroupement ;technique_observation ;biologique_statut ;etat_biologique ;biogeographique_statut ;naturalite ;preuve_existante ;niveau_precision_diffusion ;stade_vie ;sexe ;objet_denombrement ;type_denombrement ;niveau_sensibilite ;statut_observation ;floutage_dee ;statut_source ;type_info_geo ;methode_determination ;comportement ;reference_biblio ;uuid_perm_sinp ;uuid_perm_grp_sinp ;date_creation ;date_modification -valid ; 10 ; 10 ;Relevé n°1 ;Occurrence n°1 ;2017-01-01 ;2017-01-01 ;12:05:02 ;12:05:02 ; 60612 ; 60612 ;Lynx lynx (Linnaeus, 1758) ; ;Lynx Boréal ;Animalia ;Chordés ;Mammifères ;Mammalia ;Carnivora ;Felidae ;ES ; 5 ; 5 ; 1500 ; 1565 ; ; ;Administrateur test ;Gil ;Vallouise-Pelvoux ;POINT(6.6 44.85) ; 6.5 ; 44.85 ; ; ;En attente de validation ; ; ; ;Poil ;Contact aléatoire tous règnes confondus ;4d331cae-65e4-4948-b0b2-a11bc5bb46c2 ; 1 ;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins ;57b7d0f2-4183-4b7b-8f08-6e105d476dc5 ; 1 ; ; ; ; 10 ;Inventoriel ;OBS ; ;Galerie/terrier ;Non renseigné ;Non renseigné ;Non renseigné ;Sauvage ;Oui ;Précise ;Adulte ;Femelle ;Individu ;Compté ;Non sensible - Diffusion précise ;Présent ;Non ;Terrain ;Géoréférencement ;Autre méthode de détermination ;Non renseigné ; ;b4f85a2e-dd88-4cdd-aa86-f1c7370faf3f ;5b427c76-bd8c-4103-a33c-884c7037aa2b ;2021-01-11 14:20:46.492497 ;2021-01-11 14:20:46.492497 -valid ; 20 ; 20 ;Relevé n°2 ;Occurrence n°2 ;2017-01-01 ;2017-01-02 ;12:05:02 ;12:05:02 ; 351 ; 351 ;Rana temporaria Linnaeus, 1758 ;Grenouille rousse (La) ;Grenouille rousse ;Animalia ;Chordés ;Amphibiens ;Amphibia ;Anura ;Ranidae ;ES ; 1 ; 1 ; 1500 ; 1565 ; ; ;Administrateur test ;Théo ;Vallouise-Pelvoux ;POINT(6.6 44.85) ; 6.5 ; 44.85 ; ; ;En attente de validation ; ; ; ;Poils de plumes ;Contact aléatoire tous règnes confondus ;4d331cae-65e4-4948-b0b2-a11bc5bb46c2 ; 1 ;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins ;57b7d0f2-4183-4b7b-8f08-6e105d476dc5 ; 1 ; ; ; ; 10 ;Inventoriel ;OBS ; ;Galerie/terrier ;Non renseigné ;Non renseigné ;Non renseigné ;Sauvage ;Oui ;Précise ;Immature ;Femelle ;Individu ;Compté ;Non sensible - Diffusion précise ;Présent ;Non ;Terrain ;Géoréférencement ;Autre méthode de détermination ;Non renseigné ; ;830c93c7-288e-40f0-a17f-15fbb50e643a ;5b427c76-bd8c-4103-a33c-884c7037aa2b ;2021-01-11 14:20:46.492497 ;2021-01-11 14:20:46.492497 -duplicate id ; 30 ; 30 ;Relevé n°3 ;Occurrence n°3 ;2017-01-08 ; ; ; ; 67111 ; 67111 ;Alburnus alburnus (Linnaeus, 1758) ;Ablette ;Ablette ;Animalia ;Chordés ;Poissons ;Actinopterygii ;Cypriniformes ;Leuciscidae ;ES ; 1 ; 1 ; 1600 ; 1600 ; ; ;Administrateur test ;Donovan ;Vallouise-Pelvoux ;POINT(6.5 44.85) ; 6.5 ; 44.85 ; ; ;En attente de validation ; ; ; ;Poils de plumes ;Contact aléatoire tous règnes confondus ;4d331cae-65e4-4948-b0b2-a11bc5bb46c2 ; 1 ;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins ;57b7d0f2-4183-4b7b-8f08-6e105d476dc5 ; 1 ; ; ; ; 100 ;Inventoriel ;OBS ; ;Galerie/terrier ;Non renseigné ;Non renseigné ;Non renseigné ;Sauvage ;Oui ;Précise ;Juvénile ;Femelle ;Individu ;Compté ;Non sensible - Diffusion précise ;Présent ;Non ;Terrain ;Géoréférencement ;Autre méthode de détermination ;Non renseigné ; ;2f92f91a-64a2-4684-90e4-140466bb34e3 ;5937d0f2-c96d-424b-bea4-9e3fdac894ed ;2021-01-11 14:20:46.492497 ;2021-01-11 14:20:46.492497 -duplicate id ; 30 ; 40 ;Relevé n°4 ;Occurrence n°4 ;2017-01-08 ;2017-01-08 ;20:00:00 ;23:00:00 ; 67111 ; 67111 ;Alburnus alburnus (Linnaeus, 1758) ;Ablette ;Ablette ;Animalia ;Chordés ;Poissons ;Actinopterygii ;Cypriniformes ;Leuciscidae ;ES ; 1 ; 1 ; 1600 ; 1600 ; ; ;Administrateur test ;Donovan ;Vallouise-Pelvoux ;POINT(6.5 44.85) ; 6.5 ; 44.85 ; ; ;En attente de validation ; ; ; ;Poils de plumes ;Contact aléatoire tous règnes confondus ;4d331cae-65e4-4948-b0b2-a11bc5bb46c2 ; 1 ;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins ;57b7d0f2-4183-4b7b-8f08-6e105d476dc5 ; 1 ; ; ; ; 100 ;Inventoriel ;OBS ; ;Galerie/terrier ;Non renseigné ;Non renseigné ;Non renseigné ;Sauvage ;Oui ;Précise ;Juvénile ;Femelle ;Individu ;Compté ;Non sensible - Diffusion précise ;Présent ;Non ;Terrain ;Géoréférencement ;Autre méthode de détermination ;Non renseigné ; ;2f92f91a-64a2-4684-90e4-140466bb34e4 ;5937d0f2-c96d-424b-bea4-9e3fdac894ed ;2021-01-11 14:20:46.492497 ;2021-01-11 14:20:46.492497 -count min > count max ; 50 ; 50 ;Relevé n°5 ;Occurrence n°5 ;2017-01-08 ;2017/01/08 ;20:00 ;23:00:00 ; 67111 ; 67111 ;Alburnus alburnus (Linnaeus, 1758) ;Ablette ;Ablette ;Animalia ;Chordés ;Poissons ;Actinopterygii ;Cypriniformes ;Leuciscidae ;ES ; 20 ; 5 ; 1600 ; 1600 ; ; ;Administrateur test ;Donovan ;Vallouise-Pelvoux ;POINT(6.5 44.85) ; 6.5 ; 44.85 ; ; ;En attente de validation ; ; ; ;Poils de plumes ;Contact aléatoire tous règnes confondus ;4d331cae-65e4-4948-b0b2-a11bc5bb46c2 ; 1 ;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins ;57b7d0f2-4183-4b7b-8f08-6e105d476dc5 ; 1 ; ; ; ; 100 ;Inventoriel ;OBS ; ;Galerie/terrier ;Non renseigné ;Non renseigné ;Non renseigné ;Sauvage ;Oui ;Précise ;Juvénile ;Femelle ;Individu ;Compté ;Non sensible - Diffusion précise ;Présent ;Non ;Terrain ;Géoréférencement ;Autre méthode de détermination ;Non renseigné ; ;2f92f91a-64a2-4684-90e4-140466bb34e5 ;5937d0f2-c96d-424b-bea4-9e3fdac894ed ;2021-01-11 14:20:46.492497 ;2021-01-11 14:20:46.492497 -valid ; 60 ; 60 ;Relevé n°6 ;Occurrence n°6 ;2017-01-01 ;2017-01-01 ;12:05:02 ;12:05:02 ; 351 ; 351 ;Rana temporaria Linnaeus, 1758 ;Grenouille rousse (La) ;Grenouille rousse ;Animalia ;Chordés ;Amphibiens ;Amphibia ;Anura ;Ranidae ;ES ; 1 ; 1 ; 1600 ; 1600 ; ; ;Administrateur test ;Donovan ;Vallouise-Pelvoux ;POINT(6.5 44.75) ; 6.5 ; 44.85 ; ; ;En attente de validation ; ; ; ;Poils de plumes ;Contact aléatoire tous règnes confondus ;4d331cae-65e4-4948-b0b2-a11bc5bb46c2 ; 1 ;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins ;57b7d0f2-4183-4b7b-8f08-6e105d476dc5 ; 1 ; ; ; ; 100 ;Inventoriel ;OBS ; ;Galerie/terrier ;Non renseigné ;Non renseigné ;Non renseigné ;Sauvage ;Oui ;Précise ;Juvénile ;Femelle ;Individu ;Compté ;Non sensible - Diffusion précise ;Présent ;Non ;Terrain ;Géoréférencement ;Autre méthode de détermination ;Non renseigné ; ;f5515e2a-b30d-11eb-8cc8-af8c2d0867b4 ;5937d0f2-c96d-424b-bea4-9e3fdac894ed ;2021-01-11 14:20:46.492497 ;2021-01-11 14:20:46.492497 diff --git a/backend/geonature/tests/imports/files/synthese/valid_file_importable.csv b/backend/geonature/tests/imports/files/synthese/valid_file_importable.csv new file mode 100644 index 0000000000..d5d1739108 --- /dev/null +++ b/backend/geonature/tests/imports/files/synthese/valid_file_importable.csv @@ -0,0 +1,7 @@ +error;id_synthese;id_origine;comment_releve;comment_occurrence;date_debut;date_fin;heure_debut;heure_fin;cd_nom;cd_ref;nom_valide;nom_vernaculaire;nom_cite;regne;group1_inpn;group2_inpn;classe;ordre;famille;rang_taxo;nombre_min;nombre_max;alti_min;alti_max;prof_min;prof_max;observateurs;determinateur;communes;geometrie_wkt_4326;x_centroid_4326;y_centroid_4326;nom_lieu;validateur;niveau_validation;date_validation;comment_validation;preuve_numerique_url;preuve_non_numerique;jdd_nom;jdd_uuid;jdd_id;ca_nom;ca_uuid;ca_id;cd_habref;cd_habitat;nom_habitat;precision_geographique;nature_objet_geo;type_regroupement;methode_regroupement;technique_observation;biologique_statut;etat_biologique;biogeographique_statut;naturalite;preuve_existante;niveau_precision_diffusion;stade_vie;sexe;objet_denombrement;type_denombrement;niveau_sensibilite;statut_observation;floutage_dee;statut_source;type_info_geo;methode_determination;comportement;reference_biblio;uuid_perm_sinp;uuid_perm_grp_sinp;date_creation;date_modification +valid;10;10;Relevé n°1;Occurrence n°1;2017-01-01;2017-01-01;12:05:02;12:05:02;60612;60612;Lynx lynx (Linnaeus, 1758);;Lynx Boréal;Animalia;Chordés;Mammifères;Mammalia;Carnivora;Felidae;ES;5;5;1500;1565;;;Administrateur test;Gil;Vallouise-Pelvoux;POINT(6.6 44.85);6.5;44.85;;;En attente de validation;;;;Poil;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Adulte;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;b4f85a2e-dd88-4cdd-aa86-f1c7370faf3f;5b427c76-bd8c-4103-a33c-884c7037aa2b;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +valid;20;20;Relevé n°2;Occurrence n°2;2017-01-01;2017-01-02;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1500;1565;;;Administrateur test;Théo;Vallouise-Pelvoux;POINT(6.6 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;10;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Immature;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;830c93c7-288e-40f0-a17f-15fbb50e643a;5b427c76-bd8c-4103-a33c-884c7037aa2b;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +duplicate id;30;30;Relevé n°3;Occurrence n°3;2017-01-08;;;;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e3;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +duplicate id;30;40;Relevé n°4;Occurrence n°4;2017-01-08;2017-01-08;20:00:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e4;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +count min > count max;50;50;Relevé n°5;Occurrence n°5;2017-01-08;2017/01/08;20:00;23:00:00;67111;67111;Alburnus alburnus (Linnaeus, 1758);Ablette;Ablette;Animalia;Chordés;Poissons;Actinopterygii;Cypriniformes;Leuciscidae;ES;20;5;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.85);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;2f92f91a-64a2-4684-90e4-140466bb34e5;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497 +valid;60;60;Relevé n°6;Occurrence n°6;2017-01-01;2017-01-01;12:05:02;12:05:02;351;351;Rana temporaria Linnaeus, 1758;Grenouille rousse (La);Grenouille rousse;Animalia;Chordés;Amphibiens;Amphibia;Anura;Ranidae;ES;1;1;1600;1600;;;Administrateur test;Donovan;Vallouise-Pelvoux;POINT(6.5 44.75);6.5;44.85;;;En attente de validation;;;;Poils de plumes;Contact aléatoire tous règnes confondus;4d331cae-65e4-4948-b0b2-a11bc5bb46c2;1;Données d'observation de la faune, de la Flore et de la fonge du Parc national des Ecrins;57b7d0f2-4183-4b7b-8f08-6e105d476dc5;1;;;;100;Inventoriel;OBS;;Galerie/terrier;Non renseigné;Non renseigné;Non renseigné;Sauvage;Oui;Précise;Juvénile;Femelle;Individu;Compté;Non sensible - Diffusion précise;Présent;Non;Terrain;Géoréférencement;Autre méthode de détermination;Non renseigné;;f5515e2a-b30d-11eb-8cc8-af8c2d0867b4;5937d0f2-c96d-424b-bea4-9e3fdac894ed;2021-01-11 14:20:46.492497;2021-01-11 14:20:46.492497