diff --git a/Gemfile b/Gemfile index 7feedcef4..95dec4b8a 100644 --- a/Gemfile +++ b/Gemfile @@ -13,7 +13,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", "~> 2.5.0" +gem "bolognese", "~> 2.5.1" gem "bootsnap", "~> 1.4", ">= 1.4.4", require: false gem "cancancan", "~> 3.0" gem "countries", "~> 2.1", ">= 2.1.2" @@ -66,7 +66,7 @@ gem "rails", "~> 7.2" gem "rake", "~> 12.0" gem "sentry-ruby", "~> 5.20" gem "sentry-rails", "~> 5.20" -gem "shoryuken", "~> 7.0" +gem "shoryuken", "~> 7.0.1" gem "simple_command" gem "slack-notifier", "~> 2.1" gem "sparql", "~> 3.1", ">= 3.1.2" diff --git a/Gemfile.lock b/Gemfile.lock index d1c08c4e4..a61287131 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -137,7 +137,7 @@ GEM bigdecimal (4.0.1) binding_of_caller (1.0.0) debug_inspector (>= 0.0.1) - bolognese (2.5.0) + bolognese (2.5.1) activesupport (= 7.2.3) benchmark_methods (~> 0.7) bibtex-ruby (>= 5.1.0) @@ -707,7 +707,7 @@ GEM bigdecimal concurrent-ruby (~> 1.0, >= 1.0.2) sexp_processor (4.17.1) - shoryuken (7.0.0) + shoryuken (7.0.1) aws-sdk-sqs (>= 1.66.0) concurrent-ruby thor @@ -821,7 +821,7 @@ DEPENDENCIES bcrypt (~> 3.1.7) better_errors binding_of_caller - bolognese (~> 2.5.0) + bolognese (~> 2.5.1) bootsnap (~> 1.4, >= 1.4.4) brakeman (~> 6.1, >= 6.1.2) bullet (~> 8.1) @@ -897,7 +897,7 @@ DEPENDENCIES seedbank sentry-rails (~> 5.20) sentry-ruby (~> 5.20) - shoryuken (~> 7.0) + shoryuken (~> 7.0.1) shoulda-matchers (~> 4.1, >= 4.1.2) simple_command simplecov (~> 0.22.0) diff --git a/app/lib/params_sanitizer.rb b/app/lib/params_sanitizer.rb index 2c716c0dc..6801ec9df 100644 --- a/app/lib/params_sanitizer.rb +++ b/app/lib/params_sanitizer.rb @@ -175,6 +175,7 @@ class ParamsSanitizer schemeUri schemeType resourceTypeGeneral + relationTypeInformation relatedMetadataScheme schemeUri schemeType @@ -231,6 +232,7 @@ class ParamsSanitizer relatedItems: [ :relationType, :relatedItemType, + :relationTypeInformation, { relatedItemIdentifier: %i[relatedItemIdentifier relatedItemIdentifierType relatedMetadataScheme schemeURI schemeType], }, diff --git a/app/models/doi.rb b/app/models/doi.rb index a08b6608d..06980f8ce 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -300,10 +300,12 @@ def validate_publisher_obj?(doi) schemeUri: { type: :keyword }, schemeType: { type: :keyword }, resourceTypeGeneral: { type: :keyword }, + relationTypeInformation: { type: :text }, } - indexes :related_items, type: :object, properties: { + indexes :related_items, type: :object, properties: { relatedItemType: { type: :keyword }, relationType: { type: :keyword }, + relationTypeInformation: { type: :text }, relatedItemIdentifier: { type: :object, properties: { relatedItemIdentifier: { type: :keyword, normalizer: "keyword_lowercase" }, relatedItemIdentifierType: { type: :keyword }, @@ -709,8 +711,14 @@ def as_indexed_json(_options = {}) end DOI_AGGREGATION_DEFINITIONS = { - # number of resourceTypeGeneral increased from 30 to 32 in schema 4.6 - resource_types: { terms: { field: "resource_type_id_and_name", size: 32, min_doc_count: 1 } }, + # number of resourceTypeGeneral increased from 34 to 34 in schema 4.6 + resource_types: { terms: { field: "resource_type_id_and_name", size: 34, min_doc_count: 1 }, + aggs: { + resource_types: { + terms: { field: "resource_type_id_and_name", size: 34, min_doc_count: 1 } + } + } + }, open_licenses: { filter: { terms: { "rights_list.rightsIdentifier": [ @@ -728,7 +736,7 @@ def as_indexed_json(_options = {}) } }, aggs: { resource_types: { - terms: { field: "resource_type_id_and_name", size: 32, min_doc_count: 1 } + terms: { field: "resource_type_id_and_name", size: 34, min_doc_count: 1 } } } }, diff --git a/app/models/resource_type.rb b/app/models/resource_type.rb index 12112f19f..cb33924b6 100644 --- a/app/models/resource_type.rb +++ b/app/models/resource_type.rb @@ -53,7 +53,9 @@ def self.get_data(_options = {}) { "id" => "output-management-plan", "title" => "OutputManagementPlan" }, { "id" => "peer-review", "title" => "PeerReview" }, { "id" => "physical-object", "title" => "PhysicalObject" }, + { "id" => "poster", "title" => "Poster" }, { "id" => "preprint", "title" => "Preprint" }, + { "id" => "presentation", "title" => "Presentation" }, { "id" => "project", "title" => "Project" }, { "id" => "report", "title" => "Report" }, { "id" => "service", "title" => "Service" }, diff --git a/config/environments/development.rb b/config/environments/development.rb index 75eecc84e..d5d1f64ec 100644 --- a/config/environments/development.rb +++ b/config/environments/development.rb @@ -42,7 +42,6 @@ require "flipper/middleware/memoizer" config.middleware.use Flipper::Middleware::Memoizer config.flipper.memoize = false - config.hosts << "lupo_web" ENV["TEST_ENV_NUMBER"] ||= "" # For parallel tests, often set by CI, default to empty ENV["ES_PREFIX"] ||= "" # ElasticSearch index prefix diff --git a/config/initializers/constants.rb b/config/initializers/constants.rb index 7c4c7d8a8..2e6b86d0f 100644 --- a/config/initializers/constants.rb +++ b/config/initializers/constants.rb @@ -75,7 +75,9 @@ class IdentifierError < RuntimeError; end "OutputManagementPlan" => "Output Management Plan", "PeerReview" => "Peer Review", "PhysicalObject" => "Physical Object", + "Poster" => "Poster", "Preprint" => "Preprint", + "Presentation" => "Presentation", "Project" => "Project", "Report" => "Report", "Service" => "Service", diff --git a/docker-compose.yml b/docker-compose.yml index 8651eb55c..984d70ae6 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,3 +1,5 @@ +# DOCKER-COMPOSE.YML + services: web: env_file: .env @@ -40,7 +42,6 @@ services: - "3309:3306" networks: - public - elasticsearch: image: opensearchproject/opensearch:2 ports: @@ -89,4 +90,4 @@ networks: ipam: driver: default config: - - subnet: 10.0.40.0/24 + - subnet: 10.0.40.0/24 \ No newline at end of file diff --git a/openapi.yaml b/openapi.yaml index be1ff9613..704e89f3b 100644 --- a/openapi.yaml +++ b/openapi.yaml @@ -687,7 +687,9 @@ paths: - output-management-plan - peer-review - physical-object + - poster - preprint + - presentation - project - report - service @@ -2518,6 +2520,8 @@ components: type: string schemeType: type: string + relationTypeInformation: + type: string relatedItems: description: '[DataCite Metadata Schema: RelatedItem](https://datacite-metadata-schema.readthedocs.io/en/4/properties/relateditem/)' type: array @@ -2541,6 +2545,8 @@ components: type: string schemeType: type: string + relationTypeInformation: + type: string creators: type: array items: @@ -3429,6 +3435,7 @@ components: - Collects - IsTranslationOf - HasTranslation + - Other resourceTypeGeneral: description: '[DataCite Metadata Schema: resourceTypeGeneral](https://datacite-metadata-schema.readthedocs.io/en/4/appendices/appendix-1/resourceTypeGeneral/)' type: string @@ -3454,7 +3461,9 @@ components: - OutputManagementPlan - PeerReview - PhysicalObject + - Poster - Preprint + - Presentation - Project - Report - Service @@ -3511,7 +3520,9 @@ components: - LSID - PMID - PURL + - RAiD - RRID + - SWHID - UPC - URL - URN @@ -3650,6 +3661,9 @@ components: - obsoletes - is-collected-by - collects + - is-translation-of + - has-translation + - other - is-authored-by - is-authored-at - is-funded-by diff --git a/spec/fixtures/files/datacite-example-full-v4.7.xml b/spec/fixtures/files/datacite-example-full-v4.7.xml new file mode 100644 index 000000000..d4c979ecd --- /dev/null +++ b/spec/fixtures/files/datacite-example-full-v4.7.xml @@ -0,0 +1,295 @@ + + + + 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 + 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 + + + + + 1234-5678 + + Journal of Metadata Examples - Collects + + + + 0123-4567 + + Journal of Metadata Examples - IsCollectedBy + + + + 0123-4567 + + Journal of Metadata Examples - IsCollectedBy - Presentation + + + + 0123-4567 + + Journal of Metadata Examples - IsCollectedBy - Poster + + + + 0123-4567 + + Journal of Metadata Examples - IsCollectedBy - Poster + + + + 0123-4567 + + Journal of Metadata Examples - IsCollectedBy - Poster + + + + diff --git a/spec/fixtures/vcr_cassettes/DataciteDoisController/POST_/dois/when_the_request_uses_schema_4_7_-_json/creates_a_Doi.yml b/spec/fixtures/vcr_cassettes/DataciteDoisController/POST_/dois/when_the_request_uses_schema_4_7_-_json/creates_a_Doi.yml new file mode 100644 index 000000000..55244e289 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/DataciteDoisController/POST_/dois/when_the_request_uses_schema_4_7_-_json/creates_a_Doi.yml @@ -0,0 +1,75 @@ +--- +http_interactions: +- request: + method: put + uri: https://handle.test.datacite.org/api/handles/10.14454/10703 + body: + encoding: UTF-8 + string: '[{"index":100,"type":"HS_ADMIN","data":{"format":"admin","value":{"handle":"TEST/ADMIN","index":300,"permissions":"111111111111"}}},{"index":1,"type":"URL","data":{"format":"string","value":"http://www.bl.uk/pdf/patspec.pdf"}}]' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/5.0.0; mailto:info@datacite.org) + Accept: + - text/html,application/json,application/xml;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5 + Content-Type: + - application/json;charset=UTF-8 + Authorization: + - Basic + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Date: + - Tue, 27 Jan 2026 02:25:02 GMT + Content-Type: + - application/json;charset=utf-8 + Content-Length: + - '44' + Connection: + - keep-alive + Vary: + - Accept-Encoding, User-Agent + body: + encoding: ASCII-8BIT + string: '{"responseCode":1,"handle":"10.14454/10703"}' + recorded_at: Tue, 27 Jan 2026 02:25:03 GMT +- request: + method: put + uri: https://handle.test.datacite.org/api/handles/10.14454/10703 + body: + encoding: UTF-8 + string: '[{"index":100,"type":"HS_ADMIN","data":{"format":"admin","value":{"handle":"TEST/ADMIN","index":300,"permissions":"111111111111"}}},{"index":1,"type":"URL","data":{"format":"string","value":"http://www.bl.uk/pdf/patspec.pdf"}}]' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/5.0.0; mailto:info@datacite.org) + Accept: + - text/html,application/json,application/xml;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5 + Content-Type: + - application/json;charset=UTF-8 + Authorization: + - Basic + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Date: + - Tue, 27 Jan 2026 02:25:03 GMT + Content-Type: + - application/json;charset=utf-8 + Content-Length: + - '44' + Connection: + - keep-alive + Vary: + - Accept-Encoding, User-Agent + body: + encoding: ASCII-8BIT + string: '{"responseCode":1,"handle":"10.14454/10703"}' + recorded_at: Tue, 27 Jan 2026 02:25:03 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/fixtures/vcr_cassettes/DataciteDoisController/POST_/dois/when_the_request_uses_schema_4_7_-_xml/creates_a_Doi.yml b/spec/fixtures/vcr_cassettes/DataciteDoisController/POST_/dois/when_the_request_uses_schema_4_7_-_xml/creates_a_Doi.yml new file mode 100644 index 000000000..395ac7661 --- /dev/null +++ b/spec/fixtures/vcr_cassettes/DataciteDoisController/POST_/dois/when_the_request_uses_schema_4_7_-_xml/creates_a_Doi.yml @@ -0,0 +1,75 @@ +--- +http_interactions: +- request: + method: put + uri: https://handle.test.datacite.org/api/handles/10.14454/10703 + body: + encoding: UTF-8 + string: '[{"index":100,"type":"HS_ADMIN","data":{"format":"admin","value":{"handle":"TEST/ADMIN","index":300,"permissions":"111111111111"}}},{"index":1,"type":"URL","data":{"format":"string","value":"http://www.bl.uk/pdf/patspec.pdf"}}]' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/5.0.0; mailto:info@datacite.org) + Accept: + - text/html,application/json,application/xml;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5 + Content-Type: + - application/json;charset=UTF-8 + Authorization: + - Basic + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Date: + - Tue, 27 Jan 2026 02:24:48 GMT + Content-Type: + - application/json;charset=utf-8 + Content-Length: + - '44' + Connection: + - keep-alive + Vary: + - Accept-Encoding, User-Agent + body: + encoding: ASCII-8BIT + string: '{"responseCode":1,"handle":"10.14454/10703"}' + recorded_at: Tue, 27 Jan 2026 02:24:48 GMT +- request: + method: put + uri: https://handle.test.datacite.org/api/handles/10.14454/10703 + body: + encoding: UTF-8 + string: '[{"index":100,"type":"HS_ADMIN","data":{"format":"admin","value":{"handle":"TEST/ADMIN","index":300,"permissions":"111111111111"}}},{"index":1,"type":"URL","data":{"format":"string","value":"http://www.bl.uk/pdf/patspec.pdf"}}]' + headers: + User-Agent: + - Mozilla/5.0 (compatible; Maremma/5.0.0; mailto:info@datacite.org) + Accept: + - text/html,application/json,application/xml;q=0.9, text/plain;q=0.8,image/png,*/*;q=0.5 + Content-Type: + - application/json;charset=UTF-8 + Authorization: + - Basic + Accept-Encoding: + - gzip,deflate + response: + status: + code: 200 + message: OK + headers: + Date: + - Tue, 27 Jan 2026 02:24:49 GMT + Content-Type: + - application/json;charset=utf-8 + Content-Length: + - '44' + Connection: + - keep-alive + Vary: + - Accept-Encoding, User-Agent + body: + encoding: ASCII-8BIT + string: '{"responseCode":1,"handle":"10.14454/10703"}' + recorded_at: Tue, 27 Jan 2026 02:24:49 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/requests/datacite_dois/datacite_dois_spec.rb b/spec/requests/datacite_dois/datacite_dois_spec.rb index e72e8e1c3..7b2880516 100755 --- a/spec/requests/datacite_dois/datacite_dois_spec.rb +++ b/spec/requests/datacite_dois/datacite_dois_spec.rb @@ -2177,4 +2177,79 @@ def clear_doi_index end end end + + ## Metadata 4.7 queries with new field: relationTypeInformation (in relatedIdentifiers and relatedItems) + + describe "GET /dois/query=...relationTypeInformation", vcr: true, elasticsearch: true do + let!(:datacite_doi) { create(:doi, client: client, aasm_state: "findable", + related_items: [ + { + "firstPage" => "250", + "lastPage" => "264", + "publicationYear" => "2018", + "relatedItemIdentifier" => { "relatedItemIdentifier" => "10.1016/j.physletb.2017.11.044", "relatedItemIdentifierType" => "DOI" }, + "relatedItemType" => "Journal", + "relationType" => "IsPublishedIn", + "relationTypeInformation" => "Relates this DOI to the journal in which it was published.", + "titles" => [{ "title" => "Physics letters / B" }], + "volume" => "776" + } + ], + related_identifiers: [ + { + "relatedIdentifier": "10.5061/dryad.8515/1", + "relatedIdentifierType": "DOI", + "relationType": "HasPart", + "relationTypeInformation": "Relates this DOI to the dataset in Dryad that contains the data underlying the article.", + }, + { + "relatedIdentifier": "10.5061/dryad.8515/2", + "relatedIdentifierType": "DOI", + "relationType": "HasPart", + }, + { + "relatedIdentifier": "10.1371/journal.ppat.1000446", + "relatedIdentifierType": "DOI", + "relationType": "IsReferencedBy", + "relationTypeInformation": "Relates this DOI to the article that references it.", + }, + { + "relatedIdentifier": "10.1371/journal.ppat.1000446", + "relatedIdentifierType": "DOI", + "relationType": "IsSupplementTo", + }, + { + "relatedIdentifier": "19478877", + "relatedIdentifierType": "PMID", + "relationType": "IsReferencedBy", + }, + { + "relatedIdentifier": "19478877", + "relatedIdentifierType": "PMID", + "relationType": "IsSupplementTo", + } + ] + )} + + before do + clear_doi_index + import_doi_index + end + + it "finds the doi based on relatedItems.relationTypeInformation" do + get "/dois?query=relatedItems.relationTypeInformation:\"Relates this DOI to*\"", nil, headers + expect(last_response.status).to eq(200) + expect(json.dig("meta", "total")).to eq(1) + expect(json.dig("data", 0, "attributes", "relatedItems", 0, "relationTypeInformation")).to eq("Relates this DOI to the journal in which it was published.") + end + + + it "finds the dois based on relatedIdentiers.relationTypeInformation" do + get "/dois?query=relatedIdentifiers.relationTypeInformation:\"Relates this DOI to*\"", nil, headers + expect(last_response.status).to eq(200) + expect(json.dig("meta", "total")).to eq(1) + expect(json.dig("data", 0, "attributes", "relatedIdentifiers", 0, "relationTypeInformation")).to eq("Relates this DOI to the dataset in Dryad that contains the data underlying the article.") + expect(json.dig("data", 0, "attributes", "relatedIdentifiers", 2, "relationTypeInformation")).to eq("Relates this DOI to the article that references it.") + end + end end diff --git a/spec/requests/datacite_dois/patch_spec.rb b/spec/requests/datacite_dois/patch_spec.rb index 01cba929d..b3d729cff 100644 --- a/spec/requests/datacite_dois/patch_spec.rb +++ b/spec/requests/datacite_dois/patch_spec.rb @@ -998,4 +998,42 @@ end end end + + ## Metadata 4.7 elements + + context "when the record exists" do + let(:xml) { Base64.strict_encode64(file_fixture("datacite-example-full-v4.7.xml").read) } + let(:valid_attributes) do + { + "data" => { + "type" => "dois", + "attributes" => { + "url" => "http://www.bl.uk/pdf/pat.pdf", + "xml" => xml, + }, + }, + } + end + + it "updates the record" do + patch "/dois/#{doi.doi}", valid_attributes, headers + + expect(last_response.status).to eq(200) + + expect(json.dig("data", "attributes", "url")).to eq("http://www.bl.uk/pdf/pat.pdf") + expect(json.dig("data", "attributes", "doi")).to eq(doi.doi.downcase) + + expect(json.dig("data", "attributes", "types", "resourceTypeGeneral")).to eq("Presentation") + expect(json.dig("data", "attributes", "types", "resourceType")).to eq("Example ResourceType") + + expect(json.dig("data", "attributes", "relatedIdentifiers", 40, "relationType")).to eq("Other") + expect(json.dig("data", "attributes", "relatedIdentifiers", 40, "relationTypeInformation")).to eq("More relationType information to supplement relationType 'Other'") + + expect(json.dig("data", "attributes", "relatedItems", 3, "relatedItemType")).to eq("Presentation") + expect(json.dig("data", "attributes", "relatedItems", 4, "relatedItemType")).to eq("Poster") + expect(json.dig("data", "attributes", "relatedItems", 5, "relatedItemIdentifier", "relatedItemIdentifierType")).to eq("SWHID") + expect(json.dig("data", "attributes", "relatedItems", 6, "relationType")).to eq("Other") + expect(json.dig("data", "attributes", "relatedItems", 6, "relationTypeInformation")).to eq("More relationType information to supplement relationType 'Other'") + end + end end diff --git a/spec/requests/datacite_dois/post_spec.rb b/spec/requests/datacite_dois/post_spec.rb index 0309ca087..0eeab9d71 100644 --- a/spec/requests/datacite_dois/post_spec.rb +++ b/spec/requests/datacite_dois/post_spec.rb @@ -2424,5 +2424,202 @@ expect(doc.at_css("identifier").content).to eq("10.14454/10704") end end + + ## Metadata 4.7 elements + + context "when the request uses schema 4.7 - xml" do + let(:xml) { Base64.strict_encode64(file_fixture("datacite-example-full-v4.7.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") + + expect(json.dig("data", "attributes", "types", "resourceTypeGeneral")).to eq("Presentation") + + expect(json.dig("data", "attributes", "relatedIdentifiers", 36, "resourceTypeGeneral")).to eq("Poster") + expect(json.dig("data", "attributes", "relatedIdentifiers", 37, "resourceTypeGeneral")).to eq("Presentation") + expect(json.dig("data", "attributes", "relatedIdentifiers", 38, "relatedIdentifierType")).to eq("RAiD") + expect(json.dig("data", "attributes", "relatedIdentifiers", 40, "relationType")).to eq("Other") + expect(json.dig("data", "attributes", "relatedIdentifiers", 40, "relationTypeInformation")).to eq("More relationType information to supplement relationType 'Other'") + + expect(json.dig("data", "attributes", "relatedItems", 1, "relationType")).to eq("Collects") + expect(json.dig("data", "attributes", "relatedItems", 1, "titles", 0, "title")).to eq("Journal of Metadata Examples - Collects") + expect(json.dig("data", "attributes", "relatedItems", 2, "relationType")).to eq("IsCollectedBy") + expect(json.dig("data", "attributes", "relatedItems", 2, "titles", 0, "title")).to eq("Journal of Metadata Examples - IsCollectedBy") + + expect(json.dig("data", "attributes", "relatedItems", 3, "relatedItemType")).to eq("Presentation") + expect(json.dig("data", "attributes", "relatedItems", 4, "relatedItemType")).to eq("Poster") + expect(json.dig("data", "attributes", "relatedItems", 5, "relatedItemIdentifier", "relatedItemIdentifierType")).to eq("SWHID") + expect(json.dig("data", "attributes", "relatedItems", 6, "relationType")).to eq("Other") + expect(json.dig("data", "attributes", "relatedItems", 6, "relationTypeInformation")).to eq("More relationType information to supplement relationType 'Other'") + end + end + + context "when the request uses schema 4.7 - json" do + let(:valid_attributes) do + { + "data" => { + "type" => "dois", + "attributes" => { + "doi" => "10.14454/10703", + "url" => "http://www.bl.uk/pdf/patspec.pdf", + "types" => { + "resourceTypeGeneral": "Poster", + "resourceType": "Test Resource Type" + }, + "titles" => [{ "title" => "Eating your own Dog Food" }], + "publisher" => "DataCite", + "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" }], + "subjects" => [{ "subject" => "80505 Web Technologies (excl. Web Search)", + "schemeUri" => "http://www.abs.gov.au/ausstats/abs@.nsf/0/6BB427AB9696C225CA2574180004463E", + "subjectScheme" => "FOR", + "lang" => "en", + "classificationCode" => "080505" }], + "contributors" => [{ "contributorType" => "DataManager", "familyName" => "Fenner", "givenName" => "Kurt", "nameIdentifiers" => [{ "nameIdentifier" => "https://orcid.org/0000-0003-1419-2401", "nameIdentifierScheme" => "ORCID", "schemeUri" => "https://orcid.org" }], "name" => "Fenner, Kurt", "nameType" => "Personal" }], + "dates" => [{ "date" => "2017-02-24", "dateType" => "Issued" }, { "date" => "2015-11-28", "dateType" => "Created" }, { "date" => "2017-02-24", "dateType" => "Updated" }], + "relatedIdentifiers" => [ + { + "relatedIdentifier" => "10.5438/55e5-t5c0", + "relatedIdentifierType" => "DOI", + "relationType" => "Other", + "relationTypeInformation" => "More information to supplement relationType 'Other'", "resourceTypeGeneral" => "Presentation" + }, + { + "relatedIdentifier" => "10.5438/55e5-t5c0", + "relatedIdentifierType" => "RAiD", + "relationType" => "Other", + "relationTypeInformation" => "More information to supplement relationType 'Other'", "resourceTypeGeneral" => "Presentation" + }, + ], + + "relatedItems" => [ + { + "relatedItemType" => "Presentation", + "relationType" => "Other", + "relationTypeInformation" => "More information to supplement relationType 'Other'", + "relatedItemIdentifier" => { "relatedItemIdentifier" => "10.82523/hnhr-r562", "relatedItemIdentifierType" => "SWHID" } + } + ], + + "descriptions" => [ + { + "lang" => "en", + "description" => "Diet and physical activity are two modifiable factors that can curtail the development of osteoporosis in the aging population. One purpose of this study was to assess the differences in dietary intake and bone mineral density (BMD) in a Masters athlete population (n=87, n=49 female; 41.06 ± 5.00 years of age) and examine sex- and sport-related differences in dietary and total calcium and vitamin K intake and BMD of the total body, lumbar spine, and dual femoral neck (TBBMD, LSBMD and DFBMD, respectively). Total calcium is defined as calcium intake from diet and supplements. Athletes were categorized as participating in an endurance or interval sport. BMD was measured using dual-energy X-ray absorptiometry (DXA). Data on dietary intake was collected from Block 2005 Food Frequency Questionnaires (FFQs). Dietary calcium, total calcium, or vitamin K intake did not differ between the female endurance and interval athletes. All three BMD sites were significantly different among the female endurance and interval athletes, with female interval athletes having higher BMD at each site (TBBMD: 1.26 ± 0.10 g/cm2, p<0.05; LSBMD: 1.37 ± 0.14 g/cm2, p<0.01; DFBMD: 1.11 ± 0.12 g/cm2, p<0.05, for female interval athletes; TBBMD: 1.19 ± 0.09 g/cm2; LSBMD: 1.23 ± 0.16 g/cm2; DFBMD: 1.04 ± 0.10 g/cm2, for female endurance athletes). Male interval athletes had higher BMD at all three sites (TBBMD 1.44 ± 0.11 g/cm2, p<0.05; LSBMD 1.42 ± 0.15 g/cm2, p=0.179; DFBMD 1.26 ± 0.14 g/cm2, p<0.01, for male interval athletes; TBBMD 1.33 ± 0.11 g/cm2; LSBMD 1.33 ± 0.17 g/cm2; DFBMD 1.10 ± 0.12 g/cm2 for male endurance athletes). Dietary calcium, total daily calcium and vitamin K intake did not differ between the male endurance and interval athletes. This study evaluated the relationship between calcium intake and BMD. No relationship between dietary or total calcium intake and BMD was evident in all female athletes, female endurance athletes or female interval athletes. In all male athletes, there was no significant correlation between dietary or total calcium intake and BMD at any of the measured sites. However, the male interval athlete group had a negative relationship between dietary calcium intake and TBBMD (r=-0.738, p<0.05) and LSBMD (r=-0.738, p<0.05). The negative relationship persisted between total calcium intake and LSBMD (r=-0.714, p<0.05), but not TBBMD, when calcium from supplements was included. The third purpose of this study was to evaluate the relationship between vitamin K intake (as phylloquinone) and BMD. In all female athletes, there was no significant correlation between vitamin K intake and BMD at any of the measured sites. No relationship between vitamin K and BMD was evident in female interval or female endurance athletes. Similarly, there was no relationship between vitamin K intake and BMD in the male endurance and interval groups. The final purpose of this study was to assess the relationship between the Calcium-to-Vitamin K (Ca:K) ratio and BMD. A linear regression model established that the ratio predicted TBBMD in female athletes, F(1,47) = 4.652, p <0.05, and the ratio accounted for 9% of the variability in TBBMD. The regression equation was: predicted TBBMD in a female athlete = 1.250 - 0.008 x (Ca:K). In conclusion, Masters interval athletes have higher BMD than Masters endurance athletes; however, neither dietary or supplemental calcium nor vitamin K were related to BMD in skeletal sites prone to fracture in older adulthood. We found that a Ca:K ratio could predict TBBMD in female athletes. Further research should consider the calcium-to-vitamin K relationship in conjunction with other modifiable, lifestyle factors associated with bone health in the investigation of methods to minimize the development and effect of osteoporosis in the older athlete population.", + "descriptionType" => "Abstract", + }, + ], + "geoLocations" => [ + { + "geoLocationPoint" => { + "pointLatitude" => 49.0850736, + "pointLongitude" => -123.3300992, + }, + }, + ], + "source" => "test", + "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", "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", "subjects")).to eq([{ "lang" => "en", + "subject" => "80505 Web Technologies (excl. Web Search)", + "schemeUri" => "http://www.abs.gov.au/ausstats/abs@.nsf/0/6BB427AB9696C225CA2574180004463E", + "subjectScheme" => "FOR", + "classificationCode" => "080505" }, + { "schemeUri" => "http://www.oecd.org/science/inno/38235147.pdf", + "subject" => "FOS: Computer and information sciences", + "subjectScheme" => "Fields of Science and Technology (FOS)" } + ]) + expect(json.dig("data", "attributes", "contributors")).to eq([{ "affiliation" => [], + "contributorType" => "DataManager", + "familyName" => "Fenner", + "givenName" => "Kurt", + "name" => "Fenner, Kurt", + "nameIdentifiers" => + [{ + "nameIdentifier" => "https://orcid.org/0000-0003-1419-2401", + "nameIdentifierScheme" => "ORCID", + "schemeUri" => "https://orcid.org" }], + "nameType" => "Personal" + }]) + expect(json.dig("data", "attributes", "dates")).to eq([{ "date" => "2017-02-24", "dateType" => "Issued" }, { "date" => "2015-11-28", "dateType" => "Created" }, { "date" => "2017-02-24", "dateType" => "Updated" }]) + + expect(json.dig("data", "attributes", "types", "resourceTypeGeneral")).to eq("Poster") + expect(json.dig("data", "attributes", "types", "resourceType")).to eq("Test Resource Type") + + expect(json.dig("data", "attributes", "relatedIdentifiers", 0)).to eq( + { + "relatedIdentifier" => "10.5438/55e5-t5c0", + "relatedIdentifierType" => "DOI", + "relationType" => "Other", + "relationTypeInformation" => "More information to supplement relationType 'Other'", + "resourceTypeGeneral" => "Presentation" + } + ) + expect(json.dig("data", "attributes", "relatedIdentifiers", 1)).to eq( + { + "relatedIdentifier" => "10.5438/55e5-t5c0", + "relatedIdentifierType" => "RAiD", + "relationType" => "Other", + "relationTypeInformation" => "More information to supplement relationType 'Other'", + "resourceTypeGeneral" => "Presentation" + } + ) + + expect(json.dig("data", "attributes", "relatedItems")).to eq([{ + "relatedItemType" => "Presentation", + "relationType" => "Other", + "relationTypeInformation" => "More information to supplement relationType 'Other'", + "relatedItemIdentifier" => { "relatedItemIdentifier" => "10.82523/hnhr-r562", "relatedItemIdentifierType" => "SWHID" } + }]) + + expect(json.dig("data", "attributes", "descriptions", 0, "description")).to start_with("Diet and physical activity") + expect(json.dig("data", "attributes", "geoLocations")).to eq([{ "geoLocationPoint" => { "pointLatitude" => 49.0850736, "pointLongitude" => -123.3300992 } }]) + expect(json.dig("data", "attributes", "source")).to eq("test") + expect(json.dig("data", "attributes", "state")).to eq("findable") + + 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(doc.at_css("subjects").content).to eq("80505 Web Technologies (excl. Web Search)") + expect(doc.at_css("contributors").content).to eq("Fenner, KurtKurtFennerhttps://orcid.org/0000-0003-1419-2401") + expect(doc.at_css("dates").content).to eq("2017-02-242015-11-282017-02-24") + expect(doc.at_css("relatedIdentifiers").content).to eq("10.5438/55e5-t5c010.5438/55e5-t5c0") + expect(doc.at_css("descriptions").content).to start_with("Diet and physical activity") + expect(doc.at_css("geoLocations").content).to eq("49.0850736-123.3300992") + end + end end end