From 849aa7972b36fda1ecdaf5d36ea3184f8ae0682d Mon Sep 17 00:00:00 2001 From: Max Kadel Date: Tue, 8 Oct 2024 16:08:07 +0300 Subject: [PATCH 1/5] Add MLA citation for SCSB items --- Gemfile | 3 + Gemfile.lock | 16 + .../document/citation_component.html.erb | 11 + .../document/citation_component.rb | 13 + .../concerns/blacklight/document/mla.rb | 76 +++++ app/models/solr_document.rb | 3 + app/views/catalog/_citation.html.erb | 4 + app/views/catalog/_previous_next_doc.html.erb | 2 +- .../document/citation_component_spec.rb | 18 ++ spec/features/citation_spec.rb | 46 ++- spec/fixtures/bibdata/9979948663506421.xml | 302 ++++++++++++++++++ spec/models/mla_spec.rb | 53 +++ spec/requests/robots_spec.rb | 2 +- spec/views/catalog/show.html.erb_spec.rb | 15 + 14 files changed, 549 insertions(+), 15 deletions(-) create mode 100644 app/components/orangelight/document/citation_component.html.erb create mode 100644 app/components/orangelight/document/citation_component.rb create mode 100644 app/models/concerns/blacklight/document/mla.rb create mode 100644 app/views/catalog/_citation.html.erb create mode 100644 spec/components/orangelight/document/citation_component_spec.rb create mode 100644 spec/fixtures/bibdata/9979948663506421.xml create mode 100644 spec/models/mla_spec.rb diff --git a/Gemfile b/Gemfile index 642aed9cb..d22a4b68c 100644 --- a/Gemfile +++ b/Gemfile @@ -20,6 +20,9 @@ gem 'bootstrap', '~> 4.6' # In the Capistrano documentation, it has these limited to the development group, and `require: false`` gem 'capistrano', '~> 3.4' gem 'capistrano-passenger' +# support for non-marc citations (e.g. SCSB records) +gem 'citeproc-ruby' +gem 'csl-styles' gem 'ddtrace' # Authentication and authorization gem 'devise' diff --git a/Gemfile.lock b/Gemfile.lock index d5cc0db04..02d421acb 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -179,6 +179,12 @@ GEM regexp_parser (>= 1.5, < 3.0) xpath (~> 3.2) chronic (0.10.2) + citeproc (1.0.10) + namae (~> 1.0) + citeproc-ruby (2.1.0) + citeproc (~> 1.0, >= 1.0.9) + csl (~> 2.0) + observer (< 1.0) coderay (1.1.3) coercible (1.0.0) descendants_tracker (~> 0.0.1) @@ -193,6 +199,11 @@ GEM bigdecimal rexml crass (1.0.6) + csl (2.0.0) + namae (~> 1.0) + rexml + csl-styles (2.0.1) + csl (~> 2.0) csv (3.3.0) datadog-ci (0.8.3) msgpack @@ -392,6 +403,8 @@ GEM msgpack (1.7.2) multi_xml (0.6.0) mutex_m (0.2.0) + namae (1.2.0) + racc (~> 1.7) net-http (0.4.1) uri net-imap (0.4.15) @@ -417,6 +430,7 @@ GEM racc (~> 1.4) nokogiri (1.16.7-x86_64-linux) racc (~> 1.4) + observer (0.1.2) omniauth (2.1.2) hashie (>= 3.4.6) rack (>= 2.2.3) @@ -748,7 +762,9 @@ DEPENDENCIES capistrano-passenger capistrano-rails capybara + citeproc-ruby coveralls_reborn + csl-styles ddtrace devise devise-guests diff --git a/app/components/orangelight/document/citation_component.html.erb b/app/components/orangelight/document/citation_component.html.erb new file mode 100644 index 000000000..7af3dd7e2 --- /dev/null +++ b/app/components/orangelight/document/citation_component.html.erb @@ -0,0 +1,11 @@ +
+

<%= title %>

+ + <% @formats.each do |i18n_key, citation_method| %> +

<%= t(i18n_key) %>

+ <%= @document.send(citation_method).html_safe %> + <% unless @formats.keys.last === i18n_key %> +

+ <% end %> + <% end %> +
diff --git a/app/components/orangelight/document/citation_component.rb b/app/components/orangelight/document/citation_component.rb new file mode 100644 index 000000000..b0e6c91dc --- /dev/null +++ b/app/components/orangelight/document/citation_component.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +class Orangelight::Document::CitationComponent < Blacklight::Document::CitationComponent + DEFAULT_FORMATS = { + 'blacklight.citation.mla': :export_as_mla, + 'blacklight.citation.apa': :export_as_apa_citation_txt, + 'blacklight.citation.chicago': :export_as_chicago_citation_txt + }.freeze + + def initialize(document:, formats: DEFAULT_FORMATS) + super + end +end diff --git a/app/models/concerns/blacklight/document/mla.rb b/app/models/concerns/blacklight/document/mla.rb new file mode 100644 index 000000000..c77339382 --- /dev/null +++ b/app/models/concerns/blacklight/document/mla.rb @@ -0,0 +1,76 @@ +# frozen_string_literal: true + +# Creates an html MLA citation for non-Marc records +module Blacklight::Document::Mla + def self.extended(document) + Blacklight::Document::Mla.register_export_formats(document) + end + + def self.register_export_formats(document) + document.will_export_as(:mla, 'text/html') + end + + def export_as_mla + return export_as_mla_citation_txt if alma? + + cp = CiteProc::Processor.new style: 'modern-language-association', format: 'html' + item = CiteProc::Item.new(properties) + cp.import(item) + cp.render(:bibliography, id:).first + end + + def properties + props = {} + props[:id] = id + props[:edition] = edition if edition + props[:type] = type if type + props[:author] = author if author + props[:title] = title if title + props[:publisher] = publisher if publisher + props[:'publisher-place'] = publisher_place if publisher_place + props[:issued] = issued if issued + props + end + + def type + self[:format]&.first&.downcase + end + + def author + @author ||= begin + family, given = citation_fields_from_solr[:author_citation_display]&.first&.split(', ') + CiteProc::Name.new(family:, given:) if family || given + end + end + + def edition + @edition ||= begin + str = citation_fields_from_solr[:edition_display]&.first + str&.dup&.sub!(/[[:punct:]]?$/, '') + end + end + + def title + @title ||= citation_fields_from_solr[:title_citation_display]&.first + end + + def publisher + @publisher ||= citation_fields_from_solr[:pub_citation_display]&.first&.split(': ').try(:[], 1) + end + + def publisher_place + @publisher_place ||= citation_fields_from_solr[:pub_citation_display]&.first&.split(': ').try(:[], 0) + end + + def issued + @issued ||= citation_fields_from_solr[:pub_date_start_sort] + end + + def citation_fields_from_solr + @citation_fields_from_solr ||= begin + params = { q: "id:#{RSolr.solr_escape(id)}", fl: "author_citation_display, title_citation_display, pub_citation_display, number_of_pages_citation_display, pub_date_start_sort, edition_display" } + solr_response = Blacklight.default_index.connection.get('select', params:) + solr_response["response"]["docs"].first.with_indifferent_access + end + end +end diff --git a/app/models/solr_document.rb b/app/models/solr_document.rb index b5b2aaa31..1a4c3600e 100644 --- a/app/models/solr_document.rb +++ b/app/models/solr_document.rb @@ -52,6 +52,9 @@ class SolrDocument ## Adds JSON-LD use_extension(Blacklight::Document::JsonLd) + ## Adds MLA html + use_extension(Blacklight::Document::Mla) + def identifier_data values = identifiers.each_with_object({}) do |identifier, hsh| hsh[identifier.data_key.to_sym] ||= [] diff --git a/app/views/catalog/_citation.html.erb b/app/views/catalog/_citation.html.erb new file mode 100644 index 000000000..24e761ec9 --- /dev/null +++ b/app/views/catalog/_citation.html.erb @@ -0,0 +1,4 @@ +<%= render Blacklight::System::ModalComponent.new do |component| %> + <% component.with_title { t('blacklight.tools.citation') } %> + <%= render Orangelight::Document::CitationComponent.with_collection(@documents) if @documents.present? %> +<% end %> diff --git a/app/views/catalog/_previous_next_doc.html.erb b/app/views/catalog/_previous_next_doc.html.erb index 291f42675..def2d903b 100644 --- a/app/views/catalog/_previous_next_doc.html.erb +++ b/app/views/catalog/_previous_next_doc.html.erb @@ -18,7 +18,7 @@