From 1db6be2bb7ca837025360cf42992a5a09cd1812f Mon Sep 17 00:00:00 2001 From: Pablo Panero Date: Wed, 16 Oct 2019 13:44:31 +0200 Subject: [PATCH] datamodel: add resource type --- invenio_rdm_records/data/objecttypes.json | 678 ++++++++++++++++++ .../jsonschemas/records/record-v1.0.0.json | 94 ++- .../mappings/v6/records/record-v1.0.0.json | 68 +- invenio_rdm_records/marshmallow/json.py | 42 +- invenio_rdm_records/models.py | 126 ++++ tests/unit/test_schemas_json_load.py | 41 ++ 6 files changed, 982 insertions(+), 67 deletions(-) create mode 100644 invenio_rdm_records/data/objecttypes.json create mode 100644 invenio_rdm_records/models.py create mode 100644 tests/unit/test_schemas_json_load.py diff --git a/invenio_rdm_records/data/objecttypes.json b/invenio_rdm_records/data/objecttypes.json new file mode 100644 index 000000000..7dbf1e8cb --- /dev/null +++ b/invenio_rdm_records/data/objecttypes.json @@ -0,0 +1,678 @@ +[{ + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication", + "id": "https://zenodo.org/objecttypes/publication#", + "title": { + "en": "Publication" + }, + "title_plural": { + "en": "Publications" + }, + "schema.org": "https://schema.org/ScholarlyArticle", + "datacite": {"general": "Text"}, + "eurepo": "info:eu-repo/semantics/other", + "children": [ + {"$ref": "https://zenodo.org/objecttypes/publication/book"}, + {"$ref": "https://zenodo.org/objecttypes/publication/section"}, + {"$ref": "https://zenodo.org/objecttypes/publication/conferencepaper"}, + {"$ref": "https://zenodo.org/objecttypes/publication/article"}, + {"$ref": "https://zenodo.org/objecttypes/publication/patent"}, + {"$ref": "https://zenodo.org/objecttypes/publication/preprint"}, + {"$ref": "https://zenodo.org/objecttypes/publication/report"}, + {"$ref": "https://zenodo.org/objecttypes/publication/softwaredocumentation"}, + {"$ref": "https://zenodo.org/objecttypes/publication/thesis"}, + {"$ref": "https://zenodo.org/objecttypes/publication/technicalnote"}, + {"$ref": "https://zenodo.org/objecttypes/publication/workingpaper"}, + {"$ref": "https://zenodo.org/objecttypes/publication/other"}, + {"$ref": "https://zenodo.org/objecttypes/publication/datamanagementplan"}, + {"$ref": "https://zenodo.org/objecttypes/publication/annotationcollection"}, + {"$ref": "https://zenodo.org/objecttypes/publication/taxonomictreatment"} + ], + "openaire": { + "resourceType": "0001", + "type": "publication" + }, + "csl": "article" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "poster", + "id": "https://zenodo.org/objecttypes/poster#", + "title": { + "en": "Poster" + }, + "title_plural": { + "en": "Posters" + }, + "datacite": {"general": "Text", "type": "Poster"}, + "eurepo": "info:eu-repo/semantics/conferencePoster", + "schema.org": "https://schema.org/CreativeWork", + "openaire": { + "resourceType": "0004", + "type": "publication" + }, + "csl": "graphic" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "presentation", + "id": "https://zenodo.org/objecttypes/presentation#", + "title": { + "en": "Presentation" + }, + "title_plural": { + "en": "Presentations" + }, + "datacite": {"general": "Text", "type": "Presentation"}, + "eurepo": "info:eu-repo/semantics/lecture", + "schema.org": "https://schema.org/PresentationDigitalDocument", + "openaire": { + "resourceType": "0004", + "type": "publication" + }, + "csl": "speech" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "dataset", + "id": "https://zenodo.org/objecttypes/dataset#", + "title": { + "en": "Dataset" + }, + "title_plural": { + "en": "Datasets" + }, + "datacite": {"general": "Dataset"}, + "eurepo": "info:eu-repo/semantics/other", + "schema.org": "https://schema.org/Dataset", + "openaire": { + "resourceType": "0021", + "type": "dataset" + }, + "csl": "dataset" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "image", + "id": "https://zenodo.org/objecttypes/image#", + "title": { + "en": "Image" + }, + "title_plural": { + "en": "Images" + }, + "schema.org": "https://schema.org/ImageObject", + "datacite": {"general": "Image"}, + "eurepo": "info:eu-repo/semantics/other", + "children": [ + {"$ref": "https://zenodo.org/objecttypes/image/figure"}, + {"$ref": "https://zenodo.org/objecttypes/image/plot"}, + {"$ref": "https://zenodo.org/objecttypes/image/drawing"}, + {"$ref": "https://zenodo.org/objecttypes/image/diagram"}, + {"$ref": "https://zenodo.org/objecttypes/image/photo"}, + {"$ref": "https://zenodo.org/objecttypes/image/other"} + ], + "openaire": { + "resourceType": "0025", + "type": "dataset" + }, + "csl": "graphic" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "video", + "id": "https://zenodo.org/objecttypes/video", + "title": { + "en": "Video/Audio" + }, + "title_plural": { + "en": "Videos/Audio" + }, + "datacite": {"general": "Audiovisual"}, + "eurepo": "info:eu-repo/semantics/other", + "schema.org": "https://schema.org/MediaObject", + "openaire": { + "resourceType": "0033", + "type": "dataset" + }, + "csl": "motion_picture" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "software", + "id": "https://zenodo.org/objecttypes/software#", + "title": { + "en": "Software" + }, + "title_plural": { + "en": "Software" + }, + "datacite": {"general": "Software"}, + "eurepo": "info:eu-repo/semantics/other", + "openaire": { + "resourceType": "0029", + "type": "software" + }, + "schema.org": "https://schema.org/SoftwareSourceCode", + "csl": "article" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "lesson", + "id": "https://zenodo.org/objecttypes/lesson#", + "title": { + "en": "Lesson" + }, + "title_plural": { + "en": "Lessons" + }, + "datacite": {"general": "InteractiveResource"}, + "eurepo": "info:eu-repo/semantics/lecture", + "schema.org": "https://schema.org/CreativeWork", + "openaire": { + "resourceType": "0010", + "type": "other" + }, + "csl": "speech" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "other", + "id": "https://zenodo.org/objecttypes/other#", + "title": { + "en": "Other" + }, + "title_plural": { + "en": "Other" + }, + "datacite": {"general": "Other"}, + "eurepo": "info:eu-repo/semantics/other", + "schema.org": "https://schema.org/CreativeWork", + "openaire": { + "resourceType": "0020", + "type": "other" + }, + "csl": "article" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-book", + "id": "https://zenodo.org/objecttypes/publication/book#", + "title": { + "en": "Book" + }, + "title_plural": { + "en": "Books" + }, + "schema.org": "https://schema.org/Book", + "datacite": {"general": "Text", "type": "Book"}, + "eurepo": "info:eu-repo/semantics/book", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0002", + "type": "publication" + }, + "csl": "book" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-section", + "id": "https://zenodo.org/objecttypes/publication/section#", + "title": { + "en": "Book section" + }, + "title_plural": { + "en": "Book sections" + }, + "schema.org": "https://schema.org/ScholarlyArticle", + "datacite": {"general": "Text", "type": "Book section"}, + "eurepo": "info:eu-repo/semantics/bookPart", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0013", + "type": "publication" + }, + "csl": "chapter" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-conferencepaper", + "id": "https://zenodo.org/objecttypes/publication/conferencepaper#", + "title": { + "en": "Conference paper" + }, + "title_plural": { + "en": "Conference papers" + }, + "schema.org": "https://schema.org/ScholarlyArticle", + "datacite": {"general": "Text", "type": "Conference paper"}, + "eurepo": "info:eu-repo/semantics/conferencePaper", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0004", + "type": "publication" + }, + "csl": "paper-conference" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-article", + "id": "https://zenodo.org/objecttypes/publication/article#", + "title": { + "en": "Journal article" + }, + "title_plural": { + "en": "Journal articles" + }, + "schema.org": "https://schema.org/ScholarlyArticle", + "datacite": {"general": "Text", "type": "Journal article"}, + "eurepo": "info:eu-repo/semantics/article", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0001", + "type": "publication" + }, + "csl": "article-journal" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-patent", + "id": "https://zenodo.org/objecttypes/publication/patent#", + "title": { + "en": "Patent" + }, + "title_plural": { + "en": "Patents" + }, + "datacite": {"general": "Text", "type": "Patent"}, + "eurepo": "info:eu-repo/semantics/patent", + "schema.org": "https://schema.org/CreativeWork", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0019", + "type": "publication" + }, + "csl": "patent" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-preprint", + "id": "https://zenodo.org/objecttypes/publication/preprint#", + "title": { + "en": "Preprint" + }, + "title_plural": { + "en": "Preprints" + }, + "schema.org": "https://schema.org/ScholarlyArticle", + "datacite": {"general": "Text", "type": "Preprint"}, + "eurepo": "info:eu-repo/semantics/preprint", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0016", + "type": "publication" + }, + "csl": "article" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-report", + "id": "https://zenodo.org/objecttypes/publication/report#", + "title": { + "en": "Report" + }, + "title_plural": { + "en": "Reports" + }, + "schema.org": "https://schema.org/ScholarlyArticle", + "datacite": {"general": "Text", "type": "Report"}, + "eurepo": "info:eu-repo/semantics/report", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0017", + "type": "publication" + }, + "csl": "article" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-softwaredocumentation", + "id": "https://zenodo.org/objecttypes/publication/softwaredocumentation#", + "title": { + "en": "Software documentation" + }, + "title_plural": { + "en": "Software documentation" + }, + "schema.org": "https://schema.org/CreativeWork", + "datacite": {"general": "Text", "type": "Software documentation"}, + "eurepo": "info:eu-repo/semantics/technicalDocumentation", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0009", + "type": "publication" + }, + "csl": "article" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-thesis", + "id": "https://zenodo.org/objecttypes/publication/thesis#", + "title": { + "en": "Thesis" + }, + "title_plural": { + "en": "Theses" + }, + "schema.org": "https://schema.org/ScholarlyArticle", + "datacite": {"general": "Text", "type": "Thesis"}, + "eurepo": "info:eu-repo/semantics/doctoralThesis", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0006", + "type": "publication" + }, + "csl": "thesis" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-technicalnote", + "id": "https://zenodo.org/objecttypes/publication/technicalnote#", + "title": { + "en": "Technical note" + }, + "title_plural": { + "en": "Technical notes" + }, + "schema.org": "https://schema.org/ScholarlyArticle", + "datacite": {"general": "Text", "type": "Technical note"}, + "eurepo": "info:eu-repo/semantics/technicalDocumentation", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0009", + "type": "publication" + }, + "csl": "article" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-workingpaper", + "id": "https://zenodo.org/objecttypes/publication/workingpaper#", + "title": { + "en": "Working paper" + }, + "title_plural": { + "en": "Working papers" + }, + "schema.org": "https://schema.org/ScholarlyArticle", + "datacite": {"general": "Text", "type": "Working paper"}, + "eurepo": "info:eu-repo/semantics/workingPaper", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0014", + "type": "publication" + }, + "csl": "article" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-proposal", + "id": "https://zenodo.org/objecttypes/publication/proposal#", + "title": { + "en": "Proposal" + }, + "title_plural": { + "en": "Proposals" + }, + "schema.org": "https://schema.org/CreativeWork", + "datacite": {"general": "Text", "type": "Proposal"}, + "eurepo": "info:eu-repo/semantics/researchProposal", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0036", + "type": "publication" + }, + "csl": "article" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-deliverable", + "id": "https://zenodo.org/objecttypes/publication/deliverable#", + "title": { + "en": "Project deliverable" + }, + "title_plural": { + "en": "Project deliverable" + }, + "schema.org": "https://schema.org/CreativeWork", + "datacite": {"general": "Text", "type": "Project deliverable"}, + "eurepo": "info:eu-repo/semantics/report", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0034", + "type": "publication" + }, + "csl": "report" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-milestone", + "id": "https://zenodo.org/objecttypes/publication/milestone#", + "title": { + "en": "Project milestone" + }, + "title_plural": { + "en": "Project milestone" + }, + "schema.org": "https://schema.org/CreativeWork", + "datacite": {"general": "Text", "type": "Project milestone"}, + "eurepo": "info:eu-repo/semantics/report", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0035", + "type": "publication" + }, + "csl": "report" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-other", + "id": "https://zenodo.org/objecttypes/publication/other#", + "title": { + "en": "Other" + }, + "title_plural": { + "en": "Other" + }, + "schema.org": "https://schema.org/CreativeWork", + "datacite": {"general": "Text", "type": "Other"}, + "eurepo": "info:eu-repo/semantics/other", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0020", + "type": "publication" + }, + "csl": "article" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "image-figure", + "id": "https://zenodo.org/objecttypes/image/figure#", + "title": { + "en": "Figure" + }, + "title_plural": { + "en": "Figures" + }, + "schema.org": "https://schema.org/ImageObject", + "datacite": {"general": "Image", "type": "Figure"}, + "eurepo": "info:eu-repo/semantics/other", + "parent": {"$ref": "https://zenodo.org/objecttypes/image#"}, + "openaire": { + "resourceType": "0025", + "type": "dataset" + }, + "csl": "figure" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "image-plot", + "id": "https://zenodo.org/objecttypes/image/plot#", + "title": { + "en": "Plot" + }, + "title_plural": { + "en": "Plots" + }, + "schema.org": "https://schema.org/ImageObject", + "datacite": {"general": "Image", "type": "Plot"}, + "eurepo": "info:eu-repo/semantics/other", + "parent": {"$ref": "https://zenodo.org/objecttypes/image"}, + "openaire": { + "resourceType": "0025", + "type": "dataset" + }, + "csl": "figure" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "image-drawing", + "id": "https://zenodo.org/objecttypes/image/drawing#", + "title": { + "en": "Drawing" + }, + "title_plural": { + "en": "Drawings" + }, + "schema.org": "https://schema.org/ImageObject", + "datacite": {"general": "Image", "type": "Drawing"}, + "eurepo": "info:eu-repo/semantics/other", + "parent": {"$ref": "https://zenodo.org/objecttypes/image"}, + "openaire": { + "resourceType": "0025", + "type": "dataset" + }, + "csl": "graphic" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "image-diagram", + "id": "https://zenodo.org/objecttypes/image/diagram#", + "title": { + "en": "Diagram" + }, + "title_plural": { + "en": "Diagrams" + }, + "schema.org": "https://schema.org/ImageObject", + "datacite": {"general": "Image", "type": "Diagram"}, + "eurepo": "info:eu-repo/semantics/other", + "parent": {"$ref": "https://zenodo.org/objecttypes/image"}, + "openaire": { + "resourceType": "0025", + "type": "dataset" + }, + "csl": "figure" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "image-photo", + "id": "https://zenodo.org/objecttypes/image/photo#", + "title": { + "en": "Photo" + }, + "title_plural": { + "en": "Photos" + }, + "schema.org": "https://schema.org/Photograph", + "datacite": {"general": "Image", "type": "Photo"}, + "eurepo": "info:eu-repo/semantics/other", + "parent": {"$ref": "https://zenodo.org/objecttypes/image"}, + "openaire": { + "resourceType": "0025", + "type": "dataset" + }, + "csl": "graphic" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "image-other", + "id": "https://zenodo.org/objecttypes/image/other#", + "title": { + "en": "Other" + }, + "title_plural": { + "en": "Other" + }, + "schema.org": "https://schema.org/ImageObject", + "datacite": {"general": "Image", "type": "Other"}, + "eurepo": "info:eu-repo/semantics/other", + "parent": {"$ref": "https://zenodo.org/objecttypes/image"}, + "openaire": { + "resourceType": "0025", + "type": "dataset" + }, + "csl": "graphic" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-datamanagementplan", + "id": "https://zenodo.org/objecttypes/publication/datamanagementplan#", + "title": { + "en": "Data management plan" + }, + "title_plural": { + "en": "Data management plans" + }, + "schema.org": "https://schema.org/CreativeWork", + "datacite": {"general": "Text", "type": "Data Management Plan"}, + "eurepo": "info:eu-repo/semantics/technicalDocumentation", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0009", + "type": "publication" + }, + "csl": "report" + }, + + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-annotationcollection", + "id": "https://zenodo.org/objecttypes/publication/annotationcollection#", + "title": { + "en": "Annotation collection" + }, + "title_plural": { + "en": "Annotation collections" + }, + "schema.org": "https://schema.org/Collection", + "datacite": {"general": "Collection"}, + "eurepo": "info:eu-repo/semantics/technicalDocumentation", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0009", + "type": "publication" + }, + "csl": "report" + }, + { + "$schema": "https://zenodo.org/schemas/records/objecttype-v1.0.0.json", + "internal_id": "publication-taxonomictreatment", + "id": "https://zenodo.org/objecttypes/publication/taxonomictreatment#", + "title": { + "en": "Taxonomic treatment" + }, + "title_plural": { + "en": "Taxonomic treatments" + }, + "schema.org": "https://schema.org/ScholarlyArticle", + "datacite": {"general": "Text", "type": "Taxonomic treatment"}, + "eurepo": "info:eu-repo/semantics/other", + "parent": {"$ref": "https://zenodo.org/objecttypes/publication"}, + "openaire": { + "resourceType": "0020", + "type": "publication" + }, + "csl": "article" + }] + \ No newline at end of file diff --git a/invenio_rdm_records/jsonschemas/records/record-v1.0.0.json b/invenio_rdm_records/jsonschemas/records/record-v1.0.0.json index 5ca45e556..3cc6804cf 100644 --- a/invenio_rdm_records/jsonschemas/records/record-v1.0.0.json +++ b/invenio_rdm_records/jsonschemas/records/record-v1.0.0.json @@ -32,39 +32,6 @@ ], "type": "string" }, - "recid": { - "description": "Invenio record identifier (integer).", - "type": "number" - }, - "title": { - "description": "Record title.", - "type": "string" - }, - "description": { - "description": "Description/abstract for record.", - "type": "string" - }, - "owners": { - "description": "List of user IDs that are owners of the record.", - "items": { - "type": "number" - }, - "type": "array", - "minItems": 1, - "uniqueItems": true - }, - "keywords": { - "description": "Free text keywords.", - "items": { - "type": "string" - }, - "type": "array" - }, - "publication_date": { - "description": "When the record is published", - "type": "string", - "format": "date-time" - }, "contributors": { "description": "Contributors in order of importance.", "minItems": 1, @@ -123,19 +90,70 @@ } }, - "_created": { + "description": { + "description": "Description/abstract for record.", "type": "string" }, - "_updated": { + "keywords": { + "description": "Free text keywords.", + "items": { + "type": "string" + }, + "type": "array" + }, + "owners": { + "description": "List of user IDs that are owners of the record.", + "items": { + "type": "number" + }, + "type": "array", + "minItems": 1, + "uniqueItems": true + }, + "publication_date": { + "description": "When the record is published", + "type": "string", + "format": "date-time" + }, + "recid": { + "description": "Invenio record identifier (integer).", + "type": "number" + }, + "resource_type": { + "additionalProperties": false, + "description": "Record resource type.", + "properties": { + "openaire_subtype": { + "description": "OpenAIRE-specific resource type.", + "type": "string" + }, + "subtype": { + "description": "Specific resource type.", + "type": "string" + }, + "type": { + "default": "publication", + "description": "General resource type.", + "type": "string" + } + }, + "required": [ + "type" + ], + "type": "object" + }, + "title": { + "description": "Record title.", "type": "string" } }, "required": [ - "access_right", "_access", + "access_right", "contributors", - "title", - "owners" + "owners", + "resource_type", + "title" ] } diff --git a/invenio_rdm_records/mappings/v6/records/record-v1.0.0.json b/invenio_rdm_records/mappings/v6/records/record-v1.0.0.json index bdc54077d..7a8a668e0 100644 --- a/invenio_rdm_records/mappings/v6/records/record-v1.0.0.json +++ b/invenio_rdm_records/mappings/v6/records/record-v1.0.0.json @@ -21,33 +21,6 @@ "access_right": { "type": "keyword" }, - "$schema": { - "type": "keyword", - "index": false - }, - "recid": { - "type": "keyword" - }, - "title": { - "type": "text", - "copy_to": "suggest_title" - }, - "suggest_title": { - "type": "completion" - }, - "description": { - "type": "text" - }, - "owners": { - "type": "integer" - }, - "keywords": { - "type": "keyword" - }, - "publication_date": { - "type": "date", - "format": "date" - }, "contributors": { "type": "object", "properties": { @@ -81,11 +54,52 @@ } } }, + "description": { + "type": "text" + }, + "keywords": { + "type": "keyword" + }, + "owners": { + "type": "integer" + }, + "publication_date": { + "type": "date", + "format": "date" + }, + "recid": { + "type": "keyword" + }, + "resource_type": { + "type": "object", + "properties": { + "openaire_subtype": { + "type": "keyword" + }, + "type": { + "type": "keyword" + }, + "subtype": { + "type": "keyword" + } + } + }, + "suggest_title": { + "type": "completion" + }, + "title": { + "type": "text", + "copy_to": "suggest_title" + }, "_created": { "type": "date" }, "_updated": { "type": "date" + }, + "$schema": { + "type": "text", + "index": false } } } diff --git a/invenio_rdm_records/marshmallow/json.py b/invenio_rdm_records/marshmallow/json.py index 09ba0e8d6..c81edd074 100644 --- a/invenio_rdm_records/marshmallow/json.py +++ b/invenio_rdm_records/marshmallow/json.py @@ -11,10 +11,14 @@ from __future__ import absolute_import, print_function +from flask_babelex import lazy_gettext as _ from invenio_records_rest.schemas import Nested, StrictKeysMixin from invenio_records_rest.schemas.fields import DateString, \ PersistentIdentifier, SanitizedUnicode -from marshmallow import fields, validate +from marshmallow import ValidationError, fields, missing, validate, \ + validates_schema + +from ..models import AccessRight, ObjectType class AccessSchemaV1(StrictKeysMixin): @@ -43,6 +47,39 @@ class ContributorSchemaV1(StrictKeysMixin): email = fields.Email() +class ResourceTypeSchemaV1(StrictKeysMixin): + """Resource type schema.""" + + type = fields.Str( + required=True, + error_messages=dict( + required=_('Type must be specified.') + ), + ) + subtype = fields.Str() + openaire_subtype = fields.Str() + title = fields.Method('get_title', dump_only=True) + + def get_title(self, obj): + """Get title.""" + obj = ObjectType.get_by_dict(obj) + return obj['title']['en'] if obj else missing + + @validates_schema + def validate_data(self, data): + """Validate resource type.""" + obj = ObjectType.get_by_dict(data) + if obj is None: + raise ValidationError(_('Invalid resource type.')) + + def dump_openaire_type(self, obj): + """Get OpenAIRE subtype.""" + acc = obj.get('access_right') + if acc: + return AccessRight.as_category(acc) + return missing + + class MetadataSchemaV1(StrictKeysMixin): """Schema for the record metadata.""" @@ -58,12 +95,13 @@ class MetadataSchemaV1(StrictKeysMixin): keywords = fields.List(SanitizedUnicode(), many=True) publication_date = DateString() contributors = Nested(ContributorSchemaV1, many=True, required=True) + resource_type = fields.Nested(ResourceTypeSchemaV1) -# TODO: Use `RecordMetadataSchemaJSONV1` to inject PID in PUT/PATCH/... class RecordSchemaV1(StrictKeysMixin): """Record schema.""" + # TODO: Use `RecordMetadataSchemaJSONV1` to inject PID in PUT/PATCH/... metadata = fields.Nested(MetadataSchemaV1) bucket = fields.Str() created = fields.Str(dump_only=True) diff --git a/invenio_rdm_records/models.py b/invenio_rdm_records/models.py new file mode 100644 index 000000000..d7bc56532 --- /dev/null +++ b/invenio_rdm_records/models.py @@ -0,0 +1,126 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2019 CERN. +# Copyright (C) 2019 Northwestern University, +# Galter Health Sciences Library & Learning Center. +# +# Invenio-RDM-Records is free software; you can redistribute it and/or modify +# it under the terms of the MIT License; see LICENSE file for more details. + +"""Models for Invenio RDM Records.""" + +import json +from os.path import dirname, join + +from elasticsearch_dsl.utils import AttrDict +from jsonref import JsonRef + + +class AccessRight(object): + """Class defining access right status.""" + + OPEN = 'open' + + EMBARGOED = 'embargoed' + + RESTRICTED = 'restricted' + + CLOSED = 'closed' + + _category = { + OPEN: 'success', + EMBARGOED: 'warning', + RESTRICTED: 'danger', + CLOSED: 'danger', + } + + @classmethod + def as_category(cls, value, **kwargs): + """Get title for a specific status.""" + cat = cls._category[value] + return kwargs[cat] if cat in kwargs else cat + + +class ObjectType(object): + """Class to load object types data.""" + + index_id = None + index_internal_id = None + types = None + subtypes = None + + @classmethod + def _load_data(cls): + """Load object types for JSON data.""" + if cls.index_id is None: + with open(join(dirname(__file__), "data", "objecttypes.json")) \ + as fp: + data = json.load(fp) + + cls.index_internal_id = {} + cls.index_id = {} + cls.types = set() + cls.subtypes = {} + for objtype in data: + cls.index_internal_id[objtype['internal_id']] = objtype + cls.index_id[objtype['id'][:-1]] = objtype + if '-' in objtype['internal_id']: + type_, subtype = objtype['internal_id'].split('-') + cls.types.add(type_) + if type_ not in cls.subtypes: + cls.subtypes[type_] = set() + cls.subtypes[type_].add(subtype) + else: + cls.types.add(objtype['internal_id']) + + @classmethod + def validate_internal_id(cls, id): + """Check if the provided ID corresponds to the internal ones.""" + cls._load_data() + return id in cls.index_internal_id + + @classmethod + def _jsonloader(cls, uri, **dummy_kwargs): + """Local JSON loader for JsonRef.""" + cls._load_data() + return cls.index_id[uri] + + @classmethod + def get(cls, value): + """Get object type value.""" + cls._load_data() + try: + return JsonRef.replace_refs( + cls.index_internal_id[value], + jsonschema=True, + loader=cls._jsonloader) + except KeyError: + return None + + @classmethod + def get_types(cls): + """Get object type value.""" + cls._load_data() + return cls.types + + @classmethod + def get_subtypes(cls, type_): + """Get object type value.""" + cls._load_data() + return cls.subtypes[type_] + + @classmethod + def get_by_dict(cls, value): + """Get object type dict with type and subtype key.""" + if not value: + return None + if 'subtype' in value: + if isinstance(value, AttrDict): + value = value.to_dict() + internal_id = "{0}-{1}".format( + value.get('type', ''), + value.get('subtype', '') + ) + else: + internal_id = value['type'] + return cls.get(internal_id) diff --git a/tests/unit/test_schemas_json_load.py b/tests/unit/test_schemas_json_load.py new file mode 100644 index 000000000..de5b87f8f --- /dev/null +++ b/tests/unit/test_schemas_json_load.py @@ -0,0 +1,41 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2019 CERN. +# Copyright (C) 2019 Northwestern University, +# Galter Health Sciences Library & Learning Center. +# +# Invenio-RDM-Records is free software; you can redistribute it and/or modify +# it under the terms of the MIT License; see LICENSE file for more details. + +"""Tests for Invenio RDM Records JSON Schemas.""" + +import pytest + +from invenio_rdm_records.marshmallow.json import MetadataSchemaV1 + + +@pytest.mark.parametrize(('val', 'expected'), [ + (dict(type='publication', subtype='preprint'), None), + (dict(type='image', subtype='photo'), None), + (dict(type='dataset'), None), + (dict(type='dataset', title='Dataset'), dict(type='dataset')), +]) +def test_valid_resource_type(val, expected): + """Test resource type.""" + data, errors = MetadataSchemaV1(partial=['resource_type']).load( + dict(resource_type=val)) + assert data['resource_type'] == val if expected is None else expected + + +@pytest.mark.parametrize('val', [ + dict(type='image', subtype='preprint'), + dict(subtype='photo'), + dict(type='invalid'), + dict(title='Dataset'), + dict(), +]) +def test_invalid_resource_type(val): + """Test resource type.""" + data, errors = MetadataSchemaV1(partial=['resource_type']).load( + dict(resource_type=val)) + assert 'resource_type' in errors