From 3a1d1d2d46a00749584a1560a98988c02f14546e Mon Sep 17 00:00:00 2001 From: Oliver Gut Date: Thu, 5 Dec 2024 14:36:41 +0100 Subject: [PATCH 01/23] Remove obsolete file hash --- src/api/BdmsContextExtensions.cs | 1 - .../20241122080247_RemoveFileHash.Designer.cs | 3282 +++++++++++++++++ .../20241122080247_RemoveFileHash.cs | 28 + src/api/Models/File.cs | 6 - 4 files changed, 3310 insertions(+), 7 deletions(-) create mode 100644 src/api/Migrations/20241122080247_RemoveFileHash.Designer.cs create mode 100644 src/api/Migrations/20241122080247_RemoveFileHash.cs diff --git a/src/api/BdmsContextExtensions.cs b/src/api/BdmsContextExtensions.cs index 783ac425c..f5c17fbcf 100644 --- a/src/api/BdmsContextExtensions.cs +++ b/src/api/BdmsContextExtensions.cs @@ -216,7 +216,6 @@ public static void SeedData(this BdmsContext context) .RuleFor(o => o.UpdatedBy, _ => default!) .RuleFor(o => o.Updated, _ => default!) .RuleFor(o => o.Name, f => f.Random.Word()) - .RuleFor(o => o.Hash, f => f.Random.Hash()) .RuleFor(o => o.Type, f => f.Random.Word()) .RuleFor(o => o.Created, f => f.Date.Past().ToUniversalTime().OrNull(f, .05f)) .RuleFor(o => o.NameUuid, f => null); diff --git a/src/api/Migrations/20241122080247_RemoveFileHash.Designer.cs b/src/api/Migrations/20241122080247_RemoveFileHash.Designer.cs new file mode 100644 index 000000000..222d6a486 --- /dev/null +++ b/src/api/Migrations/20241122080247_RemoveFileHash.Designer.cs @@ -0,0 +1,3282 @@ +// +using System; +using BDMS; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using NetTopologySuite.Geometries; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; + +#nullable disable + +namespace BDMS.Migrations +{ + [DbContext(typeof(BdmsContext))] + [Migration("20241122080247_RemoveFileHash")] + partial class RemoveFileHash + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasDefaultSchema("bdms") + .HasAnnotation("ProductVersion", "8.0.0") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "ltree"); + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "postgis"); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("BDMS.Models.Backfill", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CasingId") + .HasColumnType("integer") + .HasColumnName("casing_id"); + + b.Property("CompletionId") + .HasColumnType("integer") + .HasColumnName("completion_id"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("FromDepth") + .HasColumnType("double precision") + .HasColumnName("from_depth"); + + b.Property("IsOpenBorehole") + .HasColumnType("boolean") + .HasColumnName("is_open_borehole"); + + b.Property("KindId") + .HasColumnType("integer") + .HasColumnName("kind_id"); + + b.Property("MaterialId") + .HasColumnType("integer") + .HasColumnName("material_id"); + + b.Property("Notes") + .HasColumnType("text") + .HasColumnName("notes"); + + b.Property("ToDepth") + .HasColumnType("double precision") + .HasColumnName("to_depth"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.HasKey("Id"); + + b.HasIndex("CasingId"); + + b.HasIndex("CompletionId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("KindId"); + + b.HasIndex("MaterialId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("backfill", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Borehole", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id_bho"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AlternateName") + .HasColumnType("text") + .HasColumnName("alternate_name_bho"); + + b.Property("Canton") + .HasColumnType("text") + .HasColumnName("canton_bho"); + + b.Property("ChronostratigraphyId") + .HasColumnType("integer") + .HasColumnName("chronostrat_id_cli"); + + b.Property("Country") + .HasColumnType("text") + .HasColumnName("country_bho"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_bho"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("created_by_bho"); + + b.Property("ElevationPrecisionId") + .HasColumnType("integer") + .HasColumnName("qt_elevation_id_cli"); + + b.Property("ElevationZ") + .HasColumnType("double precision") + .HasColumnName("elevation_z_bho"); + + b.Property("Geometry") + .HasColumnType("geometry") + .HasColumnName("geom_bho"); + + b.Property("HasGroundwater") + .HasColumnType("boolean") + .HasColumnName("groundwater_bho"); + + b.Property("HrsId") + .HasColumnType("integer") + .HasColumnName("hrs_id_cli"); + + b.Property("IsPublic") + .HasColumnType("boolean") + .HasColumnName("public_bho"); + + b.Property("LithologyTopBedrockId") + .HasColumnType("integer") + .HasColumnName("lithology_top_bedrock_id_cli"); + + b.Property("LithostratigraphyId") + .HasColumnType("integer") + .HasColumnName("lithostrat_id_cli"); + + b.Property("LocationPrecisionId") + .HasColumnType("integer") + .HasColumnName("qt_location_id_cli"); + + b.Property("LocationX") + .HasColumnType("double precision") + .HasColumnName("location_x_bho"); + + b.Property("LocationXLV03") + .HasColumnType("double precision") + .HasColumnName("location_x_lv03_bho"); + + b.Property("LocationY") + .HasColumnType("double precision") + .HasColumnName("location_y_bho"); + + b.Property("LocationYLV03") + .HasColumnType("double precision") + .HasColumnName("location_y_lv03_bho"); + + b.Property("Locked") + .HasColumnType("timestamp with time zone") + .HasColumnName("locked_bho"); + + b.Property("LockedById") + .HasColumnType("integer") + .HasColumnName("locked_by_bho"); + + b.Property("Municipality") + .HasColumnType("text") + .HasColumnName("municipality_bho"); + + b.Property("NationalInterest") + .HasColumnType("boolean") + .HasColumnName("national_interest"); + + b.Property("OriginalName") + .HasColumnType("text") + .HasColumnName("original_name_bho"); + + b.Property("OriginalReferenceSystem") + .HasColumnType("integer") + .HasColumnName("srs_id_cli"); + + b.Property("PrecisionLocationX") + .HasColumnType("integer") + .HasColumnName("precision_location_x"); + + b.Property("PrecisionLocationXLV03") + .HasColumnType("integer") + .HasColumnName("precision_location_x_lv03"); + + b.Property("PrecisionLocationY") + .HasColumnType("integer") + .HasColumnName("precision_location_y"); + + b.Property("PrecisionLocationYLV03") + .HasColumnType("integer") + .HasColumnName("precision_location_y_lv03"); + + b.Property("ProjectName") + .HasColumnType("text") + .HasColumnName("project_name_bho"); + + b.Property("PurposeId") + .HasColumnType("integer") + .HasColumnName("purpose_id_cli"); + + b.Property("QtDepthId") + .HasColumnType("integer") + .HasColumnName("qt_depth_id_cli"); + + b.Property("QtReferenceElevationId") + .HasColumnType("integer") + .HasColumnName("qt_reference_elevation_id_cli"); + + b.Property("ReferenceElevation") + .HasColumnType("double precision") + .HasColumnName("reference_elevation_bho"); + + b.Property("ReferenceElevationTypeId") + .HasColumnType("integer") + .HasColumnName("reference_elevation_type_id_cli"); + + b.Property("Remarks") + .HasColumnType("text") + .HasColumnName("remarks_bho"); + + b.Property("RestrictionId") + .HasColumnType("integer") + .HasColumnName("restriction_id_cli"); + + b.Property("RestrictionUntil") + .HasColumnType("timestamp with time zone") + .HasColumnName("restriction_until_bho"); + + b.Property("StatusId") + .HasColumnType("integer") + .HasColumnName("status_id_cli"); + + b.Property("TopBedrockFreshMd") + .HasColumnType("double precision") + .HasColumnName("top_bedrock_fresh_md"); + + b.Property("TopBedrockWeatheredMd") + .HasColumnType("double precision") + .HasColumnName("top_bedrock_weathered_md"); + + b.Property("TotalDepth") + .HasColumnType("double precision") + .HasColumnName("total_depth_bho"); + + b.Property("TypeId") + .HasColumnType("integer") + .HasColumnName("borehole_type_id"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_bho"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updated_by_bho"); + + b.Property("WorkgroupId") + .HasColumnType("integer") + .HasColumnName("id_wgp_fk"); + + b.HasKey("Id"); + + b.HasIndex("ChronostratigraphyId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ElevationPrecisionId"); + + b.HasIndex("HrsId"); + + b.HasIndex("LithologyTopBedrockId"); + + b.HasIndex("LithostratigraphyId"); + + b.HasIndex("LocationPrecisionId"); + + b.HasIndex("LockedById"); + + b.HasIndex("PurposeId"); + + b.HasIndex("QtDepthId"); + + b.HasIndex("QtReferenceElevationId"); + + b.HasIndex("ReferenceElevationTypeId"); + + b.HasIndex("RestrictionId"); + + b.HasIndex("StatusId"); + + b.HasIndex("TypeId"); + + b.HasIndex("UpdatedById"); + + b.HasIndex("WorkgroupId"); + + b.ToTable("borehole", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.BoreholeCodelist", b => + { + b.Property("BoreholeId") + .HasColumnType("integer") + .HasColumnName("borehole_id"); + + b.Property("CodelistId") + .HasColumnType("integer") + .HasColumnName("identifier_id"); + + b.Property("Value") + .IsRequired() + .HasColumnType("text") + .HasColumnName("identifier_value"); + + b.HasKey("BoreholeId", "CodelistId"); + + b.HasIndex("CodelistId"); + + b.ToTable("borehole_identifiers_codelist", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.BoreholeFile", b => + { + b.Property("BoreholeId") + .HasColumnType("integer") + .HasColumnName("id_bho_fk"); + + b.Property("FileId") + .HasColumnType("integer") + .HasColumnName("id_fil_fk"); + + b.Property("Attached") + .HasColumnType("timestamp with time zone") + .HasColumnName("attached_bfi"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_bfi"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("created_by_bfi"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description_bfi"); + + b.Property("Public") + .HasColumnType("boolean") + .HasColumnName("public_bfi"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update_bfi"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater_bfi"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("id_usr_fk"); + + b.HasKey("BoreholeId", "FileId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("FileId"); + + b.HasIndex("UpdatedById"); + + b.HasIndex("UserId"); + + b.ToTable("borehole_files", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.BoreholeGeometryElement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BoreholeId") + .HasColumnType("integer") + .HasColumnName("borehole_id"); + + b.Property("DEVI") + .HasColumnType("double precision"); + + b.Property("HAZI") + .HasColumnType("double precision"); + + b.Property("MD") + .HasColumnType("double precision"); + + b.Property("X") + .HasColumnType("double precision"); + + b.Property("Y") + .HasColumnType("double precision"); + + b.Property("Z") + .HasColumnType("double precision"); + + b.HasKey("Id"); + + b.HasIndex("BoreholeId"); + + b.ToTable("borehole_geometry", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Casing", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CompletionId") + .HasColumnType("integer") + .HasColumnName("completion_id"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("DateFinish") + .HasColumnType("date") + .HasColumnName("date_finish"); + + b.Property("DateStart") + .HasColumnType("date") + .HasColumnName("date_start"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Notes") + .HasColumnType("text") + .HasColumnName("notes"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.HasKey("Id"); + + b.HasIndex("CompletionId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("casing", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.CasingElement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CasingId") + .HasColumnType("integer") + .HasColumnName("casing_id"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("FromDepth") + .HasColumnType("double precision") + .HasColumnName("from_depth"); + + b.Property("InnerDiameter") + .HasColumnType("double precision") + .HasColumnName("inner_diameter"); + + b.Property("KindId") + .HasColumnType("integer") + .HasColumnName("kind_id"); + + b.Property("MaterialId") + .HasColumnType("integer") + .HasColumnName("material_id"); + + b.Property("OuterDiameter") + .HasColumnType("double precision") + .HasColumnName("outer_diameter"); + + b.Property("ToDepth") + .HasColumnType("double precision") + .HasColumnName("to_depth"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.HasKey("Id"); + + b.HasIndex("CasingId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("KindId"); + + b.HasIndex("MaterialId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("casing_element", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.ChronostratigraphyLayer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id_chr"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("ChronostratigraphyId") + .HasColumnType("integer") + .HasColumnName("chronostratigraphy_id"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("FromDepth") + .HasColumnType("double precision") + .HasColumnName("depth_from"); + + b.Property("StratigraphyId") + .HasColumnType("integer") + .HasColumnName("id_sty_fk"); + + b.Property("ToDepth") + .HasColumnType("double precision") + .HasColumnName("depth_to"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.HasKey("Id"); + + b.HasIndex("ChronostratigraphyId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("StratigraphyId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("chronostratigraphy", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Codelist", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id_cli"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Code") + .IsRequired() + .HasColumnType("text") + .HasColumnName("code_cli"); + + b.Property("Conf") + .HasColumnType("text") + .HasColumnName("conf_cli"); + + b.Property("De") + .HasColumnType("text") + .HasColumnName("text_cli_de"); + + b.Property("En") + .IsRequired() + .HasColumnType("text") + .HasColumnName("text_cli_en"); + + b.Property("Fr") + .HasColumnType("text") + .HasColumnName("text_cli_fr"); + + b.Property("Geolcode") + .HasColumnType("integer") + .HasColumnName("geolcode"); + + b.Property("IsDefault") + .HasColumnType("boolean") + .HasColumnName("default_cli"); + + b.Property("It") + .HasColumnType("text") + .HasColumnName("text_cli_it"); + + b.Property("Order") + .HasColumnType("integer") + .HasColumnName("order_cli"); + + b.Property("Path") + .HasColumnType("ltree") + .HasColumnName("path_cli"); + + b.Property("Ro") + .HasColumnType("text") + .HasColumnName("text_cli_ro"); + + b.Property("Schema") + .HasColumnType("text") + .HasColumnName("schema_cli"); + + b.HasKey("Id"); + + b.ToTable("codelist", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Completion", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AbandonDate") + .HasColumnType("date") + .HasColumnName("abandon_date"); + + b.Property("BoreholeId") + .HasColumnType("integer") + .HasColumnName("borehole_id"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("IsPrimary") + .HasColumnType("boolean") + .HasColumnName("is_primary"); + + b.Property("KindId") + .HasColumnType("integer") + .HasColumnName("kind_id"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Notes") + .HasColumnType("text") + .HasColumnName("notes"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.HasKey("Id"); + + b.HasIndex("BoreholeId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("KindId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("completion", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Config", b => + { + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name_cfg"); + + b.Property("Value") + .HasColumnType("text") + .HasColumnName("value_cfg"); + + b.HasKey("Name"); + + b.ToTable("config", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.FaciesDescription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id_fac"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("DescriptionQualityId") + .HasColumnType("integer") + .HasColumnName("qt_description_id"); + + b.Property("FromDepth") + .HasColumnType("double precision") + .HasColumnName("depth_from"); + + b.Property("StratigraphyId") + .HasColumnType("integer") + .HasColumnName("id_sty_fk"); + + b.Property("ToDepth") + .HasColumnType("double precision") + .HasColumnName("depth_to"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("DescriptionQualityId"); + + b.HasIndex("StratigraphyId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("facies_description", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.FieldMeasurementResult", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("FieldMeasurementId") + .HasColumnType("integer") + .HasColumnName("fieldmeasurement_id"); + + b.Property("ParameterId") + .HasColumnType("integer") + .HasColumnName("parameter"); + + b.Property("SampleTypeId") + .HasColumnType("integer") + .HasColumnName("sample_type"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.Property("Value") + .HasColumnType("double precision") + .HasColumnName("value"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("FieldMeasurementId"); + + b.HasIndex("ParameterId"); + + b.HasIndex("SampleTypeId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("fieldmeasurement_result", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.File", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id_fil"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("uploaded_fil"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("id_usr_fk"); + + b.Property("Hash") + .IsRequired() + .HasColumnType("text") + .HasColumnName("hash_fil"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name_fil"); + + b.Property("NameUuid") + .HasColumnType("text") + .HasColumnName("name_uuid_fil"); + + b.Property("Type") + .IsRequired() + .HasColumnType("text") + .HasColumnName("type_fil"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("updated_fil"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updated_by_fil"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("files", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.HydrotestEvaluationMethodCode", b => + { + b.Property("HydrotestId") + .HasColumnType("integer") + .HasColumnName("hydrotest_id"); + + b.Property("CodelistId") + .HasColumnType("integer") + .HasColumnName("codelist_id"); + + b.HasKey("HydrotestId", "CodelistId"); + + b.HasIndex("CodelistId"); + + b.ToTable("hydrotest_evaluationmethod_codelist", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.HydrotestFlowDirectionCode", b => + { + b.Property("HydrotestId") + .HasColumnType("integer") + .HasColumnName("hydrotest_id"); + + b.Property("CodelistId") + .HasColumnType("integer") + .HasColumnName("codelist_id"); + + b.HasKey("HydrotestId", "CodelistId"); + + b.HasIndex("CodelistId"); + + b.ToTable("hydrotest_flowdirection_codelist", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.HydrotestKindCode", b => + { + b.Property("HydrotestId") + .HasColumnType("integer") + .HasColumnName("hydrotest_id"); + + b.Property("CodelistId") + .HasColumnType("integer") + .HasColumnName("codelist_id"); + + b.HasKey("HydrotestId", "CodelistId"); + + b.HasIndex("CodelistId"); + + b.ToTable("hydrotest_kind_codelist", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.HydrotestResult", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("HydrotestId") + .HasColumnType("integer") + .HasColumnName("hydrotest_id"); + + b.Property("MaxValue") + .HasColumnType("double precision") + .HasColumnName("max_value"); + + b.Property("MinValue") + .HasColumnType("double precision") + .HasColumnName("min_value"); + + b.Property("ParameterId") + .HasColumnType("integer") + .HasColumnName("parameter"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.Property("Value") + .HasColumnType("double precision") + .HasColumnName("value"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("HydrotestId"); + + b.HasIndex("ParameterId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("hydrotest_result", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Instrumentation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CasingId") + .HasColumnType("integer") + .HasColumnName("casing_id"); + + b.Property("CompletionId") + .HasColumnType("integer") + .HasColumnName("completion_id"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("FromDepth") + .HasColumnType("double precision") + .HasColumnName("from_depth"); + + b.Property("IsOpenBorehole") + .HasColumnType("boolean") + .HasColumnName("is_open_borehole"); + + b.Property("KindId") + .HasColumnType("integer") + .HasColumnName("kind_id"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Notes") + .HasColumnType("text") + .HasColumnName("notes"); + + b.Property("StatusId") + .HasColumnType("integer") + .HasColumnName("status_id"); + + b.Property("ToDepth") + .HasColumnType("double precision") + .HasColumnName("to_depth"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.HasKey("Id"); + + b.HasIndex("CasingId"); + + b.HasIndex("CompletionId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("KindId"); + + b.HasIndex("StatusId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("instrumentation", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Layer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id_lay"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("AlterationId") + .HasColumnType("integer") + .HasColumnName("alteration_id_cli"); + + b.Property("CohesionId") + .HasColumnType("integer") + .HasColumnName("cohesion_id_cli"); + + b.Property("CompactnessId") + .HasColumnType("integer") + .HasColumnName("compactness_id_cli"); + + b.Property("ConsistanceId") + .HasColumnType("integer") + .HasColumnName("consistance_id_cli"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation_lay"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator_lay"); + + b.Property("DescriptionQualityId") + .HasColumnType("integer") + .HasColumnName("qt_description_id_cli"); + + b.Property("FromDepth") + .HasColumnType("double precision") + .HasColumnName("depth_from_lay"); + + b.Property("GradationId") + .HasColumnType("integer") + .HasColumnName("gradation_id_cli"); + + b.Property("GrainSize1Id") + .HasColumnType("integer") + .HasColumnName("grain_size_1_id_cli"); + + b.Property("GrainSize2Id") + .HasColumnType("integer") + .HasColumnName("grain_size_2_id_cli"); + + b.Property("HumidityId") + .HasColumnType("integer") + .HasColumnName("humidity_id_cli"); + + b.Property("IsLast") + .HasColumnType("boolean") + .HasColumnName("last_lay"); + + b.Property("IsStriae") + .HasColumnType("boolean") + .HasColumnName("striae_lay"); + + b.Property("IsUndefined") + .HasColumnType("boolean") + .HasColumnName("undefined_lay"); + + b.Property("LithologyId") + .HasColumnType("integer") + .HasColumnName("lithology_id_cli"); + + b.Property("LithologyTopBedrockId") + .HasColumnType("integer") + .HasColumnName("lithology_top_bedrock_id_cli"); + + b.Property("LithostratigraphyId") + .HasColumnType("integer") + .HasColumnName("lithostratigraphy_id_cli"); + + b.Property("Notes") + .HasColumnType("text") + .HasColumnName("notes_lay"); + + b.Property("OriginalLithology") + .HasColumnType("text") + .HasColumnName("original_lithology"); + + b.Property("OriginalUscs") + .HasColumnType("text") + .HasColumnName("uscs_original_lay"); + + b.Property("PlasticityId") + .HasColumnType("integer") + .HasColumnName("plasticity_id_cli"); + + b.Property("StratigraphyId") + .HasColumnType("integer") + .HasColumnName("id_sty_fk"); + + b.Property("ToDepth") + .HasColumnType("double precision") + .HasColumnName("depth_to_lay"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update_lay"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater_lay"); + + b.Property("Uscs1Id") + .HasColumnType("integer") + .HasColumnName("uscs_1_id_cli"); + + b.Property("Uscs2Id") + .HasColumnType("integer") + .HasColumnName("uscs_2_id_cli"); + + b.Property("UscsDeterminationId") + .HasColumnType("integer") + .HasColumnName("uscs_determination_id_cli"); + + b.HasKey("Id"); + + b.HasIndex("AlterationId"); + + b.HasIndex("CohesionId"); + + b.HasIndex("CompactnessId"); + + b.HasIndex("ConsistanceId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("DescriptionQualityId"); + + b.HasIndex("GradationId"); + + b.HasIndex("GrainSize1Id"); + + b.HasIndex("GrainSize2Id"); + + b.HasIndex("HumidityId"); + + b.HasIndex("LithologyId"); + + b.HasIndex("LithologyTopBedrockId"); + + b.HasIndex("LithostratigraphyId"); + + b.HasIndex("PlasticityId"); + + b.HasIndex("StratigraphyId"); + + b.HasIndex("UpdatedById"); + + b.HasIndex("Uscs1Id"); + + b.HasIndex("Uscs2Id"); + + b.HasIndex("UscsDeterminationId"); + + b.ToTable("layer", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.LayerColorCode", b => + { + b.Property("LayerId") + .HasColumnType("integer") + .HasColumnName("layer_id"); + + b.Property("CodelistId") + .HasColumnType("integer") + .HasColumnName("color_id"); + + b.HasKey("LayerId", "CodelistId"); + + b.HasIndex("CodelistId"); + + b.ToTable("layer_color_codelist", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.LayerDebrisCode", b => + { + b.Property("LayerId") + .HasColumnType("integer") + .HasColumnName("layer_id"); + + b.Property("CodelistId") + .HasColumnType("integer") + .HasColumnName("debris_id"); + + b.HasKey("LayerId", "CodelistId"); + + b.HasIndex("CodelistId"); + + b.ToTable("layer_debris_codelist", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.LayerGrainAngularityCode", b => + { + b.Property("LayerId") + .HasColumnType("integer") + .HasColumnName("layer_id"); + + b.Property("CodelistId") + .HasColumnType("integer") + .HasColumnName("grain_angularity_id"); + + b.HasKey("LayerId", "CodelistId"); + + b.HasIndex("CodelistId"); + + b.ToTable("layer_grain_angularity_codelist", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.LayerGrainShapeCode", b => + { + b.Property("LayerId") + .HasColumnType("integer") + .HasColumnName("layer_id"); + + b.Property("CodelistId") + .HasColumnType("integer") + .HasColumnName("grain_shape_id"); + + b.HasKey("LayerId", "CodelistId"); + + b.HasIndex("CodelistId"); + + b.ToTable("layer_grain_shape_codelist", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.LayerOrganicComponentCode", b => + { + b.Property("LayerId") + .HasColumnType("integer") + .HasColumnName("layer_id"); + + b.Property("CodelistId") + .HasColumnType("integer") + .HasColumnName("organic_components_id"); + + b.HasKey("LayerId", "CodelistId"); + + b.HasIndex("CodelistId"); + + b.ToTable("layer_organic_component_codelist", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.LayerUscs3Code", b => + { + b.Property("LayerId") + .HasColumnType("integer") + .HasColumnName("layer_id"); + + b.Property("CodelistId") + .HasColumnType("integer") + .HasColumnName("uscs3_id"); + + b.HasKey("LayerId", "CodelistId"); + + b.HasIndex("CodelistId"); + + b.ToTable("layer_uscs3_codelist", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.LithologicalDescription", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id_ldp"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("Description") + .HasColumnType("text") + .HasColumnName("description"); + + b.Property("DescriptionQualityId") + .HasColumnType("integer") + .HasColumnName("qt_description_id"); + + b.Property("FromDepth") + .HasColumnType("double precision") + .HasColumnName("depth_from"); + + b.Property("StratigraphyId") + .HasColumnType("integer") + .HasColumnName("id_sty_fk"); + + b.Property("ToDepth") + .HasColumnType("double precision") + .HasColumnName("depth_to"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("DescriptionQualityId"); + + b.HasIndex("StratigraphyId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("lithological_description", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.LithostratigraphyLayer", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("FromDepth") + .HasColumnType("double precision") + .HasColumnName("depth_from"); + + b.Property("LithostratigraphyId") + .HasColumnType("integer") + .HasColumnName("lithostratigraphy_id"); + + b.Property("StratigraphyId") + .HasColumnType("integer") + .HasColumnName("stratigraphy_id"); + + b.Property("ToDepth") + .HasColumnType("double precision") + .HasColumnName("depth_to"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("LithostratigraphyId"); + + b.HasIndex("StratigraphyId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("lithostratigraphy", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Observation", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BoreholeId") + .HasColumnType("integer") + .HasColumnName("borehole_id"); + + b.Property("CasingId") + .HasColumnType("integer") + .HasColumnName("casing_id"); + + b.Property("Comment") + .HasColumnType("text") + .HasColumnName("comment"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("Duration") + .HasColumnType("double precision") + .HasColumnName("duration"); + + b.Property("EndTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("end_time"); + + b.Property("FromDepthM") + .HasColumnType("double precision") + .HasColumnName("from_depth_m"); + + b.Property("FromDepthMasl") + .HasColumnType("double precision") + .HasColumnName("from_depth_masl"); + + b.Property("IsOpenBorehole") + .HasColumnType("boolean") + .HasColumnName("is_open_borehole"); + + b.Property("ReliabilityId") + .HasColumnType("integer") + .HasColumnName("reliability"); + + b.Property("StartTime") + .HasColumnType("timestamp with time zone") + .HasColumnName("start_time"); + + b.Property("ToDepthM") + .HasColumnType("double precision") + .HasColumnName("to_depth_m"); + + b.Property("ToDepthMasl") + .HasColumnType("double precision") + .HasColumnName("to_depth_masl"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("observation_type"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.HasKey("Id"); + + b.HasIndex("BoreholeId"); + + b.HasIndex("CasingId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("ReliabilityId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("observation", "bdms"); + + b.UseTptMappingStrategy(); + }); + + modelBuilder.Entity("BDMS.Models.Section", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BoreholeId") + .HasColumnType("integer") + .HasColumnName("borehole_id"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.HasKey("Id"); + + b.HasIndex("BoreholeId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("UpdatedById"); + + b.ToTable("section", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.SectionElement", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("creator"); + + b.Property("CuttingsId") + .HasColumnType("integer") + .HasColumnName("cuttings_id"); + + b.Property("DrillingCoreDiameter") + .HasColumnType("double precision") + .HasColumnName("drilling_core_diameter"); + + b.Property("DrillingDiameter") + .HasColumnType("double precision") + .HasColumnName("drilling_diameter"); + + b.Property("DrillingEndDate") + .HasColumnType("date") + .HasColumnName("drilling_end_date"); + + b.Property("DrillingMethodId") + .HasColumnType("integer") + .HasColumnName("drilling_method_id"); + + b.Property("DrillingMudSubtypeId") + .HasColumnType("integer") + .HasColumnName("mud_subtype_id"); + + b.Property("DrillingMudTypeId") + .HasColumnType("integer") + .HasColumnName("mud_type_id"); + + b.Property("DrillingStartDate") + .HasColumnType("date") + .HasColumnName("drilling_start_date"); + + b.Property("FromDepth") + .HasColumnType("double precision") + .HasColumnName("from_depth"); + + b.Property("Order") + .HasColumnType("integer") + .HasColumnName("order"); + + b.Property("SectionId") + .HasColumnType("integer") + .HasColumnName("section_id"); + + b.Property("ToDepth") + .HasColumnType("double precision") + .HasColumnName("to_depth"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater"); + + b.HasKey("Id"); + + b.HasIndex("CreatedById"); + + b.HasIndex("CuttingsId"); + + b.HasIndex("DrillingMethodId"); + + b.HasIndex("DrillingMudSubtypeId"); + + b.HasIndex("DrillingMudTypeId"); + + b.HasIndex("SectionId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("section_element", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Stratigraphy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id_sty"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BoreholeId") + .HasColumnType("integer") + .HasColumnName("id_bho_fk"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation_sty"); + + b.Property("CreatedById") + .HasColumnType("integer") + .HasColumnName("author_sty"); + + b.Property("Date") + .HasColumnType("timestamp with time zone") + .HasColumnName("date_sty"); + + b.Property("IsPrimary") + .HasColumnType("boolean") + .HasColumnName("primary_sty"); + + b.Property("Name") + .HasColumnType("text") + .HasColumnName("name_sty"); + + b.Property("Notes") + .HasColumnType("text") + .HasColumnName("notes_sty"); + + b.Property("QualityId") + .HasColumnType("integer") + .HasColumnName("quality_id"); + + b.Property("Updated") + .HasColumnType("timestamp with time zone") + .HasColumnName("update_sty"); + + b.Property("UpdatedById") + .HasColumnType("integer") + .HasColumnName("updater_sty"); + + b.HasKey("Id"); + + b.HasIndex("BoreholeId"); + + b.HasIndex("CreatedById"); + + b.HasIndex("QualityId"); + + b.HasIndex("UpdatedById"); + + b.ToTable("stratigraphy", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Term", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id_tes"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Creation") + .HasColumnType("timestamp with time zone") + .HasColumnName("creation_tes"); + + b.Property("Expiration") + .HasColumnType("timestamp with time zone") + .HasColumnName("expired_tes"); + + b.Property("IsDraft") + .HasColumnType("boolean") + .HasColumnName("draft_tes"); + + b.Property("TextDe") + .HasColumnType("text") + .HasColumnName("text_tes_de"); + + b.Property("TextEn") + .IsRequired() + .HasColumnType("text") + .HasColumnName("text_tes_en"); + + b.Property("TextFr") + .HasColumnType("text") + .HasColumnName("text_tes_fr"); + + b.Property("TextIt") + .HasColumnType("text") + .HasColumnName("text_tes_it"); + + b.Property("TextRo") + .HasColumnType("text") + .HasColumnName("text_tes_ro"); + + b.HasKey("Id"); + + b.ToTable("terms", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.TermsAccepted", b => + { + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("id_usr_fk"); + + b.Property("TermId") + .HasColumnType("integer") + .HasColumnName("id_tes_fk"); + + b.Property("AcceptedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("accepted_tea"); + + b.HasKey("UserId", "TermId"); + + b.HasIndex("TermId"); + + b.ToTable("terms_accepted", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.User", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id_usr"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_usr"); + + b.Property("DisabledAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("disabled_usr"); + + b.Property("FirstName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("firstname"); + + b.Property("IsAdmin") + .HasColumnType("boolean") + .HasColumnName("admin_usr"); + + b.Property("LastName") + .IsRequired() + .HasColumnType("text") + .HasColumnName("lastname"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("username"); + + b.Property("Settings") + .HasColumnType("text") + .HasColumnName("settings_usr"); + + b.Property("SubjectId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("subject_id"); + + b.HasKey("Id"); + + b.ToTable("users", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.UserWorkgroupRole", b => + { + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("id_usr_fk"); + + b.Property("WorkgroupId") + .HasColumnType("integer") + .HasColumnName("id_wgp_fk"); + + b.Property("Role") + .HasColumnType("int") + .HasColumnName("id_rol_fk"); + + b.HasKey("UserId", "WorkgroupId", "Role"); + + b.HasIndex("WorkgroupId"); + + b.ToTable("users_roles", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Workflow", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id_wkf"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("BoreholeId") + .HasColumnType("integer") + .HasColumnName("id_bho_fk"); + + b.Property("Finished") + .HasColumnType("timestamp with time zone") + .HasColumnName("finished_wkf"); + + b.Property("Notes") + .HasColumnType("text") + .HasColumnName("notes_wkf"); + + b.Property("Role") + .HasColumnType("integer") + .HasColumnName("id_rol_fk"); + + b.Property("Started") + .HasColumnType("timestamp with time zone") + .HasColumnName("started_wkf"); + + b.Property("UserId") + .HasColumnType("integer") + .HasColumnName("id_usr_fk"); + + b.HasKey("Id"); + + b.HasIndex("BoreholeId"); + + b.HasIndex("UserId"); + + b.ToTable("workflow", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Workgroup", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id_wgp"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CreatedAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("created_wgp"); + + b.Property("DisabledAt") + .HasColumnType("timestamp with time zone") + .HasColumnName("disabled_wgp"); + + b.Property("Name") + .IsRequired() + .HasColumnType("text") + .HasColumnName("name_wgp"); + + b.Property("Settings") + .HasColumnType("json") + .HasColumnName("settings_wgp"); + + b.HasKey("Id"); + + b.ToTable("workgroups", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.FieldMeasurement", b => + { + b.HasBaseType("BDMS.Models.Observation"); + + b.ToTable("field_measurement", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.GroundwaterLevelMeasurement", b => + { + b.HasBaseType("BDMS.Models.Observation"); + + b.Property("KindId") + .HasColumnType("integer") + .HasColumnName("kind"); + + b.Property("LevelM") + .HasColumnType("double precision") + .HasColumnName("level_m"); + + b.Property("LevelMasl") + .HasColumnType("double precision") + .HasColumnName("level_masl"); + + b.HasIndex("KindId"); + + b.ToTable("groundwater_level_measurement", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Hydrotest", b => + { + b.HasBaseType("BDMS.Models.Observation"); + + b.ToTable("hydrotest", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.WaterIngress", b => + { + b.HasBaseType("BDMS.Models.Observation"); + + b.Property("ConditionsId") + .HasColumnType("integer") + .HasColumnName("conditions"); + + b.Property("QuantityId") + .HasColumnType("integer") + .HasColumnName("quantity"); + + b.HasIndex("ConditionsId"); + + b.HasIndex("QuantityId"); + + b.ToTable("water_ingress", "bdms"); + }); + + modelBuilder.Entity("BDMS.Models.Backfill", b => + { + b.HasOne("BDMS.Models.Casing", "Casing") + .WithMany("Backfills") + .HasForeignKey("CasingId"); + + b.HasOne("BDMS.Models.Completion", "Completion") + .WithMany("Backfills") + .HasForeignKey("CompletionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Codelist", "Kind") + .WithMany() + .HasForeignKey("KindId"); + + b.HasOne("BDMS.Models.Codelist", "Material") + .WithMany() + .HasForeignKey("MaterialId"); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Casing"); + + b.Navigation("Completion"); + + b.Navigation("CreatedBy"); + + b.Navigation("Kind"); + + b.Navigation("Material"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.Borehole", b => + { + b.HasOne("BDMS.Models.Codelist", "Chronostratigraphy") + .WithMany() + .HasForeignKey("ChronostratigraphyId"); + + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Codelist", "ElevationPrecision") + .WithMany() + .HasForeignKey("ElevationPrecisionId"); + + b.HasOne("BDMS.Models.Codelist", "Hrs") + .WithMany() + .HasForeignKey("HrsId"); + + b.HasOne("BDMS.Models.Codelist", "LithologyTopBedrock") + .WithMany() + .HasForeignKey("LithologyTopBedrockId"); + + b.HasOne("BDMS.Models.Codelist", "Lithostratigraphy") + .WithMany() + .HasForeignKey("LithostratigraphyId"); + + b.HasOne("BDMS.Models.Codelist", "LocationPrecision") + .WithMany() + .HasForeignKey("LocationPrecisionId"); + + b.HasOne("BDMS.Models.User", "LockedBy") + .WithMany() + .HasForeignKey("LockedById"); + + b.HasOne("BDMS.Models.Codelist", "Purpose") + .WithMany() + .HasForeignKey("PurposeId"); + + b.HasOne("BDMS.Models.Codelist", "QtDepth") + .WithMany() + .HasForeignKey("QtDepthId"); + + b.HasOne("BDMS.Models.Codelist", "QtReferenceElevation") + .WithMany() + .HasForeignKey("QtReferenceElevationId"); + + b.HasOne("BDMS.Models.Codelist", "ReferenceElevationType") + .WithMany() + .HasForeignKey("ReferenceElevationTypeId"); + + b.HasOne("BDMS.Models.Codelist", "Restriction") + .WithMany() + .HasForeignKey("RestrictionId"); + + b.HasOne("BDMS.Models.Codelist", "Status") + .WithMany() + .HasForeignKey("StatusId"); + + b.HasOne("BDMS.Models.Codelist", "Type") + .WithMany() + .HasForeignKey("TypeId"); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.HasOne("BDMS.Models.Workgroup", "Workgroup") + .WithMany("Boreholes") + .HasForeignKey("WorkgroupId"); + + b.Navigation("Chronostratigraphy"); + + b.Navigation("CreatedBy"); + + b.Navigation("ElevationPrecision"); + + b.Navigation("Hrs"); + + b.Navigation("LithologyTopBedrock"); + + b.Navigation("Lithostratigraphy"); + + b.Navigation("LocationPrecision"); + + b.Navigation("LockedBy"); + + b.Navigation("Purpose"); + + b.Navigation("QtDepth"); + + b.Navigation("QtReferenceElevation"); + + b.Navigation("ReferenceElevationType"); + + b.Navigation("Restriction"); + + b.Navigation("Status"); + + b.Navigation("Type"); + + b.Navigation("UpdatedBy"); + + b.Navigation("Workgroup"); + }); + + modelBuilder.Entity("BDMS.Models.BoreholeCodelist", b => + { + b.HasOne("BDMS.Models.Borehole", "Borehole") + .WithMany("BoreholeCodelists") + .HasForeignKey("BoreholeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Codelist", "Codelist") + .WithMany("BoreholeCodelists") + .HasForeignKey("CodelistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Borehole"); + + b.Navigation("Codelist"); + }); + + modelBuilder.Entity("BDMS.Models.BoreholeFile", b => + { + b.HasOne("BDMS.Models.Borehole", "Borehole") + .WithMany("BoreholeFiles") + .HasForeignKey("BoreholeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.File", "File") + .WithMany("BoreholeFiles") + .HasForeignKey("FileId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.HasOne("BDMS.Models.User", "User") + .WithMany() + .HasForeignKey("UserId"); + + b.Navigation("Borehole"); + + b.Navigation("CreatedBy"); + + b.Navigation("File"); + + b.Navigation("UpdatedBy"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("BDMS.Models.BoreholeGeometryElement", b => + { + b.HasOne("BDMS.Models.Borehole", "Borehole") + .WithMany("BoreholeGeometry") + .HasForeignKey("BoreholeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Borehole"); + }); + + modelBuilder.Entity("BDMS.Models.Casing", b => + { + b.HasOne("BDMS.Models.Completion", "Completion") + .WithMany("Casings") + .HasForeignKey("CompletionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Completion"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.CasingElement", b => + { + b.HasOne("BDMS.Models.Casing", "Casing") + .WithMany("CasingElements") + .HasForeignKey("CasingId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Codelist", "Kind") + .WithMany() + .HasForeignKey("KindId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("BDMS.Models.Codelist", "Material") + .WithMany() + .HasForeignKey("MaterialId"); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Casing"); + + b.Navigation("CreatedBy"); + + b.Navigation("Kind"); + + b.Navigation("Material"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.ChronostratigraphyLayer", b => + { + b.HasOne("BDMS.Models.Codelist", "Chronostratigraphy") + .WithMany() + .HasForeignKey("ChronostratigraphyId"); + + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Stratigraphy", "Stratigraphy") + .WithMany("ChronostratigraphyLayers") + .HasForeignKey("StratigraphyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Chronostratigraphy"); + + b.Navigation("CreatedBy"); + + b.Navigation("Stratigraphy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.Completion", b => + { + b.HasOne("BDMS.Models.Borehole", "Borehole") + .WithMany("Completions") + .HasForeignKey("BoreholeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Codelist", "Kind") + .WithMany() + .HasForeignKey("KindId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Borehole"); + + b.Navigation("CreatedBy"); + + b.Navigation("Kind"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.FaciesDescription", b => + { + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Codelist", "DescriptionQuality") + .WithMany() + .HasForeignKey("DescriptionQualityId"); + + b.HasOne("BDMS.Models.Stratigraphy", "Stratigraphy") + .WithMany("FaciesDescriptions") + .HasForeignKey("StratigraphyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("DescriptionQuality"); + + b.Navigation("Stratigraphy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.FieldMeasurementResult", b => + { + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.FieldMeasurement", "FieldMeasurement") + .WithMany("FieldMeasurementResults") + .HasForeignKey("FieldMeasurementId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Codelist", "Parameter") + .WithMany() + .HasForeignKey("ParameterId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("BDMS.Models.Codelist", "SampleType") + .WithMany() + .HasForeignKey("SampleTypeId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("FieldMeasurement"); + + b.Navigation("Parameter"); + + b.Navigation("SampleType"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.File", b => + { + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.HydrotestEvaluationMethodCode", b => + { + b.HasOne("BDMS.Models.Codelist", "Codelist") + .WithMany("HydrotestEvaluationMethodCodes") + .HasForeignKey("CodelistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Hydrotest", "Hydrotest") + .WithMany("HydrotestEvaluationMethodCodes") + .HasForeignKey("HydrotestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Codelist"); + + b.Navigation("Hydrotest"); + }); + + modelBuilder.Entity("BDMS.Models.HydrotestFlowDirectionCode", b => + { + b.HasOne("BDMS.Models.Codelist", "Codelist") + .WithMany("HydrotestFlowDirectionCodes") + .HasForeignKey("CodelistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Hydrotest", "Hydrotest") + .WithMany("HydrotestFlowDirectionCodes") + .HasForeignKey("HydrotestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Codelist"); + + b.Navigation("Hydrotest"); + }); + + modelBuilder.Entity("BDMS.Models.HydrotestKindCode", b => + { + b.HasOne("BDMS.Models.Codelist", "Codelist") + .WithMany("HydrotestKindCodes") + .HasForeignKey("CodelistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Hydrotest", "Hydrotest") + .WithMany("HydrotestKindCodes") + .HasForeignKey("HydrotestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Codelist"); + + b.Navigation("Hydrotest"); + }); + + modelBuilder.Entity("BDMS.Models.HydrotestResult", b => + { + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Hydrotest", "Hydrotest") + .WithMany("HydrotestResults") + .HasForeignKey("HydrotestId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Codelist", "Parameter") + .WithMany() + .HasForeignKey("ParameterId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Hydrotest"); + + b.Navigation("Parameter"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.Instrumentation", b => + { + b.HasOne("BDMS.Models.Casing", "Casing") + .WithMany("Instrumentations") + .HasForeignKey("CasingId"); + + b.HasOne("BDMS.Models.Completion", "Completion") + .WithMany("Instrumentations") + .HasForeignKey("CompletionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Codelist", "Kind") + .WithMany() + .HasForeignKey("KindId"); + + b.HasOne("BDMS.Models.Codelist", "Status") + .WithMany() + .HasForeignKey("StatusId"); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Casing"); + + b.Navigation("Completion"); + + b.Navigation("CreatedBy"); + + b.Navigation("Kind"); + + b.Navigation("Status"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.Layer", b => + { + b.HasOne("BDMS.Models.Codelist", "Alteration") + .WithMany() + .HasForeignKey("AlterationId"); + + b.HasOne("BDMS.Models.Codelist", "Cohesion") + .WithMany() + .HasForeignKey("CohesionId"); + + b.HasOne("BDMS.Models.Codelist", "Compactness") + .WithMany() + .HasForeignKey("CompactnessId"); + + b.HasOne("BDMS.Models.Codelist", "Consistance") + .WithMany() + .HasForeignKey("ConsistanceId"); + + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Codelist", "DescriptionQuality") + .WithMany() + .HasForeignKey("DescriptionQualityId"); + + b.HasOne("BDMS.Models.Codelist", "Gradation") + .WithMany() + .HasForeignKey("GradationId"); + + b.HasOne("BDMS.Models.Codelist", "GrainSize1") + .WithMany() + .HasForeignKey("GrainSize1Id"); + + b.HasOne("BDMS.Models.Codelist", "GrainSize2") + .WithMany() + .HasForeignKey("GrainSize2Id"); + + b.HasOne("BDMS.Models.Codelist", "Humidity") + .WithMany() + .HasForeignKey("HumidityId"); + + b.HasOne("BDMS.Models.Codelist", "Lithology") + .WithMany() + .HasForeignKey("LithologyId"); + + b.HasOne("BDMS.Models.Codelist", "LithologyTopBedrock") + .WithMany() + .HasForeignKey("LithologyTopBedrockId"); + + b.HasOne("BDMS.Models.Codelist", "Lithostratigraphy") + .WithMany() + .HasForeignKey("LithostratigraphyId"); + + b.HasOne("BDMS.Models.Codelist", "Plasticity") + .WithMany() + .HasForeignKey("PlasticityId"); + + b.HasOne("BDMS.Models.Stratigraphy", "Stratigraphy") + .WithMany("Layers") + .HasForeignKey("StratigraphyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.HasOne("BDMS.Models.Codelist", "Uscs1") + .WithMany() + .HasForeignKey("Uscs1Id"); + + b.HasOne("BDMS.Models.Codelist", "Uscs2") + .WithMany() + .HasForeignKey("Uscs2Id"); + + b.HasOne("BDMS.Models.Codelist", "UscsDetermination") + .WithMany() + .HasForeignKey("UscsDeterminationId"); + + b.Navigation("Alteration"); + + b.Navigation("Cohesion"); + + b.Navigation("Compactness"); + + b.Navigation("Consistance"); + + b.Navigation("CreatedBy"); + + b.Navigation("DescriptionQuality"); + + b.Navigation("Gradation"); + + b.Navigation("GrainSize1"); + + b.Navigation("GrainSize2"); + + b.Navigation("Humidity"); + + b.Navigation("Lithology"); + + b.Navigation("LithologyTopBedrock"); + + b.Navigation("Lithostratigraphy"); + + b.Navigation("Plasticity"); + + b.Navigation("Stratigraphy"); + + b.Navigation("UpdatedBy"); + + b.Navigation("Uscs1"); + + b.Navigation("Uscs2"); + + b.Navigation("UscsDetermination"); + }); + + modelBuilder.Entity("BDMS.Models.LayerColorCode", b => + { + b.HasOne("BDMS.Models.Codelist", "Codelist") + .WithMany("LayerColorCodes") + .HasForeignKey("CodelistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Layer", "Layer") + .WithMany("LayerColorCodes") + .HasForeignKey("LayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Codelist"); + + b.Navigation("Layer"); + }); + + modelBuilder.Entity("BDMS.Models.LayerDebrisCode", b => + { + b.HasOne("BDMS.Models.Codelist", "Codelist") + .WithMany("LayerDebrisCodes") + .HasForeignKey("CodelistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Layer", "Layer") + .WithMany("LayerDebrisCodes") + .HasForeignKey("LayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Codelist"); + + b.Navigation("Layer"); + }); + + modelBuilder.Entity("BDMS.Models.LayerGrainAngularityCode", b => + { + b.HasOne("BDMS.Models.Codelist", "Codelist") + .WithMany("LayerGrainAngularityCodes") + .HasForeignKey("CodelistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Layer", "Layer") + .WithMany("LayerGrainAngularityCodes") + .HasForeignKey("LayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Codelist"); + + b.Navigation("Layer"); + }); + + modelBuilder.Entity("BDMS.Models.LayerGrainShapeCode", b => + { + b.HasOne("BDMS.Models.Codelist", "Codelist") + .WithMany("LayerGrainShapeCodes") + .HasForeignKey("CodelistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Layer", "Layer") + .WithMany("LayerGrainShapeCodes") + .HasForeignKey("LayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Codelist"); + + b.Navigation("Layer"); + }); + + modelBuilder.Entity("BDMS.Models.LayerOrganicComponentCode", b => + { + b.HasOne("BDMS.Models.Codelist", "Codelist") + .WithMany("LayerOrganicComponentCodes") + .HasForeignKey("CodelistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Layer", "Layer") + .WithMany("LayerOrganicComponentCodes") + .HasForeignKey("LayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Codelist"); + + b.Navigation("Layer"); + }); + + modelBuilder.Entity("BDMS.Models.LayerUscs3Code", b => + { + b.HasOne("BDMS.Models.Codelist", "Codelist") + .WithMany("LayerUscs3Codes") + .HasForeignKey("CodelistId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Layer", "Layer") + .WithMany("LayerUscs3Codes") + .HasForeignKey("LayerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Codelist"); + + b.Navigation("Layer"); + }); + + modelBuilder.Entity("BDMS.Models.LithologicalDescription", b => + { + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Codelist", "DescriptionQuality") + .WithMany() + .HasForeignKey("DescriptionQualityId"); + + b.HasOne("BDMS.Models.Stratigraphy", "Stratigraphy") + .WithMany("LithologicalDescriptions") + .HasForeignKey("StratigraphyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("DescriptionQuality"); + + b.Navigation("Stratigraphy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.LithostratigraphyLayer", b => + { + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Codelist", "Lithostratigraphy") + .WithMany() + .HasForeignKey("LithostratigraphyId"); + + b.HasOne("BDMS.Models.Stratigraphy", "Stratigraphy") + .WithMany("LithostratigraphyLayers") + .HasForeignKey("StratigraphyId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Lithostratigraphy"); + + b.Navigation("Stratigraphy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.Observation", b => + { + b.HasOne("BDMS.Models.Borehole", "Borehole") + .WithMany("Observations") + .HasForeignKey("BoreholeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Casing", "Casing") + .WithMany("Observations") + .HasForeignKey("CasingId"); + + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Codelist", "Reliability") + .WithMany() + .HasForeignKey("ReliabilityId") + .OnDelete(DeleteBehavior.NoAction); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Borehole"); + + b.Navigation("Casing"); + + b.Navigation("CreatedBy"); + + b.Navigation("Reliability"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.Section", b => + { + b.HasOne("BDMS.Models.Borehole", "Borehole") + .WithMany("Sections") + .HasForeignKey("BoreholeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Borehole"); + + b.Navigation("CreatedBy"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.SectionElement", b => + { + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Codelist", "Cuttings") + .WithMany() + .HasForeignKey("CuttingsId"); + + b.HasOne("BDMS.Models.Codelist", "DrillingMethod") + .WithMany() + .HasForeignKey("DrillingMethodId"); + + b.HasOne("BDMS.Models.Codelist", "DrillingMudSubtype") + .WithMany() + .HasForeignKey("DrillingMudSubtypeId"); + + b.HasOne("BDMS.Models.Codelist", "DrillingMudType") + .WithMany() + .HasForeignKey("DrillingMudTypeId"); + + b.HasOne("BDMS.Models.Section", "Section") + .WithMany("SectionElements") + .HasForeignKey("SectionId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("CreatedBy"); + + b.Navigation("Cuttings"); + + b.Navigation("DrillingMethod"); + + b.Navigation("DrillingMudSubtype"); + + b.Navigation("DrillingMudType"); + + b.Navigation("Section"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.Stratigraphy", b => + { + b.HasOne("BDMS.Models.Borehole", "Borehole") + .WithMany("Stratigraphies") + .HasForeignKey("BoreholeId"); + + b.HasOne("BDMS.Models.User", "CreatedBy") + .WithMany() + .HasForeignKey("CreatedById"); + + b.HasOne("BDMS.Models.Codelist", "Quality") + .WithMany() + .HasForeignKey("QualityId"); + + b.HasOne("BDMS.Models.User", "UpdatedBy") + .WithMany() + .HasForeignKey("UpdatedById"); + + b.Navigation("Borehole"); + + b.Navigation("CreatedBy"); + + b.Navigation("Quality"); + + b.Navigation("UpdatedBy"); + }); + + modelBuilder.Entity("BDMS.Models.TermsAccepted", b => + { + b.HasOne("BDMS.Models.Term", "Term") + .WithMany() + .HasForeignKey("TermId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "User") + .WithMany("TermsAccepted") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Term"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("BDMS.Models.UserWorkgroupRole", b => + { + b.HasOne("BDMS.Models.User", "User") + .WithMany("WorkgroupRoles") + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Workgroup", "Workgroup") + .WithMany() + .HasForeignKey("WorkgroupId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("User"); + + b.Navigation("Workgroup"); + }); + + modelBuilder.Entity("BDMS.Models.Workflow", b => + { + b.HasOne("BDMS.Models.Borehole", "Borehole") + .WithMany("Workflows") + .HasForeignKey("BoreholeId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.User", "User") + .WithMany() + .HasForeignKey("UserId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.Navigation("Borehole"); + + b.Navigation("User"); + }); + + modelBuilder.Entity("BDMS.Models.FieldMeasurement", b => + { + b.HasOne("BDMS.Models.Observation", null) + .WithOne() + .HasForeignKey("BDMS.Models.FieldMeasurement", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BDMS.Models.GroundwaterLevelMeasurement", b => + { + b.HasOne("BDMS.Models.Observation", null) + .WithOne() + .HasForeignKey("BDMS.Models.GroundwaterLevelMeasurement", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Codelist", "Kind") + .WithMany() + .HasForeignKey("KindId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Kind"); + }); + + modelBuilder.Entity("BDMS.Models.Hydrotest", b => + { + b.HasOne("BDMS.Models.Observation", null) + .WithOne() + .HasForeignKey("BDMS.Models.Hydrotest", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + }); + + modelBuilder.Entity("BDMS.Models.WaterIngress", b => + { + b.HasOne("BDMS.Models.Codelist", "Conditions") + .WithMany() + .HasForeignKey("ConditionsId"); + + b.HasOne("BDMS.Models.Observation", null) + .WithOne() + .HasForeignKey("BDMS.Models.WaterIngress", "Id") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired(); + + b.HasOne("BDMS.Models.Codelist", "Quantity") + .WithMany() + .HasForeignKey("QuantityId") + .OnDelete(DeleteBehavior.NoAction) + .IsRequired(); + + b.Navigation("Conditions"); + + b.Navigation("Quantity"); + }); + + modelBuilder.Entity("BDMS.Models.Borehole", b => + { + b.Navigation("BoreholeCodelists"); + + b.Navigation("BoreholeFiles"); + + b.Navigation("BoreholeGeometry"); + + b.Navigation("Completions"); + + b.Navigation("Observations"); + + b.Navigation("Sections"); + + b.Navigation("Stratigraphies"); + + b.Navigation("Workflows"); + }); + + modelBuilder.Entity("BDMS.Models.Casing", b => + { + b.Navigation("Backfills"); + + b.Navigation("CasingElements"); + + b.Navigation("Instrumentations"); + + b.Navigation("Observations"); + }); + + modelBuilder.Entity("BDMS.Models.Codelist", b => + { + b.Navigation("BoreholeCodelists"); + + b.Navigation("HydrotestEvaluationMethodCodes"); + + b.Navigation("HydrotestFlowDirectionCodes"); + + b.Navigation("HydrotestKindCodes"); + + b.Navigation("LayerColorCodes"); + + b.Navigation("LayerDebrisCodes"); + + b.Navigation("LayerGrainAngularityCodes"); + + b.Navigation("LayerGrainShapeCodes"); + + b.Navigation("LayerOrganicComponentCodes"); + + b.Navigation("LayerUscs3Codes"); + }); + + modelBuilder.Entity("BDMS.Models.Completion", b => + { + b.Navigation("Backfills"); + + b.Navigation("Casings"); + + b.Navigation("Instrumentations"); + }); + + modelBuilder.Entity("BDMS.Models.File", b => + { + b.Navigation("BoreholeFiles"); + }); + + modelBuilder.Entity("BDMS.Models.Layer", b => + { + b.Navigation("LayerColorCodes"); + + b.Navigation("LayerDebrisCodes"); + + b.Navigation("LayerGrainAngularityCodes"); + + b.Navigation("LayerGrainShapeCodes"); + + b.Navigation("LayerOrganicComponentCodes"); + + b.Navigation("LayerUscs3Codes"); + }); + + modelBuilder.Entity("BDMS.Models.Section", b => + { + b.Navigation("SectionElements"); + }); + + modelBuilder.Entity("BDMS.Models.Stratigraphy", b => + { + b.Navigation("ChronostratigraphyLayers"); + + b.Navigation("FaciesDescriptions"); + + b.Navigation("Layers"); + + b.Navigation("LithologicalDescriptions"); + + b.Navigation("LithostratigraphyLayers"); + }); + + modelBuilder.Entity("BDMS.Models.User", b => + { + b.Navigation("TermsAccepted"); + + b.Navigation("WorkgroupRoles"); + }); + + modelBuilder.Entity("BDMS.Models.Workgroup", b => + { + b.Navigation("Boreholes"); + }); + + modelBuilder.Entity("BDMS.Models.FieldMeasurement", b => + { + b.Navigation("FieldMeasurementResults"); + }); + + modelBuilder.Entity("BDMS.Models.Hydrotest", b => + { + b.Navigation("HydrotestEvaluationMethodCodes"); + + b.Navigation("HydrotestFlowDirectionCodes"); + + b.Navigation("HydrotestKindCodes"); + + b.Navigation("HydrotestResults"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/api/Migrations/20241122080247_RemoveFileHash.cs b/src/api/Migrations/20241122080247_RemoveFileHash.cs new file mode 100644 index 000000000..985fd9e6c --- /dev/null +++ b/src/api/Migrations/20241122080247_RemoveFileHash.cs @@ -0,0 +1,28 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +namespace BDMS.Migrations; + +/// +public partial class RemoveFileHash : Migration +{ + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "hash_fil", + schema: "bdms", + table: "files"); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.AddColumn( + name: "hash_fil", + schema: "bdms", + table: "files", + type: "text", + nullable: false, + defaultValue: ""); + } +} diff --git a/src/api/Models/File.cs b/src/api/Models/File.cs index 3247924e6..e8489da4c 100644 --- a/src/api/Models/File.cs +++ b/src/api/Models/File.cs @@ -42,12 +42,6 @@ public class File : IChangeTracking, IIdentifyable [Column("name_uuid_fil")] public string? NameUuid { get; set; } - /// - /// Gets or sets the 's hash. - /// - [Column("hash_fil")] - public string Hash { get; set; } - /// /// Gets or sets the 's type. /// From 648b245a53165035646c8c3abf469329eb1eb8b9 Mon Sep 17 00:00:00 2001 From: Oliver Gut Date: Mon, 2 Dec 2024 13:54:34 +0100 Subject: [PATCH 02/23] Remove deduplication check when adding or detaching borehole attachments. --- src/api/BoreholeFileCloudService.cs | 40 +++++--------- src/api/Controllers/BoreholeFileController.cs | 12 ++--- .../cypress/e2e/detailPage/attachments.cy.js | 34 ++++++------ .../attachments/table/filesTableComponent.jsx | 1 + .../Controllers/BoreholeFileControllerTest.cs | 52 +++++++++---------- 5 files changed, 63 insertions(+), 76 deletions(-) diff --git a/src/api/BoreholeFileCloudService.cs b/src/api/BoreholeFileCloudService.cs index 871dc8bcc..26924a6f8 100644 --- a/src/api/BoreholeFileCloudService.cs +++ b/src/api/BoreholeFileCloudService.cs @@ -35,18 +35,6 @@ public BoreholeFileCloudService(BdmsContext context, IConfiguration configuratio /// The to link the uploaded to. public async Task UploadFileAndLinkToBorehole(IFormFile file, int boreholeId) { - // Generate a hash based on the file content. - var base64Hash = ""; - using (SHA256 sha256Hash = SHA256.Create()) - { - using Stream stream = file.OpenReadStream(); - byte[] hashBytes = await sha256Hash.ComputeHashAsync(stream).ConfigureAwait(false); - base64Hash = Convert.ToBase64String(hashBytes); - } - - // Check any file with the same hash already exists in the database. - var fileId = context.Files.FirstOrDefault(f => f.Hash == base64Hash)?.Id; - // Use transaction to ensure data is only stored to db if the file upload was sucessful. Only create a transaction if there is not already one from the calling method. using var transaction = context.Database.CurrentTransaction == null ? await context.Database.BeginTransactionAsync().ConfigureAwait(false) : null; try @@ -60,28 +48,26 @@ public async Task UploadFileAndLinkToBorehole(IFormFile file, int if (user == null || subjectId == null) throw new InvalidOperationException($"No user with subject_id <{subjectId}> found."); - // If file does not exist on storage, upload it and create file in database. - if (fileId == null) - { - var fileExtension = Path.GetExtension(file.FileName); - var fileNameGuid = $"{Guid.NewGuid()}{fileExtension}"; + // Register the new file in the boreholes database. + var fileExtension = Path.GetExtension(file.FileName); + var fileNameGuid = $"{Guid.NewGuid()}{fileExtension}"; - var bdmsFile = new Models.File { Name = file.FileName, NameUuid = fileNameGuid, Hash = base64Hash, Type = file.ContentType }; + var bdmsFile = new Models.File { Name = file.FileName, NameUuid = fileNameGuid, Type = file.ContentType }; - await context.Files.AddAsync(bdmsFile).ConfigureAwait(false); - await context.UpdateChangeInformationAndSaveChangesAsync(httpContextAccessor.HttpContext!).ConfigureAwait(false); + await context.Files.AddAsync(bdmsFile).ConfigureAwait(false); + await context.UpdateChangeInformationAndSaveChangesAsync(httpContextAccessor.HttpContext!).ConfigureAwait(false); - fileId = bdmsFile.Id; + var fileId = bdmsFile.Id; - // Upload the file to the cloud storage. - await UploadObject(file, fileNameGuid).ConfigureAwait(false); - } + // Upload the file to the cloud storage. + await UploadObject(file, fileNameGuid).ConfigureAwait(false); // If file is already linked to the borehole, throw an exception. - if (context.BoreholeFiles.Any(bf => bf.BoreholeId == boreholeId && bf.FileId == fileId)) throw new InvalidOperationException($"File <{file.FileName}> is already attached to borehole with Id <{boreholeId}>."); + if (await context.BoreholeFiles.AnyAsync(bf => bf.BoreholeId == boreholeId && bf.FileId == fileId).ConfigureAwait(false)) + throw new InvalidOperationException($"File <{file.FileName}> is already attached to borehole with Id <{boreholeId}>."); // Link file to the borehole. - var boreholeFile = new BoreholeFile { FileId = (int)fileId, BoreholeId = boreholeId, UserId = user.Id, Attached = DateTime.UtcNow }; + var boreholeFile = new BoreholeFile { FileId = fileId, BoreholeId = boreholeId, UserId = user.Id, Attached = DateTime.UtcNow }; var entityEntry = await context.BoreholeFiles.AddAsync(boreholeFile).ConfigureAwait(false); await context.UpdateChangeInformationAndSaveChangesAsync(httpContextAccessor.HttpContext!).ConfigureAwait(false); @@ -91,7 +77,7 @@ public async Task UploadFileAndLinkToBorehole(IFormFile file, int } catch (Exception ex) { - logger.LogError(ex, $"Error attaching file <{file.FileName}> to borehole with Id <{boreholeId}>."); + logger.LogError(ex, "Error attaching file <{FileName}> to borehole with Id <{BoreholeId}>.", file.FileName, boreholeId); throw; } } diff --git a/src/api/Controllers/BoreholeFileController.cs b/src/api/Controllers/BoreholeFileController.cs index 11aa1200b..3ad572355 100644 --- a/src/api/Controllers/BoreholeFileController.cs +++ b/src/api/Controllers/BoreholeFileController.cs @@ -210,9 +210,9 @@ public async Task DetachFromBorehole([Required, Range(1, int.MaxV try { // Get the file and its borehole files from the database. - var boreholeFile = await context.BoreholeFiles.Include(f => f.File).FirstOrDefaultAsync(f => f.FileId == boreholeFileId).ConfigureAwait(false); + var boreholeFile = await context.BoreholeFiles.Include(f => f.File).SingleOrDefaultAsync(f => f.FileId == boreholeFileId).ConfigureAwait(false); - if (boreholeFile == null) return NotFound(); + if (boreholeFile == null) return NotFound("Borehole file for the provided boreholeFileId not found."); var fileId = boreholeFile.File.Id; @@ -220,11 +220,9 @@ public async Task DetachFromBorehole([Required, Range(1, int.MaxV context.BoreholeFiles.Remove(boreholeFile); await context.SaveChangesAsync().ConfigureAwait(false); - // Get the file and its borehole files from the database. - var file = await context.Files.Include(f => f.BoreholeFiles).FirstOrDefaultAsync(f => f.Id == fileId).ConfigureAwait(false); - - // If the file is not linked to any boreholes, delete it from the cloud storage and the database. - if (file?.NameUuid != null && file.BoreholeFiles.Count == 0) + // Delete the file from the cloud storage and the database. + var file = await context.Files.SingleOrDefaultAsync(f => f.Id == fileId).ConfigureAwait(false); + if (file?.NameUuid != null) { await boreholeFileCloudService.DeleteObject(file.NameUuid).ConfigureAwait(false); context.Files.Remove(file); diff --git a/src/client/cypress/e2e/detailPage/attachments.cy.js b/src/client/cypress/e2e/detailPage/attachments.cy.js index 2103d41ec..392b4d515 100644 --- a/src/client/cypress/e2e/detailPage/attachments.cy.js +++ b/src/client/cypress/e2e/detailPage/attachments.cy.js @@ -62,44 +62,48 @@ describe("Tests for 'Attachments' edit page.", () => { cy.get("tbody").children().contains("td", "text/plain"); cy.get("tbody").children().contains("td", "application/pdf"); - // Select "IRATETRINITY.pdf" second time. + // Upload and verify file "IRATETRINITY.pdf" for the second time but with different file name. cy.get("input[type=file]").selectFile( { contents: Cypress.Buffer.from(fileContent), - fileName: "IRATETRINITY.pdf", + fileName: "IRATETRINITY_2.pdf", mimeType: "application/pdf", }, { force: true }, ); - - // Upload "IRATETRINITY.pdf" second time. Should not be uploaded. cy.get('[data-cy="attachments-upload-button"]').should("be.visible").click(); cy.wait(["@upload-files"]); - - // Check if error message is displayed. - cy.contains("This file has already been uploaded for this borehole"); - - // Ensure file does not exist in download folder before download. If so, delete it. - deleteDownloadedFile("IRATETRINITY.pdf"); + cy.wait(["@getAllAttachments"]); + cy.get("tbody").children().should("have.length", 3); + cy.get("tbody").children().contains("td", "text/plain"); + cy.get("tbody").children().contains("td", "application/pdf"); // intercept download file request cy.intercept("/api/v2/boreholefile/download?boreholeFileId=**").as("download-file"); + // Ensure file does not exist in download folder before download. If so, delete it. + deleteDownloadedFile("IRATETRINITY_2.pdf"); + // Download recently uploaded file - cy.get("tbody").children().contains("span", "IRATETRINITY.pdf").click(); + cy.get("tbody").children().contains("span", "IRATETRINITY_2.pdf").click(); cy.wait("@download-file"); - // Check if file is present in download folder. - readDownloadedFile("IRATETRINITY.pdf"); + // Check if the file is present in download folder. + readDownloadedFile("IRATETRINITY_2.pdf"); // intercept delete file request cy.intercept("/api/v2/boreholefile/detachFile?boreholeId=**&boreholeFileId=**").as("delete-file"); // delete attachments - cy.get("tbody").children().first().get("td button").children().first().click(); + cy.get('[data-cy="attachments-detach-button"]').children().first().click(); cy.wait(["@delete-file"]); cy.wait(["@getAllAttachments"]); - cy.get("tbody").children().first().get("td button").children().first().click(); + cy.get("tbody").children().should("have.length", 2); + cy.get('[data-cy="attachments-detach-button"]').children().first().click(); + cy.wait(["@delete-file"]); + cy.wait(["@getAllAttachments"]); + cy.get("tbody").children().should("have.length", 1); + cy.get('[data-cy="attachments-detach-button"]').children().first().click(); cy.wait(["@delete-file"]); cy.wait(["@getAllAttachments"]); cy.get("tbody").children().should("have.length", 0); diff --git a/src/client/src/pages/detail/attachments/table/filesTableComponent.jsx b/src/client/src/pages/detail/attachments/table/filesTableComponent.jsx index 539182184..5a56ea33c 100644 --- a/src/client/src/pages/detail/attachments/table/filesTableComponent.jsx +++ b/src/client/src/pages/detail/attachments/table/filesTableComponent.jsx @@ -89,6 +89,7 @@ const FilesTableComponent = props => { {props.unlocked === true ? ( { e.stopPropagation(); props.detachFile(props.id, boreholeFile.fileId); diff --git a/tests/api/Controllers/BoreholeFileControllerTest.cs b/tests/api/Controllers/BoreholeFileControllerTest.cs index e532d323f..75f432c63 100644 --- a/tests/api/Controllers/BoreholeFileControllerTest.cs +++ b/tests/api/Controllers/BoreholeFileControllerTest.cs @@ -1,10 +1,7 @@ using Amazon.S3; -using Amazon.S3.Model; -using Azure; using BDMS.Authentication; using BDMS.Models; using Microsoft.AspNetCore.Http; -using Microsoft.AspNetCore.Http.HttpResults; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Logging; @@ -96,7 +93,6 @@ public async Task UploadAndDownload() Assert.AreEqual(content, contentResult); // Get file - Assert.AreNotEqual(null, file.Hash); Assert.AreEqual(DateTime.UtcNow.Date, file.Created?.Date); Assert.AreEqual(adminUser.SubjectId, file.CreatedBy.SubjectId); Assert.AreEqual(adminUser.Id, file.CreatedById); @@ -167,7 +163,7 @@ public async Task GetAllOfBorehole() } [TestMethod] - public async Task DetachFromBoreholeWithFileUsedByOtherBoreholeShouldDetachFile() + public async Task DetachFromBoreholeWithFileUsedByMultipleBoreholeShouldDetachAndDeleteFile() { // Get borehole Ids var firstBoreholeId = context.Boreholes.First().Id; @@ -182,24 +178,25 @@ public async Task DetachFromBoreholeWithFileUsedByOtherBoreholeShouldDetachFile( // Create file to upload var pdfFormFile = GetFormFileByContent(Guid.NewGuid().ToString(), "file_1.pdf"); - // Upload file for boreholes + // Upload file for both boreholes await controller.Upload(pdfFormFile, firstBoreholeId); await controller.Upload(pdfFormFile, secondBoreholeId); // Check counts after upload - Assert.AreEqual(filesCountBeforeUpload + 1, context.Files.Count()); + Assert.AreEqual(filesCountBeforeUpload + 2, context.Files.Count()); Assert.AreEqual(boreholeFilesCountBeforeUpload + 2, context.BoreholeFiles.Count()); Assert.AreEqual(firstBoreholeBoreholeFilesBeforeUpload + 1, context.BoreholeFiles.Where(bf => bf.BoreholeId == firstBoreholeId).Count()); Assert.AreEqual(secondBoreholeBoreholeFilesBeforeUpload + 1, context.BoreholeFiles.Where(bf => bf.BoreholeId == secondBoreholeId).Count()); - // Get latest file in db - var latestFileInDb = context.Files.OrderBy(f => f.Id).Last(); + // Get the added files + var firstBoreholeAddedFile = context.BoreholeFiles.Where(bf => bf.BoreholeId == firstBoreholeId).OrderBy(bf => bf.FileId).Last().File; + var secondBoreholeAddedFile = context.BoreholeFiles.Where(bf => bf.BoreholeId == secondBoreholeId).OrderBy(bf => bf.FileId).Last().File; // Clear context to ensure file has no info about its boreholeFiles context.ChangeTracker.Clear(); // Detach borehole file from first borehole - await controller.DetachFromBorehole(firstBoreholeId, latestFileInDb.BoreholeFiles.First(bf => bf.BoreholeId == firstBoreholeId).FileId); + await controller.DetachFromBorehole(firstBoreholeId, firstBoreholeAddedFile.BoreholeFiles.First(bf => bf.BoreholeId == firstBoreholeId).FileId); // Check counts after detach Assert.AreEqual(filesCountBeforeUpload + 1, context.Files.Count()); @@ -207,18 +204,19 @@ public async Task DetachFromBoreholeWithFileUsedByOtherBoreholeShouldDetachFile( Assert.AreEqual(firstBoreholeBoreholeFilesBeforeUpload, context.BoreholeFiles.Where(bf => bf.BoreholeId == firstBoreholeId).Count()); Assert.AreEqual(secondBoreholeBoreholeFilesBeforeUpload + 1, context.BoreholeFiles.Where(bf => bf.BoreholeId == secondBoreholeId).Count()); - // Ensure file exists - await boreholeFileCloudService.GetObject(latestFileInDb.NameUuid!); + // Ensure the file got deleted for the first borehole + var exception = await Assert.ThrowsExceptionAsync(() => boreholeFileCloudService.GetObject(firstBoreholeAddedFile.NameUuid!)); + Assert.AreEqual("The specified key does not exist.", exception.Message); + + // Ensure the file still exists for the second borehole + await boreholeFileCloudService.GetObject(secondBoreholeAddedFile.NameUuid!); } [TestMethod] public async Task DetachFromBoreholeWithFileNotUsedByOtherBoreholeShouldDetachAndDeleteFile() { - var fileName = $"{Guid.NewGuid()}.pdf"; - // Get borehole Ids var firstBoreholeId = context.Boreholes.First().Id; - var secondBoreholeId = context.Boreholes.Skip(1).First().Id; // Get counts before upload var filesCountBeforeUpload = context.Files.Count(); @@ -260,7 +258,7 @@ public async Task UpdateWithValidBoreholeFile() var borehole = new Borehole(); context.Boreholes.Add(borehole); - var file = new Models.File() { Name = $"{Guid.NewGuid}.pdf", NameUuid = $"{Guid.NewGuid}.pdf", Hash = Guid.NewGuid().ToString(), Type = "pdf" }; + var file = new Models.File() { Name = $"{Guid.NewGuid}.pdf", NameUuid = $"{Guid.NewGuid}.pdf", Type = "pdf" }; context.Files.Add(file); await context.SaveChangesAsync().ConfigureAwait(false); @@ -303,15 +301,15 @@ public async Task UploadWithMissingBoreholeFileId() } [TestMethod] - public async Task UploadWithFileAlreadyAttachedShouldThrowError() + public async Task CanUploadIdenticalFileMultipleTimes() { - var fileName = $"{Guid.NewGuid()}.pdf"; var minBoreholeId = context.Boreholes.Min(b => b.Id); - var pdfFormFile = GetFormFileByContent(Guid.NewGuid().ToString(), fileName); + var fileContent = "ANT-VII, REDASSOCIATION\r\nMONKEYBONES"; - await controller.Upload(pdfFormFile, minBoreholeId); - - await AssertIsBadRequestResponse(() => controller.Upload(pdfFormFile, minBoreholeId)); + // Upload same content using the same and different file names + await AssertIsOkResponse(() => controller.Upload(GetFormFileByContent(fileContent, "IRATEWATCH.pdf"), minBoreholeId)); + await AssertIsOkResponse(() => controller.Upload(GetFormFileByContent(fileContent, "IRATEWATCH.pdf"), minBoreholeId)); + await AssertIsOkResponse(() => controller.Upload(GetFormFileByContent(fileContent, "PAINTEDSHADOW.png"), minBoreholeId)); } [TestMethod] @@ -459,9 +457,9 @@ public async Task GetDataExtractionImage() await boreholeFileCloudService.DeleteObject($"dataextraction/{fileUuid}-1.png"); } - private async Task AssertIsBadRequestResponse(Func> action) - { - var result = await action(); - ActionResultAssert.IsBadRequest(result); - } + private static async Task AssertIsBadRequestResponse(Func> func) => + ActionResultAssert.IsBadRequest(await func()); + + private static async Task AssertIsOkResponse(Func> func) => + ActionResultAssert.IsOk(await func()); } From b1494956e6a75f6bfc485225738135ce021a8534 Mon Sep 17 00:00:00 2001 From: Oliver Gut Date: Thu, 5 Dec 2024 14:18:01 +0100 Subject: [PATCH 03/23] Do not copy borehole attachments This feature will be re-added in the future. --- src/api/Controllers/BoreholeController.cs | 6 ++---- tests/api/Controllers/BoreholeControllerTest.cs | 6 +++--- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/src/api/Controllers/BoreholeController.cs b/src/api/Controllers/BoreholeController.cs index 135a71cc2..8875ffeb9 100644 --- a/src/api/Controllers/BoreholeController.cs +++ b/src/api/Controllers/BoreholeController.cs @@ -296,10 +296,8 @@ await Context.Entry(hydrotest) } } - foreach (var boreholeFile in borehole.BoreholeFiles) - { - boreholeFile.BoreholeId = 0; - } + // Do not copy borehole attachments + borehole.BoreholeFiles.Clear(); foreach (var boreholeGeometry in borehole.BoreholeGeometry) { diff --git a/tests/api/Controllers/BoreholeControllerTest.cs b/tests/api/Controllers/BoreholeControllerTest.cs index 09983581a..c05f0b975 100644 --- a/tests/api/Controllers/BoreholeControllerTest.cs +++ b/tests/api/Controllers/BoreholeControllerTest.cs @@ -374,10 +374,10 @@ public async Task Copy() Assert.AreNotEqual(originalStratigraphy.LithostratigraphyLayers.First().Id, copiedstratigraphy.LithostratigraphyLayers.First().Id); Assert.AreEqual(originalStratigraphy.LithostratigraphyLayers.OrderBy(l => l.Id).First().LithostratigraphyId, copiedstratigraphy.LithostratigraphyLayers.OrderBy(l => l.Id).First().LithostratigraphyId); + // Borehole attachments are not copied Assert.AreNotSame(originalBorehole.BoreholeFiles, copiedBorehole.BoreholeFiles); - Assert.AreNotEqual(originalBorehole.BoreholeFiles.First().BoreholeId, copiedBorehole.BoreholeFiles.First().BoreholeId); - Assert.AreEqual(originalBorehole.BoreholeFiles.First().FileId, copiedBorehole.BoreholeFiles.First().FileId); - Assert.AreEqual(originalBorehole.BoreholeFiles.First().Description, copiedBorehole.BoreholeFiles.First().Description); + Assert.AreNotEqual(0, originalBorehole.BoreholeFiles.Count); + Assert.AreEqual(0, copiedBorehole.BoreholeFiles.Count); Assert.AreNotSame(originalStratigraphy.Layers.First().LayerColorCodes, copiedstratigraphy.Layers.First().LayerColorCodes); Assert.AreEqual(originalStratigraphy.Layers.First().LayerColorCodes.Count, copiedstratigraphy.Layers.First().LayerColorCodes.Count); From 122edfffae639fa784d49b2687dbf6c1cfbd4a42 Mon Sep 17 00:00:00 2001 From: Oliver Gut Date: Fri, 22 Nov 2024 15:46:52 +0100 Subject: [PATCH 04/23] Add release notes --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5feaf2461..8b1048f65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ - The `alternate_name` is now displayed in the borehole detail header and the map markers. - From depth and to depth are no longer displayed in groundwater level measurements. - Updated the layout of the borehole general tab. +- Removed deduplication check when adding and detaching attachments. +- When copying a borehole, attachments won't be copied. ### Fixed From add6130fb97d9ead8753b238fcd7d44e2ae86ff0 Mon Sep 17 00:00:00 2001 From: Oliver Gut Date: Thu, 5 Dec 2024 15:38:17 +0100 Subject: [PATCH 05/23] Improve readability --- src/api/BoreholeFileCloudService.cs | 20 +++++++++---------- src/api/Controllers/BoreholeFileController.cs | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/api/BoreholeFileCloudService.cs b/src/api/BoreholeFileCloudService.cs index 26924a6f8..5cd5585e9 100644 --- a/src/api/BoreholeFileCloudService.cs +++ b/src/api/BoreholeFileCloudService.cs @@ -31,9 +31,9 @@ public BoreholeFileCloudService(BdmsContext context, IConfiguration configuratio /// /// Uploads a file to the cloud storage and links it to the borehole. /// - /// The file to upload and link to the . - /// The to link the uploaded to. - public async Task UploadFileAndLinkToBorehole(IFormFile file, int boreholeId) + /// The file to upload and link to the . + /// The to link the uploaded to. + public async Task UploadFileAndLinkToBorehole(IFormFile formFile, int boreholeId) { // Use transaction to ensure data is only stored to db if the file upload was sucessful. Only create a transaction if there is not already one from the calling method. using var transaction = context.Database.CurrentTransaction == null ? await context.Database.BeginTransactionAsync().ConfigureAwait(false) : null; @@ -49,22 +49,22 @@ public async Task UploadFileAndLinkToBorehole(IFormFile file, int if (user == null || subjectId == null) throw new InvalidOperationException($"No user with subject_id <{subjectId}> found."); // Register the new file in the boreholes database. - var fileExtension = Path.GetExtension(file.FileName); + var fileExtension = Path.GetExtension(formFile.FileName); var fileNameGuid = $"{Guid.NewGuid()}{fileExtension}"; - var bdmsFile = new Models.File { Name = file.FileName, NameUuid = fileNameGuid, Type = file.ContentType }; + var file = new Models.File { Name = formFile.FileName, NameUuid = fileNameGuid, Type = formFile.ContentType }; - await context.Files.AddAsync(bdmsFile).ConfigureAwait(false); + await context.Files.AddAsync(file).ConfigureAwait(false); await context.UpdateChangeInformationAndSaveChangesAsync(httpContextAccessor.HttpContext!).ConfigureAwait(false); - var fileId = bdmsFile.Id; + var fileId = file.Id; // Upload the file to the cloud storage. - await UploadObject(file, fileNameGuid).ConfigureAwait(false); + await UploadObject(formFile, fileNameGuid).ConfigureAwait(false); // If file is already linked to the borehole, throw an exception. if (await context.BoreholeFiles.AnyAsync(bf => bf.BoreholeId == boreholeId && bf.FileId == fileId).ConfigureAwait(false)) - throw new InvalidOperationException($"File <{file.FileName}> is already attached to borehole with Id <{boreholeId}>."); + throw new InvalidOperationException($"File <{formFile.FileName}> is already attached to borehole with Id <{boreholeId}>."); // Link file to the borehole. var boreholeFile = new BoreholeFile { FileId = fileId, BoreholeId = boreholeId, UserId = user.Id, Attached = DateTime.UtcNow }; @@ -77,7 +77,7 @@ public async Task UploadFileAndLinkToBorehole(IFormFile file, int } catch (Exception ex) { - logger.LogError(ex, "Error attaching file <{FileName}> to borehole with Id <{BoreholeId}>.", file.FileName, boreholeId); + logger.LogError(ex, "Error attaching file <{FileName}> to borehole with Id <{BoreholeId}>.", formFile.FileName, boreholeId); throw; } } diff --git a/src/api/Controllers/BoreholeFileController.cs b/src/api/Controllers/BoreholeFileController.cs index 3ad572355..6568c36b3 100644 --- a/src/api/Controllers/BoreholeFileController.cs +++ b/src/api/Controllers/BoreholeFileController.cs @@ -212,7 +212,7 @@ public async Task DetachFromBorehole([Required, Range(1, int.MaxV // Get the file and its borehole files from the database. var boreholeFile = await context.BoreholeFiles.Include(f => f.File).SingleOrDefaultAsync(f => f.FileId == boreholeFileId).ConfigureAwait(false); - if (boreholeFile == null) return NotFound("Borehole file for the provided boreholeFileId not found."); + if (boreholeFile == null) return NotFound($"Borehole file for the provided {nameof(boreholeFileId)} not found."); var fileId = boreholeFile.File.Id; From 7286e42c6b28e5e2fcb3eebacf9b0a0b9ec40868 Mon Sep 17 00:00:00 2001 From: Oliver Gut Date: Thu, 5 Dec 2024 16:28:25 +0100 Subject: [PATCH 06/23] Update db context model snapshot --- src/api/Migrations/20241122080247_RemoveFileHash.Designer.cs | 5 ----- .../20241128080655_RemoveGroundwaterDepthEntries.Designer.cs | 5 ----- src/api/Migrations/BdmsContextModelSnapshot.cs | 5 ----- 3 files changed, 15 deletions(-) diff --git a/src/api/Migrations/20241122080247_RemoveFileHash.Designer.cs b/src/api/Migrations/20241122080247_RemoveFileHash.Designer.cs index 222d6a486..588b55ead 100644 --- a/src/api/Migrations/20241122080247_RemoveFileHash.Designer.cs +++ b/src/api/Migrations/20241122080247_RemoveFileHash.Designer.cs @@ -901,11 +901,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("integer") .HasColumnName("id_usr_fk"); - b.Property("Hash") - .IsRequired() - .HasColumnType("text") - .HasColumnName("hash_fil"); - b.Property("Name") .IsRequired() .HasColumnType("text") diff --git a/src/api/Migrations/20241128080655_RemoveGroundwaterDepthEntries.Designer.cs b/src/api/Migrations/20241128080655_RemoveGroundwaterDepthEntries.Designer.cs index df76964e0..2db47aea8 100644 --- a/src/api/Migrations/20241128080655_RemoveGroundwaterDepthEntries.Designer.cs +++ b/src/api/Migrations/20241128080655_RemoveGroundwaterDepthEntries.Designer.cs @@ -901,11 +901,6 @@ protected override void BuildTargetModel(ModelBuilder modelBuilder) .HasColumnType("integer") .HasColumnName("id_usr_fk"); - b.Property("Hash") - .IsRequired() - .HasColumnType("text") - .HasColumnName("hash_fil"); - b.Property("Name") .IsRequired() .HasColumnType("text") diff --git a/src/api/Migrations/BdmsContextModelSnapshot.cs b/src/api/Migrations/BdmsContextModelSnapshot.cs index 920e88271..b0273fed4 100644 --- a/src/api/Migrations/BdmsContextModelSnapshot.cs +++ b/src/api/Migrations/BdmsContextModelSnapshot.cs @@ -898,11 +898,6 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("integer") .HasColumnName("id_usr_fk"); - b.Property("Hash") - .IsRequired() - .HasColumnType("text") - .HasColumnName("hash_fil"); - b.Property("Name") .IsRequired() .HasColumnType("text") From 23f5431c2bf71ab2e0a0bc60027c1445a5b0fb76 Mon Sep 17 00:00:00 2001 From: Oliver Gut Date: Fri, 6 Dec 2024 07:47:05 +0100 Subject: [PATCH 07/23] Improve readability --- .../cypress/e2e/detailPage/attachments.cy.js | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/src/client/cypress/e2e/detailPage/attachments.cy.js b/src/client/cypress/e2e/detailPage/attachments.cy.js index 392b4d515..b5a7ce310 100644 --- a/src/client/cypress/e2e/detailPage/attachments.cy.js +++ b/src/client/cypress/e2e/detailPage/attachments.cy.js @@ -36,8 +36,7 @@ describe("Tests for 'Attachments' edit page.", () => { // // upload file cy.get('[data-cy="attachments-upload-button"]').should("be.visible").click(); - cy.wait(["@upload-files"]); - cy.wait(["@getAllAttachments"]); + cy.wait(["@upload-files", "@getAllAttachments"]); // check list of attachments cy.get("tbody").children().should("have.length", 1); @@ -56,8 +55,7 @@ describe("Tests for 'Attachments' edit page.", () => { // upload and verify file IRATETRINITY.pdf cy.get('[data-cy="attachments-upload-button"]').should("be.visible").click(); - cy.wait(["@upload-files"]); - cy.wait(["@getAllAttachments"]); + cy.wait(["@upload-files", "@getAllAttachments"]); cy.get("tbody").children().should("have.length", 2); cy.get("tbody").children().contains("td", "text/plain"); cy.get("tbody").children().contains("td", "application/pdf"); @@ -72,8 +70,7 @@ describe("Tests for 'Attachments' edit page.", () => { { force: true }, ); cy.get('[data-cy="attachments-upload-button"]').should("be.visible").click(); - cy.wait(["@upload-files"]); - cy.wait(["@getAllAttachments"]); + cy.wait(["@upload-files", "@getAllAttachments"]); cy.get("tbody").children().should("have.length", 3); cy.get("tbody").children().contains("td", "text/plain"); cy.get("tbody").children().contains("td", "application/pdf"); @@ -96,16 +93,13 @@ describe("Tests for 'Attachments' edit page.", () => { // delete attachments cy.get('[data-cy="attachments-detach-button"]').children().first().click(); - cy.wait(["@delete-file"]); - cy.wait(["@getAllAttachments"]); + cy.wait(["@delete-file", "@getAllAttachments"]); cy.get("tbody").children().should("have.length", 2); cy.get('[data-cy="attachments-detach-button"]').children().first().click(); - cy.wait(["@delete-file"]); - cy.wait(["@getAllAttachments"]); + cy.wait(["@delete-file", "@getAllAttachments"]); cy.get("tbody").children().should("have.length", 1); cy.get('[data-cy="attachments-detach-button"]').children().first().click(); - cy.wait(["@delete-file"]); - cy.wait(["@getAllAttachments"]); + cy.wait(["@delete-file", "@getAllAttachments"]); cy.get("tbody").children().should("have.length", 0); // stop editing From d10bc54f1b5b7a8a1e826c838f35e83d53433c15 Mon Sep 17 00:00:00 2001 From: danjov Date: Mon, 9 Dec 2024 11:12:56 +0100 Subject: [PATCH 08/23] Add english abstract and title for Geology 500 map --- src/view-sync/db-init/04_delete_from_borehole.sql | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/view-sync/db-init/04_delete_from_borehole.sql b/src/view-sync/db-init/04_delete_from_borehole.sql index 64288df3d..a1d4666e8 100644 --- a/src/view-sync/db-init/04_delete_from_borehole.sql +++ b/src/view-sync/db-init/04_delete_from_borehole.sql @@ -25,7 +25,7 @@ VALUES ((SELECT id_usr FROM bdms.users WHERE subject_id = 'sub_anonymous'), -- Set default settings for anonymous user (e.g. "Maps displayed") UPDATE bdms.users -SET settings_usr = '{"filter": {}, "viewerFilter": {}, "boreholetable": {"orderby": "alternate_name", "direction": "ASC"}, "eboreholetable": {"orderby": "alternate_name", "direction": "ASC"}, "map": {"explorer": {"ch.swisstopo.geologie-geocover": {"Identifier": "ch.swisstopo.geologie-geocover", "Abstract": "ch.swisstopo.geologie-geocover.wms_abstract", "position": 14, "Title": "GeoCover - Vector Datasets", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-geologischer_atlas": {"Identifier": "ch.swisstopo.geologie-geologischer_atlas", "Abstract": "The sheets of the Geological Atlas of Switzerland (GA25) give detailed information about the uppermost layers of the subsurface structure. Geological formations are represented by colours, conventional signs and symbols, which correspond to their age, composition and tectonic structure. For each sheet, an explanatory booklet is also published, in which the geological formations and special features of the study area are described. Over two thirds of the 220 map sheets that are planned have already been published.", "position": 13, "Title": "Geological Atlas GA25", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-geologischer_atlas_profile": {"Identifier": "ch.swisstopo.geologie-geologischer_atlas_profile", "Abstract": "The GA25-Profile dataset (GA25_CS) is a compilation of the profiles published together with the Geological Atlas 1:25,000. It depicts the profile tracks and contains metadata on the profiles. The given year of issue corresponds to the publication year of the respective explanatory notes. The profiles represented by the tracks were extracted from the published profile plates and, if possible, saved individually along with the entire plate legend and scale as a PDF. Since the legend always refers to the entire plate, it is likely that not all elements of the legend appear in the individual profile. In a few cases, plates with very closely spaced profiles cannot be subdivided into single profiles. In these cases, the entire plate is shown for each group of the profile tracks. LINK: Fact sheet LINK: Dataset description LINK: map.geo.admin.ch - Geological Atlas GA25 Disclaimer: The user acknowledges that the authors have made all reasonable efforts to verify the information in the particular geologic model / dataset. There is no guarantee that the provided data are correct at any particular point in the subsurface. Under no circumstances shall the publisher be liable for any loss or damage of a material or immaterial nature arising from access to or from use, misuse or technical malfunction of the published information.", "position": 12, "Title": "Geological profiles GA25", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-geotechnik-gk500-lithologie_hauptgruppen": {"Identifier": "ch.swisstopo.geologie-geotechnik-gk500-lithologie_hauptgruppen", "Abstract": "The Lithological map of Switzerland 1:500,000 provides an overview of the subsurface classified according to lithological and petrographic criteria.The geometry of the polygons was reproduced unmodified from the Geological and Tectonic maps of Switzerland 1:500,000. Additional attributes were assigned to the polygons on the basis of the Lithological-petrographic map 1:200,000.", "position": 11, "Title": "Lithology 500", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-geologische_karte": {"Identifier": "ch.swisstopo.geologie-geologische_karte", "Abstract": "Die Geologische Karte der Schweiz 1:500`000 (GK500-Geol) deckt die gesamte Schweiz und das angrenzende Ausland ab. Sie gibt einen \u00dcberblick \u00fcber die Verteilung der in der Schweiz auftretenden obersten Gesteinsschichten. Sie liefert somit eine wichtige Datengrundlage und ein Werkzeug f\u00fcr das bessere Verst\u00e4ndnis unserer Umwelt zwecks einer nachhaltigen Entwicklung. Sie ist ein unumg\u00e4ngliches Hilfsmittel f\u00fcr die Ausbildung in den Bereichen Erd- und Umweltwissenschaften und Naturgefahren.", "position": 10, "Title": "Geologie 500", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-tektonische_karte": {"Identifier": "ch.swisstopo.geologie-tektonische_karte", "Abstract": "The Tectonic Map of Switzerland (TK500) depicts the tectonic units and structural elements of the entire Swiss territory and neighboring regions. These units group together rocks with a common geodynamic history and are separated from one another by tectonic discontinuities. Within some units, a distinction has been made between crystalline basement and one or more successive series of sedimentary cover. Units are grouped into structural domains separated by major tectonic discontinuities. Units and subunits can be located by entering their name in the search field, like some structural lines (not all have names). The current map (4th edition, 2024) is accompanied by an explanatory note providing a brief definition of each unit. A first enclosure contains three NW-SE to N-S tectonic cross-sections through the entire map area, which also show the major structures at depth. A second enclosure contains a series of paleogeographic diagrams, from the Middle Jurassic (170 Ma) to the present day, showing the evolution of spatial relationships between the different tectonic domains covered by the map.", "position": 9, "Title": "Tectonics 500", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-geotechnik-gk500-gesteinsklassierung": {"Identifier": "ch.swisstopo.geologie-geotechnik-gk500-gesteinsklassierung", "Abstract": "The Lithological map of Switzerland - Groups of rocks 1:500,000 provides an overview of the subsurface subdivided into three groups of rocks: unconsolidated rocks, sedimentary rocks and crystalline rocks.The geometry of the polygons was reproduced unmodified from the Geological and Tectonic maps of Switzerland 1:500,000. Additional attributes were assigned to the polygons on the basis of the Lithological-petrographic map 1:200,000.", "position": 8, "Title": "Groups of rocks 500", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-geotechnik-gk500-genese": {"Identifier": "ch.swisstopo.geologie-geotechnik-gk500-genese", "Abstract": "The Lithological map of Switzerland - Genesis 1:500,000 provides an overview of the subsurface classified according to the origin of the rocks, e.g. deposits from rivers and glaciers, solidification of magma or transformation of rocks through the effects of pressure and temperature.The geometry of the polygons was reproduced unmodified from the Geological and Tectonic maps of Switzerland 1:500,000. Additional attributes were assigned to the polygons on the basis of the Lithological-petrographic map 1:200,000.", "position": 7, "Title": "Origin of rocks 500", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-generalkarte-ggk200": {"Identifier": "ch.swisstopo.geologie-generalkarte-ggk200", "Abstract": "Geological mapping of the whole country based on the Dufour Map of Switzerland. Comprised of eight sheets, published between 1942 and 1964, the General Geological Map of Switzerland (GGK200) is a historical document of the highest quality. The printed versions of the sheets of the General Geological Map are partially out of print, but each sheet is available as a pixel map.", "position": 6, "Title": "General Geol. Map 200", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-lockergestein_maechtigkeitsmodell": {"Identifier": "ch.swisstopo.geologie-lockergestein_maechtigkeitsmodell", "Abstract": "The thickness model of unconsolidated deposits is a digital data set that describes the thickness of the unconsolidated deposits. This product is derived from the bedrock elevation model. The subtraction of the bedrock surface from the terrain surface (digital height model, DHM25) gives the thickness of unconsolidated deposits. 3D models represent a simplification of the real geological settings. The user acknowledges that the authors have taken every reasonable effort to ensure that information contained in the presented 3D geological model is as accurate as possible. There is no guarantee that the given data related to a definite point in the subsurface is accurate. Under no circumstances will the publisher be liable for any loss or damage of a material or immaterial nature arising from access to, use or non-use of published information, or from misuse or technical breakdown.", "position": 5, "Title": "Thickness of unconsolidated deposits", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-gesteinsdichte": {"Identifier": "ch.swisstopo.geologie-gesteinsdichte", "Abstract": "An important physical property of rock is its density, which depends mainly on mineralogy and porosity. Rocks made of minerals with a high content of magnesium, iron or other heavy metallic elements have a high density. In contrast, rocks that have a large proportion of alkalis (e.g. sodium, potassium) and silicon dioxide have a comparatively low density. Furthermore, rocks with a crystalline structure generally have a greater density than those with an amorphous (glassy) structure. Density is defined as mass per unit volume of a material [kg/m3]. While the so-called bulk density comprises the entire volume of a rock, the pure density (also called grain density) represents the volume without the empty spaces - i.e. without the porosity. Based on a database of density values, a bulk-density map of Switzerland was produced, which shows the mean value and other statistical data of all measured samples from each of the 21 lithological groups. Consequently, at no point does the density map show the expected absolute bulk density of a local rock type. Instead, it primarily shows the range in which the density of the local lithology varies. The data source, the data processing and the methodology used to produce the density map can be found in the publication by Alba Zappone & Edi Kissling (2021, Swiss J. Geosciences).", "position": 4, "Title": "Rock density", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-reflexionsseismik": {"Identifier": "ch.swisstopo.geologie-reflexionsseismik", "Abstract": "This map shows the location of seismic reflection data acquired in Switzerland for the exploration of the geological subsurface. The majority of these are two-dimensional measurements (2D) along the profile traces shown. Three-dimensional measurements (3D) are only locally available within the shown perimeters. For more detailed information on the actual reflection seismic data, please contact the rights holder directly. This map is continuously updated and does not claim to be complete.

References:
  • Fabbri S. et al. (2021): Active Faulting in Lake Constance (Austria, Germany, Switzerland) Unraveled by Multi-Vintage Reflection Seismic Data. Front. Earth Sci. 9:670532.
  • Gruber, M. (2017): Structural investigations of the western Swiss Molasse Basin - From 2D seismic interpretation to a 3D geological model. - PhD Thesis Univ. Fribourg.
  • Nagra (1993): R\u00e9sultats des recherches effectu\u00e9es sur le site potentiel du Bois de la Glaive (Commune d`Ollon, VD): Recherches sur l`aptitude des sites \u00e0 accueillir un d\u00e9pot final de d\u00e9chets faiblement et moyennement radioactifs \u00e0 vie courte. NTB 93-29.
  • Nagra (1997): Geosynthese Wellenberg 1996 - Ergebnisse der Untersuchungsphasen I und II. Nagra Tech. Ber. NTB 96-01.
  • Meier, B. P. (2010): Erg\u00e4nzende Interpretation reflexionsseismischer Linien zwischen dem \u00f6stlichen und westlichen Molassebecken. Gebiete Waadtland Nord, Fribourg, Berner Seeland und Juras\u00fcdfuss zwischen Biel und Oensingen. - Nagra Arbeitsber. NAB 10-40.
  • Roth, P., Naef, H. & Schnellmann, M. (2010): Kompilation und Interpretation der Reflexionsseismik im Tafeljura und Molassebecken der Zentral- und Nordostschweiz. - Nagra Arbeitsber. NAB 10-39.
  • Sommaruga, A., Eichenberger, U. & Marillier, F. (2012): Seismic Atlas of the Swiss Molasse Basin. - Mat\u00e9r. G\u00e9ol. Suisse, G\u00e9ophys. 44.
", "position": 3, "Title": "Reflection seismic", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.bafu.hydrogeologische-karte_100": {"Identifier": "ch.bafu.hydrogeologische-karte_100", "Abstract": "Published by the Federal Office for the Environment FOEN, the specialist office of the Swiss Geological Survey responsible for hydrogeology.The hydrogeological map 1:100,000 shows the subsurface from the perspective of three disciplines: geology, hydrology and hydrogeology. The subsurface is classified according to lithological-petrographical criteria and permeability. Point and line data (springs, wells, hydraulic connections, groundwater resources, etc.) indicate the flow paths of groundwater and its exploitation at wells and tapped springs. The representation at a scale of 100,000 provides insight into the regional hydrogeological conditions. The following maps are available: 1. B\u00f6zberg/Berom\u00fcnster, 1972; 2. Lake Constance, 1980; 3. Panixerpass, 1985; 4. Biel-Bienne, 1991/92; 5. Toggenburg, 1993/94; 6. Saane, 1999; 8. Vallorbe - L\u00e9man nord, 2006; 7. Basel, 2014. For North West Switzerland, a seamless vector data set of maps 4, 6, 7 and 8 was created. The data can be obtained from the FOEN (www.bafu.admin.ch Data, indicators, maps).", "position": 2, "Title": "Hydrogeological map 100", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": false}, "ch.swisstopo.geologie-tiefengeothermie_projekte": {"Identifier": "ch.swisstopo.geologie-tiefengeothermie_projekte", "Abstract": "This map shows deep geothermal plants in operation as well as current and former deep geothermal projects in Switzerland. The project status corresponds to one of the following: - Prospection: Following regulatory approval by the canton(s) geophysical and geological studies are employed to identify a reservoir in the subsurface (permit zones shown, if available). - Under development: A reservoir has been identified and deemed suitable for producing geothermal energy. Permits required for the construction of a geothermal plant have been obtained and construction will begin shortly or is already in progress. - In operation: The plant is producing geothermal energy. - Abandoned: For any one of various reasons, the project has been stopped. Projects and plants are classified in the following types of system: Deep geothermal probe, Hydrothermal, Enhanced Geothermal System (EGS) and High temperature aquifer thermal energy storage (HT-ATES). Shallow geothermal energy production (i.e., <500 m depth to reservoir) is not featured. The map does not purport to be complete.", "position": 1, "Title": "Deep geothermal projects", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.kantone.cadastralwebmap-farbe": {"Identifier": "ch.kantone.cadastralwebmap-farbe", "Abstract": "The basis is a representation service (web map service) created using data from the federal AV-Geoportal. However, the service does not provide the full data from the official cadastral survey.", "position": 0, "Title": "CadastralWebMap", "transparency": 0, "type": "WMTS", "url": "https://wmts.geo.admin.ch/1.0.0/ch.kantone.cadastralwebmap-farbe/default/{Time}/2056/{TileMatrix}/{TileCol}/{TileRow}.png", "visibility": false, "queryable": false, "conf": {"urls": ["https://wmts.geo.admin.ch/1.0.0/ch.kantone.cadastralwebmap-farbe/default/{Time}/2056/{TileMatrix}/{TileCol}/{TileRow}.png"], "layer": "ch.kantone.cadastralwebmap-farbe", "matrixSet": "2056_28", "format": "image/png", "projection": {"code_": "EPSG:2056", "units_": "m", "extent_": [2420000, 1030000, 2900000, 1350000], "worldExtent_": null, "axisOrientation_": "enu", "global_": false, "canWrapX_": false, "defaultTileGrid_": {"minZoom": 0, "resolutions_": [1875, 937.5, 468.75, 234.375, 117.1875, 58.59375, 29.296875, 14.6484375, 7.32421875, 3.662109375, 1.8310546875, 0.91552734375, 0.457763671875, 0.2288818359375, 0.11444091796875, 0.057220458984375, 0.0286102294921875, 0.01430511474609375, 0.007152557373046875, 0.0035762786865234375, 0.0017881393432617188, 0.0008940696716308594, 0.0004470348358154297, 0.00022351741790771484, 0.00011175870895385742, 5.587935447692871e-05, 2.7939677238464355e-05, 1.3969838619232178e-05, 6.984919309616089e-06, 3.4924596548080444e-06, 1.7462298274040222e-06, 8.731149137020111e-07, 4.3655745685100555e-07, 2.1827872842550278e-07, 1.0913936421275139e-07, 5.4569682106375694e-08, 2.7284841053187847e-08, 1.3642420526593924e-08, 6.821210263296962e-09, 3.410605131648481e-09, 1.7053025658242404e-09, 8.526512829121202e-10, 4.263256414560601e-10], "zoomFactor_": 2, "maxZoom": 42, "origin_": [2420000, 1350000], "origins_": null, "tileSizes_": null, "tileSize_": 256, "extent_": [2420000, 1030000, 2900000, 1350000], "fullTileRanges_": [{"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 1, "minY": 0, "maxY": 1}, {"minX": 0, "maxX": 3, "minY": 0, "maxY": 2}, {"minX": 0, "maxX": 7, "minY": 0, "maxY": 5}, {"minX": 0, "maxX": 15, "minY": 0, "maxY": 10}, {"minX": 0, "maxX": 31, "minY": 0, "maxY": 21}, {"minX": 0, "maxX": 63, "minY": 0, "maxY": 42}, {"minX": 0, "maxX": 127, "minY": 0, "maxY": 85}, {"minX": 0, "maxX": 255, "minY": 0, "maxY": 170}, {"minX": 0, "maxX": 511, "minY": 0, "maxY": 341}, {"minX": 0, "maxX": 1023, "minY": 0, "maxY": 682}, {"minX": 0, "maxX": 2047, "minY": 0, "maxY": 1365}, {"minX": 0, "maxX": 4095, "minY": 0, "maxY": 2730}, {"minX": 0, "maxX": 8191, "minY": 0, "maxY": 5461}, {"minX": 0, "maxX": 16383, "minY": 0, "maxY": 10922}, {"minX": 0, "maxX": 32767, "minY": 0, "maxY": 21845}, {"minX": 0, "maxX": 65535, "minY": 0, "maxY": 43690}, {"minX": 0, "maxX": 131071, "minY": 0, "maxY": 87381}, {"minX": 0, "maxX": 262143, "minY": 0, "maxY": 174762}, {"minX": 0, "maxX": 524287, "minY": 0, "maxY": 349525}, {"minX": 0, "maxX": 1048575, "minY": 0, "maxY": 699050}, {"minX": 0, "maxX": 2097151, "minY": 0, "maxY": 1398101}, {"minX": 0, "maxX": 4194303, "minY": 0, "maxY": 2796202}, {"minX": 0, "maxX": 8388607, "minY": 0, "maxY": 5592405}, {"minX": 0, "maxX": 16777215, "minY": 0, "maxY": 11184810}, {"minX": 0, "maxX": 33554431, "minY": 0, "maxY": 22369621}, {"minX": 0, "maxX": 67108863, "minY": 0, "maxY": 44739242}, {"minX": 0, "maxX": 134217727, "minY": 0, "maxY": 89478485}, {"minX": 0, "maxX": 268435455, "minY": 0, "maxY": 178956970}, {"minX": 0, "maxX": 536870911, "minY": 0, "maxY": 357913941}, {"minX": 0, "maxX": 1073741823, "minY": 0, "maxY": 715827882}, {"minX": 0, "maxX": 2147483647, "minY": 0, "maxY": 1431655765}, {"minX": 0, "maxX": 4294967295, "minY": 0, "maxY": 2863311530}, {"minX": 0, "maxX": 8589934591, "minY": 0, "maxY": 5726623061}, {"minX": 0, "maxX": 17179869183, "minY": 0, "maxY": 11453246122}, {"minX": 0, "maxX": 34359738367, "minY": 0, "maxY": 22906492245}, {"minX": 0, "maxX": 68719476735, "minY": 0, "maxY": 45812984490}, {"minX": 0, "maxX": 137438953471, "minY": 0, "maxY": 91625968981}, {"minX": 0, "maxX": 274877906943, "minY": 0, "maxY": 183251937962}, {"minX": 0, "maxX": 549755813887, "minY": 0, "maxY": 366503875925}, {"minX": 0, "maxX": 1099511627775, "minY": 0, "maxY": 733007751850}, {"minX": 0, "maxX": 2199023255551, "minY": 0, "maxY": 1466015503701}, {"minX": 0, "maxX": 4398046511103, "minY": 0, "maxY": 2932031007402}], "tmpSize_": [256, 256], "tmpExtent_": [0, 0, 0, 0]}, "ol_uid": "54"}, "requestEncoding": "REST", "tileGrid": {"minZoom": 0, "resolutions_": [4000, 3750, 3500, 3250, 3000, 2750, 2500, 2250, 2000, 1750, 1500, 1250, 1000, 750, 650, 500, 250, 100, 50, 20, 10, 5, 2.5, 2, 1.5, 1, 0.5, 0.25, 0.09999999999999999], "maxZoom": 28, "origin_": null, "origins_": [[2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000]], "tileSizes_": [256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256], "tileSize_": null, "extent_": [2420000, 326000, 3444000, 1350000], "fullTileRanges_": [{"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 1, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 1, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 1, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 1, "minY": 0, "maxY": 1}, {"minX": 0, "maxX": 2, "minY": 0, "maxY": 1}, {"minX": 0, "maxX": 2, "minY": 0, "maxY": 1}, {"minX": 0, "maxX": 3, "minY": 0, "maxY": 2}, {"minX": 0, "maxX": 7, "minY": 0, "maxY": 4}, {"minX": 0, "maxX": 18, "minY": 0, "maxY": 12}, {"minX": 0, "maxX": 37, "minY": 0, "maxY": 24}, {"minX": 0, "maxX": 93, "minY": 0, "maxY": 62}, {"minX": 0, "maxX": 187, "minY": 0, "maxY": 124}, {"minX": 0, "maxX": 374, "minY": 0, "maxY": 249}, {"minX": 0, "maxX": 749, "minY": 0, "maxY": 499}, {"minX": 0, "maxX": 937, "minY": 0, "maxY": 624}, {"minX": 0, "maxX": 1249, "minY": 0, "maxY": 833}, {"minX": 0, "maxX": 1874, "minY": 0, "maxY": 1249}, {"minX": 0, "maxX": 3749, "minY": 0, "maxY": 2499}, {"minX": 0, "maxX": 7499, "minY": 0, "maxY": 4999}, {"minX": 0, "maxX": 18749, "minY": 0, "maxY": 12499}], "tmpSize_": [256, 256], "tmpExtent_": [0, 0, 0, 0], "matrixIds_": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28"]}, "style": "ch.kantone.cadastralwebmap-farbe", "dimensions": {"Time": "current"}, "wrapX": false}}}, "editor": {}}, "appearance": {"explorer": 1}}' +SET settings_usr = '{"filter": {}, "viewerFilter": {}, "boreholetable": {"orderby": "alternate_name", "direction": "ASC"}, "eboreholetable": {"orderby": "alternate_name", "direction": "ASC"}, "map": {"explorer": {"ch.swisstopo.geologie-geocover": {"Identifier": "ch.swisstopo.geologie-geocover", "Abstract": "ch.swisstopo.geologie-geocover.wms_abstract", "position": 14, "Title": "GeoCover - Vector Datasets", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-geologischer_atlas": {"Identifier": "ch.swisstopo.geologie-geologischer_atlas", "Abstract": "The sheets of the Geological Atlas of Switzerland (GA25) give detailed information about the uppermost layers of the subsurface structure. Geological formations are represented by colours, conventional signs and symbols, which correspond to their age, composition and tectonic structure. For each sheet, an explanatory booklet is also published, in which the geological formations and special features of the study area are described. Over two thirds of the 220 map sheets that are planned have already been published.", "position": 13, "Title": "Geological Atlas GA25", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-geologischer_atlas_profile": {"Identifier": "ch.swisstopo.geologie-geologischer_atlas_profile", "Abstract": "The GA25-Profile dataset (GA25_CS) is a compilation of the profiles published together with the Geological Atlas 1:25,000. It depicts the profile tracks and contains metadata on the profiles. The given year of issue corresponds to the publication year of the respective explanatory notes. The profiles represented by the tracks were extracted from the published profile plates and, if possible, saved individually along with the entire plate legend and scale as a PDF. Since the legend always refers to the entire plate, it is likely that not all elements of the legend appear in the individual profile. In a few cases, plates with very closely spaced profiles cannot be subdivided into single profiles. In these cases, the entire plate is shown for each group of the profile tracks. LINK: Fact sheet LINK: Dataset description LINK: map.geo.admin.ch - Geological Atlas GA25 Disclaimer: The user acknowledges that the authors have made all reasonable efforts to verify the information in the particular geologic model / dataset. There is no guarantee that the provided data are correct at any particular point in the subsurface. Under no circumstances shall the publisher be liable for any loss or damage of a material or immaterial nature arising from access to or from use, misuse or technical malfunction of the published information.", "position": 12, "Title": "Geological profiles GA25", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-geotechnik-gk500-lithologie_hauptgruppen": {"Identifier": "ch.swisstopo.geologie-geotechnik-gk500-lithologie_hauptgruppen", "Abstract": "The Lithological map of Switzerland 1:500,000 provides an overview of the subsurface classified according to lithological and petrographic criteria.The geometry of the polygons was reproduced unmodified from the Geological and Tectonic maps of Switzerland 1:500,000. Additional attributes were assigned to the polygons on the basis of the Lithological-petrographic map 1:200,000.", "position": 11, "Title": "Lithology 500", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-geologische_karte": {"Identifier": "ch.swisstopo.geologie-geologische_karte", "Abstract": "The 1:500,000 Geological Map of Switzerland covers the whole of Switzerland and adjoining parts of neighbouring countries. It gives an overview of the distribution of the uppermost rock strata occurring in Switzerland. Therefore, it provides an important data base and functions as a tool for gaining a better understanding of our environment in the scope of sustainable development. It is an essential aid for education in the fields of environmental and earth sciences, as well as natural hazards.", "position": 10, "Title": "Geology 500", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-tektonische_karte": {"Identifier": "ch.swisstopo.geologie-tektonische_karte", "Abstract": "The Tectonic Map of Switzerland (TK500) depicts the tectonic units and structural elements of the entire Swiss territory and neighboring regions. These units group together rocks with a common geodynamic history and are separated from one another by tectonic discontinuities. Within some units, a distinction has been made between crystalline basement and one or more successive series of sedimentary cover. Units are grouped into structural domains separated by major tectonic discontinuities. Units and subunits can be located by entering their name in the search field, like some structural lines (not all have names). The current map (4th edition, 2024) is accompanied by an explanatory note providing a brief definition of each unit. A first enclosure contains three NW-SE to N-S tectonic cross-sections through the entire map area, which also show the major structures at depth. A second enclosure contains a series of paleogeographic diagrams, from the Middle Jurassic (170 Ma) to the present day, showing the evolution of spatial relationships between the different tectonic domains covered by the map.", "position": 9, "Title": "Tectonics 500", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-geotechnik-gk500-gesteinsklassierung": {"Identifier": "ch.swisstopo.geologie-geotechnik-gk500-gesteinsklassierung", "Abstract": "The Lithological map of Switzerland - Groups of rocks 1:500,000 provides an overview of the subsurface subdivided into three groups of rocks: unconsolidated rocks, sedimentary rocks and crystalline rocks.The geometry of the polygons was reproduced unmodified from the Geological and Tectonic maps of Switzerland 1:500,000. Additional attributes were assigned to the polygons on the basis of the Lithological-petrographic map 1:200,000.", "position": 8, "Title": "Groups of rocks 500", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-geotechnik-gk500-genese": {"Identifier": "ch.swisstopo.geologie-geotechnik-gk500-genese", "Abstract": "The Lithological map of Switzerland - Genesis 1:500,000 provides an overview of the subsurface classified according to the origin of the rocks, e.g. deposits from rivers and glaciers, solidification of magma or transformation of rocks through the effects of pressure and temperature.The geometry of the polygons was reproduced unmodified from the Geological and Tectonic maps of Switzerland 1:500,000. Additional attributes were assigned to the polygons on the basis of the Lithological-petrographic map 1:200,000.", "position": 7, "Title": "Origin of rocks 500", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-generalkarte-ggk200": {"Identifier": "ch.swisstopo.geologie-generalkarte-ggk200", "Abstract": "Geological mapping of the whole country based on the Dufour Map of Switzerland. Comprised of eight sheets, published between 1942 and 1964, the General Geological Map of Switzerland (GGK200) is a historical document of the highest quality. The printed versions of the sheets of the General Geological Map are partially out of print, but each sheet is available as a pixel map.", "position": 6, "Title": "General Geol. Map 200", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-lockergestein_maechtigkeitsmodell": {"Identifier": "ch.swisstopo.geologie-lockergestein_maechtigkeitsmodell", "Abstract": "The thickness model of unconsolidated deposits is a digital data set that describes the thickness of the unconsolidated deposits. This product is derived from the bedrock elevation model. The subtraction of the bedrock surface from the terrain surface (digital height model, DHM25) gives the thickness of unconsolidated deposits. 3D models represent a simplification of the real geological settings. The user acknowledges that the authors have taken every reasonable effort to ensure that information contained in the presented 3D geological model is as accurate as possible. There is no guarantee that the given data related to a definite point in the subsurface is accurate. Under no circumstances will the publisher be liable for any loss or damage of a material or immaterial nature arising from access to, use or non-use of published information, or from misuse or technical breakdown.", "position": 5, "Title": "Thickness of unconsolidated deposits", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-gesteinsdichte": {"Identifier": "ch.swisstopo.geologie-gesteinsdichte", "Abstract": "An important physical property of rock is its density, which depends mainly on mineralogy and porosity. Rocks made of minerals with a high content of magnesium, iron or other heavy metallic elements have a high density. In contrast, rocks that have a large proportion of alkalis (e.g. sodium, potassium) and silicon dioxide have a comparatively low density. Furthermore, rocks with a crystalline structure generally have a greater density than those with an amorphous (glassy) structure. Density is defined as mass per unit volume of a material [kg/m3]. While the so-called bulk density comprises the entire volume of a rock, the pure density (also called grain density) represents the volume without the empty spaces - i.e. without the porosity. Based on a database of density values, a bulk-density map of Switzerland was produced, which shows the mean value and other statistical data of all measured samples from each of the 21 lithological groups. Consequently, at no point does the density map show the expected absolute bulk density of a local rock type. Instead, it primarily shows the range in which the density of the local lithology varies. The data source, the data processing and the methodology used to produce the density map can be found in the publication by Alba Zappone & Edi Kissling (2021, Swiss J. Geosciences).", "position": 4, "Title": "Rock density", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.swisstopo.geologie-reflexionsseismik": {"Identifier": "ch.swisstopo.geologie-reflexionsseismik", "Abstract": "This map shows the location of seismic reflection data acquired in Switzerland for the exploration of the geological subsurface. The majority of these are two-dimensional measurements (2D) along the profile traces shown. Three-dimensional measurements (3D) are only locally available within the shown perimeters. For more detailed information on the actual reflection seismic data, please contact the rights holder directly. This map is continuously updated and does not claim to be complete.

References:
  • Fabbri S. et al. (2021): Active Faulting in Lake Constance (Austria, Germany, Switzerland) Unraveled by Multi-Vintage Reflection Seismic Data. Front. Earth Sci. 9:670532.
  • Gruber, M. (2017): Structural investigations of the western Swiss Molasse Basin - From 2D seismic interpretation to a 3D geological model. - PhD Thesis Univ. Fribourg.
  • Nagra (1993): R\u00e9sultats des recherches effectu\u00e9es sur le site potentiel du Bois de la Glaive (Commune d`Ollon, VD): Recherches sur l`aptitude des sites \u00e0 accueillir un d\u00e9pot final de d\u00e9chets faiblement et moyennement radioactifs \u00e0 vie courte. NTB 93-29.
  • Nagra (1997): Geosynthese Wellenberg 1996 - Ergebnisse der Untersuchungsphasen I und II. Nagra Tech. Ber. NTB 96-01.
  • Meier, B. P. (2010): Erg\u00e4nzende Interpretation reflexionsseismischer Linien zwischen dem \u00f6stlichen und westlichen Molassebecken. Gebiete Waadtland Nord, Fribourg, Berner Seeland und Juras\u00fcdfuss zwischen Biel und Oensingen. - Nagra Arbeitsber. NAB 10-40.
  • Roth, P., Naef, H. & Schnellmann, M. (2010): Kompilation und Interpretation der Reflexionsseismik im Tafeljura und Molassebecken der Zentral- und Nordostschweiz. - Nagra Arbeitsber. NAB 10-39.
  • Sommaruga, A., Eichenberger, U. & Marillier, F. (2012): Seismic Atlas of the Swiss Molasse Basin. - Mat\u00e9r. G\u00e9ol. Suisse, G\u00e9ophys. 44.
", "position": 3, "Title": "Reflection seismic", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.bafu.hydrogeologische-karte_100": {"Identifier": "ch.bafu.hydrogeologische-karte_100", "Abstract": "Published by the Federal Office for the Environment FOEN, the specialist office of the Swiss Geological Survey responsible for hydrogeology.The hydrogeological map 1:100,000 shows the subsurface from the perspective of three disciplines: geology, hydrology and hydrogeology. The subsurface is classified according to lithological-petrographical criteria and permeability. Point and line data (springs, wells, hydraulic connections, groundwater resources, etc.) indicate the flow paths of groundwater and its exploitation at wells and tapped springs. The representation at a scale of 100,000 provides insight into the regional hydrogeological conditions. The following maps are available: 1. B\u00f6zberg/Berom\u00fcnster, 1972; 2. Lake Constance, 1980; 3. Panixerpass, 1985; 4. Biel-Bienne, 1991/92; 5. Toggenburg, 1993/94; 6. Saane, 1999; 8. Vallorbe - L\u00e9man nord, 2006; 7. Basel, 2014. For North West Switzerland, a seamless vector data set of maps 4, 6, 7 and 8 was created. The data can be obtained from the FOEN (www.bafu.admin.ch Data, indicators, maps).", "position": 2, "Title": "Hydrogeological map 100", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": false}, "ch.swisstopo.geologie-tiefengeothermie_projekte": {"Identifier": "ch.swisstopo.geologie-tiefengeothermie_projekte", "Abstract": "This map shows deep geothermal plants in operation as well as current and former deep geothermal projects in Switzerland. The project status corresponds to one of the following: - Prospection: Following regulatory approval by the canton(s) geophysical and geological studies are employed to identify a reservoir in the subsurface (permit zones shown, if available). - Under development: A reservoir has been identified and deemed suitable for producing geothermal energy. Permits required for the construction of a geothermal plant have been obtained and construction will begin shortly or is already in progress. - In operation: The plant is producing geothermal energy. - Abandoned: For any one of various reasons, the project has been stopped. Projects and plants are classified in the following types of system: Deep geothermal probe, Hydrothermal, Enhanced Geothermal System (EGS) and High temperature aquifer thermal energy storage (HT-ATES). Shallow geothermal energy production (i.e., <500 m depth to reservoir) is not featured. The map does not purport to be complete.", "position": 1, "Title": "Deep geothermal projects", "transparency": 0, "type": "WMS", "url": "https://wms.geo.admin.ch/?", "visibility": false, "queryable": true}, "ch.kantone.cadastralwebmap-farbe": {"Identifier": "ch.kantone.cadastralwebmap-farbe", "Abstract": "The basis is a representation service (web map service) created using data from the federal AV-Geoportal. However, the service does not provide the full data from the official cadastral survey.", "position": 0, "Title": "CadastralWebMap", "transparency": 0, "type": "WMTS", "url": "https://wmts.geo.admin.ch/1.0.0/ch.kantone.cadastralwebmap-farbe/default/{Time}/2056/{TileMatrix}/{TileCol}/{TileRow}.png", "visibility": false, "queryable": false, "conf": {"urls": ["https://wmts.geo.admin.ch/1.0.0/ch.kantone.cadastralwebmap-farbe/default/{Time}/2056/{TileMatrix}/{TileCol}/{TileRow}.png"], "layer": "ch.kantone.cadastralwebmap-farbe", "matrixSet": "2056_28", "format": "image/png", "projection": {"code_": "EPSG:2056", "units_": "m", "extent_": [2420000, 1030000, 2900000, 1350000], "worldExtent_": null, "axisOrientation_": "enu", "global_": false, "canWrapX_": false, "defaultTileGrid_": {"minZoom": 0, "resolutions_": [1875, 937.5, 468.75, 234.375, 117.1875, 58.59375, 29.296875, 14.6484375, 7.32421875, 3.662109375, 1.8310546875, 0.91552734375, 0.457763671875, 0.2288818359375, 0.11444091796875, 0.057220458984375, 0.0286102294921875, 0.01430511474609375, 0.007152557373046875, 0.0035762786865234375, 0.0017881393432617188, 0.0008940696716308594, 0.0004470348358154297, 0.00022351741790771484, 0.00011175870895385742, 5.587935447692871e-05, 2.7939677238464355e-05, 1.3969838619232178e-05, 6.984919309616089e-06, 3.4924596548080444e-06, 1.7462298274040222e-06, 8.731149137020111e-07, 4.3655745685100555e-07, 2.1827872842550278e-07, 1.0913936421275139e-07, 5.4569682106375694e-08, 2.7284841053187847e-08, 1.3642420526593924e-08, 6.821210263296962e-09, 3.410605131648481e-09, 1.7053025658242404e-09, 8.526512829121202e-10, 4.263256414560601e-10], "zoomFactor_": 2, "maxZoom": 42, "origin_": [2420000, 1350000], "origins_": null, "tileSizes_": null, "tileSize_": 256, "extent_": [2420000, 1030000, 2900000, 1350000], "fullTileRanges_": [{"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 1, "minY": 0, "maxY": 1}, {"minX": 0, "maxX": 3, "minY": 0, "maxY": 2}, {"minX": 0, "maxX": 7, "minY": 0, "maxY": 5}, {"minX": 0, "maxX": 15, "minY": 0, "maxY": 10}, {"minX": 0, "maxX": 31, "minY": 0, "maxY": 21}, {"minX": 0, "maxX": 63, "minY": 0, "maxY": 42}, {"minX": 0, "maxX": 127, "minY": 0, "maxY": 85}, {"minX": 0, "maxX": 255, "minY": 0, "maxY": 170}, {"minX": 0, "maxX": 511, "minY": 0, "maxY": 341}, {"minX": 0, "maxX": 1023, "minY": 0, "maxY": 682}, {"minX": 0, "maxX": 2047, "minY": 0, "maxY": 1365}, {"minX": 0, "maxX": 4095, "minY": 0, "maxY": 2730}, {"minX": 0, "maxX": 8191, "minY": 0, "maxY": 5461}, {"minX": 0, "maxX": 16383, "minY": 0, "maxY": 10922}, {"minX": 0, "maxX": 32767, "minY": 0, "maxY": 21845}, {"minX": 0, "maxX": 65535, "minY": 0, "maxY": 43690}, {"minX": 0, "maxX": 131071, "minY": 0, "maxY": 87381}, {"minX": 0, "maxX": 262143, "minY": 0, "maxY": 174762}, {"minX": 0, "maxX": 524287, "minY": 0, "maxY": 349525}, {"minX": 0, "maxX": 1048575, "minY": 0, "maxY": 699050}, {"minX": 0, "maxX": 2097151, "minY": 0, "maxY": 1398101}, {"minX": 0, "maxX": 4194303, "minY": 0, "maxY": 2796202}, {"minX": 0, "maxX": 8388607, "minY": 0, "maxY": 5592405}, {"minX": 0, "maxX": 16777215, "minY": 0, "maxY": 11184810}, {"minX": 0, "maxX": 33554431, "minY": 0, "maxY": 22369621}, {"minX": 0, "maxX": 67108863, "minY": 0, "maxY": 44739242}, {"minX": 0, "maxX": 134217727, "minY": 0, "maxY": 89478485}, {"minX": 0, "maxX": 268435455, "minY": 0, "maxY": 178956970}, {"minX": 0, "maxX": 536870911, "minY": 0, "maxY": 357913941}, {"minX": 0, "maxX": 1073741823, "minY": 0, "maxY": 715827882}, {"minX": 0, "maxX": 2147483647, "minY": 0, "maxY": 1431655765}, {"minX": 0, "maxX": 4294967295, "minY": 0, "maxY": 2863311530}, {"minX": 0, "maxX": 8589934591, "minY": 0, "maxY": 5726623061}, {"minX": 0, "maxX": 17179869183, "minY": 0, "maxY": 11453246122}, {"minX": 0, "maxX": 34359738367, "minY": 0, "maxY": 22906492245}, {"minX": 0, "maxX": 68719476735, "minY": 0, "maxY": 45812984490}, {"minX": 0, "maxX": 137438953471, "minY": 0, "maxY": 91625968981}, {"minX": 0, "maxX": 274877906943, "minY": 0, "maxY": 183251937962}, {"minX": 0, "maxX": 549755813887, "minY": 0, "maxY": 366503875925}, {"minX": 0, "maxX": 1099511627775, "minY": 0, "maxY": 733007751850}, {"minX": 0, "maxX": 2199023255551, "minY": 0, "maxY": 1466015503701}, {"minX": 0, "maxX": 4398046511103, "minY": 0, "maxY": 2932031007402}], "tmpSize_": [256, 256], "tmpExtent_": [0, 0, 0, 0]}, "ol_uid": "54"}, "requestEncoding": "REST", "tileGrid": {"minZoom": 0, "resolutions_": [4000, 3750, 3500, 3250, 3000, 2750, 2500, 2250, 2000, 1750, 1500, 1250, 1000, 750, 650, 500, 250, 100, 50, 20, 10, 5, 2.5, 2, 1.5, 1, 0.5, 0.25, 0.09999999999999999], "maxZoom": 28, "origin_": null, "origins_": [[2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000], [2420000, 1350000]], "tileSizes_": [256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256, 256], "tileSize_": null, "extent_": [2420000, 326000, 3444000, 1350000], "fullTileRanges_": [{"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 0, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 1, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 1, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 1, "minY": 0, "maxY": 0}, {"minX": 0, "maxX": 1, "minY": 0, "maxY": 1}, {"minX": 0, "maxX": 2, "minY": 0, "maxY": 1}, {"minX": 0, "maxX": 2, "minY": 0, "maxY": 1}, {"minX": 0, "maxX": 3, "minY": 0, "maxY": 2}, {"minX": 0, "maxX": 7, "minY": 0, "maxY": 4}, {"minX": 0, "maxX": 18, "minY": 0, "maxY": 12}, {"minX": 0, "maxX": 37, "minY": 0, "maxY": 24}, {"minX": 0, "maxX": 93, "minY": 0, "maxY": 62}, {"minX": 0, "maxX": 187, "minY": 0, "maxY": 124}, {"minX": 0, "maxX": 374, "minY": 0, "maxY": 249}, {"minX": 0, "maxX": 749, "minY": 0, "maxY": 499}, {"minX": 0, "maxX": 937, "minY": 0, "maxY": 624}, {"minX": 0, "maxX": 1249, "minY": 0, "maxY": 833}, {"minX": 0, "maxX": 1874, "minY": 0, "maxY": 1249}, {"minX": 0, "maxX": 3749, "minY": 0, "maxY": 2499}, {"minX": 0, "maxX": 7499, "minY": 0, "maxY": 4999}, {"minX": 0, "maxX": 18749, "minY": 0, "maxY": 12499}], "tmpSize_": [256, 256], "tmpExtent_": [0, 0, 0, 0], "matrixIds_": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28"]}, "style": "ch.kantone.cadastralwebmap-farbe", "dimensions": {"Time": "current"}, "wrapX": false}}}, "editor": {}}, "appearance": {"explorer": 1}}' WHERE subject_id = 'sub_anonymous'; -- Update and disable existing users From 650dc1fe63d2de135319d616c2d2ac6a6563822c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Dec 2024 10:31:13 +0000 Subject: [PATCH 09/23] Bump path-to-regexp and express in /src/client Bumps [path-to-regexp](https://github.com/pillarjs/path-to-regexp) to 0.1.12 and updates ancestor dependency [express](https://github.com/expressjs/express). These dependencies need to be updated together. Updates `path-to-regexp` from 0.1.10 to 0.1.12 - [Release notes](https://github.com/pillarjs/path-to-regexp/releases) - [Changelog](https://github.com/pillarjs/path-to-regexp/blob/master/History.md) - [Commits](https://github.com/pillarjs/path-to-regexp/compare/v0.1.10...v0.1.12) Updates `express` from 4.21.1 to 4.21.2 - [Release notes](https://github.com/expressjs/express/releases) - [Changelog](https://github.com/expressjs/express/blob/4.21.2/History.md) - [Commits](https://github.com/expressjs/express/compare/4.21.1...4.21.2) --- updated-dependencies: - dependency-name: path-to-regexp dependency-type: indirect - dependency-name: express dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- src/client/package-lock.json | 20 ++++++++++++-------- src/client/package.json | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/client/package-lock.json b/src/client/package-lock.json index e5f4b80c1..daf6bd299 100644 --- a/src/client/package-lock.json +++ b/src/client/package-lock.json @@ -21,7 +21,7 @@ "d3": "^7.9.0", "date-fns": "^2.30.0", "dotenv": "^16.3.1", - "express": "^4.21.1", + "express": "^4.21.2", "express-rate-limit": "^7.4.1", "http-proxy-middleware": "^3.0.3", "i18next": "^23.7.7", @@ -5513,9 +5513,9 @@ "integrity": "sha512-Z+ktTxTwv9ILfgKCk32OX3n/doe+OcLTRtqK9pcL+JsP3J1/VW8Uvl4ZjLlKqeW4rzK4oesDOGMEMRIZqtP4Iw==" }, "node_modules/express": { - "version": "4.21.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", - "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", @@ -5536,7 +5536,7 @@ "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.10", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", "qs": "6.13.0", "range-parser": "~1.2.1", @@ -5551,6 +5551,10 @@ }, "engines": { "node": ">= 0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/express-rate-limit": { @@ -8179,9 +8183,9 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-to-regexp": { - "version": "0.1.10", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", - "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" + "version": "0.1.12", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.12.tgz", + "integrity": "sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==" }, "node_modules/path-type": { "version": "4.0.0", diff --git a/src/client/package.json b/src/client/package.json index 8635272ed..452a37043 100644 --- a/src/client/package.json +++ b/src/client/package.json @@ -36,7 +36,7 @@ "d3": "^7.9.0", "date-fns": "^2.30.0", "dotenv": "^16.3.1", - "express": "^4.21.1", + "express": "^4.21.2", "express-rate-limit": "^7.4.1", "http-proxy-middleware": "^3.0.3", "i18next": "^23.7.7", From dee250bc2661c94eb69b3df454cd7e7fd8225ef2 Mon Sep 17 00:00:00 2001 From: danjov Date: Mon, 9 Dec 2024 11:31:59 +0100 Subject: [PATCH 10/23] Do not log user-controlled data Fixes https://github.com/swisstopo/swissgeol-boreholes-suite/security/code-scanning/27 --- src/api/BoreholeFileCloudService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/BoreholeFileCloudService.cs b/src/api/BoreholeFileCloudService.cs index 5cd5585e9..e4baae96e 100644 --- a/src/api/BoreholeFileCloudService.cs +++ b/src/api/BoreholeFileCloudService.cs @@ -97,7 +97,7 @@ internal async Task UploadObject(IFormFile file, string objectName) } catch (AmazonS3Exception ex) { - logger.LogError(ex, $"Error uploading file <{file.FileName}> to cloud storage."); + logger.LogError(ex, $"Error uploading file to cloud storage."); throw; } } From e6c5228f0e4fb36210501127af40c88ba889a890 Mon Sep 17 00:00:00 2001 From: danjov Date: Mon, 9 Dec 2024 11:32:40 +0100 Subject: [PATCH 11/23] Remove unsed string interpolation --- src/api/BoreholeFileCloudService.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/api/BoreholeFileCloudService.cs b/src/api/BoreholeFileCloudService.cs index e4baae96e..9b6bdb745 100644 --- a/src/api/BoreholeFileCloudService.cs +++ b/src/api/BoreholeFileCloudService.cs @@ -97,7 +97,7 @@ internal async Task UploadObject(IFormFile file, string objectName) } catch (AmazonS3Exception ex) { - logger.LogError(ex, $"Error uploading file to cloud storage."); + logger.LogError(ex, "Error uploading file to cloud storage."); throw; } } @@ -121,7 +121,7 @@ public async Task GetObject(string objectName) } catch (AmazonS3Exception ex) { - logger.LogError(ex, $"Error downloading file from cloud storage."); + logger.LogError(ex, "Error downloading file from cloud storage."); throw; } } @@ -156,7 +156,7 @@ public async Task CountDataExtractionObjects(string objectName) } catch (AmazonS3Exception ex) { - logger.LogError(ex, $"Error counting files in data extraction folder in cloud storage."); + logger.LogError(ex, "Error counting files in data extraction folder in cloud storage."); throw; } } From 84fa34cdf64207f180c1a124c38876b61db17359 Mon Sep 17 00:00:00 2001 From: danjov Date: Mon, 9 Dec 2024 11:33:45 +0100 Subject: [PATCH 12/23] Do not log user-controlled data Fixes https://github.com/swisstopo/swissgeol-boreholes-suite/security/code-scanning/27 --- src/api/BoreholeFileCloudService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/BoreholeFileCloudService.cs b/src/api/BoreholeFileCloudService.cs index 9b6bdb745..9f0080411 100644 --- a/src/api/BoreholeFileCloudService.cs +++ b/src/api/BoreholeFileCloudService.cs @@ -227,7 +227,7 @@ public async Task DeleteObject(string objectName) } catch (AmazonS3Exception ex) { - logger.LogError(ex, $"Error deleting file <{objectName}> from cloud storage."); + logger.LogError(ex, $"Error deleting file from cloud storage."); throw; } } From 751c82c0de6205a98c3abf26540d4c67a315da7a Mon Sep 17 00:00:00 2001 From: danjov Date: Mon, 9 Dec 2024 11:34:10 +0100 Subject: [PATCH 13/23] Remove unsed string interpolation --- src/api/BoreholeFileCloudService.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/BoreholeFileCloudService.cs b/src/api/BoreholeFileCloudService.cs index 9f0080411..d7fea3e22 100644 --- a/src/api/BoreholeFileCloudService.cs +++ b/src/api/BoreholeFileCloudService.cs @@ -209,7 +209,7 @@ public async Task CountDataExtractionObjects(string objectName) } catch (AmazonS3Exception ex) { - logger.LogError(ex, $"Error retrieving image information from data extraction folder in cloud storage."); + logger.LogError(ex, "Error retrieving image information from data extraction folder in cloud storage."); throw; } } @@ -227,7 +227,7 @@ public async Task DeleteObject(string objectName) } catch (AmazonS3Exception ex) { - logger.LogError(ex, $"Error deleting file from cloud storage."); + logger.LogError(ex, "Error deleting file from cloud storage."); throw; } } From 74fd8a02eb117cee70d00a4fd3edf9eb9f6a553a Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Tue, 10 Dec 2024 10:50:32 +0100 Subject: [PATCH 14/23] Hide user Layers for anonymous user --- .../src/pages/overview/layout/mainSideNav.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/client/src/pages/overview/layout/mainSideNav.tsx b/src/client/src/pages/overview/layout/mainSideNav.tsx index 94ebdbae6..adb08dc42 100644 --- a/src/client/src/pages/overview/layout/mainSideNav.tsx +++ b/src/client/src/pages/overview/layout/mainSideNav.tsx @@ -137,15 +137,15 @@ const MainSideNav = ({ setUpload(true); }} /> + } + label={t("usersMap")} + selected={isLayersPanelVisible} + onClick={handleToggleLayers} + /> )} - } - label={t("usersMap")} - selected={isLayersPanelVisible} - onClick={handleToggleLayers} - /> Date: Tue, 10 Dec 2024 10:51:15 +0100 Subject: [PATCH 15/23] Add release notes --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b1048f65..c563eef04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,7 @@ - Updated the layout of the borehole general tab. - Removed deduplication check when adding and detaching attachments. - When copying a borehole, attachments won't be copied. +- Hidden layers settings for anonymous users. ### Fixed From 18ed504e4ba7ca880b9d629359b522464bd6cd0f Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Tue, 10 Dec 2024 11:06:30 +0100 Subject: [PATCH 16/23] Fix changelog entry --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c563eef04..1ac42c50d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,7 +24,7 @@ - Updated the layout of the borehole general tab. - Removed deduplication check when adding and detaching attachments. - When copying a borehole, attachments won't be copied. -- Hidden layers settings for anonymous users. +- Removed layers settings for anonymous users. ### Fixed From 0b69106dfbc0f29a7afeccb327f600b560a08433 Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Tue, 10 Dec 2024 13:57:24 +0100 Subject: [PATCH 17/23] Hotfix restrictionUntil display --- .../cypress/e2e/detailPage/location.cy.js | 17 ++++++++++++++++- .../detail/form/location/restrictionSegment.tsx | 5 +++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/client/cypress/e2e/detailPage/location.cy.js b/src/client/cypress/e2e/detailPage/location.cy.js index f3c8532dc..c9ba55df4 100644 --- a/src/client/cypress/e2e/detailPage/location.cy.js +++ b/src/client/cypress/e2e/detailPage/location.cy.js @@ -1,6 +1,6 @@ import { addItem, saveWithSaveBar, stopEditing } from "../helpers/buttonHelpers"; import { checkRowWithText, clickOnRowWithText, showTableAndWaitForData } from "../helpers/dataGridHelpers"; -import { evaluateInput, evaluateSelect, setInput, setSelect } from "../helpers/formHelpers"; +import { evaluateInput, evaluateSelect, isDisabled, setInput, setSelect } from "../helpers/formHelpers"; import { createBorehole, goToRouteAndAcceptTerms, @@ -124,6 +124,21 @@ describe("Tests for 'Location' edit page.", () => { }); }); + it.only("Saves restriction until date.", () => { + newEditableBorehole().as("borehole_id"); + + setSelect("restrictionId", 3); + isDisabled("restrictionUntil", false); + setInput("restrictionUntil", "2012-11-14"); + evaluateInput("restrictionUntil", "2012-11-14"); + saveWithSaveBar(); + // navigate away and back to check if values are saved + cy.get('[data-cy="borehole-menu-item"]').click(); + cy.get('[data-cy="location-menu-item"]').click(); + + evaluateInput("restrictionUntil", "2012-11-14"); + }); + it("saves with ctrl s", () => { newEditableBorehole(); diff --git a/src/client/src/pages/detail/form/location/restrictionSegment.tsx b/src/client/src/pages/detail/form/location/restrictionSegment.tsx index 099dd722f..615ea404b 100644 --- a/src/client/src/pages/detail/form/location/restrictionSegment.tsx +++ b/src/client/src/pages/detail/form/location/restrictionSegment.tsx @@ -24,6 +24,11 @@ const RestrictionSegment = ({ borehole, editingEnabled, formMethods }: Restricti const { dirtyFields } = formMethods.formState; const restriction = formMethods.watch("restrictionId"); + useEffect(() => { + //TODO: Adapt data type on backend to Date instead of slicing the returned DateTime + formMethods.setValue("restrictionUntil", borehole.restrictionUntil?.toString().slice(0, 10) ?? ""); + }, [borehole.restrictionUntil, formMethods]); + useEffect(() => { if (dirtyFields.restrictionId) { setRestrictionUntilEnabled(restriction === restrictionUntilCode); From 7e05f14fb45436a0636d19ac362492bb3fa0fdb8 Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Tue, 10 Dec 2024 13:57:58 +0100 Subject: [PATCH 18/23] Remove it-only --- src/client/cypress/e2e/detailPage/location.cy.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/cypress/e2e/detailPage/location.cy.js b/src/client/cypress/e2e/detailPage/location.cy.js index c9ba55df4..e488c1ba1 100644 --- a/src/client/cypress/e2e/detailPage/location.cy.js +++ b/src/client/cypress/e2e/detailPage/location.cy.js @@ -124,7 +124,7 @@ describe("Tests for 'Location' edit page.", () => { }); }); - it.only("Saves restriction until date.", () => { + it("Saves restriction until date.", () => { newEditableBorehole().as("borehole_id"); setSelect("restrictionId", 3); From 41bdd9f5645f04745678a2b6f2185ad769037aaf Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Tue, 10 Dec 2024 13:06:24 +0100 Subject: [PATCH 19/23] Fix domainDropdown --- .../legacyComponents/domain/dropdown/domainDropdown.jsx | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/client/src/components/legacyComponents/domain/dropdown/domainDropdown.jsx b/src/client/src/components/legacyComponents/domain/dropdown/domainDropdown.jsx index be6cd6861..46ddfceb8 100644 --- a/src/client/src/components/legacyComponents/domain/dropdown/domainDropdown.jsx +++ b/src/client/src/components/legacyComponents/domain/dropdown/domainDropdown.jsx @@ -203,14 +203,12 @@ class DomainDropdown extends React.Component { ), })), ); - if (readOnly) { - let selectedOption = options.find(option => option.value === selected); - return ; - } return ( Date: Tue, 10 Dec 2024 14:15:30 +0100 Subject: [PATCH 20/23] Fix translation key --- .../src/pages/overview/sidePanelContent/filter/statusFilter.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/src/pages/overview/sidePanelContent/filter/statusFilter.jsx b/src/client/src/pages/overview/sidePanelContent/filter/statusFilter.jsx index 5e91d8dee..bd2a99329 100644 --- a/src/client/src/pages/overview/sidePanelContent/filter/statusFilter.jsx +++ b/src/client/src/pages/overview/sidePanelContent/filter/statusFilter.jsx @@ -41,7 +41,7 @@ class StatusFilter extends Component { { name: "EDIT", translationKey: "statuseditor" }, { name: "CONTROL", translationKey: "statuscontroller" }, { name: "VALID", translationKey: "statusvalidator" }, - { name: "PUBLIC", translationKey: "statuspublic" }, + { name: "PUBLIC", translationKey: "statuspublisher" }, ].map(role => ( Date: Tue, 10 Dec 2024 15:47:32 +0100 Subject: [PATCH 21/23] Fix layers display settings bug --- src/client/src/pages/settings/editorSettings.tsx | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/client/src/pages/settings/editorSettings.tsx b/src/client/src/pages/settings/editorSettings.tsx index 4dac65100..729a07d10 100644 --- a/src/client/src/pages/settings/editorSettings.tsx +++ b/src/client/src/pages/settings/editorSettings.tsx @@ -72,11 +72,12 @@ const EditorSettings = () => { position: number, queryable: boolean, ) => { + const key = type === "WMTS" ? layer?.Identifier : layer?.Name; dispatch( patchSettings( "map.explorer", { - Identifier: layer.Identifier, + Identifier: key, Abstract: layer.Abstract, position: position, Title: layer.Title, @@ -88,7 +89,7 @@ const EditorSettings = () => { conf: conf, }, // @ts-expect-error typing not complete - type === "WMTS" ? layer?.Identifier : layer?.Name, + key, ), ); }; From af0ccaa6c6df47e050a0ef3ec3e3f24eabaeac47 Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Tue, 10 Dec 2024 16:08:35 +0100 Subject: [PATCH 22/23] Add release notes entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ac42c50d..b8b531200 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,7 @@ - Filtering striae for `not specified` returned wrong results. - Filtering by `borehole status` did not work. - When saving with ctrl+s in the borehole sections, the form content was reset. +- There was a bug when changing the order,transparency or visibility of custom WMS user layers. ## v2.1.870 - 2024-09-27 From 8e98d67749beb3d7655ad1afb790f285030b2e78 Mon Sep 17 00:00:00 2001 From: MiraGeowerkstatt Date: Tue, 10 Dec 2024 16:13:24 +0100 Subject: [PATCH 23/23] Update CHANGELOG.md Co-authored-by: Daniel Jovanovic --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b8b531200..84f9950d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,7 +40,7 @@ - Filtering striae for `not specified` returned wrong results. - Filtering by `borehole status` did not work. - When saving with ctrl+s in the borehole sections, the form content was reset. -- There was a bug when changing the order,transparency or visibility of custom WMS user layers. +- There was a bug when changing the order, transparency or visibility of custom WMS user layers. ## v2.1.870 - 2024-09-27