diff --git a/Gemfile b/Gemfile index 1697f6432..bf43fe55f 100644 --- a/Gemfile +++ b/Gemfile @@ -4,7 +4,7 @@ source "https://rubygems.org" gem "aasm", "~> 5.0", ">= 5.0.1" gem "active_model_serializers", "~> 0.10.0" -gem "activerecord_json_validator", "~> 2.1", ">= 2.1.5" +gem "activerecord_json_validator", "~> 3.1" gem "apollo-federation", "1.1.3" gem "audited", "~> 5.4", ">= 5.4.3" gem "aws-sdk-s3" diff --git a/Gemfile.lock b/Gemfile.lock index 89bea2174..62f3cef99 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -66,9 +66,9 @@ GEM activemodel (= 7.1.3.2) activesupport (= 7.1.3.2) timeout (>= 0.4.0) - activerecord_json_validator (2.1.5) - activerecord (>= 4.2.0, < 8) - json_schemer (~> 0.2.18) + activerecord_json_validator (3.1.0) + activerecord (>= 4.2.0, < 9) + json_schemer (~> 2.2) activestorage (7.1.3.2) actionpack (= 7.1.3.2) activejob (= 7.1.3.2) @@ -278,8 +278,6 @@ GEM scanf (~> 1.0) sxp (~> 1.2) unicode-types (~> 1.7) - ecma-re-validator (0.4.0) - regexp_parser (~> 2.2) edtf (3.2.0) activesupport (>= 3.0, < 9.0) elasticsearch (7.17.10) @@ -390,12 +388,11 @@ GEM json-ld-preloaded (3.2.2) json-ld (~> 3.2) rdf (~> 3.2) - json_schemer (0.2.25) - ecma-re-validator (~> 0.3) + json_schemer (2.4.0) + bigdecimal hana (~> 1.3) regexp_parser (~> 2.0) simpleidn (~> 0.2) - uri_template (~> 0.7) jsonapi-renderer (0.2.2) jsonapi-serializer (2.2.0) activesupport (>= 4.2) @@ -771,7 +768,6 @@ GEM unicode_utils (1.4.0) uniform_notifier (1.16.0) uri (0.13.2) - uri_template (0.7.0) uuid (2.3.9) macaddr (~> 1.0) uuidtools (2.2.0) @@ -799,7 +795,7 @@ PLATFORMS DEPENDENCIES aasm (~> 5.0, >= 5.0.1) active_model_serializers (~> 0.10.0) - activerecord_json_validator (~> 2.1, >= 2.1.5) + activerecord_json_validator (~> 3.1) apollo-federation (= 1.1.3) audited (~> 5.4, >= 5.4.3) aws-sdk-s3 diff --git a/app/models/doi.rb b/app/models/doi.rb index 1fdf076b6..4826b0cd5 100644 --- a/app/models/doi.rb +++ b/app/models/doi.rb @@ -2,8 +2,18 @@ require "maremma" require "benchmark" +require "byebug" +require "pp" class Doi < ApplicationRecord + INVALID_SCHEMAS = %w[ + http://datacite.org/schema/kernel-2.1 + http://datacite.org/schema/kernel-2.2 + http://datacite.org/schema/kernel-3.0 + http://datacite.org/schema/kernel-3.1 + http://datacite.org/schema/kernel-3 + ].freeze + self.ignored_columns += [:publisher] PUBLISHER_JSON_SCHEMA = Rails.root.join("app", "models", "schemas", "doi", "publisher.json") audited only: %i[doi url creators contributors titles publisher_obj publication_year types descriptions container sizes formats version_info language dates identifiers related_identifiers related_items funding_references geo_locations rights_list subjects schema_version content_url landing_page aasm_state source reason] @@ -110,16 +120,13 @@ class Doi < ApplicationRecord validates_presence_of :doi validates_presence_of :url, if: Proc.new { |doi| doi.is_registered_or_findable? } - json_schema_validation = { - message: ->(errors) { errors }, - schema: PUBLISHER_JSON_SCHEMA - } - - def validate_publisher_obj?(doi) - doi.validatable? && doi.publisher_obj? && !(doi.publisher_obj.blank? || doi.publisher_obj.all?(nil)) + def validate_json_attribute?(attribute) + validatable? && !self[attribute].nil? && !INVALID_SCHEMAS.include?(self.schema_version) end - validates :publisher_obj, if: ->(doi) { validate_publisher_obj?(doi) }, json: json_schema_validation + def schema_file_path(schema_name) + Rails.root.join("app", "models", "schemas", "doi", "#{schema_name}.json") + end # from https://www.crossref.org/blog/dois-and-matching-regular-expressions/ but using uppercase validates_format_of :doi, with: /\A10\.\d{4,5}\/[-._;()\/:a-zA-Z0-9*~$=]+\z/, on: :create @@ -146,6 +153,46 @@ def validate_publisher_obj?(doi) validate :check_geo_locations, if: :geo_locations? validate :check_language, if: :language? + # JSON-SCHEMA VALIDATION + # temporarily commenting out this validation. + # validates :doi, if: proc { |doi| doi.validate_json_attribute?(:identifier) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("identifier") } }, unless: :only_validate + validates :creators, if: proc { |doi| doi.validate_json_attribute?(:creators) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("creators") } }, unless: :only_validate + validates :titles, if: proc { |doi| doi.validate_json_attribute?(:titles) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("titles") } }, unless: :only_validate + validates :publisher_obj, if: proc { |doi| doi.validate_json_attribute?(:publisher_obj) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("publisher") } }, unless: :only_validate + validates :publication_year, if: proc { |doi| doi.validate_json_attribute?(:publication_year) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("publication_year") } }, unless: :only_validate + validates :subjects, if: proc { |doi| doi.validate_json_attribute?(:subjects) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("subjects") } }, unless: :only_validate + validates :contributors, if: proc { |doi| doi.validate_json_attribute?(:contributors) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("contributors") } }, unless: :only_validate + validates :dates, if: proc { |doi| doi.validate_json_attribute?(:dates) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("dates") } }, unless: :only_validate + validates :alternate_identifiers, if: proc { |doi| doi.validate_json_attribute?(:alternate_identifiers) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("alternate_identifiers") } }, unless: :only_validate + validates :related_identifiers, if: proc { |doi| doi.validate_json_attribute?(:related_identifiers) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("related_identifiers") } }, unless: :only_validate + validates :sizes, if: proc { |doi| doi.validate_json_attribute?(:sizes) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("sizes") } }, unless: :only_validate + validates :formats, if: proc { |doi| doi.validate_json_attribute?(:formats) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("formats") } }, unless: :only_validate + validates :version, if: proc { |doi| doi.validate_json_attribute?(:version) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("version") } }, unless: :only_validate + validates :rights_list, if: proc { |doi| doi.validate_json_attribute?(:rights_list) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("rights_list") } }, unless: :only_validate + validates :descriptions, if: proc { |doi| doi.validate_json_attribute?(:descriptions) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("descriptions") } }, unless: :only_validate + validates :geolocations, if: proc { |doi| doi.validate_json_attribute?(:geolocations) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("geolocations") } }, unless: :only_validate + validates :funding_references, if: proc { |doi| doi.validate_json_attribute?(:funding_references) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("funding_references") } }, unless: :only_validate + validates :related_items, if: proc { |doi| doi.validate_json_attribute?(:related_items) }, json: { message: ->(errors) { errors }, schema: lambda { schema_file_path("related_items") } }, unless: :only_validate + + validates :raw_language, presence: true, if: proc { |doi| doi.validate_json_attribute?(:raw_language) }, json: { + message: ->(errors) { errors }, + schema: lambda { schema_file_path("language") } + }, unless: :only_validate + + validates :raw_types, if: proc { |doi| doi.validate_json_attribute?(:raw_types) }, json: { + message: ->(errors) { errors }, + schema: lambda { schema_file_path("resource_type") }, + }, unless: :only_validate + + # See https://github.com/mirego/activerecord_json_validator for an explanation of why this must be done. + def raw_language + self[:language] + end + + def raw_types + self[:types] + end + after_commit :update_url, on: %i[create update] after_commit :update_media, on: %i[create update] diff --git a/app/models/schemas/client/subjects.json b/app/models/schemas/client/subjects.json index 3e204ecd6..bf4302384 100644 --- a/app/models/schemas/client/subjects.json +++ b/app/models/schemas/client/subjects.json @@ -14,10 +14,7 @@ ] }, "lang": { - "type": [ - "string", - "null" - ] + "$ref": "../doi/language.json" }, "subject": { "type": "string" }, "subjectScheme": { "type": "string" } diff --git a/app/models/schemas/doi/affiliation.json b/app/models/schemas/doi/affiliation.json new file mode 100644 index 000000000..3d6e46600 --- /dev/null +++ b/app/models/schemas/doi/affiliation.json @@ -0,0 +1,23 @@ +{ + "title": "Affiliation", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "affiliationIdentifier": { + "type": ["string", "null"] + }, + "affiliationIdentifierScheme": { + "type": ["string", "null"] + }, + "name": { + "type": ["string", "null"] + }, + "schemeUri": { + "type": ["string", "null"] + } + }, + "dependentRequired": { + "affiliationIdentifier": ["affiliationIdentifierScheme"] + }, + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/affiliations.json b/app/models/schemas/doi/affiliations.json new file mode 100644 index 000000000..54149ea9c --- /dev/null +++ b/app/models/schemas/doi/affiliations.json @@ -0,0 +1,9 @@ +{ + "title": "Affiliations", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "minItems": 0, + "items": { + "$ref": "affiliation.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/alternate_identifier.json b/app/models/schemas/doi/alternate_identifier.json new file mode 100644 index 000000000..8303219d8 --- /dev/null +++ b/app/models/schemas/doi/alternate_identifier.json @@ -0,0 +1,17 @@ +{ + "title": "AlternateIdentifier", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "alternateIdentifier": { + "type": "string" + }, + "alternateIdentifierType": { + "type": "string" + } + }, + "additionalProperties": false, + "dependentRequired": { + "alternateIdentifier": ["alternateIdentifierType"] + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/alternate_identifiers.json b/app/models/schemas/doi/alternate_identifiers.json new file mode 100644 index 000000000..0dd4d7f77 --- /dev/null +++ b/app/models/schemas/doi/alternate_identifiers.json @@ -0,0 +1,9 @@ +{ + "title": "AlternateIdentifiers", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "minItems": 0, + "items": { + "$ref": "alternate_identifier.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/contributor.json b/app/models/schemas/doi/contributor.json new file mode 100644 index 000000000..a28790b12 --- /dev/null +++ b/app/models/schemas/doi/contributor.json @@ -0,0 +1,42 @@ +{ + "title": "Contributor", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "nameType": { + "$ref": "controlled_vocabularies/name_type.json" + }, + "givenName": { + "type": ["string", "null"] + }, + "familyName": { + "type": ["string", "null"] + }, + "contributorType": { + "oneOf": [ + { + "$ref": "controlled_vocabularies/contributor_type.json" + }, + { + "type": "null" + } + ] + }, + "lang": { + "$ref": "language.json" + }, + "affiliation": { + "$ref": "affiliations.json" + }, + "nameIdentifiers": { + "$ref": "name_identifiers.json" + } + }, + "additionalProperties": false, + "required": [ + "name" + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/contributors.json b/app/models/schemas/doi/contributors.json new file mode 100644 index 000000000..444c3fc2d --- /dev/null +++ b/app/models/schemas/doi/contributors.json @@ -0,0 +1,9 @@ +{ + "title": "Contributors", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "minItems": 0, + "items": { + "$ref": "contributor.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/controlled_vocabularies/contributor_type.json b/app/models/schemas/doi/controlled_vocabularies/contributor_type.json new file mode 100644 index 000000000..798417861 --- /dev/null +++ b/app/models/schemas/doi/controlled_vocabularies/contributor_type.json @@ -0,0 +1,37 @@ +{ + "title": "ContributorType", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": ["string", "null"], + "anyOf": [ + { + "type": "string", + "enum": [ + "ContactPerson", + "DataCollector", + "DataCurator", + "DataManager", + "Distributor", + "Editor", + "HostingInstitution", + "Producer", + "ProjectLeader", + "ProjectManager", + "ProjectMember", + "RegistrationAgency", + "RegistrationAuthority", + "RelatedPerson", + "Researcher", + "ResearchGroup", + "RightsHolder", + "Sponsor", + "Supervisor", + "Translator", + "WorkPackageLeader", + "Other" + ] + }, + { + "type": "null" + } + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/controlled_vocabularies/date_type.json b/app/models/schemas/doi/controlled_vocabularies/date_type.json new file mode 100644 index 000000000..775d4e9c2 --- /dev/null +++ b/app/models/schemas/doi/controlled_vocabularies/date_type.json @@ -0,0 +1,27 @@ +{ + "title": "DateType", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": ["string", "null"], + "anyOf": [ + { + "type": "string", + "enum": [ + "Accepted", + "Available", + "Copyrighted", + "Collected", + "Coverage", + "Created", + "Issued", + "Submitted", + "Updated", + "Valid", + "Withdrawn", + "Other" + ] + }, + { + "type": "null" + } + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/controlled_vocabularies/description_type.json b/app/models/schemas/doi/controlled_vocabularies/description_type.json new file mode 100644 index 000000000..4dbe1a046 --- /dev/null +++ b/app/models/schemas/doi/controlled_vocabularies/description_type.json @@ -0,0 +1,13 @@ +{ + "title": "DescriptionType", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string", + "enum": [ + "Abstract", + "Methods", + "SeriesInformation", + "TableOfContents", + "TechnicalInfo", + "Other" + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/controlled_vocabularies/funder_identifier_type.json b/app/models/schemas/doi/controlled_vocabularies/funder_identifier_type.json new file mode 100644 index 000000000..50c0b9972 --- /dev/null +++ b/app/models/schemas/doi/controlled_vocabularies/funder_identifier_type.json @@ -0,0 +1,12 @@ +{ + "title": "FunderIdentifierType", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string", + "enum": [ + "Crossref Funder ID", + "GRID", + "ISNI", + "ROR", + "Other" + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/controlled_vocabularies/name_type.json b/app/models/schemas/doi/controlled_vocabularies/name_type.json new file mode 100644 index 000000000..8d8f4e276 --- /dev/null +++ b/app/models/schemas/doi/controlled_vocabularies/name_type.json @@ -0,0 +1,14 @@ +{ + "title": "NameType", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": ["string", "null"], + "anyOf": [ + { + "type": "string", + "enum": ["Organizational", "Personal"] + }, + { + "type": "null" + } + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/controlled_vocabularies/number_type.json b/app/models/schemas/doi/controlled_vocabularies/number_type.json new file mode 100644 index 000000000..956207856 --- /dev/null +++ b/app/models/schemas/doi/controlled_vocabularies/number_type.json @@ -0,0 +1,19 @@ +{ + "title": "NumberType", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": ["string", "null"], + "anyOf": [ + { + "type": "string", + "enum": [ + "Article", + "Chapter", + "Report", + "Other" + ] + }, + { + "type": "null" + } + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/controlled_vocabularies/related_identifier_type.json b/app/models/schemas/doi/controlled_vocabularies/related_identifier_type.json new file mode 100644 index 000000000..8ef54b551 --- /dev/null +++ b/app/models/schemas/doi/controlled_vocabularies/related_identifier_type.json @@ -0,0 +1,28 @@ +{ + "title": "RelatedIdentifierType", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string", + "enum": [ + "ARK", + "arXiv", + "bibcode", + "CSTR", + "DOI", + "EAN13", + "EISSN", + "Handle", + "IGSN", + "ISBN", + "ISSN", + "ISTC", + "LISSN", + "LSID", + "PMID", + "PURL", + "RRID", + "UPC", + "URL", + "URN", + "w3id" + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/controlled_vocabularies/related_item_type.json b/app/models/schemas/doi/controlled_vocabularies/related_item_type.json new file mode 100644 index 000000000..79f772fe1 --- /dev/null +++ b/app/models/schemas/doi/controlled_vocabularies/related_item_type.json @@ -0,0 +1,47 @@ +{ + "title": "RelatedItemType", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": ["string", "null"], + "anyOf": [ + { + "type": "string", + "enum": [ + "Audiovisual", + "Award", + "Book", + "BookChapter", + "Collection", + "ComputationalNotebook", + "ConferencePaper", + "ConferenceProceeding", + "DataPaper", + "Dataset", + "Dissertation", + "Event", + "Image", + "InteractiveResource", + "Instrument", + "Journal", + "JournalArticle", + "Model", + "OutputManagementPlan", + "PeerReview", + "PhysicalObject", + "Preprint", + "Project", + "Report", + "Service", + "Software", + "Sound", + "Standard", + "StudyRegistration", + "Text", + "Workflow", + "Other" + ] + }, + { + "type": "null" + } + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/controlled_vocabularies/relation_type.json b/app/models/schemas/doi/controlled_vocabularies/relation_type.json new file mode 100644 index 000000000..b8aea5c96 --- /dev/null +++ b/app/models/schemas/doi/controlled_vocabularies/relation_type.json @@ -0,0 +1,45 @@ +{ + "title": "RelationType", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string", + "enum": [ + "IsCitedBy", + "Cites", + "IsSupplementTo", + "IsSupplementedBy", + "IsContinuedBy", + "Continues", + "IsDescribedBy", + "Describes", + "HasMetadata", + "IsMetadataFor", + "HasVersion", + "IsVersionOf", + "IsNewVersionOf", + "IsPreviousVersionOf", + "IsPartOf", + "HasPart", + "IsPublishedIn", + "IsReferencedBy", + "References", + "IsDocumentedBy", + "Documents", + "IsCompiledBy", + "Compiles", + "IsVariantFormOf", + "IsOriginalFormOf", + "IsIdenticalTo", + "IsReviewedBy", + "Reviews", + "IsDerivedFrom", + "IsSourceOf", + "IsRequiredBy", + "Requires", + "IsObsoletedBy", + "Obsoletes", + "IsCollectedBy", + "Collects", + "IsTranslationOf", + "HasTranslation" + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/controlled_vocabularies/resource_type_general.json b/app/models/schemas/doi/controlled_vocabularies/resource_type_general.json new file mode 100644 index 000000000..43c815c95 --- /dev/null +++ b/app/models/schemas/doi/controlled_vocabularies/resource_type_general.json @@ -0,0 +1,39 @@ +{ + "title": "ResourceTypeGeneral", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string", + "enum": [ + "Audiovisual", + "Award", + "Book", + "BookChapter", + "Collection", + "ComputationalNotebook", + "ConferencePaper", + "ConferenceProceeding", + "DataPaper", + "Dataset", + "Dissertation", + "Event", + "Image", + "InteractiveResource", + "Instrument", + "Journal", + "JournalArticle", + "Model", + "OutputManagementPlan", + "PeerReview", + "PhysicalObject", + "Preprint", + "Project", + "Report", + "Service", + "Software", + "Sound", + "Standard", + "StudyRegistration", + "Text", + "Workflow", + "Other" + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/controlled_vocabularies/title_type.json b/app/models/schemas/doi/controlled_vocabularies/title_type.json new file mode 100644 index 000000000..957caa6fc --- /dev/null +++ b/app/models/schemas/doi/controlled_vocabularies/title_type.json @@ -0,0 +1,14 @@ +{ + "title": "TitleType", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": ["string", "null"], + "anyOf": [ + { + "type": "string", + "enum": ["AlternativeTitle", "Subtitle", "TranslatedTitle", "Other"] + }, + { + "type": "null" + } + ] +} diff --git a/app/models/schemas/doi/creator.json b/app/models/schemas/doi/creator.json new file mode 100644 index 000000000..197c3c531 --- /dev/null +++ b/app/models/schemas/doi/creator.json @@ -0,0 +1,31 @@ +{ + "title": "Creator", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "nameType": { + "$ref": "controlled_vocabularies/name_type.json" + }, + "givenName": { + "type": ["string", "null"] + }, + "familyName": { + "type": ["string", "null"] + }, + "lang": { + "$ref": "language.json" + }, "affiliation": { + "$ref": "affiliations.json" + }, + "nameIdentifiers": { + "$ref": "name_identifiers.json" + } + }, + "additionalProperties": false, + "required": [ + "name" + ] +} diff --git a/app/models/schemas/doi/creators.json b/app/models/schemas/doi/creators.json new file mode 100644 index 000000000..08af1f405 --- /dev/null +++ b/app/models/schemas/doi/creators.json @@ -0,0 +1,9 @@ +{ + "title": "Creators", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "minItems": 1, + "items": { + "$ref": "creator.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/date.json b/app/models/schemas/doi/date.json new file mode 100644 index 000000000..e4319230b --- /dev/null +++ b/app/models/schemas/doi/date.json @@ -0,0 +1,23 @@ +{ + "title": "Date", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "date": { + "type": "string" + }, + "dateType": { + "$ref": "controlled_vocabularies/date_type.json" + }, + "dateInformation": { + "type": "string" + } + }, + "required": [ + "date" + ], + "dependentRequired": { + "date": ["dateType"] + }, + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/dates.json b/app/models/schemas/doi/dates.json new file mode 100644 index 000000000..6f131ae46 --- /dev/null +++ b/app/models/schemas/doi/dates.json @@ -0,0 +1,8 @@ +{ + "title": "Dates", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "items": { + "$ref": "date.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/description.json b/app/models/schemas/doi/description.json new file mode 100644 index 000000000..af13ea0fe --- /dev/null +++ b/app/models/schemas/doi/description.json @@ -0,0 +1,20 @@ +{ + "title": "Description", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "description": { + "type": "string" + }, + "descriptionType": { + "$ref": "controlled_vocabularies/description_type.json" + }, + "lang": { + "$ref": "language.json" + } + }, + "additionalProperties": false, + "dependentRequired": { + "description": ["descriptionType"] + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/descriptions.json b/app/models/schemas/doi/descriptions.json new file mode 100644 index 000000000..1158c6555 --- /dev/null +++ b/app/models/schemas/doi/descriptions.json @@ -0,0 +1,8 @@ +{ + "title": "Descriptions", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "items": { + "$ref": "description.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/format.json b/app/models/schemas/doi/format.json new file mode 100644 index 000000000..5509c9938 --- /dev/null +++ b/app/models/schemas/doi/format.json @@ -0,0 +1,5 @@ +{ + "title": "Format", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string" +} diff --git a/app/models/schemas/doi/formats.json b/app/models/schemas/doi/formats.json new file mode 100644 index 000000000..1d647b0a5 --- /dev/null +++ b/app/models/schemas/doi/formats.json @@ -0,0 +1,8 @@ +{ + "title": "Formats", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "items": { + "$ref": "size.json" + } +} diff --git a/app/models/schemas/doi/funding_reference.json b/app/models/schemas/doi/funding_reference.json new file mode 100644 index 000000000..f76fe4b76 --- /dev/null +++ b/app/models/schemas/doi/funding_reference.json @@ -0,0 +1,35 @@ +{ + "title": "FundingReference", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "funderName": { + "type": ["string", "null"] + }, + "funderIdentifier": { + "type": ["string", "null"] + }, + "funderIdentifierType": { + "$ref": "controlled_vocabularies/funder_identifier_type.json" + }, + "awardNumber": { + "type": ["string", "null"] + }, + "awardUri": { + "type": ["string", "null"] + }, + "awardTitle": { + "type": ["string", "null"] + }, + "schemeUri": { + "type": ["string", "null"] + } + }, + "required": [ + "funderName" + ], + "dependentRequired": { + "funderIdentifier": ["funderIdentifierType"] + }, + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/funding_references.json b/app/models/schemas/doi/funding_references.json new file mode 100644 index 000000000..086176618 --- /dev/null +++ b/app/models/schemas/doi/funding_references.json @@ -0,0 +1,9 @@ +{ + "title": "FundingReferences", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "minItems": 0, + "items": { + "$ref": "funding_reference.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/geo_location.json b/app/models/schemas/doi/geo_location.json new file mode 100644 index 000000000..58d2c2f11 --- /dev/null +++ b/app/models/schemas/doi/geo_location.json @@ -0,0 +1,24 @@ +{ + "title": "GeoLocation", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "geoLocationPoint": { + "$ref": "geo_location_point.json" + }, + "geoLocationBox": { + "$ref": "geo_location_box.json" + }, + "geoLocationPlace": { + "$ref": "geo_location_place.json" + }, + "geoLocationPolygon": { + "$ref": "geo_location_polygon.json" + } + }, + "required": [ + "pointLatitude", + "pointLongitude" + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/geo_location_box.json b/app/models/schemas/doi/geo_location_box.json new file mode 100644 index 000000000..a9916ab34 --- /dev/null +++ b/app/models/schemas/doi/geo_location_box.json @@ -0,0 +1,26 @@ +{ + "title": "GeoLocationBox", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "eastBoundLongitude": { + "$ref": "point_longitude.json" + }, + "northBoundLatitude": { + "$ref": "point_latitude.json" + }, + "southBoundLatitude": { + "$ref": "point_latitude.json" + }, + "westBoundLongitude": { + "$ref": "point_longitude.json" + } + }, + "required": [ + "eastBoundLongitude", + "northBoundLatitude", + "southBoundLatitude", + "westBoundLongitude" + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/geo_location_place.json b/app/models/schemas/doi/geo_location_place.json new file mode 100644 index 000000000..f5b6e5050 --- /dev/null +++ b/app/models/schemas/doi/geo_location_place.json @@ -0,0 +1,5 @@ +{ + "title": "GeoLocationPlace", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string" +} \ No newline at end of file diff --git a/app/models/schemas/doi/geo_location_point.json b/app/models/schemas/doi/geo_location_point.json new file mode 100644 index 000000000..8fccb6fdf --- /dev/null +++ b/app/models/schemas/doi/geo_location_point.json @@ -0,0 +1,18 @@ +{ + "title": "GeoLocationPoint", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "pointLatitude": { + "$ref": "point_latitude.json" + }, + "pointLongitude": { + "$ref": "point_longitude.json" + } + }, + "required": [ + "pointLatitude", + "pointLongitude" + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/geo_location_polygon.json b/app/models/schemas/doi/geo_location_polygon.json new file mode 100644 index 000000000..bf5387faf --- /dev/null +++ b/app/models/schemas/doi/geo_location_polygon.json @@ -0,0 +1,23 @@ +{ + "title": "GeoLocationPolygon", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "minItems": 4, + "items": { + "oneOf": [ + { "$ref": "polygon_point" }, + { "$ref": "in_polygon_point" } + ] + }, + "allOf": [ + { + "contains": { "$ref": "polygon_point" }, + "minContains": 4 + }, + { + "contains": { "$ref": "in_polygon_point" }, + "minContains": 0, + "maxContains": 1 + } + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/geo_locations.json b/app/models/schemas/doi/geo_locations.json new file mode 100644 index 000000000..71b98e123 --- /dev/null +++ b/app/models/schemas/doi/geo_locations.json @@ -0,0 +1,8 @@ +{ + "title": "GeoLocations", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "items": { + "$ref": "geo_location.json" + } +} diff --git a/app/models/schemas/doi/identifier.json b/app/models/schemas/doi/identifier.json new file mode 100644 index 000000000..675357b2e --- /dev/null +++ b/app/models/schemas/doi/identifier.json @@ -0,0 +1,6 @@ +{ + "title": "Doi", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": [ "string", "null" ], + "description": "A DOI (Digital Object Identifier) registered by a DataCite Member. The format should be 10.21384/foo." +} \ No newline at end of file diff --git a/app/models/schemas/doi/in_polygon_point.json b/app/models/schemas/doi/in_polygon_point.json new file mode 100644 index 000000000..cad9831e1 --- /dev/null +++ b/app/models/schemas/doi/in_polygon_point.json @@ -0,0 +1,18 @@ +{ + "title": "InPolygonPoint", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "pointLatitude": { + "$ref": "point_latitude.json" + }, + "pointLongitude": { + "$ref": "point_longitude.json" + } + }, + "required": [ + "pointLatitude", + "pointLongitude" + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/language.json b/app/models/schemas/doi/language.json new file mode 100644 index 000000000..b29cf1a77 --- /dev/null +++ b/app/models/schemas/doi/language.json @@ -0,0 +1,6 @@ +{ + "title": "Language", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": [ "string", "null" ], + "pattern": "^[a-zA-Z]{1,8}(-[a-zA-Z0-9]{1,8})*$" +} \ No newline at end of file diff --git a/app/models/schemas/doi/name_identifier.json b/app/models/schemas/doi/name_identifier.json new file mode 100644 index 000000000..95c6e48e0 --- /dev/null +++ b/app/models/schemas/doi/name_identifier.json @@ -0,0 +1,20 @@ +{ + "title": "NameIdentifier", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "schemeUri": { + "type": ["string", "null"] + }, + "nameIdentifier": { + "type": ["string", "null"] + }, + "nameIdentifierScheme": { + "type": ["string", "null"] + } + }, + "dependentRequired": { + "affiliationIdentifier": ["nameIdentifierScheme"] + }, + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/name_identifiers.json b/app/models/schemas/doi/name_identifiers.json new file mode 100644 index 000000000..855e3d0dc --- /dev/null +++ b/app/models/schemas/doi/name_identifiers.json @@ -0,0 +1,9 @@ +{ + "title": "NameIdentifiers", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "minItems": 0, + "items": { + "$ref": "name_identifier.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/point_latitude.json b/app/models/schemas/doi/point_latitude.json new file mode 100644 index 000000000..54fdedd14 --- /dev/null +++ b/app/models/schemas/doi/point_latitude.json @@ -0,0 +1,5 @@ +{ + "title": "PointLatitude", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": [ "number", "string" ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/point_longitude.json b/app/models/schemas/doi/point_longitude.json new file mode 100644 index 000000000..6040d9d3c --- /dev/null +++ b/app/models/schemas/doi/point_longitude.json @@ -0,0 +1,5 @@ +{ + "title": "PointLongitude", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": [ "number", "string" ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/polygon_point.json b/app/models/schemas/doi/polygon_point.json new file mode 100644 index 000000000..c0cf7865e --- /dev/null +++ b/app/models/schemas/doi/polygon_point.json @@ -0,0 +1,18 @@ +{ + "title": "PolygonPoint", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "pointLatitude": { + "$ref": "point_latitude.json" + }, + "pointLongitude": { + "$ref": "point_longitude.json" + } + }, + "required": [ + "pointLatitude", + "pointLongitude" + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/publication_year.json b/app/models/schemas/doi/publication_year.json new file mode 100644 index 000000000..71f642461 --- /dev/null +++ b/app/models/schemas/doi/publication_year.json @@ -0,0 +1,21 @@ +{ + "title": "publicationYear", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": [ "integer", "string" ], + "oneOf": [ + { + "type": "string", + "pattern": "^(1[0-9]{3}|2[0-9]{3}|3000)$", + "minLength": 4, + "maxLength": 4 + }, + { + "type": "integer", + "minimum": 1000, + "maximum": 3000, + "inclusiveMinimum": true, + "inclusiveMaximum": true + } + ], + "description": "publicationYear: A required value representing a year in YYYY format." +} \ No newline at end of file diff --git a/app/models/schemas/doi/publisher.json b/app/models/schemas/doi/publisher.json index f8b1c66f4..956c543e9 100644 --- a/app/models/schemas/doi/publisher.json +++ b/app/models/schemas/doi/publisher.json @@ -1,12 +1,15 @@ { + "title": "Publisher", + "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", - "$schema": "http://json-schema.org/draft-04/schema#", "properties": { "name": { "type": "string" }, "publisherIdentifier": { "type": "string" }, "publisherIdentifierScheme": { "type": "string" }, "schemeUri": { "type": "string" }, - "lang": { "type": "string" } + "lang": { + "$ref": "language.json" + } }, "additionalProperties": false } diff --git a/app/models/schemas/doi/related_identifier.json b/app/models/schemas/doi/related_identifier.json new file mode 100644 index 000000000..df4dc3705 --- /dev/null +++ b/app/models/schemas/doi/related_identifier.json @@ -0,0 +1,58 @@ +{ + "title": "RelatedIdentifiers", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "relatedIdentifier": { + "type": "string" + }, + "relationType": { + "$ref": "controlled_vocabularies/relation_type.json" + }, + "relatedIdentifierType": { + "$ref": "controlled_vocabularies/related_identifier_type.json" + }, + "relatedMetaDataScheme": { + "type": "string" + }, + "schemeUri": { + "type": "string" + }, + "resourceTypeGeneral": { + "$ref": "controlled_vocabularies/resource_type_general.json" + } + }, + "if": { + "properties": { + "relationType": { + "enum": ["HasMetadata", "IsMetadataFor"] + } + } + }, + "then": { + "properties": { + "relatedMetadataScheme": { + "type": "string" + }, + "schemeUri": { + "type": "string" + }, + "schemeType": { + "type": "string" + } + } + }, + "else": { + "not": { + "anyOf": [ + { "required": ["relatedMetadataScheme"] }, + { "required": ["schemeUri"] }, + { "required": ["schemeType"] } + ] + } + }, + "dependentRequired": { + "relatedIdentifier": ["relatedIdentifierType", "relationType"] + }, + "additionalProperties": false +} diff --git a/app/models/schemas/doi/related_identifiers.json b/app/models/schemas/doi/related_identifiers.json new file mode 100644 index 000000000..d52fc123d --- /dev/null +++ b/app/models/schemas/doi/related_identifiers.json @@ -0,0 +1,8 @@ +{ + "title": "RelatedIdentifiers", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "items": { + "$ref": "related_identifier.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/related_item.json b/app/models/schemas/doi/related_item.json new file mode 100644 index 000000000..27e0cf4e3 --- /dev/null +++ b/app/models/schemas/doi/related_item.json @@ -0,0 +1,117 @@ +{ + "title": "RelatedItem", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "relatedItemType": { + "$ref": "controlled_vocabularies/resource_type_general.json" + }, + "relationType": { + "$ref": "controlled_vocabularies/relation_type.json" + }, + "relatedItemIdentifier": { + "type": "object" + }, + "creators": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "creator.json" + } + }, + "titles": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "title.json" + } + }, + "publicationYear": { + "$ref": "publication_year.json" + }, + "volume": { + "type": "string" + }, + "issue": { + "type": "string" + }, + "number": { + "type": "string" + }, + "numberType": { + "$ref": "controlled_vocabularies/number_type.json" + }, + "firstPage": { + "type": "string" + }, + "lastPage": { + "type": "string" + }, + "publisher": { + "type": "string" + }, + "edition": { + "type": "string" + }, + "contributors": { + "type": "array", + "minItems": 0, + "items": { + "$ref": "contributor.json" + } + } + }, + "if": { + "properties": { + "relationType": { + "enum": [ "HasMetadata", "IsMetadataFor" ] + } + } + }, + "then": { + "properties": { + "relatedItemIdentifier": { + "type": "object", + "properties": { + "relatedItemIdentifier": { + "type": "string" + }, + "relatedItemIdentifierType": { + "$ref": "controlled_vocabularies/related_identifier_type.json" + }, + "relatedMetadataScheme": { + "type": "string" + }, + "schemeURI": { + "type": "string" + }, + "schemeType": { + "type": "string" + } + }, + "additionalProperties": false + } + } + }, + "else": { + "properties": { + "relatedItemIdentifier": { + "type": "object", + "properties": { + "relatedItemIdentifier": { + "type": "string" + }, + "relatedItemIdentifierType": { + "$ref": "controlled_vocabularies/related_identifier_type.json" + } + }, + "additionalProperties": false + } + } + }, + "unevaluatedProperties": false, + "required": [ + "relatedItemType", + "relationType" + ] +} \ No newline at end of file diff --git a/app/models/schemas/doi/related_item_identifier.json b/app/models/schemas/doi/related_item_identifier.json new file mode 100644 index 000000000..5de94221f --- /dev/null +++ b/app/models/schemas/doi/related_item_identifier.json @@ -0,0 +1,23 @@ +{ + "title": "RelatedItemIdentifier", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "relatedItemIdentifier": { + "type": "string" + }, + "relatedItemIdentifierType": { + "$ref": "controlled_vocabularies/related_identifier_type.json" + }, + "relatedMetadataScheme": { + "type": "string" + }, + "schemeURI": { + "type": "string" + }, + "schemeType": { + "type": "string" + } + }, + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/related_items.json b/app/models/schemas/doi/related_items.json new file mode 100644 index 000000000..882b77ab0 --- /dev/null +++ b/app/models/schemas/doi/related_items.json @@ -0,0 +1,9 @@ +{ + "title": "RelatedItems", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "minItems": 0, + "items": { + "$ref": "related_item.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/resource_type.json b/app/models/schemas/doi/resource_type.json new file mode 100644 index 000000000..a276587b4 --- /dev/null +++ b/app/models/schemas/doi/resource_type.json @@ -0,0 +1,13 @@ +{ + "title": "ResourceType", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "resourceType": { "type": "string" }, + "resourceTypeGeneral": { "$ref": "controlled_vocabularies/resource_type_general.json" } + }, + "required": [ + "resourceType", + "resourceTypeGeneral" + ] +} diff --git a/app/models/schemas/doi/rights.json b/app/models/schemas/doi/rights.json new file mode 100644 index 000000000..fbc046bd4 --- /dev/null +++ b/app/models/schemas/doi/rights.json @@ -0,0 +1,16 @@ +{ + "title": "Rights", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "rights": { "type": "string" }, + "rightsUri": { "type": "string" }, + "rightsIdentifier": { "type": "string" }, + "rightsIdentifierScheme": { "type": "string" }, + "schemeUri": { "type": "string" }, + "lang": { + "$ref": "language.json" + } + }, + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/rights_list.json b/app/models/schemas/doi/rights_list.json new file mode 100644 index 000000000..22528d106 --- /dev/null +++ b/app/models/schemas/doi/rights_list.json @@ -0,0 +1,8 @@ +{ + "title": "RightsList", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "items": { + "$ref": "rights.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/size.json b/app/models/schemas/doi/size.json new file mode 100644 index 000000000..a95e0ee3a --- /dev/null +++ b/app/models/schemas/doi/size.json @@ -0,0 +1,5 @@ +{ + "title": "Size", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "string" +} diff --git a/app/models/schemas/doi/sizes.json b/app/models/schemas/doi/sizes.json new file mode 100644 index 000000000..8f20fc865 --- /dev/null +++ b/app/models/schemas/doi/sizes.json @@ -0,0 +1,9 @@ +{ + "title": "Sizes", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "minItems": 0, + "items": { + "$ref": "size.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/subject.json b/app/models/schemas/doi/subject.json new file mode 100644 index 000000000..7fa2b7ee1 --- /dev/null +++ b/app/models/schemas/doi/subject.json @@ -0,0 +1,31 @@ +{ + "title": "Subject", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "subject": { + "type": ["string", "null"] + }, + "schemeUri": { + "type": ["string", "null"], + "format": "uri" + }, + "valueUri": { + "type": ["string", "null"], + "format": "uri" + }, + "subjectScheme": { + "type": ["string", "null" ] + }, + "classificationCode": { + "type": ["string", "null" ] + }, + "lang": { + "$ref": "language.json" + } + }, + "required": [ + "subject" + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/subjects.json b/app/models/schemas/doi/subjects.json new file mode 100644 index 000000000..c87f6cd40 --- /dev/null +++ b/app/models/schemas/doi/subjects.json @@ -0,0 +1,8 @@ +{ + "title": "Subjects", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "items": { + "$ref": "subject.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/title.json b/app/models/schemas/doi/title.json new file mode 100644 index 000000000..bebf87244 --- /dev/null +++ b/app/models/schemas/doi/title.json @@ -0,0 +1,20 @@ +{ + "title": "Title", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "title": { + "type": "string" + }, + "titleType": { + "$ref": "controlled_vocabularies/title_type.json" + }, + "lang": { + "$ref": "language.json" + } + }, + "required": [ + "title" + ], + "additionalProperties": false +} \ No newline at end of file diff --git a/app/models/schemas/doi/titles.json b/app/models/schemas/doi/titles.json new file mode 100644 index 000000000..7b1def10c --- /dev/null +++ b/app/models/schemas/doi/titles.json @@ -0,0 +1,9 @@ +{ + "title": "Titles", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "array", + "minItems": 1, + "items": { + "$ref": "title.json" + } +} \ No newline at end of file diff --git a/app/models/schemas/doi/version.json b/app/models/schemas/doi/version.json new file mode 100644 index 000000000..aebd57662 --- /dev/null +++ b/app/models/schemas/doi/version.json @@ -0,0 +1,5 @@ +{ + "title": "Version", + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": [ "number", "string" ] +} diff --git a/app/validators/xml_schema_validator.rb b/app/validators/xml_schema_validator.rb index 7705ac6c2..8f06dc466 100644 --- a/app/validators/xml_schema_validator.rb +++ b/app/validators/xml_schema_validator.rb @@ -40,13 +40,7 @@ def validate_each(record, _attribute, value) kernel = get_valid_kernel(record.schema_version) return false if kernel.blank? - invalid_schemas = %w[ - http://datacite.org/schema/kernel-2.1 - http://datacite.org/schema/kernel-2.2 - http://datacite.org/schema/kernel-3.0 - http://datacite.org/schema/kernel-3.1 - http://datacite.org/schema/kernel-3 - ] + invalid_schemas = Doi::INVALID_SCHEMAS if invalid_schemas.include?(record.schema_version) && !record.skip_schema_version_validation record.errors.add(:xml, "DOI #{record.uid}: Schema #{record.schema_version} is no longer supported") diff --git a/spec/concerns/indexable_spec.rb b/spec/concerns/indexable_spec.rb index 380867b5a..69e77cee2 100644 --- a/spec/concerns/indexable_spec.rb +++ b/spec/concerns/indexable_spec.rb @@ -69,9 +69,9 @@ let!(:doi) do create( :doi, - titles: { title: "Soil investigations" }, + titles: [ { title: "Soil investigations" } ], publisher: "Pangaea", - descriptions: { description: "this is a description" }, + descriptions: [{ description: "this is a description", descriptionType: "SeriesInformation" }], aasm_state: "findable", ) end diff --git a/spec/factories/doi.rb b/spec/factories/doi.rb index 870ffc72b..a85d32e01 100644 --- a/spec/factories/doi.rb +++ b/spec/factories/doi.rb @@ -97,7 +97,10 @@ [{ "title": "Data from: A new malaria agent in African hominids." }] end descriptions do - [{ "description": "Data from: A new malaria agent in African hominids." }] + [{ + "description": "Data from: A new malaria agent in African hominids.", + "descriptionType": "TechnicalInfo" + }] end subjects do [ diff --git a/spec/fixtures/files/datacite-user-example.json b/spec/fixtures/files/datacite-user-example.json index 32bcaf699..7ae61d0bc 100644 --- a/spec/fixtures/files/datacite-user-example.json +++ b/spec/fixtures/files/datacite-user-example.json @@ -11,6 +11,7 @@ "nameType": "Personal", "givenName": "Julia M.", "familyName": "Rovera", + "name": "Rovera, Julia M.", "affiliation": [{ "name": "Drexel University" }], diff --git a/spec/fixtures/files/nasa_error.json b/spec/fixtures/files/nasa_error.json index 82023f91c..c7c01b433 100644 --- a/spec/fixtures/files/nasa_error.json +++ b/spec/fixtures/files/nasa_error.json @@ -10,7 +10,14 @@ "name":"Maskey, Manil", "nameType":"Personal", "givenName":"Manil", - "familyName":"Maskey" + "familyName":"Maskey", + "nameIdentifiers": [ + { + "schemeUri": "https://orcid.org", + "nameIdentifier": "https://orcid.org/0000-0001-5727-2427", + "nameIdentifierScheme": "ORCID" + } + ] }, { "name":"Ramachandran, Rahul", @@ -31,20 +38,29 @@ "familyName":"Ramasubramanian" } ], - "titles":{ + "titles": [ + { "title":"Tropical Cyclone Satellite Imagery and Wind Speed Dataset" - }, + } + ], "publisher": "Radiant MLHub", "publicationYear": 2020, "types":{ "resourceTypeGeneral":"Dataset" }, "version":1.0, - "contributors":{ + "contributors": [{ "nameType":"Organizational", "name":"NASA Interagency Implementation and Advanced Concepts Team (IMPACT)", - "contributorType":"DataCurator" - }, + "contributorType":"DataCurator", + "nameIdentifiers": [ + { + "schemeUri": "https://orcid.org", + "nameIdentifier": "https://orcid.org/0000-0001-5727-2427", + "nameIdentifierScheme": "ORCID" + } + ] + }], "dates":{ "dateType":"Valid", "date": "2000/2019" diff --git a/spec/fixtures/vcr_cassettes/DataciteDoisController/PATCH_/dois/_id/when_the_title_is_changed_wrong_format/error.yml b/spec/fixtures/vcr_cassettes/DataciteDoisController/PATCH_/dois/_id/when_the_title_is_changed_wrong_format/error.yml index 34e50a0c8..4ee491148 100644 --- a/spec/fixtures/vcr_cassettes/DataciteDoisController/PATCH_/dois/_id/when_the_title_is_changed_wrong_format/error.yml +++ b/spec/fixtures/vcr_cassettes/DataciteDoisController/PATCH_/dois/_id/when_the_title_is_changed_wrong_format/error.yml @@ -1,51 +1,38 @@ --- http_interactions: - request: - method: get - uri: https://api.datacite.org/re3data/10.17616/r3xs37 + method: put + uri: https://handle.test.datacite.org/api/handles/10.14454/4K3M-NYVG body: - encoding: US-ASCII - string: '' + encoding: UTF-8 + string: '[{"index":100,"type":"HS_ADMIN","data":{"format":"admin","value":{"handle":"","index":300,"permissions":"111111111111"}}},{"index":1,"type":"URL","data":{"format":"string","value":"http://www.bl.uk/pdf/pat.pdf"}}]' headers: User-Agent: - - Mozilla/5.0 (compatible; Maremma/4.9.6; mailto:info@datacite.org) + - 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 + code: 401 + message: Unauthorized headers: Date: - - Wed, 04 May 2022 17:40:51 GMT - Content-Type: - - application/json; charset=utf-8 + - Thu, 22 May 2025 13:11:35 GMT + Content-Length: + - '0' Connection: - keep-alive - Status: - - 200 OK - Cache-Control: - - max-age=0, private, must-revalidate - Vary: - - Origin - Etag: - - W/"4779b1c8cb81d39142cef21ab1d60307" - X-Runtime: - - '0.261111' - X-Request-Id: - - eda1eb1c-86ed-44bc-abb8-e241e0c9da76 - X-Powered-By: - - Phusion Passenger 5.2.3 - Server: - - nginx/1.12.2 + Phusion Passenger 5.2.3 - Content-Encoding: - - gzip + Www-Authenticate: + - Basic realm="handle", Handle sessionId="node0jpq58pljxzd91vdly5e1oc72o5", + nonce="XJEPmnoCbjbSEdGkeuQcGQ==", error="Identity not verified" body: encoding: ASCII-8BIT - string: !binary |- - H4sIAAAAAAAAA6xY224bORL9FUJPDqDW1XHGflqN480IiGLDF3iR3XmguqslJmyyQbKt0QT+m/mMfZsf21PsltUdO8rMIoAfLLFYrMupw0N96WUyyN7Zl57Keme98WgwfnMyPhleT/91M33T6/fCtiQsOJpGw35PhuDUsgrkeVfz/Zw3u2k2Ho1G49F4eoydjkrrVbBu+0EW7ONq9uHd7GLWWbpzGivrEEp/NhxuNptBKc1KkhxkNOxYnlsTZBpw6r+/9AL9Fr69L61Nh73H/pOpMrn9x9537/HXfi8jnzpVBmXNPjyRiLcoibiqllr5NTmRWycupAtr8Z9qNJqciAvzoJw1BSEiLW5SRSYlL9bSC2mE1IX1QUxHyZakE2vluQaiXrQlmUSmMPdCq6WTWGH/0qVr9aDMqi/K+uD4vzSZyJT3VCgjA74SK7KOcnJ8JNY40tzZQoQ11UH2BbXD6yOkTCyVzdQDOfRjK3wT8EBcOrWCY623gh6s5vNrbzJ6XkpPMTpPmeJsRYrDfV+oIJQXyMXJgCg4NfHJKhjkMlWaD7F5DGmmcweLe1qRQSnnxgcVAJ6++IV0sbY6/C7O4dnVB11ZjZJxxAvplCFxTR5FTNfiaHY/fxVXOFPe0nSmMfxGT44Ws+u7BTaGGM6deaoCAvzZEbIaiAaYAuFknEqBAJDYvrD31mmERAHFt9quVIq+X7qVNOp3tMUacXS/uKzDQ2HQXyStnkpTb7+WmaqNF9bwXHC1m0SO7q8X568GYh7EBtXMK6AN+b3sKMKz2bjcxrzmXA5GiEU3xbmtDNoQW9egUxzNz29eCWXEBBMa68hwXRIZkZILKldo00YB5LG+6LO4dRVwfEPw6BXghq3j04G4Rf19FSGcVxqQqHHAVVhS2LDHXUG5kexuD2lEkMErz4O2yP/pRCAL0CqtyRhngdK1iVVWRam5S6EuHRm51Jg19po6632ymwauJnoawc3ppPWpadzHg1lPi6eAD3HaauT6qmxOgFfLjgH6GHCzdY8PtJbPdZTaAiFlcBAHcM90HIGpCnK28ki13ZRWYJ9shWZpP+gQ3HsQXyVXzKt7hiOzilTV9AghddfP0ajYJ25TtGTC7rgAf6Sq1Jhzt40WMgM2I1KYmDu2EVovMR+X78URQwq6CRwcugvXV8tP9BVZT8R7ldMTXWKjT9doLba9/ee7NldPxuJnxXO2PWA0FR9kqFyLgA8Zj6diFsDLJcYK0NhNBad1mZI0duVkuT543ng6mvx142PxjmIKEXlXUkvCrfTdpMbHmM7/b+dr3occvEpruOMjbrjDOb2uj2u2HazgCfvnjuFCc9u+WICfUX50KaZ47rYe1yE+f7+SJ/WpP8RZLHQcLr6Dj0BUusqYDBBtHcqrZ2nh7meNAFa5/XpabjCboLoUpWtvK6Xz1MboTQB2pMsw8eAaEplNMfcG+qSF62e75oXkAT9kcqUlWDoKnENmsx2FMQMddDhDOeyD8hVG5RvGqEfpYJORe1YQ3nLVLEb6+EzbjXVZhzdw5a/r4eoUqZR6j/qWGJO7UexYg1bjzLcMoVviyHbswDcZbiAHrdH5PnXbF6zzKOIUqt7yK1dggUqDPzoeIDVwATZgatt3JNVLBgi0jh2lVI3IAcXWRTK1/v2WFoLi/HtiCO1ml7sLo+FdxnQFJbVlQr24g1Gj3Y01Cdqbq4DvqmeCW24Ui20ytd7mO9irZVRxALkLuBPA0abSmjV9e/nCZO3FA/cKxBvObl0UGVXt+talSRqZmOxk4r4uyUfMlqsKkf/5XyeiTExEBRwsCFrYQ0LjMqlwWT4/BR3phv0M4lGb8vW5fy48CZAIeQyGiRLJdVB/fXl9NppO6GR5ejyJhs3Lo2PVftw0ta5oSS6pjB/aKCJ9FCnDQqHeS4JwdMOMglTa84dh7qT5nFjN2jVZaUvpZ1DvYB0KvvI56gZhL8nb/k5j8jPjoFhG7X4grAqJdjXAguij3+p4v27GD4PYU+5//hEaZd8XHdQ0yd8VG9Jhw68qA9DIHPfAC7DZYyE+IV6w+BvAYlY4gKHJyoylez39SxhqFxbEnA+St26QfAcjCICJfBZl+07z1U97fpIiO8wIHvYpC0OG76/xgYwtd6W2csf2ux8DalPKnu97enA7WrFQiMhmlDYR1O7e48o0vomjAS+oRIqbagl94REEXD/nqv0DfgiJiXnBGx+OS5XdQH1Q0Rm8t5fzuCpLVX//lT/f/q3BSjXc3YE4uqHOy9k8uVr8Et14m4eNxIXB8ryJ2eI94OrVPVX2xqen/AMIXghtesSbkF/LYGe8oybJ6E0yPrkdnZ5NT8/Grz9yuiVa1BhMYHCMv9vRT2fHP51Npx97j4+P/wMAAP//AwCTHMqHrhEAAA== - http_version: null - recorded_at: Wed, 04 May 2022 17:40:49 GMT -recorded_with: VCR 5.1.0 + string: '' + recorded_at: Thu, 22 May 2025 13:11:35 GMT +recorded_with: VCR 6.2.0 diff --git a/spec/graphql/types/work_type_spec.rb b/spec/graphql/types/work_type_spec.rb index 3481c46d9..13c2f490e 100644 --- a/spec/graphql/types/work_type_spec.rb +++ b/spec/graphql/types/work_type_spec.rb @@ -935,9 +935,9 @@ { "name" => "Kristian Garza", "nameType" => "Personal", - "affiliation" => { + "affiliation" => [{ "name" => "Ruhr-University Bochum, Germany" - } + }] }, { "familyName" => "Garza", @@ -968,14 +968,16 @@ { "givenName" => "Cody", "familyName" => "Ross", + "name" => "Ross, Cody", "contributorType" => "Editor", - "affiliation" => { + "affiliation" => [{ "name" => "Ruhr-University Bochum, Germany" - } + }] }, { "givenName" => "Kristian", "familyName" => "Garza", + "name" => "Garza, Kristian", "contributorType" => "Editor", "affiliation" => [ { @@ -1090,50 +1092,52 @@ aasm_state: "findable", creators: [ { - "name" => "Kristian Garza", + "name" => "Garza, Kristian", "nameType" => "Personal", "nameIdentifiers" => - { + [{ "schemeUri": "https://orcid.org", "nameIdentifier": "https://orcid.org/0000-0002-7105-9881", "nameIdentifierScheme": "ORCID" - } + }] }, { "name" => "Ross, Cody", "familyName" => "Ross", "givenName" => "Cody", "nameIdentifiers" => - { + [{ "nameIdentifier" => "https://orcid.org/0000-0003-3484-6875", "nameIdentifierScheme" => "ORCID", "schemeUri" => "https://orcid.org", - }, + }], "nameType" => "Personal", }, ], contributors: [ { + "name" => "Ross, Cody", "givenName" => "Cody", "familyName" => "Ross", "contributorType" => "Editor", "nameIdentifiers" => - { + [{ "schemeUri": "https://orcid.org", "nameIdentifier": "https://orcid.org/0000-0002-7105-9881", "nameIdentifierScheme": "ORCID" - } + }] }, { + "name" => "Garza, Kristian", "givenName" => "Kristian", "familyName" => "Garza", "contributorType" => "Editor", "nameIdentifiers" => - { + [{ "nameIdentifier" => "https://orcid.org/0000-0003-3484-6875", "nameIdentifierScheme" => "ORCID", "schemeUri" => "https://orcid.org", - }, + }], }, ], ) @@ -1180,7 +1184,7 @@ expect(response.dig("data", "works", "authors").length).to eq(2) expect(response.dig("data", "works", "authors", 0)).to eq( { "id" => "https://orcid.org/0000-0002-7105-9881", - "title" => "Kristian Garza", + "title" => "Garza, Kristian", "count" => 1 } ) end @@ -1193,7 +1197,7 @@ expect(response.dig("data", "works", "nodes", 0, "creators")).to eq( [ { "id" => "https://orcid.org/0000-0002-7105-9881", - "name" => "Kristian Garza", + "name" => "Garza, Kristian", "givenName" => nil, "familyName" => nil }, { "id" => "https://orcid.org/0000-0003-3484-6875", @@ -1206,12 +1210,12 @@ expect(response.dig("data", "works", "nodes", 0, "contributors")).to eq( [ { "id" => "https://orcid.org/0000-0002-7105-9881", - "name" => nil, + "name" => "Ross, Cody", "givenName" => "Cody", "familyName" => "Ross", "contributorType" => "Editor" }, { "id" => "https://orcid.org/0000-0003-3484-6875", - "name" => nil, + "name" => "Garza, Kristian", "givenName" => "Kristian", "familyName" => "Garza", "contributorType" => "Editor" } @@ -1542,6 +1546,7 @@ create_list(:doi, 5, aasm_state: "findable", types: { "resourceTypeGeneral" => "Text" }, creators: [{ + name: "test_name-5", affiliation: [{ "name": "5", "affiliationIdentifier": "https://ror.org/5", @@ -1555,6 +1560,7 @@ create_list(:doi, 4, aasm_state: "findable", types: { "resourceTypeGeneral" => "JournalArticle" }, creators: [{ + name: "test_name-4", affiliation: [{ "name": "4", "affiliationIdentifier": "https://ror.org/4", @@ -1568,6 +1574,7 @@ create_list(:doi, 3, aasm_state: "findable", types: { "resourceTypeGeneral" => "Image" }, creators: [{ + name: "test_name-3", affiliation: [{ "name": "3", "affiliationIdentifier": "https://ror.org/3", @@ -1581,6 +1588,7 @@ create_list(:doi, 2, aasm_state: "findable", types: { "resourceTypeGeneral" => "PhysicalObject" }, creators: [{ + name: "test_name-2", affiliation: [{ "name": "2", "affiliationIdentifier": "https://ror.org/2", @@ -1594,6 +1602,7 @@ create(:doi, aasm_state: "findable", types: { "resourceTypeGeneral" => "Preprint" }, creators: [{ + name: "test_name-1", affiliation: [ { "name": "1", @@ -1614,7 +1623,9 @@ end let!(:missing) do create_list(:doi, 3, aasm_state: "findable", - creators: [{ affiliation: [] }], + creators: [{ + name: "test_name-3", + affiliation: [] }], rights_list: []) end @@ -1654,9 +1665,9 @@ { "name" => "Kristian Garza", "nameType" => "Personal", - "affiliation" => { + "affiliation" => [{ "name" => "Ruhr-University Bochum, Germany" - } + }] }, { "familyName" => "Garza", @@ -1692,18 +1703,18 @@ }, ], "contributorType" => "Editor", - "affiliation" => { + "affiliation" => [{ "name" => "Ruhr-University Bochum, Germany", "affiliationIdentifier": "https://ror.org/013meh722", "affiliationIdentifierScheme": "ROR" - } + }] }, { "givenName" => "Kristian", "familyName" => "Garza", + "name" => "Garza, Kristian", "contributorType" => "Editor", - "affiliation" => [ - { + "affiliation" => [{ "name" => "University of Cambridge" } ] diff --git a/spec/models/doi_spec.rb b/spec/models/doi_spec.rb index a2359634e..d59f2d3c2 100644 --- a/spec/models/doi_spec.rb +++ b/spec/models/doi_spec.rb @@ -63,7 +63,7 @@ travel_to(Time.zone.local(2023, 12, 14, 10, 7, 40)) do expect(doi).to receive(:send_import_message).with(doi.to_jsonapi) - doi.update(funding_references: [{ "funder" => "New Funder", "title" => "New Title" }]) + doi.update(funding_references: [{ "funderName" => "New Funder", "awardTitle" => "New Award Title" }]) end end @@ -1430,7 +1430,7 @@ publisher: publisher, publication_year: publication_year, types: types, - descriptions: [{ "description" => description }], + descriptions: [{ "description" => description, "descriptionType" => "Abstract" }], event: "publish") end @@ -1477,7 +1477,7 @@ end it "descriptions" do - expect(subject.descriptions).to eq([{ "description" => description }]) + expect(subject.descriptions).to eq([{ "description" => description, "descriptionType" => "Abstract" }]) xml = Maremma.from_xml(subject.xml).fetch("resource", {}) expect(xml.dig("descriptions", "description")).to eq("__content__" => "Eating your own dog food is a slang term to describe that an organization should itself use the products and services it provides. For DataCite this means that we should use DOIs with appropriate metadata and strategies for long-term preservation for...", "descriptionType" => "Abstract") diff --git a/spec/requests/datacite_dois/patch_spec.rb b/spec/requests/datacite_dois/patch_spec.rb index 01cba929d..64b881f5b 100644 --- a/spec/requests/datacite_dois/patch_spec.rb +++ b/spec/requests/datacite_dois/patch_spec.rb @@ -417,7 +417,7 @@ patch "/dois/#{doi.doi}", valid_attributes, headers expect(last_response.status).to eq(422) - expect(json["errors"]).to eq([{ "source" => "titles", "title" => "Title 'Submitted chemical data for InChIKey=YAPQBXQYLJRXSA-UHFFFAOYSA-N' should be an object instead of a string.", "uid" => "10.14454/4k3m-nyvg" }]) + expect(json["errors"]).to eq([{ "source" => "titles", "title" => "Value at root is not an array", "uid" => "10.14454/4k3m-nyvg" }]) end end diff --git a/spec/requests/datacite_dois/post_geo_spec.rb b/spec/requests/datacite_dois/post_geo_spec.rb index 0d46ca5eb..a8d2302a9 100644 --- a/spec/requests/datacite_dois/post_geo_spec.rb +++ b/spec/requests/datacite_dois/post_geo_spec.rb @@ -132,7 +132,7 @@ { "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", + "descriptionType" => "Abstract" }, ], "geoLocations" => [ diff --git a/spec/requests/datacite_dois/post_spec.rb b/spec/requests/datacite_dois/post_spec.rb index 0309ca087..7d2cb1a13 100644 --- a/spec/requests/datacite_dois/post_spec.rb +++ b/spec/requests/datacite_dois/post_spec.rb @@ -2,6 +2,7 @@ require "rails_helper" include Passwordable +require "pp" describe DataciteDoisController, type: :request, vcr: true do let(:admin) { create(:provider, symbol: "ADMIN") } @@ -357,7 +358,7 @@ "schemeType" => "URL" }, "relatedItemType" => "Journal", - "relationType" => "IsPublishedIn", + "relationType" => "HasMetadata", "titles" => [{ "title" => "Physics letters / B" }], "volume" => "776" }], @@ -388,7 +389,7 @@ expect(json.dig("data", "attributes", "source")).to eq("test") expect(json.dig("data", "attributes", "types")).to eq("bibtex" => "article", "citeproc" => "article-journal", "resourceType" => "BlogPosting", "resourceTypeGeneral" => "Text", "ris" => "RPRT", "schemaOrg" => "ScholarlyArticle") expect(json.dig("data", "attributes", "state")).to eq("findable") - expect(json.dig("data", "attributes", "relatedItems")).to eq(["relationType" => "IsPublishedIn", + expect(json.dig("data", "attributes", "relatedItems")).to eq(["relationType" => "HasMetadata", "relatedItemType" => "Journal", "publicationYear" => "2018", "relatedItemIdentifier" => { @@ -826,6 +827,7 @@ "nameType": "Personal", "givenName": "Julia M.", "familyName": "Rovera", + "name": "Rovera, Julia M.", "affiliation": [{ "name": "Drexel University" }], @@ -906,10 +908,11 @@ it "fails to create a Doi" do post "/dois", valid_attributes, headers - expect(last_response.status).to eq(201) + expect(last_response.status).to eq(422) end end + # There were no nameIdentifiers in contributors/creators. Added them so that would be tested. context "when the request has wrong object in nameIdentifiers nasa" do let(:valid_attributes) { JSON.parse(file_fixture("nasa_error.json").read) } @@ -1287,7 +1290,7 @@ end context "when the title changes" do - let(:titles) { { "title" => "Referee report. For: RESEARCH-3482 [version 5; referees: 1 approved, 1 approved with reservations]" } } + let(:titles) { [ { "title" => "Referee report. For: RESEARCH-3482 [version 5; referees: 1 approved, 1 approved with reservations]" } ] } let(:xml) { Base64.strict_encode64(file_fixture("datacite.xml").read) } let(:valid_attributes) do { @@ -2192,7 +2195,7 @@ it "updates the Doi" do get "/dois/#{doi.doi}", nil, headers - expect(json.dig("data", "attributes", "descriptions")).to eq([{ "description" => "Data from: A new malaria agent in African hominids." }]) + expect(json.dig("data", "attributes", "descriptions")).to eq([{ "description" => "Data from: A new malaria agent in African hominids.", "descriptionType" => "TechnicalInfo" }]) expect(json.dig("data", "attributes", "container")).to be_empty patch "/dois/#{doi.doi}", update_attributes, headers @@ -2425,4 +2428,97 @@ end end end + + # json-schema testing + + describe "POST /dois - json-schema" do + let(:valid_attributes) do + { + "data" => { + "type" => "dois", + "attributes" => { + "doi" => "10.14454/10703", + "url" => "http://www.bl.uk/pdf/patspec.pdf", + "types" => { "bibtex" => "article", "citeproc" => "article-journal", "resourceType" => "BlogPosting", "resourceTypeGeneral" => "Text", "ris" => "RPRT", "schemaOrg" => "ScholarlyArticle" }, + "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" }], + "language" => "en", + "alternateIdentifiers" => [{ "alternateIdentifier" => "123", "alternateIdentifierType" => "Repository ID" }], + "rightsList" => [{ "rights" => "Creative Commons Attribution 3.0", "rightsUri" => "http://creativecommons.org/licenses/by/3.0/", "lang" => "en" }], + "sizes" => ["4 kB", "12.6 MB"], + "formats" => ["application/pdf", "text/csv"], + "version" => "1.1", + "fundingReferences" => [{ "funderIdentifier" => "https://doi.org/10.13039/501100009053", "funderIdentifierType" => "Crossref Funder ID", "funderName" => "The Wellcome Trust DBT India Alliance" }], + "source" => "test", + "event" => "publish", + "relatedItems" => [{ + "contributors" => [{ "name" => "Smithson, James", + "contributorType" => "ProjectLeader", + "givenName" => "James", + "familyName" => "Smithson", + "nameType" => "Personal" + }], + "creators" => [{ "name" => "Smith, John", + "nameType" => "Personal", + "givenName" => "John", + "familyName" => "Smith", + }], + "firstPage" => "249", + "lastPage" => "264", + "publicationYear" => "2018", + "relatedItemIdentifier" => { "relatedItemIdentifier" => "10.1016/j.physletb.2017.11.044", + "relatedItemIdentifierType" => "DOI", + "relatedMetadataScheme" => "citeproc+json", + "schemeURI" => "https://github.com/citation-style-language/schema/raw/master/csl-data.json", + "schemeType" => "URL" + }, + "relatedItemType" => "Journal", + "relationType" => "HasMetadata", + "titles" => [{ "title" => "Physics letters / B" }], + "volume" => "776" + }], + }, + }, + } + end + + before do + VCR.eject_cassette + VCR.turn_off! + WebMock.allow_net_connect! + end + + context "json-schema - VALID doi" do + before do + valid_attributes["data"]["attributes"]["language"] = "fr" + end + + it "creates a Doi" do + VCR.turned_off do + post "/dois", valid_attributes, headers + end + + expect(last_response.status).to eq(201) + end + end + + context "json-schema - validate language field - INVALID" do + before do + valid_attributes["data"]["attributes"]["language"] = "fr!800-afs" + end + + it "creates a Doi" do + VCR.turned_off do + post "/dois", valid_attributes, headers + end + + expect(last_response.status).to eq(422) + expect(json.dig("errors")).to eq([ + { "source" => "metadata", "title" => "Is invalid", "uid" => "10.14454/10703" } + ]) + end + end + end end