From 66176050a9daa820c44836286fdc8bc0d06d5a33 Mon Sep 17 00:00:00 2001 From: Martin Fenner Date: Wed, 13 May 2020 11:16:03 +0200 Subject: [PATCH 1/4] implement graphql actor interface --- app/graphql/lupo_schema.rb | 5 +- app/graphql/schema.graphql | 130 +++++-- app/graphql/types/actor_connection_type.rb | 16 + app/graphql/types/actor_edge_type.rb | 5 + app/graphql/types/actor_item.rb | 28 ++ app/graphql/types/base_object.rb | 6 +- app/graphql/types/funder_type.rb | 6 +- app/graphql/types/organization_type.rb | 8 +- app/graphql/types/person_type.rb | 6 +- app/graphql/types/query_type.rb | 90 +++-- app/models/concerns/modelable.rb | 13 + app/models/funder.rb | 2 +- app/models/person.rb | 18 +- spec/concerns/modelable_spec.rb | 32 ++ .../find_actor/returns_actor_information.yml | 57 +++ .../returns_actor_information.yml | 75 ++++ .../returns_actor_information.yml | 53 +++ .../returns_actor_information.yml | 348 ++++++++++++++++++ .../Person/find_by_id/found_with_X_in_ID.yml | 53 +++ .../Person/find_by_id/not_found.yml | 10 +- spec/graphql/types/actor_item_spec.rb | 113 ++++++ spec/graphql/types/organization_type_spec.rb | 2 +- spec/graphql/types/person_type_spec.rb | 14 +- spec/models/person_spec.rb | 21 +- 24 files changed, 1010 insertions(+), 101 deletions(-) create mode 100644 app/graphql/types/actor_connection_type.rb create mode 100644 app/graphql/types/actor_edge_type.rb create mode 100644 app/graphql/types/actor_item.rb create mode 100644 spec/concerns/modelable_spec.rb create mode 100644 spec/fixtures/vcr_cassettes/ActorItem/find_actor/returns_actor_information.yml create mode 100644 spec/fixtures/vcr_cassettes/ActorItem/find_actor_funder/returns_actor_information.yml create mode 100644 spec/fixtures/vcr_cassettes/ActorItem/find_actor_person/returns_actor_information.yml create mode 100644 spec/fixtures/vcr_cassettes/ActorItem/query_actors/returns_actor_information.yml create mode 100644 spec/fixtures/vcr_cassettes/Person/find_by_id/found_with_X_in_ID.yml create mode 100644 spec/graphql/types/actor_item_spec.rb diff --git a/app/graphql/lupo_schema.rb b/app/graphql/lupo_schema.rb index 0af6f909f..a4352b128 100644 --- a/app/graphql/lupo_schema.rb +++ b/app/graphql/lupo_schema.rb @@ -5,15 +5,14 @@ class LupoSchema < GraphQL::Schema use GraphQL::Tracing::DataDogTracing, service: 'graphql' use ApolloFederation::Tracing + use GraphQL::Batch + use GraphQL::Cache default_max_page_size 1000 max_depth 10 # mutation(Types::MutationType) query(QueryType) - - use GraphQL::Batch - use GraphQL::Cache end GraphQL::Errors.configure(LupoSchema) do diff --git a/app/graphql/schema.graphql b/app/graphql/schema.graphql index 02547bed6..2f5eab91f 100644 --- a/app/graphql/schema.graphql +++ b/app/graphql/schema.graphql @@ -1,3 +1,64 @@ +""" +The connection type for ActorItem. +""" +type ActorConnection { + """ + A list of edges. + """ + edges: [ActorEdge] + + """ + A list of nodes. + """ + nodes: [ActorItem] + + """ + Information to aid in pagination. + """ + pageInfo: PageInfo! + totalCount: Int! +} + +""" +An edge in a connection. +""" +type ActorEdge { + """ + A cursor for use in pagination. + """ + cursor: String! + + """ + The item at the end of the edge. + """ + node: ActorItem +} + +""" +Information about people, research organizations and funders +""" +interface ActorItem { + """ + An alias for the actor. + """ + alternateName: [String!] + + """ + The persistent identifier for the actor. + """ + id: ID! + + """ + The name of the actor. + """ + name: String! + + """ + The type of the actor. + """ + type: String! +} + """ Information about addresses """ @@ -5260,14 +5321,14 @@ type Facet { """ Information about funders """ -type Funder { +type Funder implements ActorItem { """ Physical address of the funder. """ address: Address """ - An alias for the funder. + An alias for the actor. """ alternateName: [String!] @@ -5315,12 +5376,12 @@ type Funder { downloadCount: Int """ - Crossref Funder ID + The persistent identifier for the actor. """ id: ID! """ - The name of the funder. + The name of the actor. """ name: String! @@ -5391,7 +5452,7 @@ type Funder { ): SoftwareConnection """ - The type of the item. + The type of the actor. """ type: String! @@ -8155,14 +8216,14 @@ type ModelEdge { """ Information about organizations """ -type Organization { +type Organization implements ActorItem { """ Physical address of the organization. """ address: Address """ - An alias for the organization. + An alias for the actor. """ alternateName: [String!] @@ -8209,9 +8270,9 @@ type Organization { downloadCount: Int """ - ROR ID + The persistent identifier for the actor. """ - id: ID + id: ID! """ The identifier(s) for the organization. @@ -8219,7 +8280,7 @@ type Organization { identifiers: [Identifier!] """ - The name of the organization. + The name of the actor. """ name: String! @@ -8288,14 +8349,14 @@ type Organization { ): SoftwareConnection """ - The type of the item. + The type of the actor. """ type: String! """ URL of the organization. """ - url: [String!] + url: [Url!] """ The number of views according to the Counter Code of Practice. @@ -9290,12 +9351,17 @@ type PeerReviewEdge { """ A person. """ -type Person { +type Person implements ActorItem { """ Affiliations(s) of the person. """ affiliation: [Affiliation!] + """ + An alias for the actor. + """ + alternateName: [String!] + """ The number of citations. """ @@ -9349,19 +9415,14 @@ type Person { givenName: String """ - The ORCID ID of the person. - """ - id: ID - - """ - The name of the person. + The persistent identifier for the actor. """ - name: String + id: ID! """ - Other names. + The name of the actor. """ - otherNames: [String!] + name: String! """ Authored publications @@ -9428,7 +9489,7 @@ type Person { ): SoftwareConnection """ - The type of the item. + The type of the actor. """ type: String! @@ -10909,6 +10970,29 @@ type PublicationEdge { type Query { _service: _Service! + actor(id: ID!): ActorItem! + actors( + """ + Returns the elements in the list that come after the specified cursor. + """ + after: String + + """ + Returns the elements in the list that come before the specified cursor. + """ + before: String + + """ + Returns the first _n_ elements from the list. + """ + first: Int + + """ + Returns the last _n_ elements from the list. + """ + last: Int + query: String + ): ActorConnection! audiovisual(id: ID!): Audiovisual! audiovisuals( """ diff --git a/app/graphql/types/actor_connection_type.rb b/app/graphql/types/actor_connection_type.rb new file mode 100644 index 000000000..e11dffc76 --- /dev/null +++ b/app/graphql/types/actor_connection_type.rb @@ -0,0 +1,16 @@ +# frozen_string_literal: true + +class ActorConnectionType < BaseConnection + edge_type(ActorEdgeType) + field_class GraphQL::Cache::Field + + field :total_count, Integer, null: false, cache: true + + def total_count + args = object.arguments + + Organization.query(args[:query], limit: 0).dig(:meta, "total").to_i + + Funder.query(args[:query], limit: 0).dig(:meta, "total").to_i + + Person.query(args[:query], limit: 0).dig(:meta, "total").to_i + end +end diff --git a/app/graphql/types/actor_edge_type.rb b/app/graphql/types/actor_edge_type.rb new file mode 100644 index 000000000..7dda47f85 --- /dev/null +++ b/app/graphql/types/actor_edge_type.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +class ActorEdgeType < GraphQL::Types::Relay::BaseEdge + node_type(ActorItem) +end diff --git a/app/graphql/types/actor_item.rb b/app/graphql/types/actor_item.rb new file mode 100644 index 000000000..e5aa2809a --- /dev/null +++ b/app/graphql/types/actor_item.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true + +module ActorItem + include BaseInterface + include Bolognese::MetadataUtils + + description "Information about people, research organizations and funders" + + field :id, ID, null: false, description: "The persistent identifier for the actor." + field :type, String, null: false, description: "The type of the actor." + field :name, String, null: false, description: "The name of the actor." + field :alternate_name, [String], null: true, description: "An alias for the actor." + + definition_methods do + # Determine what object type to use for `object` + def resolve_type(object, context) + if object.type == "Person" + PersonType + elsif object.type == "Organization" + OrganizationType + elsif object.type == "Funder" + FunderType + else + raise "Unexpected Actor: #{object.inspect}" + end + end + end +end diff --git a/app/graphql/types/base_object.rb b/app/graphql/types/base_object.rb index 4f7779306..68d641ab2 100644 --- a/app/graphql/types/base_object.rb +++ b/app/graphql/types/base_object.rb @@ -15,10 +15,14 @@ def doi_from_url(url) def orcid_from_url(url) if /\A(?:(http|https):\/\/(orcid.org)\/)(.+)\z/.match?(url) uri = Addressable::URI.parse(url) - uri.path.gsub(/^\//, "").downcase + uri.path.gsub(/^\//, "").upcase end end + def ror_id_from_url(url) + Array(/\A(http|https):\/\/(ror\.org\/0\w{6}\d{2})\z/.match(url)).last + end + def facet_by_year(arr) arr.map do |hsh| { "id" => hsh["key_as_string"][0..3], diff --git a/app/graphql/types/funder_type.rb b/app/graphql/types/funder_type.rb index 6055f9d35..5a34b9c93 100644 --- a/app/graphql/types/funder_type.rb +++ b/app/graphql/types/funder_type.rb @@ -1,12 +1,10 @@ # frozen_string_literal: true class FunderType < BaseObject + implements ActorItem + description "Information about funders" - field :id, ID, null: false, description: "Crossref Funder ID" - field :type, String, null: false, description: "The type of the item." - field :name, String, null: false, description: "The name of the funder." - field :alternate_name, [String], null: true, description: "An alias for the funder." field :address, AddressType, null: true, description: "Physical address of the funder." field :view_count, Integer, null: true, description: "The number of views according to the Counter Code of Practice." field :download_count, Integer, null: true, description: "The number of downloads according to the Counter Code of Practice." diff --git a/app/graphql/types/organization_type.rb b/app/graphql/types/organization_type.rb index 916596133..12c948435 100644 --- a/app/graphql/types/organization_type.rb +++ b/app/graphql/types/organization_type.rb @@ -1,14 +1,12 @@ # frozen_string_literal: true class OrganizationType < BaseObject + implements ActorItem + description "Information about organizations" - field :id, ID, null: true, description: "ROR ID" - field :type, String, null: false, description: "The type of the item." - field :name, String, null: false, description: "The name of the organization." - field :alternate_name, [String], null: true, description: "An alias for the organization." field :identifiers, [IdentifierType], null: true, description: "The identifier(s) for the organization." - field :url, [String], null: true, hash_key: "links", description: "URL of the organization." + field :url, [Url], null: true, hash_key: "links", description: "URL of the organization." field :address, AddressType, null: true, description: "Physical address of the organization." field :view_count, Integer, null: true, description: "The number of views according to the Counter Code of Practice." field :download_count, Integer, null: true, description: "The number of downloads according to the Counter Code of Practice." diff --git a/app/graphql/types/person_type.rb b/app/graphql/types/person_type.rb index 9fdde3e97..b05ee5588 100644 --- a/app/graphql/types/person_type.rb +++ b/app/graphql/types/person_type.rb @@ -1,14 +1,12 @@ # frozen_string_literal: true class PersonType < BaseObject + implements ActorItem + description "A person." - field :id, ID, null: true, description: "The ORCID ID of the person." - field :type, String, null: false, description: "The type of the item." - field :name, String, null: true, description: "The name of the person." field :given_name, String, null: true, description: "Given name. In the U.S., the first name of a Person." field :family_name, String, null: true, description: "Family name. In the U.S., the last name of an Person." - field :other_names, [String], null: true, description: "Other names." field :affiliation, [AffiliationType], null: true, description: "Affiliations(s) of the person." field :view_count, Integer, null: true, description: "The number of views according to the Counter Code of Practice." field :download_count, Integer, null: true, description: "The number of downloads according to the Counter Code of Practice." diff --git a/app/graphql/types/query_type.rb b/app/graphql/types/query_type.rb index be5d81893..032a3f50f 100644 --- a/app/graphql/types/query_type.rb +++ b/app/graphql/types/query_type.rb @@ -3,7 +3,7 @@ class QueryType < BaseObject extend_type - field :members, MemberConnectionType, null: false, connection: true, max_page_size: 1000 do + field :members, MemberConnectionType, null: false, connection: true do argument :query, String, required: false argument :first, Int, required: false, default_value: 25 end @@ -20,7 +20,7 @@ def member(id:) Provider.unscoped.where("allocator.role_name IN ('ROLE_FOR_PROFIT_PROVIDER', 'ROLE_CONTRACTUAL_PROVIDER', 'ROLE_CONSORTIUM' , 'ROLE_CONSORTIUM_ORGANIZATION', 'ROLE_ALLOCATOR', 'ROLE_ADMIN', 'ROLE_MEMBER', 'ROLE_REGISTRATION_AGENCY')").where(deleted_at: nil).where(symbol: id).first end - field :repositories, RepositoryConnectionType, null: false, connection: true, max_page_size: 1000 do + field :repositories, RepositoryConnectionType, null: false, connection: true do argument :query, String, required: false argument :year, String, required: false argument :software, String, required: false @@ -56,7 +56,7 @@ def prefix(id:) Prefix.where(prefix: id).first end - field :funders, FunderConnectionType, null: false, connection: true, max_page_size: 1000 do + field :funders, FunderConnectionType, null: false, connection: true do argument :query, String, required: false argument :first, Int, required: false, default_value: 25 end @@ -87,7 +87,7 @@ def data_catalog(id:) result end - field :data_catalogs, DataCatalogConnectionType, null: false, connection: true, max_page_size: 1000 do + field :data_catalogs, DataCatalogConnectionType, null: false, connection: true do argument :query, String, required: false argument :first, Int, required: false, default_value: 25 end @@ -96,7 +96,7 @@ def data_catalogs(**args) DataCatalog.query(args[:query], limit: args[:first]).fetch(:data, []) end - field :organizations, OrganizationConnectionType, null: false, connection: true, max_page_size: 1000 do + field :organizations, OrganizationConnectionType, null: false, connection: true do argument :query, String, required: false end @@ -126,7 +126,7 @@ def person(id:) result end - field :people, PersonConnectionType, null: false, connection: true, max_page_size: 1000 do + field :people, PersonConnectionType, null: false, connection: true do argument :query, String, required: false argument :first, Int, required: false, default_value: 25 end @@ -135,7 +135,37 @@ def people(**args) Person.query(args[:query], rows: args[:first]).fetch(:data, []) end - field :works, WorkConnectionType, null: false, connection: true, max_page_size: 1000 do + field :actors, ActorConnectionType, null: false, connection: true do + argument :query, String, required: false + end + + def actors(**args) + Organization.query(args[:query]).fetch(:data, []) + + Funder.query(args[:query]).fetch(:data, []) + + Person.query(args[:query]).fetch(:data, []) + end + + field :actor, ActorItem, null: false do + argument :id, ID, required: true + end + + def actor(id:) + if orcid_from_url(id) + result = Person.find_by_id(id).fetch(:data, []).first + elsif ror_id_from_url(id) + result = Organization.find_by_id(id).fetch(:data, []).first + elsif doi_from_url(id).to_s.starts_with?("10.13039") + result = Funder.find_by_id(id).fetch(:data, []).first + else + result = nil + end + + fail ActiveRecord::RecordNotFound if result.nil? + + result + end + + field :works, WorkConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -165,7 +195,7 @@ def work(id:) set_doi(id) end - field :datasets, DatasetConnectionType, null: false, connection: true, max_page_size: 1000 do + field :datasets, DatasetConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -195,7 +225,7 @@ def dataset(id:) set_doi(id) end - field :publications, PublicationConnectionType, null: false, connection: true, max_page_size: 1000 do + field :publications, PublicationConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -225,7 +255,7 @@ def publication(id:) set_doi(id) end - field :audiovisuals, AudiovisualConnectionType, null: false, connection: true, max_page_size: 1000 do + field :audiovisuals, AudiovisualConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -255,7 +285,7 @@ def audiovisual(id:) set_doi(id) end - field :collections, CollectionConnectionType, null: false, connection: true, max_page_size: 1000 do + field :collections, CollectionConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -285,7 +315,7 @@ def collection(id:) set_doi(id) end - field :data_papers, DataPaperConnectionType, null: false, connection: true, max_page_size: 1000 do + field :data_papers, DataPaperConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -315,7 +345,7 @@ def data_paper(id:) set_doi(id) end - field :events, EventConnectionType, null: false, connection: true, max_page_size: 1000 do + field :events, EventConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -345,7 +375,7 @@ def event(id:) set_doi(id) end - field :images, ImageConnectionType, null: false, connection: true, max_page_size: 1000 do + field :images, ImageConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -375,7 +405,7 @@ def image(id:) set_doi(id) end - field :interactive_resources, InteractiveResourceConnectionType, null: false, connection: true, max_page_size: 1000 do + field :interactive_resources, InteractiveResourceConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -405,7 +435,7 @@ def interactive_resource(id:) set_doi(id) end - field :models, ModelConnectionType, null: false, connection: true, max_page_size: 1000 do + field :models, ModelConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -465,7 +495,7 @@ def physical_object(id:) set_doi(id) end - field :services, ServiceConnectionType, null: false, connection: true, max_page_size: 1000 do + field :services, ServiceConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -495,7 +525,7 @@ def service(id:) set_doi(id) end - field :softwares, SoftwareConnectionType, null: false, connection: true, max_page_size: 1000 do + field :softwares, SoftwareConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -525,7 +555,7 @@ def software(id:) set_doi(id) end - field :sounds, SoundConnectionType, null: false, connection: true, max_page_size: 1000 do + field :sounds, SoundConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -555,7 +585,7 @@ def sound(id:) set_doi(id) end - field :workflows, WorkflowConnectionType, null: false, connection: true, max_page_size: 1000 do + field :workflows, WorkflowConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -585,7 +615,7 @@ def workflow(id:) set_doi(id) end - field :dissertations, DissertationConnectionType, null: false, connection: true, max_page_size: 1000 do + field :dissertations, DissertationConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -616,7 +646,7 @@ def dissertation(id:) set_doi(id) end - field :preprints, PreprintConnectionType, null: false, connection: true, max_page_size: 1000 do + field :preprints, PreprintConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -647,7 +677,7 @@ def preprint(id:) set_doi(id) end - field :peer_reviews, PeerReviewConnectionType, null: false, connection: true, max_page_size: 1000 do + field :peer_reviews, PeerReviewConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -678,7 +708,7 @@ def peer_review(id:) set_doi(id) end - field :conference_papers, ConferencePaperConnectionType, null: false, connection: true, max_page_size: 1000 do + field :conference_papers, ConferencePaperConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -709,7 +739,7 @@ def conference_paper(id:) set_doi(id) end - field :book_chapters, BookChapterConnectionType, null: false, connection: true, max_page_size: 1000 do + field :book_chapters, BookChapterConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -740,7 +770,7 @@ def book_chapter(id:) set_doi(id) end - field :books, BookConnectionType, null: false, connection: true, max_page_size: 1000 do + field :books, BookConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -771,7 +801,7 @@ def book(id:) set_doi(id) end - field :journal_articles, JournalArticleConnectionType, null: false, connection: true, max_page_size: 1000 do + field :journal_articles, JournalArticleConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -802,7 +832,7 @@ def journal_article(id:) set_doi(id) end - field :instruments, InstrumentConnectionType, null: false, connection: true, max_page_size: 1000 do + field :instruments, InstrumentConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -834,7 +864,7 @@ def instrument(id:) set_doi(id) end - field :others, OtherConnectionType, null: false, connection: true, max_page_size: 1000 do + field :others, OtherConnectionType, null: false, connection: true do argument :query, String, required: false argument :ids, [String], required: false argument :user_id, String, required: false @@ -864,7 +894,7 @@ def other(id:) set_doi(id) end - field :usage_reports, UsageReportConnectionType, null: false, connection: true, max_page_size: 1000 do + field :usage_reports, UsageReportConnectionType, null: false, connection: true do argument :first, Int, required: false, default_value: 25 end diff --git a/app/models/concerns/modelable.rb b/app/models/concerns/modelable.rb index abe9841b8..43b9dc331 100644 --- a/app/models/concerns/modelable.rb +++ b/app/models/concerns/modelable.rb @@ -8,5 +8,18 @@ def doi_from_url(url) uri.path.gsub(/^\//, '').downcase end end + + def orcid_as_url(orcid) + return nil unless orcid.present? + + "https://orcid.org/#{orcid}" + end + + def orcid_from_url(url) + if /\A(?:(http|https):\/\/(orcid.org)\/)(.+)\z/.match?(url) + uri = Addressable::URI.parse(url) + uri.path.gsub(/^\//, "").upcase + end + end end end diff --git a/app/models/funder.rb b/app/models/funder.rb index 319b2572c..df27e4809 100644 --- a/app/models/funder.rb +++ b/app/models/funder.rb @@ -4,7 +4,7 @@ class Funder def self.find_by_id(id) doi = doi_from_url(id) - return [] unless doi.present? + return {} unless doi.present? url = "https://api.crossref.org/funders/#{doi}" response = Maremma.get(url, host: true) diff --git a/app/models/person.rb b/app/models/person.rb index 62da1c5c8..1ecdb8d06 100644 --- a/app/models/person.rb +++ b/app/models/person.rb @@ -54,7 +54,7 @@ def self.parse_message(message: nil) orcid = message.fetch("orcid-id", nil) given_name = message.fetch("given-names", nil) family_name = message.fetch("family-names", nil) - other_names = Array.wrap(message.fetch("other-name", nil)) + alternate_name = Array.wrap(message.fetch("other-name", nil)) if message.fetch("credit-name", nil).present? name = message.fetch("credit-name") elsif given_name.present? || family_name.present? @@ -62,6 +62,7 @@ def self.parse_message(message: nil) else name = orcid end + # TODO affiliation for find_by_id affiliation = Array.wrap(message.fetch("institution-name", nil)).map { |a| { name: a } }.compact Hashie::Mash.new({ @@ -70,21 +71,8 @@ def self.parse_message(message: nil) orcid: orcid, given_name: given_name, family_name: family_name, - other_names: other_names, + alternate_name: alternate_name, name: name, affiliation: affiliation }.compact) end - - def self.orcid_as_url(orcid) - return nil unless orcid.present? - - "https://orcid.org/#{orcid}" - end - - def self.orcid_from_url(url) - if /\A(?:(http|https):\/\/(orcid.org)\/)(.+)\z/.match?(url) - uri = Addressable::URI.parse(url) - uri.path.gsub(/^\//, "").downcase - end - end end diff --git a/spec/concerns/modelable_spec.rb b/spec/concerns/modelable_spec.rb new file mode 100644 index 000000000..a25210062 --- /dev/null +++ b/spec/concerns/modelable_spec.rb @@ -0,0 +1,32 @@ +require 'rails_helper' + +describe Person, vcr: true do + subject { Person } + + context "orcid_from_url" do + it "orcid" do + string = "https://orcid.org/0000-0003-2706-4082" + expect(subject.orcid_from_url(string)).to eq("0000-0003-2706-4082") + end + + it "orcid with lowercase X" do + string = "https://orcid.org/0000-0001-7701-701x" + expect(subject.orcid_from_url(string)).to eq("0000-0001-7701-701X") + end + + it "orcid without protocol" do + string = "orcid.org/0000-0003-2706-4082" + expect(subject.orcid_from_url(string)).to be_nil + end + + it "orcid not as url" do + string = "0000-0003-2706-4082" + expect(subject.orcid_from_url(string)).to be_nil + end + + it "invalid orcid" do + string = "XXXXX" + expect(subject.orcid_from_url(string)).to be_nil + end + end +end diff --git a/spec/fixtures/vcr_cassettes/ActorItem/find_actor/returns_actor_information.yml b/spec/fixtures/vcr_cassettes/ActorItem/find_actor/returns_actor_information.yml new file mode 100644 index 000000000..d25151ad6 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/ActorItem/find_actor/returns_actor_information.yml @@ -0,0 +1,57 @@ +--- +http_interactions: +- request: + method: get + uri: https://api.ror.org/organizations/ror.org/013meh722 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/4.6.1; mailto:info@datacite.org) + Accept: + - text/html,application/json,application/xml;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5 + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json + Connection: + - keep-alive + Date: + - Wed, 13 May 2020 06:02:31 GMT + Status: + - 200 OK + X-Frame-Options: + - SAMEORIGIN + Allow: + - GET, HEAD, OPTIONS + X-Powered-By: + - Phusion Passenger 6.0.4 + Server: + - nginx/1.17.3 + Phusion Passenger 6.0.4 + Content-Encoding: + - gzip + Vary: + - Accept-Encoding,Cookie,Origin + X-Cache: + - Hit from cloudfront + Via: + - 1.1 0b9e85cfe8fe19b385db56d32b4ce802.cloudfront.net (CloudFront) + X-Amz-Cf-Pop: + - FRA2-C1 + X-Amz-Cf-Id: + - L70W-Vc3HeXFSBegwtVIPvO0HcdjOkQO9rVTr0pAZmxXzqBUfzPN8w== + Age: + - '2262' + body: + encoding: ASCII-8BIT + string: !binary |- + H4sIAAAAAAAAA3xUXU/jMBD8K5WfURp/233jOI5DSBwFIR5OqAqJWyzSpHKS61Wo//3WDrR2daIv9eyOZ3c2m7wjW6EZeu37TTebTl3rstatpjmma/MqCUFnqCnWBiiPjf1jXGf73aRdTi6K9Yuz1coAod9tTIdmv9FlNZRFb9sGPZ+h2jZvIeq1QXq73WZlsc6KMhvepp5R1LboxpsHucmxTKCUrm12a88B1PVFP8AZwj2woPTWvtmNqWyxGFz94QNqmSY7ZIIfj6ZH6UW7XMQO6uLF1L7I+3gEpTtnl7tu1dZg1biVK7ZND0zbtYJqyJc7tIeWynZoerdDs/fP4+I4r95UkxvbrKp2jQ7URdlWPn/1De3PkPnbG9cU9cJWnRe5fri99v8bZ5bGOQMPpxnq2g+r9oPKxx8mWCmuKUPPIPJjaKp7szy5h3iOcWBLytFB4ST6CSXnJIKKkRygP+OcMRylBNE6goyQ+CJjOpblWsRZIZiIYM5VnkKeQhlDkZMU0hjKPLkrcaxMdSLFOI0hlzrpSpKkLtdJk5LFbWBB0p41TpvUCSRplqSOGEuhSiBP/ApBEwtg3+/Cz8uH8y8XCONxaR4vzh++Il74JRuZN3f3t19RfQdSKhXYv9zqP7tIuJaKS3LcwyhCpKY0rB9WOSX+WVAiZbAvKQ7rhrEAurfMlJB+igQ+UsKnmFY4jJlAxzKQOSZCjrelzkUISaLCdS658HOmUMw/Ogk7Sj8w/ZALy0+oZNAFDzVz0AwxPb4ZREBE43HoT/B5qYq+OHU9p7Ba7Oj5gOc4V1pj4R3OCRPQZGh8jhVWmgTRq/vr76eCK/hiZRyGleWfqklsv9//AwAA//8DALZf1ADSBQAA + http_version: null + recorded_at: Wed, 13 May 2020 06:40:13 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/fixtures/vcr_cassettes/ActorItem/find_actor_funder/returns_actor_information.yml b/spec/fixtures/vcr_cassettes/ActorItem/find_actor_funder/returns_actor_information.yml new file mode 100644 index 000000000..5fbc2f3ee --- /dev/null +++ b/spec/fixtures/vcr_cassettes/ActorItem/find_actor_funder/returns_actor_information.yml @@ -0,0 +1,75 @@ +--- +http_interactions: +- request: + method: get + uri: https://api.crossref.org/funders/10.13039/501100003987 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/4.6.1; mailto:info@datacite.org) + Accept: + - text/html,application/json,application/xml;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5 + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json;charset=UTF-8 + Vary: + - Accept + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - X-Requested-With + Content-Length: + - '3321' + Server: + - http-kit + Date: + - Wed, 13 May 2020 06:44:32 GMT + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + Connection: + - close + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"funder","message-version":"1.0.0","message":{"hierarchy-names":{"501100000621":"Girton + College, University of Cambridge","501100007552":"School of Clinical Medicine, + University of Cambridge","501100000609":"Emmanuel College, University of Cambridge","501100000705":"School + of the Biological Sciences, University of Cambridge","501100000602":"Department + of Anglo-Saxon, Norse and Celtic, Faculty of English, University of Cambridge","501100008101":"St\u00a0Catharine''s + College, University of Cambridge","501100000622":"Gonville and Caius College, + University of Cambridge","501100003987":"James Baird Fund, University of Cambridge","501100000663":"Newnham + College, University of Cambridge","501100000742":"Churchill College, University + of Cambridge","501100005705":"St. Edmund\u2019s College, University of Cambridge","501100009163":"Centre + of Latin American Studies, University of Cambridge","501100000653":"Magdalene + College, University of Cambridge","501100004537":"Institute for Aviation and + the Environment, University of Cambridge","501100004222":"Pembroke College, + University of Cambridge","501100004495":"Sir Arthur Marshall Institute for + Aeronautics, University of Cambridge","501100000591":"Corpus Christi College, + University of Cambridge","501100000595":"Darwin College, University of Cambridge","501100008420":"Homerton + College, University of Cambridge","501100000585":"Centre for Entrepreneurial + Learning, University of Cambridge","501100000644":"Jesus College, University + of Cambridge","501100000727":"Trinity College, University of Cambridge","501100000603":"Department + of Clinical Veterinary Medicine, University of Cambridge","501100000735":"University + of Cambridge","501100006299":"Department of Materials Science and Metallurgy, + University of Cambridge","501100000587":"Centre for Research in the Arts, + Social Sciences and Humanities, University of Cambridge","501100005796":"Department + of Biochemistry, University of Cambridge","more":null,"501100000590":"Christ''s + College, University of Cambridge","501100001625":"Clare College, University + of Cambridge","501100000648":"King''s College Cambridge, University of Cambridge","501100000580":"Cambridge + Institute for Medical Research, University of Cambridge","501100008931":"Sidney + Sussex College, University of Cambridge","501100000710":"Smuts Memorial Fund, + University of Cambridge"},"replaced-by":[],"work-count":12,"name":"James Baird + Fund, University of Cambridge","descendants":[],"descendant-work-count":12,"id":"501100003987","tokens":["james","baird","fund","university","of","cambridge"],"replaces":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100003987","hierarchy":{"501100000735":{"501100000621":{},"501100007552":{},"501100000609":{},"501100000705":{},"501100000602":{},"501100008101":{},"501100000622":{},"501100003987":{},"501100000663":{},"501100000742":{},"501100005705":{"more":true},"501100009163":{},"501100000653":{},"501100004537":{},"501100004222":{},"501100004495":{},"501100000591":{},"501100000595":{},"501100008420":{},"501100000585":{},"501100000644":{},"501100000727":{},"501100000603":{},"501100006299":{},"501100000587":{},"501100005796":{},"501100000590":{},"501100001625":{},"501100000648":{},"501100000580":{},"501100008931":{},"501100000710":{}}},"alt-names":[],"location":"United + Kingdom"}}' + http_version: null + recorded_at: Wed, 13 May 2020 06:44:32 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/fixtures/vcr_cassettes/ActorItem/find_actor_person/returns_actor_information.yml b/spec/fixtures/vcr_cassettes/ActorItem/find_actor_person/returns_actor_information.yml new file mode 100644 index 000000000..54e6b8056 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/ActorItem/find_actor_person/returns_actor_information.yml @@ -0,0 +1,53 @@ +--- +http_interactions: +- request: + method: get + uri: https://pub.orcid.org/v3.0/0000-0001-7701-701X/person + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/4.6.1; mailto:info@datacite.org) + Accept: + - application/json;charset=UTF-8 + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.16.1 + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Content-Type: + - application/json;charset=UTF-8 + Content-Encoding: + - gzip + Date: + - Wed, 13 May 2020 08:19:54 GMT + Expires: + - '0' + Pragma: + - no-cache + X-Xss-Protection: + - 1; mode=block + Access-Control-Allow-Origin: + - "*" + X-Content-Type-Options: + - nosniff + Connection: + - keep-alive + Set-Cookie: + - X-Mapping-fjhppofk=EDEB8B375DA428655747278237992826; path=/ + X-Frame-Options: + - DENY + body: + encoding: ASCII-8BIT + string: !binary |- + H4sIAAAAAAAAA42SwU6EMBCG36UXLzRLQ5R1j77AJp5MjIdCu8vE0pK2oA3Zd3fqArsqWklKWvrN908mjERx52lrBBxACiq4l2Sne6UyonmL+5HUVuLX+W4kA1c9btgtY9s7VrAi35anbFW0Ahf5PcJHGKSmMcFdUeTR2EDw+sBbUIHOHczX+5sHG6SOBDYlwE/EuV9nelsvpwEcVKDAByzs+kpBTTLScd/gOceH4mK0LOMrZ09Ranwj7aWr30dzAcnu+WXRbla8m2spZlRgjpZ3TZhdVjrJbR2h3qpE8Fc4Hf5djg3IlkMq5pNJ288YOrkQmORSY5uwtHgGUf0qw5uxImGeqLR50cVJvHtpNVcUhNQ+Sm1qLj8r/jGltZjT3zUdMgZ/9A+k7ow/oAMAAA== + http_version: null + recorded_at: Wed, 13 May 2020 08:19:54 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/fixtures/vcr_cassettes/ActorItem/query_actors/returns_actor_information.yml b/spec/fixtures/vcr_cassettes/ActorItem/query_actors/returns_actor_information.yml new file mode 100644 index 000000000..80415f398 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/ActorItem/query_actors/returns_actor_information.yml @@ -0,0 +1,348 @@ +--- +http_interactions: +- request: + method: get + uri: https://api.ror.org/organizations?query=Cambridge%20University + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/4.6.1; mailto:info@datacite.org) + Accept: + - text/html,application/json,application/xml;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5 + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json + Connection: + - keep-alive + Date: + - Wed, 13 May 2020 04:55:01 GMT + Status: + - 200 OK + X-Frame-Options: + - SAMEORIGIN + Allow: + - GET, HEAD, OPTIONS + X-Powered-By: + - Phusion Passenger 6.0.4 + Server: + - nginx/1.17.3 + Phusion Passenger 6.0.4 + Content-Encoding: + - gzip + Vary: + - Accept-Encoding,Cookie,Origin + X-Cache: + - Miss from cloudfront + Via: + - 1.1 3e9b9356decf1aa720af0bc92acc0586.cloudfront.net (CloudFront) + X-Amz-Cf-Pop: + - DUS51-C1 + X-Amz-Cf-Id: + - RhIuRqvysuc7Wiy19ZBF0FQiEKxgk7Iu026uaHo53hKpusY9JSeYTw== + body: + encoding: ASCII-8BIT + string: !binary |- + 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 + http_version: null + recorded_at: Wed, 13 May 2020 04:55:01 GMT +- request: + method: get + uri: https://api.crossref.org/funders?query=Cambridge%20University&rows=100 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/4.6.1; mailto:info@datacite.org) + Accept: + - text/html,application/json,application/xml;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5 + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json;charset=UTF-8 + Vary: + - Accept + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - X-Requested-With + Content-Length: + - '11336' + Server: + - http-kit + Date: + - Wed, 13 May 2020 04:55:01 GMT + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + Connection: + - close + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"funder-list","message-version":"1.0.0","message":{"items-per-page":100,"query":{"start-index":0,"search-terms":"Cambridge + University"},"total-results":36,"items":[{"id":"501100003987","location":"United + Kingdom","name":"James Baird Fund, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100003987","replaces":[],"replaced-by":[],"tokens":["james","baird","fund","university","of","cambridge"]},{"id":"501100000621","location":"United + Kingdom","name":"Girton College, University of Cambridge","alt-names":["Girton"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000621","replaces":[],"replaced-by":[],"tokens":["girton","college","university","of","cambridge","girton"]},{"id":"501100000705","location":"United + Kingdom","name":"School of the Biological Sciences, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000705","replaces":[],"replaced-by":[],"tokens":["school","of","the","biological","sciences","university","of","cambridge"]},{"id":"501100000585","location":"United + Kingdom","name":"Centre for Entrepreneurial Learning, University of Cambridge","alt-names":["CfEL"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000585","replaces":[],"replaced-by":[],"tokens":["centre","for","entrepreneurial","learning","university","of","cambridge","cfel"]},{"id":"501100008931","location":"United + Kingdom","name":"Sidney Sussex College, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100008931","replaces":[],"replaced-by":[],"tokens":["sidney","sussex","college","university","of","cambridge"]},{"id":"501100006299","location":"United + Kingdom","name":"Department of Materials Science and Metallurgy, University + of Cambridge","alt-names":["DMSM"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100006299","replaces":[],"replaced-by":[],"tokens":["department","of","materials","science","and","metallurgy","university","of","cambridge","dmsm"]},{"id":"501100000727","location":"United + Kingdom","name":"Trinity College, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000727","replaces":[],"replaced-by":[],"tokens":["trinity","college","university","of","cambridge"]},{"id":"501100004495","location":"United + Kingdom","name":"Sir Arthur Marshall Institute for Aeronautics, University + of Cambridge","alt-names":["SAMIA"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100004495","replaces":[],"replaced-by":[],"tokens":["sir","arthur","marshall","institute","for","aeronautics","university","of","cambridge","samia"]},{"id":"501100000580","location":"United + Kingdom","name":"Cambridge Institute for Medical Research, University of Cambridge","alt-names":["CIMR"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000580","replaces":[],"replaced-by":[],"tokens":["cambridge","institute","for","medical","research","university","of","cambridge","cimr"]},{"id":"501100000595","location":"United + Kingdom","name":"Darwin College, University of Cambridge","alt-names":["Darwin"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000595","replaces":[],"replaced-by":[],"tokens":["darwin","college","university","of","cambridge","darwin"]},{"id":"501100008101","location":"United + Kingdom","name":"St\u00a0Catharine''s College, University of Cambridge","alt-names":["St\u00a0Catharine''s + College"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100008101","replaces":[],"replaced-by":[],"tokens":["st\u00a0catharines","college","university","of","cambridge","st\u00a0catharines","college"]},{"id":"501100000602","location":"United + Kingdom","name":"Department of Anglo-Saxon, Norse and Celtic, Faculty of English, + University of Cambridge","alt-names":["ASNC"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000602","replaces":[],"replaced-by":[],"tokens":["department","of","anglo","saxon","norse","and","celtic","faculty","of","english","university","of","cambridge","asnc"]},{"id":"501100000648","location":"United + Kingdom","name":"King''s College Cambridge, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000648","replaces":[],"replaced-by":[],"tokens":["kings","college","cambridge","university","of","cambridge"]},{"id":"501100001625","location":"United + Kingdom","name":"Clare College, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100001625","replaces":[],"replaced-by":[],"tokens":["clare","college","university","of","cambridge"]},{"id":"501100004537","location":"United + Kingdom","name":"Institute for Aviation and the Environment, University of + Cambridge","alt-names":["University of Cambridge Institute for Aviation and + the Environment","IAE"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100004537","replaces":[],"replaced-by":[],"tokens":["institute","for","aviation","and","the","environment","university","of","cambridge","university","of","cambridge","institute","for","aviation","and","the","environment","iae"]},{"id":"501100002926","location":"United + Kingdom","name":"Cambridge University Hospitals","alt-names":["CUH"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100002926","replaces":[],"replaced-by":[],"tokens":["cambridge","university","hospitals","cuh"]},{"id":"501100000653","location":"United + Kingdom","name":"Magdalene College, University of Cambridge","alt-names":["Magdalene + College"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000653","replaces":[],"replaced-by":[],"tokens":["magdalene","college","university","of","cambridge","magdalene","college"]},{"id":"501100000742","location":"United + Kingdom","name":"Churchill College, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000742","replaces":[],"replaced-by":[],"tokens":["churchill","college","university","of","cambridge"]},{"id":"501100000590","location":"United + Kingdom","name":"Christ''s College, University of Cambridge","alt-names":["Christ''s + College"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000590","replaces":[],"replaced-by":[],"tokens":["christs","college","university","of","cambridge","christs","college"]},{"id":"501100000644","location":"United + Kingdom","name":"Jesus College, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000644","replaces":[],"replaced-by":[],"tokens":["jesus","college","university","of","cambridge"]},{"id":"501100005796","location":"United + Kingdom","name":"Department of Biochemistry, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100005796","replaces":[],"replaced-by":[],"tokens":["department","of","biochemistry","university","of","cambridge"]},{"id":"501100000591","location":"United + Kingdom","name":"Corpus Christi College, University of Cambridge","alt-names":["Corpus + Christi College"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000591","replaces":[],"replaced-by":[],"tokens":["corpus","christi","college","university","of","cambridge","corpus","christi","college"]},{"id":"501100004222","location":"United + Kingdom","name":"Pembroke College, University of Cambridge","alt-names":["Pembroke + College, Cambridge","Pembroke"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100004222","replaces":[],"replaced-by":[],"tokens":["pembroke","college","university","of","cambridge","pembroke","college","cambridge","pembroke"]},{"id":"501100000609","location":"United + Kingdom","name":"Emmanuel College, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000609","replaces":[],"replaced-by":[],"tokens":["emmanuel","college","university","of","cambridge"]},{"id":"501100000603","location":"United + Kingdom","name":"Department of Clinical Veterinary Medicine, University of + Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000603","replaces":[],"replaced-by":[],"tokens":["department","of","clinical","veterinary","medicine","university","of","cambridge"]},{"id":"100010441","location":"United + Kingdom","name":"Department of Earth Sciences, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/100010441","replaces":[],"replaced-by":[],"tokens":["department","of","earth","sciences","university","of","cambridge"]},{"id":"501100005705","location":"United + Kingdom","name":"St. Edmund\u2019s College, University of Cambridge","alt-names":["St + Edmund\u2019s College, University of Cambridge"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100005705","replaces":[],"replaced-by":[],"tokens":["st","edmund\u2019s","college","university","of","cambridge","st","edmund\u2019s","college","university","of","cambridge"]},{"id":"501100000710","location":"United + Kingdom","name":"Smuts Memorial Fund, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000710","replaces":[],"replaced-by":[],"tokens":["smuts","memorial","fund","university","of","cambridge"]},{"id":"501100000587","location":"United + Kingdom","name":"Centre for Research in the Arts, Social Sciences and Humanities, + University of Cambridge","alt-names":["CRASSH"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000587","replaces":[],"replaced-by":[],"tokens":["centre","for","research","in","the","arts","social","sciences","and","humanities","university","of","cambridge","crassh"]},{"id":"501100008420","location":"United + Kingdom","name":"Homerton College, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100008420","replaces":[],"replaced-by":[],"tokens":["homerton","college","university","of","cambridge"]},{"id":"501100007552","location":"United + Kingdom","name":"School of Clinical Medicine, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100007552","replaces":[],"replaced-by":[],"tokens":["school","of","clinical","medicine","university","of","cambridge"]},{"id":"501100009163","location":"United + Kingdom","name":"Centre of Latin American Studies, University of Cambridge","alt-names":["Centre + of Latin American Studies"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100009163","replaces":[],"replaced-by":[],"tokens":["centre","of","latin","american","studies","university","of","cambridge","centre","of","latin","american","studies"]},{"id":"501100000663","location":"United + Kingdom","name":"Newnham College, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000663","replaces":[],"replaced-by":[],"tokens":["newnham","college","university","of","cambridge"]},{"id":"501100000735","location":"United + Kingdom","name":"University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000735","replaces":[],"replaced-by":[],"tokens":["university","of","cambridge"]},{"id":"501100000622","location":"United + Kingdom","name":"Gonville and Caius College, University of Cambridge","alt-names":[],"uri":"http:\/\/dx.doi.org\/10.13039\/501100000622","replaces":[],"replaced-by":[],"tokens":["gonville","and","caius","college","university","of","cambridge"]},{"id":"501100002927","location":"United + Kingdom","name":"Addenbrooke''s Charitable Trust, Cambridge University Hospitals","alt-names":["ACT","Addenbrooke''s + Charitable Trust, Cambridge University Hospitals NHS Foundation Trust"],"uri":"http:\/\/dx.doi.org\/10.13039\/501100002927","replaces":[],"replaced-by":[],"tokens":["addenbrookes","charitable","trust","cambridge","university","hospitals","act","addenbrookes","charitable","trust","cambridge","university","hospitals","nhs","foundation","trust"]}]}}' + http_version: null + recorded_at: Wed, 13 May 2020 04:55:01 GMT +- request: + method: get + uri: https://pub.orcid.org/v3.0/expanded-search/?q=Cambridge%20University&rows=25&start=1 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/4.6.1; mailto:info@datacite.org) + Accept: + - application/json;charset=UTF-8 + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.16.1 + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Content-Type: + - application/json;charset=UTF-8 + Content-Encoding: + - gzip + Date: + - Wed, 13 May 2020 04:55:06 GMT + Expires: + - '0' + Pragma: + - no-cache + X-Xss-Protection: + - 1; mode=block + Access-Control-Allow-Origin: + - "*" + X-Content-Type-Options: + - nosniff + Connection: + - keep-alive + Set-Cookie: + - X-Mapping-fjhppofk=ED381B330E0E589099E2A39D5201DC2A; path=/ + X-Frame-Options: + - DENY + body: + encoding: ASCII-8BIT + string: !binary |- + H4sIAAAAAAAAA8VY3XLaOBR+FQ033Z3BHdsYjHtHSjZJm1AG6HZ3O70Q9sHWRkiMZCUhnT7CvsO+y+6D7REhgVQ2TRq6yUzASLJ0fr/zHX1uwNWCigwyT4E2vGy8+vi5IVXKMo9ljVcNH/88/A+9KO62vW4riBvNRs4uQHiCzkHjmjeyEDg4o3PGl3ejIybOcTRVkLFyNdp4JQznzYYsC1DrkY+fmg2YU8ZvHpnQJStNyaS4XdB4L/A0pVm5JHJGXtP5VLEsh8anL81KUQOv24ljLwqiliPqkaIFnZM3q5+OyAdGlVL8UKGbdTNNMqZMlMQa84UmryXnULH+3dVMqqxW95bnR0nixXHSrnQTOWNpQYG7uh9ml1Rl+n9W/1SKDI+sUyf04ij2vaTr+446Y7koGLiKvKHp+b7UOKbqAq1CNkLXO7B+hgyhBFVIox/tz8CLQ/xI/Nj150hOQZWuAVBoDs+SeS2vlbQw/ZKum3nj3qB/MnSl7R8eDHqT473I2xM5Z5SMjD5n4r7T6qaIt+UnfFoYvWt1TxepkrOSnAh0qaD2eMrJgdFMgNZknBZS2uzabLre5P4L6/TG03fI3IcpCIQrK9EHqXhGDjOTrrYgY1AXLAWN+6Y7/BF0OqEXdju/Of44o6pkFbD9gXJdPMAb6w3I5CW5eeXb7hkAx8QkZ7becEp6M8VSai1zt9SG2ThlIFIguIpMIC2E5DK35thkUZM8OgedmXEBsxkDnrkzRmu4Wtmcz6zAa2fVn1qfvUkrTBC+OqFj/wMQf6LlKzxwZJZ7yYYDJS/FU6ELQQb33hhhV9VNOvgRxC5UHzGDMe5qOpGKCbkXZY+4nNq8KiiKKfJVYrCSYbJc7AyXE85RBKbvohDsintx95aJfFORd212Sm1G9OZwE9hHIHNFbZXSZAQaqEoLMoDyUqpz8tNp78h7//ZnfG0Al+R3O/ba7tmHBWbWHJAL2O3t0JBTIVAKmwRSlGzGUoSMWzkymiGhwUdGhTXySC7REmOJeXTP6Xbd4dUKhTJJMrAayfl05ZjtNTjDpUZgylYcaUvdW9RaV+0nJts/f5MTQy9IxsivIOD6RhA1pYLpOUFDYgSQtV/H0pQFUbdGzJU0i8fnI+JhO/C9qJNU4KEymeEVQfq+NOdGsedhheQMj0yxtuxaYpSiS7ImcLXMcfPCTZFajWHwY6jyzTH16d1O/A7W98A1HQImFVU8xNbEZ7Ib5pQtnd+ELexr2m0skUnH7Wt6osSMqugTRjS7hgv271/M6OfqFoZIQ0hvCpwTTqffXDlgpU6Lc3jQ4jFT5IByqs1U0TnmI4KZfa8+ODqdoOP5SbtVwTPEtZTKVLQcKH3G9kPUN47vYfHW2sLnioVZ1jU1CrGrUEyX+GUsgNyriscsx8O2yFUvpRnM7dS7BdSV0O+nHiOgmUXzHaQfGx4Pm1g3JscUO1jXlGcsy/ZE+neo/IQKsHHQKcOgUuzr2mJjVJZYP3NM2x0IHkZ+4vlB1KmGIQFVQHQOYgrpfq4jvkKWfXDRvlFWaadq2qKHLUkpRXMLtI+NTcnSWrAe1fwEiWfX70QuqhVzyFwjnVxfswyZ99c2avQVWb1CtlY80mT3GdQmeCZY4B9vvXqlgzCMvdiP3RLVRwiriIxThARQ++k9jS4V5RYqB7dd3oO49y6ygj6MIz9wQbXuFgf70+nymUpuH9sNdPQDOoU4th9+BZUYSbV0tXr34kAt4Zku5sgEmxQ7eIytxa4SGMVdrxsnXUepAdNFBbHsS12wPVe/LR2GyJYtxg7NlLN0DbvLrQ77u1IsaoeYZ7FfkWIISlUh+QF0uRctb/qaWxBBeYfFUttOSOjVZcHYqBwk/sCpIyQvubx8BAbbBgwHV33YBGha2FA+lnrBSjx1cDwmv0gjshuCMFGY7TsyN0o6kYethpu5I8irev5TmlOaOti7Wk3uJvd0HVZ951UZRLcG0NUWaCISadREPw3qQi9pxfgUxS5/PLR2qkoe7MkedFH1I645w3aMMkehK+4fBVirV7kYAzXfi7wTbVmSoU+tL60AqVTYabu5PCwYZ4tFBWiNSwCXaN69QM5ekrslj1TrjOYZ5SBgn9RqE9X3SUjNRTzp8dVlA9dbZQzlFWbuzWz0N14FcbcdBsGX/wC9xMP0OxsAAA== + http_version: null + recorded_at: Wed, 13 May 2020 04:55:06 GMT +- request: + method: get + uri: https://api.ror.org/organizations?query=Cambridge%20University + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/4.6.1; mailto:info@datacite.org) + Accept: + - text/html,application/json,application/xml;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5 + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json + Connection: + - keep-alive + Date: + - Wed, 13 May 2020 04:55:01 GMT + Status: + - 200 OK + X-Frame-Options: + - SAMEORIGIN + Allow: + - GET, HEAD, OPTIONS + X-Powered-By: + - Phusion Passenger 6.0.4 + Server: + - nginx/1.17.3 + Phusion Passenger 6.0.4 + Content-Encoding: + - gzip + Vary: + - Accept-Encoding,Cookie,Origin + X-Cache: + - Hit from cloudfront + Via: + - 1.1 877a7509af39a63279b2520fa0b455fa.cloudfront.net (CloudFront) + X-Amz-Cf-Pop: + - DUS51-C1 + X-Amz-Cf-Id: + - euD_b0lctTOgpfxl5r-Z_F2TNoAzRSzT4N51Eqg0iAbB1M9aXjrYHA== + Age: + - '5' + body: + encoding: ASCII-8BIT + string: !binary |- + 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 + http_version: null + recorded_at: Wed, 13 May 2020 04:55:06 GMT +- request: + method: get + uri: https://api.crossref.org/funders?query=Cambridge%20University&rows=0 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/4.6.1; mailto:info@datacite.org) + Accept: + - text/html,application/json,application/xml;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5 + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Content-Type: + - application/json;charset=UTF-8 + Vary: + - Accept + Access-Control-Allow-Origin: + - "*" + Access-Control-Allow-Headers: + - X-Requested-With + Content-Length: + - '195' + Server: + - http-kit + Date: + - Wed, 13 May 2020 04:55:07 GMT + X-Rate-Limit-Limit: + - '50' + X-Rate-Limit-Interval: + - 1s + Connection: + - close + body: + encoding: ASCII-8BIT + string: '{"status":"ok","message-type":"funder-list","message-version":"1.0.0","message":{"items-per-page":0,"query":{"start-index":0,"search-terms":"Cambridge + University"},"total-results":36,"items":[]}}' + http_version: null + recorded_at: Wed, 13 May 2020 04:55:07 GMT +- request: + method: get + uri: https://pub.orcid.org/v3.0/expanded-search/?q=Cambridge%20University&rows=25&start=1 + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/4.6.1; mailto:info@datacite.org) + Accept: + - application/json;charset=UTF-8 + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.16.1 + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Content-Type: + - application/json;charset=UTF-8 + Content-Encoding: + - gzip + Date: + - Wed, 13 May 2020 04:55:08 GMT + Expires: + - '0' + Pragma: + - no-cache + X-Xss-Protection: + - 1; mode=block + Access-Control-Allow-Origin: + - "*" + X-Content-Type-Options: + - nosniff + Connection: + - keep-alive + Set-Cookie: + - X-Mapping-fjhppofk=ED381B330E0E589099E2A39D5201DC2A; path=/ + X-Frame-Options: + - DENY + body: + encoding: ASCII-8BIT + string: !binary |- + H4sIAAAAAAAAA8VY3XLaOBR+FQ033Z3BHdsYjHtHSjZJm1AG6HZ3O70Q9sHWRkiMZCUhnT7CvsO+y+6D7REhgVQ2TRq6yUzASLJ0fr/zHX1uwNWCigwyT4E2vGy8+vi5IVXKMo9ljVcNH/88/A+9KO62vW4riBvNRs4uQHiCzkHjmjeyEDg4o3PGl3ejIybOcTRVkLFyNdp4JQznzYYsC1DrkY+fmg2YU8ZvHpnQJStNyaS4XdB4L/A0pVm5JHJGXtP5VLEsh8anL81KUQOv24ljLwqiliPqkaIFnZM3q5+OyAdGlVL8UKGbdTNNMqZMlMQa84UmryXnULH+3dVMqqxW95bnR0nixXHSrnQTOWNpQYG7uh9ml1Rl+n9W/1SKDI+sUyf04ij2vaTr+446Y7koGLiKvKHp+b7UOKbqAq1CNkLXO7B+hgyhBFVIox/tz8CLQ/xI/Nj150hOQZWuAVBoDs+SeS2vlbQw/ZKum3nj3qB/MnSl7R8eDHqT473I2xM5Z5SMjD5n4r7T6qaIt+UnfFoYvWt1TxepkrOSnAh0qaD2eMrJgdFMgNZknBZS2uzabLre5P4L6/TG03fI3IcpCIQrK9EHqXhGDjOTrrYgY1AXLAWN+6Y7/BF0OqEXdju/Of44o6pkFbD9gXJdPMAb6w3I5CW5eeXb7hkAx8QkZ7becEp6M8VSai1zt9SG2ThlIFIguIpMIC2E5DK35thkUZM8OgedmXEBsxkDnrkzRmu4Wtmcz6zAa2fVn1qfvUkrTBC+OqFj/wMQf6LlKzxwZJZ7yYYDJS/FU6ELQQb33hhhV9VNOvgRxC5UHzGDMe5qOpGKCbkXZY+4nNq8KiiKKfJVYrCSYbJc7AyXE85RBKbvohDsintx95aJfFORd212Sm1G9OZwE9hHIHNFbZXSZAQaqEoLMoDyUqpz8tNp78h7//ZnfG0Al+R3O/ba7tmHBWbWHJAL2O3t0JBTIVAKmwRSlGzGUoSMWzkymiGhwUdGhTXySC7REmOJeXTP6Xbd4dUKhTJJMrAayfl05ZjtNTjDpUZgylYcaUvdW9RaV+0nJts/f5MTQy9IxsivIOD6RhA1pYLpOUFDYgSQtV/H0pQFUbdGzJU0i8fnI+JhO/C9qJNU4KEymeEVQfq+NOdGsedhheQMj0yxtuxaYpSiS7ImcLXMcfPCTZFajWHwY6jyzTH16d1O/A7W98A1HQImFVU8xNbEZ7Ib5pQtnd+ELexr2m0skUnH7Wt6osSMqugTRjS7hgv271/M6OfqFoZIQ0hvCpwTTqffXDlgpU6Lc3jQ4jFT5IByqs1U0TnmI4KZfa8+ODqdoOP5SbtVwTPEtZTKVLQcKH3G9kPUN47vYfHW2sLnioVZ1jU1CrGrUEyX+GUsgNyriscsx8O2yFUvpRnM7dS7BdSV0O+nHiOgmUXzHaQfGx4Pm1g3JscUO1jXlGcsy/ZE+neo/IQKsHHQKcOgUuzr2mJjVJZYP3NM2x0IHkZ+4vlB1KmGIQFVQHQOYgrpfq4jvkKWfXDRvlFWaadq2qKHLUkpRXMLtI+NTcnSWrAe1fwEiWfX70QuqhVzyFwjnVxfswyZ99c2avQVWb1CtlY80mT3GdQmeCZY4B9vvXqlgzCMvdiP3RLVRwiriIxThARQ++k9jS4V5RYqB7dd3oO49y6ygj6MIz9wQbXuFgf70+nymUpuH9sNdPQDOoU4th9+BZUYSbV0tXr34kAt4Zku5sgEmxQ7eIytxa4SGMVdrxsnXUepAdNFBbHsS12wPVe/LR2GyJYtxg7NlLN0DbvLrQ77u1IsaoeYZ7FfkWIISlUh+QF0uRctb/qaWxBBeYfFUttOSOjVZcHYqBwk/sCpIyQvubx8BAbbBgwHV33YBGha2FA+lnrBSjx1cDwmv0gjshuCMFGY7TsyN0o6kYethpu5I8irev5TmlOaOti7Wk3uJvd0HVZ951UZRLcG0NUWaCISadREPw3qQi9pxfgUxS5/PLR2qkoe7MkedFH1I645w3aMMkehK+4fBVirV7kYAzXfi7wTbVmSoU+tL60AqVTYabu5PCwYZ4tFBWiNSwCXaN69QM5ekrslj1TrjOYZ5SBgn9RqE9X3SUjNRTzp8dVlA9dbZQzlFWbuzWz0N14FcbcdBsGX/wC9xMP0OxsAAA== + http_version: null + recorded_at: Wed, 13 May 2020 04:55:08 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/fixtures/vcr_cassettes/Person/find_by_id/found_with_X_in_ID.yml b/spec/fixtures/vcr_cassettes/Person/find_by_id/found_with_X_in_ID.yml new file mode 100644 index 000000000..c22176685 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/Person/find_by_id/found_with_X_in_ID.yml @@ -0,0 +1,53 @@ +--- +http_interactions: +- request: + method: get + uri: https://pub.orcid.org/v3.0/0000-0001-7701-701X/person + body: + encoding: US-ASCII + string: '' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/4.6.1; mailto:info@datacite.org) + Accept: + - application/json;charset=UTF-8 + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Server: + - nginx/1.16.1 + Cache-Control: + - no-cache, no-store, max-age=0, must-revalidate + Content-Type: + - application/json;charset=UTF-8 + Content-Encoding: + - gzip + Date: + - Wed, 13 May 2020 08:14:53 GMT + Expires: + - '0' + Pragma: + - no-cache + X-Xss-Protection: + - 1; mode=block + Access-Control-Allow-Origin: + - "*" + X-Content-Type-Options: + - nosniff + Connection: + - keep-alive + Set-Cookie: + - X-Mapping-fjhppofk=ED381B330E0E589099E2A39D5201DC2A; path=/ + X-Frame-Options: + - DENY + body: + encoding: ASCII-8BIT + string: !binary |- + H4sIAAAAAAAAA42SwU6EMBCG36UXLzRLQ5R1j77AJp5MjIdCu8vE0pK2oA3Zd3fqArsqWklKWvrN908mjERx52lrBBxACiq4l2Sne6UyonmL+5HUVuLX+W4kA1c9btgtY9s7VrAi35anbFW0Ahf5PcJHGKSmMcFdUeTR2EDw+sBbUIHOHczX+5sHG6SOBDYlwE/EuV9nelsvpwEcVKDAByzs+kpBTTLScd/gOceH4mK0LOMrZ09Ranwj7aWr30dzAcnu+WXRbla8m2spZlRgjpZ3TZhdVjrJbR2h3qpE8Fc4Hf5djg3IlkMq5pNJ288YOrkQmORSY5uwtHgGUf0qw5uxImGeqLR50cVJvHtpNVcUhNQ+Sm1qLj8r/jGltZjT3zUdMgZ/9A+k7ow/oAMAAA== + http_version: null + recorded_at: Wed, 13 May 2020 08:14:53 GMT +recorded_with: VCR 5.1.0 diff --git a/spec/fixtures/vcr_cassettes/Person/find_by_id/not_found.yml b/spec/fixtures/vcr_cassettes/Person/find_by_id/not_found.yml index eec7b9d43..8ca98bf5a 100644 --- a/spec/fixtures/vcr_cassettes/Person/find_by_id/not_found.yml +++ b/spec/fixtures/vcr_cassettes/Person/find_by_id/not_found.yml @@ -2,7 +2,7 @@ http_interactions: - request: method: get - uri: https://pub.orcid.org/v3.0/xxxxx/person + uri: https://pub.orcid.org/v3.0/XXXXX/person body: encoding: US-ASCII string: '' @@ -27,7 +27,7 @@ http_interactions: Content-Encoding: - gzip Date: - - Wed, 08 Apr 2020 17:09:17 GMT + - Wed, 13 May 2020 08:16:45 GMT Expires: - '0' Pragma: @@ -41,13 +41,13 @@ http_interactions: Connection: - keep-alive Set-Cookie: - - X-Mapping-fjhppofk=26484D0F5DA32D2D6AF64AA1C9DBBA16; path=/ + - X-Mapping-fjhppofk=EDEB8B375DA428655747278237992826; path=/ X-Frame-Options: - DENY body: encoding: ASCII-8BIT string: !binary |- - H4sIAAAAAAAAA32OwQrCMAyGXyX0vK0KIrirInhREF+grnErdM1I2imI724ningxhxzy5/uSu2KUgYJg2ZBFVS9mi0JZHNHTgFz2KGLaPFc5gD1F2FIKtoZTh5BRStwgXI1AyNllyirYJu9hNN5ZEx0FQGbiGg7H9W4DbgO3qb6AKlSSn1t/5Hn5pXu/u5rNl4XqibF04UKZ7WIcpNa6x/6MLBVx42zurTaD0x+r6MiUzh6lI4outOrxBN6+4ecLAQAA + H4sIAAAAAAAAA32OwQrCMAyGXyX0vFmFIbirInhREA9euzVuha4ZSTsP4rtbRREv5pBD/nxfclOMMlIQLFuyqOpqXhXK4oSeRuRyQBHT5bnKAewpwpZSsDWceoSMUuIW4WoEQs4uz2wG2+Q9TMY7a6KjAMhMXMPhuN5twG3g/KwvoAqV5OfWH3lefune767mi2WhBmIsXbhQZvsYR6m1HnBokGVG3Dqbe6fN6PTHKjoypcaj9ETRhU7dH308uiALAQAA http_version: null - recorded_at: Wed, 08 Apr 2020 17:09:17 GMT + recorded_at: Wed, 13 May 2020 08:16:45 GMT recorded_with: VCR 5.1.0 diff --git a/spec/graphql/types/actor_item_spec.rb b/spec/graphql/types/actor_item_spec.rb new file mode 100644 index 000000000..e5aaab7a7 --- /dev/null +++ b/spec/graphql/types/actor_item_spec.rb @@ -0,0 +1,113 @@ +require "rails_helper" + +describe ActorItem do + describe "fields" do + subject { described_class } + + it { is_expected.to have_field(:id).of_type(!types.ID) } + it { is_expected.to have_field(:type).of_type("String!") } + it { is_expected.to have_field(:name).of_type("String!") } + end + + describe "find actor", vcr: true do + let(:query) do + %(query { + actor(id: "https://ror.org/013meh722") { + id + type + name + alternateName + } + }) + end + + it "returns actor information" do + response = LupoSchema.execute(query).as_json + + expect(response.dig("data", "actor", "id")).to eq("https://ror.org/013meh722") + expect(response.dig("data", "actor", "type")).to eq("Organization") + expect(response.dig("data", "actor", "name")).to eq("University of Cambridge") + end + end + + describe "find actor funder", vcr: true do + let(:query) do + %(query { + actor(id: "https://doi.org/10.13039/501100003987") { + id + type + name + alternateName + } + }) + end + + it "returns actor information" do + response = LupoSchema.execute(query).as_json + + expect(response.dig("data", "actor", "id")).to eq("https://doi.org/10.13039/501100003987") + expect(response.dig("data", "actor", "type")).to eq("Funder") + expect(response.dig("data", "actor", "name")).to eq("James Baird Fund, University of Cambridge") + end + end + + describe "find actor person", vcr: true do + let(:query) do + %(query { + actor(id: "https://orcid.org/0000-0001-7701-701X") { + id + type + name + alternateName + } + }) + end + + it "returns actor information" do + response = LupoSchema.execute(query).as_json + + expect(response.dig("data", "actor", "id")).to eq("https://orcid.org/0000-0001-7701-701X") + expect(response.dig("data", "actor", "type")).to eq("Person") + expect(response.dig("data", "actor", "name")).to eq("Rory O'Bryen") + expect(response.dig("data", "actor", "alternateName")).to eq([]) + end + end + + describe "query actors", vcr: true do + let(:query) do + %(query { + actors(query: "Cambridge University") { + totalCount + nodes { + id + type + name + alternateName + ... on Person { + affiliation { + name + } + } + } + } + }) + end + + it "returns actor information" do + response = LupoSchema.execute(query).as_json + + expect(response.dig("data", "actors", "totalCount")).to eq(1796010) + expect(response.dig("data", "actors", "nodes").length).to eq(81) + organization = response.dig("data", "actors", "nodes", 0) + expect(organization.fetch("id")).to eq("https://ror.org/013meh722") + expect(organization.fetch("name")).to eq("University of Cambridge") + funder = response.dig("data", "actors", "nodes", 20) + expect(funder.fetch("id")).to eq("https://doi.org/10.13039/501100003987") + expect(funder.fetch("name")).to eq("James Baird Fund, University of Cambridge") + person = response.dig("data", "actors", "nodes", 74) + expect(person.fetch("id")).to eq("https://orcid.org/0000-0001-7701-701X") + expect(person.fetch("name")).to eq("Rory O'Bryen") + expect(person.fetch("affiliation")).to eq([{"name"=>"University of Cambridge"}, {"name"=>"University of Cambridge Trinity Hall"}]) + end + end +end diff --git a/spec/graphql/types/organization_type_spec.rb b/spec/graphql/types/organization_type_spec.rb index 6a4a24cb0..b14baa4d2 100644 --- a/spec/graphql/types/organization_type_spec.rb +++ b/spec/graphql/types/organization_type_spec.rb @@ -4,7 +4,7 @@ describe "fields" do subject { described_class } - it { is_expected.to have_field(:id).of_type(types.ID) } + it { is_expected.to have_field(:id).of_type(!types.ID) } it { is_expected.to have_field(:type).of_type("String!") } it { is_expected.to have_field(:name).of_type("String!") } it { is_expected.to have_field(:alternateName).of_type("[String!]") } diff --git a/spec/graphql/types/person_type_spec.rb b/spec/graphql/types/person_type_spec.rb index bcbf0a15b..10f858f97 100644 --- a/spec/graphql/types/person_type_spec.rb +++ b/spec/graphql/types/person_type_spec.rb @@ -4,12 +4,12 @@ describe "fields" do subject { described_class } - it { is_expected.to have_field(:id).of_type(types.ID) } + it { is_expected.to have_field(:id).of_type(!types.ID) } it { is_expected.to have_field(:type).of_type("String!") } - it { is_expected.to have_field(:name).of_type("String") } + it { is_expected.to have_field(:name).of_type("String!") } it { is_expected.to have_field(:givenName).of_type("String") } it { is_expected.to have_field(:familyName).of_type("String") } - it { is_expected.to have_field(:otherNames).of_type("[String!]") } + it { is_expected.to have_field(:alternateName).of_type("[String!]") } it { is_expected.to have_field(:citationCount).of_type("Int") } it { is_expected.to have_field(:viewCount).of_type("Int") } it { is_expected.to have_field(:downloadCount).of_type("Int") } @@ -49,7 +49,7 @@ name givenName familyName - otherNames + alternateName affiliation { name } @@ -85,7 +85,7 @@ expect(response.dig("data", "person", "name")).to eq("K. J. Garza") expect(response.dig("data", "person", "givenName")).to eq("Kristian") expect(response.dig("data", "person", "familyName")).to eq("Garza") - expect(response.dig("data", "person", "otherNames")).to eq([]) + expect(response.dig("data", "person", "alternateName")).to eq([]) expect(response.dig("data", "person", "affiliation")).to eq([]) expect(response.dig("data", "person", "citationCount")).to eq(0) expect(response.dig("data", "person", "works", "totalCount")).to eq(1) @@ -109,7 +109,7 @@ name givenName familyName - otherNames + alternateName affiliation { name } @@ -135,7 +135,7 @@ expect(person.fetch("name")).to eq("Stephen A. Fenner") expect(person.fetch("givenName")).to eq("Stephen") expect(person.fetch("familyName")).to eq("Fenner") - expect(person.fetch("otherNames")).to eq([]) + expect(person.fetch("alternateName")).to eq([]) expect(person.fetch("affiliation")).to eq([{"name"=>"Harvard College"}, {"name"=>"University of Chicago"}, {"name"=>"University of South Carolina"}, diff --git a/spec/models/person_spec.rb b/spec/models/person_spec.rb index b56cb438e..1211fbd13 100644 --- a/spec/models/person_spec.rb +++ b/spec/models/person_spec.rb @@ -11,6 +11,8 @@ expect(person.name).to eq("Agnes Ebenberger") expect(person.given_name).to eq("Agnes") expect(person.family_name).to eq("Ebenberger") + expect(person.alternate_name).to eq([]) + expect(person.affiliation).to eq([]) end it "also found" do @@ -22,6 +24,21 @@ expect(person.name).to eq("K. J. Garza") expect(person.given_name).to eq("Kristian") expect(person.family_name).to eq("Garza") + expect(person.alternate_name).to eq([]) + expect(person.affiliation).to eq([]) + end + + it "found with X in ID" do + id = "https://orcid.org/0000-0001-7701-701X" + people = Person.find_by_id(id) + expect(people[:data].size).to eq(1) + person = people[:data].first + expect(person.id).to eq("https://orcid.org/0000-0001-7701-701X") + expect(person.name).to eq("Rory O'Bryen") + expect(person.given_name).to eq("Rory") + expect(person.family_name).to eq("O'Bryen") + expect(person.alternate_name).to eq([]) + expect(person.affiliation).to eq([]) end it "not found" do @@ -43,7 +60,7 @@ expect(person.name).to eq("Letícia Rodrigues Bueno") expect(person.given_name).to eq("Letícia Rodrigues") expect(person.family_name).to eq("Bueno") - expect(person.other_names).to eq([]) + expect(person.alternate_name).to eq([]) expect(person.affiliation).to eq([{"name"=>"Universidade Estadual de Maringá"}, {"name"=>"Universidade Federal do ABC"}, {"name"=>"Universidade Federal do Rio de Janeiro"}]) @@ -75,7 +92,7 @@ expect(person.name).to eq("Patricia Cruse") expect(person.given_name).to eq("Patricia") expect(person.family_name).to eq("Cruse") - expect(person.other_names).to eq(["Trisha Cruse"]) + expect(person.alternate_name).to eq(["Trisha Cruse"]) expect(person.affiliation).to eq([{"name"=>"DataCite"}, {"name"=>"University of California Berkeley"}]) end end From 932eda2e97ca69734afa2709b333e7c5b5f65309 Mon Sep 17 00:00:00 2001 From: kjgarza Date: Thu, 14 May 2020 12:56:34 +0200 Subject: [PATCH 2/4] fix: order of prefix building on seeding data --- db/seeds/development/base.seeds.rb | 2 +- db/seeds/development/consortium_transfer.seeds.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/db/seeds/development/base.seeds.rb b/db/seeds/development/base.seeds.rb index 35ade98b8..5d7291e20 100644 --- a/db/seeds/development/base.seeds.rb +++ b/db/seeds/development/base.seeds.rb @@ -8,7 +8,7 @@ client = Client.where(symbol: "DATACITE.TEST").first || FactoryBot.create(:client, provider: provider, symbol: ENV["MDS_USERNAME"], password: ENV["MDS_PASSWORD"]) if Prefix.where(uid: "10.14454").blank? prefix = FactoryBot.create(:prefix, uid: "10.14454") - FactoryBot.create(:provider_prefix, provider_id: provider.symbol, prefix_id: prefix.uid) + ### This creates both the client_prefix and the pprovider association FactoryBot.create(:client_prefix, client_id: client.symbol, prefix_id: prefix.uid) end dois = FactoryBot.create_list(:doi, 10, client: client, state: "findable") diff --git a/db/seeds/development/consortium_transfer.seeds.rb b/db/seeds/development/consortium_transfer.seeds.rb index ce1ec1ad1..74403ccb2 100644 --- a/db/seeds/development/consortium_transfer.seeds.rb +++ b/db/seeds/development/consortium_transfer.seeds.rb @@ -3,13 +3,13 @@ fail "Seed tasks can only be used in the development enviroment" if Rails.env.production? after "development:base" do - provider = Provider.where(symbol: "QUECHUA").first || FactoryBot.create(:provider, symbol: "QUECHUA") client = Client.where(symbol: "QUECHUA.TEXT").first || FactoryBot.create(:client, provider: provider, symbol: "QUECHUA.TEXT", password: ENV["MDS_PASSWORD"]) if Prefix.where(uid: "10.14459").blank? prefix = FactoryBot.create(:prefix, uid: "10.14459") - FactoryBot.create(:provider_prefix, provider_id: provider.symbol, prefix_id: prefix.uid) - FactoryBot.create(:client_prefix, client_id: client.symbol, prefix_id: prefix.uid) + ## one needs to create the provider first so the assignation is made + provider_prefix_id = FactoryBot.create(:provider_prefix, provider_id: provider.symbol, prefix_id: prefix.uid) + FactoryBot.create(:client_prefix, client_id: client.symbol, prefix_id: prefix.uid, provider_prefix_id: provider_prefix_id.uid) end dois = FactoryBot.create_list(:doi, 10, client: client, state: "findable") FactoryBot.create_list(:event_for_datacite_related, 3, obj_id: dois.first.doi) From e35d95d0bab92a35772f4dea51064e79bdbc01f7 Mon Sep 17 00:00:00 2001 From: kjgarza Date: Thu, 14 May 2020 12:57:23 +0200 Subject: [PATCH 3/4] fix: recreate clientprefix after destroy --- app/models/client.rb | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/app/models/client.rb b/app/models/client.rb index 7eb53df05..3f75255f9 100644 --- a/app/models/client.rb +++ b/app/models/client.rb @@ -366,13 +366,16 @@ def transfer_prefixes(target_id) if prefix_ids.present? response = ProviderPrefix.where("prefix_id IN (?)", prefix_ids).destroy_all - puts "#{response.count} provider prefixes deleted." + Rails.logger.info "[Transfer] #{response.count} provider prefixes deleted." end - # Assign prefix(es) to provider + # Assign prefix(es) to provider and client prefixes_names.each do |prefix| - ProviderPrefix.create(provider_id: target_id, prefix_id: prefix) - puts "Provider prefix for provider #{target_id} and prefix #{prefix} created." + provider_prefix = ProviderPrefix.create(provider_id: target_id, prefix_id: prefix) + Rails.logger.info "[Transfer] Provider prefix for provider #{target_id} and prefix #{prefix} created." + + ClientPrefix.create(client_id: symbol, provider_prefix_id: provider_prefix.uid, prefix_id: prefix) + Rails.logger.info "Client prefix for client #{symbol} and prefix #{prefix} created." end end From a59d22534973a03859079f9aa074e71cc2db778b Mon Sep 17 00:00:00 2001 From: kjgarza Date: Thu, 14 May 2020 13:15:04 +0200 Subject: [PATCH 4/4] test: check clientprefix are there and correct creation order --- spec/models/client_spec.rb | 13 +++++++++---- spec/requests/clients_spec.rb | 10 +++++----- spec/requests/repositories_spec.rb | 5 ++++- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/spec/models/client_spec.rb b/spec/models/client_spec.rb index 69bc481fb..317f0f9fa 100644 --- a/spec/models/client_spec.rb +++ b/spec/models/client_spec.rb @@ -27,9 +27,11 @@ let!(:prefixes) { create_list(:prefix, 3) } let!(:prefix) { prefixes.first } - let!(:client_prefix) { create(:client_prefix, client: client, prefix: prefix) } + ### Order is important in creating prefixes relations let!(:provider_prefix) { create(:provider_prefix, provider: provider, prefix: prefix) } let!(:provider_prefix_more) { create(:provider_prefix, provider: provider, prefix: prefixes.last) } + let!(:client_prefix) { create(:client_prefix, client: client, prefix: prefix, provider_prefix_id: provider_prefix.uid) } + let(:new_provider) { create(:provider, symbol: "QUECHUA", member_type: "direct_member") } let(:options) { { target_id: new_provider.symbol } } let(:bad_options) { { target_id: "SALS" } } @@ -44,6 +46,8 @@ expect(new_provider.prefix_ids).to include(prefix.uid) expect(provider.prefix_ids).not_to include(prefix.uid) + + expect(client.prefix_ids).to include(prefix.uid) end it "it doesn't transfer" do @@ -101,9 +105,10 @@ describe "Client prefixes transfer" do let!(:prefixes) { create_list(:prefix, 3) } let!(:prefix) { prefixes.first } - let!(:client_prefix) { create(:client_prefix, client: client, prefix: prefix) } - let!(:provider_prefix) { create(:provider_prefix, provider: provider, prefix: prefix) } + ### Order is important in creating prefixes relations + let!(:provider_prefix) { create(:provider_prefix, provider: provider, prefix: prefix) } let!(:provider_prefix_more) { create(:provider_prefix, provider: provider, prefix: prefixes.last) } + let!(:client_prefix) { create(:client_prefix, client: client, prefix: prefix , provider_prefix_id: provider_prefix.uid) } let(:new_provider) { create(:provider, symbol: "QUECHUA") } it "works" do @@ -114,10 +119,10 @@ expect(new_provider.prefix_ids).to include(prefix.uid) expect(provider.prefix_ids).not_to include(prefix.uid) + expect(client.prefix_ids).to include(prefix.uid) end end - describe "methods" do it "should not update the symbol" do client.update_attributes :symbol => client.symbol+'foo.bar' diff --git a/spec/requests/clients_spec.rb b/spec/requests/clients_spec.rb index 154d40961..68534787a 100644 --- a/spec/requests/clients_spec.rb +++ b/spec/requests/clients_spec.rb @@ -222,12 +222,10 @@ let(:new_provider) { create(:provider, symbol: "QUECHUA", password_input: "12345") } let!(:prefixes) { create_list(:prefix, 3) } let!(:prefix) { prefixes.first } - let!(:client_prefix) { create(:client_prefix, client: client, prefix: prefix) } - let!(:provider_prefix) { create(:provider_prefix, provider: provider, prefix: prefix) } let!(:provider_prefix_more) { create(:provider_prefix, provider: provider, prefix: prefixes.last) } + let!(:provider_prefix) { create(:provider_prefix, provider: provider, prefix: prefix) } + let!(:client_prefix) { create(:client_prefix, client: client, prefix: prefix, provider_prefix_id: provider_prefix.uid) } let(:doi) { create_list(:doi, 10, client: client) } - - let(:params) do { "data" => { @@ -254,8 +252,10 @@ expect(json.dig("data", "relationships", "prefixes", "data").first.dig("id")).to eq(prefixes.last.uid) get "/providers/#{new_provider.symbol}" - expect(json.dig("data", "relationships", "prefixes", "data").first.dig("id")).to eq(prefix.uid) + + get "/prefixes/#{prefix.uid}" + expect(json.dig("data", "relationships", "clients", "data").first.dig("id")).to eq(client.symbol.downcase) end end diff --git a/spec/requests/repositories_spec.rb b/spec/requests/repositories_spec.rb index 07ef6031a..28f910875 100644 --- a/spec/requests/repositories_spec.rb +++ b/spec/requests/repositories_spec.rb @@ -287,8 +287,8 @@ let(:new_provider) { create(:provider, symbol: "QUECHUA", password_input: "12345") } let!(:prefix) { create(:prefix) } - let!(:client_prefix) { create(:client_prefix, client: client, prefix: prefix) } let!(:provider_prefix) { create(:provider_prefix, provider: provider, prefix: prefix) } + let!(:client_prefix) { create(:client_prefix, client: client, prefix: prefix, provider_prefix_id: provider_prefix.uid) } let(:doi) { create_list(:doi, 10, client: client) } let(:params) do @@ -318,6 +318,9 @@ get "/providers/#{new_provider.symbol}" expect(json.dig("data", "relationships", "prefixes", "data").first.dig("id")).to eq(prefix.uid) + + get "/prefixes/#{prefix.uid}" + expect(json.dig("data", "relationships", "clients", "data").first.dig("id")).to eq(client.symbol.downcase) end end