class MetadataSchemaBaseV1(StrictKeysMixin): """Schema for the record metadata.""" id = PersistentIdentifier() identifiers = Nested(IdentifierSchemaV1, many=True, required=True) name = SanitizedUnicode(required=True, validate=validate.Length(min=3)) status = SanitizedUnicode() aliases = fields.List(SanitizedUnicode(), many=True) acronyms = fields.List(SanitizedUnicode(), many=True) types = fields.List(SanitizedUnicode(), many=True) wikipedia_url = fields.Url() email_address = fields.Email() ip_addresses = fields.List(SanitizedUnicode(), many=True) established = fields.Integer() onei_registry = fields.Integer() exportable = fields.Bool() links = fields.List(fields.Url(), many=True) labels = Nested(LabelSchemaV1, many=True) relationships = Nested(RelationSchemaV1, many=True) addresses = Nested(AddressSchemaV1, many=True) redirect = IdentifierSchemaV1() _schema = GenFunction( attribute="$schema", data_key="$schema", deserialize=schema_from_context, # to be added only when loading )
class _TestSchemaNested(Schema): """Test schema with custom Nested field.""" nested_field = Nested(NestedSchema, attribute='metadata.nested', many=True, required=True) non_list = Nested(_TestSchema)
class MetadataFullSchemaV1(MetadataSchemaBaseV1): """Schema for the record metadata.""" source_repo = Nested(SourceSchemaV1) contributors = Nested(ContributorSchemaV1, many=True) @post_dump(pass_many=False) def full_source(self, record, **kwargs): source_uuid = record['source_repo']['uuid'] source = SourceRecord.get_record(source_uuid) record['source_repo'] = source return record
class MetadataSchemaV1(StrictKeysMixin): """Schema for the record metadata.""" id = PersistentIdentifier() title = SanitizedUnicode() resource_type = SanitizedUnicode() docset = fields.Nested(DocsetSchemaV1, many=False) publications = fields.Nested(PublicationchemaV1, many=True) datasets = fields.Nested(DatasetSchemaV1, many=True) tools = Nested(ToolSchemaV1, many=True) outputs = Nested(OutputSchemaV1, many=True) virtenvs = Nested(VirtenvSchemaV1, many=True) contributors = Nested(ContributorSchemaV1, many=True)
class RelatedIdentifierSchemaV1(BaseSchema): """Related identifier schema.""" RELATIONS = [ "IsCitedBy", "Cites", "IsSupplementTo", "IsSupplementedBy", "IsContinuedBy", "Continues", "IsDescribedBy", "Describes", "HasMetadata", "IsMetadataFor", "HasVersion", "IsVersionOf", "IsNewVersionOf", "IsPreviousVersionOf", "IsPartOf", "HasPart", "IsReferencedBy", "References", "IsDocumentedBy", "Documents", "IsCompiledBy", "Compiles", "IsVariantFormOf", "IsOriginalFormOf", "IsIdenticalTo", "IsReviewedBy", "Reviews", "IsDerivedFrom", "IsSourceOf", "IsRequiredBy", "Requires", "IsObsoletedBy", "Obsoletes" ] SCHEMES = [ "ARK", "arXiv", "bibcode", "DOI", "EAN13", "EISSN", "Handle", "IGSN", "ISBN", "ISSN", "ISTC", "LISSN", "LSID", "PMID", "PURL", "UPC", "URL", "URN", "w3id" ] identifier = SanitizedUnicode(required=True) scheme = SanitizedUnicode( required=True, validate=validate.OneOf(choices=SCHEMES, error=_('Invalid related identifier scheme. ' + '{input} not one of {choices}.'))) relation_type = SanitizedUnicode( required=True, validate=validate.OneOf( choices=RELATIONS, error=_('Invalid relation type. {input} not one of {choices}.'))) resource_type = Nested(ResourceTypeSchemaV1)
class MetadataSchemaV1(StrictKeysMixin): """Schema for the record metadata.""" {{ cookiecutter.datamodel_pid_name }} = PersistentIdentifier() title = SanitizedUnicode(required=True, validate=validate.Length(min=3)) keywords = fields.List(SanitizedUnicode(), many=True) publication_date = DateString() contributors = Nested(ContributorSchemaV1, many=True, required=True)
class MetadataSchemaV1(SchemaEnforcingMixin, StrictKeysMixin): """Schema for the record metadata.""" control_number = PersistentIdentifier() title = SanitizedUnicode(required=True, validate=validate.Length(min=3)) keywords = fields.List(SanitizedUnicode(), many=True) publication_date = DateString() contributors = Nested(ContributorSchemaV1, many=True, required=True)
class AuthorMetadataSchemaV1(StrictKeysMixin): """Schema for the author metadata.""" _oai = Nested(OaiSchemaV1) id = PersistentIdentifier() name = SanitizedUnicode(required=True) organization = SanitizedUnicode(required=False) class Meta: unknown = INCLUDE
class BibliographicRecordSchemaV1(BaseSchema): """Record schema.""" metadata = Nested(MetadataSchemaV1) bucket = fields.Str() created = fields.Str(dump_only=True) revision = fields.Integer(dump_only=True) updated = fields.Str(dump_only=True) links = fields.Dict(dump_only=True) id = PersistentIdentifier(attribute='pid.pid_value')
class RecordSchemaV1(BaseSchema): """Record schema.""" # TODO: Use `RecordMetadataSchemaJSONV1` to inject PID in PUT/PATCH/... metadata = Nested(MetadataSchemaV1) bucket = fields.Str() created = fields.Str(dump_only=True) revision = fields.Integer(dump_only=True) updated = fields.Str(dump_only=True) links = fields.Dict(dump_only=True) id = PersistentIdentifier(attribute='pid.pid_value')
class MetadataSchemaV1(StrictKeysMixin): """Schema for the record metadata.""" def get_id(self, obj): """Get record id.""" pid = self.context.get('pid') return pid.pid_value if pid else missing id = PersistentIdentifier() title = SanitizedUnicode(required=True, validate=validate.Length(min=3)) keywords = fields.Nested(fields.Str(), many=True) publication_date = DateString() contributors = Nested(ContributorSchemaV1, many=True, required=True) testOption = fields.Integer()
class MetadataSchemaV1(StrictKeysMixin): """Schema for the record metadata.""" id = PersistentIdentifier() title = SanitizedUnicode(required=True, validate=validate.Length(min=3)) keywords = fields.List(SanitizedUnicode(), many=True) publication_date = DateString() contributors = Nested(ContributorSchemaV1, many=True, required=True) _schema = GenFunction( attribute="$schema", data_key="$schema", deserialize=schema_from_context, # to be added only when loading )
class MetadataSchemaV1(StrictKeysMixin): """Schema for the record metadata.""" id = PersistentIdentifier() title = SanitizedUnicode(required=True, validate=validate.Length(min=3)) keywords = fields.List(SanitizedUnicode(), many=True) publication_date = DateString() contributors = Nested(ContributorSchemaV1, many=True, required=True) educationLevel = SanitizedUnicode(required=True) subject = SanitizedUnicode(required=True) coverage = SanitizedUnicode(required=True) description = SanitizedUnicode(required=True) revisioned = fields.Boolean(required=True) license = SanitizedUnicode(required=True)
class MetadataSchemaV1(StrictKeysMixin): """Schema for the record metadata.""" id = PersistentIdentifier() title = SanitizedUnicode() creator = SanitizedUnicode() fileName = SanitizedUnicode() fileType = SanitizedUnicode() owner = fields.Integer() metadata = Nested(MetaDataSchemaX) keywords = fields.List(SanitizedUnicode(), many=True) publication_date = DateString() contributors = Nested(ContributorSchemaV1, many=True) doi = fields.Str() _schema = GenFunction( attribute="$schema", data_key="$schema", deserialize=schema_from_context, # to be added only when loading ) _oai = Nested(OaiSchemaV1) class Meta: unknown = INCLUDE
class CreatorSchemaV1(BaseSchema): """Creator schema.""" NAMES = ["Organizational", "Personal"] # TODO: Need to revisit `name` in Deposit form: # current mock-up doesn't have `name` field, so there is assumed # work on the front-end to fill this value. name = SanitizedUnicode(required=True) type = SanitizedUnicode( required=True, validate=validate.OneOf( choices=NAMES, error=_('Invalid name type. {input} not one of {choices}.'))) given_name = SanitizedUnicode() family_name = SanitizedUnicode() identifiers = fields.Dict() affiliations = fields.List(Nested(AffiliationSchemaV1)) @validates("identifiers") def validate_identifiers(self, value): """Validate well-formed identifiers are passed.""" if any(key not in ['Orcid', 'ror'] for key in value.keys()): raise ValidationError(_("Invalid identifier.")) if 'Orcid' in value: if not idutils.is_orcid(value.get('Orcid')): raise ValidationError(_("Invalid identifier.")) if 'ror' in value: if not idutils.is_ror(value.get('ror')): raise ValidationError(_("Invalid identifier.")) @validates_schema def validate_data(self, data, **kwargs): """Validate identifier based on type.""" if data['type'] == "Personal": person_identifiers = ['Orcid'] identifiers = data.get('identifiers', {}).keys() if any([ident not in person_identifiers for ident in identifiers]): raise ValidationError(_("Invalid identifier for a person.")) elif data['type'] == "Organizational": org_identifiers = ['ror'] identifiers = data.get('identifiers', {}).keys() if any([ident not in org_identifiers for ident in identifiers]): raise ValidationError( _("Invalid identifier for an organization."))
class RelationSchemaWithIDsV1(StrictKeysMixin): """Ids schema.""" id = SanitizedUnicode() identifiers = Nested(IdentifierSchemaV1, many=True, required=True) type = SanitizedUnicode() label = SanitizedUnicode() @post_dump def dump_id(self, relationship, **kwargs): if 'id' not in relationship: pidvalue = relationship['identifiers'][0]['value'] # TODO: ver si hay que optimizar esto. pid, org = OrganizationRecord.get_org_by_pid(pidvalue) if pid and org: relationship['id'] = str(pid.pid_value) return relationship
class MetadataSchemaBaseV1(StrictKeysMixin): """Base Schema for the record metadata.""" id = PersistentIdentifier() identifiers = Nested(IdentifierSchemaV1, many=True) source_repo = Nested(SourceSchemaV1) spec = Nested(SpecSchemaV1) title = SanitizedUnicode(required=True, validate=validate.Length(min=3)) creators = Nested(ContributorSchemaV1, many=True) keywords = fields.List(SanitizedUnicode(), many=True) description = SanitizedUnicode(required=True, validate=validate.Length(min=3)) publisher = SanitizedUnicode() sources = fields.List(SanitizedUnicode(), many=True) rights = fields.List(SanitizedUnicode(), many=True) types = fields.List(SanitizedUnicode(), many=True) formats = fields.List(SanitizedUnicode(), many=True) language = fields.Str() publication_date = DateString() references = Nested(ReferenceSchemaV1, many=True) terms = fields.List(SanitizedUnicode(), many=True) status = fields.Str() organizations = Nested(OrganizationDataSchema, many=True) classifications = Nested(ClasificationDataSchema, many=True)
class DocumentMetadataSchemaV1(StrictKeysMixin): """Schema for the document metadata.""" pid = PersistentIdentifier() ark = SanitizedUnicode() documentType = SanitizedUnicode() title = fields.List(fields.Dict()) partOf = fields.List(fields.Dict()) abstracts = fields.List(fields.Dict()) contribution = fields.List(fields.Dict()) organisation = fields.List(fields.Dict()) language = fields.List(fields.Dict()) copyrightDate = fields.List(fields.String()) editionStatement = fields.Dict() provisionActivity = fields.List(fields.Dict()) extent = SanitizedUnicode() otherMaterialCharacteristics = SanitizedUnicode() formats = fields.List(SanitizedUnicode()) additionalMaterials = SanitizedUnicode() series = fields.List(fields.Dict()) notes = fields.List(fields.String()) identifiedBy = fields.List(fields.Dict()) subjects = fields.List(fields.Dict()) classification = fields.List(fields.Dict()) collections = fields.List(fields.Dict()) dissertation = fields.Dict() otherEdition = fields.List(fields.Dict()) usageAndAccessPolicy = fields.Dict() projects = fields.List(fields.Dict()) oa_status = SanitizedUnicode() subdivisions = fields.List(fields.Dict()) harvested = fields.Boolean() contentNote = fields.List(SanitizedUnicode()) customField1 = fields.List(fields.String(validate=validate.Length(min=1))) customField2 = fields.List(fields.String(validate=validate.Length(min=1))) customField3 = fields.List(fields.String(validate=validate.Length(min=1))) masked = SanitizedUnicode() _bucket = SanitizedUnicode() _files = Nested(FileSchemaV1, many=True) _oai = fields.Dict() # When loading, if $schema is not provided, it's retrieved by # Record.schema property. schema = GenFunction(load_only=True, attribute="$schema", data_key="$schema", deserialize=schema_from_document) permissions = fields.Dict(dump_only=True) permalink = SanitizedUnicode(dump_only=True) @pre_dump def populate_files_properties(self, item, **kwargs): """Add some customs properties to file before dumping it. :param item: Item object to process :returns: Modified item """ if not item.get('_files'): return item # Check if organisation record forces to point file to an external url item['external_url'] = has_external_urls_for_files(item) # Add restriction, link and thumbnail to files populate_files_properties(item) # Sort files to have the main file in first position item['_files'] = sorted(item['_files'], key=lambda file: file.get('order', 100)) return item @pre_dump def add_permissions(self, item, **kwargs): """Add permissions to record. :param item: Dict representing the record. :returns: Modified dict. """ # For public views, no check for permissions if request.args.get('view'): return item item['permissions'] = { 'read': DocumentPermission.read(current_user_record, item), 'update': DocumentPermission.update(current_user_record, item), 'delete': DocumentPermission.delete(current_user_record, item) } return item @pre_dump def add_permalink(self, item, **kwargs): """Add permanent link to document.""" item['permalink'] = DocumentRecord.get_permanent_link( request.host_url, item['pid']) return item @pre_dump def add_formatted_texts(self, item, **kwargs): """Add formatted texts for objects which are processing in backend. :param item: Dict of record data. :returns: Modified data. """ # Provision activity processing for index, provision_activity in enumerate( item.get('provisionActivity', [])): item['provisionActivity'][index][ 'text'] = create_publication_statement(provision_activity) # Part of proccessing for index, part_of in enumerate(item.get('partOf', [])): item['partOf'][index]['text'] = part_of_format(part_of) # Contribution for index, contribution in enumerate(item.get('contribution', [])): item['contribution'][index]['text'] = contribution_text( contribution) if item.get('dissertation'): item['dissertation']['text'] = dissertation(item) return item @pre_load def guess_organisation(self, data, **kwargs): """Guess organisation from current logged user. :param data: Dict of record data. :returns: Modified dict of record data. """ # Organisation already attached to document, we do nothing. if data.get('organisation'): return data # Store current user organisation in new document. if current_user_record.get('organisation'): data['organisation'] = [current_user_record['organisation']] return data @pre_load def remove_fields(self, data, **kwargs): """Removes computed fields. :param data: Dict of record data. :returns: Modified data. """ for provision_activity in data.get('provisionActivity', []): provision_activity.pop('text', None) for part_of in data.get('partOf', []): part_of.pop('text', None) for contribution in data.get('contribution', []): contribution.pop('text', None) data.get('dissertation', {}).pop('text', None) data.pop('permalink', None) data.pop('permissions', None) return data
class MetadataSchemaRelIDsV1(MetadataSchemaBaseV1): """Schema for the record metadata.""" relationships = Nested(RelationSchemaWithIDsV1, many=True)
class MetadataSchemaV1(BaseSchema): """Schema for the record metadata.""" # Administrative fields _access = Nested(AccessSchemaV1, required=True) _owners = fields.List(fields.Integer, validate=validate.Length(min=1), required=True) _created_by = fields.Integer(required=True) _default_preview = SanitizedUnicode() _files = fields.List(Nested(FilesSchemaV1, dump_only=True)) _internal_notes = fields.List(Nested(InternalNoteSchemaV1)) _embargo_date = DateString(data_key="embargo_date", attribute="embargo_date") _communities = GenMethod('dump_communities') _contact = SanitizedUnicode(data_key="contact", attribute="contact") # Metadata fields access_right = SanitizedUnicode(required=True) identifiers = Identifiers() creators = fields.List(Nested(CreatorSchemaV1), required=True) titles = fields.List(Nested(TitleSchemaV1), required=True) resource_type = Nested(ResourceTypeSchemaV1, required=True) recid = PersistentIdentifier() publication_date = EDTFLevel0DateString( missing=lambda: date.today().isoformat()) subjects = fields.List(Nested(SubjectSchemaV1)) contributors = fields.List(Nested(ContributorSchemaV1)) dates = fields.List(Nested(DateSchemaV1)) language = SanitizedUnicode(validate=validate_iso639_3) related_identifiers = fields.List(Nested(RelatedIdentifierSchemaV1)) version = SanitizedUnicode() licenses = fields.List(Nested(LicenseSchemaV1)) descriptions = fields.List(Nested(DescriptionSchemaV1)) locations = fields.List(Nested(LocationSchemaV1)) references = fields.List(Nested(ReferenceSchemaV1)) extensions = fields.Method('dump_extensions', 'load_extensions') def dump_extensions(self, obj): """Dumps the extensions value. :params obj: invenio_records_files.api.Record instance """ current_app_metadata_extensions = ( current_app.extensions['invenio-rdm-records'].metadata_extensions) ExtensionSchema = current_app_metadata_extensions.to_schema() return ExtensionSchema().dump(obj.get('extensions', {})) def load_extensions(self, value): """Loads the 'extensions' field. :params value: content of the input's 'extensions' field """ current_app_metadata_extensions = ( current_app.extensions['invenio-rdm-records'].metadata_extensions) ExtensionSchema = current_app_metadata_extensions.to_schema() return ExtensionSchema().load(value) def dump_communities(self, obj): """Dumps communities related to the record.""" # NOTE: If the field is already there, it's coming from ES if '_communities' in obj: return CommunityStatusV1().dump(obj['_communities']) record = self.context.get('record') if record: _record = Record(record, model=record.model) return CommunityStatusV1().dump( RecordCommunitiesCollection(_record).as_dict()) @validates('_embargo_date') def validate_embargo_date(self, value): """Validate that embargo date is in the future.""" if arrow.get(value).date() <= arrow.utcnow().date(): raise ValidationError(_('Embargo date must be in the future.'), field_names=['embargo_date']) @validates('access_right') def validate_access_right(self, value): """Validate that access right is one of the allowed ones.""" access_right_key = {'access_right': value} validate_entry('access_right', access_right_key) @post_load def post_load_publication_date(self, obj, **kwargs): """Add '_publication_date_search' field.""" prepare_publication_date(obj) return obj
class CommunityStatusV1(BaseSchema): """Status of a community request.""" pending = fields.List(Nested(CommunitiesRequestV1)) accepted = fields.List(Nested(CommunitiesRequestV1)) rejected = fields.List(Nested(CommunitiesRequestV1))
class LocationSchemaV1(BaseSchema): """Location schema.""" point = Nested(PointSchemaV1) place = SanitizedUnicode(required=True) description = SanitizedUnicode()
class RelationSchemaV1(StrictKeysMixin): """Ids schema.""" identifiers = Nested(IdentifierSchemaV1, many=True, required=True) type = SanitizedUnicode() label = SanitizedUnicode()
name = fields.Str(required=True) role = fields.Str() affiliations = fields.List(fields.Str()) email = fields.Str() class MetadataSchemaV1(StrictKeysMixin): """Schema for the record metadata.""" def get_{{ cookiecutter.pid_name }}(self, obj): """Get record id.""" pid = self.context.get('pid') return pid.pid_value if pid else missing {{ cookiecutter.pid_name }} = PersistentIdentifier() title = SanitizedUnicode(required=True, validate=validate.Length(min=3)) keywords = fields.Nested(fields.Str(), many=True) publication_date = DateString() contributors = Nested(ContributorSchemaV1, many=True, required=True) class RecordSchemaV1(StrictKeysMixin): """Record schema.""" metadata = fields.Nested(MetadataSchemaV1) created = fields.Str(dump_only=True) revision = fields.Integer(dump_only=True) updated = fields.Str(dump_only=True) links = fields.Dict(dump_only=True) id = PersistentIdentifier()
class MetadataSchemaV1(MetadataSchemaBaseV1): """Schema for the record metadata.""" source_repo = Nested(SourceSchemaV1)