diff --git a/app/models/concerns/iiif_print/solr/document.rb b/app/models/concerns/iiif_print/solr/document.rb index edb1fdbb..489d9366 100644 --- a/app/models/concerns/iiif_print/solr/document.rb +++ b/app/models/concerns/iiif_print/solr/document.rb @@ -53,4 +53,8 @@ def file_set_ids def any_highlighting? response&.[]('highlighting')&.[](id)&.present? end + + def solr_document + self + end end diff --git a/app/presenters/iiif_print/iiif_manifest_presenter_behavior.rb b/app/presenters/iiif_print/iiif_manifest_presenter_behavior.rb index bfd580a9..cec1477c 100644 --- a/app/presenters/iiif_print/iiif_manifest_presenter_behavior.rb +++ b/app/presenters/iiif_print/iiif_manifest_presenter_behavior.rb @@ -8,7 +8,8 @@ module IiifManifestPresenterBehavior attr_accessor :base_url def manifest_metadata - @manifest_metadata ||= IiifPrint.manifest_metadata_from(work: model, presenter: self) + # ensure we are using a SolrDocument + @manifest_metadata ||= IiifPrint.manifest_metadata_from(work: model.solr_document, presenter: self) end def search_service diff --git a/lib/iiif_print.rb b/lib/iiif_print.rb index d8595b64..218b1dd1 100644 --- a/lib/iiif_print.rb +++ b/lib/iiif_print.rb @@ -154,38 +154,38 @@ def self.default_fields(fields: config.metadata_fields) end end - def self.fields_for_allinson_flex(fields: allinson_flex_fields) - fields.map do |field| + ## + # @param fields [Array] + def self.fields_for_allinson_flex(fields: allinson_flex_fields, sort_order: IiifPrint.config.iiif_metadata_field_presentation_order) + fields = sort_af_fields!(fields, sort_order: sort_order) + fields.each_with_object({}) do |field, hash| + # filters out admin_only fields + next if field.indexing&.include?('admin_only') + + # WARNING: This is assuming A LOT + # This is taking the Allinson Flex fields that have the same name and only + # using the first one while discarding the rest. There currently no way to + # controller which one(s) are discarded but this fits for the moment. + next if hash.key?(field.name) + # currently only supports the faceted option # Why the `render_as:`? This was originally derived from Hyku default attributes # @see https://github.com/samvera/hyku/blob/c702844de4c003eaa88eb5a7514c7a1eae1b289e/app/views/hyrax/base/_attribute_rows.html.erb#L3 - options = field.indexing.include?('facetable') ? { render_as: :faceted } : nil - Field.new( + hash[field.name] = Field.new( name: field.name, label: field.value, - options: options + options: field.indexing&.include?('facetable') ? { render_as: :faceted } : nil ) - end + end.values end CollectionFieldShim = Struct.new(:name, :value, :indexing, keyword_init: true) + ## + # @return [Array] def self.allinson_flex_fields return @allinson_flex_fields if defined?(@allinson_flex_fields) - # sql query method was refactored to active record - # original query: - # AllinsonFlex::ProfileProperty - # .find_by_sql( - # "SELECT DISTINCT allinson_flex_profile_texts.value AS label, " \ - # "allinson_flex_profile_properties.name AS name " \ - # "FROM allinson_flex_profile_properties " \ - # "JOIN allinson_flex_profile_texts " \ - # "ON allinson_flex_profile_properties.id = " \ - # "allinson_flex_profile_texts.profile_property_id " \ - # "WHERE allinson_flex_profile_texts.name = 'display_label'" - # ) - # In this ActiveRecord query, allinson_flex_profile_properties.indexing was added allinson_flex_relation = AllinsonFlex::ProfileProperty .joins(:texts) .where(allinson_flex_profile_texts: { name: 'display_label' }) @@ -198,4 +198,16 @@ def self.allinson_flex_fields end @allinson_flex_fields = flex_fields end + + ## + # @param fields [Array] + # @param sort_order [Array] + def self.sort_af_fields!(fields, sort_order:) + return fields if sort_order.blank? + + fields.sort_by do |field| + sort_order_index = sort_order.index(field.name.to_sym) + sort_order_index.nil? ? sort_order.length : sort_order_index + end + end end diff --git a/lib/iiif_print/configuration.rb b/lib/iiif_print/configuration.rb index ec588cbf..f21ae531 100644 --- a/lib/iiif_print/configuration.rb +++ b/lib/iiif_print/configuration.rb @@ -195,6 +195,29 @@ def all_text_generator_function IiifPrint::Data::WorkDerivatives.data(from: object, of_type: 'txt') end end + + attr_writer :iiif_metadata_field_presentation_order + ## + # This is the default sorter for the metadata. It will sort by the order of the keys specificied. + # By default, this is turned off as it returns nil. If you want to turn it on, you can set this + # this to an array of symbols the properties on the work. + # + # @example [:title, :description, :date_created] + # @return [Array] + def iiif_metadata_field_presentation_order + @iiif_metadata_field_presentation_order || nil + end + + def questioning_authority_fields=(fields) + @questioning_authority_fields = Array.wrap(fields).map(&:to_s) + end + + ## + # This is used to explicitly set which fields should be rendered as a Questioning Authority in the UV. + # By default, we render `rights_statement` and `license` as QA fields. + def questioning_authority_fields + @questioning_authority_fields ||= ['rights_statement', 'license'] + end end # rubocop:enable Metrics/ModuleLength end diff --git a/lib/iiif_print/metadata.rb b/lib/iiif_print/metadata.rb index b1fdec0c..64059932 100644 --- a/lib/iiif_print/metadata.rb +++ b/lib/iiif_print/metadata.rb @@ -67,7 +67,7 @@ def scrub(value) def cast_to_value(field_name:, options:) if options&.[](:render_as) == :faceted faceted_values_for(field_name: field_name) - elsif options&.[](:render_as) == :rights_statement || options&.[](:render_as) == :license + elsif qa_field?(field_name: options&.dig(:render_as) || field_name) authority_values_for(field_name: field_name) else make_link(values_for(field_name: field_name)) @@ -85,6 +85,10 @@ def faceted_values_for(field_name:) end end + def qa_field?(field_name:, questioning_authority_fields: IiifPrint.config.questioning_authority_fields) + questioning_authority_fields.include?(field_name.to_s) + end + def authority_values_for(field_name:) authority = Qa::Authorities::Local.subauthority_for(field_name.to_s.pluralize) values_for(field_name: field_name).map do |value| diff --git a/spec/iiif_print/configuration_spec.rb b/spec/iiif_print/configuration_spec.rb index c810a9cc..d2ffc883 100644 --- a/spec/iiif_print/configuration_spec.rb +++ b/spec/iiif_print/configuration_spec.rb @@ -151,4 +151,30 @@ expect(function.parameters).to eq([[:keyreq, :object]]) end end + + describe "#iiif_metadata_field_presentation_order" do + subject { config.iiif_metadata_field_presentation_order } + + it { is_expected.to be_a NilClass } + it "allows for an override" do + original = config.iiif_metadata_field_presentation_order + config.iiif_metadata_field_presentation_order = :title + expect(config.iiif_metadata_field_presentation_order).not_to eq original + end + end + + describe "#questioning_authority_fields" do + subject { config.questioning_authority_fields } + + it { is_expected.to be_a Array } + context "by default" do + it { is_expected.to eq ['rights_statement', 'license'] } + end + + it "allows for an override" do + expect do + config.questioning_authority_fields = ['rights_statement', 'license', 'subject'] + end.to change(config, :questioning_authority_fields).from(['rights_statement', 'license']).to(['rights_statement', 'license', 'subject']) + end + end end diff --git a/spec/iiif_print_spec.rb b/spec/iiif_print_spec.rb index 393cef3a..5117bd09 100644 --- a/spec/iiif_print_spec.rb +++ b/spec/iiif_print_spec.rb @@ -45,4 +45,72 @@ end end end + + describe ".fields_for_allinson_flex" do + subject { described_class.fields_for_allinson_flex(fields: fields, sort_order: sort_order) } + let(:sort_order) { [] } + + context "when the fields include an admin only indexing property" do + let(:fields) do + [ + IiifPrint::CollectionFieldShim.new(name: :title, value: "My Title"), + IiifPrint::CollectionFieldShim.new(name: :creator, value: "Hyrax, Sam", indexing: ["admin_only"]) + ] + end + + it "does not include the admin only field" do + # We are mapping from one data structure to another + expect(subject.map(&:name)).to eq([fields.first.name]) + end + end + + context "when the fields include duplicate name properties" do + let(:fields) do + [ + IiifPrint::CollectionFieldShim.new(name: :title, value: "My Title"), + IiifPrint::CollectionFieldShim.new(name: :title, value: "My Other Title") + ] + end + + it "does not include later duplicates" do + expect(subject.map(&:label)).to eq([fields.first.value]) + end + end + + context "when we provide a fields sort order" do + let(:fields) do + [ + IiifPrint::CollectionFieldShim.new(name: :title, value: "My Title"), + IiifPrint::CollectionFieldShim.new(name: :creator, value: "Hyrax, Sam"), + IiifPrint::CollectionFieldShim.new(name: :date_created, value: "2023-05-02") + ] + end + let(:sort_order) { [:creator, :title] } + + it "returns the fields in the order specified and puts unspecified fields last" do + expect(subject.map(&:name)).to eq([:creator, :title, :date_created]) + end + end + end + + describe ".sort_af_fields!" do + let(:fields) { [:title, :creator, :date_created].map { |name| IiifPrint::Field.new(name: name) } } + subject(:sort_af_fields) { described_class.sort_af_fields!(fields, sort_order: sort_order) } + + context "when the sort order is an empty array" do + let(:sort_order) { [] } + + it "returns the fields in the order they were given" do + expect(sort_af_fields).to eq(fields) + end + end + + context "when the sort order specifies some of the fields" do + let(:sort_order) { [:date_created, :title] } + + it "returns the fields in the order specified and puts unspecified fields last" do + expect(sort_af_fields).to eq([:date_created, :title, :creator].map { |name| IiifPrint::Field.new(name: name) }) + end + end + end end