예제 #1
0
class UserSerializer(JSONAPISerializer):
    filterable_fields = frozenset([
        'full_name',
        'given_name',
        'middle_names',
        'family_name',
        'id'
    ])
    id = IDField(source='_id', read_only=True)
    type = TypeField()
    full_name = ser.CharField(source='fullname', required=True, label='Full name', help_text='Display name used in the general user interface')
    given_name = ser.CharField(required=False, allow_blank=True, help_text='For bibliographic citations')
    middle_names = ser.CharField(required=False, allow_blank=True, help_text='For bibliographic citations')
    family_name = ser.CharField(required=False, allow_blank=True, help_text='For bibliographic citations')
    suffix = ser.CharField(required=False, allow_blank=True, help_text='For bibliographic citations')
    date_registered = ser.DateTimeField(read_only=True)

    # Social Fields are broken out to get around DRF complex object bug and to make API updating more user friendly.
    gitHub = DevOnly(ser.CharField(required=False, label='GitHub', source='social.github', allow_blank=True, help_text='GitHub Handle'))
    scholar = DevOnly(ser.CharField(required=False, source='social.scholar', allow_blank=True, help_text='Google Scholar Account'))
    personal_website = DevOnly(ser.URLField(required=False, source='social.personal', allow_blank=True, help_text='Personal Website'))
    twitter = DevOnly(ser.CharField(required=False, source='social.twitter', allow_blank=True, help_text='Twitter Handle'))
    linkedIn = DevOnly(ser.CharField(required=False, source='social.linkedIn', allow_blank=True, help_text='LinkedIn Account'))
    impactStory = DevOnly(ser.CharField(required=False, source='social.impactStory', allow_blank=True, help_text='ImpactStory Account'))
    orcid = DevOnly(ser.CharField(required=False, label='ORCID', source='social.orcid', allow_blank=True, help_text='ORCID'))
    researcherId = DevOnly(ser.CharField(required=False, label='ResearcherID', source='social.researcherId', allow_blank=True, help_text='ResearcherId Account'))
    profile_image_url = DevOnly(ser.SerializerMethodField(required=False, read_only=True))

    def get_profile_image_url(self, user):
        size = self.context['request'].query_params.get('profile_image_size')
        return user.profile_image_url(size=size)

    links = LinksField({'html': 'absolute_url'})
    nodes = JSONAPIHyperlinkedIdentityField(view_name='users:user-nodes', lookup_field='pk', lookup_url_kwarg='user_id',
                                             link_type='related')

    class Meta:
        type_ = 'users'

    def absolute_url(self, obj):
        return obj.absolute_url

    def update(self, instance, validated_data):
        assert isinstance(instance, User), 'instance must be a User'
        for attr, value in validated_data.items():
            if 'social' == attr:
                for key, val in value.items():
                    instance.social[key] = val
            else:
                setattr(instance, attr, value)
        instance.save()
        return instance
예제 #2
0
class NodeSerializer(JSONAPISerializer):
    # TODO: If we have to redo this implementation in any of the other serializers, subclass ChoiceField and make it
    # handle blank choices properly. Currently DRF ChoiceFields ignore blank options, which is incorrect in this
    # instance
    filterable_fields = frozenset([
        'title',
        'description',
        'public',
        'tags',
        'category',
        'date_created',
        'date_modified',
        'registration'
    ])

    id = IDField(source='_id', read_only=True)
    type = TypeField()

    category_choices = Node.CATEGORY_MAP.keys()
    category_choices_string = ', '.join(["'{}'".format(choice) for choice in category_choices])

    title = ser.CharField(required=True)
    description = ser.CharField(required=False, allow_blank=True, allow_null=True)
    category = ser.ChoiceField(choices=category_choices, help_text="Choices: " + category_choices_string)
    date_created = ser.DateTimeField(read_only=True)
    date_modified = ser.DateTimeField(read_only=True)
    registration = ser.BooleanField(read_only=True, source='is_registration')
    fork = ser.BooleanField(read_only=True, source='is_fork')
    collection = DevOnly(ser.BooleanField(read_only=True, source='is_folder'))
    dashboard = ser.BooleanField(read_only=True, source='is_dashboard')
    tags = JSONAPIListField(child=NodeTagField(), required=False)

    # Public is only write-able by admins--see update method
    public = 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')

    links = LinksField({'html': 'get_absolute_url'})
    # TODO: When we have osf_permissions.ADMIN permissions, make this writable for admins

    children = RelationshipField(
        related_view='nodes:node-children',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'count': 'get_node_count'},
    )

    comments = RelationshipField(
        related_view='nodes:node-comments',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'unread': 'get_unread_comments_count'})

    contributors = RelationshipField(
        related_view='nodes:node-contributors',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'count': 'get_contrib_count'},
    )

    files = RelationshipField(
        related_view='nodes:node-providers',
        related_view_kwargs={'node_id': '<pk>'}
    )

    forked_from = RelationshipField(
        related_view='nodes:node-detail',
        related_view_kwargs={'node_id': '<forked_from_id>'}
    )

    node_links = DevOnly(RelationshipField(
        related_view='nodes:node-pointers',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'count': 'get_pointers_count'},
    ))

    parent = RelationshipField(
        related_view='nodes:node-detail',
        related_view_kwargs={'node_id': '<parent_id>'}
    )

    registrations = DevOnly(HideIfRegistration(RelationshipField(
        related_view='nodes:node-registrations',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'count': 'get_registration_count'}
    )))

    logs = RelationshipField(
        related_view='nodes:node-logs',
        related_view_kwargs={'node_id': '<pk>'},
    )

    class Meta:
        type_ = 'nodes'

    def get_absolute_url(self, obj):
        return obj.absolute_url

    # TODO: See if we can get the count filters into the filter rather than the serializer.

    def get_user_auth(self, request):
        user = request.user
        if user.is_anonymous():
            auth = Auth(None)
        else:
            auth = Auth(user)
        return auth

    def get_node_count(self, obj):
        auth = self.get_user_auth(self.context['request'])
        nodes = [node for node in obj.nodes if node.can_view(auth) and node.primary and not node.is_deleted]
        return len(nodes)

    def get_contrib_count(self, obj):
        return len(obj.contributors)

    def get_registration_count(self, obj):
        auth = self.get_user_auth(self.context['request'])
        registrations = [node for node in obj.node__registrations if node.can_view(auth)]
        return len(registrations)

    def get_pointers_count(self, obj):
        return len(obj.nodes_pointer)

    def get_unread_comments_count(self, obj):
        auth = self.get_user_auth(self.context['request'])
        user = auth.user
        return Comment.find_unread(user=user, node=obj)

    def create(self, validated_data):
        node = Node(**validated_data)
        try:
            node.save()
        except ValidationValueError as e:
            raise InvalidModelValueError(detail=e.message)
        return node

    def update(self, node, validated_data):
        """Update instance with the validated data. Requires
        the request to be in the serializer context.
        """
        assert isinstance(node, Node), 'node must be a Node'
        auth = self.get_user_auth(self.context['request'])
        old_tags = set([tag._id for tag in node.tags])
        if 'tags' in validated_data:
            current_tags = set(validated_data.get('tags'))
            del validated_data['tags']
        elif self.partial:
            current_tags = set(old_tags)
        else:
            current_tags = set()

        for new_tag in (current_tags - old_tags):
            node.add_tag(new_tag, auth=auth)
        for deleted_tag in (old_tags - current_tags):
            node.remove_tag(deleted_tag, auth=auth)

        if validated_data:
            try:
                node.update(validated_data, auth=auth)
            except ValidationValueError as e:
                raise InvalidModelValueError(detail=e.message)
            except PermissionsError:
                raise exceptions.PermissionDenied

        return node
예제 #3
0
class CollectionSerializer(JSONAPISerializer):
    filterable_fields = frozenset([
        'title',
        'date_created',
        'date_modified',
    ])

    id = IDField(source='_id', read_only=True)
    type = TypeField()

    title = ser.CharField(required=True)
    date_created = ser.DateTimeField(read_only=True)
    date_modified = ser.DateTimeField(read_only=True)

    links = LinksField({})

    node_links = DevOnly(RelationshipField(
        related_view='collections:node-pointers',
        related_view_kwargs={'collection_id': '<pk>'},
        related_meta={'count': 'get_node_links_count'}
    ))

    # TODO: Add a self link to this when it's available
    linked_nodes = DevOnly(RelationshipField(
        related_view='collections:linked-nodes',
        related_view_kwargs={'collection_id': '<pk>'},
        related_meta={'count': 'get_node_links_count'}
    ))

    class Meta:
        type_ = 'collections'

    def get_absolute_url(self, obj):
        return obj.absolute_url

    def get_node_links_count(self, obj):
        return len(obj.nodes_pointer)

    def create(self, validated_data):
        node = Node(**validated_data)
        node.is_folder = True
        node.category = ''
        try:
            node.save()
        except ValidationValueError as e:
            raise InvalidModelValueError(detail=e.message)
        return node

    def update(self, node, validated_data):
        """Update instance with the validated data. Requires
        the request to be in the serializer context.
        """
        assert isinstance(node, Node), 'collection must be a Node'
        auth = get_user_auth(self.context['request'])

        if validated_data:
            try:
                node.update(validated_data, auth=auth)
            except ValidationValueError as e:
                raise InvalidModelValueError(detail=e.message)
            except PermissionsError:
                raise exceptions.PermissionDenied

        return node
예제 #4
0
class NodeSerializer(JSONAPISerializer):
    # TODO: If we have to redo this implementation in any of the other serializers, subclass ChoiceField and make it
    # handle blank choices properly. Currently DRF ChoiceFields ignore blank options, which is incorrect in this
    # instance
    filterable_fields = frozenset([
        'id',
        'title',
        'description',
        'public',
        'tags',
        'category',
        'date_created',
        'date_modified',
        'root',
        'parent',
        'contributors'
    ])

    non_anonymized_fields = [
        'id',
        'title',
        'description',
        'category',
        'date_created',
        'date_modified',
        'registration',
        'tags',
        'public',
        'links',
        'children',
        'comments',
        'contributors',
        'files',
        'node_links',
        'parent',
        'root',
        'logs',
    ]

    id = IDField(source='_id', read_only=True)
    type = TypeField()

    category_choices = Node.CATEGORY_MAP.items()
    category_choices_string = ', '.join(["'{}'".format(choice[0]) for choice in category_choices])

    title = ser.CharField(required=True)
    description = ser.CharField(required=False, allow_blank=True, allow_null=True)
    category = ser.ChoiceField(choices=category_choices, help_text="Choices: " + category_choices_string)
    date_created = ser.DateTimeField(read_only=True)
    date_modified = ser.DateTimeField(read_only=True)
    registration = ser.BooleanField(read_only=True, source='is_registration')
    fork = ser.BooleanField(read_only=True, source='is_fork')
    collection = ser.BooleanField(read_only=True, source='is_collection')
    tags = JSONAPIListField(child=NodeTagField(), required=False)
    template_from = ser.CharField(required=False, 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.')
    current_user_permissions = ser.SerializerMethodField(help_text='List of strings representing the permissions '
                                                                   'for the current user on this node.')

    # Public is only write-able by admins--see update method
    public = 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')

    links = LinksField({'html': 'get_absolute_html_url'})
    # TODO: When we have osf_permissions.ADMIN permissions, make this writable for admins

    children = RelationshipField(
        related_view='nodes:node-children',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'count': 'get_node_count'},
    )

    comments = RelationshipField(
        related_view='nodes:node-comments',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'unread': 'get_unread_comments_count'})

    contributors = RelationshipField(
        related_view='nodes:node-contributors',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'count': 'get_contrib_count'},
    )

    files = RelationshipField(
        related_view='nodes:node-providers',
        related_view_kwargs={'node_id': '<pk>'}
    )

    forked_from = RelationshipField(
        related_view='nodes:node-detail',
        related_view_kwargs={'node_id': '<forked_from_id>'}
    )

    node_links = RelationshipField(
        related_view='nodes:node-pointers',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'count': 'get_pointers_count'},
    )

    parent = RelationshipField(
        related_view='nodes:node-detail',
        related_view_kwargs={'node_id': '<parent_node._id>'},
        filter_key='parent_node'
    )

    registrations = DevOnly(HideIfRegistration(RelationshipField(
        related_view='nodes:node-registrations',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'count': 'get_registration_count'}
    )))

    primary_institution = RelationshipField(
        related_view='nodes:node-institution-detail',
        related_view_kwargs={'node_id': '<pk>'},
        self_view='nodes:node-relationships-institution',
        self_view_kwargs={'node_id': '<pk>'}
    )

    root = RelationshipField(
        related_view='nodes:node-detail',
        related_view_kwargs={'node_id': '<root._id>'}
    )

    logs = RelationshipField(
        related_view='nodes:node-logs',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'count': 'get_logs_count'}
    )

    def get_current_user_permissions(self, obj):
        user = self.context['request'].user
        if user.is_anonymous():
            return ['read']
        permissions = obj.get_permissions(user=user)
        if not permissions:
            permissions = ['read']
        return permissions

    class Meta:
        type_ = 'nodes'

    def get_absolute_url(self, obj):
        return obj.get_absolute_url()

    # TODO: See if we can get the count filters into the filter rather than the serializer.

    def get_logs_count(self, obj):
        return len(obj.logs)

    def get_node_count(self, obj):
        auth = get_user_auth(self.context['request'])
        nodes = [node for node in obj.nodes if node.can_view(auth) and node.primary and not node.is_deleted]
        return len(nodes)

    def get_contrib_count(self, obj):
        return len(obj.contributors)

    def get_registration_count(self, obj):
        auth = get_user_auth(self.context['request'])
        registrations = [node for node in obj.registrations_all if node.can_view(auth)]
        return len(registrations)

    def get_pointers_count(self, obj):
        return len(obj.nodes_pointer)

    def get_unread_comments_count(self, obj):
        user = get_user_auth(self.context['request']).user
        node_comments = Comment.find_n_unread(user=user, node=obj, page='node')

        return {
            'node': node_comments
        }

    def create(self, validated_data):
        if 'template_from' in validated_data:
            request = self.context['request']
            user = request.user
            template_from = validated_data.pop('template_from')
            template_node = Node.load(key=template_from)
            if template_node is None:
                raise exceptions.NotFound
            if not template_node.has_permission(user, 'read', check_parent=False):
                raise exceptions.PermissionDenied

            validated_data.pop('creator')
            changed_data = {template_from: validated_data}
            node = template_node.use_as_template(auth=get_user_auth(request), changes=changed_data)
        else:
            node = Node(**validated_data)
        try:
            node.save()
        except ValidationValueError as e:
            raise InvalidModelValueError(detail=e.message)
        return node

    def update(self, node, validated_data):
        """Update instance with the validated data. Requires
        the request to be in the serializer context.
        """
        assert isinstance(node, Node), 'node must be a Node'
        auth = get_user_auth(self.context['request'])
        old_tags = set([tag._id for tag in node.tags])
        if 'tags' in validated_data:
            current_tags = set(validated_data.get('tags'))
            del validated_data['tags']
        elif self.partial:
            current_tags = set(old_tags)
        else:
            current_tags = set()

        for new_tag in (current_tags - old_tags):
            node.add_tag(new_tag, auth=auth)
        for deleted_tag in (old_tags - current_tags):
            node.remove_tag(deleted_tag, auth=auth)

        if validated_data:
            try:
                node.update(validated_data, auth=auth)
            except ValidationValueError as e:
                raise InvalidModelValueError(detail=e.message)
            except PermissionsError:
                raise exceptions.PermissionDenied
            except NodeUpdateError as e:
                raise exceptions.ValidationError(detail=e.reason)

        return node
예제 #5
0
class RegistrationSerializer(NodeSerializer):

    pending_embargo_approval = HideIfRetraction(
        ser.BooleanField(
            read_only=True,
            source='is_pending_embargo',
            help_text=
            'The associated Embargo is awaiting approval by project admins.'))
    pending_registration_approval = HideIfRetraction(
        ser.BooleanField(
            source='is_pending_registration',
            read_only=True,
            help_text=
            'The associated RegistrationApproval is awaiting approval by project admins.'
        ))
    pending_retraction = HideIfRetraction(
        ser.BooleanField(
            source='is_pending_retraction',
            read_only=True,
            help_text=
            'The registration is awaiting retraction approval by project admins.'
        ))
    retracted = ser.BooleanField(
        source='is_retracted',
        read_only=True,
        help_text='The registration has been retracted.')

    date_registered = ser.DateTimeField(source='registered_date',
                                        read_only=True,
                                        help_text='Date time of registration.')
    embargo_end_date = HideIfRetraction(
        ser.SerializerMethodField(
            help_text='When the embargo on this registration will be lifted.'))

    retraction_justification = ser.CharField(source='retraction.justification',
                                             read_only=True)
    registration_supplement = ser.SerializerMethodField()
    registered_meta = HideIfRetraction(
        ser.SerializerMethodField(
            help_text=
            'A dictionary with supplemental registration questions and responses.'
        ))

    registered_by = HideIfRetraction(
        RelationshipField(
            related_view='users:user-detail',
            related_view_kwargs={'user_id': '<registered_user_id>'}))

    registered_from = HideIfRetraction(
        RelationshipField(
            related_view='nodes:node-detail',
            related_view_kwargs={'node_id': '<registered_from_id>'}))

    children = HideIfRetraction(
        RelationshipField(
            related_view='registrations:registration-children',
            related_view_kwargs={'node_id': '<pk>'},
            related_meta={'count': 'get_node_count'},
        ))

    comments = HideIfRetraction(
        RelationshipField(related_view='registrations:registration-comments',
                          related_view_kwargs={'node_id': '<pk>'},
                          related_meta={'unread':
                                        'get_unread_comments_count'}))

    contributors = RelationshipField(
        related_view='registrations:registration-contributors',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'count': 'get_contrib_count'})

    files = HideIfRetraction(
        RelationshipField(related_view='registrations:registration-providers',
                          related_view_kwargs={'node_id': '<pk>'}))

    forked_from = HideIfRetraction(
        RelationshipField(related_view='nodes:node-detail',
                          related_view_kwargs={'node_id': '<forked_from_id>'}))

    node_links = DevOnly(
        HideIfRetraction(
            RelationshipField(
                related_view='registrations:registration-pointers',
                related_view_kwargs={'node_id': '<pk>'},
                related_meta={'count': 'get_pointers_count'})))

    parent = HideIfRetraction(
        RelationshipField(related_view='registrations:registration-detail',
                          related_view_kwargs={'node_id': '<parent_id>'}))

    logs = HideIfRetraction(
        RelationshipField(
            related_view='registrations:registration-logs',
            related_view_kwargs={'node_id': '<pk>'},
        ))

    root = HideIfRetraction(
        RelationshipField(related_view='registrations:registration-detail',
                          related_view_kwargs={'node_id': '<root._id>'}))

    primary_institution = RelationshipField(
        related_view='registrations:registration-institution-detail',
        related_view_kwargs={'node_id': '<pk>'})

    # TODO: Finish me

    # TODO: Override create?

    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})

    def get_absolute_url(self, obj):
        return self.get_registration_url(obj)

    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[0]
            if schema is None:
                return None
            return schema.name
        return None

    def update(self, *args, **kwargs):
        raise exceptions.APIException('Registrations cannot be modified.')

    class Meta:
        type_ = 'registrations'
예제 #6
0
class UserSerializer(JSONAPISerializer):
    filterable_fields = frozenset(
        ['full_name', 'given_name', 'middle_names', 'family_name', 'id'])
    non_anonymized_fields = ['type']
    id = IDField(source='_id', read_only=True)
    type = TypeField()
    full_name = ser.CharField(
        source='fullname',
        required=True,
        label='Full name',
        help_text='Display name used in the general user interface')
    given_name = ser.CharField(required=False,
                               allow_blank=True,
                               help_text='For bibliographic citations')
    middle_names = ser.CharField(required=False,
                                 allow_blank=True,
                                 help_text='For bibliographic citations')
    family_name = ser.CharField(required=False,
                                allow_blank=True,
                                help_text='For bibliographic citations')
    suffix = ser.CharField(required=False,
                           allow_blank=True,
                           help_text='For bibliographic citations')
    date_registered = ser.DateTimeField(read_only=True)

    # Social Fields are broken out to get around DRF complex object bug and to make API updating more user friendly.
    gitHub = DevOnly(
        AllowMissing(ser.CharField(required=False,
                                   source='social.github',
                                   allow_blank=True,
                                   help_text='GitHub Handle'),
                     required=False,
                     source='social.github'))
    scholar = DevOnly(
        AllowMissing(ser.CharField(required=False,
                                   source='social.scholar',
                                   allow_blank=True,
                                   help_text='Google Scholar Account'),
                     required=False,
                     source='social.scholar'))
    personal_website = DevOnly(
        AllowMissing(ser.URLField(required=False,
                                  source='social.personal',
                                  allow_blank=True,
                                  help_text='Personal Website'),
                     required=False,
                     source='social.personal'))
    twitter = DevOnly(
        AllowMissing(ser.CharField(required=False,
                                   source='social.twitter',
                                   allow_blank=True,
                                   help_text='Twitter Handle'),
                     required=False,
                     source='social.twitter'))
    linkedIn = DevOnly(
        AllowMissing(ser.CharField(required=False,
                                   source='social.linkedIn',
                                   allow_blank=True,
                                   help_text='LinkedIn Account'),
                     required=False,
                     source='social.linkedIn'))
    impactStory = DevOnly(
        AllowMissing(ser.CharField(required=False,
                                   source='social.impactStory',
                                   allow_blank=True,
                                   help_text='ImpactStory Account'),
                     required=False,
                     source='social.impactStory'))
    orcid = DevOnly(
        AllowMissing(ser.CharField(required=False,
                                   source='social.orcid',
                                   allow_blank=True,
                                   help_text='ORCID'),
                     required=False,
                     source='social.orcid'))
    researcherId = DevOnly(
        AllowMissing(ser.CharField(required=False,
                                   source='social.researcherId',
                                   allow_blank=True,
                                   help_text='ResearcherId Account'),
                     required=False,
                     source='social.researcherId'))
    researchGate = DevOnly(
        AllowMissing(ser.CharField(required=False,
                                   source='social.researchGate',
                                   allow_blank=True,
                                   help_text='ResearchGate Account'),
                     required=False,
                     source='social.researchGate'))
    academiaInstitution = DevOnly(
        AllowMissing(ser.CharField(required=False,
                                   source='social.academiaInstitution',
                                   allow_blank=True,
                                   help_text='AcademiaInstitution Field'),
                     required=False,
                     source='social.academiaInstitution'))
    academiaProfileID = DevOnly(
        AllowMissing(ser.CharField(required=False,
                                   source='social.academiaProfileID',
                                   allow_blank=True,
                                   help_text='AcademiaProfileID Field'),
                     required=False,
                     source='social.academiaProfileID'))
    baiduScholar = DevOnly(
        AllowMissing(ser.CharField(required=False,
                                   source='social.baiduScholar',
                                   allow_blank=True,
                                   help_text='Baidu Scholar Account'),
                     required=False,
                     source='social.baiduScholar'))
    links = LinksField({
        'html': 'absolute_url',
        'profile_image': 'profile_image_url',
    })

    nodes = RelationshipField(
        related_view='users:user-nodes',
        related_view_kwargs={'user_id': '<pk>'},
    )

    institutions = RelationshipField(
        related_view='users:user-institutions',
        related_view_kwargs={'user_id': '<pk>'},
        self_view='users:user-institutions-relationship',
        self_view_kwargs={'user_id': '<pk>'},
    )

    class Meta:
        type_ = 'users'

    def absolute_url(self, obj):
        if obj is not None:
            return obj.absolute_url
        return None

    def get_absolute_url(self, obj):
        return absolute_reverse('users:user-detail',
                                kwargs={'user_id': obj._id})

    def profile_image_url(self, user):
        size = self.context['request'].query_params.get('profile_image_size')
        return user.profile_image_url(size=size)

    def update(self, instance, validated_data):
        assert isinstance(instance, User), 'instance must be a User'
        for attr, value in validated_data.items():
            if 'social' == attr:
                for key, val in value.items():
                    instance.social[key] = val
            else:
                setattr(instance, attr, value)
        try:
            instance.save()
        except ValidationValueError as e:
            raise InvalidModelValueError(detail=e.message)
        return instance
예제 #7
0
class UserSerializer(JSONAPISerializer):
    filterable_fields = frozenset(
        ['full_name', 'given_name', 'middle_names', 'family_name', 'id'])
    non_anonymized_fields = ['type']
    id = IDField(source='_id', read_only=True)
    type = TypeField()
    full_name = ser.CharField(
        source='fullname',
        required=True,
        label='Full name',
        help_text='Display name used in the general user interface')
    given_name = ser.CharField(required=False,
                               allow_blank=True,
                               help_text='For bibliographic citations')
    middle_names = ser.CharField(required=False,
                                 allow_blank=True,
                                 help_text='For bibliographic citations')
    family_name = ser.CharField(required=False,
                                allow_blank=True,
                                help_text='For bibliographic citations')
    suffix = HideIfDisabled(
        ser.CharField(required=False,
                      allow_blank=True,
                      help_text='For bibliographic citations'))
    date_registered = HideIfDisabled(DateByVersion(read_only=True))
    active = HideIfDisabled(
        ser.BooleanField(read_only=True, source='is_active'))
    timezone = HideIfDisabled(
        ser.CharField(required=False,
                      help_text="User's timezone, e.g. 'Etc/UTC"))
    locale = HideIfDisabled(
        ser.CharField(required=False,
                      help_text="User's locale, e.g.  'en_US'"))
    social = ListDictField(required=False)
    can_view_reviews = ShowIfCurrentUser(
        ser.SerializerMethodField(
            help_text=
            'Whether the current user has the `view_submissions` permission to ANY reviews provider.'
        ))

    links = HideIfDisabled(
        LinksField({
            'html': 'absolute_url',
            'profile_image': 'profile_image_url',
        }))

    nodes = HideIfDisabled(
        RelationshipField(
            related_view='users:user-nodes',
            related_view_kwargs={'user_id': '<_id>'},
            related_meta={'projects_in_common': 'get_projects_in_common'},
        ))

    quickfiles = HideIfDisabled(
        QuickFilesRelationshipField(
            related_view='users:user-quickfiles',
            related_view_kwargs={'user_id': '<_id>'},
        ))

    registrations = DevOnly(
        HideIfDisabled(
            RelationshipField(
                related_view='users:user-registrations',
                related_view_kwargs={'user_id': '<_id>'},
            )))

    institutions = HideIfDisabled(
        RelationshipField(
            related_view='users:user-institutions',
            related_view_kwargs={'user_id': '<_id>'},
            self_view='users:user-institutions-relationship',
            self_view_kwargs={'user_id': '<_id>'},
        ))

    actions = ShowIfCurrentUser(
        RelationshipField(
            related_view='users:user-action-list',
            related_view_kwargs={'user_id': '<_id>'},
        ))

    class Meta:
        type_ = 'users'

    def get_projects_in_common(self, obj):
        user = get_user_auth(self.context['request']).user
        if obj == user:
            return user.contributor_to.count()
        return obj.n_projects_in_common(user)

    def absolute_url(self, obj):
        if obj is not None:
            return obj.absolute_url
        return None

    def get_absolute_url(self, obj):
        return absolute_reverse(
            'users:user-detail',
            kwargs={
                'user_id':
                obj._id,
                'version':
                self.context['request'].parser_context['kwargs']['version']
            })

    def get_can_view_reviews(self, obj):
        group_qs = GroupObjectPermission.objects.filter(
            group__user=obj, permission__codename='view_submissions')
        return group_qs.exists() or obj.userobjectpermission_set.filter(
            permission__codename='view_submissions')

    def profile_image_url(self, user):
        size = self.context['request'].query_params.get('profile_image_size')
        return user.profile_image_url(size=size)

    def update(self, instance, validated_data):
        assert isinstance(instance, OSFUser), 'instance must be a User'
        for attr, value in validated_data.items():
            if 'social' == attr:
                for key, val in value.items():
                    # currently only profileWebsites are a list, the rest of the social key only has one value
                    if key == 'profileWebsites':
                        instance.social[key] = val
                    else:
                        if len(val) > 1:
                            raise InvalidModelValueError(
                                detail=
                                '{} only accept a list of one single value'.
                                format(key))
                        instance.social[key] = val[0]
            else:
                setattr(instance, attr, value)
        try:
            instance.save()
        except ValidationValueError as e:
            raise InvalidModelValueError(detail=e.message)
        except ValidationError as e:
            raise InvalidModelValueError(e)

        return instance
예제 #8
0
class RegistrationSerializer(NodeSerializer):

    retracted = ser.BooleanField(
        source='is_retracted',
        read_only=True,
        help_text='Whether this registration has been retracted.')
    date_registered = ser.DateTimeField(source='registered_date',
                                        read_only=True,
                                        help_text='Date time of registration.')
    retraction_justification = ser.CharField(source='retraction.justification',
                                             read_only=True)
    pending_retraction = HideIfRetraction(
        ser.BooleanField(source='is_pending_retraction',
                         read_only=True,
                         help_text='Is this registration pending retraction?'))
    pending_registration_approval = HideIfRetraction(
        ser.BooleanField(
            source='sanction.pending_approval',
            read_only=True,
            help_text='Does this registration have a sanction pending approval?'
        ))
    pending_embargo = HideIfRetraction(
        ser.BooleanField(read_only=True,
                         source='is_pending_embargo',
                         help_text='Is this registration pending embargo?'))
    registered_meta = HideIfRetraction(
        ser.SerializerMethodField(
            help_text=
            'A dictionary with embargo end date, whether registration choice was immediate or embargoed,'
            ' and answers to supplemental registration questions'))
    registration_supplement = ser.SerializerMethodField()

    registered_by = HideIfRetraction(
        RelationshipField(
            related_view='users:user-detail',
            related_view_kwargs={'user_id': '<registered_user_id>'}))

    registered_from = HideIfRetraction(
        RelationshipField(
            related_view='nodes:node-detail',
            related_view_kwargs={'node_id': '<registered_from_id>'}))

    children = HideIfRetraction(
        RelationshipField(
            related_view='registrations:registration-children',
            related_view_kwargs={'node_id': '<pk>'},
            related_meta={'count': 'get_node_count'},
        ))

    comments = HideIfRetraction(
        RelationshipField(related_view='registrations:registration-comments',
                          related_view_kwargs={'node_id': '<pk>'},
                          related_meta={'unread':
                                        'get_unread_comments_count'}))

    contributors = RelationshipField(
        related_view='registrations:registration-contributors',
        related_view_kwargs={'node_id': '<pk>'},
        related_meta={'count': 'get_contrib_count'})

    files = HideIfRetraction(
        RelationshipField(related_view='registrations:registration-providers',
                          related_view_kwargs={'node_id': '<pk>'}))

    forked_from = HideIfRetraction(
        RelationshipField(related_view='nodes:node-detail',
                          related_view_kwargs={'node_id': '<forked_from_id>'}))

    node_links = DevOnly(
        HideIfRetraction(
            RelationshipField(
                related_view='registrations:registration-pointers',
                related_view_kwargs={'node_id': '<pk>'},
                related_meta={'count': 'get_pointers_count'})))

    parent = HideIfRetraction(
        RelationshipField(related_view='nodes:node-detail',
                          related_view_kwargs={'node_id': '<parent_id>'}))

    logs = HideIfRetraction(
        RelationshipField(
            related_view='nodes:node-logs',
            related_view_kwargs={'node_id': '<pk>'},
        ))

    # TODO: Finish me

    # TODO: Override create?

    links = LinksField({
        'self': 'get_registration_url',
        'html': 'get_absolute_url'
    })

    def get_registration_url(self, obj):
        return absolute_reverse('registrations:registration-detail',
                                kwargs={'node_id': obj._id})

    def get_absolute_url(self, obj):
        return obj.absolute_url

    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_registration_supplement(self, obj):
        if obj.registered_schema:
            schema = obj.registered_schema[0]
            if schema is None:
                return None
            return schema.name
        return None

    def update(self, *args, **kwargs):
        raise exceptions.APIException('Registrations cannot be modified.')

    class Meta:
        type_ = 'registrations'