Skip to content

Commit

Permalink
Merge pull request #702 from dlcs/feature/manifest_asset_customfields
Browse files Browse the repository at this point in the history
Include custom fields, tags, and roles in single item/named query manifests
  • Loading branch information
griffri authored Jan 11, 2024
2 parents d800361 + d94a7ca commit 3e584e7
Show file tree
Hide file tree
Showing 3 changed files with 121 additions and 6 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
Expand All @@ -8,6 +9,7 @@
using IIIF.ImageApi.V2;
using IIIF.ImageApi.V3;
using IIIF.Presentation.V3.Annotation;
using IIIF.Presentation.V3.Strings;
using IIIF.Serialisation;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json.Linq;
Expand Down Expand Up @@ -213,7 +215,86 @@ public async Task Get_ManifestForImage_ReturnsManifest_ByName()
response.Headers.CacheControl.Public.Should().BeTrue();
response.Headers.CacheControl.MaxAge.Should().BeGreaterThan(TimeSpan.FromSeconds(2));
}

[Fact]
public async Task Get_V3ManifestForImage_ReturnsManifest_WithCustomFields()
{
// Arrange
const string defaultLanguage = "none";
var id = AssetId.FromString($"99/1/{nameof(Get_V3ManifestForImage_ReturnsManifest_WithCustomFields)}");
var namedId = $"test/1/{nameof(Get_V3ManifestForImage_ReturnsManifest_WithCustomFields)}";
var asset = await dbFixture.DbContext.Images.AddTestAsset(id,
origin: "testorigin",
ref1: "string-example-1",
ref2: "string-example-2",
ref3: "string-example-3",
num1: 1,
num2: 2,
num3: 3);
await dbFixture.DbContext.SaveChangesAsync();

var path = $"iiif-manifest/{namedId}";

// Act
var response = await httpClient.GetAsync(path);

// Assert
var jsonResponse = JObject.Parse(await response.Content.ReadAsStringAsync());
var metadata = jsonResponse.SelectToken("items[0].metadata")
.ToObject<List<LabelValuePair>>()
.ToDictionary(
lvp => lvp.Label[defaultLanguage][0],
lvp => lvp.Value[defaultLanguage][0]);

response.StatusCode.Should().Be(HttpStatusCode.OK);
metadata.Should().NotBeNullOrEmpty();
metadata.Should().Contain("String 1", asset.Entity.Reference1);
metadata.Should().Contain("String 2", asset.Entity.Reference2);
metadata.Should().Contain("String 3", asset.Entity.Reference3);
metadata.Should().Contain("Number 1", asset.Entity.NumberReference1.ToString());
metadata.Should().Contain("Number 2", asset.Entity.NumberReference2.ToString());
metadata.Should().Contain("Number 3", asset.Entity.NumberReference3.ToString());
}

[Fact]
public async Task Get_V2ManifestForImage_ReturnsManifest_WithCustomFields()
{
// Arrange
var id = AssetId.FromString($"99/1/{nameof(Get_V2ManifestForImage_ReturnsManifest_WithCustomFields)}");
var namedId = $"test/1/{nameof(Get_V2ManifestForImage_ReturnsManifest_WithCustomFields)}";
var asset = await dbFixture.DbContext.Images.AddTestAsset(id,
origin: "testorigin",
ref1: "string-example-1",
ref2: "string-example-2",
ref3: "string-example-3",
num1: 1,
num2: 2,
num3: 3);
await dbFixture.DbContext.SaveChangesAsync();

var path = $"iiif-manifest/v2/{namedId}";

// Act
var response = await httpClient.GetAsync(path);

// Assert
var jsonResponse = JObject.Parse(await response.Content.ReadAsStringAsync());
var metadata = jsonResponse.SelectToken("sequences[0].canvases[0].metadata")
.ToObject<List<IIIF.Presentation.V2.Metadata>>()
.ToDictionary(
m => m.Label.LanguageValues[0].Value,
m => m.Value.LanguageValues[0].Value);

response.StatusCode.Should().Be(HttpStatusCode.OK);
metadata.Should().NotBeNullOrEmpty();
metadata.Should().Contain("String 1", asset.Entity.Reference1);
metadata.Should().Contain("String 2", asset.Entity.Reference2);
metadata.Should().Contain("String 3", asset.Entity.Reference3);
metadata.Should().Contain("Number 1", asset.Entity.NumberReference1.ToString());
metadata.Should().Contain("Number 2", asset.Entity.NumberReference2.ToString());
metadata.Should().Contain("Number 3", asset.Entity.NumberReference3.ToString());
}

[Fact]
public async Task Get_V2ManifestForRestrictedImage_ReturnsManifest_WithoutAuthServices()
{
Expand All @@ -231,11 +312,14 @@ await dbFixture.DbContext.Images.AddTestAsset(id, roles: "clickthrough", maxUnau
// Assert
var jsonContent = await response.Content.ReadAsStringAsync();
var jsonResponse = JObject.Parse(jsonContent);

jsonResponse["@id"].ToString().Should().Be($"http://localhost/iiif-manifest/v2/{id}");
jsonResponse.SelectToken("sequences[0].canvases[0].thumbnail.@id").Value<string>()
.Should().StartWith($"http://localhost/thumbs/{id}/full");

jsonContent.Should().NotContain("clickthrough", "auth services are not included in v2 manifests");
jsonResponse.SelectTokens("sequences[*].canvases[*].images[*].resource.service")
.Select(token => token.ToString())
.Should().NotContainMatch("*clickthrough*", "auth services are not included in v2 manifests");

response.StatusCode.Should().Be(HttpStatusCode.OK);
response.Headers.Should().ContainKey("x-asset-id").WhoseValue.Should().ContainSingle(id.ToString());
response.Headers.CacheControl.Public.Should().BeTrue();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -266,13 +266,16 @@ public async Task Get_AssetsRequireAuth_ReturnsV2ManifestWithoutAuthServices()

// Act
var response = await httpClient.GetAsync(path);
var test = response.Content.ReadAsStringAsync();

// Assert
response.StatusCode.Should().Be(HttpStatusCode.OK);

var jsonContent = await response.Content.ReadAsStringAsync();
var jsonResponse = JObject.Parse(jsonContent);
jsonContent.Should().NotContain("clickthrough", "auth services are not included in v2 manifests");
jsonResponse.SelectTokens("sequences[*].canvases[*].images[*].resource.service")
.Select(token => token.ToString())
.Should().NotContainMatch("*clickthrough*", "auth services are not included in v2 manifests");
jsonResponse.SelectToken("sequences[0].canvases").Count().Should().Be(3);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ public class IIIFCanvasFactory
private readonly IPolicyRepository policyRepository;
private readonly OrchestratorSettings orchestratorSettings;
private readonly Dictionary<string, ThumbnailPolicy> thumbnailPolicies = new();

private const string MetadataLanguage = "none";

public IIIFCanvasFactory(
IAssetPathGenerator assetPathGenerator,
IOptions<OrchestratorSettings> orchestratorSettings,
Expand Down Expand Up @@ -67,6 +68,11 @@ public IIIFCanvasFactory(
Label = new LanguageMap("en", $"Canvas {counter}"),
Width = i.Width,
Height = i.Height,
Metadata = GetImageMetadata(i)
.Select(m =>
new LabelValuePair(new LanguageMap(MetadataLanguage, m.Key),
new LanguageMap(MetadataLanguage, m.Value)))
.ToList(),
Items = new AnnotationPage
{
Id = $"{canvasId}/page",
Expand Down Expand Up @@ -124,6 +130,13 @@ public IIIFCanvasFactory(
Label = new MetaDataValue($"Canvas {counter}"),
Width = i.Width,
Height = i.Height,
Metadata = GetImageMetadata(i)
.Select(m => new IIIF2.Metadata()
{
Label = new MetaDataValue(m.Key),
Value = new MetaDataValue(m.Value)
})
.ToList(),
Images = new ImageAnnotation
{
Id = string.Concat(fullyQualifiedImageId, "/imageanno/0"),
Expand All @@ -135,7 +148,7 @@ public IIIFCanvasFactory(
Width = thumbnailSizes.MaxDerivativeSize.Width,
Height = thumbnailSizes.MaxDerivativeSize.Height,
Service = GetImageServices(i, customerPathElement, null)
}
},
}.AsList()
};

Expand Down Expand Up @@ -313,7 +326,22 @@ private List<IService> GetImageServices(Asset asset, CustomerPathElement custome
return authServiceToAdd.AsListOf<IService>();
}
}


private Dictionary<string, string> GetImageMetadata(Asset asset)
{
return new Dictionary<string, string>()
{
{ "String 1", asset.Reference1 ?? string.Empty },
{ "String 2", asset.Reference2 ?? string.Empty },
{ "String 3", asset.Reference3 ?? string.Empty },
{ "Number 1", (asset.NumberReference1 ?? 0).ToString() },
{ "Number 2", (asset.NumberReference2 ?? 0).ToString() },
{ "Number 3", (asset.NumberReference3 ?? 0).ToString() },
{ "Tags", asset.Tags ?? string.Empty },
{ "Roles", asset.Roles ?? string.Empty }
};
}

/// <summary>
/// Class containing details of available thumbnail sizes
/// </summary>
Expand Down

0 comments on commit 3e584e7

Please sign in to comment.