diff --git a/.env.test b/.env.test index ea7f31bf..341fa390 100644 --- a/.env.test +++ b/.env.test @@ -15,12 +15,10 @@ GLOBAL_MESSAGE_URL=http://test.nla.gov.au/catalogue-message/1234 BOOTSNAP_CACHE_DIR=./tmp # Requesting -CATALOGUE_SERVICES_API_BASE_URL="define CATALOGUE_SERVICES_API_BASE_URL" -CATALOGUE_SERVICES_CLIENT="define CATALOGUE_SERVICES_CLIENT" -CATALOGUE_SERVICES_SECRET="define CATALOGUE_SERVICES_SECRET" -CATALOGUE_SERVICES_REALM="define CATALOGUE_SERVICES_REALM" +CATALOGUE_SERVICES_API_BASE_URL=http://catservices.test +CATALOGUE_SERVICES_CLIENT="catalogue-services" +CATALOGUE_SERVICES_SECRET="254241c8-1e99-4855-a0ae-52b04702c3e5" +CATALOGUE_SERVICES_REALM="example-realm" # turn of functionality during FOLIO update FOLIO_UPDATE_IN_PROGRESS= - -CATALOGUE_SERVICES_API_BASE_URL=http://catservices.test diff --git a/app/components/related_documents_component.html.erb b/app/components/related_documents_component.html.erb new file mode 100644 index 00000000..e907b4dc --- /dev/null +++ b/app/components/related_documents_component.html.erb @@ -0,0 +1,12 @@ + diff --git a/app/components/related_documents_component.rb b/app/components/related_documents_component.rb new file mode 100644 index 00000000..79df819b --- /dev/null +++ b/app/components/related_documents_component.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class RelatedDocumentsComponent < Blacklight::Component + attr_reader :related_docs + + def initialize(related_docs:) + @related_docs = related_docs + end + + def render? + related_docs.present? + end +end diff --git a/app/controllers/catalog_controller.rb b/app/controllers/catalog_controller.rb index 69dc4752..eff18d88 100644 --- a/app/controllers/catalog_controller.rb +++ b/app/controllers/catalog_controller.rb @@ -381,7 +381,11 @@ class CatalogController < ApplicationController values: ->(__field_config, document, _context) { document.extract_notes_by_header("box_list") } # Collection Show Page - Related Section - config.add_related_field "relatedmaterial", field: "relatedmaterial_html_tesm", helper_method: :render_html_tags + config.add_related_field "relatedmaterial", + label: I18n.t("blacklight.search.fields.relatedmaterial"), + helper_method: :render_related_docs, + values: ->(__field_config, document, _context) { CatalogueServicesClient.new.related_docs(pid: "nla.obj-#{document.pid}") }, + if: ->(_controller, _config, document) { document.pid.present? } config.add_related_field "separatedmaterial", field: "separatedmaterial_html_tesm", helper_method: :render_html_tags config.add_related_field "otherfindaid", field: "otherfindaid_html_tesm", helper_method: :render_html_tags config.add_related_field "altformavail", field: "altformavail_html_tesm", helper_method: :render_html_tags @@ -481,4 +485,10 @@ class CatalogController < ApplicationController # Group header values config.add_group_header_field "abstract_or_scope", accessor: true, truncate: true, helper_method: :render_html_tags end + + private + + def has_pid? + document.pid.present? + end end diff --git a/app/helpers/field_helper.rb b/app/helpers/field_helper.rb new file mode 100644 index 00000000..6f022a5f --- /dev/null +++ b/app/helpers/field_helper.rb @@ -0,0 +1,7 @@ +module FieldHelper + def render_related_docs(document:, field:, config:, value:, context:) + if document.pid.present? + render RelatedDocumentsComponent.new(related_docs: value) + end + end +end diff --git a/app/helpers/file_size_helper.rb b/app/helpers/file_size_helper.rb new file mode 100644 index 00000000..69bdca99 --- /dev/null +++ b/app/helpers/file_size_helper.rb @@ -0,0 +1,17 @@ +module FileSizeHelper + def format_filesize(size) + if size.present? + if size.to_i < 1024 + "#{size} B" + elsif size.to_i < 1048576 # 1024 * 1024 + "#{(size.to_f / 1024).round(2)} KB" + elsif size.to_i < 1073741824 # 1024 * 1024 * 1024 + "#{(size.to_f / 1048576).round(2)} MB" + else + "#{(size.to_f / 1073741824).round(2)} GB" + end + else + "0 B" + end + end +end diff --git a/app/models/related_document.rb b/app/models/related_document.rb new file mode 100644 index 00000000..c1e55e80 --- /dev/null +++ b/app/models/related_document.rb @@ -0,0 +1,19 @@ +# frozen_string_literal: true + +class RelatedDocument < OpenStruct + def link_text + if copyRole == "fas" + "#{I18n.t("related_docs.link_text_fas")} (Type: #{fileType}, Size: #{ApplicationController.helpers.format_filesize(fileSize)})" + else + "#{I18n.t("related_docs.link_text")} ( Type: #{fileType}, Size: #{ApplicationController.helpers.format_filesize(fileSize)})" + end + end + + def download_url + if copyRole == "fas" + "https://nla.gov.au/#{pid}/relateddocs/download?copyRole=#{copyRole}©Id=#{id}" + else + "https://nla.gov.au/#{pid}/relateddocs/download?copyRole=#{copyRole}" + end + end +end diff --git a/app/models/solr_document.rb b/app/models/solr_document.rb index 22d8e473..c62d9302 100644 --- a/app/models/solr_document.rb +++ b/app/models/solr_document.rb @@ -12,6 +12,7 @@ class SolrDocument attribute :physdesc_dimensions, :string, "physdesc_dimensions_ssi" attribute :physdesc_facet, :string, "physdesc_facet_ssi" attribute :notes, :array, "note_json_ssm" + attribute :pid, :string, "ead_ssi" # **** BEWARE! **** # Arclight aliases "level_ssm" and "unitid_ssm" fields to String type attributes in the diff --git a/app/services/catalogue_services_client.rb b/app/services/catalogue_services_client.rb index eb1bf035..f39708da 100644 --- a/app/services/catalogue_services_client.rb +++ b/app/services/catalogue_services_client.rb @@ -76,6 +76,26 @@ def get_access_conditions(instance_id:, holdings_id:) item ? item["note"] : nil end + def related_docs(pid:) + conn = setup_connection + + res = Rails.cache.fetch([pid, :related_docs], expires_in: 10.minutes) { conn.get("/catalogue-services/ead/relateddocs/#{pid}") } + if res.status == 200 + if res.body.present? && res.body["docs"].present? + res.body["docs"].map do |attrs| + attrs[:pid] = pid # insert the pid since we need it to construct the download URL + RelatedDocument.new(attrs) + end + end + else + Rails.logger.error "Failed to retrieve related documents for #{pid}" + nil + end + rescue => e + Rails.logger.error "related_docs - Failed to connect catalogue-service: #{e.message}" + nil + end + private def setup_connection diff --git a/config/environments/test.rb b/config/environments/test.rb index 0f67aea9..f717e0c5 100644 --- a/config/environments/test.rb +++ b/config/environments/test.rb @@ -25,16 +25,7 @@ # Show full error reports and disable caching. config.consider_all_requests_local = true config.action_controller.perform_caching = false - config.cache_store = :redis_cache_store, { - driver: :hiredis, - url: ENV["REDIS_URL"], - timeout: 30, - reconnect_attempts: 3, - expires_in: 1.hour, - namespace: "arclight", - pool_size: 5, - pool_timeout: 5 - } + config.cache_store = :null_store # Raise exceptions instead of rendering exception templates. config.action_dispatch.show_exceptions = false diff --git a/config/locales/arclight.en.yml b/config/locales/arclight.en.yml index 552c00ce..fb837a98 100644 --- a/config/locales/arclight.en.yml +++ b/config/locales/arclight.en.yml @@ -25,7 +25,7 @@ en: descrules: Rules or conventions extentsinfo: Extent information - relatedmaterial: Related Material + relatedmaterial: Related Documentation separatedmaterial: Separated Material otherfindaid: Other Finding Aids altformavail: Existence and Location of Copies diff --git a/config/locales/en.yml b/config/locales/en.yml index 8186a2d2..bd905b2a 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -55,4 +55,6 @@ en: container_list: "Container List" box_list: "Box List" bibref: "Bibliographic Reference(s)" - + related_docs: + link_text_fas: "Supplementary finding aid" + link_text: "Transcript" diff --git a/spec/components/related_documents_component_spec.rb b/spec/components/related_documents_component_spec.rb new file mode 100644 index 00000000..ae7a8831 --- /dev/null +++ b/spec/components/related_documents_component_spec.rb @@ -0,0 +1,50 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe RelatedDocumentsComponent, type: :component do + let(:pid) { "nla.obj-123" } + + let(:related_docs) do + docs = JSON.parse(IO.read("spec/files/catalogue_services/related_docs.json"))["docs"] + docs.map! do |attrs| + attrs[:pid] = pid + RelatedDocument.new(attrs) + end + end + + context "when there are no related documents" do + it "does not render when there are no related documents" do + render_inline(described_class.new(related_docs: nil)) + + expect(page).to have_no_css("ol#related-documents") + end + end + + context "when there are related document" do + it "renders the related documents" do + render_inline(described_class.new(related_docs: related_docs(pid))) + + expect(page).to have_css("ol#related-documents") + expect(page).to have_css("li", count: 4) + end + end + + context "when there are external comments" do + it "renders the external comments" do + render_inline(described_class.new(related_docs: related_docs(pid))) + + expect(page).to have_content("Appendix C - Items in Series 12.1") + end + end + + private + + def related_docs(pid) + docs = JSON.parse(IO.read("spec/files/catalogue_services/related_docs.json"))["docs"] + docs.map! do |attrs| + attrs[:pid] = pid # insert the pid since we need it to construct the download URL + RelatedDocument.new(attrs) + end + end +end diff --git a/spec/features/related_documents_spec.rb b/spec/features/related_documents_spec.rb new file mode 100644 index 00000000..0c2bb488 --- /dev/null +++ b/spec/features/related_documents_spec.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe "Related Documents" do + describe "when at the collection level" do + before do + solr_response = IO.read("spec/files/solr/280011976.json") + + WebMock.stub_request(:get, /solr:8983/) + .with( + headers: { + "Accept" => "*/*", + "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + } + ) + .to_return(status: 200, body: solr_response, headers: {}) + + availability_response = IO.read("spec/files/catalogue_services/08aed703-3648-54d0-80ef-fddb3c635731.json") + + WebMock.stub_request(:get, /catalogue-services\/folio\/instance\/(.*)/) + .to_return(status: 200, body: availability_response, headers: {"Content-Type" => "application/json"}) + end + + context "when there are related documents" do + before do + docs_response = IO.read("spec/files/catalogue_services/related_docs.json") + WebMock.stub_request(:get, /catservices.test\/catalogue-services\/ead\/relateddocs\/(nla.obj-[0-9]*)/) + .to_return(status: 200, body: docs_response, headers: {"Content-Type" => "application/json"}) + end + + it "renders the related documents" do + visit solr_document_path(id: "280011976") + + expect(page).to have_css("h3", text: "Related") + expect(page).to have_css("ol#related-documents") + expect(page).to have_css("ol#related-documents li", count: 4) + end + end + + context "when there are no related documents" do + before do + WebMock.stub_request(:get, /catservices.test\/catalogue-services\/ead\/relateddocs\/(nla.obj-[0-9]*)/) + .to_return(status: 200, body: "", headers: {"Content-Type" => "application/json"}) + end + + it "does not render the related documents" do + visit solr_document_path(id: "280011976") + + expect(page).to have_no_css("h3", text: "Related") + expect(page).to have_no_css("ol#related-documents") + expect(page).to have_no_css("ol#related-documents li") + end + end + end +end diff --git a/spec/files/catalogue_services/no_related_docs.json b/spec/files/catalogue_services/no_related_docs.json new file mode 100644 index 00000000..6f9406d4 --- /dev/null +++ b/spec/files/catalogue_services/no_related_docs.json @@ -0,0 +1,3 @@ +{ + "docs": [] +} diff --git a/spec/files/catalogue_services/related_docs.json b/spec/files/catalogue_services/related_docs.json new file mode 100644 index 00000000..79ecd226 --- /dev/null +++ b/spec/files/catalogue_services/related_docs.json @@ -0,0 +1,36 @@ +{ + "docs": [ + { + "id": "nla.obj-367760674", + "copyRole": "fas", + "fileName": "Finding aid supplementary", + "externalComments": "Appendix C - Items in Series 12.1", + "fileType": "pdf", + "fileSize": 124305 + }, + { + "id": "nla.obj-367758458", + "copyRole": "fas", + "fileName": "Finding aid supplementary", + "externalComments": "Appendix B - Selected items in Subseries 5.2", + "fileType": "pdf", + "fileSize": 113986 + }, + { + "id": "nla.obj-367758206", + "copyRole": "fas", + "fileName": "Finding aid supplementary", + "externalComments": "Appendix A - Concordance (Box List)", + "fileType": "pdf", + "fileSize": 401572 + }, + { + "id": "nla.obj-367766877", + "copyRole": "fas", + "fileName": "Finding aid supplementary", + "externalComments": "Appendix D - Items in Series 17", + "fileType": "pdf", + "fileSize": 200793 + } + ] +} diff --git a/spec/helpers/file_size_helper_spec.rb b/spec/helpers/file_size_helper_spec.rb new file mode 100644 index 00000000..c1fbe3f1 --- /dev/null +++ b/spec/helpers/file_size_helper_spec.rb @@ -0,0 +1,31 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe FileSizeHelper do + describe "#format_filesize" do + it "returns 0 when there is no file size" do + expect(helper.format_filesize(nil)).to eq("0 B") + end + + it "returns the size in kilobytes" do + expect(helper.format_filesize(1024)).to eq("1.0 KB") + end + + it "returns the size in megabytes" do + expect(helper.format_filesize(1024 * 1024)).to eq("1.0 MB") + end + + it "returns the size in gigabytes" do + expect(helper.format_filesize(1024 * 1024 * 1024)).to eq("1.0 GB") + end + + it "returns sizes 1 TB or larger in gigabytes" do + expect(helper.format_filesize(1024 * 1024 * 1024 * 1024)).to eq("1024.0 GB") + end + + it "rounds to the nearest 2 decimal places" do + expect(helper.format_filesize(124305)).to eq("121.39 KB") + end + end +end diff --git a/spec/models/related_document_spec.rb b/spec/models/related_document_spec.rb new file mode 100644 index 00000000..5754863b --- /dev/null +++ b/spec/models/related_document_spec.rb @@ -0,0 +1,69 @@ +# frozen_string_literal: true + +require "rails_helper" + +RSpec.describe RelatedDocument do + subject(:related_document) { described_class.new(fas_attrs) } + + let(:fas_attrs) do + { + id: "nla.obj-367760674", + copyRole: "fas", + fileName: "Finding aid supplementary", + externalComments: "Appendix C - Items in Series 12.1", + fileType: "pdf", + fileSize: 124305 + } + end + let(:non_fas_attrs) do + { + id: "nla.obj-594455512", + copyRole: "te", + fileName: "Electronic Transcript", + externalComments: "", + fileType: "doc", + fileSize: 57 + } + end + + it "converts a hash into an OpenStruct" do + expect(related_document).not_to be_nil + expect(related_document.is_a?(OpenStruct)).to be true + end + + it "does not convert non-hash objects into an OpenStruct" do + expect { described_class.new("string") }.to raise_error(NoMethodError) + end + + it "has the file type in the link text" do + expect(related_document.link_text).to include("Type: pdf") + end + + it "has the file size in the link text" do + expect(related_document.link_text).to include("Size: 121.39 KB") + end + + context "when copyRole is 'fas'" do + subject(:related_document) { described_class.new(fas_attrs) } + + it "contains 'Supplementary finding aid' in the link text" do + expect(related_document.link_text).to include("Supplementary finding aid") + end + + it "has the 'copyId' parameter in the download URL" do + expect(related_document.download_url).to include("©Id=") + end + end + + context "when copyRole is not 'fas'" do + subject(:related_document) { described_class.new(non_fas_attrs) } + + it "contains 'Transcript' in the link text" do + expect(related_document.link_text).to include("Transcript") + end + + it "does not have the 'copyId' parameter in the download URL" do + expect(related_document.download_url).not_to include("©Id=") + end + end +end diff --git a/spec/services/catalogue_services_client_spec.rb b/spec/services/catalogue_services_client_spec.rb index 174501ae..11e58e77 100644 --- a/spec/services/catalogue_services_client_spec.rb +++ b/spec/services/catalogue_services_client_spec.rb @@ -57,4 +57,60 @@ expect(service.get_access_conditions(instance_id: "08aed703-3648-54d0-80ef-fddb3c635731", holdings_id: "d6c97d9e-dfe6-5faa-9f0b-020b2bddbf8c")).to be_nil end end + + describe "#related_docs" do + context "when there are related records" do + before do + cat_response = IO.read("spec/files/catalogue_services/related_docs.json") + WebMock.stub_request(:get, /catservices.test\/catalogue-services\/ead\/relateddocs\/nla.obj-123/) + .to_return(status: 200, body: cat_response, headers: {"Content-Type" => "application/json"}) + end + + let(:related_docs) { service.related_docs(pid: "nla.obj-123") } + + it "returns the related records" do + expect(related_docs).not_to be_nil + expect(related_docs.size).to eq 4 + expect(related_docs.first["id"]).to eq "nla.obj-367760674" + expect(related_docs.first["copyRole"]).to eq "fas" + expect(related_docs.first["fileName"]).to eq "Finding aid supplementary" + expect(related_docs.first["fileType"]).to eq "pdf" + expect(related_docs.first["fileSize"]).to eq 124305 + end + end + + context "when there are no related records" do + before do + cat_response = IO.read("spec/files/catalogue_services/no_related_docs.json") + WebMock.stub_request(:get, /catservices.test\/catalogue-services\/ead\/relateddocs\/nla.obj-123/) + .to_return(status: 200, body: cat_response, headers: {"Content-Type" => "application/json"}) + end + + it "returns an empty response" do + expect(service.related_docs(pid: "nla.obj-123")).to be_nil + end + end + + context "when the service returns an error" do + before do + WebMock.stub_request(:get, /catservices.test\/catalogue-services\/ead\/relateddocs\/nla.obj-123/) + .to_return(status: 500, body: "", headers: {"Content-Type" => "application/json"}) + end + + it "returns an empty response" do + expect(service.related_docs(pid: "nla.obj-123")).to be_nil + end + end + + context "when failed to connect to catalogue-service" do + before do + WebMock.stub_request(:get, /catservices.test\/catalogue-services\/ead\/relateddocs\/nla.obj-123/) + .to_raise(StandardError) + end + + it "returns an empty response" do + expect(service.related_docs(pid: "nla.obj-123")).to be_nil + end + end + end end diff --git a/spec/support/webmock.rb b/spec/support/webmock.rb index 173ad896..d97e1866 100644 --- a/spec/support/webmock.rb +++ b/spec/support/webmock.rb @@ -47,5 +47,14 @@ } ) .to_return(status: 200, body: "", headers: {"Content-Type" => "application/json"}) + + WebMock.stub_request(:get, /catservices.test\/catalogue-services\/ead\/relateddocs\/(nla.obj-[0-9]*)/) + .with( + headers: { + "Accept" => "*/*", + "Accept-Encoding" => "gzip;q=1.0,deflate;q=0.6,identity;q=0.3" + } + ) + .to_return(status: 200, body: "", headers: {"Content-Type" => "application/json"}) end end