diff --git a/lib/dpul_collections/indexing_pipeline/figgy/hydration_cache_entry.ex b/lib/dpul_collections/indexing_pipeline/figgy/hydration_cache_entry.ex
index 6b211663..c592a65c 100644
--- a/lib/dpul_collections/indexing_pipeline/figgy/hydration_cache_entry.ex
+++ b/lib/dpul_collections/indexing_pipeline/figgy/hydration_cache_entry.ex
@@ -32,10 +32,38 @@ defmodule DpulCollections.IndexingPipeline.Figgy.HydrationCacheEntry do
years_is: extract_years(data),
display_date_s: format_date(metadata),
page_count_i: page_count(metadata),
- image_service_urls_ss: image_service_urls(metadata, related_data)
+ image_service_urls_ss: image_service_urls(metadata, related_data),
+ primary_thumbnail_service_url_s: primary_thumbnail_service_url(metadata, related_data)
}
end
+ defp primary_thumbnail_service_url(
+ %{"thumbnail_id" => thumbnail_id} = metadata,
+ %{"member_ids" => member_data} = related_data
+ )
+ when is_list(thumbnail_id) do
+ thumbnail_member =
+ thumbnail_id
+ |> Enum.at(0, %{})
+ |> Map.get("id")
+ |> then(fn id -> member_data[id] end)
+
+ if is_nil(thumbnail_member) do
+ # When thumbnail id does not correspond to a related FileSet,
+ # use the first image service url
+ image_service_urls(metadata, related_data)
+ |> Enum.at(0)
+ else
+ extract_service_url(thumbnail_member)
+ end
+ end
+
+ defp primary_thumbnail_service_url(metadata, related_data) do
+ # When the thumbnail id is not set, use first image service url
+ image_service_urls(metadata, related_data)
+ |> Enum.at(0)
+ end
+
defp image_service_urls(%{"member_ids" => member_ids}, related_data) do
member_ids
|> Enum.map(&extract_service_url(&1, related_data))
diff --git a/lib/dpul_collections/item.ex b/lib/dpul_collections/item.ex
index 2d6d8d74..344708a0 100644
--- a/lib/dpul_collections/item.ex
+++ b/lib/dpul_collections/item.ex
@@ -8,6 +8,7 @@ defmodule DpulCollections.Item do
:page_count,
:url,
:image_service_urls,
+ :primary_thumbnail_service_url,
:description
]
@@ -25,6 +26,7 @@ defmodule DpulCollections.Item do
page_count: doc["page_count_i"],
url: generate_url(id, slug),
image_service_urls: doc["image_service_urls_ss"] || [],
+ primary_thumbnail_service_url: doc["primary_thumbnail_service_url_s"],
description: doc["description_txtm"] || []
}
end
diff --git a/lib/dpul_collections/solr.ex b/lib/dpul_collections/solr.ex
index 3a49e0f4..dffbb1e5 100644
--- a/lib/dpul_collections/solr.ex
+++ b/lib/dpul_collections/solr.ex
@@ -19,7 +19,8 @@ defmodule DpulCollections.Solr do
"page_count_i",
"detectlang_ss",
"slug_s",
- "image_service_urls_ss"
+ "image_service_urls_ss",
+ "primary_thumbnail_service_url_s"
]
@spec query(map(), String.t()) :: map()
diff --git a/lib/dpul_collections_web/live/item_live.ex b/lib/dpul_collections_web/live/item_live.ex
index a1caa5eb..75a0daa6 100644
--- a/lib/dpul_collections_web/live/item_live.ex
+++ b/lib/dpul_collections_web/live/item_live.ex
@@ -38,7 +38,7 @@ defmodule DpulCollectionsWeb.ItemLive do
<.thumbs
- :for={{thumb, thumb_num} <- Enum.with_index(@item.image_service_urls)}
+ :for={{thumb, thumb_num} <- thumbnail_service_urls(5, @item)}
:if={@item.page_count}
thumb={thumb}
thumb_num={thumb_num}
@@ -343,4 +343,28 @@ defmodule DpulCollectionsWeb.SearchLive do
type == :post -> [{"...", false}, {page, false}]
end
end
+
+ defp thumbnail_service_urls(max_thumbnails, item) do
+ thumbnail_service_urls(
+ max_thumbnails,
+ item.image_service_urls,
+ item.primary_thumbnail_service_url
+ )
+ end
+
+ defp thumbnail_service_urls(max_thumbnails, image_service_urls, nil) do
+ # Truncate image service urls to max value
+ image_service_urls
+ |> Enum.slice(0, max_thumbnails)
+ |> Enum.with_index()
+ end
+
+ defp thumbnail_service_urls(max_thumbnails, image_service_urls, primary_thumbnail_service_url) do
+ # Move thumbnail url to front of list and then truncate to max value
+ image_service_urls
+ |> Enum.filter(&(&1 != primary_thumbnail_service_url))
+ |> List.insert_at(0, primary_thumbnail_service_url)
+ |> Enum.slice(0, max_thumbnails)
+ |> Enum.with_index()
+ end
end
diff --git a/test/dpul_collections/indexing_pipeline/figgy/hydration_cache_entry_test.exs b/test/dpul_collections/indexing_pipeline/figgy/hydration_cache_entry_test.exs
index 9f5d333f..3fe7f4a1 100644
--- a/test/dpul_collections/indexing_pipeline/figgy/hydration_cache_entry_test.exs
+++ b/test/dpul_collections/indexing_pipeline/figgy/hydration_cache_entry_test.exs
@@ -68,7 +68,8 @@ defmodule DpulCollections.IndexingPipeline.Figgy.HydrationCacheEntryTest do
"internal_resource" => "EphemeraFolder",
"metadata" => %{
"member_ids" => [%{"id" => "1"}],
- "title" => ["test title 4"]
+ "title" => ["test title 4"],
+ "thumbnail_id" => [%{"id" => "1"}]
}
}
})
@@ -79,6 +80,115 @@ defmodule DpulCollections.IndexingPipeline.Figgy.HydrationCacheEntryTest do
assert doc[:image_service_urls_ss] == [
"https://iiif-cloud.princeton.edu/iiif/2/0c%2Fff%2F89%2F0cff895a01ea48959c3da8c6eaab4017%2Fintermediate_file"
]
+
+ # Has thumbnail url
+ assert doc[:primary_thumbnail_service_url_s] ==
+ "https://iiif-cloud.princeton.edu/iiif/2/0c%2Fff%2F89%2F0cff895a01ea48959c3da8c6eaab4017%2Fintermediate_file"
+ end
+
+ test "uses first image service url when there is no thumbnail_id property" do
+ {:ok, entry} =
+ IndexingPipeline.write_hydration_cache_entry(%{
+ cache_version: 0,
+ record_id: "0cff895a-01ea-4895-9c3d-a8c6eaab4013",
+ source_cache_order: ~U[2018-03-09 20:19:35.465203Z],
+ related_data: %{
+ "member_ids" => %{
+ "1" => %{
+ "internal_resource" => "FileSet",
+ "id" => "9ad621a7b-01ea-4895-9c3d-a8c6eaab4013",
+ "metadata" => %{
+ "file_metadata" => [
+ %{
+ "id" => %{"id" => "0cff895a-01ea-4895-9c3d-a8c6eaab4017"},
+ "internal_resource" => "FileMetadata",
+ "mime_type" => ["image/tiff"],
+ "use" => [%{"@id" => "http://pcdm.org/use#ServiceFile"}]
+ }
+ ]
+ }
+ }
+ }
+ },
+ data: %{
+ "id" => "0cff895a-01ea-4895-9c3d-a8c6eaab4013",
+ "internal_resource" => "EphemeraFolder",
+ "metadata" => %{
+ "member_ids" => [%{"id" => "1"}],
+ "title" => ["test title 4"]
+ }
+ }
+ })
+
+ doc = HydrationCacheEntry.to_solr_document(entry)
+
+ assert doc[:primary_thumbnail_service_url_s] ==
+ "https://iiif-cloud.princeton.edu/iiif/2/0c%2Fff%2F89%2F0cff895a01ea48959c3da8c6eaab4017%2Fintermediate_file"
+ end
+
+ test "uses first image service url when thumbnail id does not point to related FileSet" do
+ {:ok, entry} =
+ IndexingPipeline.write_hydration_cache_entry(%{
+ cache_version: 0,
+ record_id: "0cff895a-01ea-4895-9c3d-a8c6eaab4013",
+ source_cache_order: ~U[2018-03-09 20:19:35.465203Z],
+ related_data: %{
+ "member_ids" => %{
+ "1" => %{
+ "internal_resource" => "FileSet",
+ "id" => "9ad621a7b-01ea-4895-9c3d-a8c6eaab4013",
+ "metadata" => %{
+ "file_metadata" => [
+ %{
+ "id" => %{"id" => "0cff895a-01ea-4895-9c3d-a8c6eaab4017"},
+ "internal_resource" => "FileMetadata",
+ "mime_type" => ["image/tiff"],
+ "use" => [%{"@id" => "http://pcdm.org/use#ServiceFile"}]
+ }
+ ]
+ }
+ }
+ }
+ },
+ data: %{
+ "id" => "0cff895a-01ea-4895-9c3d-a8c6eaab4013",
+ "internal_resource" => "EphemeraFolder",
+ "metadata" => %{
+ "member_ids" => [%{"id" => "1"}],
+ "title" => ["test title 4"],
+ "thumbnail_id" => [%{"id" => "9"}]
+ }
+ }
+ })
+
+ doc = HydrationCacheEntry.to_solr_document(entry)
+
+ assert doc[:primary_thumbnail_service_url_s] ==
+ "https://iiif-cloud.princeton.edu/iiif/2/0c%2Fff%2F89%2F0cff895a01ea48959c3da8c6eaab4017%2Fintermediate_file"
+ end
+
+ test "does not add a thumbnail service url when there are no image members" do
+ {:ok, entry} =
+ IndexingPipeline.write_hydration_cache_entry(%{
+ cache_version: 0,
+ record_id: "0cff895a-01ea-4895-9c3d-a8c6eaab4013",
+ source_cache_order: ~U[2018-03-09 20:19:35.465203Z],
+ related_data: %{
+ "member_ids" => %{}
+ },
+ data: %{
+ "id" => "0cff895a-01ea-4895-9c3d-a8c6eaab4013",
+ "internal_resource" => "EphemeraFolder",
+ "metadata" => %{
+ "member_ids" => [],
+ "title" => ["test title 4"]
+ }
+ }
+ })
+
+ doc = HydrationCacheEntry.to_solr_document(entry)
+
+ assert doc[:primary_thumbnail_service_url_s] == nil
end
test "can handle when members do not have the correct file metadata type" do
diff --git a/test/dpul_collections/indexing_pipeline/integration/full_integration_test.exs b/test/dpul_collections/indexing_pipeline/integration/full_integration_test.exs
index 68b72741..e86abbdc 100644
--- a/test/dpul_collections/indexing_pipeline/integration/full_integration_test.exs
+++ b/test/dpul_collections/indexing_pipeline/integration/full_integration_test.exs
@@ -196,5 +196,8 @@ defmodule DpulCollections.IndexingPipeline.FiggyFullIntegrationTest do
"https://iiif-cloud.princeton.edu/iiif/2/5e%2F24%2Faf%2F5e24aff45b2e4c9aaba3f05321d1c797%2Fintermediate_file"
| _rest
] = document["image_service_urls_ss"]
+
+ assert "https://iiif-cloud.princeton.edu/iiif/2/5e%2F24%2Faf%2F5e24aff45b2e4c9aaba3f05321d1c797%2Fintermediate_file" =
+ document["primary_thumbnail_service_url_s"]
end
end
diff --git a/test/dpul_collections_web/live/item_live_test.exs b/test/dpul_collections_web/live/item_live_test.exs
index 72ae8873..3f05d990 100644
--- a/test/dpul_collections_web/live/item_live_test.exs
+++ b/test/dpul_collections_web/live/item_live_test.exs
@@ -19,6 +19,7 @@ defmodule DpulCollectionsWeb.ItemLiveTest do
"https://example.com/iiif/2/image1",
"https://example.com/iiif/2/image2"
],
+ primary_thumbnail_service_url_s: "https://example.com/iiif/2/image2",
description_txtm: ["This is a test description"]
},
%{
@@ -29,7 +30,8 @@ defmodule DpulCollectionsWeb.ItemLiveTest do
image_service_urls_ss: [
"https://example.com/iiif/2/image1",
"https://example.com/iiif/2/image2"
- ]
+ ],
+ primary_thumbnail_service_url_s: "https://example.com/iiif/2/image1"
},
%{
id: 3,
@@ -39,7 +41,8 @@ defmodule DpulCollectionsWeb.ItemLiveTest do
image_service_urls_ss: [
"https://example.com/iiif/2/image1",
"https://example.com/iiif/2/image2"
- ]
+ ],
+ primary_thumbnail_service_url_s: "https://example.com/iiif/2/image1"
}
],
active_collection()
@@ -108,10 +111,10 @@ defmodule DpulCollectionsWeb.ItemLiveTest do
"Download"
)
- # Large thumbnail renders
+ # Large thumbnail renders using thumbnail service url
assert view
|> has_element?(
- ".primary-thumbnail img[src='https://example.com/iiif/2/image1/full/525,800/0/default.jpg']"
+ ".primary-thumbnail img[src='https://example.com/iiif/2/image2/full/525,800/0/default.jpg']"
)
assert view
diff --git a/test/dpul_collections_web/live/search_live_test.exs b/test/dpul_collections_web/live/search_live_test.exs
index 0e7e9c51..90aa8c22 100644
--- a/test/dpul_collections_web/live/search_live_test.exs
+++ b/test/dpul_collections_web/live/search_live_test.exs
@@ -53,27 +53,38 @@ defmodule DpulCollectionsWeb.SearchLiveTest do
end
test "GET /search renders thumbnails for each resource", %{conn: conn} do
- {:ok, view, _html} = live(conn, "/search?")
+ {:ok, _view, html} = live(conn, "/search?")
- assert view
- |> has_element?(
- "#item-1 img[src='https://example.com/iiif/2/image1/square/350,350/0/default.jpg']"
- )
+ {:ok, document} =
+ html
+ |> Floki.parse_document()
- assert view
- |> has_element?(
- "#item-1 img[src='https://example.com/iiif/2/image2/square/350,350/0/default.jpg']"
- )
+ # There should be a maximum of 5 thumbnails on the search results page
+ assert document |> Floki.find("#item-1 > div > img") |> Enum.count() == 5
- assert view
- |> has_element?(
- "#item-2 img[src='https://example.com/iiif/2/image1/square/350,350/0/default.jpg']"
- )
+ # Odd numbered documents in test data do not have a thumbnail id
+ # so the order of thumbnails should be the same as the image member order
+ assert document
+ |> Floki.attribute("#item-1 > div > :first-child", "src") == [
+ "https://example.com/iiif/2/image1/square/350,350/0/default.jpg"
+ ]
- assert view
- |> has_element?(
- "#item-2 img[src='https://example.com/iiif/2/image2/square/350,350/0/default.jpg']"
- )
+ assert document
+ |> Floki.attribute("#item-1 > div > :nth-child(2)", "src") == [
+ "https://example.com/iiif/2/image2/square/350,350/0/default.jpg"
+ ]
+
+ # Even numbered documents in test data have a thumbnail id so the order
+ # of thumbnails should be different from the image member order
+ assert document
+ |> Floki.attribute("#item-2 > div > :first-child", "src") == [
+ "https://example.com/iiif/2/image2/square/350,350/0/default.jpg"
+ ]
+
+ assert document
+ |> Floki.attribute("#item-2 > div > :nth-child(2)", "src") == [
+ "https://example.com/iiif/2/image1/square/350,350/0/default.jpg"
+ ]
end
test "searching filters results", %{conn: conn} do
diff --git a/test/support/solr_test_support.ex b/test/support/solr_test_support.ex
index 6f9a88a8..ff4ae6d0 100644
--- a/test/support/solr_test_support.ex
+++ b/test/support/solr_test_support.ex
@@ -2,7 +2,17 @@ defmodule SolrTestSupport do
def mock_solr_documents(count \\ 100) do
for n <- 1..count do
date = 2025 - n
- page_count = Enum.random(1..10)
+
+ # Equals the number of image service urls
+ page_count = 7
+
+ # Assign thumbnail urls to even numbered documents.
+ # Used for testing thumbnail rendering order
+ thumbnail_url =
+ cond do
+ rem(n, 2) == 0 -> "https://example.com/iiif/2/image2"
+ true -> nil
+ end
%{
id: n,
@@ -12,8 +22,14 @@ defmodule SolrTestSupport do
page_count_i: page_count,
image_service_urls_ss: [
"https://example.com/iiif/2/image1",
- "https://example.com/iiif/2/image2"
- ]
+ "https://example.com/iiif/2/image2",
+ "https://example.com/iiif/2/image3",
+ "https://example.com/iiif/2/image4",
+ "https://example.com/iiif/2/image5",
+ "https://example.com/iiif/2/image6",
+ "https://example.com/iiif/2/image7"
+ ],
+ primary_thumbnail_service_url_s: thumbnail_url
}
end
end