diff --git a/app/models/doi.rb b/app/models/doi.rb index 35f99d961..02cdcdfdc 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -258,6 +258,7 @@ def validate_publisher_obj?(doi) indexes :provider_id, type: :keyword indexes :consortium_id, type: :keyword indexes :resource_type_id, type: :keyword + indexes :person_id, type: :keyword indexes :affiliation_id, type: :keyword indexes :fair_affiliation_id, type: :keyword indexes :organization_id, type: :keyword @@ -563,6 +564,14 @@ def validate_publisher_obj?(doi) indexes :fields_of_science, type: :keyword indexes :fields_of_science_combined, type: :keyword indexes :fields_of_science_repository, type: :keyword + indexes :related_doi, type: :object, properties: { + client_id: { type: :keyword }, + doi: { type: :keyword }, + organization_id: { type: :keyword }, + person_id: { type: :keyword }, + resource_type_id: { type: :keyword }, + resource_type_id_and_name: { type: :keyword }, + } end end @@ -1672,6 +1681,10 @@ def consortium_id client.provider.consortium_id.downcase if client.present? && client.provider.consortium_id.present? end + def related_dois + Doi::Indexer::RelatedDoiIndexer.new(related_identifiers).as_indexed_json + end + def related_dmp_ids Array.wrap(related_identifiers).select { |related_identifier| related_identifier["relatedIdentifierType"] == "DOI" @@ -1702,21 +1715,38 @@ def sponsor_contributors end + def person_id + (Array.wrap(creators) + Array.wrap(contributors)).reduce([]) do |sum, c| + Array.wrap(c.fetch("nameIdentifiers", nil)).each do |name_identifier| + if name_identifier.is_a?(Hash) && name_identifier.fetch("nameIdentifierScheme", nil) == "ORCID" && name_identifier.fetch("nameIdentifier", nil).present? + sum << orcid_as_url( + orcid_from_url(name_identifier.fetch("nameIdentifier", nil)) + ) + end + end + sum.uniq + end + end + def organization_id (Array.wrap(creators) + Array.wrap(contributors)).reduce([]) do |sum, c| Array.wrap(c.fetch("nameIdentifiers", nil)).each do |name_identifier| - sum << ror_from_url(name_identifier.fetch("nameIdentifier", nil)) if name_identifier.is_a?(Hash) && name_identifier.fetch("nameIdentifierScheme", nil) == "ROR" && name_identifier.fetch("nameIdentifier", nil).present? + if name_identifier.is_a?(Hash) && name_identifier.fetch("nameIdentifierScheme", nil) == "ROR" && name_identifier.fetch("nameIdentifier", nil).present? + sum << ror_from_url(name_identifier.fetch("nameIdentifier", nil)) + end end - sum + sum.uniq end end def fair_organization_id (Array.wrap(creators) + sponsor_contributors).reduce([]) do |sum, c| Array.wrap(c.fetch("nameIdentifiers", nil)).each do |name_identifier| - sum << ror_from_url(name_identifier.fetch("nameIdentifier", nil)) if name_identifier.is_a?(Hash) && name_identifier.fetch("nameIdentifierScheme", nil) == "ROR" && name_identifier.fetch("nameIdentifier", nil).present? + if name_identifier.is_a?(Hash) && name_identifier.fetch("nameIdentifierScheme", nil) == "ROR" && name_identifier.fetch("nameIdentifier", nil).present? + sum << ror_from_url(name_identifier.fetch("nameIdentifier", nil)) + end end - sum + sum.uniq end end @@ -1725,7 +1755,7 @@ def affiliation_id Array.wrap(c.fetch("affiliation", nil)).each do |affiliation| sum << ror_from_url(affiliation.fetch("affiliationIdentifier", nil)) if affiliation.is_a?(Hash) && affiliation.fetch("affiliationIdentifierScheme", nil) == "ROR" && affiliation.fetch("affiliationIdentifier", nil).present? end - sum + sum.uniq end end @@ -1734,7 +1764,7 @@ def fair_affiliation_id Array.wrap(c.fetch("affiliation", nil)).each do |affiliation| sum << ror_from_url(affiliation.fetch("affiliationIdentifier", nil)) if affiliation.is_a?(Hash) && affiliation.fetch("affiliationIdentifierScheme", nil) == "ROR" && affiliation.fetch("affiliationIdentifier", nil).present? end - sum + sum.uniq end end @@ -1743,7 +1773,7 @@ def affiliation_id_and_name Array.wrap(c.fetch("affiliation", nil)).each do |affiliation| sum << "#{ror_from_url(affiliation.fetch('affiliationIdentifier', nil))}:#{affiliation.fetch('name', nil)}" if affiliation.is_a?(Hash) && affiliation.fetch("affiliationIdentifierScheme", nil) == "ROR" && affiliation.fetch("affiliationIdentifier", nil).present? end - sum + sum.uniq end end @@ -1752,7 +1782,7 @@ def fair_affiliation_id_and_name Array.wrap(c.fetch("affiliation", nil)).each do |affiliation| sum << "#{ror_from_url(affiliation.fetch('affiliationIdentifier', nil))}:#{affiliation.fetch('name', nil)}" if affiliation.is_a?(Hash) && affiliation.fetch("affiliationIdentifierScheme", nil) == "ROR" && affiliation.fetch("affiliationIdentifier", nil).present? end - sum + sum.uniq end end diff --git a/app/models/doi/indexer/related_doi_indexer.rb b/app/models/doi/indexer/related_doi_indexer.rb new file mode 100644 index 000000000..eb97419d3 --- /dev/null +++ b/app/models/doi/indexer/related_doi_indexer.rb @@ -0,0 +1,45 @@ +# frozen_string_literal: true + +module Doi::Indexer + class RelatedDoiIndexer + def initialize(related_identifiers) + @related_identifiers = related_identifiers + @related_dois = nil + end + + def related_dois + @related_dois ||= @related_identifiers.select { |r| r["relatedIdentifierType"] == "DOI" } + end + + def related_grouped_by_id + related_dois.group_by { |r| r["relatedIdentifier"].downcase } + end + + def relation_types_gouped_by_id + related_grouped_by_id.transform_values do |values| + values.map { |val| val["relationType"].underscore }.uniq + end + end + + def related_doi_ids + related_grouped_by_id.keys + end + + def dois + Doi.where(doi: related_doi_ids) + end + + def indexed_dois + dois.map { |d| RelatedIdentifierDenormalizer.new(d).to_hash } + end + + def as_indexed_json + rtypes = relation_types_gouped_by_id + indexed_dois.map do |indexed_doi| + doi = indexed_doi["doi"] + indexed_doi["relation_type"] = rtypes[doi] + indexed_doi + end + end + end +end diff --git a/app/models/doi/indexer/related_identifier_denormalizer.rb b/app/models/doi/indexer/related_identifier_denormalizer.rb new file mode 100644 index 000000000..9188015f8 --- /dev/null +++ b/app/models/doi/indexer/related_identifier_denormalizer.rb @@ -0,0 +1,32 @@ +# frozen_string_literal: true + +module Doi::Indexer + class RelatedIdentifierDenormalizer + attr_reader :related_doi + + def initialize(doi) + @related_doi = doi + end + + def to_hash + %w[ + client_id + doi + organization_id + person_id + resource_type_id + resource_type_id_and_name + ].index_with { |method_name| send(method_name) } + end + + delegate :resource_type_id, to: :related_doi + delegate :resource_type_id_and_name, to: :related_doi + delegate :organization_id, to: :related_doi + delegate :person_id, to: :related_doi + delegate :client_id, to: :related_doi + + def doi + @related_doi.doi.downcase + end + end +end diff --git a/spec/models/doi_spec.rb b/spec/models/doi_spec.rb index 515357dd5..9636b2b80 100644 --- a/spec/models/doi_spec.rb +++ b/spec/models/doi_spec.rb @@ -1081,6 +1081,66 @@ end end + describe "person_ids" do + it "from creators and contributors" do + subject = build( + :doi, + creators: [ + { + "familyName" => "Garza", + "givenName" => "Kristian", + "name" => "Garza, Kristian", + "nameIdentifiers" => [ + { + "nameIdentifier" => "https://orcid.org/0000-0003-3484-6875", + "nameIdentifierScheme" => "ORCID", + "schemeUri" => "https://orcid.org", + }, + ], + "nameType" => "Personal", + "affiliation" => [ + { + "name" => "University of Cambridge", + "affiliationIdentifier" => "https://ror.org/013meh722", + "affiliationIdentifierScheme" => "ROR", + }, + ], + }, + ], + contributors: [ + { + "contributorType" => "Sponsor", + "familyName" => "Bob", + "givenName" => "Jones", + "name" => "Jones, Bob", + "nameIdentifiers" => [ + { + "nameIdentifier" => "https://orcid.org/0000-0003-3484-0000", + "nameIdentifierScheme" => "ORCID", + "schemeUri" => "https://orcid.org", + }, + ], + "nameType" => "Personal", + "affiliation" => [ + { + "name" => "University of Examples", + "affiliationIdentifier" => "https://ror.org/013meh8888", + "affiliationIdentifierScheme" => "ROR", + }, + ], + }, + ] + ) + expect(subject).to be_valid + expect(subject.person_id).to eq( + [ + "https://orcid.org/0000-0003-3484-6875", + "https://orcid.org/0000-0003-3484-0000", + ] + ) + end + end + describe "related_identifiers" do it "has part" do subject = build(:doi, related_identifiers: [ diff --git a/spec/models/doi_verified_related_identifiers_spec.rb b/spec/models/doi_verified_related_identifiers_spec.rb new file mode 100644 index 000000000..04c237fc7 --- /dev/null +++ b/spec/models/doi_verified_related_identifiers_spec.rb @@ -0,0 +1,60 @@ + +# frozen_string_literal: true + +require "rails_helper" + +describe Doi, type: :model, vcr: true, elasticsearch: true do + describe "related_doi" do + let(:client) { create(:client) } + let(:target_doi) do + create(:doi, + client: client, + aasm_state: "findable", + types: { "resourceTypeGeneral" => "Dataset" } + ) + end + let(:doi) do + create(:doi, + client: client, + aasm_state: "findable", + related_identifiers: [ + { + "relatedIdentifier": target_doi.doi, + "relatedIdentifierType": "DOI", + "relationType": "HasPart", + "resourceTypeGeneral": "OutputManagementPlan", + }, + { + "relatedIdentifier": target_doi.doi, + "relatedIdentifierType": "DOI", + "relationType": "Cites", + "resourceTypeGeneral": "Text", + } + ]) + end + + it "indexes related_dois" do + expect(doi.related_dois.first["doi"]).to eq(target_doi.doi.downcase) + end + + it "indexes related doi's client_id" do + expect(doi.related_dois.first["client_id"]).to eq(target_doi.client_id) + end + + it "indexes related doi's person_id" do + expect(doi.related_dois.first["person_id"]).to eq(target_doi.person_id) + end + + it "does not index related doi's claimed resource_type_id" do + expect(doi.related_dois.first["resource_type_id"]).not_to eq("output_management_plan") + end + + it "indexes related doi's true resource_type_id" do + expect(doi.related_dois.first["resource_type_id"]).to eq("dataset") + end + + it "indexes all relations to the related doi" do + expect(doi.related_dois.first["relation_type"]).to eq(["has_part", "cites"]) + end + end +end