diff --git a/src/IIIFPresentation/API/Features/Manifest/CanvasPaintingResolver.cs b/src/IIIFPresentation/API/Features/Manifest/CanvasPaintingResolver.cs index e490201..1130f7b 100644 --- a/src/IIIFPresentation/API/Features/Manifest/CanvasPaintingResolver.cs +++ b/src/IIIFPresentation/API/Features/Manifest/CanvasPaintingResolver.cs @@ -218,7 +218,8 @@ public class CanvasPaintingResolver( CustomerId = customerId, CanvasOrder = count, AssetId = $"{customerId}/{space}/{id}", - ChoiceOrder = -1 + ChoiceOrder = -1, + Ingesting = true }; count++; diff --git a/src/IIIFPresentation/BackgroundHandler/BatchCompletion/BatchCompletionMessageHandler.cs b/src/IIIFPresentation/BackgroundHandler/BatchCompletion/BatchCompletionMessageHandler.cs index af3af21..f32fc42 100644 --- a/src/IIIFPresentation/BackgroundHandler/BatchCompletion/BatchCompletionMessageHandler.cs +++ b/src/IIIFPresentation/BackgroundHandler/BatchCompletion/BatchCompletionMessageHandler.cs @@ -76,7 +76,7 @@ private async Task UpdateAssetsIfRequired(BatchCompletionMessage batchCompletion private void CompleteBatch(Batch batch) { - batch.Finished = DateTime.UtcNow; //todo: change to actual batch completion time? + batch.Processed = DateTime.UtcNow; batch.Status = BatchStatus.Completed; } @@ -86,7 +86,7 @@ private void UpdateCanvasPaintings(HydraCollection assets, Batch batch) foreach (var canvasPainting in batch.Manifest.CanvasPaintings) { - if (canvasPainting.CanvasOriginalId == null) // Trying to figure out an asset that hasn't been updated + if (canvasPainting.Ingesting) { var assetId = AssetId.FromString(canvasPainting.AssetId!); @@ -98,7 +98,8 @@ private void UpdateCanvasPaintings(HydraCollection assets, Batch batch) $"{dlcsSettings.OrchestratorUri}/iiif-img/{assetId.Customer}/{assetId.Space}/{assetId.Asset}/full/max/0/default.jpg"); //todo: do we need this? Supposed to be null for an asset really canvasPainting.Thumbnail = new Uri( - $"{dlcsSettings.OrchestratorUri}/thumbs/{assetId.Customer}/{assetId.Space}/{assetId.Asset}/100,/max/0/default.jpg"); //todo: move this to class + $"{dlcsSettings.OrchestratorUri}/thumbs/{assetId.Customer}/{assetId.Space}/{assetId.Asset}/100,/max/0/default.jpg"); //todo: how to get this? + canvasPainting.Ingesting = false; canvasPainting.Modified = DateTime.UtcNow; canvasPainting.StaticHeight = asset.Height; canvasPainting.StaticWidth = asset.Width; diff --git a/src/IIIFPresentation/DLCS/DlcsSettings.cs b/src/IIIFPresentation/DLCS/DlcsSettings.cs index bf84f46..26e0cf2 100644 --- a/src/IIIFPresentation/DLCS/DlcsSettings.cs +++ b/src/IIIFPresentation/DLCS/DlcsSettings.cs @@ -27,5 +27,5 @@ public class DlcsSettings /// /// Used to authenticate requests that do not go via the HttpContextAccessor /// - public string ApiLocalAuth { get; set; } //Todo: is this right? is there a better way of setting auth + public string? ApiLocalAuth { get; set; } } diff --git a/src/IIIFPresentation/Models/Database/CanvasPainting.cs b/src/IIIFPresentation/Models/Database/CanvasPainting.cs index 2af173c..6d73d38 100644 --- a/src/IIIFPresentation/Models/Database/CanvasPainting.cs +++ b/src/IIIFPresentation/Models/Database/CanvasPainting.cs @@ -119,6 +119,11 @@ public int? ChoiceOrder /// An asset id showing this asset is an internal item /// public string? AssetId { get; set; } + + /// + /// Whether the asset is currently being ingested into the DLCS + /// + public bool Ingesting { get; set; } = false; } public static class CanvasPaintingX diff --git a/src/IIIFPresentation/Models/Database/General/Batch.cs b/src/IIIFPresentation/Models/Database/General/Batch.cs index c897e1e..1e9c2e6 100644 --- a/src/IIIFPresentation/Models/Database/General/Batch.cs +++ b/src/IIIFPresentation/Models/Database/General/Batch.cs @@ -27,7 +27,7 @@ public class Batch /// /// When the batch was added to the DLCS /// - public DateTime? Finished { get; set; } + public DateTime? Processed { get; set; } /// /// Id of related manifest diff --git a/src/IIIFPresentation/Repository/Migrations/20241219171537_renameBatchFinishedAndAddIngesting.Designer.cs b/src/IIIFPresentation/Repository/Migrations/20241219171537_renameBatchFinishedAndAddIngesting.Designer.cs new file mode 100644 index 0000000..8407bde --- /dev/null +++ b/src/IIIFPresentation/Repository/Migrations/20241219171537_renameBatchFinishedAndAddIngesting.Designer.cs @@ -0,0 +1,408 @@ +// +using System; +using Microsoft.EntityFrameworkCore; +using Microsoft.EntityFrameworkCore.Infrastructure; +using Microsoft.EntityFrameworkCore.Migrations; +using Microsoft.EntityFrameworkCore.Storage.ValueConversion; +using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata; +using Repository; + +#nullable disable + +namespace Repository.Migrations +{ + [DbContext(typeof(PresentationContext))] + [Migration("20241219171537_renameBatchFinishedAndAddIngesting")] + partial class renameBatchFinishedAndAddIngesting + { + /// + protected override void BuildTargetModel(ModelBuilder modelBuilder) + { +#pragma warning disable 612, 618 + modelBuilder + .HasAnnotation("ProductVersion", "8.0.11") + .HasAnnotation("Relational:MaxIdentifierLength", 63); + + NpgsqlModelBuilderExtensions.HasPostgresExtension(modelBuilder, "citext"); + NpgsqlModelBuilderExtensions.UseIdentityByDefaultColumns(modelBuilder); + + modelBuilder.Entity("Models.Database.CanvasPainting", b => + { + b.Property("CanvasPaintingId") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("canvas_painting_id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("CanvasPaintingId")); + + b.Property("AssetId") + .HasColumnType("text") + .HasColumnName("asset_id"); + + b.Property("CanvasLabel") + .HasColumnType("text") + .HasColumnName("canvas_label"); + + b.Property("CanvasOrder") + .HasColumnType("integer") + .HasColumnName("canvas_order"); + + b.Property("CanvasOriginalId") + .HasColumnType("text") + .HasColumnName("canvas_original_id"); + + b.Property("ChoiceOrder") + .IsRequired() + .HasColumnType("integer") + .HasColumnName("choice_order"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created") + .HasDefaultValueSql("now()"); + + b.Property("CustomerId") + .HasColumnType("integer") + .HasColumnName("customer_id"); + + b.Property("Id") + .HasColumnType("text") + .HasColumnName("canvas_id"); + + b.Property("Ingesting") + .HasColumnType("boolean") + .HasColumnName("ingesting"); + + b.Property("Label") + .HasColumnType("jsonb") + .HasColumnName("label"); + + b.Property("ManifestId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("manifest_id"); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("modified") + .HasDefaultValueSql("now()"); + + b.Property("StaticHeight") + .HasColumnType("integer") + .HasColumnName("static_height"); + + b.Property("StaticWidth") + .HasColumnType("integer") + .HasColumnName("static_width"); + + b.Property("Target") + .HasColumnType("text") + .HasColumnName("target"); + + b.Property("Thumbnail") + .HasColumnType("text") + .HasColumnName("thumbnail"); + + b.HasKey("CanvasPaintingId") + .HasName("pk_canvas_paintings"); + + b.HasIndex("ManifestId", "CustomerId") + .HasDatabaseName("ix_canvas_paintings_manifest_id_customer_id"); + + b.HasIndex("Id", "CustomerId", "ManifestId", "AssetId", "CanvasOrder", "ChoiceOrder") + .IsUnique() + .HasDatabaseName("ix_canvas_paintings_canvas_id_customer_id_manifest_id_asset_id") + .HasFilter("canvas_original_id is null"); + + b.HasIndex("Id", "CustomerId", "ManifestId", "CanvasOriginalId", "CanvasOrder", "ChoiceOrder") + .IsUnique() + .HasDatabaseName("ix_canvas_paintings_canvas_id_customer_id_manifest_id_canvas_o") + .HasFilter("asset_id is null"); + + b.ToTable("canvas_paintings", (string)null); + }); + + modelBuilder.Entity("Models.Database.Collections.Collection", b => + { + b.Property("Id") + .HasColumnType("text") + .HasColumnName("id"); + + b.Property("CustomerId") + .HasColumnType("integer") + .HasColumnName("customer_id"); + + b.Property("Created") + .HasColumnType("timestamp with time zone") + .HasColumnName("created"); + + b.Property("CreatedBy") + .HasColumnType("text") + .HasColumnName("created_by"); + + b.Property("IsPublic") + .HasColumnType("boolean") + .HasColumnName("is_public"); + + b.Property("IsStorageCollection") + .HasColumnType("boolean") + .HasColumnName("is_storage_collection"); + + b.Property("Label") + .HasColumnType("jsonb") + .HasColumnName("label"); + + b.Property("LockedBy") + .HasColumnType("text") + .HasColumnName("locked_by"); + + b.Property("Modified") + .HasColumnType("timestamp with time zone") + .HasColumnName("modified"); + + b.Property("ModifiedBy") + .HasColumnType("text") + .HasColumnName("modified_by"); + + b.Property("Tags") + .HasColumnType("text") + .HasColumnName("tags"); + + b.Property("Thumbnail") + .HasColumnType("text") + .HasColumnName("thumbnail"); + + b.Property("UsePath") + .HasColumnType("boolean") + .HasColumnName("use_path"); + + b.HasKey("Id", "CustomerId") + .HasName("pk_collections"); + + b.ToTable("collections", (string)null); + }); + + modelBuilder.Entity("Models.Database.Collections.Manifest", b => + { + b.Property("Id") + .HasColumnType("text") + .HasColumnName("id"); + + b.Property("CustomerId") + .HasColumnType("integer") + .HasColumnName("customer_id"); + + b.Property("Created") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("created") + .HasDefaultValueSql("now()"); + + b.Property("CreatedBy") + .HasColumnType("text") + .HasColumnName("created_by"); + + b.Property("Label") + .HasColumnType("text") + .HasColumnName("label"); + + b.Property("Modified") + .ValueGeneratedOnAdd() + .HasColumnType("timestamp with time zone") + .HasColumnName("modified") + .HasDefaultValueSql("now()"); + + b.Property("ModifiedBy") + .HasColumnType("text") + .HasColumnName("modified_by"); + + b.Property("SpaceId") + .HasColumnType("integer") + .HasColumnName("space_id"); + + b.HasKey("Id", "CustomerId") + .HasName("pk_manifests"); + + b.ToTable("manifests", (string)null); + }); + + modelBuilder.Entity("Models.Database.General.Batch", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("CustomerId") + .HasColumnType("integer") + .HasColumnName("customer_id"); + + b.Property("ManifestId") + .IsRequired() + .HasColumnType("text") + .HasColumnName("manifest_id"); + + b.Property("Processed") + .HasColumnType("timestamp with time zone") + .HasColumnName("processed"); + + b.Property("Status") + .IsRequired() + .HasColumnType("text") + .HasColumnName("status"); + + b.Property("Submitted") + .HasColumnType("timestamp with time zone") + .HasColumnName("submitted"); + + b.HasKey("Id") + .HasName("pk_batches"); + + b.HasIndex("ManifestId", "CustomerId") + .HasDatabaseName("ix_batches_manifest_id_customer_id"); + + b.ToTable("batches", (string)null); + }); + + modelBuilder.Entity("Models.Database.General.Hierarchy", b => + { + b.Property("Id") + .ValueGeneratedOnAdd() + .HasColumnType("integer") + .HasColumnName("id"); + + NpgsqlPropertyBuilderExtensions.UseIdentityByDefaultColumn(b.Property("Id")); + + b.Property("Canonical") + .HasColumnType("boolean") + .HasColumnName("canonical"); + + b.Property("CollectionId") + .HasColumnType("text") + .HasColumnName("collection_id"); + + b.Property("CustomerId") + .HasColumnType("integer") + .HasColumnName("customer_id"); + + b.Property("ItemsOrder") + .HasColumnType("integer") + .HasColumnName("items_order"); + + b.Property("ManifestId") + .HasColumnType("text") + .HasColumnName("manifest_id"); + + b.Property("Parent") + .HasColumnType("text") + .HasColumnName("parent"); + + b.Property("Slug") + .IsRequired() + .HasColumnType("citext") + .HasColumnName("slug"); + + b.Property("Type") + .HasColumnType("integer") + .HasColumnName("type"); + + b.HasKey("Id") + .HasName("pk_hierarchy"); + + b.HasIndex("Parent", "CustomerId") + .HasDatabaseName("ix_hierarchy_parent_customer_id"); + + b.HasIndex("CollectionId", "CustomerId", "Canonical") + .IsUnique() + .HasDatabaseName("ix_hierarchy_collection_id_customer_id_canonical") + .HasFilter("canonical is true"); + + b.HasIndex("CustomerId", "Slug", "Parent") + .IsUnique() + .HasDatabaseName("ix_hierarchy_customer_id_slug_parent"); + + b.HasIndex("ManifestId", "CustomerId", "Canonical") + .IsUnique() + .HasDatabaseName("ix_hierarchy_manifest_id_customer_id_canonical") + .HasFilter("canonical is true"); + + b.ToTable("hierarchy", null, t => + { + t.HasCheckConstraint("stop_collection_and_manifest_in_same_record", "num_nonnulls(manifest_id, collection_id) = 1"); + }); + }); + + modelBuilder.Entity("Models.Database.CanvasPainting", b => + { + b.HasOne("Models.Database.Collections.Manifest", "Manifest") + .WithMany("CanvasPaintings") + .HasForeignKey("ManifestId", "CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_canvas_paintings_manifests_manifest_id_customer_id"); + + b.Navigation("Manifest"); + }); + + modelBuilder.Entity("Models.Database.General.Batch", b => + { + b.HasOne("Models.Database.Collections.Manifest", "Manifest") + .WithMany("Batches") + .HasForeignKey("ManifestId", "CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .IsRequired() + .HasConstraintName("fk_batches_manifests_manifest_id_customer_id"); + + b.Navigation("Manifest"); + }); + + modelBuilder.Entity("Models.Database.General.Hierarchy", b => + { + b.HasOne("Models.Database.Collections.Collection", "Collection") + .WithMany("Hierarchy") + .HasForeignKey("CollectionId", "CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_hierarchy_collections_collection_id_customer_id"); + + b.HasOne("Models.Database.Collections.Manifest", "Manifest") + .WithMany("Hierarchy") + .HasForeignKey("ManifestId", "CustomerId") + .OnDelete(DeleteBehavior.Cascade) + .HasConstraintName("fk_hierarchy_manifests_manifest_id_customer_id"); + + b.HasOne("Models.Database.Collections.Collection", "ParentCollection") + .WithMany("Children") + .HasForeignKey("Parent", "CustomerId") + .OnDelete(DeleteBehavior.NoAction) + .HasConstraintName("fk_hierarchy_collections_parent_customer_id"); + + b.Navigation("Collection"); + + b.Navigation("Manifest"); + + b.Navigation("ParentCollection"); + }); + + modelBuilder.Entity("Models.Database.Collections.Collection", b => + { + b.Navigation("Children"); + + b.Navigation("Hierarchy"); + }); + + modelBuilder.Entity("Models.Database.Collections.Manifest", b => + { + b.Navigation("Batches"); + + b.Navigation("CanvasPaintings"); + + b.Navigation("Hierarchy"); + }); +#pragma warning restore 612, 618 + } + } +} diff --git a/src/IIIFPresentation/Repository/Migrations/20241219171537_renameBatchFinishedAndAddIngesting.cs b/src/IIIFPresentation/Repository/Migrations/20241219171537_renameBatchFinishedAndAddIngesting.cs new file mode 100644 index 0000000..dc088ee --- /dev/null +++ b/src/IIIFPresentation/Repository/Migrations/20241219171537_renameBatchFinishedAndAddIngesting.cs @@ -0,0 +1,39 @@ +using Microsoft.EntityFrameworkCore.Migrations; + +#nullable disable + +namespace Repository.Migrations +{ + /// + public partial class renameBatchFinishedAndAddIngesting : Migration + { + /// + protected override void Up(MigrationBuilder migrationBuilder) + { + migrationBuilder.RenameColumn( + name: "finished", + table: "batches", + newName: "processed"); + + migrationBuilder.AddColumn( + name: "ingesting", + table: "canvas_paintings", + type: "boolean", + nullable: false, + defaultValue: false); + } + + /// + protected override void Down(MigrationBuilder migrationBuilder) + { + migrationBuilder.DropColumn( + name: "ingesting", + table: "canvas_paintings"); + + migrationBuilder.RenameColumn( + name: "processed", + table: "batches", + newName: "finished"); + } + } +} diff --git a/src/IIIFPresentation/Repository/Migrations/PresentationContextModelSnapshot.cs b/src/IIIFPresentation/Repository/Migrations/PresentationContextModelSnapshot.cs index c5c48d5..5185e9d 100644 --- a/src/IIIFPresentation/Repository/Migrations/PresentationContextModelSnapshot.cs +++ b/src/IIIFPresentation/Repository/Migrations/PresentationContextModelSnapshot.cs @@ -67,6 +67,10 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("text") .HasColumnName("canvas_id"); + b.Property("Ingesting") + .HasColumnType("boolean") + .HasColumnName("ingesting"); + b.Property("Label") .HasColumnType("jsonb") .HasColumnName("label"); @@ -234,15 +238,15 @@ protected override void BuildModel(ModelBuilder modelBuilder) .HasColumnType("integer") .HasColumnName("customer_id"); - b.Property("Finished") - .HasColumnType("timestamp with time zone") - .HasColumnName("finished"); - b.Property("ManifestId") .IsRequired() .HasColumnType("text") .HasColumnName("manifest_id"); + b.Property("Processed") + .HasColumnType("timestamp with time zone") + .HasColumnName("processed"); + b.Property("Status") .IsRequired() .HasColumnType("text")