Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
4641d45
Bump actions/setup-java from 4 to 5
dependabot[bot] Aug 25, 2025
29459c0
Bump actions/setup-dotnet from 4 to 5
dependabot[bot] Sep 8, 2025
5b80305
Bump actions/cache from 4 to 5
dependabot[bot] Dec 15, 2025
5bf73c4
Add initial adjuncts work
JackLewis-digirati Dec 15, 2025
dffa749
Allow PUT to work
JackLewis-digirati Dec 16, 2025
97aff8c
Enable Delete + GetAll adjuncts to work
JackLewis-digirati Dec 17, 2025
4ffb27e
Final steps before review
JackLewis-digirati Dec 19, 2025
ff17be7
Add migration
JackLewis-digirati Dec 19, 2025
eba6cbb
remove unneeded $
JackLewis-digirati Dec 19, 2025
5c36138
Update appetiser compose
JackLewis-digirati Dec 19, 2025
05e1eb2
Add adjuncts link to asset
JackLewis-digirati Dec 19, 2025
dae4125
Modify properties
JackLewis-digirati Dec 19, 2025
1023d14
Remove paging
JackLewis-digirati Jan 5, 2026
0b71348
Code review fixes
JackLewis-digirati Jan 6, 2026
fac5866
Code review changes
JackLewis-digirati Jan 7, 2026
e981711
Tweak GetAllAdjuncts query
donaldgray Jan 7, 2026
1bfcc26
Merge pull request #1082 from dlcs/feature/externalAdjuncts
JackLewis-digirati Jan 9, 2026
ccb44b5
Allow migrations to be run in all envs
donaldgray Jan 12, 2026
893fb7e
Merge pull request #1083 from dlcs/feature/migrations
donaldgray Jan 15, 2026
cc9cdcf
Tighten up adjunct.id validation
donaldgray Jan 13, 2026
88c5aaf
Remove AssetId property from Adjunct Hydra model
donaldgray Jan 13, 2026
d54e5b5
Validate adjunct language length
donaldgray Jan 13, 2026
b94c0a8
Rename restricted character setting to remove
donaldgray Jan 14, 2026
6245146
Fix typo in invalid asset error message
donaldgray Jan 14, 2026
7f660ba
Validation rules for Adjunct id
donaldgray Jan 14, 2026
0c70a15
Prevent duplicate adjunct.ids that differ by case
donaldgray Jan 15, 2026
63c4dde
Add DbForeignKeyConstraintError
donaldgray Jan 15, 2026
ce1509b
PUT/POST adjuncts returns 404 if asset not found
donaldgray Jan 15, 2026
392f1b3
Adjunct saves "size" param if specified
donaldgray Jan 15, 2026
36a08e3
Tidy adjuncts store and Migrations post test
donaldgray Jan 15, 2026
811570d
Include AssetId in adjunct unique constraint
donaldgray Jan 15, 2026
66974be
Allow adjunct language up to 10 chars
donaldgray Jan 15, 2026
f663934
Don't use required in adjunct hydra model
donaldgray Jan 15, 2026
fab0cc9
Merge pull request #1086 from dlcs/bugfix/adjunct_missing_id
donaldgray Jan 16, 2026
58e49fe
Merge pull request #1081 from dlcs/dependabot/github_actions/actions/…
donaldgray Jan 16, 2026
a4ecd61
Merge pull request #1040 from dlcs/dependabot/github_actions/actions/…
donaldgray Jan 16, 2026
988158f
Merge pull request #1037 from dlcs/dependabot/github_actions/actions/…
donaldgray Jan 16, 2026
64439cb
Bump packages in github actions
donaldgray Jan 16, 2026
b0d9475
Merge pull request #1087 from dlcs/feature/update_actions
donaldgray Jan 16, 2026
abd4940
Allow adjunct @type to change
donaldgray Jan 16, 2026
258a962
Merge pull request #1088 from dlcs/bugfix/adjunct_type
donaldgray Jan 16, 2026
ed7c428
Include adjuncts in query for projections
donaldgray Jan 21, 2026
4c93801
Extend ManifestV3Builder to add adjuncts
donaldgray Jan 21, 2026
3ccd5bd
Merge pull request #1089 from dlcs/feature/output_external_adjunct
donaldgray Jan 23, 2026
9caf95c
ADR for maxWidth and openFullMax
donaldgray Jan 23, 2026
32ffc52
Update maxWidth openFullMax ADR
donaldgray Jan 23, 2026
bf51867
Expand maxWidth in ADR
donaldgray Jan 23, 2026
fce125d
Merge pull request #1090 from dlcs/feature/maxwidth_adr
donaldgray Jan 23, 2026
738edcf
Ensure adjunct ordering on Manifest
donaldgray Jan 26, 2026
94bc624
Merge pull request #1091 from dlcs/feature/adjunct_order_manifest
donaldgray Jan 26, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 4 additions & 7 deletions .github/actions/docker-build-and-push/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,11 @@ runs:
using: "composite"
steps:
- id: checkout
uses: actions/checkout@v2
uses: actions/checkout@v6
- id: docker-setup-buildx
uses: docker/setup-buildx-action@v2
with:
driver-opts: |
image=moby/buildkit:v0.10.6
uses: docker/setup-buildx-action@v3
- id: docker-meta
uses: docker/metadata-action@v3
uses: docker/metadata-action@v5
with:
images: ghcr.io/dlcs/${{ inputs.image-name }}
tags: |
Expand All @@ -37,7 +34,7 @@ runs:
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}
- id: docker-login
uses: docker/login-action@v1
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/run_build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ jobs:
SOLUTION: "protagonist.sln"
steps:
- id: checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- id: setup-dotnet
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v5
with:
dotnet-version: "8.0.x"
- id: restore-dotnet-dependencies
Expand Down Expand Up @@ -56,7 +56,7 @@ jobs:
- image: "migrator"
dockerfile: "Dockerfile.Migrator"
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v6
- uses: ./.github/actions/docker-build-and-push
with:
image-name: ${{ matrix.image }}
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/run_sonar.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,18 @@ jobs:
SOLUTION: "protagonist.sln"
steps:
- name: Set up JDK 17
uses: actions/setup-java@v4
uses: actions/setup-java@v5
with:
java-version: 17
distribution: 'zulu' # Alternative distribution options are available.
- id: checkout
uses: actions/checkout@v5
uses: actions/checkout@v6
- id: setup-dotnet
uses: actions/setup-dotnet@v4
uses: actions/setup-dotnet@v5
with:
dotnet-version: "8.0.x"
- name: Cache SonarCloud packages
uses: actions/cache@v4
uses: actions/cache@v5
with:
path: ~/sonar/cache
key: ${{ runner.os }}-sonar
Expand Down
2 changes: 1 addition & 1 deletion compose/.env.dist
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Thumbs__UpscaleThreshold=40

# Appetiser
# ------------------------------------------------------------------------------
KAKADU_APPS_LOCATION=s3://bucket/kakadu/kdu.tar.gz
KDU_BINARIES=s3://bucket/kakadu/kdu.tar.gz

# Special Server
# ------------------------------------------------------------------------------
Expand Down
4 changes: 1 addition & 3 deletions compose/docker-compose.local.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
version: '3'

volumes:
dlcs_postgres_data: {}
dlcs_postgres_data_backups: {}
Expand Down Expand Up @@ -50,7 +48,7 @@ services:
- .env

appetiser:
image: ghcr.io/dlcs/appetiser:pr-25 # TODO - temp use PR until release cut
image: ghcr.io/dlcs/appetiser:2.1.0
ports:
- "5031:8000"
volumes:
Expand Down
222 changes: 222 additions & 0 deletions docs/adr/0010-replace-maxunauthorised.md

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion docs/adr/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@
7. [Engine ImageServer](0006-engine-imageserver.md)
8. [In-house Image Server](0007-inhouse-image-server.md)
9. [ElasticTranscoder Replacement](0008-et-replacement.md)
10. [Engine Use Appetiser for Thumbs](0009-engine-appetiser-thumbs.md)
10. [Engine Use Appetiser for Thumbs](0009-engine-appetiser-thumbs.md)
11. [Replace `maxUnauthorised`](0010-replace-maxunauthorised.md)
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
using API.Features.Adjuncts.Validation;
using API.Settings;
using DLCS.HydraModel;
using FluentValidation.TestHelper;
using Microsoft.Extensions.Options;

namespace API.Tests.Features.Adjuncts.Validation;

public class HydraAdjunctValidatorTests
{
private readonly HydraAdjunctValidator sut = new(Options.Create(
new ApiSettings
{
RestrictedResourceIdCharacterString = "\\ /"
}));

[Fact]
public void Valid_WhenAllValidatorsUsed()
{
var adjunct = new Adjunct("https://localhost", 1, 1, "assetId", "adjunctId")
{
ExternalId = "https://localhost:2000/some-id",
MediaType = "mediaType",
IIIFLink = "seeAlso",
Type = "Image",
Language = ["fra", "en"]
};
var result = sut.TestValidate(adjunct);
result.ShouldNotHaveAnyValidationErrors();
}

[Fact]
public void ExternalId_NotValidUri()
{
var adjunct = new Adjunct("https://localhost", 1, 1, "assetId", "adjunctId")
{
ExternalId = "not-uri",
MediaType = "mediaType",
IIIFLink = "seeAlso",
Type = "Image"
};
var result = sut.TestValidate(adjunct);
result.ShouldHaveValidationErrorFor(r => r.ExternalId)
.WithErrorMessage("'externalId' is required and must be a well formed URI");
}

[Fact]
public void ExternalId_Null()
{
var adjunct = new Adjunct
{
ExternalId = null,
MediaType = "mediaType",
IIIFLink = "seeAlso",
Type = "Image"
};
var result = sut.TestValidate(adjunct);
result.ShouldHaveValidationErrorFor(r => r.ExternalId)
.WithErrorMessage("'externalId' is required and must be a well formed URI");
}

[Theory]
[InlineData("SeeAlso")]
[InlineData("Invalid")]
public void IIIFLink_NotValid(string iiifLink)
{
var adjunct = new Adjunct
{
MediaType = "mediaType",
IIIFLink = iiifLink,
Type = "Image",
ExternalId = "https://localhost/customers/1/spaces/1/images/assetId/valid"
};
var result = sut.TestValidate(adjunct);
result.ShouldHaveValidationErrorFor(r => r.IIIFLink)
.WithErrorMessage("Valid values for 'iiifLink' are 'seeAlso', 'annotations', 'rendering'");
}

[Fact]
public void IIIFLink_Null()
{
var adjunct = new Adjunct
{
MediaType = "mediaType",
Type = "Image",
ExternalId = "https://localhost/customers/1/spaces/1/images/assetId/valid"
};
var result = sut.TestValidate(adjunct);
result.ShouldHaveValidationErrorFor(r => r.IIIFLink)
.WithErrorMessage("'iiifLink' is required");
}

[Fact]
public void MediaType_Null()
{
var adjunct = new Adjunct
{
IIIFLink = "seeAlso",
Type = "Image",
ExternalId = "https://localhost/customers/1/spaces/1/images/assetId/valid"
};
var result = sut.TestValidate(adjunct);
result.ShouldHaveValidationErrorFor(r => r.MediaType)
.WithErrorMessage("'mediaType' is required");
}

[Fact]
public void ModelId_Null()
{
var adjunct = new Adjunct
{
MediaType = "mediaType",
IIIFLink = "seeAlso",
Type = "Image",
ExternalId = "https://localhost/customers/1/spaces/1/images/assetId/valid"
};
var result = sut.TestValidate(adjunct);
result.ShouldHaveValidationErrorFor(r => r.ModelId)
.WithErrorMessage("Adjunct identifier could not be found");
}

[Theory]
[InlineData(" space")]
[InlineData("slash\\")]
[InlineData("other/slash")]
public void ModelId_InvalidCharacters(string modelId)
{
var adjunct = new Adjunct
{
MediaType = "mediaType",
IIIFLink = "seeAlso",
Type = "Image",
ExternalId = "https://localhost/customers/1/spaces/1/images/assetId/valid",
ModelId = modelId
};
var result = sut.TestValidate(adjunct);
result.ShouldHaveValidationErrorFor(r => r.ModelId)
.WithErrorMessage("Adjunct id contains at least one of the following restricted characters. Invalid values are: \\ /");
}

[Fact]
public void ModelId_TooLong()
{
var adjunct = new Adjunct
{
MediaType = "mediaType",
IIIFLink = "seeAlso",
Type = "Image",
ExternalId = "https://localhost/customers/1/spaces/1/images/assetId/valid",
ModelId = new string('a', 201),
};
var result = sut.TestValidate(adjunct);
result.ShouldHaveValidationErrorFor(r => r.ModelId)
.WithErrorMessage("Adjunct id must be 200 characters or less");
}

[Fact]
public void Type_Error_WhenNotSet()
{
var adjunct = new Adjunct
{
MediaType = "mediaType",
IIIFLink = "seeAlso",
Type = null,
ExternalId = "https://localhost/customers/1/spaces/1/images/assetId"
};
var result = sut.TestValidate(adjunct);
result.ShouldHaveValidationErrorFor(r => r.Type)
.WithErrorMessage("'@type' is required");
}

[Fact]
public void Language_Error_TooLong()
{
var adjunct = new Adjunct
{
MediaType = "mediaType",
IIIFLink = "seeAlso",
Type = "AnnotationPage",
Language = ["en", "an overly long language string"],
ExternalId = "https://localhost/customers/1/spaces/1/images/assetId"
};
var result = sut.TestValidate(adjunct);
result.ShouldHaveValidationErrorFor(r => r.Language)
.WithErrorMessage("All 'language' values must be 10 characters or less. e.g. ISO language codes, sub-codes or 'none'");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ public void AssetRepository_FailsToSaveAsset_WhichHasRestrictedCharacters()

var result = AssetPreparer.PrepareAssetForUpsert(null, newAsset, false, false, new []{' '});
result.Success.Should().BeFalse();
result.ErrorMessage.Should().Be("Asset id contains at least one of the following restricted characters. Valid values are: ");
result.ErrorMessage.Should().Be("Asset id contains at least one of the following restricted characters. Invalid values are: ");
}

[Fact]
Expand Down
Loading
Loading