From 800a6e5ee215504d1b11dca89facbee985f41f83 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Wed, 4 Oct 2023 14:32:11 -0400 Subject: [PATCH 01/41] Temporarily - pull the schema-4.5 bolognese branch - for development. --- Gemfile | 3 +- Gemfile.lock | 79 ++++++++++++++++++++++++---------------------------- 2 files changed, 38 insertions(+), 44 deletions(-) diff --git a/Gemfile b/Gemfile index fff1d4630..094a93a6c 100644 --- a/Gemfile +++ b/Gemfile @@ -12,7 +12,8 @@ gem "aws-sdk-sqs", "~> 1.3" gem "base32-url", "~> 0.3" gem "batch-loader", "~> 1.4", ">= 1.4.1" gem "bcrypt", "~> 3.1.7" -gem "bolognese", "~> 1.11.0" +# gem "bolognese", "~> 1.11.0" +gem "bolognese", git: 'https://github.com/datacite/bolognese', branch: 'schema-4.5' gem "bootsnap", "~> 1.4", ">= 1.4.4", require: false gem "cancancan", "~> 3.0" gem "commonmarker", "~> 0.23.4" diff --git a/Gemfile.lock b/Gemfile.lock index 3cd8428a1..73534779a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,3 +1,33 @@ +GIT + remote: https://github.com/datacite/bolognese + revision: 05a692152fe25363d8931ecbb9bdafc1d9bf5bc9 + branch: schema-4.5 + specs: + bolognese (1.11.2) + activesupport (>= 4.2.5) + benchmark_methods (~> 0.7) + bibtex-ruby (>= 5.1.0) + builder (~> 3.2, >= 3.2.2) + citeproc-ruby (~> 1.1, >= 1.1.12) + colorize (~> 0.8.1) + concurrent-ruby (~> 1.1, >= 1.1.5) + csl-styles (~> 1.0, >= 1.0.1.10) + edtf (~> 3.0, >= 3.0.4) + gender_detector (~> 0.1.2) + iso8601 (~> 0.9.1) + json-ld-preloaded (~> 3.1, >= 3.1.3) + jsonlint (~> 0.3.0) + loofah (~> 2.0, >= 2.0.3) + maremma (>= 4.9.4, < 5) + namae (~> 1.0) + nokogiri (>= 1.13.2, < 1.14) + oj (~> 3.10) + oj_mimic_json (~> 1.0, >= 1.0.1) + postrank-uri (~> 1.0, >= 1.0.18) + rdf-rdfxml (~> 3.1) + rdf-turtle (~> 3.1) + thor (>= 0.19) + GEM remote: https://rubygems.org/ specs: @@ -113,30 +143,6 @@ GEM latex-decode (~> 0.0) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) - bolognese (1.11.0) - activesupport (>= 4.2.5) - benchmark_methods (~> 0.7) - bibtex-ruby (>= 5.1.0) - builder (~> 3.2, >= 3.2.2) - citeproc-ruby (~> 1.1, >= 1.1.12) - colorize (~> 0.8.1) - concurrent-ruby (~> 1.1, >= 1.1.5) - csl-styles (~> 1.0, >= 1.0.1.10) - edtf (~> 3.0, >= 3.0.4) - gender_detector (~> 0.1.2) - iso8601 (~> 0.9.1) - json-ld-preloaded (~> 3.1, >= 3.1.3) - jsonlint (~> 0.3.0) - loofah (~> 2.0, >= 2.0.3) - maremma (>= 4.9.4, < 5) - namae (~> 1.0) - nokogiri (>= 1.13.2, < 1.14) - oj (~> 3.10) - oj_mimic_json (~> 1.0, >= 1.0.1) - postrank-uri (~> 1.0, >= 1.0.18) - rdf-rdfxml (~> 3.1) - rdf-turtle (~> 3.1) - thor (>= 0.19) bootsnap (1.15.0) msgpack (~> 1.2) builder (3.2.4) @@ -212,7 +218,7 @@ GEM scanf (~> 1.0) sxp (~> 1.2) unicode-types (~> 1.7) - edtf (3.1.0) + edtf (3.1.1) activesupport (>= 3.0, < 8.0) elasticsearch (7.5.0) elasticsearch-api (= 7.5.0) @@ -275,9 +281,6 @@ GEM graphql (~> 1, > 1.8) graphql-errors (0.4.0) graphql (>= 1.6.0, < 2) - haml (5.2.2) - temple (>= 0.8.0) - tilt hashdiff (1.0.1) hashid-rails (1.4.1) activerecord (>= 4.0) @@ -295,7 +298,7 @@ GEM iso8601 (0.9.1) jmespath (1.6.2) json (2.6.3) - json-canonicalization (0.3.1) + json-canonicalization (0.3.2) json-ld (3.2.3) htmlentities (~> 4.3) json-canonicalization (~> 0.3) @@ -475,23 +478,14 @@ GEM link_header (~> 0.0, >= 0.0.8) rdf-aggregate-repo (3.2.1) rdf (~> 3.2) - rdf-rdfa (3.2.0) - haml (~> 5.2) - htmlentities (~> 4.3) - rdf (~> 3.2) - rdf-aggregate-repo (~> 3.2) - rdf-vocab (~> 3.2) - rdf-xsd (~> 3.2) - rdf-rdfxml (3.2.0) + rdf-rdfxml (3.2.2) + builder (~> 3.2) htmlentities (~> 4.3) rdf (~> 3.2) - rdf-rdfa (~> 3.2) rdf-xsd (~> 3.2) rdf-turtle (3.2.1) ebnf (~> 2.3) rdf (~> 3.2) - rdf-vocab (3.2.3) - rdf (~> 3.2, >= 3.2.4) rdf-xsd (3.2.1) rdf (~> 3.2) rexml (~> 3.2) @@ -612,7 +606,6 @@ GEM rdf (~> 3.2) sysrandom (1.0.5) systemu (2.6.5) - temple (0.9.1) terrapin (0.6.0) climate_control (>= 0.0.3, < 1.0) test-prof (0.10.2) @@ -664,7 +657,7 @@ DEPENDENCIES bcrypt (~> 3.1.7) better_errors binding_of_caller - bolognese (~> 1.11.0) + bolognese! bootsnap (~> 1.4, >= 1.4.4) bullet (~> 6.1) byebug @@ -756,4 +749,4 @@ DEPENDENCIES webmock (~> 3.1) BUNDLED WITH - 2.3.20 + 2.4.20 From 71251f74221cb896740fe4ed65a403b0472d79fa Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Wed, 4 Oct 2023 16:16:51 -0400 Subject: [PATCH 02/41] Appease rubocop. --- Gemfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile b/Gemfile index 094a93a6c..73b832080 100644 --- a/Gemfile +++ b/Gemfile @@ -13,7 +13,7 @@ gem "base32-url", "~> 0.3" gem "batch-loader", "~> 1.4", ">= 1.4.1" gem "bcrypt", "~> 3.1.7" # gem "bolognese", "~> 1.11.0" -gem "bolognese", git: 'https://github.com/datacite/bolognese', branch: 'schema-4.5' +gem "bolognese", git: "https://github.com/datacite/bolognese", branch: "schema-4.5" gem "bootsnap", "~> 1.4", ">= 1.4.4", require: false gem "cancancan", "~> 3.0" gem "commonmarker", "~> 0.23.4" From cbf19aee3b086dc2cac57f7abef88c4dcf234f49 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Fri, 6 Oct 2023 09:07:58 -0400 Subject: [PATCH 03/41] Elastic search and misc --- app/models/concerns/crosscitable.rb | 1 + app/models/doi.rb | 33 +++++++++++++++++++++++++---- 2 files changed, 30 insertions(+), 4 deletions(-) diff --git a/app/models/concerns/crosscitable.rb b/app/models/concerns/crosscitable.rb index c794390d2..e0fd93139 100644 --- a/app/models/concerns/crosscitable.rb +++ b/app/models/concerns/crosscitable.rb @@ -119,6 +119,7 @@ def update_xml subjects content_url schema_version + publisher_obj ].map { |a| [a.to_sym, send(a.to_s)] }.to_h. compact diff --git a/app/models/doi.rb b/app/models/doi.rb index f5ed52a02..4631d296f 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -4,7 +4,7 @@ require "benchmark" class Doi < ApplicationRecord - audited only: %i[doi url creators contributors titles publisher publication_year types descriptions container sizes formats version_info language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects schema_version content_url landing_page aasm_state source reason] + audited only: %i[doi url creators contributors titles publisher publication_year types descriptions container sizes formats version_info language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects schema_version content_url landing_page aasm_state source reason publisher_obj] # disable STI self.inheritance_column = :_type_disabled @@ -117,6 +117,7 @@ class Doi < ApplicationRecord validate :check_descriptions, if: :descriptions? validate :check_types, if: :types? validate :check_container, if: :container? + validate :check_publisher_obj, if: :publsher_obj? validate :check_subjects, if: :subjects? validate :check_creators, if: :creators? validate :check_contributors, if: :contributors? @@ -313,7 +314,14 @@ class Doi < ApplicationRecord nameType: { type: :text }, givenName: { type: :text }, familyName: { type: :text }, - } }, + }}, + publisher_obj { type: :object, properties: { + name: { type: :text, fields: { keyword: { type: "keyword" } } }, + publisherIdentifier: { type: :keyword, normalizer: "keyword_lowercase" }, + publisherIdentifierScheme: { type: :keyword }, + schemeUri: { type: :keyword }, + lang: { type: :keyword }, + }} } indexes :types, type: :object, properties: { resourceTypeGeneral: { type: :keyword }, @@ -549,6 +557,13 @@ class Doi < ApplicationRecord indexes :fields_of_science, type: :keyword indexes :fields_of_science_combined, type: :keyword indexes :fields_of_science_repository, type: :keyword + indexes :publisher_obj, type: :object, properties: { + name: { type: :text, fields: { keyword: { type: "keyword" } } }, + publisherIdentifier: { type: :keyword, normalizer: "keyword_lowercase" }, + publisherIdentifierScheme: { type: :keyword }, + schemeUri: { type: :keyword }, + lang: { type: :keyword }, + } end end @@ -638,6 +653,7 @@ def as_indexed_json(_options = {}) "version_ids" => version_ids, "version_of_ids" => version_of_ids, "primary_title" => Array.wrap(primary_title), + "publisher_obj" => publisher_obj, } end @@ -761,7 +777,7 @@ def self.igsn_id_catalog_aggregations end def self.query_fields - ["uid^50", "related_identifiers.relatedIdentifier^3", "titles.title^3", "creator_names^3", "creators.id^3", "publisher^3", "descriptions.description^3", "subjects.subject^3"] + ["uid^50", "related_identifiers.relatedIdentifier^3", "titles.title^3", "creator_names^3", "creators.id^3", "publisher^3", "descriptions.description^3", "subjects.subject^3", "publisher_obj.name^3"] end # return results for one or more ids @@ -910,6 +926,7 @@ def self.query(query, options = {}) query = query.gsub(/citationCount/, "citation_count") query = query.gsub(/viewCount/, "view_count") query = query.gsub(/downloadCount/, "download_count") + query = query.gsub(/publisherObj/, "publisher_obj") query = query.gsub("/", "\\/") end @@ -1170,7 +1187,7 @@ def self.import_one(doi_id: nil, id: nil) end meta = doi.read_datacite(string: string, sandbox: doi.sandbox) - attrs = %w(creators contributors titles publisher publication_year types descriptions container sizes formats language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects content_url version_info).map do |a| + attrs = %w(creators contributors titles publisher publication_year types descriptions container sizes formats language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects content_url version_info publisher_obj).map do |a| [a.to_sym, meta[a]] end.to_h.merge(schema_version: meta["schema_version"] || "http://datacite.org/schema/kernel-4", xml: string, version: doi.version.to_i + 1) @@ -1546,6 +1563,10 @@ def container=(value) write_attribute(:container, value || {}) end + def publsher_obj=(value) + write_attribute(:publsher_obj, value || {}) + end + def types=(value) write_attribute(:types, value || {}) end @@ -1887,6 +1908,10 @@ def check_container errors.add(:container, "Container '#{container}' should be an object instead of a string.") unless container.is_a?(Hash) end + def check_publisher_obj + errors.add(:publsher_obj, "Publisher_obj '#{publisher_obj}' should be an object instead of a string.") unless publisher_obj.is_a?(Hash) + end + def check_language errors.add(:language, "Language #{language} is in an invalid format.") if !language.match?(/^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/) end From a4dc6b72b3839c7dae1b9713c35d41ba47f2d92a Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Fri, 6 Oct 2023 13:00:24 -0400 Subject: [PATCH 04/41] Fix syntax errors. --- app/models/doi.rb | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/app/models/doi.rb b/app/models/doi.rb index 4631d296f..80999d99b 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -117,7 +117,7 @@ class Doi < ApplicationRecord validate :check_descriptions, if: :descriptions? validate :check_types, if: :types? validate :check_container, if: :container? - validate :check_publisher_obj, if: :publsher_obj? + validate :check_publisher_obj, if: :publisher_obj? validate :check_subjects, if: :subjects? validate :check_creators, if: :creators? validate :check_contributors, if: :contributors? @@ -315,13 +315,6 @@ class Doi < ApplicationRecord givenName: { type: :text }, familyName: { type: :text }, }}, - publisher_obj { type: :object, properties: { - name: { type: :text, fields: { keyword: { type: "keyword" } } }, - publisherIdentifier: { type: :keyword, normalizer: "keyword_lowercase" }, - publisherIdentifierScheme: { type: :keyword }, - schemeUri: { type: :keyword }, - lang: { type: :keyword }, - }} } indexes :types, type: :object, properties: { resourceTypeGeneral: { type: :keyword }, @@ -1563,8 +1556,8 @@ def container=(value) write_attribute(:container, value || {}) end - def publsher_obj=(value) - write_attribute(:publsher_obj, value || {}) + def publisher_obj=(value) + write_attribute(:publisher_obj, value || {}) end def types=(value) @@ -1909,7 +1902,7 @@ def check_container end def check_publisher_obj - errors.add(:publsher_obj, "Publisher_obj '#{publisher_obj}' should be an object instead of a string.") unless publisher_obj.is_a?(Hash) + errors.add(:publisher_obj, "Publisher_obj '#{publisher_obj}' should be an object instead of a string.") unless publisher_obj.is_a?(Hash) end def check_language From 02823f2ae4192128110f775f4f344e96e19b487b Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Fri, 6 Oct 2023 15:59:00 -0400 Subject: [PATCH 05/41] Preliminary support for receiving and storing publisher hash values --- app/controllers/datacite_dois_controller.rb | 9 + app/lib/params_sanitizer.rb | 20 ++ app/models/concerns/crosscitable.rb | 5 + app/models/doi.rb | 10 + spec/factories/doi.rb | 8 +- .../files/datacite-example-full-v4.5.xml | 255 ++++++++++++++++++ spec/models/doi_spec.rb | 18 ++ spec/requests/datacite_dois_spec.rb | 176 +++++++++++- 8 files changed, 499 insertions(+), 2 deletions(-) create mode 100644 spec/fixtures/files/datacite-example-full-v4.5.xml diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index 57a55db5a..92221b197 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -787,6 +787,15 @@ def safe_params ParamsSanitizer.sanitize_nameIdentifiers(params[:creators]) ParamsSanitizer.sanitize_nameIdentifiers(params[:contributors]) + # Normalize publisher attribute to hash value + if params.dig(:data, :attributes, :publisher).present? + params[:data][:attributes].merge( + publisher: ParamsSanitizer.normalize_publisher( + params[:data][:attributes][:publisher] + ) + ) + end + p = params.require(:data).permit( :type, diff --git a/app/lib/params_sanitizer.rb b/app/lib/params_sanitizer.rb index b90b24820..cb60364dd 100644 --- a/app/lib/params_sanitizer.rb +++ b/app/lib/params_sanitizer.rb @@ -35,6 +35,15 @@ class ParamsSanitizer :titles, { titles: %i[title titleType lang] }, :publisher, + { + publisher: %i[ + name + publisherIdentifier + publisherIdentifierScheme + schemeUri + lang + ], + }, :publicationYear, :created, :prefix, @@ -287,6 +296,7 @@ def cleanse add_metadata_version(meta) add_landingpage() + #Add regenerate value to params, either from the params themselves or from the line above @params.merge(regenerate: @params[:regenerate] || regenerate).except( # ignore camelCase keys, and read-only keys :confirmDoi, @@ -458,4 +468,14 @@ def self.sanitize_nameIdentifiers(array) end end end + + def self.normalize_publisher(params_publisher_value) + if params_publisher_value.respond_to?(:keys) + params_publisher_value + else + { + "name": params_publisher_value + } + end + end end diff --git a/app/models/concerns/crosscitable.rb b/app/models/concerns/crosscitable.rb index e0fd93139..95f7df184 100644 --- a/app/models/concerns/crosscitable.rb +++ b/app/models/concerns/crosscitable.rb @@ -123,6 +123,11 @@ def update_xml ].map { |a| [a.to_sym, send(a.to_s)] }.to_h. compact + # Insert publisher_obj for publisher to generate XML + if read_attrs.dig(:publisher).present? && publisher_obj.present? + read_attrs[:publisher] = publisher_obj + end + if from.present? send( "read_" + from, diff --git a/app/models/doi.rb b/app/models/doi.rb index 80999d99b..911ba77fc 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -132,6 +132,7 @@ class Doi < ApplicationRecord after_commit :update_url, on: %i[create update] after_commit :update_media, on: %i[create update] + before_validation :update_publisher, if: [ :will_save_change_to_publisher?, :publisher? ] before_validation :update_xml, if: :regenerate before_validation :update_agency before_validation :update_field_of_science @@ -2234,6 +2235,15 @@ def update_types ).compact end + def update_publisher + if publisher_before_type_cast.is_a?(Hash) + self.publisher_obj = publisher_before_type_cast + self.publisher = publisher_before_type_cast.dig(:name) + else + self.publisher_obj = { :name => publisher } + end + end + def self.repair_landing_page(id: nil) if id.blank? Rails.logger.error "[Error] No id provided." diff --git a/spec/factories/doi.rb b/spec/factories/doi.rb index 29a50d86b..708cd6d53 100644 --- a/spec/factories/doi.rb +++ b/spec/factories/doi.rb @@ -90,7 +90,13 @@ descriptions do [{ "description": "Data from: A new malaria agent in African hominids." }] end - publisher { "Dryad Digital Repository" } + publisher { { + "name": "Dryad Digital Repository", + "publisherIdentifier": "https://ror.org/00x6h5n95", + "publisherIdentifierScheme": "ROR", + "schemeUri": "https://ror.org/", + "lang": "en" + } } subjects do [ { "subject": "Phylogeny" }, diff --git a/spec/fixtures/files/datacite-example-full-v4.5.xml b/spec/fixtures/files/datacite-example-full-v4.5.xml new file mode 100644 index 000000000..b6642a58f --- /dev/null +++ b/spec/fixtures/files/datacite-example-full-v4.5.xml @@ -0,0 +1,255 @@ + + + + 10.82433/B09Z-4K37 + + + ExampleFamilyName, ExampleGivenName + ExampleGivenName + ExampleFamilyName + https://orcid.org/0000-0001-5727-2427 + ExampleAffiliation + + + ExampleOrganization + https://ror.org/04wxnsj81 + + + + Example Title + Example Subtitle + Example TranslatedTitle + Example AlternativeTitle + + Example Publisher + 2023 + Example ResourceType + + FOS: Computer and information sciences + Digital curation and preservation + Example Subject + + + + ExampleFamilyName, ExampleGivenName + ExampleGivenName + ExampleFamilyName + https://orcid.org/0000-0001-5727-2427/ + ExampleAffiliation + + + ExampleFamilyName, ExampleGivenName + + + ExampleFamilyName, ExampleGivenName + + + ExampleFamilyName, ExampleGivenName + + + ExampleOrganization + + + ExampleFamilyName, ExampleGivenName + + + ExampleOrganization + + + ExampleFamilyName, ExampleGivenName + + + ExampleFamilyName, ExampleGivenName + + + ExampleFamilyName, ExampleGivenName + + + ExampleFamilyName, ExampleGivenName + + + DataCite + + + International DOI Foundation + + + ExampleFamilyName, ExampleGivenName + + + ExampleFamilyName, ExampleGivenName + + + ExampleContributor + + + ExampleFamilyName, ExampleGivenName + + + ExampleContributor + + + ExampleFamilyName, ExampleGivenName + + + ExampleOrganization + + + ExampleFamilyName, ExampleGivenName + + + + 2023-01-01 + 2023-01-01 + 2023-01-01 + 2022-01-01/2022-12-31 + 2023-01-01 + 2023-01-01 + 2023-01-01 + 2023-01-01 + 2023-01-01 + 2023-01-01 + 2023-01-01 + + en + + 12345 + + + ark:/13030/tqb3kh97gh8w + arXiv:0706.0001 + 2018AGUFM.A24K..07S + 10.1016/j.epsl.2011.11.037 + 9783468111242 + 1562-6865 + 10013/epic.10033 + IECUR0097 + 978-3-905673-82-1 + 0077-5606 + 0A9 2002 12B4A105 7 + 1188-1534 + urn:lsid:ubio.org:namebank:11815 + 12082125 + http://purl.oclc.org/foo/bar + 123456789999 + http://www.heatflow.und.edu/index2.html + urn:nbn:de:101:1-201102033592 + https://w3id.org/games/spec/coil#Coil_Bomb_Die_Of_Age + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + 10.1016/j.epsl.2011.11.037 + + + 1 MB + 90 pages + + + application/xml + text/plain + + 1 + + Creative Commons Attribution 4.0 International + + + Example Abstract + Example Methods + Example SeriesInformation + Example TableOfContents + Example TechnicalInfo + Example Other + + + + Vancouver, British Columbia, Canada + + 49.2827 + -123.1207 + + + -123.27 + -123.02 + 49.195 + 49.315 + + + + 41.991 + -71.032 + + + 42.893 + -69.622 + + + 41.991 + -68.211 + + + 41.090 + -69.622 + + + 41.991 + -71.032 + + + + + + + Example Funder + https://doi.org/10.13039/501100000780 + 12345 + Example AwardTitle + + + + + 1234-5678 + + + ExampleFamilyName, ExampleGivenName + ExampleGivenName + ExampleFamilyName + + + + Example RelatedItem Title + Example RelatedItem TranslatedTitle + + 1990 + 1 + 2 + 1 + 1 + 100 + Example RelatedItem Publisher + Example RelatedItem Edition + + + ExampleFamilyName, ExampleGivenName + ExampleGivenName + ExampleFamilyName + + + + + + \ No newline at end of file diff --git a/spec/models/doi_spec.rb b/spec/models/doi_spec.rb index e58d68bd6..2080c7832 100644 --- a/spec/models/doi_spec.rb +++ b/spec/models/doi_spec.rb @@ -1210,6 +1210,20 @@ expect(subject.publication_year).to eq(2011) end + it "publisher" do + expect(subject.publisher).to eq("Dryad Digital Repository") + end + + it "publisher_obj" do + expect(subject.publisher_obj).to eq({ + "name" => "Dryad Digital Repository", + "publisherIdentifier" => "https://ror.org/00x6h5n95", + "publisherIdentifierScheme" => "ROR", + "schemeUri" => "https://ror.org/", + "lang" => "en" + }) + end + it "schema_version" do expect(subject.schema_version).to eq("http://datacite.org/schema/kernel-4") end @@ -1271,6 +1285,10 @@ expect(xml.dig("publisher")).to eq(publisher) end + it "publisher_obj" do + expect(subject.publisher_obj).to eq({ "name" => publisher }) + end + it "publication_year" do expect(subject.publication_year).to eq(2011) diff --git a/spec/requests/datacite_dois_spec.rb b/spec/requests/datacite_dois_spec.rb index 8d720cc6a..bcaeae226 100755 --- a/spec/requests/datacite_dois_spec.rb +++ b/spec/requests/datacite_dois_spec.rb @@ -1939,6 +1939,13 @@ doc = Nokogiri::XML(Base64.decode64(json.dig("data", "attributes", "xml")), nil, "UTF-8", &:noblanks) expect(doc.at_css("identifier").content).to eq("10.14454/10703") + + expect(Doi.where(doi: "10.14454/10703").first.publisher).to eq("DataCite") + expect(Doi.where(doi: "10.14454/10703").first.publisher_obj).to eq( + { + "name" => "DataCite" + } + ) end end @@ -2563,7 +2570,6 @@ it "updates the record" do patch "/dois/10.14454/8na3-9s47", valid_attributes, headers - p json expect(last_response.status).to eq(201) expect(json.dig("data", "attributes", "url")).to eq("https://ors.datacite.org/doi:/10.14454/8na3-9s47") expect(json.dig("data", "attributes", "doi")).to eq("10.14454/8na3-9s47") @@ -2886,6 +2892,52 @@ end end + context "when the request uses schema 4.5" do + let(:xml) { Base64.strict_encode64(file_fixture("datacite-example-full-v4.5.xml").read) } + let(:doi) { "10.14454/10703" } + let(:valid_attributes) do + { + "data" => { + "type" => "dois", + "attributes" => { + "doi" => doi, + "url" => "http://www.bl.uk/pdf/patspec.pdf", + "xml" => xml, + "event" => "publish", + }, + }, + } + end + + it "creates a Doi" do + post "/dois", valid_attributes, headers + + expect(last_response.status).to eq(201) + expect(json.dig("data", "attributes", "doi")).to eq(doi) + expect(json.dig("data", "attributes", "schemaVersion")).to eq("http://datacite.org/schema/kernel-4") + expect(json.dig("data", "attributes", "state")).to eq("findable") + expect(json.dig("data", "attributes", "publisher")).to eq("Example Publisher") + + doc = Nokogiri::XML(Base64.decode64(json.dig("data", "attributes", "xml")), nil, "UTF-8", &:noblanks) + expect(doc.at_css("publisher").content).to eq("Example Publisher") + expect(doc.at_css("publisher")["publisherIdentifier"]).to eq("https://ror.org/04z8jg394") + expect(doc.at_css("publisher")["publisherIdentifierScheme"]).to eq("ROR") + expect(doc.at_css("publisher")["schemeURI"]).to eq("https://ror.org/") + expect(doc.at_css("publisher")["xml:lang"]).to eq("en") + + expect(Doi.where(doi: "10.14454/10703").first.publisher_obj).to eq( + { + "name" => "Example Publisher", + "publisherIdentifier" => "https://ror.org/04z8jg394", + "publisherIdentifierScheme" => "ROR", + "schemeUri" => "https://ror.org/", + "lang" => "en", + } + ) + expect(Doi.where(doi: doi).first.publisher).to eq("Example Publisher") + end + end + context "when the request uses namespaced xml" do let(:xml) { Base64.strict_encode64(file_fixture("ns0.xml").read) } let(:valid_attributes) do @@ -4051,6 +4103,128 @@ end end + describe "PUT /dois/:id" do + context "update publisher" do + let(:doi) { create(:doi, doi: "10.14454/10703", publisher: nil, publisher_obj: nil, client: client) } + let(:xml) { Base64.strict_encode64(file_fixture("datacite-example-full-v4.5.xml").read) } + + let(:publisher_as_string_attributes) do + { + "data" => { + "type" => "dois", + "attributes" => { + "publisher" => "DataCite", + "event" => "publish", + } + } + } + end + + let(:publisher_as_obj_attributes) do + { + "data" => { + "type" => "dois", + "attributes" => { + "publisher" => { + "name" => "DataCite", + "publisherIdentifier" => "https://ror.org/04wxnsj81", + "publisherIdentifierScheme" => "ROR", + "schemeUri" => "https://ror.org/", + "lang" => "en", + }, + "event" => "publish", + } + } + } + end + + let(:publisher_obj_in_xml) do + { + "data" => { + "type" => "dois", + "attributes" => { + "xml" => xml, + "event" => "publish", + }, + }, + } + end + + it "with publisher as string" do + put "/dois/#{doi.doi}", publisher_as_string_attributes, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data", "attributes", "doi")).to eq(doi.doi) + expect(json.dig("data", "attributes", "schemaVersion")).to eq("http://datacite.org/schema/kernel-4") + expect(json.dig("data", "attributes", "state")).to eq("findable") + expect(json.dig("data", "attributes", "publisher")).to eq("DataCite") + + expect(Doi.where(doi: doi.doi).first.publisher_obj).to eq( + { + "name" => "DataCite", + } + ) + expect(Doi.where(doi: doi.doi).first.publisher).to eq("DataCite") + end + + it "with publisher as object" do + put "/dois/#{doi.doi}", publisher_as_obj_attributes, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data", "attributes", "doi")).to eq(doi.doi) + expect(json.dig("data", "attributes", "schemaVersion")).to eq("http://datacite.org/schema/kernel-4") + expect(json.dig("data", "attributes", "state")).to eq("findable") + expect(json.dig("data", "attributes", "publisher")).to eq("DataCite") + + doc = Nokogiri::XML(Base64.decode64(json.dig("data", "attributes", "xml")), nil, "UTF-8", &:noblanks) + expect(doc.at_css("publisher").content).to eq("DataCite") + expect(doc.at_css("publisher")["publisherIdentifier"]).to eq("https://ror.org/04wxnsj81") + expect(doc.at_css("publisher")["publisherIdentifierScheme"]).to eq("ROR") + expect(doc.at_css("publisher")["schemeURI"]).to eq("https://ror.org/") + expect(doc.at_css("publisher")["xml:lang"]).to eq("en") + + expect(Doi.where(doi: doi.doi).first.publisher_obj).to eq( + { + "name" => "DataCite", + "publisherIdentifier" => "https://ror.org/04wxnsj81", + "publisherIdentifierScheme" => "ROR", + "schemeUri" => "https://ror.org/", + "lang" => "en", + } + ) + expect(Doi.where(doi: doi.doi).first.publisher).to eq("DataCite") + end + + it "with publisher obj in xml" do + put "/dois/#{doi.doi}", publisher_obj_in_xml, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data", "attributes", "doi")).to eq(doi.doi) + expect(json.dig("data", "attributes", "schemaVersion")).to eq("http://datacite.org/schema/kernel-4") + expect(json.dig("data", "attributes", "state")).to eq("findable") + expect(json.dig("data", "attributes", "publisher")).to eq("Example Publisher") + + doc = Nokogiri::XML(Base64.decode64(json.dig("data", "attributes", "xml")), nil, "UTF-8", &:noblanks) + expect(doc.at_css("publisher").content).to eq("Example Publisher") + expect(doc.at_css("publisher")["publisherIdentifier"]).to eq("https://ror.org/04z8jg394") + expect(doc.at_css("publisher")["publisherIdentifierScheme"]).to eq("ROR") + expect(doc.at_css("publisher")["schemeURI"]).to eq("https://ror.org/") + expect(doc.at_css("publisher")["xml:lang"]).to eq("en") + + expect(Doi.where(doi: "10.14454/10703").first.publisher_obj).to eq( + { + "name" => "Example Publisher", + "publisherIdentifier" => "https://ror.org/04z8jg394", + "publisherIdentifierScheme" => "ROR", + "schemeUri" => "https://ror.org/", + "lang" => "en", + } + ) + expect(Doi.where(doi: doi.doi).first.publisher).to eq("Example Publisher") + end + end + end + describe "DELETE /dois/:id" do let(:doi) { create(:doi, client: client, aasm_state: "draft") } From 3ab5c6cfaed5ad845537f38409f6524069ef2b6e Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Sun, 8 Oct 2023 01:24:46 -0400 Subject: [PATCH 06/41] Use updated bolognese from schema-4.5-r2 branch - ref works better than branch name in Gemfile. Mod for publisher_obj. --- Gemfile | 3 ++- Gemfile.lock | 6 +++--- app/models/doi.rb | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index 73b832080..86d4c36e3 100644 --- a/Gemfile +++ b/Gemfile @@ -13,7 +13,8 @@ gem "base32-url", "~> 0.3" gem "batch-loader", "~> 1.4", ">= 1.4.1" gem "bcrypt", "~> 3.1.7" # gem "bolognese", "~> 1.11.0" -gem "bolognese", git: "https://github.com/datacite/bolognese", branch: "schema-4.5" +# gem "bolognese", git: "https://github.com/datacite/bolognese", branch: "schema-4.5" +gem 'bolognese', git: 'https://github.com/datacite/bolognese.git', ref: '51731cb' gem "bootsnap", "~> 1.4", ">= 1.4.4", require: false gem "cancancan", "~> 3.0" gem "commonmarker", "~> 0.23.4" diff --git a/Gemfile.lock b/Gemfile.lock index 73534779a..ec2006418 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ GIT - remote: https://github.com/datacite/bolognese - revision: 05a692152fe25363d8931ecbb9bdafc1d9bf5bc9 - branch: schema-4.5 + remote: https://github.com/datacite/bolognese.git + revision: 51731cb38ef1a35eb58e72e99ff463f1d49201b2 + ref: 51731cb specs: bolognese (1.11.2) activesupport (>= 4.2.5) diff --git a/app/models/doi.rb b/app/models/doi.rb index 911ba77fc..0c240a74a 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -117,7 +117,7 @@ class Doi < ApplicationRecord validate :check_descriptions, if: :descriptions? validate :check_types, if: :types? validate :check_container, if: :container? - validate :check_publisher_obj, if: :publisher_obj? + # validate :check_publisher_obj, if: :publisher_obj? validate :check_subjects, if: :subjects? validate :check_creators, if: :creators? validate :check_contributors, if: :contributors? From 67e5ff4c16364ec413067af9e334e041c829b9ae Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Fri, 13 Oct 2023 15:03:55 -0400 Subject: [PATCH 07/41] Added accessor for publisher in doi model, serializer, and ?publisher=true query parameter. Updated bolognese branch. --- Gemfile | 2 +- Gemfile.lock | 4 +- app/controllers/datacite_dois_controller.rb | 6 +++ app/models/doi.rb | 42 +++++++++++++++------ app/serializers/datacite_doi_serializer.rb | 6 +++ 5 files changed, 46 insertions(+), 14 deletions(-) diff --git a/Gemfile b/Gemfile index 86d4c36e3..61551ba22 100644 --- a/Gemfile +++ b/Gemfile @@ -14,7 +14,7 @@ gem "batch-loader", "~> 1.4", ">= 1.4.1" gem "bcrypt", "~> 3.1.7" # gem "bolognese", "~> 1.11.0" # gem "bolognese", git: "https://github.com/datacite/bolognese", branch: "schema-4.5" -gem 'bolognese', git: 'https://github.com/datacite/bolognese.git', ref: '51731cb' +gem 'bolognese', git: 'https://github.com/datacite/bolognese.git', ref: '4e55843' gem "bootsnap", "~> 1.4", ">= 1.4.4", require: false gem "cancancan", "~> 3.0" gem "commonmarker", "~> 0.23.4" diff --git a/Gemfile.lock b/Gemfile.lock index ec2006418..94a13f2b8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,7 +1,7 @@ GIT remote: https://github.com/datacite/bolognese.git - revision: 51731cb38ef1a35eb58e72e99ff463f1d49201b2 - ref: 51731cb + revision: 4e5584329a66d801adc629da90a01e6fc990d36c + ref: 4e55843 specs: bolognese (1.11.2) activesupport (>= 4.2.5) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index 92221b197..16dea7991 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -196,6 +196,7 @@ def index current_ability: current_ability, detail: params[:detail], affiliation: params[:affiliation], + publisher: params[:publisher], is_collection: options[:is_collection], } @@ -339,6 +340,7 @@ def index detail: params[:detail], composite: params[:composite], affiliation: params[:affiliation], + publisher: params[:publisher], # The cursor link should be an array of values, but we want to encode it into a single string for the URL "page[cursor]" => page[:cursor] ? make_cursor(results) : nil, @@ -359,6 +361,7 @@ def index detail: params[:detail], composite: params[:composite], affiliation: params[:affiliation], + publisher: params[:publisher], is_collection: options[:is_collection], } @@ -459,6 +462,7 @@ def show detail: true, composite: nil, affiliation: params[:affiliation], + publisher: params[:publisher], } render json: DataciteDoiSerializer.new(doi, options).serialized_json, @@ -539,6 +543,7 @@ def create current_ability: current_ability, detail: true, affiliation: params[:affiliation], + publisher: params[:publisher], } render json: DataciteDoiSerializer.new(@doi, options).serialized_json, @@ -597,6 +602,7 @@ def update current_ability: current_ability, detail: true, affiliation: params[:affiliation], + publisher: params[:publisher], } render json: DataciteDoiSerializer.new(@doi, options).serialized_json, diff --git a/app/models/doi.rb b/app/models/doi.rb index 0c240a74a..cc34a1482 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -551,6 +551,7 @@ class Doi < ApplicationRecord indexes :fields_of_science, type: :keyword indexes :fields_of_science_combined, type: :keyword indexes :fields_of_science_repository, type: :keyword +=begin indexes :publisher_obj, type: :object, properties: { name: { type: :text, fields: { keyword: { type: "keyword" } } }, publisherIdentifier: { type: :keyword, normalizer: "keyword_lowercase" }, @@ -558,6 +559,7 @@ class Doi < ApplicationRecord schemeUri: { type: :keyword }, lang: { type: :keyword }, } +=end end end @@ -647,7 +649,7 @@ def as_indexed_json(_options = {}) "version_ids" => version_ids, "version_of_ids" => version_of_ids, "primary_title" => Array.wrap(primary_title), - "publisher_obj" => publisher_obj, + # "publisher_obj" => publisher_obj, } end @@ -771,7 +773,8 @@ def self.igsn_id_catalog_aggregations end def self.query_fields - ["uid^50", "related_identifiers.relatedIdentifier^3", "titles.title^3", "creator_names^3", "creators.id^3", "publisher^3", "descriptions.description^3", "subjects.subject^3", "publisher_obj.name^3"] + # ["uid^50", "related_identifiers.relatedIdentifier^3", "titles.title^3", "creator_names^3", "creators.id^3", "publisher^3", "descriptions.description^3", "subjects.subject^3", "publisher_obj.name^3"] + ["uid^50", "related_identifiers.relatedIdentifier^3", "titles.title^3", "creator_names^3", "creators.id^3", "publisher^3", "descriptions.description^3", "subjects.subject^3"] end # return results for one or more ids @@ -920,7 +923,7 @@ def self.query(query, options = {}) query = query.gsub(/citationCount/, "citation_count") query = query.gsub(/viewCount/, "view_count") query = query.gsub(/downloadCount/, "download_count") - query = query.gsub(/publisherObj/, "publisher_obj") + # query = query.gsub(/publisherObj/, "publisher_obj") query = query.gsub("/", "\\/") end @@ -1181,8 +1184,9 @@ def self.import_one(doi_id: nil, id: nil) end meta = doi.read_datacite(string: string, sandbox: doi.sandbox) - attrs = %w(creators contributors titles publisher publication_year types descriptions container sizes formats language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects content_url version_info publisher_obj).map do |a| - [a.to_sym, meta[a]] + # attrs = %w(creators contributors titles publisher publication_year types descriptions container sizes formats language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects content_url version_info publisher_obj).map do |a| + attrs = %w(creators contributors titles publisher publication_year types descriptions container sizes formats language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects content_url version_info).map do |a| + [a.to_sym, meta[a]] end.to_h.merge(schema_version: meta["schema_version"] || "http://datacite.org/schema/kernel-4", xml: string, version: doi.version.to_i + 1) # update_attributes will trigger validations and Elasticsearch indexing @@ -1557,9 +1561,9 @@ def container=(value) write_attribute(:container, value || {}) end - def publisher_obj=(value) - write_attribute(:publisher_obj, value || {}) - end + #def publisher_obj=(value) + # write_attribute(:publisher_obj, value || {}) + #end def types=(value) write_attribute(:types, value || {}) @@ -1902,9 +1906,9 @@ def check_container errors.add(:container, "Container '#{container}' should be an object instead of a string.") unless container.is_a?(Hash) end - def check_publisher_obj - errors.add(:publisher_obj, "Publisher_obj '#{publisher_obj}' should be an object instead of a string.") unless publisher_obj.is_a?(Hash) - end + # def check_publisher_obj + # errors.add(:publisher_obj, "Publisher_obj '#{publisher_obj}' should be an object instead of a string.") unless publisher_obj.is_a?(Hash) + # end def check_language errors.add(:language, "Language #{language} is in an invalid format.") if !language.match?(/^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/) @@ -2244,6 +2248,19 @@ def update_publisher end end + def publisher + pub = read_attribute('publisher') + pub_obj = read_attribute('publisher_obj') + + return nil if pub.nil? && pub_obj.nil? + + if !pub_obj.nil? + pub_obj + else + return { "name" => pub || "" } + end + end + def self.repair_landing_page(id: nil) if id.blank? Rails.logger.error "[Error] No id provided." @@ -2381,4 +2398,7 @@ def self.add_index_type(options = {}) "Finished updating dois, total #{count}" end + + private + #attr_accessor :publisher_obj end diff --git a/app/serializers/datacite_doi_serializer.rb b/app/serializers/datacite_doi_serializer.rb index 36c897f28..8b2adb6dc 100644 --- a/app/serializers/datacite_doi_serializer.rb +++ b/app/serializers/datacite_doi_serializer.rb @@ -118,6 +118,12 @@ class DataciteDoiSerializer attribute :doi, &:uid + attribute :publisher do |object, params| + # publisher accessor will now always return a publisher object. + # new obj format only if ?publisher=true, otherwise serialize the old format (a string) + params[:publisher] ? object.publisher : ( object.publisher["name"] || nil ) + end + attribute :creators do |object, params| # Always return an array of creators and affiliations # use new array format only if affiliation param present From b54dbbf5e0ea8402710b8f7204c41e00b33c1e2f Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Fri, 13 Oct 2023 16:25:00 -0400 Subject: [PATCH 08/41] Fix to serializer for null publisher. --- app/serializers/datacite_doi_serializer.rb | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/app/serializers/datacite_doi_serializer.rb b/app/serializers/datacite_doi_serializer.rb index 8b2adb6dc..e3563be58 100644 --- a/app/serializers/datacite_doi_serializer.rb +++ b/app/serializers/datacite_doi_serializer.rb @@ -121,7 +121,13 @@ class DataciteDoiSerializer attribute :publisher do |object, params| # publisher accessor will now always return a publisher object. # new obj format only if ?publisher=true, otherwise serialize the old format (a string) - params[:publisher] ? object.publisher : ( object.publisher["name"] || nil ) + + if params[:publisher] + object.publisher ? object.publisher : nil + else + object.publisher ? object.publisher["name"] : nil + end + end attribute :creators do |object, params| From 80b6d5b0767a22f130772948c61f648e2a9e95f6 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Sun, 15 Oct 2023 12:23:41 -0400 Subject: [PATCH 09/41] More fixes. --- app/models/concerns/crosscitable.rb | 3 ++- app/models/doi.rb | 2 +- app/serializers/datacite_doi_serializer.rb | 4 +--- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/app/models/concerns/crosscitable.rb b/app/models/concerns/crosscitable.rb index 95f7df184..8ee240289 100644 --- a/app/models/concerns/crosscitable.rb +++ b/app/models/concerns/crosscitable.rb @@ -119,14 +119,15 @@ def update_xml subjects content_url schema_version - publisher_obj ].map { |a| [a.to_sym, send(a.to_s)] }.to_h. compact # Insert publisher_obj for publisher to generate XML +=begin if read_attrs.dig(:publisher).present? && publisher_obj.present? read_attrs[:publisher] = publisher_obj end +=end if from.present? send( diff --git a/app/models/doi.rb b/app/models/doi.rb index cc34a1482..17ebb9345 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -4,7 +4,7 @@ require "benchmark" class Doi < ApplicationRecord - audited only: %i[doi url creators contributors titles publisher publication_year types descriptions container sizes formats version_info language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects schema_version content_url landing_page aasm_state source reason publisher_obj] + audited only: %i[doi url creators contributors titles publisher publication_year types descriptions container sizes formats version_info language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects schema_version content_url landing_page aasm_state source reason] # disable STI self.inheritance_column = :_type_disabled diff --git a/app/serializers/datacite_doi_serializer.rb b/app/serializers/datacite_doi_serializer.rb index e3563be58..16a674bf4 100644 --- a/app/serializers/datacite_doi_serializer.rb +++ b/app/serializers/datacite_doi_serializer.rb @@ -121,13 +121,11 @@ class DataciteDoiSerializer attribute :publisher do |object, params| # publisher accessor will now always return a publisher object. # new obj format only if ?publisher=true, otherwise serialize the old format (a string) - - if params[:publisher] + if params && (params[:publisher] == 'true') object.publisher ? object.publisher : nil else object.publisher ? object.publisher["name"] : nil end - end attribute :creators do |object, params| From d3dff8c0995e30e3256c444b6b59959ed5f99e93 Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Mon, 16 Oct 2023 11:05:56 -0400 Subject: [PATCH 10/41] Fixes to serializer for publisher param when data is from ES; refinement to publisher handling in Doi model and controller --- app/controllers/datacite_dois_controller.rb | 9 - app/lib/params_sanitizer.rb | 11 - app/models/doi.rb | 9 +- app/serializers/datacite_doi_serializer.rb | 12 +- spec/models/doi_spec.rb | 12 +- spec/requests/datacite_dois_spec.rb | 251 +++++++++++++++++++- 6 files changed, 255 insertions(+), 49 deletions(-) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index 16dea7991..66efea029 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -793,15 +793,6 @@ def safe_params ParamsSanitizer.sanitize_nameIdentifiers(params[:creators]) ParamsSanitizer.sanitize_nameIdentifiers(params[:contributors]) - # Normalize publisher attribute to hash value - if params.dig(:data, :attributes, :publisher).present? - params[:data][:attributes].merge( - publisher: ParamsSanitizer.normalize_publisher( - params[:data][:attributes][:publisher] - ) - ) - end - p = params.require(:data).permit( :type, diff --git a/app/lib/params_sanitizer.rb b/app/lib/params_sanitizer.rb index cb60364dd..6d912b1b4 100644 --- a/app/lib/params_sanitizer.rb +++ b/app/lib/params_sanitizer.rb @@ -296,7 +296,6 @@ def cleanse add_metadata_version(meta) add_landingpage() - #Add regenerate value to params, either from the params themselves or from the line above @params.merge(regenerate: @params[:regenerate] || regenerate).except( # ignore camelCase keys, and read-only keys :confirmDoi, @@ -468,14 +467,4 @@ def self.sanitize_nameIdentifiers(array) end end end - - def self.normalize_publisher(params_publisher_value) - if params_publisher_value.respond_to?(:keys) - params_publisher_value - else - { - "name": params_publisher_value - } - end - end end diff --git a/app/models/doi.rb b/app/models/doi.rb index 17ebb9345..0b3a3065d 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -576,7 +576,7 @@ def as_indexed_json(_options = {}) "creator_names" => creator_names, "titles" => Array.wrap(titles), "descriptions" => Array.wrap(descriptions), - "publisher" => publisher, + "publisher" => publisher && publisher["name"], "client_id" => client_id, "provider_id" => provider_id, "consortium_id" => consortium_id, @@ -2240,11 +2240,12 @@ def update_types end def update_publisher - if publisher_before_type_cast.is_a?(Hash) + if publisher_before_type_cast.respond_to?(:to_hash) self.publisher_obj = publisher_before_type_cast self.publisher = publisher_before_type_cast.dig(:name) - else - self.publisher_obj = { :name => publisher } + elsif publisher_before_type_cast.respond_to?(:to_str) + self.publisher_obj = { :name => publisher_before_type_cast } + self.publisher = publisher_before_type_cast end end diff --git a/app/serializers/datacite_doi_serializer.rb b/app/serializers/datacite_doi_serializer.rb index 16a674bf4..f7718dc9b 100644 --- a/app/serializers/datacite_doi_serializer.rb +++ b/app/serializers/datacite_doi_serializer.rb @@ -122,9 +122,17 @@ class DataciteDoiSerializer # publisher accessor will now always return a publisher object. # new obj format only if ?publisher=true, otherwise serialize the old format (a string) if params && (params[:publisher] == 'true') - object.publisher ? object.publisher : nil + if object.publisher.respond_to?(:to_hash) + object.publisher + elsif object.publisher.respond_to?(:to_str) + { "name" => object.publisher } + end else - object.publisher ? object.publisher["name"] : nil + if object.publisher.respond_to?(:to_hash) + object.publisher["name"] + elsif object.publisher.respond_to?(:to_str) + object.publisher + end end end diff --git a/spec/models/doi_spec.rb b/spec/models/doi_spec.rb index 2080c7832..f335ac341 100644 --- a/spec/models/doi_spec.rb +++ b/spec/models/doi_spec.rb @@ -1211,11 +1211,7 @@ end it "publisher" do - expect(subject.publisher).to eq("Dryad Digital Repository") - end - - it "publisher_obj" do - expect(subject.publisher_obj).to eq({ + expect(subject.publisher).to eq({ "name" => "Dryad Digital Repository", "publisherIdentifier" => "https://ror.org/00x6h5n95", "publisherIdentifierScheme" => "ROR", @@ -1279,16 +1275,12 @@ end it "publisher" do - expect(subject.publisher).to eq(publisher) + expect(subject.publisher).to eq({ "name" => publisher }) xml = Maremma.from_xml(subject.xml).fetch("resource", {}) expect(xml.dig("publisher")).to eq(publisher) end - it "publisher_obj" do - expect(subject.publisher_obj).to eq({ "name" => publisher }) - end - it "publication_year" do expect(subject.publication_year).to eq(2011) diff --git a/spec/requests/datacite_dois_spec.rb b/spec/requests/datacite_dois_spec.rb index bcaeae226..de3a10134 100755 --- a/spec/requests/datacite_dois_spec.rb +++ b/spec/requests/datacite_dois_spec.rb @@ -224,6 +224,59 @@ next_link = next_link_absolute.path + "?" + next_link_absolute.query expect(next_link).to eq("/dois?fields%5Bdois%5D=id%2Csubjects&page%5Bnumber%5D=2&page%5Bsize%5D=2") end + + it "returns publisher objects when publisher param is set to true" do + get "/dois?publisher=true", nil, headers + + expect(last_response.status).to eq(200) + json["data"].each do |doi| + expect(doi.dig("attributes", "publisher")).to eq( + { + "name" => "Dryad Digital Repository", + } + ) + end + end + end + + describe "GET /dois with publisher param", elasticsearch: true do + let!(:doi) { create(:doi, client: client, publisher: nil) } + + it "returns nil publisher when publisher param is not set" do + get "/dois?publisher=true", nil, headers + + expect(last_response.status).to eq(200) + json["data"].each do |doi| + expect(doi.dig("attributes", "publisher")).to eq(nil) + end + end + + it "returns nil publisher when publisher param is set to true" do + get "/dois?publisher=true", nil, headers + + expect(last_response.status).to eq(200) + json["data"].each do |doi| + expect(doi.dig("attributes", "publisher")).to eq(nil) + end + end + end + + describe "GET /dois/:id with publisher param", elasticsearch: true do + let!(:doi) { create(:doi, client: client, publisher: nil) } + + it "returns nil publisher when publisher param is not set" do + get "/dois/#{doi.doi}?publisher=true", nil, headers + + expect(last_response.status).to eq(200) + expect(json.dig("attributes", "publisher")).to eq(nil) + end + + it "returns nil publisher when publisher param is set to true" do + get "/dois/#{doi.doi}?publisher=true", nil, headers + + expect(last_response.status).to eq(200) + expect(json.dig("attributes", "publisher")).to eq(nil) + end end describe "GET /dois with filter", elasticsearch: true do @@ -589,6 +642,29 @@ expect(json.dig("data", "attributes", "creators", 0, "nameIdentifiers")).to eq([{ "nameIdentifier" => "http://viaf.org/viaf/4934600", "nameIdentifierScheme" => "VIAF" }]) end end + + context "when the publisher param is set to true" do + it "returns the Doi" do + get "/dois/#{doi.doi}?publisher=true", nil, headers + + expect(last_response.status).to eq(200) + result = json.dig("data") + + expect(result.dig("attributes", "doi")).to eq(doi.doi.downcase) + expect(result.dig("attributes", "titles")).to eq(doi.titles) + expect(result.dig("attributes", "identifiers")).to eq([{ "identifier" => "pk-1234", "identifierType" => "publisher ID" }]) + expect(result.dig("attributes", "alternateIdentifiers")).to eq([{ "alternateIdentifier" => "pk-1234", "alternateIdentifierType" => "publisher ID" }]) + expect(result.dig("attributes", "publisher")).to eq( + { + "name" => "Dryad Digital Repository", + "publisherIdentifier" => "https://ror.org/00x6h5n95", + "publisherIdentifierScheme" => "ROR", + "schemeUri" => "https://ror.org/", + "lang" => "en" + } + ) + end + end end describe "GET /dois for dissertations", elasticsearch: true, vcr: true do @@ -1940,8 +2016,7 @@ doc = Nokogiri::XML(Base64.decode64(json.dig("data", "attributes", "xml")), nil, "UTF-8", &:noblanks) expect(doc.at_css("identifier").content).to eq("10.14454/10703") - expect(Doi.where(doi: "10.14454/10703").first.publisher).to eq("DataCite") - expect(Doi.where(doi: "10.14454/10703").first.publisher_obj).to eq( + expect(Doi.where(doi: "10.14454/10703").first.publisher).to eq( { "name" => "DataCite" } @@ -2925,7 +3000,25 @@ expect(doc.at_css("publisher")["schemeURI"]).to eq("https://ror.org/") expect(doc.at_css("publisher")["xml:lang"]).to eq("en") - expect(Doi.where(doi: "10.14454/10703").first.publisher_obj).to eq( + expect(Doi.where(doi: "10.14454/10703").first.publisher).to eq( + { + "name" => "Example Publisher", + "publisherIdentifier" => "https://ror.org/04z8jg394", + "publisherIdentifierScheme" => "ROR", + "schemeUri" => "https://ror.org/", + "lang" => "en", + } + ) + end + + it "creates a Doi with publisher param set to true" do + post "/dois?publisher=true", valid_attributes, headers + + expect(last_response.status).to eq(201) + expect(json.dig("data", "attributes", "doi")).to eq(doi) + expect(json.dig("data", "attributes", "schemaVersion")).to eq("http://datacite.org/schema/kernel-4") + expect(json.dig("data", "attributes", "state")).to eq("findable") + expect(json.dig("data", "attributes", "publisher")).to eq( { "name" => "Example Publisher", "publisherIdentifier" => "https://ror.org/04z8jg394", @@ -2934,7 +3027,76 @@ "lang" => "en", } ) - expect(Doi.where(doi: doi).first.publisher).to eq("Example Publisher") + end + end + + context "when the request is valid with publisher as a hash" do + let(:valid_attributes) do + { + "data" => { + "type" => "dois", + "attributes" => { + "doi" => "10.14454/10703", + "url" => "http://www.bl.uk/pdf/patspec.pdf", + "types" => { "resourceTypeGeneral" => "Text" }, + "titles" => [{ "title" => "Eating your own Dog Food" }], + "publisher" => { + "name" => "DataCite", + "publisherIdentifier" => "https://ror.org/04wxnsj81", + "publisherIdentifierScheme" => "ROR", + "schemeUri" => "https://ror.org/", + "lang" => "en", + }, + "publicationYear" => 2016, + "creators" => [{ "familyName" => "Fenner", "givenName" => "Martin", "nameIdentifiers" => [{ "nameIdentifier" => "https://orcid.org/0000-0003-1419-2405", "nameIdentifierScheme" => "ORCID", "schemeUri" => "https://orcid.org" }], "name" => "Fenner, Martin", "nameType" => "Personal" }], + "event" => "publish", + }, + }, + } + end + + it "creates a Doi with publisher param not set" do + post "/dois", valid_attributes, headers + + expect(last_response.status).to eq(201) + expect(json.dig("data", "attributes", "url")).to eq("http://www.bl.uk/pdf/patspec.pdf") + expect(json.dig("data", "attributes", "doi")).to eq("10.14454/10703") + expect(json.dig("data", "attributes", "titles")).to eq([{ "title" => "Eating your own Dog Food" }]) + expect(json.dig("data", "attributes", "creators")).to eq([{ "affiliation" => [], "familyName" => "Fenner", "givenName" => "Martin", "nameIdentifiers" => [{ "nameIdentifier" => "https://orcid.org/0000-0003-1419-2405", "nameIdentifierScheme" => "ORCID", "schemeUri" => "https://orcid.org" }], "name" => "Fenner, Martin", "nameType" => "Personal" }]) + expect(json.dig("data", "attributes", "publisher")).to eq("DataCite") + expect(json.dig("data", "attributes", "publicationYear")).to eq(2016) + expect(json.dig("data", "attributes", "state")).to eq("findable") + + expect(Doi.where(doi: "10.14454/10703").first.publisher).to eq( + { + "name" => "DataCite", + "publisherIdentifier" => "https://ror.org/04wxnsj81", + "publisherIdentifierScheme" => "ROR", + "schemeUri" => "https://ror.org/", + "lang" => "en", + } + ) + end + + it "creates a Doi with publisher param set to true" do + post "/dois?publisher=true", valid_attributes, headers + + expect(last_response.status).to eq(201) + expect(json.dig("data", "attributes", "url")).to eq("http://www.bl.uk/pdf/patspec.pdf") + expect(json.dig("data", "attributes", "doi")).to eq("10.14454/10703") + expect(json.dig("data", "attributes", "titles")).to eq([{ "title" => "Eating your own Dog Food" }]) + expect(json.dig("data", "attributes", "creators")).to eq([{ "affiliation" => [], "familyName" => "Fenner", "givenName" => "Martin", "nameIdentifiers" => [{ "nameIdentifier" => "https://orcid.org/0000-0003-1419-2405", "nameIdentifierScheme" => "ORCID", "schemeUri" => "https://orcid.org" }], "name" => "Fenner, Martin", "nameType" => "Personal" }]) + expect(json.dig("data", "attributes", "publisher")).to eq( + { + "name" => "DataCite", + "publisherIdentifier" => "https://ror.org/04wxnsj81", + "publisherIdentifierScheme" => "ROR", + "schemeUri" => "https://ror.org/", + "lang" => "en", + } + ) + expect(json.dig("data", "attributes", "publicationYear")).to eq(2016) + expect(json.dig("data", "attributes", "state")).to eq("findable") end end @@ -4105,7 +4267,7 @@ describe "PUT /dois/:id" do context "update publisher" do - let(:doi) { create(:doi, doi: "10.14454/10703", publisher: nil, publisher_obj: nil, client: client) } + let(:doi) { create(:doi, doi: "10.14454/10703", publisher: nil, client: client) } let(:xml) { Base64.strict_encode64(file_fixture("datacite-example-full-v4.5.xml").read) } let(:publisher_as_string_attributes) do @@ -4159,12 +4321,25 @@ expect(json.dig("data", "attributes", "state")).to eq("findable") expect(json.dig("data", "attributes", "publisher")).to eq("DataCite") - expect(Doi.where(doi: doi.doi).first.publisher_obj).to eq( + expect(Doi.where(doi: doi.doi).first.publisher).to eq( + { + "name" => "DataCite", + } + ) + end + + it "with publisher as string with publisher param set to true" do + put "/dois/#{doi.doi}?publisher=true", publisher_as_string_attributes, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data", "attributes", "doi")).to eq(doi.doi) + expect(json.dig("data", "attributes", "schemaVersion")).to eq("http://datacite.org/schema/kernel-4") + expect(json.dig("data", "attributes", "state")).to eq("findable") + expect(json.dig("data", "attributes", "publisher")).to eq( { "name" => "DataCite", } ) - expect(Doi.where(doi: doi.doi).first.publisher).to eq("DataCite") end it "with publisher as object" do @@ -4183,7 +4358,25 @@ expect(doc.at_css("publisher")["schemeURI"]).to eq("https://ror.org/") expect(doc.at_css("publisher")["xml:lang"]).to eq("en") - expect(Doi.where(doi: doi.doi).first.publisher_obj).to eq( + expect(Doi.where(doi: doi.doi).first.publisher).to eq( + { + "name" => "DataCite", + "publisherIdentifier" => "https://ror.org/04wxnsj81", + "publisherIdentifierScheme" => "ROR", + "schemeUri" => "https://ror.org/", + "lang" => "en", + } + ) + end + + it "with publisher as object with publisher param set to true" do + put "/dois/#{doi.doi}?publisher=true", publisher_as_obj_attributes, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data", "attributes", "doi")).to eq(doi.doi) + expect(json.dig("data", "attributes", "schemaVersion")).to eq("http://datacite.org/schema/kernel-4") + expect(json.dig("data", "attributes", "state")).to eq("findable") + expect(json.dig("data", "attributes", "publisher")).to eq( { "name" => "DataCite", "publisherIdentifier" => "https://ror.org/04wxnsj81", @@ -4192,7 +4385,6 @@ "lang" => "en", } ) - expect(Doi.where(doi: doi.doi).first.publisher).to eq("DataCite") end it "with publisher obj in xml" do @@ -4211,7 +4403,25 @@ expect(doc.at_css("publisher")["schemeURI"]).to eq("https://ror.org/") expect(doc.at_css("publisher")["xml:lang"]).to eq("en") - expect(Doi.where(doi: "10.14454/10703").first.publisher_obj).to eq( + expect(Doi.where(doi: "10.14454/10703").first.publisher).to eq( + { + "name" => "Example Publisher", + "publisherIdentifier" => "https://ror.org/04z8jg394", + "publisherIdentifierScheme" => "ROR", + "schemeUri" => "https://ror.org/", + "lang" => "en", + } + ) + end + + it "with publisher obj in xml with publisher param set to true" do + put "/dois/#{doi.doi}?publisher=true", publisher_obj_in_xml, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data", "attributes", "doi")).to eq(doi.doi) + expect(json.dig("data", "attributes", "schemaVersion")).to eq("http://datacite.org/schema/kernel-4") + expect(json.dig("data", "attributes", "state")).to eq("findable") + expect(json.dig("data", "attributes", "publisher")).to eq( { "name" => "Example Publisher", "publisherIdentifier" => "https://ror.org/04z8jg394", @@ -4220,7 +4430,6 @@ "lang" => "en", } ) - expect(Doi.where(doi: doi.doi).first.publisher).to eq("Example Publisher") end end end @@ -4545,7 +4754,15 @@ expect(last_response.status).to eq(200) data = Maremma.from_xml(last_response.body).to_h.fetch("resource", {}) expect(data.dig("xmlns")).to eq("http://datacite.org/schema/kernel-4") - expect(data.dig("publisher")).to eq("Dryad Digital Repository") + expect(data.dig("publisher")).to eq( + { + "__content__" => "Dryad Digital Repository", + "publisherIdentifier" => "https://ror.org/00x6h5n95", + "publisherIdentifierScheme" => "ROR", + "schemeURI" => "https://ror.org/", + "xml:lang" => "en" + } + ) expect(data.dig("titles", "title")).to eq("Data from: A new malaria agent in African hominids.") end end @@ -4557,7 +4774,15 @@ expect(last_response.status).to eq(200) data = Maremma.from_xml(last_response.body).to_h.fetch("resource", {}) expect(data.dig("xmlns")).to eq("http://datacite.org/schema/kernel-4") - expect(data.dig("publisher")).to eq("Dryad Digital Repository") + expect(data.dig("publisher")).to eq( + { + "__content__" => "Dryad Digital Repository", + "publisherIdentifier" => "https://ror.org/00x6h5n95", + "publisherIdentifierScheme" => "ROR", + "schemeURI" => "https://ror.org/", + "xml:lang" => "en" + } + ) expect(data.dig("titles", "title")).to eq("Data from: A new malaria agent in African hominids.") end end From b907405461e7e2e4b1206bcbeb1a24a12db823d0 Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Mon, 16 Oct 2023 11:35:31 -0400 Subject: [PATCH 11/41] Normalization for publisher-as-hash in GraphQL WorkType --- app/graphql/types/doi_item.rb | 10 +++++++++- spec/graphql/types/work_type_spec.rb | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/app/graphql/types/doi_item.rb b/app/graphql/types/doi_item.rb index a652a8b5a..c885076f7 100644 --- a/app/graphql/types/doi_item.rb +++ b/app/graphql/types/doi_item.rb @@ -524,6 +524,14 @@ def identifiers end end + def publisher + if object.publisher.respond_to?(:to_hash) + object.publisher["name"] + elsif object.publisher.respond_to?(:to_str) + object.publisher + end + end + def bibtex pages = if object.container.to_h["firstPage"].present? @@ -854,7 +862,7 @@ def citeproc_hsh "volume" => object.container.to_h["volume"], "issue" => object.container.to_h["issue"], "page" => page, - "publisher" => object.publisher, + "publisher" => object.publisher["name"] || object.publisher, "title" => parse_attributes(object.titles, content: "title", first: true), "URL" => object.url, "version" => object.version_info, diff --git a/spec/graphql/types/work_type_spec.rb b/spec/graphql/types/work_type_spec.rb index 22e45bf30..4bd5f76bb 100644 --- a/spec/graphql/types/work_type_spec.rb +++ b/spec/graphql/types/work_type_spec.rb @@ -58,6 +58,7 @@ identifierType title } + publisher bibtex xml schemaOrg @@ -90,6 +91,9 @@ expect(response.dig("data", "work", "id")).to eq( "https://handle.stage.datacite.org/#{work.doi.downcase}", ) + expect(response.dig("data", "work", "publisher")).to eq( + "Dryad Digital Repository", + ) bibtex = BibTeX.parse(response.dig("data", "work", "bibtex")).to_a(quotes: ""). @@ -331,6 +335,7 @@ nodes { id doi + publisher creators{ type } @@ -514,6 +519,9 @@ expect( response.dig("data", "works", "nodes", 0, "creators", 1, "type"), ).to be nil + expect( + response.dig("data", "works", "nodes", 0, "publisher"), + ).to eq("Dryad Digital Repository") end_cursor = response.dig("data", "works", "pageInfo", "endCursor") response = From b5e47c80925a5f2e845b2524f748e0718af77ef6 Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Thu, 19 Oct 2023 12:28:55 -0400 Subject: [PATCH 12/41] Support for publisher hash in WorkSerializer; test corrections for bolognese changes with Schema 4.5 and affiliation fixes (4a29b935017fa27545f21be877b8fb18d0f31dcc) --- app/models/doi.rb | 3 - app/serializers/work_serializer.rb | 8 +- spec/concerns/crosscitable_spec.rb | 114 +++++++++++++++++++++++----- spec/requests/datacite_dois_spec.rb | 19 ++++- spec/requests/index_spec.rb | 20 ++++- 5 files changed, 138 insertions(+), 26 deletions(-) diff --git a/app/models/doi.rb b/app/models/doi.rb index 0b3a3065d..479fb2416 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -2399,7 +2399,4 @@ def self.add_index_type(options = {}) "Finished updating dois, total #{count}" end - - private - #attr_accessor :publisher_obj end diff --git a/app/serializers/work_serializer.rb b/app/serializers/work_serializer.rb index 7474791c4..9a295268b 100644 --- a/app/serializers/work_serializer.rb +++ b/app/serializers/work_serializer.rb @@ -67,7 +67,13 @@ class WorkSerializer Array.wrap(object.descriptions).first.to_h.fetch("description", nil) end - attribute :container_title, &:publisher + attribute :container_title do |object| + if object.publisher.respond_to?(:to_hash) + object.publisher["name"] + elsif object.publisher.respond_to?(:to_str) + object.publisher + end + end attribute :resource_type_subtype do |object| object.types.to_h.fetch("resourceType", nil) diff --git a/spec/concerns/crosscitable_spec.rb b/spec/concerns/crosscitable_spec.rb index e9a41ef42..5491e5831 100644 --- a/spec/concerns/crosscitable_spec.rb +++ b/spec/concerns/crosscitable_spec.rb @@ -199,7 +199,11 @@ ) expect(meta["titles"]).to eq([{ "title" => "Eating your own Dog Food" }]) expect(meta["publication_year"]).to eq("2016") - expect(meta["publisher"]).to eq("DataCite") + expect(meta["publisher"]).to eq( + { + "name" => "DataCite" + } + ) end it "from schema 3" do @@ -222,7 +226,11 @@ [{ "title" => "Data from: A new malaria agent in African hominids." }], ) expect(meta["publication_year"]).to eq("2011") - expect(meta["publisher"]).to eq("Dryad Digital Repository") + expect(meta["publisher"]).to eq( + { + "name" => "Dryad Digital Repository" + } + ) end it "from schema 2.2" do @@ -263,7 +271,11 @@ ], ) expect(meta["publication_year"]).to eq("2010") - expect(meta["publisher"]).to eq("Springer") + expect(meta["publisher"]).to eq( + { + "name" => "Springer" + } + ) end it "from schema 4 missing creators" do @@ -276,7 +288,11 @@ expect(meta["creators"]).to be_empty expect(meta["titles"]).to eq([{ "title" => "Eating your own Dog Food" }]) expect(meta["publication_year"]).to eq("2016") - expect(meta["publisher"]).to eq("DataCite") + expect(meta["publisher"]).to eq( + { + "name" => "DataCite" + } + ) end it "from namespaced xml" do @@ -322,7 +338,11 @@ ], ) expect(meta["publication_year"]).to eq("2014") - expect(meta["publisher"]).to eq("eLife Sciences Publications, Ltd") + expect(meta["publisher"]).to eq( + { + "name" => "eLife Sciences Publications, Ltd" + } + ) expect(meta["container"]).to eq( "firstPage" => "e01567", "identifier" => "2050-084X", @@ -361,7 +381,11 @@ ], ) expect(meta["publication_year"]).to eq("2014") - expect(meta["publisher"]).to eq("eLife Sciences Publications, Ltd") + expect(meta["publisher"]).to eq( + { + "name" => "eLife Sciences Publications, Ltd" + } + ) expect(meta["container"]).to eq( "firstPage" => "e01567", "identifier" => "2050-084X", @@ -421,7 +445,11 @@ ], ) expect(meta["publication_year"]).to eq("2014") - expect(meta["publisher"]).to eq("{eLife} Sciences Organisation, Ltd.") + expect(meta["publisher"]).to eq( + { + "name" => "{eLife} Sciences Organisation, Ltd." + } + ) expect(meta["container"]).to eq( "identifier" => "2050-084X", "identifierType" => "ISSN", @@ -456,7 +484,11 @@ ], ) expect(meta["publication_year"]).to eq("2014") - expect(meta["publisher"]).to eq("(:unav)") + expect(meta["publisher"]).to eq( + { + "name" => "(:unav)" + } + ) expect(meta["container"]).to eq( "title" => "eLife", "type" => "Journal", "volume" => "3", ) @@ -488,7 +520,11 @@ [{ "title" => "R Interface to the DataONE REST API" }], ) expect(meta["publication_year"]).to eq("2016") - expect(meta["publisher"]).to eq("https://cran.r-project.org") + expect(meta["publisher"]).to eq( + { + "name" => "https://cran.r-project.org" + } + ) end it "from schema_org" do @@ -514,7 +550,11 @@ ) expect(meta["titles"]).to eq([{ "title" => "Eating your own Dog Food" }]) expect(meta["publication_year"]).to eq("2016") - expect(meta["publisher"]).to eq("DataCite") + expect(meta["publisher"]).to eq( + { + "name" => "DataCite" + } + ) end it "from schema_org url" do @@ -540,7 +580,11 @@ ], ) expect(meta["publication_year"]).to eq("2014") - expect(meta["publisher"]).to eq("PANGAEA") + expect(meta["publisher"]).to eq( + { + "name" => "PANGAEA" + } + ) expect(meta["schema_version"]).to eq(nil) end end @@ -576,7 +620,11 @@ [{ "title" => "Data from: A new malaria agent in African hominids." }], ) expect(meta["publication_year"]).to eq("2011") - expect(meta["publisher"]).to eq("Dryad Digital Repository") + expect(meta["publisher"]).to eq( + { + "name" => "Dryad Digital Repository" + } + ) end it "from schema 2.2" do @@ -615,7 +663,11 @@ ], ) expect(meta["publication_year"]).to eq("2010") - expect(meta["publisher"]).to eq("Springer") + expect(meta["publisher"]).to eq( + { + "name" => "Springer" + } + ) end it "from schema 4 missing creators" do @@ -626,7 +678,11 @@ expect(meta["creators"]).to be_empty expect(meta["titles"]).to eq([{ "title" => "Eating your own Dog Food" }]) expect(meta["publication_year"]).to eq("2016") - expect(meta["publisher"]).to eq("DataCite") + expect(meta["publisher"]).to eq( + { + "name" => "DataCite" + } + ) end it "from crossref" do @@ -656,7 +712,11 @@ ], ) expect(meta["publication_year"]).to eq("2014") - expect(meta["publisher"]).to eq("eLife Sciences Publications, Ltd") + expect(meta["publisher"]).to eq( + { + "name" => "eLife Sciences Publications, Ltd" + } + ) expect(meta["container"]).to eq( "firstPage" => "e01567", "identifier" => "2050-084X", @@ -688,7 +748,11 @@ ], ) expect(meta["publication_year"]).to eq("2014") - expect(meta["publisher"]).to eq("{eLife} Sciences Organisation, Ltd.") + expect(meta["publisher"]).to eq( + { + "name" => "{eLife} Sciences Organisation, Ltd." + } + ) expect(meta["container"]).to eq( "identifier" => "2050-084X", "identifierType" => "ISSN", @@ -721,7 +785,11 @@ ], ) expect(meta["publication_year"]).to eq("2014") - expect(meta["publisher"]).to eq("(:unav)") + expect(meta["publisher"]).to eq( + { + "name" => "(:unav)" + } + ) expect(meta["container"]).to eq( "title" => "eLife", "type" => "Journal", "volume" => "3", ) @@ -751,7 +819,11 @@ [{ "title" => "R Interface to the DataONE REST API" }], ) expect(meta["publication_year"]).to eq("2016") - expect(meta["publisher"]).to eq("https://cran.r-project.org") + expect(meta["publisher"]).to eq( + { + "name" => "https://cran.r-project.org" + } + ) end it "from schema_org" do @@ -775,7 +847,11 @@ ) expect(meta["titles"]).to eq([{ "title" => "Eating your own Dog Food" }]) expect(meta["publication_year"]).to eq("2016") - expect(meta["publisher"]).to eq("DataCite") + expect(meta["publisher"]).to eq( + { + "name" => "DataCite" + } + ) end end end diff --git a/spec/requests/datacite_dois_spec.rb b/spec/requests/datacite_dois_spec.rb index de3a10134..1ac80cd2f 100755 --- a/spec/requests/datacite_dois_spec.rb +++ b/spec/requests/datacite_dois_spec.rb @@ -2384,7 +2384,7 @@ "name" => "Miller, Elizabeth", "nameIdentifiers" => [{ "nameIdentifier" => "https://orcid.org/0000-0001-5000-0007", "nameIdentifierScheme" => "ORCID", "schemeUri" => "https://orcid.org" }], "nameType" => "Personal") - expect(json.dig("data", "attributes", "creators")[1]).to eq("affiliation" => [{ "affiliationIdentifierScheme" => "ROR", "affiliationIdentifier" => "https://ror.org/05gq02987", "name" => "Brown University" }, { "affiliationIdentifierScheme" => "GRID", "affiliationIdentifier" => "https://grid.ac/institutes/grid.268117.b", "name" => "Wesleyan University" }], + expect(json.dig("data", "attributes", "creators")[1]).to eq("affiliation" => [{ "affiliationIdentifierScheme" => "ROR", "affiliationIdentifier" => "https://ror.org/05gq02987", "name" => "Brown University" }, { "affiliationIdentifierScheme" => "GRID", "affiliationIdentifier" => "https://grid.ac/institutes/grid.268117.b", "schemeUri" => "https://grid.ac/institutes/", "name" => "Wesleyan University" }], "familyName" => "Carberry", "givenName" => "Josiah", "name" => "Carberry, Josiah", @@ -2986,12 +2986,29 @@ it "creates a Doi" do post "/dois", valid_attributes, headers + pp json expect(last_response.status).to eq(201) expect(json.dig("data", "attributes", "doi")).to eq(doi) expect(json.dig("data", "attributes", "schemaVersion")).to eq("http://datacite.org/schema/kernel-4") expect(json.dig("data", "attributes", "state")).to eq("findable") expect(json.dig("data", "attributes", "publisher")).to eq("Example Publisher") + expect(json.dig("data", "attributes", "relatedIdentifiers", 34)).to eq( + { + "relatedIdentifier" => "10.1016/j.epsl.2011.11.037", + "relatedIdentifierType" => "DOI", + "relationType" => "Collects", + "resourceTypeGeneral" => "Other", + } + ) + expect(json.dig("data", "attributes", "relatedIdentifiers", 35)).to eq( + { + "relatedIdentifier" => "10.1016/j.epsl.2011.11.037", + "relatedIdentifierType" => "DOI", + "relationType" => "IsCollectedBy", + "resourceTypeGeneral" => "Other" + } + ) doc = Nokogiri::XML(Base64.decode64(json.dig("data", "attributes", "xml")), nil, "UTF-8", &:noblanks) expect(doc.at_css("publisher").content).to eq("Example Publisher") diff --git a/spec/requests/index_spec.rb b/spec/requests/index_spec.rb index e960d0a77..a3679beae 100644 --- a/spec/requests/index_spec.rb +++ b/spec/requests/index_spec.rb @@ -47,7 +47,15 @@ expect(last_response.status).to eq(200) data = Maremma.from_xml(last_response.body).to_h.fetch("resource", {}) expect(data.dig("xmlns")).to eq("http://datacite.org/schema/kernel-4") - expect(data.dig("publisher")).to eq("Dryad Digital Repository") + expect(data.dig("publisher")).to eq( + { + "__content__" => "Dryad Digital Repository", + "publisherIdentifier" => "https://ror.org/00x6h5n95", + "publisherIdentifierScheme" => "ROR", + "schemeURI" => "https://ror.org/", + "xml:lang" => "en" + } + ) expect(data.dig("titles", "title")).to eq( "Data from: A new malaria agent in African hominids.", ) @@ -61,7 +69,15 @@ expect(last_response.status).to eq(200) data = Maremma.from_xml(last_response.body).to_h.fetch("resource", {}) expect(data.dig("xmlns")).to eq("http://datacite.org/schema/kernel-4") - expect(data.dig("publisher")).to eq("Dryad Digital Repository") + expect(data.dig("publisher")).to eq( + { + "__content__" => "Dryad Digital Repository", + "publisherIdentifier" => "https://ror.org/00x6h5n95", + "publisherIdentifierScheme" => "ROR", + "schemeURI" => "https://ror.org/", + "xml:lang" => "en" + } + ) expect(data.dig("titles", "title")).to eq( "Data from: A new malaria agent in African hominids.", ) From 4ba23fa3d8d7890c969b6addb3fe045c3d2e86b3 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Mon, 23 Oct 2023 13:18:43 -0400 Subject: [PATCH 13/41] Update bolognese gem (from bolognese schema-4.5 branch) --- Gemfile | 3 +-- Gemfile.lock | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/Gemfile b/Gemfile index bafb92016..99352f880 100644 --- a/Gemfile +++ b/Gemfile @@ -13,8 +13,7 @@ gem "base32-url", "~> 0.3" gem "batch-loader", "~> 1.4", ">= 1.4.1" gem "bcrypt", "~> 3.1.7" # gem "bolognese", "~> 1.11.0" -# gem "bolognese", git: "https://github.com/datacite/bolognese", branch: "schema-4.5" -gem 'bolognese', git: 'https://github.com/datacite/bolognese.git', ref: '4e55843' +gem "bolognese", git: "https://github.com/datacite/bolognese", branch: "schema-4.5" gem "bootsnap", "~> 1.4", ">= 1.4.4", require: false gem "cancancan", "~> 3.0" gem "commonmarker", "~> 0.23.4" diff --git a/Gemfile.lock b/Gemfile.lock index abb9caba0..617257108 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,9 +1,9 @@ GIT - remote: https://github.com/datacite/bolognese.git - revision: 4e5584329a66d801adc629da90a01e6fc990d36c - ref: 4e55843 + remote: https://github.com/datacite/bolognese + revision: 7b602b596bbbcda3cd8d222cfec46417aa488132 + branch: schema-4.5 specs: - bolognese (1.11.2) + bolognese (1.11.4) activesupport (>= 4.2.5) benchmark_methods (~> 0.7) bibtex-ruby (>= 5.1.0) From c462c44b0e2198faaf0bfcd8b76b3f8677274d22 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Tue, 24 Oct 2023 15:19:11 -0400 Subject: [PATCH 14/41] Make publisher_obj private. --- app/models/doi.rb | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/app/models/doi.rb b/app/models/doi.rb index 2faa2e66d..5f7420a2f 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -2423,4 +2423,16 @@ def handleResourceType(types) types.to_h["resourceTypeGeneral"] end end + + private + + # Make the publisher_obj attribute private. + def publisher_obj + self[:publisher_obj] + end + + def publisher_obj=(value) + write_attribute(:publisher_obj, value) + end + end From 28b07dda01468520889c651626ccdd3bac412e00 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Wed, 25 Oct 2023 13:16:44 -0400 Subject: [PATCH 15/41] Allow publisher=true to available options for validate (and affiliation=true, as well) --- app/controllers/datacite_dois_controller.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index 66efea029..cb51cb006 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -515,7 +515,11 @@ def validate options = {} options[:include] = @include options[:is_collection] = false - options[:params] = { current_ability: current_ability } + options[:params] = { + current_ability: current_ability, + affiliation: params[:affiliation], + publisher: params[:publisher] + } render json: DataciteDoiSerializer.new(@doi, options).serialized_json, status: :ok From eb0e99af6b7a396b755756c9f59e91c6deba8fd4 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Wed, 25 Oct 2023 17:28:20 -0400 Subject: [PATCH 16/41] First installment of migration script (publisher => publisher_obj). Modeled after migration scripts for affiliations. --- app/jobs/doi_convert_publisher_by_id_job.rb | 14 +++++++ app/models/doi.rb | 41 ++++++++++++++++++++- lib/tasks/doi.rake | 8 ++++ 3 files changed, 62 insertions(+), 1 deletion(-) create mode 100644 app/jobs/doi_convert_publisher_by_id_job.rb diff --git a/app/jobs/doi_convert_publisher_by_id_job.rb b/app/jobs/doi_convert_publisher_by_id_job.rb new file mode 100644 index 000000000..7e839db35 --- /dev/null +++ b/app/jobs/doi_convert_publisher_by_id_job.rb @@ -0,0 +1,14 @@ +# frozen_string_literal: true + +class DoiConvertPublisherByIdJob < ApplicationJob + queue_as :lupo_background + + rescue_from ActiveJob::DeserializationError, + Elasticsearch::Transport::Transport::Errors::BadRequest do |error| + Rails.logger.error error.message + end + + def perform(options = {}) + Doi.convert_publisher_by_id(options) + end +end diff --git a/app/models/doi.rb b/app/models/doi.rb index 5f7420a2f..d6162872b 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -1467,6 +1467,45 @@ def self.convert_affiliation_by_id(options = {}) count end + def self.convert_publishers(options = {}) + from_id = (options[:from_id] || Doi.minimum(:id)).to_i + until_id = (options[:until_id] || Doi.maximum(:id)).to_i + + # get every id between from_id and until_id + (from_id..until_id).step(500).each do |id| + DoiConvertPublisherByIdJob.perform_later(options.merge(id: id)) + Rails.logger.info "Queued converting publisher to publisher_obj for DOIs with IDs starting with #{id}." unless Rails.env.test? + end + + "Queued converting #{(from_id..until_id).to_a.length} publishers." + end + + def self.convert_publisher_by_id(options = {}) + return nil if options[:id].blank? + + id = options[:id].to_i + count = 0 + + Doi.where(id: id..(id + 499)).find_each do |doi| + should_update = true + + if should_update + Doi.auditing_enabled = false + doi.update_columns(publisher_obj: doi.publisher) + Doi.auditing_enabled = true + + count += 1 + end + end + + Rails.logger.info "[MySQL] Converted publishers for #{count} DOIs with IDs #{id} - #{id + 499}." if count > 0 + + count + rescue TypeError, ActiveRecord::ActiveRecordError, ActiveRecord::LockWaitTimeout => e + Rails.logger.error "[MySQL] Error converting publishers for DOIs with IDs #{id} - #{id + 499}: #{e.message}." + count + end + def self.convert_containers(options = {}) from_id = (options[:from_id] || Doi.minimum(:id)).to_i until_id = (options[:until_id] || Doi.maximum(:id)).to_i @@ -2269,7 +2308,7 @@ def publisher return nil if pub.nil? && pub_obj.nil? - if !pub_obj.nil? + if !(pub_obj.nil? || pub_obj.empty?) pub_obj else return { "name" => pub || "" } diff --git a/lib/tasks/doi.rake b/lib/tasks/doi.rake index 12edc6677..828aafc9b 100644 --- a/lib/tasks/doi.rake +++ b/lib/tasks/doi.rake @@ -245,6 +245,14 @@ namespace :doi do puts Doi.convert_affiliations(from_id: from_id, until_id: until_id) end + desc "Convert publishers to new format" + task convert_publishers: :environment do + from_id = (ENV["FROM_ID"] || Doi.minimum(:id)).to_i + until_id = (ENV["UNTIL_ID"] || Doi.maximum(:id)).to_i + + puts Doi.convert_publishers(from_id: from_id, until_id: until_id) + end + desc "Convert containers to new format" task convert_containers: :environment do from_id = (ENV["FROM_ID"] || Doi.minimum(:id)).to_i From 856e49542cd4d60293411d9e2bea0e0ee7fec06d Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Thu, 26 Oct 2023 10:56:53 -0400 Subject: [PATCH 17/41] Change private to protected on publisher_obj accessors. --- app/models/doi.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/doi.rb b/app/models/doi.rb index d6162872b..2be3f3754 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -2463,7 +2463,7 @@ def handleResourceType(types) end end - private + protected # Make the publisher_obj attribute private. def publisher_obj From a069e3d8304d8b226dea78cd2f2422edee3cdaf9 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Fri, 27 Oct 2023 20:37:44 -0400 Subject: [PATCH 18/41] Mods for activities endpoint. --- app/controllers/activities_controller.rb | 9 ++++ app/models/doi.rb | 2 +- app/serializers/activity_serializer.rb | 55 +++++++++++++++++++++++- 3 files changed, 63 insertions(+), 3 deletions(-) diff --git a/app/controllers/activities_controller.rb b/app/controllers/activities_controller.rb index e14a5059d..8b044b377 100644 --- a/app/controllers/activities_controller.rb +++ b/app/controllers/activities_controller.rb @@ -69,6 +69,9 @@ def index end, }.compact options[:is_collection] = true + options[:params] = { + publisher: params[:publisher], + } render json: ActivitySerializer.new(results, options).serialized_json, status: :ok @@ -105,6 +108,9 @@ def index }.compact options[:include] = @include options[:is_collection] = true + options[:params] = { + publisher: params[:publisher], + } render json: ActivitySerializer.new(results, options).serialized_json, status: :ok @@ -129,6 +135,9 @@ def show options = {} options[:include] = @include options[:is_collection] = false + options[:params] = { + publisher: params[:publisher], + } render json: ActivitySerializer.new(@activity, options).serialized_json, status: :ok diff --git a/app/models/doi.rb b/app/models/doi.rb index 2be3f3754..b70e32045 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -4,7 +4,7 @@ require "benchmark" class Doi < ApplicationRecord - audited only: %i[doi url creators contributors titles publisher publication_year types descriptions container sizes formats version_info language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects schema_version content_url landing_page aasm_state source reason] + audited only: %i[doi url creators contributors titles publisher publisher_obj publication_year types descriptions container sizes formats version_info language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects schema_version content_url landing_page aasm_state source reason] # disable STI self.inheritance_column = :_type_disabled diff --git a/app/serializers/activity_serializer.rb b/app/serializers/activity_serializer.rb index 45f4e4093..13940fc53 100644 --- a/app/serializers/activity_serializer.rb +++ b/app/serializers/activity_serializer.rb @@ -11,8 +11,59 @@ class ActivitySerializer "prov:wasDerivedFrom", "prov:wasAttributedTo", :action, - :version, - :changes + :version + + attribute :changes do |object, params| + changes = object._source.changes + pub = changes.publisher + pub_obj = changes.publisher_obj + + ret = changes + + if object._source.action == 'update' + if (pub || pub_obj) + if params[:publisher] == 'true' + if !pub_obj + changes.publisher = + [ + { "name": pub[0] }, + { "name": pub[1] }, + ] + else + changes.publisher = changes.publisher_obj + end + else + if !pub + changes.publisher = [ pub_obj[0].name, pub_obj[1].name ] + end + end + + ret = changes + end + elsif object._source.action == 'create' + if (pub || pub_obj) + if params[:publisher] == 'true' + if !pub_obj + changes.publisher = { "name": pub } + else + changes.publisher = changes.publisher_obj + end + else + if !pub + changes.publisher = pub_obj.name + end + end + + ret = changes + end + end + + if pub_obj + changes.delete("publisher_obj") + end + + ret + end attribute "prov:wasDerivedFrom", &:was_derived_from From ddfd286a5d9c0c2b8d1dc6cf37ef6d68b384c248 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Sat, 28 Oct 2023 01:51:37 -0400 Subject: [PATCH 19/41] Mods for activities endpoint. Made publisher_obj accessors public to appease audited gem. --- app/models/doi.rb | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/app/models/doi.rb b/app/models/doi.rb index b70e32045..d5f64492b 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -2462,16 +2462,4 @@ def handleResourceType(types) types.to_h["resourceTypeGeneral"] end end - - protected - - # Make the publisher_obj attribute private. - def publisher_obj - self[:publisher_obj] - end - - def publisher_obj=(value) - write_attribute(:publisher_obj, value) - end - end From 703bb6595eba23f8f84507bebf881da46b9d2d4e Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Sun, 29 Oct 2023 12:44:23 -0400 Subject: [PATCH 20/41] Tests for activities endpoint - publishers flag. --- spec/requests/activities_spec.rb | 56 ++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/spec/requests/activities_spec.rb b/spec/requests/activities_spec.rb index 84f184c4c..5af98fdea 100644 --- a/spec/requests/activities_spec.rb +++ b/spec/requests/activities_spec.rb @@ -178,4 +178,60 @@ end end end + + describe "query activities - when the publisher param is not 'true'", elasticsearch: true do + let!(:doi) { create(:doi, client: client) } + let!(:other_doi) { create(:doi, client: client) } + + before do + DataciteDoi.import + Activity.import + sleep 2 + end + + context "query by doi" do + it "returns the activities" do + get "/activities?datacite-doi-id=#{doi.doi.downcase}", + nil, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data").length).to eq(1) + expect(json.dig("meta", "total")).to eq(1) + expect(json.dig("data", 0, "attributes", "action")).to eq("create") + expect(json.dig("data", 0, "attributes", "changes", "publisher")).to eq("Dryad Digital Repository") + end + end + end + + describe "query activities - when the publisher param is set to true", elasticsearch: true do + let!(:doi) { create(:doi, client: client) } + let!(:other_doi) { create(:doi, client: client) } + + before do + DataciteDoi.import + Activity.import + sleep 2 + end + + context "query by doi" do + it "returns the activities" do + get "/activities?publisher=true&datacite-doi-id=#{doi.doi.downcase}", + nil, headers + + expect(last_response.status).to eq(200) + expect(json.dig("data").length).to eq(1) + expect(json.dig("meta", "total")).to eq(1) + expect(json.dig("data", 0, "attributes", "action")).to eq("create") + expect(json.dig("data", 0, "attributes", "changes", "publisher")).to eq( + { + "lang" => "en", + "name" => "Dryad Digital Repository", + "schemeUri" => "https://ror.org/", + "publisherIdentifier" => "https://ror.org/00x6h5n95", + "publisherIdentifierScheme" => "ROR" + } + ) + end + end + end end From dc9c611f028acad29329678c81319a62c973d35f Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Wed, 1 Nov 2023 01:26:54 -0400 Subject: [PATCH 21/41] Validation for publisher_obj (activerecord_json_validator). --- app/models/doi.rb | 19 +++++++++++-------- app/models/schemas/doi/publisher.json | 12 ++++++++++++ 2 files changed, 23 insertions(+), 8 deletions(-) create mode 100644 app/models/schemas/doi/publisher.json diff --git a/app/models/doi.rb b/app/models/doi.rb index d5f64492b..2d9fed171 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -4,6 +4,7 @@ require "benchmark" class Doi < ApplicationRecord + PUBLISHER_JSON_SCHEMA = "#{Rails.root}/app/models/schemas/doi/publisher.json" audited only: %i[doi url creators contributors titles publisher publisher_obj publication_year types descriptions container sizes formats version_info language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects schema_version content_url landing_page aasm_state source reason] # disable STI @@ -103,6 +104,12 @@ class Doi < ApplicationRecord validates_presence_of :doi validates_presence_of :url, if: Proc.new { |doi| doi.is_registered_or_findable? } + validates :publisher_obj, if: :publisher_obj?, + json: { + message: ->(errors) { errors }, + schema: PUBLISHER_JSON_SCHEMA + } + # from https://www.crossref.org/blog/dois-and-matching-regular-expressions/ but using uppercase validates_format_of :doi, with: /\A10\.\d{4,5}\/[-._;()\/:a-zA-Z0-9*~$=]+\z/, on: :create validates_format_of :url, with: /\A(ftp|http|https):\/\/\S+/, if: :url?, message: "URL is not valid" @@ -117,7 +124,7 @@ class Doi < ApplicationRecord validate :check_descriptions, if: :descriptions? validate :check_types, if: :types? validate :check_container, if: :container? - # validate :check_publisher_obj, if: :publisher_obj? + validate :check_publisher, if: :publisher? validate :check_subjects, if: :subjects? validate :check_creators, if: :creators? validate :check_contributors, if: :contributors? @@ -1614,10 +1621,6 @@ def container=(value) write_attribute(:container, value || {}) end - #def publisher_obj=(value) - # write_attribute(:publisher_obj, value || {}) - #end - def types=(value) write_attribute(:types, value || {}) end @@ -1959,9 +1962,9 @@ def check_container errors.add(:container, "Container '#{container}' should be an object instead of a string.") unless container.is_a?(Hash) end - # def check_publisher_obj - # errors.add(:publisher_obj, "Publisher_obj '#{publisher_obj}' should be an object instead of a string.") unless publisher_obj.is_a?(Hash) - # end + def check_publisher + errors.add(:publisher, "Publisher '#{publisher}' should be an object instead of a string.") unless publisher.is_a?(Hash) + end def check_language errors.add(:language, "Language #{language} is in an invalid format.") if !language.match?(/^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$/) diff --git a/app/models/schemas/doi/publisher.json b/app/models/schemas/doi/publisher.json new file mode 100644 index 000000000..3b8fcc7c2 --- /dev/null +++ b/app/models/schemas/doi/publisher.json @@ -0,0 +1,12 @@ +{ + "type": "object", + "$schema": "http://json-schema.org/draft-04/schema#", + "properties": { + "name": { "type": "string" }, + "publisherIdentifier": { "type": "string" }, + "publisherIdentifierScheme": { "type": "string" }, + "schemeUri": { "type": "string" }, + "xml:lang": { "type": "string" } + }, + "additionalProperties": true +} From 14cb361345220c7dcc4ab207c3ef68b55ac9d169 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Thu, 2 Nov 2023 21:42:25 -0400 Subject: [PATCH 22/41] Mods to publisher/publisher_obj. (activerecord_json_validator). --- app/models/doi.rb | 2 +- app/models/schemas/doi/publisher.json | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/models/doi.rb b/app/models/doi.rb index 2d9fed171..06c38a885 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -104,7 +104,7 @@ class Doi < ApplicationRecord validates_presence_of :doi validates_presence_of :url, if: Proc.new { |doi| doi.is_registered_or_findable? } - validates :publisher_obj, if: :publisher_obj?, + validates :publisher_obj, if: :publisher?, json: { message: ->(errors) { errors }, schema: PUBLISHER_JSON_SCHEMA diff --git a/app/models/schemas/doi/publisher.json b/app/models/schemas/doi/publisher.json index 3b8fcc7c2..6a1c76b6a 100644 --- a/app/models/schemas/doi/publisher.json +++ b/app/models/schemas/doi/publisher.json @@ -6,7 +6,7 @@ "publisherIdentifier": { "type": "string" }, "publisherIdentifierScheme": { "type": "string" }, "schemeUri": { "type": "string" }, - "xml:lang": { "type": "string" } + "lang": { "type": "string" } }, - "additionalProperties": true + "additionalProperties": false } From a1cc1a90455e64f3d766880dea57dc1f28564c39 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Fri, 3 Nov 2023 16:24:33 -0400 Subject: [PATCH 23/41] Clean blank and null properties from publisher parameters in datacite_dois_controller.rb --- app/controllers/datacite_dois_controller.rb | 4 ++++ app/models/doi.rb | 2 ++ 2 files changed, 6 insertions(+) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index cb51cb006..595676107 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -794,6 +794,10 @@ def safe_params end end + if params.dig(:data, :attributes, :publisher).present? && params.dig(:data, :attributes, :publisher).respond_to?(:to_hash) + params[:data][:attributes][:publisher].compact_blank! + end + ParamsSanitizer.sanitize_nameIdentifiers(params[:creators]) ParamsSanitizer.sanitize_nameIdentifiers(params[:contributors]) diff --git a/app/models/doi.rb b/app/models/doi.rb index 06c38a885..850d32438 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -104,11 +104,13 @@ class Doi < ApplicationRecord validates_presence_of :doi validates_presence_of :url, if: Proc.new { |doi| doi.is_registered_or_findable? } +=begin validates :publisher_obj, if: :publisher?, json: { message: ->(errors) { errors }, schema: PUBLISHER_JSON_SCHEMA } +=end # from https://www.crossref.org/blog/dois-and-matching-regular-expressions/ but using uppercase validates_format_of :doi, with: /\A10\.\d{4,5}\/[-._;()\/:a-zA-Z0-9*~$=]+\z/, on: :create From c104c9d337ff94ca69763a959f383914aff1657e Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Sat, 4 Nov 2023 12:01:20 -0400 Subject: [PATCH 24/41] Revert back original to publisher_obj validation. --- app/models/doi.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/models/doi.rb b/app/models/doi.rb index bed811279..036041cb5 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -104,13 +104,11 @@ class Doi < ApplicationRecord validates_presence_of :doi validates_presence_of :url, if: Proc.new { |doi| doi.is_registered_or_findable? } -=begin - validates :publisher_obj, if: :publisher?, + validates :publisher_obj, if: :publisher_obj?, json: { message: ->(errors) { errors }, schema: PUBLISHER_JSON_SCHEMA } -=end # from https://www.crossref.org/blog/dois-and-matching-regular-expressions/ but using uppercase validates_format_of :doi, with: /\A10\.\d{4,5}\/[-._;()\/:a-zA-Z0-9*~$=]+\z/, on: :create From be0bbd3cb184c42aa63819bede46fc1f2f94d368 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Tue, 7 Nov 2023 01:55:38 -0500 Subject: [PATCH 25/41] Allow blank/null publisher_obj properties. --- app/controllers/datacite_dois_controller.rb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index 595676107..cb51cb006 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -794,10 +794,6 @@ def safe_params end end - if params.dig(:data, :attributes, :publisher).present? && params.dig(:data, :attributes, :publisher).respond_to?(:to_hash) - params[:data][:attributes][:publisher].compact_blank! - end - ParamsSanitizer.sanitize_nameIdentifiers(params[:creators]) ParamsSanitizer.sanitize_nameIdentifiers(params[:contributors]) From e685e0456537a588127cd65c8351ca012ab4ecd3 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Tue, 7 Nov 2023 14:11:14 -0500 Subject: [PATCH 26/41] Validation. --- app/controllers/datacite_dois_controller.rb | 4 ++++ app/models/doi.rb | 10 +++++----- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index cb51cb006..4d763fed9 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -797,6 +797,10 @@ def safe_params ParamsSanitizer.sanitize_nameIdentifiers(params[:creators]) ParamsSanitizer.sanitize_nameIdentifiers(params[:contributors]) + if params.dig(:data, :attributes, :publisher).present? && params.dig(:data, :attributes, :publisher).respond_to?(:to_hash) + params[:data][:attributes][:publisher].compact! + end + p = params.require(:data).permit( :type, diff --git a/app/models/doi.rb b/app/models/doi.rb index 036041cb5..9dcefd346 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -104,11 +104,11 @@ class Doi < ApplicationRecord validates_presence_of :doi validates_presence_of :url, if: Proc.new { |doi| doi.is_registered_or_findable? } - validates :publisher_obj, if: :publisher_obj?, - json: { - message: ->(errors) { errors }, - schema: PUBLISHER_JSON_SCHEMA - } + validates :publisher_obj, if: :publisher_obj? && Proc.new { |doi| doi.validatable? }, + json: { + message: ->(errors) { errors }, + schema: PUBLISHER_JSON_SCHEMA + } # from https://www.crossref.org/blog/dois-and-matching-regular-expressions/ but using uppercase validates_format_of :doi, with: /\A10\.\d{4,5}\/[-._;()\/:a-zA-Z0-9*~$=]+\z/, on: :create From 676ded16590c71d40b12d6ccc1658d516df54929 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Thu, 9 Nov 2023 13:40:16 -0500 Subject: [PATCH 27/41] Move processing of null parameters over to update_publisher. --- Gemfile.lock | 2 +- app/controllers/datacite_dois_controller.rb | 4 --- app/models/doi.rb | 28 +++++++++++++++------ 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index d0f943877..2c054d38d 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: https://github.com/datacite/bolognese - revision: ca90d2c7e33fdd76d0ee7ad00434740a324166df + revision: 714d71a4a2169d1880ccb296df3ca1331e0e1a83 branch: schema-4.5 specs: bolognese (1.11.5) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index 4d763fed9..cb51cb006 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -797,10 +797,6 @@ def safe_params ParamsSanitizer.sanitize_nameIdentifiers(params[:creators]) ParamsSanitizer.sanitize_nameIdentifiers(params[:contributors]) - if params.dig(:data, :attributes, :publisher).present? && params.dig(:data, :attributes, :publisher).respond_to?(:to_hash) - params[:data][:attributes][:publisher].compact! - end - p = params.require(:data).permit( :type, diff --git a/app/models/doi.rb b/app/models/doi.rb index 9dcefd346..60609591d 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -104,11 +104,14 @@ class Doi < ApplicationRecord validates_presence_of :doi validates_presence_of :url, if: Proc.new { |doi| doi.is_registered_or_findable? } - validates :publisher_obj, if: :publisher_obj? && Proc.new { |doi| doi.validatable? }, - json: { - message: ->(errors) { errors }, - schema: PUBLISHER_JSON_SCHEMA - } +validates :publisher_obj, if: :publisher_obj? && Proc.new { |doi| + doi.validatable? && + !(doi.publisher.blank? || doi.publisher.all?(nil)) +}, +json: { + message: ->(errors) { errors }, + schema: PUBLISHER_JSON_SCHEMA +} # from https://www.crossref.org/blog/dois-and-matching-regular-expressions/ but using uppercase validates_format_of :doi, with: /\A10\.\d{4,5}\/[-._;()\/:a-zA-Z0-9*~$=]+\z/, on: :create @@ -2297,8 +2300,19 @@ def update_types def update_publisher if publisher_before_type_cast.respond_to?(:to_hash) - self.publisher_obj = publisher_before_type_cast - self.publisher = publisher_before_type_cast.dig(:name) + if !(publisher_before_type_cast.blank? || publisher_before_type_cast.values.all?(nil)) + self.publisher_obj = { + :name => publisher_before_type_cast.fetch(:name, nil), + :lang => publisher_before_type_cast.fetch(:lang, nil), + :schemeUri => publisher_before_type_cast.fetch(:schemeUri, nil), + :publisherIdentifier => publisher_before_type_cast.fetch(:publisherIdentifier, nil), + :publisherIdentifierScheme => publisher_before_type_cast.fetch(:publisherIdentifierScheme, nil) + }.compact + self.publisher = publisher_before_type_cast.dig(:name) + else + self.publisher_obj = nil + self.publisher = nil + end elsif publisher_before_type_cast.respond_to?(:to_str) self.publisher_obj = { :name => publisher_before_type_cast } self.publisher = publisher_before_type_cast From c0a98ca09d734ee5a980c5ccd1ccec4d95685751 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Mon, 13 Nov 2023 17:23:19 -0500 Subject: [PATCH 28/41] Appease rubocop. --- app/controllers/datacite_dois_controller.rb | 2 +- app/models/concerns/crosscitable.rb | 2 +- app/models/doi.rb | 40 ++++++++++----------- app/serializers/activity_serializer.rb | 14 ++++---- app/serializers/datacite_doi_serializer.rb | 2 +- spec/models/doi_spec.rb | 2 +- 6 files changed, 31 insertions(+), 31 deletions(-) diff --git a/app/controllers/datacite_dois_controller.rb b/app/controllers/datacite_dois_controller.rb index cb51cb006..5a4270a3f 100644 --- a/app/controllers/datacite_dois_controller.rb +++ b/app/controllers/datacite_dois_controller.rb @@ -515,7 +515,7 @@ def validate options = {} options[:include] = @include options[:is_collection] = false - options[:params] = { + options[:params] = { current_ability: current_ability, affiliation: params[:affiliation], publisher: params[:publisher] diff --git a/app/models/concerns/crosscitable.rb b/app/models/concerns/crosscitable.rb index 8ee240289..5e9e6b067 100644 --- a/app/models/concerns/crosscitable.rb +++ b/app/models/concerns/crosscitable.rb @@ -122,7 +122,7 @@ def update_xml ].map { |a| [a.to_sym, send(a.to_s)] }.to_h. compact - # Insert publisher_obj for publisher to generate XML +# Insert publisher_obj for publisher to generate XML =begin if read_attrs.dig(:publisher).present? && publisher_obj.present? read_attrs[:publisher] = publisher_obj diff --git a/app/models/doi.rb b/app/models/doi.rb index 60609591d..cf193418f 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -104,14 +104,14 @@ class Doi < ApplicationRecord validates_presence_of :doi validates_presence_of :url, if: Proc.new { |doi| doi.is_registered_or_findable? } -validates :publisher_obj, if: :publisher_obj? && Proc.new { |doi| - doi.validatable? && - !(doi.publisher.blank? || doi.publisher.all?(nil)) -}, -json: { - message: ->(errors) { errors }, - schema: PUBLISHER_JSON_SCHEMA -} + validates :publisher_obj, if: :publisher_obj? && Proc.new { |doi| + doi.validatable? && + !(doi.publisher.blank? || doi.publisher.all?(nil)) + }, + json: { + message: ->(errors) { errors }, + schema: PUBLISHER_JSON_SCHEMA + } # from https://www.crossref.org/blog/dois-and-matching-regular-expressions/ but using uppercase validates_format_of :doi, with: /\A10\.\d{4,5}\/[-._;()\/:a-zA-Z0-9*~$=]+\z/, on: :create @@ -325,7 +325,7 @@ class Doi < ApplicationRecord nameType: { type: :text }, givenName: { type: :text }, familyName: { type: :text }, - }}, + } }, } indexes :types, type: :object, properties: { resourceTypeGeneral: { type: :keyword }, @@ -561,7 +561,7 @@ class Doi < ApplicationRecord indexes :fields_of_science, type: :keyword indexes :fields_of_science_combined, type: :keyword indexes :fields_of_science_repository, type: :keyword -=begin +=begin indexes :publisher_obj, type: :object, properties: { name: { type: :text, fields: { keyword: { type: "keyword" } } }, publisherIdentifier: { type: :keyword, normalizer: "keyword_lowercase" }, @@ -1196,7 +1196,7 @@ def self.import_one(doi_id: nil, id: nil) meta = doi.read_datacite(string: string, sandbox: doi.sandbox) # attrs = %w(creators contributors titles publisher publication_year types descriptions container sizes formats language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects content_url version_info publisher_obj).map do |a| attrs = %w(creators contributors titles publisher publication_year types descriptions container sizes formats language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects content_url version_info).map do |a| - [a.to_sym, meta[a]] + [a.to_sym, meta[a]] end.to_h.merge(schema_version: meta["schema_version"] || "http://datacite.org/schema/kernel-4", xml: string, version: doi.version.to_i + 1) # update_attributes will trigger validations and Elasticsearch indexing @@ -2302,11 +2302,11 @@ def update_publisher if publisher_before_type_cast.respond_to?(:to_hash) if !(publisher_before_type_cast.blank? || publisher_before_type_cast.values.all?(nil)) self.publisher_obj = { - :name => publisher_before_type_cast.fetch(:name, nil), - :lang => publisher_before_type_cast.fetch(:lang, nil), - :schemeUri => publisher_before_type_cast.fetch(:schemeUri, nil), - :publisherIdentifier => publisher_before_type_cast.fetch(:publisherIdentifier, nil), - :publisherIdentifierScheme => publisher_before_type_cast.fetch(:publisherIdentifierScheme, nil) + name: publisher_before_type_cast.fetch(:name, nil), + lang: publisher_before_type_cast.fetch(:lang, nil), + schemeUri: publisher_before_type_cast.fetch(:schemeUri, nil), + publisherIdentifier: publisher_before_type_cast.fetch(:publisherIdentifier, nil), + publisherIdentifierScheme: publisher_before_type_cast.fetch(:publisherIdentifierScheme, nil) }.compact self.publisher = publisher_before_type_cast.dig(:name) else @@ -2314,21 +2314,21 @@ def update_publisher self.publisher = nil end elsif publisher_before_type_cast.respond_to?(:to_str) - self.publisher_obj = { :name => publisher_before_type_cast } + self.publisher_obj = { name: publisher_before_type_cast } self.publisher = publisher_before_type_cast end end def publisher - pub = read_attribute('publisher') - pub_obj = read_attribute('publisher_obj') + pub = read_attribute("publisher") + pub_obj = read_attribute("publisher_obj") return nil if pub.nil? && pub_obj.nil? if !(pub_obj.nil? || pub_obj.empty?) pub_obj else - return { "name" => pub || "" } + { "name" => pub || "" } end end diff --git a/app/serializers/activity_serializer.rb b/app/serializers/activity_serializer.rb index 13940fc53..99c14cc1b 100644 --- a/app/serializers/activity_serializer.rb +++ b/app/serializers/activity_serializer.rb @@ -20,16 +20,16 @@ class ActivitySerializer ret = changes - if object._source.action == 'update' - if (pub || pub_obj) - if params[:publisher] == 'true' + if object._source.action == "update" + if pub || pub_obj + if params[:publisher] == "true" if !pub_obj changes.publisher = [ { "name": pub[0] }, { "name": pub[1] }, ] - else + else changes.publisher = changes.publisher_obj end else @@ -40,9 +40,9 @@ class ActivitySerializer ret = changes end - elsif object._source.action == 'create' - if (pub || pub_obj) - if params[:publisher] == 'true' + elsif object._source.action == "create" + if pub || pub_obj + if params[:publisher] == "true" if !pub_obj changes.publisher = { "name": pub } else diff --git a/app/serializers/datacite_doi_serializer.rb b/app/serializers/datacite_doi_serializer.rb index f7718dc9b..d958c82c5 100644 --- a/app/serializers/datacite_doi_serializer.rb +++ b/app/serializers/datacite_doi_serializer.rb @@ -121,7 +121,7 @@ class DataciteDoiSerializer attribute :publisher do |object, params| # publisher accessor will now always return a publisher object. # new obj format only if ?publisher=true, otherwise serialize the old format (a string) - if params && (params[:publisher] == 'true') + if params && (params[:publisher] == "true") if object.publisher.respond_to?(:to_hash) object.publisher elsif object.publisher.respond_to?(:to_str) diff --git a/spec/models/doi_spec.rb b/spec/models/doi_spec.rb index 231a11d41..515357dd5 100644 --- a/spec/models/doi_spec.rb +++ b/spec/models/doi_spec.rb @@ -1211,7 +1211,7 @@ end it "publisher" do - expect(subject.publisher).to eq({ + expect(subject.publisher).to eq({ "name" => "Dryad Digital Repository", "publisherIdentifier" => "https://ror.org/00x6h5n95", "publisherIdentifierScheme" => "ROR", From b6756d591d057ae3346f02d13f0073c0117e2e50 Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Tue, 14 Nov 2023 10:59:18 -0500 Subject: [PATCH 29/41] Cleanup --- app/models/concerns/crosscitable.rb | 7 ------- 1 file changed, 7 deletions(-) diff --git a/app/models/concerns/crosscitable.rb b/app/models/concerns/crosscitable.rb index 5e9e6b067..c794390d2 100644 --- a/app/models/concerns/crosscitable.rb +++ b/app/models/concerns/crosscitable.rb @@ -122,13 +122,6 @@ def update_xml ].map { |a| [a.to_sym, send(a.to_s)] }.to_h. compact -# Insert publisher_obj for publisher to generate XML -=begin - if read_attrs.dig(:publisher).present? && publisher_obj.present? - read_attrs[:publisher] = publisher_obj - end -=end - if from.present? send( "read_" + from, From dde6e5107787fa96c6d2649677a013bf721b969d Mon Sep 17 00:00:00 2001 From: codycooperross <50597551+codycooperross@users.noreply.github.com> Date: Thu, 16 Nov 2023 09:45:38 -0500 Subject: [PATCH 30/41] Publisher param test corrections --- spec/requests/datacite_dois_spec.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/requests/datacite_dois_spec.rb b/spec/requests/datacite_dois_spec.rb index f6f28e04d..173678009 100755 --- a/spec/requests/datacite_dois_spec.rb +++ b/spec/requests/datacite_dois_spec.rb @@ -239,11 +239,11 @@ end end - describe "GET /dois with publisher param", elasticsearch: true do + describe "GET /dois with nil publisher values", elasticsearch: true do let!(:doi) { create(:doi, client: client, publisher: nil) } it "returns nil publisher when publisher param is not set" do - get "/dois?publisher=true", nil, headers + get "/dois", nil, headers expect(last_response.status).to eq(200) json["data"].each do |doi| @@ -261,11 +261,11 @@ end end - describe "GET /dois/:id with publisher param", elasticsearch: true do + describe "GET /dois/:id with nil publisher values", elasticsearch: true do let!(:doi) { create(:doi, client: client, publisher: nil) } it "returns nil publisher when publisher param is not set" do - get "/dois/#{doi.doi}?publisher=true", nil, headers + get "/dois/#{doi.doi}", nil, headers expect(last_response.status).to eq(200) expect(json.dig("attributes", "publisher")).to eq(nil) From 8fa20c19553902e6a3079e29f8f8e7dd544f7f16 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Mon, 27 Nov 2023 17:09:50 -0500 Subject: [PATCH 31/41] Mods from suggestions in PR. --- app/graphql/types/doi_item.rb | 7 +- app/models/doi.rb | 78 ++++++++++++---------- app/serializers/activity_serializer.rb | 51 +++----------- app/serializers/datacite_doi_serializer.rb | 18 ++--- 4 files changed, 62 insertions(+), 92 deletions(-) diff --git a/app/graphql/types/doi_item.rb b/app/graphql/types/doi_item.rb index 33071737d..468a63a4b 100644 --- a/app/graphql/types/doi_item.rb +++ b/app/graphql/types/doi_item.rb @@ -580,9 +580,12 @@ def identifiers end def publisher - if object.publisher.respond_to?(:to_hash) + case object.publisher + when Hash object.publisher["name"] - elsif object.publisher.respond_to?(:to_str) + when String + object.publisher + else object.publisher end end diff --git a/app/models/doi.rb b/app/models/doi.rb index cf193418f..392414a71 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -104,14 +104,16 @@ class Doi < ApplicationRecord validates_presence_of :doi validates_presence_of :url, if: Proc.new { |doi| doi.is_registered_or_findable? } - validates :publisher_obj, if: :publisher_obj? && Proc.new { |doi| - doi.validatable? && - !(doi.publisher.blank? || doi.publisher.all?(nil)) - }, - json: { + json_schema_validation = { message: ->(errors) { errors }, schema: PUBLISHER_JSON_SCHEMA } + + def validate_publisher_obj?(doi) + doi.validatable? && doi.publisher_obj? && !(doi.publisher.blank? || doi.publisher.all?(nil)) + end + + validates :publisher_obj, if: ->(doi) { validate_publisher_obj?(doi) }, json: json_schema_validation # from https://www.crossref.org/blog/dois-and-matching-regular-expressions/ but using uppercase validates_format_of :doi, with: /\A10\.\d{4,5}\/[-._;()\/:a-zA-Z0-9*~$=]+\z/, on: :create @@ -561,15 +563,6 @@ class Doi < ApplicationRecord indexes :fields_of_science, type: :keyword indexes :fields_of_science_combined, type: :keyword indexes :fields_of_science_repository, type: :keyword -=begin - indexes :publisher_obj, type: :object, properties: { - name: { type: :text, fields: { keyword: { type: "keyword" } } }, - publisherIdentifier: { type: :keyword, normalizer: "keyword_lowercase" }, - publisherIdentifierScheme: { type: :keyword }, - schemeUri: { type: :keyword }, - lang: { type: :keyword }, - } -=end end end @@ -659,7 +652,6 @@ def as_indexed_json(_options = {}) "version_ids" => version_ids, "version_of_ids" => version_of_ids, "primary_title" => Array.wrap(primary_title), - # "publisher_obj" => publisher_obj, } end @@ -783,7 +775,6 @@ def self.igsn_id_catalog_aggregations end def self.query_fields - # ["uid^50", "related_identifiers.relatedIdentifier^3", "titles.title^3", "creator_names^3", "creators.id^3", "publisher^3", "descriptions.description^3", "subjects.subject^3", "publisher_obj.name^3"] ["uid^50", "related_identifiers.relatedIdentifier^3", "titles.title^3", "creator_names^3", "creators.id^3", "publisher^3", "descriptions.description^3", "subjects.subject^3"] end @@ -933,7 +924,6 @@ def self.query(query, options = {}) query = query.gsub(/citationCount/, "citation_count") query = query.gsub(/viewCount/, "view_count") query = query.gsub(/downloadCount/, "download_count") - # query = query.gsub(/publisherObj/, "publisher_obj") query = query.gsub("/", "\\/") end @@ -1194,7 +1184,6 @@ def self.import_one(doi_id: nil, id: nil) end meta = doi.read_datacite(string: string, sandbox: doi.sandbox) - # attrs = %w(creators contributors titles publisher publication_year types descriptions container sizes formats language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects content_url version_info publisher_obj).map do |a| attrs = %w(creators contributors titles publisher publication_year types descriptions container sizes formats language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects content_url version_info).map do |a| [a.to_sym, meta[a]] end.to_h.merge(schema_version: meta["schema_version"] || "http://datacite.org/schema/kernel-4", xml: string, version: doi.version.to_i + 1) @@ -1487,7 +1476,7 @@ def self.convert_publishers(options = {}) Rails.logger.info "Queued converting publisher to publisher_obj for DOIs with IDs starting with #{id}." unless Rails.env.test? end - "Queued converting #{(from_id..until_id).to_a.length} publishers." + "Queued converting #{(from_id..until_id).size} publishers." end def self.convert_publisher_by_id(options = {}) @@ -2299,23 +2288,13 @@ def update_types end def update_publisher - if publisher_before_type_cast.respond_to?(:to_hash) - if !(publisher_before_type_cast.blank? || publisher_before_type_cast.values.all?(nil)) - self.publisher_obj = { - name: publisher_before_type_cast.fetch(:name, nil), - lang: publisher_before_type_cast.fetch(:lang, nil), - schemeUri: publisher_before_type_cast.fetch(:schemeUri, nil), - publisherIdentifier: publisher_before_type_cast.fetch(:publisherIdentifier, nil), - publisherIdentifierScheme: publisher_before_type_cast.fetch(:publisherIdentifierScheme, nil) - }.compact - self.publisher = publisher_before_type_cast.dig(:name) - else - self.publisher_obj = nil - self.publisher = nil - end - elsif publisher_before_type_cast.respond_to?(:to_str) - self.publisher_obj = { name: publisher_before_type_cast } - self.publisher = publisher_before_type_cast + case publisher_before_type_cast + when Hash + update_publisher_from_hash + when String + update_publisher_from_string + else + reset_publishers end end @@ -2470,7 +2449,6 @@ def self.add_index_type(options = {}) "Finished updating dois, total #{count}" end - # QUICK FIX UNTIL PROJECT IS A RESOURCE_TYPE_GENERAL IN THE SCHEMA def handle_resource_type(types) if types.present? && types["resourceType"] == "Project" && (types["resourceTypeGeneral"] == "Text" || types["resourceTypeGeneral"] == "Other") @@ -2479,4 +2457,30 @@ def handle_resource_type(types) types.to_h["resourceTypeGeneral"] end end + + private + + def update_publisher_from_hash + if !publisher_before_type_cast.values.all?(nil) + self.publisher_obj = { + name: publisher_before_type_cast.fetch(:name, nil), + lang: publisher_before_type_cast.fetch(:lang, nil), + schemeUri: publisher_before_type_cast.fetch(:schemeUri, nil), + publisherIdentifier: publisher_before_type_cast.fetch(:publisherIdentifier, nil), + publisherIdentifierScheme: publisher_before_type_cast.fetch(:publisherIdentifierScheme, nil) + }.compact + self.publisher = publisher_before_type_cast.dig(:name) + else + reset_publishers + end + end + + def update_publisher_from_string + self.publisher_obj = { name: publisher_before_type_cast } + self.publisher = publisher_before_type_cast + end + + def reset_publishers + self.publisher_obj = nil self.publisher = nil + end end diff --git a/app/serializers/activity_serializer.rb b/app/serializers/activity_serializer.rb index 99c14cc1b..e36cdeb8d 100644 --- a/app/serializers/activity_serializer.rb +++ b/app/serializers/activity_serializer.rb @@ -17,52 +17,21 @@ class ActivitySerializer changes = object._source.changes pub = changes.publisher pub_obj = changes.publisher_obj - - ret = changes - - if object._source.action == "update" - if pub || pub_obj - if params[:publisher] == "true" - if !pub_obj - changes.publisher = - [ - { "name": pub[0] }, - { "name": pub[1] }, - ] - else - changes.publisher = changes.publisher_obj - end + + if params[:publisher] == "true" + changes.publisher = + if pub + object._source.action == "update" ? [{ "name": pub[0] }, { "name": pub[1] }] : { "name": pub } else - if !pub - changes.publisher = [ pub_obj[0].name, pub_obj[1].name ] - end + changes.publisher_obj end - - ret = changes - end - elsif object._source.action == "create" - if pub || pub_obj - if params[:publisher] == "true" - if !pub_obj - changes.publisher = { "name": pub } - else - changes.publisher = changes.publisher_obj - end - else - if !pub - changes.publisher = pub_obj.name - end - end - - ret = changes - end + elsif pub_obj + changes.publisher = object._source.action == "update" ? [pub_obj[0].name, pub_obj[1].name] : pub_obj.name end - if pub_obj - changes.delete("publisher_obj") - end + changes.delete("publisher_obj") if pub_obj - ret + changes end attribute "prov:wasDerivedFrom", &:was_derived_from diff --git a/app/serializers/datacite_doi_serializer.rb b/app/serializers/datacite_doi_serializer.rb index d958c82c5..12aa93647 100644 --- a/app/serializers/datacite_doi_serializer.rb +++ b/app/serializers/datacite_doi_serializer.rb @@ -120,19 +120,13 @@ class DataciteDoiSerializer attribute :publisher do |object, params| # publisher accessor will now always return a publisher object. - # new obj format only if ?publisher=true, otherwise serialize the old format (a string) - if params && (params[:publisher] == "true") - if object.publisher.respond_to?(:to_hash) - object.publisher - elsif object.publisher.respond_to?(:to_str) - { "name" => object.publisher } - end + # new obj format only if ?publisher=true, otherwise serialize the old format (a string + if params&.dig(:publisher) == "true" + return { "name" => object.publisher } if object.publisher.respond_to?(:to_str) + return object.publisher else - if object.publisher.respond_to?(:to_hash) - object.publisher["name"] - elsif object.publisher.respond_to?(:to_str) - object.publisher - end + return object.publisher if object.publisher.respond_to?(:to_str) + return object.publisher["name"] end end From 3926084d6c31c2da3c1a408b817c8a7f7b0de5c3 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Mon, 27 Nov 2023 17:15:46 -0500 Subject: [PATCH 32/41] Appease rubocop. --- app/serializers/activity_serializer.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/app/serializers/activity_serializer.rb b/app/serializers/activity_serializer.rb index e36cdeb8d..f5d514a89 100644 --- a/app/serializers/activity_serializer.rb +++ b/app/serializers/activity_serializer.rb @@ -17,7 +17,7 @@ class ActivitySerializer changes = object._source.changes pub = changes.publisher pub_obj = changes.publisher_obj - + if params[:publisher] == "true" changes.publisher = if pub @@ -29,9 +29,9 @@ class ActivitySerializer changes.publisher = object._source.action == "update" ? [pub_obj[0].name, pub_obj[1].name] : pub_obj.name end - changes.delete("publisher_obj") if pub_obj + changes.delete("publisher_obj") if pub_obj - changes + changes end attribute "prov:wasDerivedFrom", &:was_derived_from From 8e8bb94ea159b86792ceff4d6c56bb17e245d370 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Mon, 27 Nov 2023 17:25:28 -0500 Subject: [PATCH 33/41] Use updated bolognese branch. --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2c054d38d..2ce4f4683 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: https://github.com/datacite/bolognese - revision: 714d71a4a2169d1880ccb296df3ca1331e0e1a83 + revision: 98870f13479ef266a4b773e5295958886252a5a8 branch: schema-4.5 specs: bolognese (1.11.5) From 99163919b094a6693d7d72437aed91d9362e3e3b Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Mon, 27 Nov 2023 17:31:19 -0500 Subject: [PATCH 34/41] Cleanup syntax error. --- app/models/doi.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/models/doi.rb b/app/models/doi.rb index 392414a71..972d24b73 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -2481,6 +2481,7 @@ def update_publisher_from_string end def reset_publishers - self.publisher_obj = nil self.publisher = nil + self.publisher_obj = nil + self.publisher = nil end end From 1782bb3bc14ce3d2002e44b807e6f239adf024e9 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Mon, 27 Nov 2023 18:12:06 -0500 Subject: [PATCH 35/41] Appease rubocop. --- app/models/doi.rb | 49 +++++++++++++++++++++++------------------------ 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/app/models/doi.rb b/app/models/doi.rb index 972d24b73..35f99d961 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -108,11 +108,11 @@ class Doi < ApplicationRecord message: ->(errors) { errors }, schema: PUBLISHER_JSON_SCHEMA } - + def validate_publisher_obj?(doi) doi.validatable? && doi.publisher_obj? && !(doi.publisher.blank? || doi.publisher.all?(nil)) end - + validates :publisher_obj, if: ->(doi) { validate_publisher_obj?(doi) }, json: json_schema_validation # from https://www.crossref.org/blog/dois-and-matching-regular-expressions/ but using uppercase @@ -2459,29 +2459,28 @@ def handle_resource_type(types) end private + def update_publisher_from_hash + if !publisher_before_type_cast.values.all?(nil) + self.publisher_obj = { + name: publisher_before_type_cast.fetch(:name, nil), + lang: publisher_before_type_cast.fetch(:lang, nil), + schemeUri: publisher_before_type_cast.fetch(:schemeUri, nil), + publisherIdentifier: publisher_before_type_cast.fetch(:publisherIdentifier, nil), + publisherIdentifierScheme: publisher_before_type_cast.fetch(:publisherIdentifierScheme, nil) + }.compact + self.publisher = publisher_before_type_cast.dig(:name) + else + reset_publishers + end + end - def update_publisher_from_hash - if !publisher_before_type_cast.values.all?(nil) - self.publisher_obj = { - name: publisher_before_type_cast.fetch(:name, nil), - lang: publisher_before_type_cast.fetch(:lang, nil), - schemeUri: publisher_before_type_cast.fetch(:schemeUri, nil), - publisherIdentifier: publisher_before_type_cast.fetch(:publisherIdentifier, nil), - publisherIdentifierScheme: publisher_before_type_cast.fetch(:publisherIdentifierScheme, nil) - }.compact - self.publisher = publisher_before_type_cast.dig(:name) - else - reset_publishers + def update_publisher_from_string + self.publisher_obj = { name: publisher_before_type_cast } + self.publisher = publisher_before_type_cast + end + + def reset_publishers + self.publisher_obj = nil + self.publisher = nil end - end - - def update_publisher_from_string - self.publisher_obj = { name: publisher_before_type_cast } - self.publisher = publisher_before_type_cast - end - - def reset_publishers - self.publisher_obj = nil - self.publisher = nil - end end From b7db165b59148d3f6711018ee08466a0898bfaf3 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Mon, 27 Nov 2023 19:47:41 -0500 Subject: [PATCH 36/41] Revert some changes. --- app/serializers/activity_serializer.rb | 49 ++++++++++++++++++---- app/serializers/datacite_doi_serializer.rb | 16 ++++--- 2 files changed, 51 insertions(+), 14 deletions(-) diff --git a/app/serializers/activity_serializer.rb b/app/serializers/activity_serializer.rb index f5d514a89..99c14cc1b 100644 --- a/app/serializers/activity_serializer.rb +++ b/app/serializers/activity_serializer.rb @@ -18,20 +18,51 @@ class ActivitySerializer pub = changes.publisher pub_obj = changes.publisher_obj - if params[:publisher] == "true" - changes.publisher = - if pub - object._source.action == "update" ? [{ "name": pub[0] }, { "name": pub[1] }] : { "name": pub } + ret = changes + + if object._source.action == "update" + if pub || pub_obj + if params[:publisher] == "true" + if !pub_obj + changes.publisher = + [ + { "name": pub[0] }, + { "name": pub[1] }, + ] + else + changes.publisher = changes.publisher_obj + end + else + if !pub + changes.publisher = [ pub_obj[0].name, pub_obj[1].name ] + end + end + + ret = changes + end + elsif object._source.action == "create" + if pub || pub_obj + if params[:publisher] == "true" + if !pub_obj + changes.publisher = { "name": pub } + else + changes.publisher = changes.publisher_obj + end else - changes.publisher_obj + if !pub + changes.publisher = pub_obj.name + end end - elsif pub_obj - changes.publisher = object._source.action == "update" ? [pub_obj[0].name, pub_obj[1].name] : pub_obj.name + + ret = changes + end end - changes.delete("publisher_obj") if pub_obj + if pub_obj + changes.delete("publisher_obj") + end - changes + ret end attribute "prov:wasDerivedFrom", &:was_derived_from diff --git a/app/serializers/datacite_doi_serializer.rb b/app/serializers/datacite_doi_serializer.rb index 12aa93647..27bfc6038 100644 --- a/app/serializers/datacite_doi_serializer.rb +++ b/app/serializers/datacite_doi_serializer.rb @@ -121,12 +121,18 @@ class DataciteDoiSerializer attribute :publisher do |object, params| # publisher accessor will now always return a publisher object. # new obj format only if ?publisher=true, otherwise serialize the old format (a string - if params&.dig(:publisher) == "true" - return { "name" => object.publisher } if object.publisher.respond_to?(:to_str) - return object.publisher + if params && (params[:publisher] == "true") + if object.publisher.respond_to?(:to_hash) + object.publisher + elsif object.publisher.respond_to?(:to_str) + { "name" => object.publisher } + end else - return object.publisher if object.publisher.respond_to?(:to_str) - return object.publisher["name"] + if object.publisher.respond_to?(:to_hash) + object.publisher["name"] + elsif object.publisher.respond_to?(:to_str) + object.publisher + end end end From 06c5e313c200db2d20d4acc114a281a7f0add763 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Mon, 27 Nov 2023 22:17:01 -0500 Subject: [PATCH 37/41] DOI serializer. --- app/serializers/datacite_doi_serializer.rb | 27 ++++++++++++---------- 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/app/serializers/datacite_doi_serializer.rb b/app/serializers/datacite_doi_serializer.rb index 27bfc6038..c0c4433a2 100644 --- a/app/serializers/datacite_doi_serializer.rb +++ b/app/serializers/datacite_doi_serializer.rb @@ -119,19 +119,22 @@ class DataciteDoiSerializer attribute :doi, &:uid attribute :publisher do |object, params| - # publisher accessor will now always return a publisher object. - # new obj format only if ?publisher=true, otherwise serialize the old format (a string - if params && (params[:publisher] == "true") - if object.publisher.respond_to?(:to_hash) - object.publisher - elsif object.publisher.respond_to?(:to_str) - { "name" => object.publisher } - end + # new - format obj only if ?publisher=true, otherwise serialize the old format (a string) + if object.publisher.nil? + nil else - if object.publisher.respond_to?(:to_hash) - object.publisher["name"] - elsif object.publisher.respond_to?(:to_str) - object.publisher + if params&.dig(:publisher) == "true" + if object.publisher.respond_to?(:to_str) + { "name" => object.publisher } + else + object.publisher + end + else + if object.publisher.respond_to?(:to_str) + object.publisher + else + object.publisher["name"] + end end end end From 7954d19206167131f7bb100028f124c0d0754f50 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Tue, 28 Nov 2023 00:16:49 -0500 Subject: [PATCH 38/41] Cleanup. --- app/serializers/datacite_doi_serializer.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/app/serializers/datacite_doi_serializer.rb b/app/serializers/datacite_doi_serializer.rb index c0c4433a2..b47af8753 100644 --- a/app/serializers/datacite_doi_serializer.rb +++ b/app/serializers/datacite_doi_serializer.rb @@ -124,16 +124,16 @@ class DataciteDoiSerializer nil else if params&.dig(:publisher) == "true" - if object.publisher.respond_to?(:to_str) - { "name" => object.publisher } - else + if object.publisher.respond_to?(:to_hash) object.publisher + else + { "name" => object.publisher } end else - if object.publisher.respond_to?(:to_str) - object.publisher - else + if object.publisher.respond_to?(:to_hash) object.publisher["name"] + else + object.publisher end end end From 668c643f3f43dc032ac151c58fe70d6a609773f1 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Thu, 30 Nov 2023 20:49:35 -0500 Subject: [PATCH 39/41] Update bolognese branch. --- Gemfile.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gemfile.lock b/Gemfile.lock index 2ce4f4683..a200b297a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,6 +1,6 @@ GIT remote: https://github.com/datacite/bolognese - revision: 98870f13479ef266a4b773e5295958886252a5a8 + revision: 23a3e940aaf59090f71bae7bc58724a392f364e2 branch: schema-4.5 specs: bolognese (1.11.5) From cbce6af4a72329f2a58c689f707f4f5b9f1a96df Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Mon, 4 Dec 2023 13:28:33 -0500 Subject: [PATCH 40/41] Update bolognese to use v2.0.0 --- Gemfile | 3 +-- Gemfile.lock | 56 +++++++++++++++++++++++----------------------------- 2 files changed, 26 insertions(+), 33 deletions(-) diff --git a/Gemfile b/Gemfile index 81c04a742..81f660188 100644 --- a/Gemfile +++ b/Gemfile @@ -12,8 +12,7 @@ gem "aws-sdk-sqs", "~> 1.3" gem "base32-url", "~> 0.3" gem "batch-loader", "~> 1.4", ">= 1.4.1" gem "bcrypt", "~> 3.1.7" -# gem "bolognese", "~> 1.11.5" -gem "bolognese", git: "https://github.com/datacite/bolognese", branch: "schema-4.5" +gem "bolognese", "~> 2.0.0" gem "bootsnap", "~> 1.4", ">= 1.4.4", require: false gem "cancancan", "~> 3.0" gem "commonmarker", "~> 0.23.4" diff --git a/Gemfile.lock b/Gemfile.lock index a200b297a..040c625be 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,33 +1,3 @@ -GIT - remote: https://github.com/datacite/bolognese - revision: 23a3e940aaf59090f71bae7bc58724a392f364e2 - branch: schema-4.5 - specs: - bolognese (1.11.5) - activesupport (>= 4.2.5) - benchmark_methods (~> 0.7) - bibtex-ruby (>= 5.1.0) - builder (~> 3.2, >= 3.2.2) - citeproc-ruby (~> 1.1, >= 1.1.12) - colorize (~> 0.8.1) - concurrent-ruby (~> 1.1, >= 1.1.5) - csl-styles (~> 1.0, >= 1.0.1.10) - edtf (~> 3.0, >= 3.0.4) - gender_detector (~> 0.1.2) - iso8601 (~> 0.9.1) - json-ld-preloaded (~> 3.1, >= 3.1.3) - jsonlint (~> 0.3.0) - loofah (~> 2.0, >= 2.0.3) - maremma (>= 4.9.4, < 5) - namae (~> 1.0) - nokogiri (>= 1.13.2, < 1.14) - oj (~> 3.10) - oj_mimic_json (~> 1.0, >= 1.0.1) - postrank-uri (~> 1.0, >= 1.0.18) - rdf-rdfxml (~> 3.1) - rdf-turtle (~> 3.1) - thor (>= 0.19) - GEM remote: https://rubygems.org/ specs: @@ -143,6 +113,30 @@ GEM latex-decode (~> 0.0) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) + bolognese (2.0.0) + activesupport (>= 4.2.5) + benchmark_methods (~> 0.7) + bibtex-ruby (>= 5.1.0) + builder (~> 3.2, >= 3.2.2) + citeproc-ruby (~> 1.1, >= 1.1.12) + colorize (~> 0.8.1) + concurrent-ruby (~> 1.1, >= 1.1.5) + csl-styles (~> 1.0, >= 1.0.1.10) + edtf (~> 3.0, >= 3.0.4) + gender_detector (~> 0.1.2) + iso8601 (~> 0.9.1) + json-ld-preloaded (~> 3.1, >= 3.1.3) + jsonlint (~> 0.3.0) + loofah (~> 2.0, >= 2.0.3) + maremma (>= 4.9.4, < 5) + namae (~> 1.0) + nokogiri (>= 1.13.2, < 1.14) + oj (~> 3.10) + oj_mimic_json (~> 1.0, >= 1.0.1) + postrank-uri (~> 1.0, >= 1.0.18) + rdf-rdfxml (~> 3.1) + rdf-turtle (~> 3.1) + thor (>= 0.19) bootsnap (1.15.0) msgpack (~> 1.2) builder (3.2.4) @@ -662,7 +656,7 @@ DEPENDENCIES bcrypt (~> 3.1.7) better_errors binding_of_caller - bolognese! + bolognese (~> 2.0.0) bootsnap (~> 1.4, >= 1.4.4) bullet (~> 6.1) byebug From 580e305d008341e025b7ce72b71fcff3942b98e9 Mon Sep 17 00:00:00 2001 From: Suzanne Vogt Date: Mon, 4 Dec 2023 13:59:42 -0500 Subject: [PATCH 41/41] Implementing review comment. --- app/graphql/types/doi_item.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/graphql/types/doi_item.rb b/app/graphql/types/doi_item.rb index 468a63a4b..6e2fdf89e 100644 --- a/app/graphql/types/doi_item.rb +++ b/app/graphql/types/doi_item.rb @@ -920,7 +920,7 @@ def citeproc_hsh "volume" => object.container.to_h["volume"], "issue" => object.container.to_h["issue"], "page" => page, - "publisher" => object.publisher["name"] || object.publisher, + "publisher" => (object.publisher.is_a?(Hash) ? object.publisher&.fetch("name", nil) : object.publisher), "title" => parse_attributes(object.titles, content: "title", first: true), "URL" => object.url, "version" => object.version_info,