class BaseRegistrationSerializer(NodeSerializer): title = ser.CharField(read_only=True) description = ser.CharField(read_only=True) category_choices = NodeSerializer.category_choices category_choices_string = NodeSerializer.category_choices_string category = HideIfWithdrawal( ser.ChoiceField(read_only=True, choices=category_choices, help_text='Choices: ' + category_choices_string)) date_modified = VersionedDateTimeField(source='last_logged', read_only=True) fork = HideIfWithdrawal(ser.BooleanField(read_only=True, source='is_fork')) collection = HideIfWithdrawal( ser.BooleanField(read_only=True, source='is_collection')) access_requests_enabled = HideIfWithdrawal( ser.BooleanField(read_only=True)) node_license = HideIfWithdrawal(NodeLicenseSerializer(read_only=True)) tags = HideIfWithdrawal( ValuesListField(attr_name='name', child=ser.CharField(), required=False)) public = HideIfWithdrawal( ser.BooleanField( source='is_public', required=False, help_text='Nodes that are made public will give read-only access ' 'to everyone. Private nodes require explicit read ' 'permission. Write and admin access are the same for ' 'public and private nodes. Administrators on a parent ' 'node have implicit read permissions for all child nodes')) current_user_permissions = HideIfWithdrawal( ser.SerializerMethodField( help_text='List of strings representing the permissions ' 'for the current user on this node.')) pending_embargo_approval = HideIfWithdrawal( ser.BooleanField( read_only=True, source='is_pending_embargo', help_text= 'The associated Embargo is awaiting approval by project admins.')) pending_registration_approval = HideIfWithdrawal( ser.BooleanField( source='is_pending_registration', read_only=True, help_text= 'The associated RegistrationApproval is awaiting approval by project admins.' )) pending_withdrawal = HideIfWithdrawal( ser.BooleanField( source='is_pending_retraction', read_only=True, help_text= 'The registration is awaiting withdrawal approval by project admins.' )) withdrawn = ser.BooleanField( source='is_retracted', read_only=True, help_text='The registration has been withdrawn.') date_registered = VersionedDateTimeField( source='registered_date', read_only=True, help_text='Date time of registration.') date_withdrawn = VersionedDateTimeField( source='retraction.date_retracted', read_only=True, help_text='Date time of when this registration was retracted.') embargo_end_date = HideIfWithdrawal( ser.SerializerMethodField( help_text='When the embargo on this registration will be lifted.')) withdrawal_justification = ser.CharField(source='retraction.justification', read_only=True) template_from = HideIfWithdrawal( ser.CharField( read_only=True, allow_blank=False, allow_null=False, help_text= 'Specify a node id for a node you would like to use as a template for the ' 'new node. Templating is like forking, except that you do not copy the ' 'files, only the project structure. Some information is changed on the top ' 'level project by submitting the appropriate fields in the request body, ' 'and some information will not change. By default, the description will ' 'be cleared and the project will be made private.')) registration_supplement = ser.SerializerMethodField() registered_meta = HideIfWithdrawal( ser.SerializerMethodField( help_text= 'A dictionary with supplemental registration questions and responses.' )) registered_by = HideIfWithdrawal( RelationshipField( related_view='users:user-detail', related_view_kwargs={'user_id': '<registered_user._id>'})) registered_from = HideIfWithdrawal( RelationshipField( related_view='nodes:node-detail', related_view_kwargs={'node_id': '<registered_from._id>'})) children = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-children', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_node_count'}, )) comments = HideIfWithdrawal( RelationshipField(related_view='registrations:registration-comments', related_view_kwargs={'node_id': '<_id>'}, related_meta={'unread': 'get_unread_comments_count'}, filter={'target': '<_id>'})) contributors = RelationshipField( related_view='registrations:registration-contributors', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_contrib_count'}) implicit_contributors = RelationshipField( related_view='registrations:registration-implicit-contributors', related_view_kwargs={'node_id': '<_id>'}, help_text= 'This feature is experimental and being tested. It may be deprecated.') files = HideIfWithdrawal( RelationshipField(related_view='registrations:registration-providers', related_view_kwargs={'node_id': '<_id>'})) wikis = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-wikis', related_view_kwargs={'node_id': '<_id>'}, )) forked_from = HideIfWithdrawal( RelationshipField( related_view=lambda n: 'registrations:registration-detail' if getattr(n, 'is_registration', False) else 'nodes:node-detail', related_view_kwargs={'node_id': '<forked_from_id>'})) template_node = HideIfWithdrawal( RelationshipField( related_view='nodes:node-detail', related_view_kwargs={'node_id': '<template_node._id>'})) license = HideIfWithdrawal( RelationshipField( related_view='licenses:license-detail', related_view_kwargs={ 'license_id': '<node_license.node_license._id>' }, )) logs = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-logs', related_view_kwargs={'node_id': '<_id>'}, )) forks = HideIfWithdrawal( RelationshipField(related_view='registrations:registration-forks', related_view_kwargs={'node_id': '<_id>'})) node_links = ShowIfVersion(HideIfWithdrawal( RelationshipField( related_view='registrations:registration-pointers', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_pointers_count'}, help_text= 'This feature is deprecated as of version 2.1. Use linked_nodes instead.' )), min_version='2.0', max_version='2.0') parent = HideIfWithdrawal( RelationshipField(related_view='registrations:registration-detail', related_view_kwargs={'node_id': '<parent_node._id>'}, filter_key='parent_node')) root = HideIfWithdrawal( RelationshipField(related_view='registrations:registration-detail', related_view_kwargs={'node_id': '<root._id>'})) affiliated_institutions = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-institutions', related_view_kwargs={'node_id': '<_id>'})) registration_schema = RelationshipField( related_view='metaschemas:registration-metaschema-detail', related_view_kwargs={'metaschema_id': '<registered_schema_id>'}) registrations = HideIfRegistration( RelationshipField(related_view='nodes:node-registrations', related_view_kwargs={'node_id': '<_id>'})) draft_registrations = HideIfRegistration( RelationshipField(related_view='nodes:node-draft-registrations', related_view_kwargs={'node_id': '<_id>'})) preprints = HideIfWithdrawal( HideIfRegistration( RelationshipField(related_view='nodes:node-preprints', related_view_kwargs={'node_id': '<_id>'}))) identifiers = HideIfWithdrawal( RelationshipField(related_view='registrations:identifier-list', related_view_kwargs={'node_id': '<_id>'})) linked_nodes = HideIfWithdrawal( RelationshipField(related_view='registrations:linked-nodes', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_node_links_count'}, self_view='registrations:node-pointer-relationship', self_view_kwargs={'node_id': '<_id>'})) linked_registrations = HideIfWithdrawal( RelationshipField( related_view='registrations:linked-registrations', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_registration_links_count'}, self_view='registrations:node-registration-pointer-relationship', self_view_kwargs={'node_id': '<_id>'})) view_only_links = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-view-only-links', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_view_only_links_count'}, )) citation = HideIfWithdrawal( RelationshipField(related_view='registrations:registration-citation', related_view_kwargs={'node_id': '<_id>'})) links = LinksField({ 'self': 'get_registration_url', 'html': 'get_absolute_html_url' }) def get_registration_url(self, obj): return absolute_reverse( 'registrations:registration-detail', kwargs={ 'node_id': obj._id, 'version': self.context['request'].parser_context['kwargs']['version'] }) def get_absolute_url(self, obj): return self.get_registration_url(obj) def create(self, validated_data): auth = get_user_auth(self.context['request']) draft = validated_data.pop('draft') registration_choice = validated_data.pop('registration_choice', 'immediate') embargo_lifted = validated_data.pop('lift_embargo', None) reviewer = is_prereg_admin_not_project_admin(self.context['request'], draft) try: draft.validate_metadata(metadata=draft.registration_metadata, reviewer=reviewer, required_fields=True) except ValidationValueError as e: raise exceptions.ValidationError(e.message) registration = draft.register(auth, save=True) if registration_choice == 'embargo': if not embargo_lifted: raise exceptions.ValidationError( 'lift_embargo must be specified.') embargo_end_date = embargo_lifted.replace(tzinfo=pytz.utc) try: registration.embargo_registration(auth.user, embargo_end_date) except ValidationError as err: raise exceptions.ValidationError(err.message) else: try: registration.require_approval(auth.user) except NodeStateError as err: raise exceptions.ValidationError(err) registration.save() return registration def get_registered_meta(self, obj): if obj.registered_meta: meta_values = obj.registered_meta.values()[0] try: return json.loads(meta_values) except TypeError: return meta_values except ValueError: return meta_values return None def get_embargo_end_date(self, obj): if obj.embargo_end_date: return obj.embargo_end_date return None def get_registration_supplement(self, obj): if obj.registered_schema: schema = obj.registered_schema.first() if schema is None: return None return schema.name return None def get_current_user_permissions(self, obj): return NodeSerializer.get_current_user_permissions(self, obj) def update(self, registration, validated_data): auth = Auth(self.context['request'].user) # Update tags if 'tags' in validated_data: new_tags = validated_data.pop('tags', []) try: registration.update_tags(new_tags, auth=auth) except NodeStateError as err: raise Conflict(err.message) is_public = validated_data.get('is_public', None) if is_public is not None: if is_public: try: registration.update(validated_data, auth=auth) except NodeUpdateError as err: raise exceptions.ValidationError(err.reason) except NodeStateError as err: raise exceptions.ValidationError(err.message) else: raise exceptions.ValidationError( 'Registrations can only be turned from private to public.') return registration class Meta: type_ = 'registrations'
class RegistrationSerializer(NodeSerializer): admin_only_editable_fields = [ 'affiliated_institutions', 'article_doi', 'custom_citation', 'description', 'is_pending_retraction', 'is_public', 'license', 'license_type', 'subjects', 'withdrawal_justification', 'category', ] # Remember to add new RegistrationSerializer fields to this list # if you don't need them to be anonymized non_anonymized_fields = NodeSerializer.non_anonymized_fields + [ 'archiving', 'article_doi', 'date_registered', 'date_withdrawn', 'embargo_end_date', 'embargoed', 'pending_embargo_approval', 'pending_embargo_termination_approval', 'pending_registration_approval', 'pending_withdrawal', 'provider', 'registered_by', 'registered_from', 'registered_meta', 'registration_responses', 'registration_schema', 'registration_supplement', 'withdrawal_justification', 'withdrawn', ] title = ser.CharField(read_only=True) description = ser.CharField(required=False, allow_blank=True, allow_null=True) category_choices = NodeSerializer.category_choices category_choices_string = NodeSerializer.category_choices_string category = ser.ChoiceField(required=False, choices=category_choices, help_text='Choices: ' + category_choices_string) date_modified = VersionedDateTimeField(source='last_logged', read_only=True) fork = HideIfWithdrawal(ser.BooleanField(read_only=True, source='is_fork')) collection = HideIfWithdrawal( ser.BooleanField(read_only=True, source='is_collection')) access_requests_enabled = HideIfWithdrawal( ser.BooleanField(read_only=True)) node_license = HideIfWithdrawal( NodeLicenseSerializer(required=False, source='license')) tags = HideIfWithdrawal( ValuesListField(attr_name='name', child=ser.CharField(), required=False)) article_doi = ser.CharField(required=False, allow_null=True) public = HideIfWithdrawal( ser.BooleanField( source='is_public', required=False, help_text='Nodes that are made public will give read-only access ' 'to everyone. Private nodes require explicit read ' 'permission. Write and admin access are the same for ' 'public and private nodes. Administrators on a parent ' 'node have implicit read permissions for all child nodes', )) current_user_permissions = HideIfWithdrawal( ser.SerializerMethodField( help_text='List of strings representing the permissions ' 'for the current user on this node.', )) pending_embargo_approval = HideIfWithdrawal( ser.BooleanField( read_only=True, source='is_pending_embargo', help_text= 'The associated Embargo is awaiting approval by project admins.', )) pending_embargo_termination_approval = HideIfWithdrawal( ser.BooleanField( read_only=True, source='is_pending_embargo_termination', help_text= 'The associated Embargo early termination is awaiting approval by project admins', )) embargoed = HideIfWithdrawal( ser.BooleanField(read_only=True, source='is_embargoed')) pending_registration_approval = HideIfWithdrawal( ser.BooleanField( source='is_pending_registration', read_only=True, help_text= 'The associated RegistrationApproval is awaiting approval by project admins.', )) archiving = HideIfWithdrawal(ser.BooleanField(read_only=True)) pending_withdrawal = HideIfWithdrawal( ser.BooleanField( source='is_pending_retraction', read_only=True, help_text= 'The registration is awaiting withdrawal approval by project admins.', )) withdrawn = ser.BooleanField( source='is_retracted', read_only=True, help_text='The registration has been withdrawn.', ) date_registered = VersionedDateTimeField( source='registered_date', read_only=True, help_text='Date time of registration.') date_withdrawn = VersionedDateTimeField( read_only=True, help_text='Date time of when this registration was retracted.') embargo_end_date = HideIfWithdrawal( ser.SerializerMethodField( help_text='When the embargo on this registration will be lifted.')) custom_citation = HideIfWithdrawal( ser.CharField(allow_blank=True, required=False)) withdrawal_justification = ser.CharField(read_only=True) template_from = HideIfWithdrawal( ser.CharField( read_only=True, allow_blank=False, allow_null=False, help_text= 'Specify a node id for a node you would like to use as a template for the ' 'new node. Templating is like forking, except that you do not copy the ' 'files, only the project structure. Some information is changed on the top ' 'level project by submitting the appropriate fields in the request body, ' 'and some information will not change. By default, the description will ' 'be cleared and the project will be made private.', )) registration_supplement = ser.SerializerMethodField() # Will be deprecated in favor of registration_responses registered_meta = HideIfWithdrawal( ser.SerializerMethodField( help_text= 'A dictionary with supplemental registration questions and responses.', )) registration_responses = HideIfWithdrawal( ser.SerializerMethodField( help_text= 'A dictionary with supplemental registration questions and responses.', )) registered_by = HideIfWithdrawal( RelationshipField( related_view='users:user-detail', related_view_kwargs={'user_id': '<registered_user._id>'}, )) registered_from = RelationshipField( related_view='nodes:node-detail', related_view_kwargs={'node_id': '<registered_from._id>'}, ) children = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-children', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_node_count'}, )) comments = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-comments', related_view_kwargs={'node_id': '<_id>'}, related_meta={ 'unread': 'get_unread_comments_count', 'count': 'get_total_comments_count', }, filter={'target': '<_id>'}, )) contributors = RelationshipField( related_view='registrations:registration-contributors', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_contrib_count'}, ) bibliographic_contributors = RelationshipField( related_view='registrations:registration-bibliographic-contributors', related_view_kwargs={'node_id': '<_id>'}, ) implicit_contributors = RelationshipField( related_view='registrations:registration-implicit-contributors', related_view_kwargs={'node_id': '<_id>'}, help_text= 'This feature is experimental and being tested. It may be deprecated.', ) files = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-storage-providers', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_files_count'}, )) wikis = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-wikis', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_wiki_page_count'}, )) forked_from = HideIfWithdrawal( RelationshipField( related_view=lambda n: 'registrations:registration-detail' if getattr(n, 'is_registration', False) else 'nodes:node-detail', related_view_kwargs={'node_id': '<forked_from_id>'}, )) template_node = HideIfWithdrawal( RelationshipField( related_view='nodes:node-detail', related_view_kwargs={'node_id': '<template_node._id>'}, )) license = HideIfWithdrawal( NodeLicenseRelationshipField( related_view='licenses:license-detail', related_view_kwargs={'license_id': '<license.node_license._id>'}, read_only=False, )) logs = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-logs', related_view_kwargs={'node_id': '<_id>'}, )) forks = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-forks', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_forks_count'}, )) groups = HideIfRegistration( RelationshipField( related_view='nodes:node-groups', related_view_kwargs={'node_id': '<_id>'}, )) node_links = ShowIfVersion( HideIfWithdrawal( RelationshipField( related_view='registrations:registration-pointers', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_pointers_count'}, help_text= 'This feature is deprecated as of version 2.1. Use linked_nodes instead.', )), min_version='2.0', max_version='2.0', ) linked_by_nodes = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-linked-by-nodes', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_linked_by_nodes_count'}, )) linked_by_registrations = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-linked-by-registrations', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_linked_by_registrations_count'}, )) parent = RelationshipField( related_view='registrations:registration-detail', related_view_kwargs={'node_id': '<parent_node._id>'}, filter_key='parent_node', ) root = RelationshipField( related_view='registrations:registration-detail', related_view_kwargs={'node_id': '<root._id>'}, ) region = HideIfWithdrawal( RelationshipField( related_view='regions:region-detail', related_view_kwargs={'region_id': '<osfstorage_region._id>'}, read_only=True, )) affiliated_institutions = RelationshipField( related_view='registrations:registration-institutions', related_view_kwargs={'node_id': '<_id>'}, self_view='registrations:registration-relationships-institutions', self_view_kwargs={'node_id': '<_id>'}, read_only=False, many=True, required=False, ) registration_schema = RelationshipField( related_view='schemas:registration-schema-detail', related_view_kwargs={'schema_id': '<registered_schema_id>'}, ) settings = HideIfRegistration( RelationshipField( related_view='nodes:node-settings', related_view_kwargs={'node_id': '<_id>'}, )) registrations = HideIfRegistration( RelationshipField( related_view='nodes:node-registrations', related_view_kwargs={'node_id': '<_id>'}, )) draft_registrations = HideIfRegistration( RelationshipField( related_view='nodes:node-draft-registrations', related_view_kwargs={'node_id': '<_id>'}, )) preprints = HideIfWithdrawal( HideIfRegistration( RelationshipField( related_view='nodes:node-preprints', related_view_kwargs={'node_id': '<_id>'}, ))) identifiers = RelationshipField( related_view='registrations:identifier-list', related_view_kwargs={'node_id': '<_id>'}, ) linked_nodes = HideIfWithdrawal( RelationshipField( related_view='registrations:linked-nodes', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_node_links_count'}, self_view='registrations:node-pointer-relationship', self_view_kwargs={'node_id': '<_id>'}, )) linked_registrations = HideIfWithdrawal( RelationshipField( related_view='registrations:linked-registrations', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_registration_links_count'}, self_view='registrations:node-registration-pointer-relationship', self_view_kwargs={'node_id': '<_id>'}, )) view_only_links = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-view-only-links', related_view_kwargs={'node_id': '<_id>'}, related_meta={'count': 'get_view_only_links_count'}, )) citation = HideIfWithdrawal( RelationshipField( related_view='registrations:registration-citation', related_view_kwargs={'node_id': '<_id>'}, )) provider = RegistrationProviderRelationshipField( related_view= 'providers:registration-providers:registration-provider-detail', related_view_kwargs={'provider_id': '<provider._id>'}, read_only=True, ) @property def subjects_related_view(self): # Overrides TaxonomizableSerializerMixin return 'registrations:registration-subjects' @property def subjects_self_view(self): # Overrides TaxonomizableSerializerMixin return 'registrations:registration-relationships-subjects' links = LinksField({'html': 'get_absolute_html_url'}) def get_absolute_url(self, obj): return obj.get_absolute_url() def get_registered_meta(self, obj): if obj.registered_meta: meta_values = self.anonymize_registered_meta(obj) try: return json.loads(meta_values) except TypeError: return meta_values except ValueError: return meta_values return None def get_registration_responses(self, obj): if obj.registration_responses: return self.anonymize_registration_responses(obj) return None def get_embargo_end_date(self, obj): if obj.embargo_end_date: return obj.embargo_end_date return None def get_registration_supplement(self, obj): if obj.registered_schema: schema = obj.registered_schema.first() if schema is None: return None return schema.name return None def get_current_user_permissions(self, obj): return NodeSerializer.get_current_user_permissions(self, obj) def get_view_only_links_count(self, obj): return obj.private_links.filter(is_deleted=False).count() def get_total_comments_count(self, obj): return obj.comment_set.filter(page='node', is_deleted=False).count() def get_files_count(self, obj): return obj.files_count or 0 def anonymize_registered_meta(self, obj): """ Looks at every question on every page of the schema, for any titles that have a contributor-input block type. If present, deletes that question's response from meta_values. """ cleaned_registered_meta = strip_registered_meta_comments( obj.registered_meta.values()[0]) return self.anonymize_fields(obj, cleaned_registered_meta) def anonymize_registration_responses(self, obj): """ For any questions that have a `contributor-input` block type, delete that question's response from registration_responses. We want to make sure author's names that need to be anonymized aren't surfaced when viewed through an anonymous VOL """ return self.anonymize_fields(obj, obj.registration_responses) def anonymize_fields(self, obj, data): """ Consolidates logic to anonymize fields with contributor information on both registered_meta and registration_responses """ if is_anonymized(self.context['request']): anonymous_registration_response_keys = obj.get_contributor_registration_response_keys( ) for key in anonymous_registration_response_keys: if key in data: del data[key] return data def check_admin_perms(self, registration, user, validated_data): """ While admin/write users can make both make modifications to registrations, most fields are restricted to admin-only edits. You must be an admin contributor on the registration; you cannot have gotten your admin permissions through group membership. Add fields that need admin perms to admin_only_editable_fields """ user_is_admin = registration.is_admin_contributor(user) for field in validated_data: if field in self.admin_only_editable_fields and not user_is_admin: raise exceptions.PermissionDenied() def update_registration_tags(self, registration, validated_data, auth): new_tags = validated_data.pop('tags', []) try: registration.update_tags(new_tags, auth=auth) except NodeStateError as err: raise Conflict(str(err)) def retract_registration(self, registration, validated_data, user): is_pending_retraction = validated_data.pop('is_pending_retraction', None) withdrawal_justification = validated_data.pop( 'withdrawal_justification', None) if withdrawal_justification and not is_pending_retraction: raise exceptions.ValidationError( 'You cannot provide a withdrawal_justification without a concurrent withdrawal request.', ) if is_truthy(is_pending_retraction): if registration.is_pending_retraction: raise exceptions.ValidationError( 'This registration is already pending withdrawal.') try: retraction = registration.retract_registration( user, withdrawal_justification, save=True) except NodeStateError as err: raise exceptions.ValidationError(str(err)) retraction.ask( registration.get_active_contributors_recursive( unique_users=True)) elif is_pending_retraction is not None: raise exceptions.ValidationError( 'You cannot set is_pending_withdrawal to False.') def update(self, registration, validated_data): user = self.context['request'].user auth = Auth(user) self.check_admin_perms(registration, user, validated_data) validated_data.pop('_id', None) if 'tags' in validated_data: self.update_registration_tags(registration, validated_data, auth) if 'custom_citation' in validated_data: registration.update_custom_citation( validated_data.pop('custom_citation'), auth) if 'license_type' in validated_data or 'license' in validated_data: license_details = get_license_details(registration, validated_data) validated_data['node_license'] = license_details validated_data.pop('license_type', None) validated_data.pop('license', None) if 'affiliated_institutions' in validated_data: institutions_list = validated_data.pop('affiliated_institutions') new_institutions = [{ '_id': institution } for institution in institutions_list] update_institutions(registration, new_institutions, user) registration.save() if 'subjects' in validated_data: subjects = validated_data.pop('subjects', None) self.update_subjects(registration, subjects, auth) if 'withdrawal_justification' in validated_data or 'is_pending_retraction' in validated_data: self.retract_registration(registration, validated_data, user) if 'is_public' in validated_data: if validated_data.get('is_public') is False: raise exceptions.ValidationError( 'Registrations can only be turned from private to public.') try: registration.update(validated_data, auth=auth) except ValidationError as e: raise InvalidModelValueError(detail=e.messages[0]) except NodeUpdateError as err: raise exceptions.ValidationError(err.reason) except NodeStateError as err: raise exceptions.ValidationError(str(err)) return registration class Meta: type_ = 'registrations'
class DraftRegistrationSerializer(DraftRegistrationLegacySerializer, TaxonomizableSerializerMixin): """ New DraftRegistrationSerializer - instead of the node_id being provided in the URL, an optional node is passed in under `branched_from`. DraftRegistrations have several fields that can be edited that are persisted to the final registration. """ category_choices = list(settings.NODE_CATEGORY_MAP.items()) category_choices_string = ', '.join(["'{}'".format(choice[0]) for choice in category_choices]) title = ser.CharField(required=False, allow_blank=True) description = ser.CharField(required=False, allow_blank=True, allow_null=True) category = ser.ChoiceField(required=False, choices=category_choices, help_text='Choices: ' + category_choices_string) tags = ValuesListField(attr_name='name', child=ser.CharField(), required=False) node_license = NodeLicenseSerializer(required=False, source='license') links = LinksField({ 'self': 'get_absolute_url', }) affiliated_institutions = RelationshipField( related_view='draft_registrations:draft-registration-institutions', related_view_kwargs={'draft_id': '<_id>'}, self_view='draft_registrations:draft-registration-relationships-institutions', self_view_kwargs={'draft_id': '<_id>'}, read_only=False, many=True, required=False, ) branched_from = NodeRelationshipField( related_view=lambda n: 'draft_nodes:draft-node-detail' if getattr(n, 'type', False) == 'osf.draftnode' else 'nodes:node-detail', related_view_kwargs={'node_id': '<branched_from._id>'}, read_only=False, required=False, ) contributors = RelationshipField( related_view='draft_registrations:draft-registration-contributors', related_view_kwargs={'draft_id': '<_id>'}, ) license = NodeLicenseRelationshipField( related_view='licenses:license-detail', related_view_kwargs={'license_id': '<license.node_license._id>'}, read_only=False, ) @property def subjects_related_view(self): # Overrides TaxonomizableSerializerMixin return 'draft_registrations:draft-registration-subjects' @property def subjects_view_kwargs(self): # Overrides TaxonomizableSerializerMixin return {'draft_id': '<_id>'} @property def subjects_self_view(self): # Overrides TaxonomizableSerializerMixin return 'draft_registrations:draft-registration-relationships-subjects' def get_self_url(self, obj): return absolute_reverse( 'draft_registrations:draft-registration-list', kwargs={ 'version': self.context['request'].parser_context['kwargs']['version'], }, ) def get_absolute_url(self, obj): return obj.get_absolute_url() # Overrides DraftRegistrationLegacySerializer def get_node(self, validated_data): # Node comes from branched_from relationship rather than from URL return validated_data.pop('branched_from', None) def expect_subjects_as_relationships(self, request): """Determines whether subjects should be serialized as a relationship. Older serializers expect subjects as attributes for earlier versions, but this new serializer does not have to adhere to that same behavior. :param object request: Request object :return bool: Subjects should be serialized as relationships """ # Overrides TaxonomizableSerializerMixin return True