Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
723 commits
Select commit Hold shift + click to select a range
1a2087e
Implement dimensions and orientation operations from the same vips im…
tonytw1 May 17, 2025
5464c29
Put colour model and information operations behind a single interface.
tonytw1 May 17, 2025
59ab804
Put colour model and information operations behind a single interface.
tonytw1 May 17, 2025
533886d
Merge colour model and information operations into a single Vips imag…
tonytw1 May 17, 2025
83203c7
Put all dimensions, orientation and colour calls under a single method.
tonytw1 May 17, 2025
aa27189
Merge dimensions, orientation and colour calls under a single vips im…
tonytw1 May 17, 2025
f505722
Time getImageInformation.
tonytw1 May 18, 2025
4ea5d1d
thumbnail javadoc.
tonytw1 May 18, 2025
f0e349f
Remove unused imagemagik thumbnail.
tonytw1 May 18, 2025
3970c9d
Defer reading of file metadata until after we know we can read the im…
tonytw1 May 17, 2025
c3d7306
Time toFileMetadata.
tonytw1 May 18, 2025
18e9bd8
Refactor; move thumb dimensions call closed to thumb generation.
tonytw1 May 18, 2025
b789852
Log to show that we know the dimensions of created thumbnails.
tonytw1 May 18, 2025
5a21e66
generate thumb nail returns the thumbs dimensions to avoid an immedia…
tonytw1 May 18, 2025
4e9a6ef
Set vips no cache; helps with long running memory?
tonytw1 May 19, 2025
614c1f4
VipsHelper might be less leaky then VipsRaw?
tonytw1 May 19, 2025
1389cf9
Move cache = 0 to init.
tonytw1 May 20, 2025
b770e84
Log exceptions inside vips.run.
tonytw1 May 20, 2025
604a08e
[libvips] Refactor; thumb can reuse saveImageToFile for Jpegs writing…
tonytw1 Jan 19, 2026
806d7f2
Manually manage arena to ensure it's explicitly closed.
tonytw1 May 20, 2025
ffb40d0
Additional colour interreptations.
tonytw1 Jan 26, 2026
e381b1b
Correct CMYK renders too light in thumbnails.
tonytw1 May 25, 2025
a49a0b2
[libvips] save files by mimeType
tonytw1 May 24, 2025
c1cff16
[libvips] Palettise PNG saved files.
tonytw1 May 25, 2025
7033d29
[libvips] toOptimisedFile uses vips to transform from source to png.
tonytw1 Jan 12, 2026
d557fe5
[libvips] Refactor; do not pass the static OptimiseWithPngQuant aroun…
tonytw1 Jan 16, 2026
303ccf6
[libvips] OptimiseWithPngQuant is a class so it's imageOps dependency…
tonytw1 Jan 16, 2026
44d81ea
[libvips] save image has option to quantise PNG
tonytw1 May 25, 2025
8810c6e
[libvips] OptimiseWithPngQuant should quantise it's output.
tonytw1 Jan 16, 2026
6aad60c
[libvips] Log toOptimisedFile time.
tonytw1 Jan 17, 2026
8b31608
[libvips] Save image explicitly mentions default PNG compression.
tonytw1 Feb 11, 2026
04555d7
[libvips] png Q option is not needed if we are not actually quantisin…
tonytw1 Feb 12, 2026
b97fdae
[libvips] OptimizedOps needs to the same icc correction as cropping.
tonytw1 Feb 12, 2026
7d835ca
Clean up; recoverWith exception handling and arena.close in createThu…
tonytw1 Feb 15, 2026
6365699
[libvips] VIPS enabled image loader and cropper can probably use a sm…
tonytw1 Jun 29, 2025
954501e
[libvips] Test to exercise create thumbnail.
tonytw1 Jan 20, 2026
f09bdd1
[libvips] Test for correct thumbnail of png with alpha.
tonytw1 Feb 1, 2026
432055c
[libvips] Test for correct thumbnail of a tif with alpha.
tonytw1 Feb 1, 2026
65bb3a4
Additional thumbnail tests (LAB and LAB16)
tonytw1 Jan 31, 2026
6af8b90
Rebase ImageUploadTest
tonytw1 May 4, 2026
a39a7f7
Spike; create master crop file via vips.
tonytw1 May 21, 2025
32bb074
Naive resize crops to jpegs only step.
tonytw1 May 23, 2025
205e8be
createCrops and resizeImageVips in same Future and arena to allow sha…
tonytw1 May 23, 2025
7392406
Try to use 1 load of the source image across all resizes; do the resi…
tonytw1 May 23, 2025
4511af3
createCrops takes the masterCrop as a VImage rather than a file.
tonytw1 May 23, 2025
1db5e72
createMasterCrop moving to same arena.
tonytw1 May 23, 2025
bff8071
Remove colourModel check from createMasterCrop.
tonytw1 May 23, 2025
d0d6264
Logging. Show when we reload the master crop from disk.
tonytw1 May 23, 2025
1557124
Correct arena close timing.
tonytw1 May 23, 2025
ff51e93
createMasterCrop no Futures.
tonytw1 May 23, 2025
948e552
arena scope?
tonytw1 May 23, 2025
5d1f5a2
arena scope?
tonytw1 May 23, 2025
c436b49
arena scope?
tonytw1 May 23, 2025
a11a4f9
arena scope?
tonytw1 May 23, 2025
6980aeb
Spike; no reload of master crop image.
tonytw1 May 23, 2025
f0bfd46
Marking TODO; why local file for master crop.
tonytw1 May 24, 2025
0f26e3c
Log local resize file location.
tonytw1 May 24, 2025
86847b5
PNG specific optimiseImage steps can move straight into the resizeIma…
tonytw1 May 24, 2025
00b7a70
Logging.
tonytw1 May 24, 2025
fc6e2e2
TODO Strip true is needed to stop exif auto correction until we can s…
tonytw1 May 24, 2025
b32558b
Revert "Revert "Master image converted to sRBG colour space.""
tonytw1 May 24, 2025
e57f74f
Resize uses save file.
tonytw1 Feb 10, 2026
dee2f81
Log crop type decision.
tonytw1 May 24, 2025
b4fd794
Colour correct not effective if metadata stripped. Bake it in?
tonytw1 May 24, 2025
3c451d3
Refactor; master crop image file write pushes up out of the create ma…
tonytw1 May 24, 2025
c395164
createMasterCrop uses saveToFile and can now save PNGs.
tonytw1 Feb 10, 2026
10be4fa
Refactor. S3 store of master crop pushes up. MasterCrop is a simpler …
tonytw1 May 24, 2025
67c6c78
Refactor. File create for mastercrop pushes up to be next to the s3 s…
tonytw1 May 24, 2025
d367304
Master file create order; before arena close.
tonytw1 May 24, 2025
d7b6815
Comment; master crop if different from the the full dimensions crop; …
tonytw1 May 24, 2025
66646aa
Refactor; split creation of crop files from publishing to S3.
tonytw1 May 25, 2025
6d42cb7
quantise crops.
tonytw1 Feb 11, 2026
cf6ec4a
isGraphic was sendint all TIFFs to PNG.
tonytw1 May 25, 2025
1efdd1a
isGraphic was sendint all TIFFs to PNG.
tonytw1 May 25, 2025
e16da12
Correct CMYK renders too light in crops.
tonytw1 May 25, 2025
85dcac1
Unused parameters.
tonytw1 May 26, 2025
4b8d801
Unused parameters.
tonytw1 May 26, 2025
a5b937d
Bypass icc_transform for LAB images.
tonytw1 May 26, 2025
25128bc
Remove non used non vips functions.
tonytw1 Feb 28, 2026
5a4a31e
Remove non used runConvert command.
tonytw1 May 26, 2025
5da3885
Remove unused iccColourSpace val.
tonytw1 Jun 29, 2025
7a3204a
Reapply png master quality.
tonytw1 Jun 29, 2025
33eea38
Crop quality values can be int.
tonytw1 Jan 17, 2026
96e146c
CropType decision can be deferred until after the master crop has bee…
tonytw1 Nov 24, 2025
fb56f87
Refactor. Push the isGraphic? decision up out of cropType so that is …
tonytw1 Dec 29, 2025
9fd23cb
Spike. vips based implementation of isGraphic? is likely to involve t…
tonytw1 Dec 29, 2025
7db8431
Test to exercise ImageOperations resize.
tonytw1 Feb 18, 2026
48a6c72
[libvips] Testing around hasAlpha.
tonytw1 Feb 1, 2026
cf1dcf4
Clarify master crop quality values.
tonytw1 Jan 17, 2026
aa70afb
[libvips-cropping] Allow embedded icc profile to be used in crop icc …
tonytw1 Jan 19, 2026
b6d7d31
[libvips-cropping] Image operations resize takes the output file as a…
tonytw1 Jan 21, 2026
0e8c320
[libvips-cropping] Cropping of LAB fixed by making non icc_transform …
tonytw1 Jan 19, 2026
ccb4f1a
[libvips-cropping] Show that it is possible to manually trim metadata…
tonytw1 Feb 12, 2026
09d9311
[libvips-cropping] Bake the credit, copyright and supplier transmissi…
tonytw1 Jan 24, 2026
28f2478
XMP Credit -> photoshop:Credit
tonytw1 Feb 24, 2026
b10d376
XMP Byline -> creator.
tonytw1 Feb 24, 2026
0bb3fbc
[libvips-cropping] While manually stripping metadata might be useful,…
tonytw1 Feb 12, 2026
5ccabf0
[libvips-cropping] Additional resize tests.
tonytw1 Jan 31, 2026
7218627
[libvips-cropping] Test for correct resize of png with alpha.
tonytw1 Feb 16, 2026
b89b121
[libvips-cropping] Provide an example of the vips can't render a LAB …
tonytw1 Jan 31, 2026
40416f0
[libvips-cropping] Cleanup; Lower the input of apiSource to imageId f…
tonytw1 Jan 26, 2026
dfbcfcb
[libvips-cropping] resizeImageVips does not need the MasterCrop object
tonytw1 Mar 15, 2026
23f3edb
[libvips-cropping] Metadata for crop call.
tonytw1 Feb 1, 2026
83397ae
[libvips-cropping] Crop metadata in XMP via vips removes exiftool as …
tonytw1 Jan 24, 2026
e426395
[libvips-cropping] createCrops moves to image operations for testing.
tonytw1 Jan 26, 2026
6927318
[libvips-cropping] Tests to exercise crops.
tonytw1 Jan 31, 2026
0ca0f62
[libvips-cropping] createCrops can execute it's resizeImage calls in …
tonytw1 Mar 15, 2026
d2e2d11
[libvips-cropping] Master crop save in parallel.
tonytw1 Jan 26, 2026
12c8c7d
[libvips-cropping] Logging.
tonytw1 Jan 26, 2026
b871698
[libvips-cropping] Logging and imports.
tonytw1 Jan 26, 2026
e81ee6d
[libvips-cropping] Do not send resizes until master has successfully …
tonytw1 Jan 27, 2026
708e44a
[libvips-cropping] getImageInformation uses imageOperations.hasAlpha …
tonytw1 Feb 1, 2026
8a2f65e
[libvips-cropping] Missing arena.close()
tonytw1 Feb 24, 2026
0f298b7
[libvips-cropping] Crops uses master hasAlpha image operation rather …
tonytw1 Feb 1, 2026
d08c017
[libvips-cropping] Do not repeat calls to image_get_interpretation
tonytw1 Feb 24, 2026
4b2aeb1
Removes exiftool from base image.
tonytw1 Feb 20, 2026
294dfcf
Remove pnquant from base image.
tonytw1 Jan 13, 2026
9320649
Reindexing from S3. Thrall endpoint to trigger a projection of all S3…
tonytw1 Sep 23, 2024
adc8683
Reindex is bucket aware (what was it doing before?)
tonytw1 Dec 1, 2024
b7c52a9
Reindex process queues project image operations.
tonytw1 Mar 30, 2025
2ec31a3
Reindex should write projection results as UpsertFromProjectionMessag…
tonytw1 Mar 30, 2025
eab4baf
Reindex logging message.
tonytw1 Apr 18, 2025
8409f5b
Reindex messages are put into the low priority queue.
tonytw1 Apr 18, 2025
3d746a4
[reindexing] Form to request reindex of single image.
tonytw1 Mar 25, 2026
7fcb2ea
[reindexing] S3 reindexing logging.
tonytw1 Mar 25, 2026
29186ff
[reindexing] Reindex from CSV end point.
tonytw1 Mar 25, 2026
ad13f08
[reindexing] Prompt fort full reindex.
tonytw1 Mar 26, 2026
5109236
[reindexing] Combine.
tonytw1 Mar 26, 2026
d858f85
[reindexing] Send reindexMessages in batches for faster enqueuing.
tonytw1 Mar 26, 2026
6c22ca1
Queue reindex requests by most recently last modified first.
tonytw1 Mar 26, 2026
b131dd0
Reindex kinesis stream runs separately with it's own concurrency.
tonytw1 Mar 27, 2026
a1c2753
CSV reindex is batched and put onto the low priority queue.
tonytw1 Apr 22, 2026
058face
reindexMessage processing needs to throw to be retried.
tonytw1 Apr 23, 2026
3bf6f9f
Spike; simpler SyndicationFilter
tonytw1 Sep 18, 2025
9706417
Add syndicationStatus as a filter in the q parameter so that it can b…
tonytw1 Sep 19, 2025
7412300
Filter test.
tonytw1 Sep 19, 2025
1a06c08
Queued for syndication must be syndicatableCategory / owned not just …
tonytw1 Oct 5, 2025
7796a55
Image.syndicationStatus aligns with syndicationFilter on not needing …
tonytw1 Oct 11, 2025
9cbfe02
Image.syndicationStatus aligns with syndicationFilter on defination o…
tonytw1 Oct 12, 2025
14f6f09
Update ImageTest syndication tests to match isOwned syndication right…
tonytw1 Dec 30, 2025
ee68fa2
Update ElasticSearchTest syndication tests to match isOwned syndicati…
tonytw1 Dec 30, 2025
b708ef5
syndicationStatus query suggestion in UI.
tonytw1 Feb 5, 2026
d12d621
Update test; we do not syndicate replaced images.
tonytw1 May 2, 2026
527e718
Get getCssColour supports sub folder colours overriding parent colour…
tonytw1 Aug 2, 2025
8e350dc
Extract collection paths for reuse in CssColours.
tonytw1 Aug 2, 2025
3980fc7
Recent print usages highlight only counts recent published usages.
tonytw1 Jun 21, 2025
6131316
Refactor; image screen usage panel considers whole usage when making …
tonytw1 Jun 21, 2025
2a6defc
Image screen usage panel does not highlight non published print uses …
tonytw1 Jun 21, 2025
fedf4a2
Update Observer collection colours.
tonytw1 Jun 22, 2025
0360251
Fork Tortoise usage rights with minimal config.
tonytw1 Feb 13, 2025
53f225d
Add GNM as an agency.
tonytw1 Feb 13, 2025
0ffcedf
Set Tortoise contact photographers.
tonytw1 Apr 10, 2025
d17ed00
Chris Riddell is an Observer contacted illustrator.
tonytw1 Jun 22, 2025
b0f8d38
Remove Dave Benett Collection from list of explicity pay to use Getty…
tonytw1 Feb 25, 2026
811d22f
v2 sigs do not work for buckets created after June 2024.
tonytw1 Sep 23, 2025
5e3803c
migrationStatusRefresher interval.
tonytw1 Sep 24, 2025
b8be738
Thrall "/thrall" prefix via explicit Routes.withPrefix because play.h…
tonytw1 Nov 16, 2025
6098c9a
No +nocsrf on thrall UI routes.
tonytw1 Nov 16, 2025
bfc373a
Usages updates should go on the main kinesis stream so that they are …
tonytw1 Nov 16, 2025
983a9ac
Revert "remove preview view"
tonytw1 Nov 26, 2025
1bfa754
Fixes stickiness when paging through preview images.
tonytw1 Nov 26, 2025
769c00f
Immutable placeholders look out of place; change to allow ids to upda…
tonytw1 Nov 27, 2025
8f5074c
Fixes inSelectionMode not been past to ui-preview-image-large. Fixes …
tonytw1 Nov 27, 2025
8f28d64
Allow more than 1 item to be selected from preview mode. Allow range …
tonytw1 Nov 29, 2025
3559695
Always show reapable filter.
tonytw1 Feb 5, 2026
68f2108
Media API offers an end point for downloading the master crop.
tonytw1 Feb 20, 2026
59079d4
Kahana picks up master asset for download.
tonytw1 Feb 20, 2026
88e1ace
Digital usage webTitle and sectionId are optional.
tonytw1 Feb 21, 2026
be78886
Enable iPhone HEIC support.
tonytw1 May 26, 2025
27ab5de
Kahuna only build for faster UI dev.
tonytw1 Mar 1, 2026
393b3da
Explicit human-readable crop display names.
tonytw1 Jan 11, 2025
f7fff63
Register 3:2 as a known aspect ratio so that in can be cleaned with t…
tonytw1 Dec 7, 2024
234f14b
Register 3:2 as a crop option.
tonytw1 Dec 7, 2024
36ae45f
Observer wants 5:3 crop options.
tonytw1 Mar 1, 2026
b01111d
Crops download as the original filename falling back to Grid image id…
tonytw1 Mar 8, 2026
8ae4d75
Disable reaping of S3 vectors.
tonytw1 Mar 22, 2026
ff5608a
Set start dates for publication photographers to 22 April 2025 for r…
tonytw1 Mar 25, 2026
eefbadc
Logging. Projected logs the media-id not the whole response.
tonytw1 Mar 26, 2026
39b2157
Lower concurrency on reindex.
tonytw1 Apr 22, 2026
c0b143f
Log ignored reindex ids.
tonytw1 Apr 23, 2026
d44d629
Fix off by 1 in message processing attempts log output.
tonytw1 Apr 23, 2026
73965b7
refactor; continueScrolling rename to be general.
tonytw1 Apr 25, 2026
e64c235
refactor; continueScrolling and closeScroll move to ElasticSearchClie…
tonytw1 Apr 25, 2026
1f5b558
End point to output all currently held document ids to a tmp file.
tonytw1 Apr 25, 2026
931257c
Clarifying rename; this parameter is the number of retries after the …
tonytw1 Apr 28, 2026
57d2197
Fixes 4775
tonytw1 May 4, 2026
ed35d6d
Remove duplicate toFileMetadata which only populates log markers.
tonytw1 May 9, 2026
20128a8
Build vips-8.18.3 base image.
tonytw1 Jun 12, 2026
eb0b956
Use vips 8.18.3 base image.
tonytw1 Jun 12, 2026
4e549be
[multi-tenant] EmbedderMessage is instance aware.
tonytw1 Jun 26, 2026
31cb3ce
Port Bedrock create image embedding back from lambda.
tonytw1 Jul 3, 2026
301f59f
[generalise-embedding-impl] Extract common embedding implementation i…
tonytw1 Jun 28, 2026
bf34635
createImageEmbedding is available on Embedder interface.
tonytw1 Jun 14, 2026
89eb6f7
[generalise-embedding-impl] Embedder takes a general EmbeddingImpleme…
tonytw1 Jun 28, 2026
24e8006
[generalise-embedding-impl] EmbeddingImplementation interface adds em…
tonytw1 Jun 28, 2026
bdd85a2
[embedding-source] ImageOperations.createEmbeddingSource to normalise…
tonytw1 May 9, 2026
9b8cfc9
[embedding-source] Explicitly strip metadata so that we be sure that …
tonytw1 Jun 28, 2026
8675c7d
[embedding-source] Support optional letter boxing the embedding sourc…
tonytw1 May 20, 2026
47452e8
[send-embedder-sqs-message] Introduce the embedding source S3 bucket …
tonytw1 Jun 28, 2026
6d80b5d
[thrall-embedding] Placeholder for SQS embed required message consume…
tonytw1 Jun 20, 2026
a8a9f54
[thrall-embedding] Parse EmbedderMessage
tonytw1 Jul 4, 2026
b557216
[thrall-embedding] EmbeddingSqsConsumer gets store and embedder
tonytw1 Jul 4, 2026
e697ca8
[thrall-embedding] Picking up the embed source file from S3 in thrall.
tonytw1 Jun 25, 2026
c57befd
[thrall-embedding] Make create embedding call and produce an Embedding.
tonytw1 Jun 25, 2026
08f26d1
[thrall-embedding] Send update embed message.
tonytw1 Jul 4, 2026
3924bcc
[generalise-embedding-impl] EmbeddingImplementation returns an Embedd…
tonytw1 Jul 4, 2026
796c779
[mapping] Provide a geminiEmbedding2 field on Embedding.
tonytw1 May 11, 2026
c7241c3
[gemini-embedding] Initial Gemini Embedding 2 client.
tonytw1 May 26, 2026
d549a03
[gemini-embedding] Implement text query to vector
tonytw1 May 10, 2026
ac3f885
[gemini-embedding] Use task type on query embedding.
tonytw1 May 13, 2026
a20c48f
[gemini-embedding] Revert; worked better without?
tonytw1 May 16, 2026
96c55a8
[gemini-embedding] Embedding for uploaded image contains title and de…
tonytw1 Jun 28, 2026
ca7fdde
[gemini-embedding] Refactor; setup for config.
tonytw1 Jun 20, 2026
005a811
[gemini-embedding] provides embeddingSourceImageFormat.
tonytw1 Jun 28, 2026
828a533
[gemini-embeddings] extends embedding implementation interface.
tonytw1 Jun 28, 2026
863bb6f
[indexing] Provide a geminiEmbedding2 mapping with Google's recommend…
tonytw1 Jun 13, 2026
97ae215
[gemini-embedding]; define googleCloudEmbedding component to replace …
tonytw1 Jun 20, 2026
ff7bf08
[query] knnSearch mapping field to use is a constant.
tonytw1 Jun 13, 2026
41d78bd
[query] Use geminiEmbedding2 Elastic mapping
tonytw1 May 11, 2026
7e9ebc1
[query] Switch knn search field to embeddin.geminiEmbedding2.image.
tonytw1 Jun 13, 2026
98e92d4
Effect of similarity filter.
tonytw1 Jul 5, 2026
0c45199
Setting up to use similar too as boolean clause of normal search.
tonytw1 Jul 5, 2026
0f94570
Pass maybeSimilarToVector down to normal search.
tonytw1 May 16, 2026
14ba525
knn is constrained to the withFilter query. knn should look like a mu…
tonytw1 May 16, 2026
8cad706
searchRequest is a normal query or a knn with the query as it's filter.
tonytw1 May 17, 2026
4629635
Ignore similar when building Elastic query from structuredQuery. simi…
tonytw1 May 17, 2026
cb7d918
Happy with numCandiates to be 2 * k given we have a constraint on sim…
tonytw1 Jun 14, 2026
b0ea859
Bigger cast?
tonytw1 May 17, 2026
1225da7
[ui] More List This link is conditional on this image having an embed…
tonytw1 May 18, 2026
9d5a38c
[ui] Clicking More Like This does not need to set the Use AI Search t…
tonytw1 May 18, 2026
63db958
Knn search is optionally bounded on similarity.
tonytw1 May 22, 2026
e86e2c9
Test
tonytw1 May 26, 2026
76efc59
tests compile.
tonytw1 May 26, 2026
79f803c
Test compile
tonytw1 Jun 14, 2026
65de290
Clip similarity on knnSearch.
tonytw1 Jun 13, 2026
e604155
Debug
tonytw1 Jun 13, 2026
7bc684c
Clip similarity on Guardian's makeHybridSearchRequest.
tonytw1 Jun 13, 2026
75b82bc
Given a similarity constraint then results.totalHits and even scrolli…
tonytw1 Jun 13, 2026
d123031
Debug
tonytw1 Jun 13, 2026
52bef3e
Logging.
tonytw1 Jun 13, 2026
6a49495
Tuning text search similarity.
tonytw1 Jun 14, 2026
787c22e
Tone down createMultiMatchQuery overmatching.
tonytw1 Jun 14, 2026
fc99e72
Spike - want the other 1/2 of a hybird search to be the 'normal' keyw…
tonytw1 Jun 14, 2026
0cddc0a
Spike - want the other 1/2 of a hybird search to be the 'normal' keyw…
tonytw1 Jun 14, 2026
7c78d7a
Spike - want the other 1/2 of a hybird search to be the 'normal' keyw…
tonytw1 Jun 14, 2026
494db00
Spike - want the other 1/2 of a hybird search to be the 'normal' keyw…
tonytw1 Jun 14, 2026
1d47704
Spike - want the other 1/2 of a hybird search to be the 'normal' keyw…
tonytw1 Jun 14, 2026
223773d
minimumShouldMatch to only bring in matches!
tonytw1 Jun 14, 2026
3a42550
Use normal query for maxScore.
tonytw1 Jun 15, 2026
16ace60
createMultiMatchQuery unused.
tonytw1 Jun 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ jobs:
npm test
- name: Image Embedder bundling
run: ./scripts/embedder-deploy/build.sh
- uses: guardian/actions-riff-raff@v4.2.4
- uses: guardian/actions-riff-raff@v4.3.3
if: "! github.event.pull_request.head.repo.fork"
with:
githubToken: ${{ secrets.GITHUB_TOKEN }}
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/sbt-dependency-graph.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
java-version: 17
- name: Install sbt
id: sbt
uses: sbt/setup-sbt@3e125ece5c3e5248e18da9ed8d2cce3d335ec8dd # v1.1.14
uses: sbt/setup-sbt@4ed7b7ec4bfa2074fe48554c09e341267397247c # v1.2.0
- name: Submit dependencies
id: submit
uses: scalacenter/sbt-dependency-submission@f43202114d7522a4b233e052f82c2eea8d658134 # v3.2.1
Expand Down
5 changes: 2 additions & 3 deletions auth/app/auth/AuthComponents.scala
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package auth

import com.gu.mediaservice.lib.management.{InnerServiceStatusCheckController, Management}
import com.gu.mediaservice.lib.management.Management
import com.gu.mediaservice.lib.play.GridComponents
import play.api.ApplicationLoader.Context
import play.api.{Configuration, Environment}
Expand All @@ -14,10 +14,9 @@ class AuthComponents(context: Context) extends GridComponents(context, new AuthC

val controller = new AuthController(auth, providers, config, controllerComponents, authorisation)
val permissionsAwareManagement = new Management(controllerComponents, buildInfo)
val InnerServiceStatusCheckController = new InnerServiceStatusCheckController(auth, controllerComponents, config.services, wsClient)


override val router = new Routes(httpErrorHandler, controller, permissionsAwareManagement, InnerServiceStatusCheckController)
override val router = new Routes(httpErrorHandler, controller, permissionsAwareManagement)
}

object AuthHttpConfig {
Expand Down
6 changes: 4 additions & 2 deletions auth/app/auth/AuthConfig.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package auth

import com.gu.mediaservice.lib.config.{CommonConfig, GridConfigResources}
import com.gu.mediaservice.model.Instance

class AuthConfig(resources: GridConfigResources) extends CommonConfig(resources) {
val rootUri: String = services.authBaseUri
val mediaApiUri: String = services.apiBaseUri
val rootUri: Instance => String = services.authBaseUri
val rootInstanceUri: Instance => String = services.authBaseInstanceUri
val mediaApiUri: Instance => String = services.apiBaseUri
}
32 changes: 20 additions & 12 deletions auth/app/auth/AuthController.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,43 +6,51 @@ import com.gu.mediaservice.lib.auth.Authentication.{InnerServicePrincipal, Machi
import com.gu.mediaservice.lib.auth.Permissions.{DeleteImage, ShowPaid, UploadImages}
import com.gu.mediaservice.lib.auth.provider.AuthenticationProviders
import com.gu.mediaservice.lib.auth.{Authentication, Authorisation, Internal}
import com.gu.mediaservice.lib.config.InstanceForRequest
import com.gu.mediaservice.lib.guardian.auth.PandaAuthenticationProvider
import com.gu.mediaservice.model.Instance
import play.api.libs.json.Json
import play.api.mvc.{BaseController, ControllerComponents, Result}
import play.api.mvc.{AnyContent, BaseController, ControllerComponents, Request, Result}

import java.net.URI
import java.util.Date
import java.time.Instant
import scala.concurrent.{ExecutionContext, Future}
import scala.util.Try

class AuthController(auth: Authentication, providers: AuthenticationProviders, val config: AuthConfig,
override val controllerComponents: ControllerComponents,
authorisation: Authorisation)(implicit ec: ExecutionContext)
extends BaseController
with ArgoHelpers {
with ArgoHelpers with InstanceForRequest {

val indexResponse = {
def indexResponse()(implicit instance: Instance) = {
val indexData = Map("description" -> "This is the Auth API")
val indexLinks = List(
Link("root", config.mediaApiUri),
Link("login", config.services.loginUriTemplate),
Link("ui:logout", s"${config.rootUri}/logout"),
Link("session", s"${config.rootUri}/session")
Link("root", config.mediaApiUri(instance)),
Link("login", config.services.loginUriTemplate(instance)),
Link("ui:logout", s"${config.rootUri(instance)}/logout"),
Link("session", s"${config.rootInstanceUri(instance)}/session")
)
respond(indexData, indexLinks)
}

def cookieMonster = auth { request =>
providers.userProvider match {
case panda: PandaAuthenticationProvider =>{
val cookieBatter = panda.readAuthenticatedUser(request).map(user => panda.generateCookie(user.copy(expires = new Date().getTime)))
case panda: PandaAuthenticationProvider =>
val cookieBatter = panda.readAuthenticatedUser(request)
// Note the cookie monster does not expire the cookie itself, but instead expires the panda token stored
// by the cookie. The cookie will remain in the browser storage, but if decoded will declare that it expired
// at the epoch in 1970.
.map(user => panda.generateCookie(user.copy(expires = Instant.ofEpochMilli(0L))))
cookieBatter.fold(respond("Me want cookie."))(cookie => respond("Cookies are a sometimes food.").withCookies(cookie))
}
case _ => respond("Me want cookie.")
}
}

def index = auth { indexResponse }
def index = auth { request =>
implicit val instance: Instance = instanceOf(request)
indexResponse()
}

def session = auth { request =>
val showPaid = authorisation.hasPermissionTo(ShowPaid)(request.user)
Expand Down
1 change: 0 additions & 1 deletion auth/conf/routes
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ GET /cookieMonster auth.AuthController.cookieMonster
# Management
GET /management/healthcheck com.gu.mediaservice.lib.management.Management.healthCheck
GET /management/manifest com.gu.mediaservice.lib.management.Management.manifest
GET /management/whoAmI com.gu.mediaservice.lib.management.InnerServiceStatusCheckController.whoAmI(depth: Int)

# Shoo robots away
GET /robots.txt com.gu.mediaservice.lib.management.Management.disallowRobots
122 changes: 68 additions & 54 deletions build.sbt
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import play.sbt.PlayImport.PlayKeys._
import com.typesafe.sbt.packager.docker.*
import play.sbt.PlayImport.PlayKeys.*
import sbt.Package.FixedTimestamp

import scala.sys.process._
import scala.collection.JavaConverters.*
import scala.sys.process.*
import scala.util.control.NonFatal
import scala.collection.JavaConverters._

import com.typesafe.sbt.packager.debian.JDebPackaging

// We need to keep the timestamps to allow caching headers to work as expected on assets.
// The below should work, but some problem in one of the plugins (possible the play plugin? or sbt-web?) causes
Expand Down Expand Up @@ -53,6 +52,7 @@ val commonSettings = Seq(
"org.scalatestplus" %% "mockito-3-4" % "3.1.4.0" % Test,
"org.mockito" % "mockito-core" % "2.18.0" % Test,
"org.scalamock" %% "scalamock" % "5.1.0" % Test,
"org.testcontainers" % "localstack" % "1.21.4" % Test
),
dependencyOverrides ++= jacksonOverrides,

Expand All @@ -76,9 +76,10 @@ Global / concurrentRestrictions := Seq(
Tags.limitAll(12)
)

val awsSdkVersion = "1.12.470"
val awsSdkV2Version = "2.42.25"
val elastic4sVersion = "8.18.2"
val awsSdkVersion = "1.12.797"
val awsSdkV2Version = "2.44.13"
val elastic4sVersion = "8.19.1"
val awsKclVersion = "3.4.3"
val okHttpVersion = "3.12.1"

val bbcBuildProcess: Boolean = System.getenv().asScala.get("BUILD_ORG").contains("bbc")
Expand All @@ -90,22 +91,25 @@ val maybeBBCLib: Option[sbt.ProjectReference] = if(bbcBuildProcess) Some(bbcProj

lazy val commonLib = project("common-lib").settings(
libraryDependencies ++= Seq(
"com.google.guava" % "guava" % "33.5.0-jre",
"com.gu" %% "editorial-permissions-client" % "4.0.0",
"com.gu" %% "pan-domain-auth-play_3-0" % "9.0.0",
"com.gu" %% "pan-domain-auth-play_3-0" % "19.0.0",
"com.amazonaws" % "aws-java-sdk-iam" % awsSdkVersion,
"com.amazonaws" % "aws-java-sdk-s3" % awsSdkVersion,
"com.amazonaws" % "aws-java-sdk-ec2" % awsSdkVersion,
"com.amazonaws" % "aws-java-sdk-sqs" % awsSdkVersion,
"software.amazon.awssdk" % "sqs" % awsSdkV2Version,
"com.amazonaws" % "aws-java-sdk-sns" % awsSdkVersion,
"com.amazonaws" % "aws-java-sdk-sts" % awsSdkVersion,
"com.amazonaws" % "aws-java-sdk-dynamodb" % awsSdkVersion,
"com.amazonaws" % "aws-java-sdk-kinesis" % awsSdkVersion,
"software.amazon.awssdk" % "s3" % awsSdkV2Version,
"nl.gn0s1s" %% "elastic4s-core" % elastic4sVersion,
"nl.gn0s1s" %% "elastic4s-client-esjava" % elastic4sVersion,
"nl.gn0s1s" %% "elastic4s-domain" % elastic4sVersion,
"com.gu" %% "thrift-serializer" % "5.0.2",
"org.scalaz" %% "scalaz-core" % "7.3.8",
"org.im4java" % "im4java" % "1.4.0",
"app.photofox.vips-ffm" % "vips-ffm-core" % "1.9.6",
"com.gu" % "kinesis-logback-appender" % "1.4.4",
"net.logstash.logback" % "logstash-logback-encoder" % "5.0",
logback, // play-logback; needed when running the scripts
Expand All @@ -124,8 +128,10 @@ lazy val commonLib = project("common-lib").settings(
// declare explicit dependency on desired version of aws sdk v2 bedrock runtime
"software.amazon.awssdk" % "bedrockruntime" % awsSdkV2Version,
"software.amazon.awssdk" % "s3vectors" % awsSdkV2Version,
"com.adobe.xmp" % "xmpcore" % "6.1.11",
ws,
"org.testcontainers" % "elasticsearch" % "1.21.4" % Test
"com.google.genai" % "google-genai" % "1.53.0" exclude("com.fasterxml.jackson.module", "jackson-module-kotlin"),
"org.testcontainers" % "testcontainers-elasticsearch" % "2.0.2" % Test,
),
dependencyOverrides += "ch.qos.logback" % "logback-classic" % "1.2.13" % Test
)
Expand All @@ -142,9 +148,9 @@ lazy val auth = playProject("auth", 9011)

lazy val collections = playProject("collections", 9010)

lazy val cropper = playProject("cropper", 9006)
lazy val cropper = playImageLoaderProject("cropper", 9006)

lazy val imageLoader = playProject("image-loader", 9003).settings {
lazy val imageLoader = playImageLoaderProject("image-loader", 9003).settings {
libraryDependencies ++= Seq(
"org.apache.tika" % "tika-core" % "3.2.3",
"com.drewnoakes" % "metadata-extractor" % "2.19.0"
Expand Down Expand Up @@ -176,39 +182,33 @@ lazy val thrall = playProject("thrall", 9002)
pipelineStages := Seq(digest, gzip),
libraryDependencies ++= Seq(
"org.codehaus.groovy" % "groovy-json" % "3.0.7",
// TODO upgrading kcl to v3? check if you can remove avro override below
"software.amazon.kinesis" % "amazon-kinesis-client" % "2.6.1",
"software.amazon.kinesis" % "amazon-kinesis-client" % awsKclVersion,
// explicit dependencies on kinesis and dynamodb to upgrade the versions used by kcl
"software.amazon.awssdk" % "kinesis" % awsSdkV2Version,
"software.amazon.awssdk" % "dynamodb" % awsSdkV2Version,
"com.gu" %% "kcl-pekko-stream" % "0.1.0",
"org.testcontainers" % "elasticsearch" % "1.19.2" % Test,
"com.google.protobuf" % "protobuf-java" % "3.19.6"
"com.gu" %% "kcl-pekko-stream" % "0.1.2",
"org.testcontainers" % "testcontainers-elasticsearch" % "2.0.2" % Test,
"com.google.protobuf" % "protobuf-java" % "3.19.6",
"software.amazon.awssdk" % "sqs" % awsSdkV2Version,
"org.apache.pekko" %% "pekko-connectors-sqs" % "1.0.2"
),
// amazon-kinesis-client 2.6.0 brings in a critically vulnerable version of apache avro,
// but we cannot upgrade amazon-kinesis-client further without performing the v2->v3 upgrade https://docs.aws.amazon.com/streams/latest/dev/kcl-migration-from-2-3.html
dependencyOverrides ++= Seq(
"org.apache.avro" % "avro" % "1.11.4",
"org.apache.pekko" %% "pekko-stream" % "1.0.3"
"org.apache.pekko" %% "pekko-stream" % "1.0.3",
"org.apache.pekko" %% "pekko-http" % "1.0.1",
"org.apache.pekko" %% "pekko-http-core" % "1.0.1",
"org.apache.pekko" %% "pekko-parsing" % "1.0.1"
)
)

lazy val usage = playProject("usage", 9009).settings(
libraryDependencies ++= Seq(
"com.gu" %% "content-api-client-default" % "32.0.0",
"com.gu" %% "content-api-client-aws" % "0.7.6",
"io.reactivex" %% "rxscala" % "0.27.0",
// amazon-kinesis-client brings in a critical vulnerability warning through apache avro, resolved in versions 1.11.4 and 1.12.0.
// updating amazon-kinesis-client? check if the override below can be removed
"software.amazon.kinesis" % "amazon-kinesis-client" % "3.0.2",
"software.amazon.kinesis" % "amazon-kinesis-client" % awsKclVersion,
// explicit dependencies on kinesis and dynamodb to upgrade the versions used by kcl
"software.amazon.awssdk" % "kinesis" % awsSdkV2Version,
"software.amazon.awssdk" % "dynamodb" % awsSdkV2Version,
"com.google.protobuf" % "protobuf-java" % "3.19.6"
),
dependencyOverrides ++= Seq(
"org.apache.avro" % "avro" % "1.11.4",
)
)

lazy val scripts = project("scripts")
Expand Down Expand Up @@ -251,39 +251,53 @@ val buildInfo = Seq(
)

def playProject(projectName: String, port: Int, path: Option[String] = None): Project = {
val commonProject = project(projectName, path)
.enablePlugins(PlayScala, JDebPackaging, SystemdPlugin, BuildInfoPlugin)
project(projectName, path)
.enablePlugins(PlayScala, BuildInfoPlugin, DockerPlugin)
.dependsOn(restLib)
.settings(commonSettings ++ buildInfo ++ Seq(
dockerBaseImage := "eclipse-temurin:25",
dockerExposedPorts := Seq(port),
playDefaultPort := port,
debianPackageDependencies := Seq("java11-runtime-headless"),
Linux / maintainer := "Guardian Developers <dig.dev.software@theguardian.com>",
Linux / packageSummary := description.value,
packageDescription := description.value,

bashScriptEnvConfigLocation := Some("/etc/environment"),
Debian / makeEtcDefault := None,
Debian / packageBin := {
val originalFileName = (Debian / packageBin).value
val (base, ext) = originalFileName.baseAndExt
val newBase = base.replace(s"_${version.value}_all","")
val newFileName = file(originalFileName.getParent) / s"$newBase.$ext"
IO.move(originalFileName, newFileName)
println(s"Renamed $originalFileName to $newFileName")
newFileName
},
Universal / mappings ++= Seq(
file("common-lib/src/main/resources/application.conf") -> "conf/application.conf",
file("common-lib/src/main/resources/logback.xml") -> "conf/logback.xml"
),
Universal / javaOptions ++= Seq(
"-Dpidfile.path=/dev/null",
s"-Dconfig.file=/usr/share/$projectName/conf/application.conf",
s"-Dlogger.file=/usr/share/$projectName/conf/logback.xml",
"-J-Xlog:gc*",
s"-J-Xlog:gc:/var/log/$projectName/gc.log"
)
))
//Add the BBC library dependency if defined
maybeBBCLib.fold(commonProject){commonProject.dependsOn(_)}
s"-Dconfig.file=/opt/docker/conf/application.conf",
s"-Dlogger.file=/opt/docker/conf/logback.xml",
"-XX:+PrintCommandLineFlags", "-XX:MaxRAMPercentage=40"
))
)
}

def playImageLoaderProject(projectName: String, port: Int, path: Option[String] = None): Project = {
project(projectName, path)
.enablePlugins(PlayScala, BuildInfoPlugin, DockerPlugin)
.dependsOn(restLib)
.settings(commonSettings ++ buildInfo ++ Seq(
dockerBaseImage := "eu.gcr.io/grid-301122/jdk-vips:25-8.18.3",
dockerExposedPorts := Seq(port),
dockerCommands ++= Seq(
Cmd("ENV", "LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libjemalloc.so")
),
playDefaultPort := port,

bashScriptEnvConfigLocation := Some("/etc/environment"),
Universal / mappings ++= Seq(
file("common-lib/src/main/resources/application.conf") -> "conf/application.conf",
file("common-lib/src/main/resources/logback.xml") -> "conf/logback.xml",
file("image-loader/cmyk.icc") -> "cmyk.icc",
file("image-loader/facebook-TINYsRGB_c2.icc") -> "facebook-TINYsRGB_c2.icc",
file("image-loader/grayscale.icc") -> "grayscale.icc",
file("image-loader/srgb.icc") -> "srgb.icc"
),
Universal / javaOptions ++= Seq(
"-Dpidfile.path=/dev/null",
s"-Dconfig.file=/opt/docker/conf/application.conf",
s"-Dlogger.file=/opt/docker/conf/logback.xml",
"-XX:+PrintCommandLineFlags", "-XX:MaxRAMPercentage=20"
)))
}
Loading