From e4a89aadc70bb6355f12baa4205ce2e7e981bb98 Mon Sep 17 00:00:00 2001 From: "jack.lewis" Date: Fri, 13 Dec 2024 12:10:57 +0000 Subject: [PATCH 1/5] Add fallback value to Behavior --- .../Integration/ModifyCollectionTests.cs | 113 +++++++++++++++++- .../API/Features/Storage/Helpers/BehaviorX.cs | 10 +- 2 files changed, 117 insertions(+), 6 deletions(-) diff --git a/src/IIIFPresentation/API.Tests/Integration/ModifyCollectionTests.cs b/src/IIIFPresentation/API.Tests/Integration/ModifyCollectionTests.cs index 75c6eaeb..861d3f7a 100644 --- a/src/IIIFPresentation/API.Tests/Integration/ModifyCollectionTests.cs +++ b/src/IIIFPresentation/API.Tests/Integration/ModifyCollectionTests.cs @@ -635,6 +635,68 @@ public async Task CreateCollection_FailsToCreateCollection_WhenCalledWithoutShow // Assert response.StatusCode.Should().Be(HttpStatusCode.Forbidden); } + + [Fact] + public async Task CreateCollection_CreatesNonPublicIIIFCollection_WhenNullBehavior() + { + // Arrange + var slug = nameof(CreateCollection_CreatesNonPublicIIIFCollection_WhenNullBehavior); + var collection = $@"{{ + ""type"": ""Collection"", + ""label"": {{ + ""en"": [ + ""iiif post"" + ] + }}, + ""slug"": ""{slug}"", + ""parent"": ""{parent}"", + ""tags"": ""some, tags"", + ""itemsOrder"": 1, + ""thumbnail"": [ + {{ + ""id"": ""https://example.org/img/thumb.jpg"", + ""type"": ""Image"", + ""format"": ""image/jpeg"", + ""width"": 300, + ""height"": 200 + }} + ] +}}"; + var requestMessage = HttpRequestMessageBuilder.GetPrivateRequest(HttpMethod.Post, $"{Customer}/collections", + collection); + + // Act + var response = await httpClient.AsCustomer().SendAsync(requestMessage); + + var responseCollection = await response.ReadAsPresentationResponseAsync(); + + var id = responseCollection!.Id!.Split('/', StringSplitOptions.TrimEntries).Last(); + + var fromDatabase = dbContext.Collections.First(c => c.Id == id); + var hierarchyFromDatabase = dbContext.Hierarchy.First(h => h.CustomerId == 1 && h.CollectionId == id); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.Created); + fromDatabase.Id.Length.Should().BeGreaterThan(6); + hierarchyFromDatabase.Parent.Should().Be(parent); + fromDatabase.Label!.Values.First()[0].Should().Be("iiif post"); + hierarchyFromDatabase.Slug.Should().Be(slug); + hierarchyFromDatabase.ItemsOrder.Should().Be(1); + fromDatabase.Thumbnail.Should().Be("https://example.org/img/thumb.jpg"); + fromDatabase.IsPublic.Should().BeFalse(); + fromDatabase.IsStorageCollection.Should().BeFalse(); + fromDatabase.Modified.Should().Be(fromDatabase.Created); + responseCollection!.View!.PageSize.Should().Be(20); + responseCollection.View.Page.Should().Be(1); + responseCollection.View.Id.Should().Contain("?page=1&pageSize=20"); + responseCollection.PartOf.Single().Id.Should().Be("http://localhost/1/collections/root"); + responseCollection.PartOf.Single().Label["en"].Single().Should().Be("repository root"); + + var context = (JArray)responseCollection.Context; + context.First.Value().Should().Be("http://tbc.org/iiif-repository/1/context.json"); + context.Last.Value().Should().Be("http://iiif.io/api/presentation/3/context.json"); + + } [Fact] public async Task UpdateCollection_ReturnsUnauthorized_WhenCalledWithoutAuth() @@ -1671,6 +1733,55 @@ public async Task UpdateCollection_FailsToUpdateIiifCollection_WhenInvalidJson() response.StatusCode.Should().Be(HttpStatusCode.BadRequest); error.Detail.Should().Be("Could not deserialize collection"); } + + [Fact] + public async Task UpdateCollection_CreatesNonPublicIIIFCollection_WhenNoBehavior() + { + // Arrange + var updatedCollection = new PresentationCollection() + { + Label = new LanguageMap("en", ["test collection - create from update"]), + Slug = "create-from-update", + Parent = parent, + ItemsOrder = 1, + PresentationThumbnail = "some/location/2", + Tags = "some, tags, 2", + }; + + var updateRequestMessage = HttpRequestMessageBuilder.GetPrivateRequest(HttpMethod.Put, + $"{Customer}/collections/createFromUpdate", updatedCollection.AsJson()); + + // Act + var response = await httpClient.AsCustomer().SendAsync(updateRequestMessage); + + var responseCollection = await response.ReadAsPresentationResponseAsync(); + + var id = responseCollection!.Id!.Split('/', StringSplitOptions.TrimEntries).Last(); + + var fromDatabase = dbContext.Collections.First(c => c.Id == id); + var hierarchyFromDatabase = dbContext.Hierarchy.First(h => h.CustomerId == 1 && h.CollectionId == id); + + // Assert + response.StatusCode.Should().Be(HttpStatusCode.OK); + fromDatabase.Id.Should().Be("createFromUpdate"); + hierarchyFromDatabase.Parent.Should().Be(parent); + fromDatabase.Label!.Values.First()[0].Should().Be("test collection - create from update"); + hierarchyFromDatabase.Slug.Should().Be("create-from-update"); + hierarchyFromDatabase.ItemsOrder.Should().Be(1); + fromDatabase.Thumbnail.Should().Be("some/location/2"); + fromDatabase.Tags.Should().Be("some, tags, 2"); + fromDatabase.IsPublic.Should().BeFalse(); + fromDatabase.IsStorageCollection.Should().BeFalse(); + responseCollection!.View!.PageSize.Should().Be(20); + responseCollection.View.Page.Should().Be(1); + responseCollection.View.Id.Should().Contain("?page=1&pageSize=20"); + responseCollection.PartOf.Single().Id.Should().Be("http://localhost/1/collections/root"); + responseCollection.PartOf.Single().Label["en"].Single().Should().Be("repository root"); + + var context = (JArray)responseCollection.Context; + context.First.Value().Should().Be("http://tbc.org/iiif-repository/1/context.json"); + context.Last.Value().Should().Be("http://iiif.io/api/presentation/3/context.json"); + } [Fact] public async Task CreateCollection_CreatesMinimalCollection_ViaHierarchicalCollection() @@ -1927,7 +2038,7 @@ await amazonS3.GetObjectAsync(LocalStackFixture.StorageBucketName, s3Manifest.Id.Should().EndWith(fromDatabase.Id, "Stored Id is flat path"); (s3Manifest.Context as string).Should() .Be("http://iiif.io/api/presentation/3/context.json", "Context set automatically"); - } + } private void SetCorrectEtag(HttpRequestMessage requestMessage, Collection dbCollection) { diff --git a/src/IIIFPresentation/API/Features/Storage/Helpers/BehaviorX.cs b/src/IIIFPresentation/API/Features/Storage/Helpers/BehaviorX.cs index 054f4176..df97b4f3 100644 --- a/src/IIIFPresentation/API/Features/Storage/Helpers/BehaviorX.cs +++ b/src/IIIFPresentation/API/Features/Storage/Helpers/BehaviorX.cs @@ -4,13 +4,13 @@ namespace API.Features.Storage.Helpers; public static class BehaviorX { - public static bool IsPublic(this List behaviors) + public static bool IsPublic(this List? behaviors) { - return behaviors.Contains(Behavior.IsPublic); + return behaviors?.Contains(Behavior.IsPublic) ?? false; } - public static bool IsStorageCollection(this List behaviors) + public static bool IsStorageCollection(this List? behaviors) { - return behaviors.Contains(Behavior.IsStorageCollection); + return behaviors?.Contains(Behavior.IsStorageCollection) ?? false; } -} \ No newline at end of file +} From a7b5900c0fa092ec955205f1fa2d704706dd80d3 Mon Sep 17 00:00:00 2001 From: "jack.lewis" Date: Fri, 13 Dec 2024 14:03:07 +0000 Subject: [PATCH 2/5] fixing broken test --- .../API.Tests/Integration/ModifyCollectionTests.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/IIIFPresentation/API.Tests/Integration/ModifyCollectionTests.cs b/src/IIIFPresentation/API.Tests/Integration/ModifyCollectionTests.cs index 861d3f7a..3eba9e30 100644 --- a/src/IIIFPresentation/API.Tests/Integration/ModifyCollectionTests.cs +++ b/src/IIIFPresentation/API.Tests/Integration/ModifyCollectionTests.cs @@ -1737,11 +1737,14 @@ public async Task UpdateCollection_FailsToUpdateIiifCollection_WhenInvalidJson() [Fact] public async Task UpdateCollection_CreatesNonPublicIIIFCollection_WhenNoBehavior() { + var collectionId = "noBehavior"; + var slug = nameof(UpdateCollection_CreatesNonPublicIIIFCollection_WhenNoBehavior); + // Arrange var updatedCollection = new PresentationCollection() { Label = new LanguageMap("en", ["test collection - create from update"]), - Slug = "create-from-update", + Slug = slug, Parent = parent, ItemsOrder = 1, PresentationThumbnail = "some/location/2", @@ -1749,7 +1752,7 @@ public async Task UpdateCollection_CreatesNonPublicIIIFCollection_WhenNoBehavior }; var updateRequestMessage = HttpRequestMessageBuilder.GetPrivateRequest(HttpMethod.Put, - $"{Customer}/collections/createFromUpdate", updatedCollection.AsJson()); + $"{Customer}/collections/{collectionId}", updatedCollection.AsJson()); // Act var response = await httpClient.AsCustomer().SendAsync(updateRequestMessage); @@ -1763,10 +1766,10 @@ public async Task UpdateCollection_CreatesNonPublicIIIFCollection_WhenNoBehavior // Assert response.StatusCode.Should().Be(HttpStatusCode.OK); - fromDatabase.Id.Should().Be("createFromUpdate"); + fromDatabase.Id.Should().Be(collectionId); hierarchyFromDatabase.Parent.Should().Be(parent); fromDatabase.Label!.Values.First()[0].Should().Be("test collection - create from update"); - hierarchyFromDatabase.Slug.Should().Be("create-from-update"); + hierarchyFromDatabase.Slug.Should().Be(slug); hierarchyFromDatabase.ItemsOrder.Should().Be(1); fromDatabase.Thumbnail.Should().Be("some/location/2"); fromDatabase.Tags.Should().Be("some, tags, 2"); From a5546a80718b661e65bfd3aaea8d03fdbf7b908e Mon Sep 17 00:00:00 2001 From: "jack.lewis" Date: Mon, 16 Dec 2024 16:13:51 +0000 Subject: [PATCH 3/5] remove unnecessary spaces --- .../API.Tests/Integration/ModifyCollectionTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/IIIFPresentation/API.Tests/Integration/ModifyCollectionTests.cs b/src/IIIFPresentation/API.Tests/Integration/ModifyCollectionTests.cs index 3eba9e30..ece183d7 100644 --- a/src/IIIFPresentation/API.Tests/Integration/ModifyCollectionTests.cs +++ b/src/IIIFPresentation/API.Tests/Integration/ModifyCollectionTests.cs @@ -2041,7 +2041,7 @@ await amazonS3.GetObjectAsync(LocalStackFixture.StorageBucketName, s3Manifest.Id.Should().EndWith(fromDatabase.Id, "Stored Id is flat path"); (s3Manifest.Context as string).Should() .Be("http://iiif.io/api/presentation/3/context.json", "Context set automatically"); - } + } private void SetCorrectEtag(HttpRequestMessage requestMessage, Collection dbCollection) { From 14499fabf808b148e28d44d69260def08f309da4 Mon Sep 17 00:00:00 2001 From: "jack.lewis" Date: Thu, 9 Jan 2025 17:28:52 +0000 Subject: [PATCH 4/5] Adding BehaviourX tests --- .../Storage/Helpers/BehaviourXTests.cs | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 src/IIIFPresentation/API.Tests/Features/Storage/Helpers/BehaviourXTests.cs diff --git a/src/IIIFPresentation/API.Tests/Features/Storage/Helpers/BehaviourXTests.cs b/src/IIIFPresentation/API.Tests/Features/Storage/Helpers/BehaviourXTests.cs new file mode 100644 index 00000000..5cf1e9fd --- /dev/null +++ b/src/IIIFPresentation/API.Tests/Features/Storage/Helpers/BehaviourXTests.cs @@ -0,0 +1,42 @@ + +using API.Features.Storage.Helpers; +using Models.Infrastucture; + +namespace API.Tests.Features.Storage.Helpers; + +public class BehaviourXTests +{ + [Fact] + public void Behaviors_ShouldBeFalseWhenEmptyList() + { + // Arrange + var behaviors = new List(); + + behaviors.IsPublic().Should().BeFalse(); + behaviors.IsStorageCollection().Should().BeFalse(); + } + + [Fact] + public void Behaviors_ShouldBeTrueWhenExists() + { + // Arrange + var behaviors = new List() + { + Behavior.IsPublic, + Behavior.IsStorageCollection + }; + + behaviors.IsPublic().Should().BeTrue(); + behaviors.IsStorageCollection().Should().BeTrue(); + } + + [Fact] + public void Behaviors_ShouldBeFalseWhenNull() + { + // Arrange + List? behaviors = null; + + behaviors.IsPublic().Should().BeFalse(); + behaviors.IsStorageCollection().Should().BeFalse(); + } +} From 63171c9972bb1f0f611b0a54fc0e76e0771476cd Mon Sep 17 00:00:00 2001 From: "jack.lewis" Date: Fri, 10 Jan 2025 09:22:01 +0000 Subject: [PATCH 5/5] Update to change RequiresSpace to RequiresSpaceHeader --- .../API.Tests/Integration/ModifyManifestAssetCreationTests.cs | 2 +- .../API/Features/Storage/Helpers/ErrorHelper.cs | 2 +- src/IIIFPresentation/Models/API/General/ModifyCollectionType.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/IIIFPresentation/API.Tests/Integration/ModifyManifestAssetCreationTests.cs b/src/IIIFPresentation/API.Tests/Integration/ModifyManifestAssetCreationTests.cs index 9f7b51af..8fe9e6d1 100644 --- a/src/IIIFPresentation/API.Tests/Integration/ModifyManifestAssetCreationTests.cs +++ b/src/IIIFPresentation/API.Tests/Integration/ModifyManifestAssetCreationTests.cs @@ -93,7 +93,7 @@ public async Task CreateManifest_BadRequest_WhenNoSpaceHeader() response.StatusCode.Should().Be(HttpStatusCode.BadRequest); var error = await response.ReadAsPresentationResponseAsync(); error!.Detail.Should().Be("A request with assets requires the space header to be set"); - error.ErrorTypeUri.Should().Be("http://localhost/errors/ModifyCollectionType/RequiresSpace"); + error.ErrorTypeUri.Should().Be("http://localhost/errors/ModifyCollectionType/RequiresSpaceHeader"); } [Fact] diff --git a/src/IIIFPresentation/API/Features/Storage/Helpers/ErrorHelper.cs b/src/IIIFPresentation/API/Features/Storage/Helpers/ErrorHelper.cs index a80025cf..65becbf0 100644 --- a/src/IIIFPresentation/API/Features/Storage/Helpers/ErrorHelper.cs +++ b/src/IIIFPresentation/API/Features/Storage/Helpers/ErrorHelper.cs @@ -60,7 +60,7 @@ public static ModifyEntityResult ErrorCreatingSpace( public static ModifyEntityResult SpaceRequired() where T : class => ModifyEntityResult.Failure( - "A request with assets requires the space header to be set", ModifyCollectionType.RequiresSpace, + "A request with assets requires the space header to be set", ModifyCollectionType.RequiresSpaceHeader, WriteResult.BadRequest); public static ModifyEntityResult CouldNotRetrieveAssetId() diff --git a/src/IIIFPresentation/Models/API/General/ModifyCollectionType.cs b/src/IIIFPresentation/Models/API/General/ModifyCollectionType.cs index ffb1e6d0..bb791d13 100644 --- a/src/IIIFPresentation/Models/API/General/ModifyCollectionType.cs +++ b/src/IIIFPresentation/Models/API/General/ModifyCollectionType.cs @@ -13,7 +13,7 @@ public enum ModifyCollectionType ParentMustBeStorageCollection = 9, CannotChangeCollectionType = 10, ErrorCreatingSpace = 11, - RequiresSpace = 12, + RequiresSpaceHeader = 12, CouldNotRetrieveAssetId = 13, DlcsException = 14, ValidationFailed = 15,