예제 #1
0
def add_contributor_json(user, current_user=None, node=None):
    """
    Generate a dictionary representation of a user, optionally including # projects shared with `current_user`

    :param User user: The user object to serialize
    :param User current_user : The user object for a different user, to calculate number of projects in common
    :return dict: A dict representing the serialized user data
    """
    # get shared projects
    if current_user:
        n_projects_in_common = current_user.n_projects_in_common(user)
    else:
        n_projects_in_common = 0

    current_employment = None
    education = None

    if user.jobs:
        current_employment = user.jobs[0]['institution']

    if user.schools:
        education = user.schools[0]['institution']

    contributor_json = {
        'fullname':
        user.fullname,
        'email':
        user.email,
        'id':
        user._primary_key,
        'employment':
        current_employment,
        'education':
        education,
        'n_projects_in_common':
        n_projects_in_common,
        'registered':
        user.is_registered,
        'active':
        user.is_active,
        'profile_image_url':
        user.profile_image_url(size=settings.PROFILE_IMAGE_MEDIUM),
        'profile_url':
        user.profile_url
    }

    if node:
        contributor_info = user.contributor_set.get(node=node.parent_node)
        contributor_json['permission'] = get_contributor_permissions(
            contributor_info, as_list=False)
        contributor_json['visible'] = contributor_info.visible

    return contributor_json
예제 #2
0
파일: utils.py 프로젝트: mfraezz/osf.io
def add_contributor_json(user, current_user=None, node=None):
    """
    Generate a dictionary representation of a user, optionally including # projects shared with `current_user`

    :param User user: The user object to serialize
    :param User current_user : The user object for a different user, to calculate number of projects in common
    :return dict: A dict representing the serialized user data
    """
    # get shared projects
    if current_user:
        n_projects_in_common = current_user.n_projects_in_common(user)
    else:
        n_projects_in_common = 0

    current_employment = None
    education = None

    if user.jobs:
        current_employment = user.jobs[0]['institution']

    if user.schools:
        education = user.schools[0]['institution']

    contributor_json = {
        'fullname': user.fullname,
        'email': user.email,
        'id': user._primary_key,
        'employment': current_employment,
        'education': education,
        'n_projects_in_common': n_projects_in_common,
        'registered': user.is_registered,
        'active': user.is_active,
        'profile_image_url': user.profile_image_url(size=settings.PROFILE_IMAGE_MEDIUM),
        'profile_url': user.profile_url
    }

    if node:
        contributor_info = user.contributor_set.get(node=node.parent_node)
        contributor_json['permission'] = get_contributor_permissions(contributor_info, as_list=False)
        contributor_json['visible'] = contributor_info.visible

    return contributor_json
예제 #3
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
    """
    contrib = None
    if isinstance(user, Contributor):
        contrib = user
        user = contrib.user
    fullname = user.display_full_name(node=node)
    ret = {
        'id':
        str(user._id),
        'registered':
        user.is_registered,
        'surname':
        user.family_name,
        'fullname':
        fullname,
        'shortname':
        fullname if len(fullname) < 50 else fullname[:23] + '...' +
        fullname[-23:],
        'profile_image_url':
        user.profile_image_url(size=settings.PROFILE_IMAGE_MEDIUM),
        'active':
        user.is_active,
    }
    if node is not None:
        if admin:
            flags = {
                'visible': False,
                'permission': 'read',
            }
        else:
            is_contributor_obj = isinstance(contrib, Contributor)
            flags = {
                'visible':
                contrib.visible if is_contributor_obj else
                node.contributor_set.filter(user=user, visible=True).exists(),
                'permission':
                get_contributor_permissions(contrib, as_list=False)
                if is_contributor_obj else 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

        ret.update({
            'activity_points':
            user.get_activity_points(),
            'profile_image_url':
            user.profile_image_url(size=settings.PROFILE_IMAGE_LARGE),
            'is_merged':
            user.is_merged,
            'merged_by':
            merged_by,
        })
        if include_node_counts:
            projects = user.nodes.exclude(is_deleted=True).filter(
                type='osf.node').get_roots()
            ret.update({
                'number_projects':
                projects.count(),
                'number_public_projects':
                projects.filter(is_public=True).count(),
            })

    return ret
예제 #4
0
파일: utils.py 프로젝트: mfraezz/osf.io
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
    """
    contrib = None
    if isinstance(user, Contributor):
        contrib = user
        user = contrib.user
    fullname = user.display_full_name(node=node)
    ret = {
        'id': str(user._id),
        'registered': user.is_registered,
        'surname': user.family_name,
        'fullname': fullname,
        'shortname': fullname if len(fullname) < 50 else fullname[:23] + '...' + fullname[-23:],
        'profile_image_url': user.profile_image_url(size=settings.PROFILE_IMAGE_MEDIUM),
        'active': user.is_active,
    }
    if node is not None:
        if admin:
            flags = {
                'visible': False,
                'permission': 'read',
            }
        else:
            is_contributor_obj = isinstance(contrib, Contributor)
            flags = {
                'visible': contrib.visible if is_contributor_obj else node.contributor_set.filter(user=user, visible=True).exists(),
                'permission': get_contributor_permissions(contrib, as_list=False) if is_contributor_obj else 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

        ret.update({
            'activity_points': user.get_activity_points(),
            'profile_image_url': user.profile_image_url(size=settings.PROFILE_IMAGE_LARGE),
            'is_merged': user.is_merged,
            'merged_by': merged_by,
        })
        if include_node_counts:
            projects = user.nodes.exclude(is_deleted=True).filter(type='osf.node').get_roots()
            ret.update({
                'number_projects': projects.count(),
                'number_public_projects': projects.filter(is_public=True).count(),
            })

    return ret
예제 #5
0
def _view_project(node,
                  auth,
                  primary=False,
                  embed_contributors=False,
                  embed_descendants=False,
                  embed_registrations=False,
                  embed_forks=False):
    """Build a JSON object containing everything needed to render
    project.view.mako.
    """
    node = AbstractNode.objects.filter(
        pk=node.pk).include('contributor__user__guids').get()
    user = auth.user
    try:
        contributor = node.contributor_set.get(user=user)
    except Contributor.DoesNotExist:
        contributor = None

    parent = node.find_readable_antecedent(auth)
    if user:
        bookmark_collection = find_bookmark_collection(user)
        bookmark_collection_id = bookmark_collection._id
        in_bookmark_collection = bookmark_collection.linked_nodes.filter(
            pk=node.pk).exists()
    else:
        in_bookmark_collection = False
        bookmark_collection_id = ''
    view_only_link = auth.private_key or request.args.get('view_only',
                                                          '').strip('/')
    anonymous = has_anonymous_link(node, auth)
    addons = list(node.get_addons())
    widgets, configs, js, css = _render_addons(addons)
    redirect_url = node.url + '?view_only=None'
    node_linked_preprint = node.linked_preprint

    disapproval_link = ''
    if (node.is_pending_registration and node.has_permission(user, ADMIN)):
        disapproval_link = node.root.registration_approval.stashed_urls.get(
            user._id, {}).get('reject', '')

    if (node.is_pending_embargo and node.has_permission(user, ADMIN)):
        disapproval_link = node.root.embargo.stashed_urls.get(user._id,
                                                              {}).get(
                                                                  'reject', '')

    # Before page load callback; skip if not primary call
    if primary:
        for addon in addons:
            messages = addon.before_page_load(node, user) or []
            for message in messages:
                status.push_status_message(message,
                                           kind='info',
                                           dismissible=False,
                                           trust=True)
    NodeRelation = apps.get_model('osf.NodeRelation')

    is_registration = node.is_registration
    data = {
        'node': {
            'disapproval_link':
            disapproval_link,
            'id':
            node._primary_key,
            'title':
            node.title,
            'category':
            node.category_display,
            'category_short':
            node.category,
            'node_type':
            node.project_or_component,
            'description':
            node.description or '',
            'license':
            serialize_node_license_record(node.license),
            'url':
            node.url,
            'api_url':
            node.api_url,
            'absolute_url':
            node.absolute_url,
            'redirect_url':
            redirect_url,
            'display_absolute_url':
            node.display_absolute_url,
            'update_url':
            node.api_url_for('update_node'),
            'in_dashboard':
            in_bookmark_collection,
            'is_public':
            node.is_public,
            'is_archiving':
            node.archiving,
            'date_created':
            iso8601format(node.created),
            'date_modified':
            iso8601format(node.last_logged) if node.last_logged else '',
            'tags':
            list(
                node.tags.filter(system=False).values_list('name', flat=True)),
            'children':
            node.nodes_active.exists(),
            'child_exists':
            Node.objects.get_children(node, active=True).exists(),
            'is_registration':
            is_registration,
            'is_pending_registration':
            node.is_pending_registration if is_registration else False,
            'is_retracted':
            node.is_retracted if is_registration else False,
            'is_pending_retraction':
            node.is_pending_retraction if is_registration else False,
            'retracted_justification':
            getattr(node.retraction, 'justification', None)
            if is_registration else None,
            'date_retracted':
            iso8601format(getattr(node.retraction, 'date_retracted', None))
            if is_registration else '',
            'embargo_end_date':
            node.embargo_end_date.strftime('%A, %b %d, %Y')
            if is_registration and node.embargo_end_date else '',
            'is_pending_embargo':
            node.is_pending_embargo if is_registration else False,
            'is_embargoed':
            node.is_embargoed if is_registration else False,
            'is_pending_embargo_termination':
            is_registration and node.is_embargoed
            and (node.embargo_termination_approval
                 and node.embargo_termination_approval.is_pending_approval),
            'registered_from_url':
            node.registered_from.url if is_registration else '',
            'registered_date':
            iso8601format(node.registered_date) if is_registration else '',
            'root_id':
            node.root._id if node.root else None,
            'registered_meta':
            node.registered_meta,
            'registered_schemas':
            serialize_meta_schemas(list(node.registered_schema.all()))
            if is_registration else False,
            'is_fork':
            node.is_fork,
            'forked_from_id':
            node.forked_from._primary_key if node.is_fork else '',
            'forked_from_display_absolute_url':
            node.forked_from.display_absolute_url if node.is_fork else '',
            'forked_date':
            iso8601format(node.forked_date) if node.is_fork else '',
            'fork_count':
            node.forks.exclude(type='osf.registration').filter(
                is_deleted=False).count(),
            'private_links': [x.to_json() for x in node.private_links_active],
            'link':
            view_only_link,
            'templated_count':
            node.templated_list.count(),
            'linked_nodes_count':
            NodeRelation.objects.filter(child=node, is_node_link=True).exclude(
                parent__type='osf.collection').count(),
            'anonymous':
            anonymous,
            'comment_level':
            node.comment_level,
            'has_comments':
            node.comment_set.exists(),
            'identifiers': {
                'doi': node.get_identifier_value('doi'),
                'ark': node.get_identifier_value('ark'),
            },
            'institutions':
            get_affiliated_institutions(node) if node else [],
            'has_draft_registrations':
            node.has_active_draft_registrations,
            'is_preprint':
            node.is_preprint,
            'has_moderated_preprint':
            node_linked_preprint.provider.reviews_workflow
            if node_linked_preprint else '',
            'preprint_state':
            node_linked_preprint.machine_state if node_linked_preprint else '',
            'preprint_word':
            node_linked_preprint.provider.preprint_word
            if node_linked_preprint else '',
            'preprint_provider': {
                'name': node_linked_preprint.provider.name,
                'workflow': node_linked_preprint.provider.reviews_workflow
            } if node_linked_preprint else {},
            'is_preprint_orphan':
            node.is_preprint_orphan,
            'has_published_preprint':
            node.preprints.filter(
                is_published=True).exists() if node else False,
            'preprint_file_id':
            node.preprint_file._id if node.preprint_file else None,
            'preprint_url':
            node.preprint_url
        },
        'parent_node': {
            'exists':
            parent is not None,
            'id':
            parent._primary_key if parent else '',
            'title':
            parent.title if parent else '',
            'category':
            parent.category_display if parent else '',
            'url':
            parent.url if parent else '',
            'api_url':
            parent.api_url if parent else '',
            'absolute_url':
            parent.absolute_url if parent else '',
            'registrations_url':
            parent.web_url_for('node_registrations') if parent else '',
            'is_public':
            parent.is_public if parent else '',
            'is_contributor':
            parent.is_contributor(user) if parent else '',
            'can_view':
            parent.can_view(auth) if parent else False,
        },
        'user': {
            'is_contributor':
            bool(contributor),
            'is_admin':
            bool(contributor) and contributor.admin,
            'is_admin_parent':
            parent.is_admin_parent(user) if parent else False,
            'can_edit':
            bool(contributor) and contributor.write
            and not node.is_registration,
            'can_edit_tags':
            bool(contributor) and contributor.write,
            'has_read_permissions':
            node.has_permission(user, READ),
            'permissions':
            get_contributor_permissions(contributor, as_list=True)
            if contributor else [],
            'id':
            user._id if user else None,
            'username':
            user.username if user else None,
            'fullname':
            user.fullname if user else '',
            'can_comment':
            bool(contributor) or node.can_comment(auth),
            'show_wiki_widget':
            _should_show_wiki_widget(node, contributor),
            'dashboard_id':
            bookmark_collection_id,
            'institutions':
            get_affiliated_institutions(user) if user else [],
        },
        # TODO: Namespace with nested dicts
        'addons_enabled': [each.short_name for each in addons],
        'addons':
        configs,
        'addon_widgets':
        widgets,
        'addon_widget_js':
        js,
        'addon_widget_css':
        css,
        'node_categories': [{
            'value': key,
            'display_name': value
        } for key, value in settings.NODE_CATEGORY_MAP.iteritems()]
    }
    if embed_contributors and not anonymous:
        data['node']['contributors'] = utils.serialize_visible_contributors(
            node)
    else:
        data['node']['contributors'] = list(
            node.contributors.values_list('guids___id', flat=True))
    if embed_descendants:
        descendants, all_readable = _get_readable_descendants(auth=auth,
                                                              node=node)
        data['user']['can_sort'] = all_readable
        data['node']['descendants'] = [
            serialize_node_summary(node=each,
                                   auth=auth,
                                   primary=not node.has_node_link_to(each),
                                   show_path=False) for each in descendants
        ]
    if embed_registrations:
        data['node']['registrations'] = [
            serialize_node_summary(node=each, auth=auth, show_path=False)
            for each in node.registrations_all.order_by('-registered_date').
            exclude(is_deleted=True).annotate(nlogs=Count('logs'))
        ]
    if embed_forks:
        data['node']['forks'] = [
            serialize_node_summary(node=each, auth=auth, show_path=False)
            for each in node.forks.exclude(type='osf.registration').exclude(
                is_deleted=True).order_by('-forked_date').annotate(
                    nlogs=Count('logs'))
        ]
    return data
예제 #6
0
파일: node.py 프로젝트: aaxelb/osf.io
def _view_project(node, auth, primary=False,
                  embed_contributors=False, embed_descendants=False,
                  embed_registrations=False, embed_forks=False):
    """Build a JSON object containing everything needed to render
    project.view.mako.
    """
    node = AbstractNode.objects.filter(pk=node.pk).include('contributor__user__guids').get()
    user = auth.user

    try:
        contributor = node.contributor_set.get(user=user)
    except Contributor.DoesNotExist:
        contributor = None

    parent = node.find_readable_antecedent(auth)
    if user:
        bookmark_collection = find_bookmark_collection(user)
        bookmark_collection_id = bookmark_collection._id
        in_bookmark_collection = bookmark_collection.guid_links.filter(_id=node._id).exists()
    else:
        in_bookmark_collection = False
        bookmark_collection_id = ''

    view_only_link = auth.private_key or request.args.get('view_only', '').strip('/')
    anonymous = has_anonymous_link(node, auth)
    addons = list(node.get_addons())
    widgets, configs, js, css = _render_addons(addons)
    redirect_url = node.url + '?view_only=None'

    disapproval_link = ''
    if (node.is_pending_registration and node.has_permission(user, ADMIN)):
        disapproval_link = node.root.registration_approval.stashed_urls.get(user._id, {}).get('reject', '')

    if (node.is_pending_embargo and node.has_permission(user, ADMIN)):
        disapproval_link = node.root.embargo.stashed_urls.get(user._id, {}).get('reject', '')

    # Before page load callback; skip if not primary call
    if primary:
        for addon in addons:
            messages = addon.before_page_load(node, user) or []
            for message in messages:
                status.push_status_message(message, kind='info', dismissible=False, trust=True)
    NodeRelation = apps.get_model('osf.NodeRelation')

    is_registration = node.is_registration
    data = {
        'node': {
            'disapproval_link': disapproval_link,
            'id': node._primary_key,
            'title': node.title,
            'category': node.category_display,
            'category_short': node.category,
            'node_type': node.project_or_component,
            'description': node.description or '',
            'license': serialize_node_license_record(node.license),
            'url': node.url,
            'api_url': node.api_url,
            'absolute_url': node.absolute_url,
            'redirect_url': redirect_url,
            'display_absolute_url': node.display_absolute_url,
            'update_url': node.api_url_for('update_node'),
            'in_dashboard': in_bookmark_collection,
            'is_public': node.is_public,
            'is_archiving': node.archiving,
            'date_created': iso8601format(node.created),
            'date_modified': iso8601format(node.last_logged) if node.last_logged else '',
            'tags': list(node.tags.filter(system=False).values_list('name', flat=True)),
            'children': node.nodes_active.exists(),
            'child_exists': Node.objects.get_children(node, active=True).exists(),
            'is_supplemental_project': node.has_linked_published_preprints,
            'is_registration': is_registration,
            'is_pending_registration': node.is_pending_registration if is_registration else False,
            'is_retracted': node.is_retracted if is_registration else False,
            'is_pending_retraction': node.is_pending_retraction if is_registration else False,
            'retracted_justification': getattr(node.retraction, 'justification', None) if is_registration else None,
            'date_retracted': iso8601format(getattr(node.retraction, 'date_retracted', None)) if is_registration else '',
            'embargo_end_date': node.embargo_end_date.strftime('%A, %b %d, %Y') if is_registration and node.embargo_end_date else '',
            'is_pending_embargo': node.is_pending_embargo if is_registration else False,
            'is_embargoed': node.is_embargoed if is_registration else False,
            'is_pending_embargo_termination': is_registration and node.is_embargoed and (
                node.embargo_termination_approval and
                node.embargo_termination_approval.is_pending_approval
            ),
            'registered_from_url': node.registered_from.url if is_registration else '',
            'registered_date': iso8601format(node.registered_date) if is_registration else '',
            'root_id': node.root._id if node.root else None,
            'registered_meta': node.registered_meta,
            'registered_schemas': serialize_meta_schemas(list(node.registered_schema.all())) if is_registration else False,
            'is_fork': node.is_fork,
            'is_collected': node.is_collected,
            'collections': serialize_collections(node.collecting_metadata_list, auth),
            'forked_from_id': node.forked_from._primary_key if node.is_fork else '',
            'forked_from_display_absolute_url': node.forked_from.display_absolute_url if node.is_fork else '',
            'forked_date': iso8601format(node.forked_date) if node.is_fork else '',
            'fork_count': node.forks.exclude(type='osf.registration').filter(is_deleted=False).count(),
            'private_links': [x.to_json() for x in node.private_links_active],
            'link': view_only_link,
            'templated_count': node.templated_list.count(),
            'linked_nodes_count': NodeRelation.objects.filter(child=node, is_node_link=True).exclude(parent__type='osf.collection').count(),
            'anonymous': anonymous,
            'comment_level': node.comment_level,
            'has_comments': node.comment_set.exists(),
            'identifiers': {
                'doi': node.get_identifier_value('doi'),
                'ark': node.get_identifier_value('ark'),
            },
            'visible_preprints': serialize_preprints(node, user),
            'institutions': get_affiliated_institutions(node) if node else [],
            'has_draft_registrations': node.has_active_draft_registrations,
            'access_requests_enabled': node.access_requests_enabled,
            'storage_location': node.osfstorage_region.name,
            'waterbutler_url': node.osfstorage_region.waterbutler_url,
            'mfr_url': node.osfstorage_region.mfr_url
        },
        'parent_node': {
            'exists': parent is not None,
            'id': parent._primary_key if parent else '',
            'title': parent.title if parent else '',
            'category': parent.category_display if parent else '',
            'url': parent.url if parent else '',
            'api_url': parent.api_url if parent else '',
            'absolute_url': parent.absolute_url if parent else '',
            'registrations_url': parent.web_url_for('node_registrations', _guid=True) if parent else '',
            'is_public': parent.is_public if parent else '',
            'is_contributor': parent.is_contributor(user) if parent else '',
            'can_view': parent.can_view(auth) if parent else False,
        },
        'user': {
            'is_contributor': bool(contributor),
            'is_admin': bool(contributor) and contributor.admin,
            'is_admin_parent': parent.is_admin_parent(user) if parent else False,
            'can_edit': bool(contributor) and contributor.write and not node.is_registration,
            'can_edit_tags': bool(contributor) and contributor.write,
            'has_read_permissions': node.has_permission(user, READ),
            'permissions': get_contributor_permissions(contributor, as_list=True) if contributor else [],
            'id': user._id if user else None,
            'username': user.username if user else None,
            'fullname': user.fullname if user else '',
            'can_comment': bool(contributor) or node.can_comment(auth),
            'show_wiki_widget': _should_show_wiki_widget(node, contributor),
            'dashboard_id': bookmark_collection_id,
            'institutions': get_affiliated_institutions(user) if user else [],
        },
        # TODO: Namespace with nested dicts
        'addons_enabled': [each.short_name for each in addons],
        'addons': configs,
        'addon_widgets': widgets,
        'addon_widget_js': js,
        'addon_widget_css': css,
        'node_categories': [
            {'value': key, 'display_name': value}
            for key, value in settings.NODE_CATEGORY_MAP.items()
        ]
    }

    # Default should be at top of list for UI and for the project overview page the default region
    # for a component is that of the it's parent node.
    region_list = get_storage_region_list(user, node=node)

    data.update({'storage_regions': region_list})
    data.update({'storage_flag_is_active': storage_i18n_flag_active()})

    if embed_contributors and not anonymous:
        data['node']['contributors'] = utils.serialize_visible_contributors(node)
    else:
        data['node']['contributors'] = list(node.contributors.values_list('guids___id', flat=True))
    if embed_descendants:
        descendants, all_readable = _get_readable_descendants(auth=auth, node=node)
        data['user']['can_sort'] = all_readable
        data['node']['descendants'] = [
            serialize_node_summary(node=each, auth=auth, primary=not node.has_node_link_to(each), show_path=False)
            for each in descendants
        ]
    if embed_registrations:
        data['node']['registrations'] = [
            serialize_node_summary(node=each, auth=auth, show_path=False)
            for each in node.registrations_all.order_by('-registered_date').exclude(is_deleted=True)
        ]
    if embed_forks:
        data['node']['forks'] = [
            serialize_node_summary(node=each, auth=auth, show_path=False)
            for each in node.forks.exclude(type='osf.registration').exclude(is_deleted=True).order_by('-forked_date')
        ]
    return data