Ejemplo n.º 1
0
def test_reduce_permissions():
    result = permissions.reduce_permissions(['read', 'write', 'admin'])
    assert_equal(result, 'admin')

    result2 = permissions.reduce_permissions(['read', 'write'])
    assert_equal(result2, 'write')

    result3 = permissions.reduce_permissions(['read'])
    assert_equal(result3, 'read')
Ejemplo n.º 2
0
def test_reduce_permissions():
    result = permissions.reduce_permissions(['read', 'write', 'admin'])
    assert_equal(result, 'admin')

    result2 = permissions.reduce_permissions(['read', 'write'])
    assert_equal(result2, 'write')

    result3 = permissions.reduce_permissions(['read'])
    assert_equal(result3, 'read')
Ejemplo n.º 3
0
    def create(self, validated_data):
        auth = Auth(self.context['request'].user)
        node = self.context['view'].get_node()
        contributor = get_object_or_error(User,
                                          validated_data['_id'],
                                          display_name='user')
        # Node object checks for contributor existence but can still change permissions anyway
        if contributor in node.contributors:
            raise exceptions.ValidationError(
                '{} is already a contributor'.format(contributor.fullname))

        bibliographic = validated_data['bibliographic']
        permissions = osf_permissions.expand_permissions(
            validated_data.get('permission')
        ) or osf_permissions.DEFAULT_CONTRIBUTOR_PERMISSIONS
        node.add_contributor(contributor=contributor,
                             auth=auth,
                             visible=bibliographic,
                             permissions=permissions,
                             save=True)
        contributor.permission = osf_permissions.reduce_permissions(
            node.get_permissions(contributor))
        contributor.bibliographic = node.get_visible(contributor)
        contributor.node_id = node._id
        return contributor
Ejemplo n.º 4
0
    def update(self, instance, validated_data):
        index = None
        if 'index' in validated_data:
            index = validated_data.pop('index')

        contributor = instance
        auth = Auth(self.context['request'].user)
        node = self.context['view'].get_node()

        if 'bibliographic' in validated_data:
            bibliographic = validated_data.get('bibliographic')
        else:
            bibliographic = node.get_visible(contributor)
        permission = validated_data.get('permission') or contributor.permission
        try:
            if index is not None:
                node.move_contributor(contributor, auth, index, save=True)
            node.update_contributor(contributor, permission, bibliographic, auth, save=True)
        except NodeStateError as e:
            raise exceptions.ValidationError(detail=e.message)
        except ValueError as e:
            raise exceptions.ValidationError(detail=e.message)
        contributor.permission = osf_permissions.reduce_permissions(node.get_permissions(contributor))
        contributor.bibliographic = node.get_visible(contributor)
        contributor.node_id = node._id
        if index is not None:
            contributor.index = index
        return contributor
Ejemplo n.º 5
0
def _render_node(node, auth=None):
    """

    :param node:
    :return:

    """
    perm = None
    # NOTE: auth.user may be None if viewing public project while not
    # logged in
    if auth and auth.user and node.get_permissions(auth.user):
        perm_list = node.get_permissions(auth.user)
        perm = permissions.reduce_permissions(perm_list)

    return {
        "title": node.title,
        "id": node._primary_key,
        "url": node.url,
        "api_url": node.api_url,
        "primary": node.primary,
        "date_modified": utils.iso8601format(node.date_modified),
        "category": node.category,
        "permissions": perm,  # A string, e.g. 'admin', or None,
        "archiving": node.archiving,
    }
Ejemplo n.º 6
0
    def update(self, instance, validated_data):
        index = None
        if 'index' in validated_data:
            index = validated_data.pop('index')

        contributor = instance
        auth = Auth(self.context['request'].user)
        node = self.context['view'].get_node()

        if 'bibliographic' in validated_data:
            bibliographic = validated_data.get('bibliographic')
        else:
            bibliographic = node.get_visible(contributor)
        permission = validated_data.get('permission') or contributor.permission
        try:
            if index is not None:
                node.move_contributor(contributor, auth, index, save=True)
            node.update_contributor(contributor,
                                    permission,
                                    bibliographic,
                                    auth,
                                    save=True)
        except NodeStateError as e:
            raise exceptions.ValidationError(detail=e.message)
        except ValueError as e:
            raise exceptions.ValidationError(detail=e.message)
        contributor.permission = osf_permissions.reduce_permissions(
            node.get_permissions(contributor))
        contributor.bibliographic = node.get_visible(contributor)
        contributor.node_id = node._id
        if index is not None:
            contributor.index = index
        return contributor
Ejemplo n.º 7
0
def serialize_simple_user(user_info):
    user = User.load(user_info[0])
    return {
        'id': user._id,
        'name': user.fullname,
        'permission': reduce_permissions(user_info[1]) if user_info[1] else None,
    }
Ejemplo n.º 8
0
def _render_node(node, auth=None):
    """

    :param node:
    :return:

    """
    perm = None
    # NOTE: auth.user may be None if viewing public project while not
    # logged in
    if auth and auth.user and node.get_permissions(auth.user):
        perm_list = node.get_permissions(auth.user)
        perm = permissions.reduce_permissions(perm_list)

    return {
        'title': node.title,
        'id': node._primary_key,
        'url': node.url,
        'api_url': node.api_url,
        'primary': node.primary,
        'date_modified': utils.iso8601format(node.date_modified),
        'category': node.category,
        'permissions': perm,  # A string, e.g. 'admin', or None,
        'archiving': node.archiving,
    }
Ejemplo n.º 9
0
def _render_node(node, auth=None):
    """

    :param node:
    :return:

    """
    perm = None
    # NOTE: auth.user may be None if viewing public project while not
    # logged in
    if auth and auth.user and node.get_permissions(auth.user):
        perm_list = node.get_permissions(auth.user)
        perm = permissions.reduce_permissions(perm_list)

    return {
        'title': node.title,
        'id': node._primary_key,
        'url': node.url,
        'api_url': node.api_url,
        'primary': node.primary,
        'date_modified': utils.iso8601format(node.date_modified),
        'category': node.category,
        'permissions': perm,  # A string, e.g. 'admin', or None,
        'archiving': node.archiving,
    }
Ejemplo n.º 10
0
def serialize_simple_user(user_info):
    user = User.load(user_info[0])
    return {
        'id': user._id,
        'name': user.fullname,
        'permission':
        reduce_permissions(user_info[1]) if user_info[1] else None,
    }
Ejemplo n.º 11
0
def serialize_user(user, node=None, full=False):
    """Return a dictionary representation of a registered user.

    :param User user: A User object
    :param bool full: Include complete user properties

    """
    fullname = user.display_full_name(node=node)
    rv = {
        'id': str(user._primary_key),
        'registered': user.is_registered,
        'surname': user.family_name,
        'fullname': fullname,
        'shortname': fullname if len(fullname) < 50 else fullname[:23] + "..." + fullname[-23:],
        'gravatar_url': gravatar(
            user, use_ssl=True,
            size=settings.GRAVATAR_SIZE_ADD_CONTRIBUTOR
        ),
        'active': user.is_active(),
    }
    if node is not None:
        rv.update({
            'visible': user._id in node.visible_contributor_ids,
            'permission': reduce_permissions(node.get_permissions(user)),
        })
    if user.is_registered:
        rv.update({
            'url': user.url,
            'absolute_url': user.absolute_url,
            'display_absolute_url': user.display_absolute_url,
            'date_registered': user.date_registered.strftime("%Y-%m-%d"),
        })

    if full:
        if user.is_merged:
            merger = user.merged_by
            merged_by = {
                'id': str(merger._primary_key),
                'url': merger.url,
                'absolute_url': merger.absolute_url
            }
        else:
            merged_by = None
        rv.update({
            'number_projects': len(get_projects(user)),
            'number_public_projects': len(get_public_projects(user)),
            'activity_points': user.get_activity_points(),
            'gravatar_url': gravatar(
                user, use_ssl=True,
                size=settings.GRAVATAR_SIZE_PROFILE
            ),
            'is_merged': user.is_merged,
            'merged_by': merged_by,
        })

    return rv
Ejemplo n.º 12
0
class NodeContributorsSerializer(JSONAPISerializer):
    """ Separate from UserSerializer due to necessity to override almost every field as read only
    """
    non_anonymized_fields = ['bibliographic', 'permission']
    filterable_fields = frozenset(
        ['id', 'bibliographic', 'permission', 'index'])

    id = IDField(source='_id', read_only=True)
    type = TypeField()
    index = ser.IntegerField(required=False, read_only=True, source='_order')

    bibliographic = ser.BooleanField(
        help_text=
        'Whether the user will be included in citations for this node or not.',
        default=True)
    permission = ser.ChoiceField(
        choices=osf_permissions.PERMISSIONS,
        required=False,
        allow_null=True,
        default=osf_permissions.reduce_permissions(
            osf_permissions.DEFAULT_CONTRIBUTOR_PERMISSIONS),
        help_text=
        'User permission level. Must be "read", "write", or "admin". Defaults to "write".'
    )
    unregistered_contributor = ser.SerializerMethodField()

    links = LinksField({'self': 'get_absolute_url'})

    users = RelationshipField(related_view='users:user-detail',
                              related_view_kwargs={'user_id': '<user._id>'},
                              always_embed=True)

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

    class Meta:
        type_ = 'contributors'

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

    def get_unregistered_contributor(self, obj):
        unclaimed_records = obj.user.unclaimed_records.get(obj.node._id, None)
        if unclaimed_records:
            return unclaimed_records.get('name', None)
Ejemplo n.º 13
0
    def create(self, validated_data):
        auth = Auth(self.context['request'].user)
        node = self.context['view'].get_node()
        contributor = get_object_or_error(User, validated_data['_id'], display_name='user')
        # Node object checks for contributor existence but can still change permissions anyway
        if contributor in node.contributors:
            raise exceptions.ValidationError('{} is already a contributor'.format(contributor.fullname))

        bibliographic = validated_data['bibliographic']
        permissions = osf_permissions.expand_permissions(validated_data.get('permission')) or osf_permissions.DEFAULT_CONTRIBUTOR_PERMISSIONS
        node.add_contributor(contributor=contributor, auth=auth, visible=bibliographic, permissions=permissions, save=True)
        contributor.permission = osf_permissions.reduce_permissions(node.get_permissions(contributor))
        contributor.bibliographic = node.get_visible(contributor)
        contributor.node_id = node._id
        return contributor
Ejemplo n.º 14
0
    def update(self, instance, validated_data):
        contributor = instance
        auth = Auth(self.context['request'].user)
        node = self.context['view'].get_node()

        visible = validated_data.get('bibliographic')
        permission = validated_data.get('permission')
        try:
            node.update_contributor(contributor, permission, visible, auth, save=True)
        except NodeStateError as e:
            raise exceptions.ValidationError(e)
        contributor.permission = osf_permissions.reduce_permissions(node.get_permissions(contributor))
        contributor.bibliographic = node.get_visible(contributor)
        contributor.node_id = node._id
        return contributor
Ejemplo n.º 15
0
class NodeContributorsSerializer(JSONAPISerializer):
    """ Separate from UserSerializer due to necessity to override almost every field as read only
    """
    filterable_fields = frozenset([
        'id',
        'bibliographic',
        'permission'
    ])

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

    bibliographic = ser.BooleanField(help_text='Whether the user will be included in citations for this node or not.',
                                     default=True)
    permission = ser.ChoiceField(choices=osf_permissions.PERMISSIONS, required=False, allow_null=True,
                                 default=osf_permissions.reduce_permissions(osf_permissions.DEFAULT_CONTRIBUTOR_PERMISSIONS),
                                 help_text='User permission level. Must be "read", "write", or "admin". Defaults to "write".')

    links = LinksField({
        'self': 'get_absolute_url'
    })

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

    class Meta:
        type_ = 'contributors'

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

    def get_absolute_url(self, obj):
        node_id = self.context['request'].parser_context['kwargs']['node_id']
        return absolute_reverse(
            'nodes:node-contributor-detail',
            kwargs={
                'node_id': node_id,
                'user_id': obj._id
            }
        )
Ejemplo n.º 16
0
def _render_node(node, user=None):
    """

    :param node:
    :return:

    """
    perm = None
    if user:
        perm_list = node.get_permissions(user)
        perm = permissions.reduce_permissions(perm_list)
    return {
        'title': node.title,
        'id': node._primary_key,
        'url': node.url,
        'api_url': node.api_url,
        'primary': node.primary,
        'date_modified': utils.iso8601format(node.date_modified),
        'category': node.category,
        'permissions': perm,  # A string, e.g. 'admin', or None
    }
Ejemplo n.º 17
0
def test_reduce_permissions_with_unknown_permission_raises_error():
    with assert_raises(ValueError):
        permissions.reduce_permissions(['unknownpermission'])
Ejemplo n.º 18
0
def test_reduce_permissions_with_empty_list_raises_error():
    with assert_raises(ValueError):
        permissions.reduce_permissions([])
Ejemplo n.º 19
0
def test_reduce_permissions_with_empty_list_raises_error():
    with assert_raises(ValueError):
        permissions.reduce_permissions([])
Ejemplo n.º 20
0
def test_reduce_permissions_with_unknown_permission_raises_error():
    with assert_raises(ValueError):
        permissions.reduce_permissions(['unknownpermission'])
Ejemplo n.º 21
0
class NodeContributorsSerializer(JSONAPISerializer):
    """ Separate from UserSerializer due to necessity to override almost every field as read only
    """
    filterable_fields = frozenset([
        'fullname', 'given_name', 'middle_name', 'family_name', 'id',
        'bibliographic', 'permissions'
    ])
    id = ser.CharField(source='_id', label='ID')
    fullname = ser.CharField(
        read_only=True,
        help_text='Display name used in the general user interface')
    given_name = ser.CharField(read_only=True,
                               help_text='For bibliographic citations')
    middle_name = ser.CharField(read_only=True,
                                source='middle_names',
                                help_text='For bibliographic citations')
    family_name = ser.CharField(read_only=True,
                                help_text='For bibliographic citations')
    suffix = ser.CharField(read_only=True,
                           help_text='For bibliographic citations')
    date_registered = ser.DateTimeField(read_only=True)

    profile_image_url = 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)

    bibliographic = ser.BooleanField(
        help_text=
        'Whether the user will be included in citations for this node or not.',
        default=True)

    permission = ser.ChoiceField(
        choices=osf_permissions.PERMISSIONS,
        required=False,
        allow_null=True,
        default=osf_permissions.reduce_permissions(
            osf_permissions.DEFAULT_CONTRIBUTOR_PERMISSIONS),
        help_text=
        'User permission level. Must be "read", "write", or "admin". Defaults to "write".'
    )

    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 get_absolute_url(self, obj):
        node_id = self.context['request'].parser_context['kwargs']['node_id']
        return absolute_reverse('nodes:node-contributor-detail',
                                kwargs={
                                    'node_id': node_id,
                                    'user_id': obj._id
                                })

    def create(self, validated_data):
        auth = Auth(self.context['request'].user)
        node = self.context['view'].get_node()
        contributor = get_object_or_error(User,
                                          validated_data['_id'],
                                          display_name='user')
        # Node object checks for contributor existence but can still change permissions anyway
        if contributor in node.contributors:
            raise exceptions.ValidationError(
                '{} is already a contributor'.format(contributor.fullname))

        bibliographic = validated_data['bibliographic']
        permissions = osf_permissions.expand_permissions(
            validated_data.get('permission')
        ) or osf_permissions.DEFAULT_CONTRIBUTOR_PERMISSIONS
        node.add_contributor(contributor=contributor,
                             auth=auth,
                             visible=bibliographic,
                             permissions=permissions,
                             save=True)
        contributor.permission = osf_permissions.reduce_permissions(
            node.get_permissions(contributor))
        contributor.bibliographic = node.get_visible(contributor)
        contributor.node_id = node._id
        return contributor
Ejemplo n.º 22
0
def serialize_user(user, node=None, admin=False, full=False, is_profile=False, include_node_counts=False):
    """
    Return a dictionary representation of a registered user.

    :param User user: A User object
    :param bool full: Include complete user properties
    """
    from website.project.utils import PROJECT_QUERY
    contrib = None
    if isinstance(user, Contributor):
        contrib = user
        user = contrib.user
    fullname = user.display_full_name(node=node)
    ret = {
        'id': str(user._primary_key),
        'registered': user.is_registered,
        'surname': user.family_name,
        'fullname': fullname,
        'shortname': fullname if len(fullname) < 50 else fullname[:23] + '...' + fullname[-23:],
        'gravatar_url': gravatar(
            user, use_ssl=True,
            size=settings.PROFILE_IMAGE_MEDIUM
        ),
        'active': user.is_active,
    }
    if node is not None:
        if admin:
            flags = {
                'visible': False,
                'permission': 'read',
            }
        else:
            flags = {
                'visible': contrib.visible if isinstance(contrib, Contributor) else node.contributor_set.filter(user=user, visible=True).exists(),
                'permission': reduce_permissions(node.get_permissions(user)),
            }
        ret.update(flags)
    if user.is_registered:
        ret.update({
            'url': user.url,
            'absolute_url': user.absolute_url,
            'display_absolute_url': user.display_absolute_url,
            'date_registered': user.date_registered.strftime('%Y-%m-%d'),
        })

    if full:
        # Add emails
        if is_profile:
            ret['emails'] = [
                {
                    'address': each,
                    'primary': each.strip().lower() == user.username.strip().lower(),
                    'confirmed': True,
                } for each in user.emails
            ] + [
                {
                    'address': each,
                    'primary': each.strip().lower() == user.username.strip().lower(),
                    'confirmed': False
                }
                for each in user.get_unconfirmed_emails_exclude_external_identity()
            ]

        if user.is_merged:
            merger = user.merged_by
            merged_by = {
                'id': str(merger._primary_key),
                'url': merger.url,
                'absolute_url': merger.absolute_url
            }
        else:
            merged_by = None

        projects = Node.find_for_user(user, PROJECT_QUERY).get_roots()
        ret.update({
            'activity_points': user.get_activity_points(),
            'gravatar_url': gravatar(
                user, use_ssl=True,
                size=settings.PROFILE_IMAGE_LARGE
            ),
            'is_merged': user.is_merged,
            'merged_by': merged_by,
        })
        if include_node_counts:
            ret.update({
                'number_projects': projects.count(),
                'number_public_projects': projects.filter(is_public=True).count(),
            })

    return ret
Ejemplo n.º 23
0
def serialize_user(user, node=None, admin=False, full=False, is_profile=False):
    """
    Return a dictionary representation of a registered user.

    :param User user: A User object
    :param bool full: Include complete user properties
    """
    fullname = user.display_full_name(node=node)
    ret = {
        'id': str(user._primary_key),
        'registered': user.is_registered,
        'surname': user.family_name,
        'fullname': fullname,
        'shortname': fullname if len(fullname) < 50 else fullname[:23] + "..." + fullname[-23:],
        'gravatar_url': gravatar(
            user, use_ssl=True,
            size=settings.PROFILE_IMAGE_MEDIUM
        ),
        'active': user.is_active,
    }
    if node is not None:
        if admin:
            flags = {
                'visible': False,
                'permission': 'read',
            }
        else:
            flags = {
                'visible': user._id in node.visible_contributor_ids,
                'permission': reduce_permissions(node.get_permissions(user)),
            }
        ret.update(flags)
    if user.is_registered:
        ret.update({
            'url': user.url,
            'absolute_url': user.absolute_url,
            'display_absolute_url': user.display_absolute_url,
            'date_registered': user.date_registered.strftime("%Y-%m-%d"),
        })

    if full:
        # Add emails
        if is_profile:
            ret['emails'] = [
                {
                    'address': each,
                    'primary': each.strip().lower() == user.username.strip().lower(),
                    'confirmed': True,
                } for each in user.emails
            ] + [
                {
                    'address': each,
                    'primary': each.strip().lower() == user.username.strip().lower(),
                    'confirmed': False
                }
                for each in user.unconfirmed_emails
            ]

        if user.is_merged:
            merger = user.merged_by
            merged_by = {
                'id': str(merger._primary_key),
                'url': merger.url,
                'absolute_url': merger.absolute_url
            }
        else:
            merged_by = None
        ret.update({
            'number_projects': get_projects(user).count(),
            'number_public_projects': get_public_projects(user).count(),
            'activity_points': user.get_activity_points(),
            'gravatar_url': gravatar(
                user, use_ssl=True,
                size=settings.PROFILE_IMAGE_LARGE
            ),
            'is_merged': user.is_merged,
            'merged_by': merged_by,
        })

    return ret
Ejemplo n.º 24
0
def serialize_simple_user_and_node_permissions(node, user):
    return {
        'id': user._id,
        'name': user.fullname,
        'permission': reduce_permissions(node.get_permissions(user))
    }
Ejemplo n.º 25
0
def serialize_simple_user_and_node_permissions(node, user):
    return {
        'id': user._id,
        'name': user.fullname,
        'permission': reduce_permissions(node.get_permissions(user))
    }
Ejemplo n.º 26
0
def serialize_user(user, node=None, admin=False, full=False):
    """
    Return a dictionary representation of a registered user.

    :param User user: A User object
    :param bool full: Include complete user properties
    """
    fullname = user.display_full_name(node=node)
    ret = {
        'id':
        str(user._primary_key),
        'registered':
        user.is_registered,
        'surname':
        user.family_name,
        'fullname':
        fullname,
        'shortname':
        fullname if len(fullname) < 50 else fullname[:23] + "..." +
        fullname[-23:],
        'gravatar_url':
        gravatar(user,
                 use_ssl=True,
                 size=settings.GRAVATAR_SIZE_ADD_CONTRIBUTOR),
        'active':
        user.is_active,
    }
    if node is not None:
        if admin:
            flags = {
                'visible': False,
                'permission': 'read',
            }
        else:
            flags = {
                'visible': user._id in node.visible_contributor_ids,
                'permission': reduce_permissions(node.get_permissions(user)),
            }
        ret.update(flags)
    if user.is_registered:
        ret.update({
            'url':
            user.url,
            'absolute_url':
            user.absolute_url,
            'display_absolute_url':
            user.display_absolute_url,
            'date_registered':
            user.date_registered.strftime("%Y-%m-%d"),
        })

    if full:
        # Add emails
        ret['emails'] = [{
            'address': each,
            'primary': each == user.username,
            'confirmed': True,
        } for each in user.emails] + [{
            'address': each,
            'primary': each == user.username,
            'confirmed': False
        } for each in user.unconfirmed_emails]

        if user.is_merged:
            merger = user.merged_by
            merged_by = {
                'id': str(merger._primary_key),
                'url': merger.url,
                'absolute_url': merger.absolute_url
            }
        else:
            merged_by = None
        ret.update({
            'number_projects':
            len(get_projects(user)),
            'number_public_projects':
            len(get_public_projects(user)),
            'activity_points':
            user.get_activity_points(),
            'gravatar_url':
            gravatar(user, use_ssl=True, size=settings.GRAVATAR_SIZE_PROFILE),
            'is_merged':
            user.is_merged,
            'merged_by':
            merged_by,
        })

    return ret
Ejemplo n.º 27
0
def serialize_user(user, node=None, admin=False, full=False, is_profile=False, include_node_counts=False):
    """
    Return a dictionary representation of a registered user.

    :param User user: A User object
    :param bool full: Include complete user properties
    """
    from website.project.utils import PROJECT_QUERY
    contrib = None
    if isinstance(user, Contributor):
        contrib = user
        user = contrib.user
    fullname = user.display_full_name(node=node)
    ret = {
        'id': str(user._primary_key),
        'registered': user.is_registered,
        'surname': user.family_name,
        'fullname': fullname,
        'shortname': fullname if len(fullname) < 50 else fullname[:23] + '...' + fullname[-23:],
        'gravatar_url': gravatar(
            user, use_ssl=True,
            size=settings.PROFILE_IMAGE_MEDIUM
        ),
        'active': user.is_active,
    }
    if node is not None:
        if admin:
            flags = {
                'visible': False,
                'permission': 'read',
            }
        else:
            flags = {
                'visible': contrib.visible if isinstance(contrib, Contributor) else node.contributor_set.filter(user=user, visible=True).exists(),
                'permission': reduce_permissions(node.get_permissions(user)),
            }
        ret.update(flags)
    if user.is_registered:
        ret.update({
            'url': user.url,
            'absolute_url': user.absolute_url,
            'display_absolute_url': user.display_absolute_url,
            'date_registered': user.date_registered.strftime('%Y-%m-%d'),
        })

    if full:
        # Add emails
        if is_profile:
            ret['emails'] = [
                {
                    'address': each,
                    'primary': each.strip().lower() == user.username.strip().lower(),
                    'confirmed': True,
                } for each in user.emails.values_list('address', flat=True)
            ] + [
                {
                    'address': each,
                    'primary': each.strip().lower() == user.username.strip().lower(),
                    'confirmed': False
                }
                for each in user.get_unconfirmed_emails_exclude_external_identity()
            ]

        if user.is_merged:
            merger = user.merged_by
            merged_by = {
                'id': str(merger._primary_key),
                'url': merger.url,
                'absolute_url': merger.absolute_url
            }
        else:
            merged_by = None

        projects = Node.find_for_user(user, PROJECT_QUERY).get_roots()
        ret.update({
            'activity_points': user.get_activity_points(),
            'gravatar_url': gravatar(
                user, use_ssl=True,
                size=settings.PROFILE_IMAGE_LARGE
            ),
            'is_merged': user.is_merged,
            'merged_by': merged_by,
        })
        if include_node_counts:
            ret.update({
                'number_projects': projects.count(),
                'number_public_projects': projects.filter(is_public=True).count(),
            })

    return ret