Exemplo n.º 1
0
def _kwargs_to_nodes(kwargs):
    """Retrieve project and component objects from keyword arguments.

    :param dict kwargs: Dictionary of keyword arguments
    :return: Tuple of project and component

    """
    project = kwargs.get('project') or Node.load(kwargs.get('pid', kwargs.get('nid')))
    if not project:
        raise HTTPError(http.NOT_FOUND)
    if project.category != 'project':
        raise HTTPError(http.BAD_REQUEST)
    if project.is_deleted:
        raise HTTPError(http.GONE)

    if kwargs.get('nid') or kwargs.get('node'):
        node = kwargs.get('node') or Node.load(kwargs.get('nid'))
        if not node:
            raise HTTPError(http.NOT_FOUND)
        if node.is_deleted:
            raise HTTPError(http.GONE)
    else:
        node = None

    return project, node
Exemplo n.º 2
0
def project_generate_private_link_post(auth, node, **kwargs):
    """ creata a new private link object and add it to the node and its selected children"""

    node_ids = request.json.get('node_ids', [])
    name = request.json.get('name', '')
    anonymous = request.json.get('anonymous', False)

    if node._id not in node_ids:
        node_ids.insert(0, node._id)

    nodes = [Node.load(node_id) for node_id in node_ids]

    has_public_node = any(node.is_public for node in nodes)

    new_link = new_private_link(
        name=name, user=auth.user, nodes=nodes, anonymous=anonymous
    )

    if anonymous and has_public_node:
        status.push_status_message(
            'Anonymized view-only links <b>DO NOT</b> '
            'anonymize contributors of public project or component.'
        )

    return new_link
Exemplo n.º 3
0
    def test_bulk_creates_children_and_sanitizes_html_logged_in_owner(self):
        title = "<em>Cool</em> <strong>Project</strong>"
        description = 'An <script>alert("even cooler")</script> child'

        res = self.app.post_json_api(
            self.url,
            {
                "data": [
                    {
                        "type": "nodes",
                        "attributes": {
                            "title": title,
                            "description": description,
                            "category": "project",
                            "public": True,
                        },
                    }
                ]
            },
            auth=self.user.auth,
            bulk=True,
        )
        child_id = res.json["data"][0]["id"]
        assert_equal(res.status_code, 201)
        url = "/{}nodes/{}/".format(API_BASE, child_id)

        res = self.app.get(url, auth=self.user.auth)
        assert_equal(res.json["data"]["attributes"]["title"], strip_html(title))
        assert_equal(res.json["data"]["attributes"]["description"], strip_html(description))
        assert_equal(res.json["data"]["attributes"]["category"], "project")

        self.project.reload()
        child_id = res.json["data"]["id"]
        assert_equal(child_id, self.project.nodes[0]._id)
        assert_equal(Node.load(child_id).logs[0].action, NodeLog.PROJECT_CREATED)
Exemplo n.º 4
0
def project_new_post(auth, **kwargs):
    user = auth.user

    title = strip_html(request.json.get('title'))
    template = request.json.get('template')
    description = strip_html(request.json.get('description'))
    title = title.strip()

    if not title or len(title) > 200:
        raise HTTPError(http.BAD_REQUEST)

    if template:
        original_node = Node.load(template)
        changes = {
            'title': title
        }

        if description:
            changes['description'] = description

        project = original_node.use_as_template(
            auth=auth,
            changes={
                template: changes
            })

    else:
        project = new_node('project', title, user, description)

    return {
        'projectUrl': project.url
    }, http.CREATED
Exemplo n.º 5
0
 def get_object(self):
     link_id = self.kwargs['link_id']
     view_only_link = PrivateLink.load(link_id)
     return {
         'data': [Node.load(node) for node in view_only_link.nodes],
         'self': view_only_link
     }
 def test_make_new_node_settings(self):
     node_settings_document = self.node_settings_documents[0]
     node = Node.load(node_settings_document['owner'])
     user_settings_document = database['addons3usersettings'].find_one({
         '_id':  node_settings_document['user_settings']
     })
     external_account, user, new = migration.migrate_to_external_account(
         user_settings_document
     )
     user_settings = migration.make_new_user_settings(user)
     node_settings = migration.make_new_node_settings(
         node,
         node_settings_document,
         external_account,
         user_settings
     )
     assert(
         'addons3nodesettings' not in node._backrefs['addons']
     )
     assert_equal(
         len(node._backrefs['addons']['s3nodesettings']['owner']),
         1
     )
     assert_equal(
         node._backrefs['addons']['s3nodesettings']['owner'][0],
         node_settings._id
     )
Exemplo n.º 7
0
    def test_POST_register_make_public_does_not_make_children_public(self, mock_enqueue):
        component = NodeFactory(
            creator=self.user,
            parent=self.project,
            title='Component'
        )
        subproject = ProjectFactory(
            creator=self.user,
            parent=self.project,
            title='Subproject'
        )
        subproject_component = NodeFactory(
            creator=self.user,
            parent=subproject,
            title='Subcomponent'
        )

        res = self.app.post(
            self.project.api_url_for('register_draft_registration', draft_id=self.draft._id),
            self.valid_make_public_payload,
            content_type='application/json',
            auth=self.user.auth
        )
        self.project.reload()
        # Last node directly registered from self.project
        registration = Node.load(self.project.node__registrations[-1])
        assert_false(registration.is_public)
        for node in registration.get_descendants_recursive():
            assert_true(node.is_registration)
            assert_false(node.is_public)
    def test_POST_register_embargo_does_not_make_project_or_children_public(self, mock_enqueue):
        public_project = ProjectFactory(creator=self.user, is_public=True)
        component = NodeFactory(creator=self.user, parent=public_project, title="Component", is_public=True)
        subproject = ProjectFactory(creator=self.user, parent=public_project, title="Subproject", is_public=True)
        subproject_component = NodeFactory(creator=self.user, parent=subproject, title="Subcomponent", is_public=True)
        res = self.app.post(
            public_project.api_url_for("node_register_template_page_post", template=u"Open-Ended_Registration"),
            self.valid_embargo_payload,
            content_type="application/json",
            auth=self.user.auth,
        )
        public_project.reload()
        assert_equal(res.status_code, 201)

        # Last node directly registered from self.project
        registration = Node.load(public_project.node__registrations[-1])

        assert_true(registration.is_registration)
        assert_false(registration.is_public)
        assert_true(registration.is_pending_embargo_for_existing_registration)
        assert_is_not_none(registration.embargo)

        for node in registration.get_descendants_recursive():
            assert_true(node.is_registration)
            assert_false(node.is_public)
Exemplo n.º 9
0
def get_configured_projects(user):
    """Filter all user subscriptions for ones that are on parent projects
     and return the project ids.

    :param user: modular odm User object
    :return: list of project ids for projects with no parent
    """
    configured_project_ids = set()
    user_subscriptions = get_all_user_subscriptions(user)

    for subscription in user_subscriptions:
        if subscription is None:
            continue
        # If the user has opted out of emails skip
        node = subscription.owner

        if not isinstance(node, Node) or (user in subscription.none and not node.parent_id):
            continue

        while node.parent_id and not node.is_deleted:
            node = Node.load(node.parent_id)

        if not node.is_deleted:
            configured_project_ids.add(node._id)

    return list(configured_project_ids)
Exemplo n.º 10
0
def add_hook_to_old_node_settings(document, account):
    connect = GitHubClient(external_account=account)
    secret = make_hook_secret()
    hook = None
    try:
        hook = connect.add_hook(
            document['user'], document['repo'],
            'web',
            {
                'url': urlparse.urljoin(
                    HOOK_DOMAIN,
                    os.path.join(
                        Node.load(document['owner']).api_url, 'github', 'hook/'
                    )
                ),
                'content_type': github_settings.HOOK_CONTENT_TYPE,
                'secret': secret,
            },
            events=github_settings.HOOK_EVENTS,
        )
    except ApiError:
        pass
    if hook:
        database['addongithubnodesettings'].find_and_modify(
            {'_id': document['_id']},
            {
                '$set': {
                    'hook_id': hook.id,
                    'hook_secret': secret
                }
            }
        )
Exemplo n.º 11
0
def project_generate_private_link_post(auth, node, **kwargs):
    """ creata a new private link object and add it to the node and its selected children"""

    node_ids = request.json.get('node_ids', [])
    name = request.json.get('name', '')

    anonymous = request.json.get('anonymous', False)

    if node._id not in node_ids:
        node_ids.insert(0, node._id)

    nodes = [Node.load(node_id) for node_id in node_ids]

    has_public_node = any(node.is_public for node in nodes)

    try:
        new_link = new_private_link(
            name=name, user=auth.user, nodes=nodes, anonymous=anonymous
        )
    except ValidationValueError as e:
        raise HTTPError(
            http.BAD_REQUEST,
            data=dict(message_long=e.message)
        )

    if anonymous and has_public_node:
        status.push_status_message(
            'Anonymized view-only links <b>DO NOT</b> '
            'anonymize contributors of public projects or components.',
            trust=True
        )

    return new_link
Exemplo n.º 12
0
    def test_POST_register_make_public_immediately_makes_children_public(self, mock_enqueue):
        component = NodeFactory(
            creator=self.user,
            parent=self.project,
            title='Component'
        )
        subproject = ProjectFactory(
            creator=self.user,
            parent=self.project,
            title='Subproject'
        )
        subproject_component = NodeFactory(
            creator=self.user,
            parent=subproject,
            title='Subcomponent'
        )

        res = self.app.post(
            self.project.api_url_for('node_register_template_page_post', template=u'Open-Ended_Registration'),
            self.valid_make_public_payload,
            content_type='application/json',
            auth=self.user.auth
        )
        self.project.reload()
        # Last node directly registered from self.project
        registration = Node.load(self.project.node__registrations[-1])
        assert_true(registration.is_public)
        for node in registration.get_descendants_recursive():
            assert_true(node.is_registration)
            assert_true(node.is_public)
Exemplo n.º 13
0
    def create(self, validated_data):
        inst = self.context["view"].get_object()["self"]
        user = self.context["request"].user
        node_dicts = validated_data["data"]

        changes_flag = False
        for node_dict in node_dicts:
            node = Node.load(node_dict["_id"])
            if not node:
                raise exceptions.NotFound(detail='Node with id "{}" was not found'.format(node_dict["_id"]))
            if not node.has_permission(user, osf_permissions.ADMIN):
                raise exceptions.PermissionDenied(
                    detail="Admin permission on node {} required".format(node_dict["_id"])
                )
            if inst not in node.affiliated_institutions:
                node.add_affiliated_institution(inst, user, save=True)
                changes_flag = True

        if not changes_flag:
            raise RelationshipPostMakesNoChanges

        return {
            "data": list(
                Node.find_by_institutions(inst, Q("is_registration", "eq", False) & Q("is_deleted", "ne", True))
            ),
            "self": inst,
        }
Exemplo n.º 14
0
def add_pointer(auth):
    """Add a single pointer to a node using only JSON parameters

    """
    to_node_id = request.json.get('toNodeID')
    pointer_to_move = request.json.get('pointerID')

    if not (to_node_id and pointer_to_move):
        raise HTTPError(http.BAD_REQUEST)

    pointer = Node.load(pointer_to_move)
    to_node = Node.load(to_node_id)
    try:
        _add_pointers(to_node, [pointer], auth)
    except ValueError:
        raise HTTPError(http.BAD_REQUEST)
Exemplo n.º 15
0
    def create(self, validated_data):
        node = Node.load(validated_data.pop('node', None))
        if not node:
            raise exceptions.NotFound('Unable to find Node with specified id.')

        auth = get_user_auth(self.context['request'])
        if not node.has_permission(auth.user, permissions.ADMIN):
            raise exceptions.PermissionDenied

        primary_file = validated_data.pop('primary_file', None)
        if not primary_file:
            raise exceptions.ValidationError(detail='You must specify a valid primary_file to create a preprint.')

        provider = validated_data.pop('provider', None)
        if not provider:
            raise exceptions.ValidationError(detail='You must specify a valid provider to create a preprint.')

        if PreprintService.find(Q('node', 'eq', node) & Q('provider', 'eq', provider)).count():
            conflict = PreprintService.find_one(Q('node', 'eq', node) & Q('provider', 'eq', provider))
            raise Conflict('Only one preprint per provider can be submitted for a node. Check `meta[existing_resource_id]`.', meta={'existing_resource_id': conflict._id})

        preprint = PreprintService(node=node, provider=provider)
        self.set_field(preprint.set_primary_file, primary_file, auth, save=True)
        preprint.node._has_abandoned_preprint = True
        preprint.node.save()

        return self.update(preprint, validated_data)
Exemplo n.º 16
0
    def create(self, validated_data):
        request = self.context['request']
        user = request.user
        if 'template_from' in validated_data:
            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)
        if is_truthy(request.GET.get('inherit_contributors')) and validated_data['parent'].has_permission(user, 'write'):
            auth = get_user_auth(request)
            parent = validated_data['parent']
            contributors = []
            for contributor in parent.contributors:
                if contributor is not user:
                    contributors.append({
                        'user': contributor,
                        'permissions': parent.get_permissions(contributor),
                        'visible': parent.get_visible(contributor)
                    })
            node.add_contributors(contributors, auth=auth, log=True, save=True)
        return node
Exemplo n.º 17
0
    def test_bulk_creates_children_and_sanitizes_html_logged_in_owner(self):
        title = '<em>Cool</em> <strong>Project</strong>'
        description = 'An <script>alert("even cooler")</script> child'

        res = self.app.post_json_api(self.url, {
            'data': [{
                'type': 'nodes',
                'attributes': {
                    'title': title,
                    'description': description,
                    'category': 'project',
                    'public': True
                }
            }]
        }, auth=self.user.auth, bulk=True)
        child_id = res.json['data'][0]['id']
        assert_equal(res.status_code, 201)
        url = '/{}nodes/{}/'.format(API_BASE, child_id)

        res = self.app.get(url, auth=self.user.auth)
        assert_equal(res.json['data']['attributes']['title'], strip_html(title))
        assert_equal(res.json['data']['attributes']['description'], strip_html(description))
        assert_equal(res.json['data']['attributes']['category'], 'project')

        self.project.reload()
        child_id = res.json['data']['id']
        assert_equal(child_id, self.project.nodes[0]._id)
        assert_equal(Node.load(child_id).logs[0].action, NodeLog.PROJECT_CREATED)
Exemplo n.º 18
0
def main():
    nodes = Node.objects.all()
    total = len(nodes)
    count = 0
    page_size = 1000

    while count < total:
        for node in nodes[count:count+page_size]:
            modm_node = MODMNode.load(node._guid.guid)
            verify_contributors(node, modm_node)
            verify_tags(node, modm_node)
            count += 1

            if count % (total * .001) == 0:
                floatal = float(total)
                flount = float(count)
                print 'Verified nodes {}%'.format((
                    (floatal - flount) / floatal - 1.0) * -100.0)

            # clear out
            modm_node = None
            node = None
            floatal = None
            flount = None

            if count % page_size == 0:
                garbage = gc.collect()
                print '{}:{} Collected {} whole garbages...'.format(count, total,
                                                                    garbage)
    print '\a'
    print '\a'
    print '\a'
    print '\a'
    print '\a'
Exemplo n.º 19
0
    def has_object_permission(self, request, view, obj):
        assert isinstance(obj, dict)
        auth = get_user_auth(request)
        parent_node = obj['self']

        if request.method in permissions.SAFE_METHODS:
            return parent_node.can_view(auth)
        elif request.method == 'DELETE':
            return parent_node.can_edit(auth)
        else:
            has_parent_auth = parent_node.can_edit(auth)
            if not has_parent_auth:
                return False
            pointer_nodes = []
            for pointer in request.data.get('data', []):
                node = Node.load(pointer['id'])
                if not node or node.is_collection:
                    raise exceptions.NotFound(detail='Node with id "{}" was not found'.format(pointer['id']))
                pointer_nodes.append(node)
            has_pointer_auth = True
            for pointer in pointer_nodes:
                if not pointer.can_view(auth):
                    has_pointer_auth = False
                    break
            return has_pointer_auth
Exemplo n.º 20
0
 def has_object_permission(self, request, view, obj):
     if not isinstance(obj, Node):
         obj = Node.load(request.parser_context['kwargs'][view.node_lookup_url_kwarg])
     assert isinstance(obj, Node), 'obj must be a Node'
     if obj.is_registration:
         return request.method in permissions.SAFE_METHODS
     return True
Exemplo n.º 21
0
 def has_object_permission(self, request, view, obj):
     assert isinstance(obj, (Node, DraftRegistration, PrivateLink)), 'obj must be a Node, Draft Registration, or PrivateLink, got {}'.format(obj)
     auth = get_user_auth(request)
     node = Node.load(request.parser_context['kwargs']['node_id'])
     if request.method != 'DELETE' and is_prereg_admin(auth.user):
         return True
     return node.has_permission(auth.user, osf_permissions.ADMIN)
Exemplo n.º 22
0
def project_contributors_post(auth, node, **kwargs):
    """ Add contributors to a node. """

    user_dicts = request.json.get('users')
    node_ids = request.json.get('node_ids')

    if user_dicts is None or node_ids is None:
        raise HTTPError(http.BAD_REQUEST)

    # Prepare input data for `Node::add_contributors`
    contribs = deserialize_contributors(node, user_dicts, auth=auth)
    node.add_contributors(contributors=contribs, auth=auth)
    node.save()

    # Disconnect listener to avoid multiple invite emails
    unreg_contributor_added.disconnect(finalize_invitation)

    for child_id in node_ids:
        child = Node.load(child_id)
        # Only email unreg users once
        child_contribs = deserialize_contributors(
            child, user_dicts, auth=auth
        )
        child.add_contributors(contributors=child_contribs, auth=auth)
        child.save()
    # Reconnect listener
    unreg_contributor_added.connect(finalize_invitation)
    return {'status': 'success'}, 201
Exemplo n.º 23
0
def project_new_post(auth, **kwargs):
    user = auth.user

    data = request.get_json()
    title = strip_html(data.get("title"))
    title = title.strip()
    category = data.get("category", "project")
    template = data.get("template")
    description = strip_html(data.get("description"))
    new_project = {}

    if template:
        original_node = Node.load(template)
        changes = {"title": title, "category": category, "template_node": original_node}

        if description:
            changes["description"] = description

        project = original_node.use_as_template(auth=auth, changes={template: changes})

    else:
        try:
            project = new_node(category, title, user, description)
        except ValidationValueError as e:
            raise HTTPError(http.BAD_REQUEST, data=dict(message_long=e.message))
        new_project = _view_project(project, auth)
    return {"projectUrl": project.url, "newNode": new_project["node"] if new_project else None}, http.CREATED
Exemplo n.º 24
0
def serialize_wiki_settings(user, node_ids):
    """ Format wiki data for project settings page

    :param user: modular odm User object
    :param node_ids: list of parent project ids
    :return: treebeard-formatted data
    """
    items = []

    for node_id in node_ids:
        node = Node.load(node_id)
        assert node, '{} is not a valid Node.'.format(node_id)

        can_read = node.has_permission(user, 'read')
        include_wiki_settings = node.include_wiki_settings(user)

        if not include_wiki_settings:
            continue

        children = []

        if node.admin_public_wiki(user):
            children.append({
                'select': {
                    'title': "permission",
                    'permission':
                        'public'
                        if node.get_addon('wiki').is_publicly_editable
                        else 'private'
                },
            })
        children.extend(serialize_wiki_settings(
            user,
            [
                n._id
                for n in node.nodes
                if n.primary and
                not n.is_deleted
            ]
        ))

        item = {
            'node': {
                'id': node_id,
                'url': node.url if can_read else '',
                'title': node.title if can_read else 'Private Project',
            },
            'children': children,
            'kind': 'folder' if not node.node__parent or not node.parent_node.has_permission(user, 'read') else 'node',
            'nodeType': node.project_or_component,
            'category': node.category,
            'permissions': {
                'view': can_read,
            },
        }

        items.append(item)

    return items
Exemplo n.º 25
0
 def has_object_permission(self, request, view, obj):
     assert isinstance(obj, (Node, User)), 'obj must be a Node or User, got {}'.format(obj)
     auth = get_user_auth(request)
     node = Node.load(request.parser_context['kwargs'][view.node_lookup_url_kwarg])
     if request.method in permissions.SAFE_METHODS:
         return node.is_public or node.can_view(auth)
     else:
         return node.has_permission(auth.user, osf_permissions.ADMIN)
Exemplo n.º 26
0
 def create(self, validated_data):
     request = self.context['request']
     user = request.user
     auth = Auth(user)
     node = self.context['view'].get_node()
     pointer_node = Node.load(validated_data['node']['_id'])
     pointer = node.add_pointer(pointer_node, auth, save=True)
     return pointer
Exemplo n.º 27
0
def format_file_subscription(user, node_id, path, provider):
    """Format a single file event"""
    node = Node.load(node_id)
    wb_path = path.lstrip('/')
    for subscription in get_all_node_subscriptions(user, node):
        if wb_path in getattr(subscription, 'event_name'):
            return serialize_event(user, subscription, node)
    return serialize_event(user, node=node, event_description='file_updated')
Exemplo n.º 28
0
 def has_object_permission(self, request, view, obj):
     assert isinstance(obj, (Node, User, Institution, AddonSettingsBase, DraftRegistration, PrivateLink)), 'obj must be a Node, User, Institution, Draft Registration, PrivateLink, or AddonSettings; got {}'.format(obj)
     auth = get_user_auth(request)
     node = Node.load(request.parser_context['kwargs'][view.node_lookup_url_kwarg])
     if request.method in permissions.SAFE_METHODS:
         return node.is_public or node.can_view(auth)
     else:
         return node.has_permission(auth.user, osf_permissions.ADMIN)
Exemplo n.º 29
0
def search_contributor():
    nid = request.args.get('excludeNode')
    exclude = Node.load(nid).contributors if nid else []
    query = bleach.clean(request.args.get('query', ''), tags=[], strip=True)
    page = int(bleach.clean(request.args.get('page', '0'), tags=[], strip=True))
    size = int(bleach.clean(request.args.get('size', '5'), tags=[], strip=True))
    return search.search_contributor(query=query, page=page, size=size,
                                     exclude=exclude, current_user=get_current_user())
Exemplo n.º 30
0
def node_child_tree(user, node_ids):
    """ Format data to test for node privacy settings for use in treebeard.
    """
    items = []
    for node_id in node_ids:
        node = Node.load(node_id)
        assert node, '{} is not a valid Node.'.format(node_id)

        can_read = node.has_permission(user, 'read')
        can_read_children = node.has_permission_on_children(user, 'read')
        if not can_read and not can_read_children:
            continue

        contributors = []
        for contributor in node.contributors:
            contributors.append({
                'id': contributor._id,
                'is_admin': node.has_permission(contributor, ADMIN),
                'is_confirmed': contributor.is_confirmed
            })

        children = []
        # List project/node if user has at least 'read' permissions (contributor or admin viewer) or if
        # user is contributor on a component of the project/node
        can_write = node.has_permission(user, 'admin')
        children.extend(node_child_tree(
            user,
            [
                n._id
                for n in node.nodes
                if n.primary and
                not n.is_deleted
            ]
        ))
        item = {
            'node': {
                'id': node_id,
                'url': node.url if can_read else '',
                'title': node.title if can_read else 'Private Project',
                'is_public': node.is_public,
                'can_write': can_write,
                'contributors': contributors,
                'visible_contributors': node.visible_contributor_ids,
                'is_admin': node.has_permission(user, ADMIN)
            },
            'user_id': user._id,
            'children': children,
            'kind': 'folder' if not node.node__parent or not node.parent_node.has_permission(user, 'read') else 'node',
            'nodeType': node.project_or_component,
            'category': node.category,
            'permissions': {
                'view': can_read,
            }
        }

        items.append(item)

    return items
Exemplo n.º 31
0
    def perform_destroy(self, instance):
        data = self.request.data['data']
        user = self.request.user
        ids = [datum['id'] for datum in data]
        nodes = []
        for id_ in ids:
            node = Node.load(id_)
            if not node.has_permission(user, osf_permissions.WRITE):
                raise exceptions.PermissionDenied(detail='Write permission on node {} required'.format(id_))
            nodes.append(node)

        for node in nodes:
            node.remove_affiliated_institution(inst=instance['self'], user=user)
            node.save()
Exemplo n.º 32
0
 def has_object_permission(self, request, view, obj):
     assert isinstance(obj, (Node, Pointer)), 'obj must be a Node or Pointer, got {}'.format(obj)
     auth = get_user_auth(request)
     parent_node = Node.load(request.parser_context['kwargs']['node_id'])
     pointer_node = Pointer.load(request.parser_context['kwargs']['pointer_id']).node
     if request.method in permissions.SAFE_METHODS:
         has_parent_auth = parent_node.can_view(auth)
         has_pointer_auth = pointer_node.can_view(auth)
         public = obj.is_public
         has_auth = public or (has_parent_auth and has_pointer_auth)
         return has_auth
     else:
         has_auth = parent_node.can_edit(auth) and pointer_node.can_edit(auth)
         return has_auth
Exemplo n.º 33
0
    def test_register_template_make_public_makes_children_pending_registration(self, mock_enqueue):
        comp1 = NodeFactory(parent=self.node)
        NodeFactory(parent=comp1)

        url = self.node.api_url_for('register_draft_registration', draft_id=self.draft._id)
        res = self.app.post_json(url, self.immediate_payload, auth=self.user.auth)

        assert_equal(res.status_code, http.ACCEPTED)
        self.node.reload()
        # Most recent node is a registration
        reg = Node.load(self.node.node__registrations[-1])
        for node in reg.get_descendants_recursive():
            assert_true(node.is_registration)
            assert_true(node.is_pending_registration)
Exemplo n.º 34
0
def project_remove_contributor(auth, **kwargs):
    """Remove a contributor from a list of nodes.

    :param Auth auth: Consolidated authorization
    :raises: HTTPError(400) if contributors to be removed are not in list
        or if no admin users would remain after changes were applied

    """
    contributor_id = request.get_json()['contributorID']
    node_ids = request.get_json()['nodeIDs']
    contributor = User.load(contributor_id)
    if contributor is None:
        raise HTTPError(http.BAD_REQUEST, data={'message_long': 'Contributor not found.'})
    redirect_url = {}
    parent_id = node_ids[0]
    for node_id in node_ids:
        # Update permissions and order
        node = Node.load(node_id)

        # Forbidden unless user is removing herself
        if not node.has_permission(auth.user, 'admin'):
            if auth.user != contributor:
                raise HTTPError(http.FORBIDDEN)

        if len(node.visible_contributor_ids) == 1 \
                and node.visible_contributor_ids[0] == contributor._id:
            raise HTTPError(http.FORBIDDEN, data={
                'message_long': 'Must have at least one bibliographic contributor'
            })

        nodes_removed = node.remove_contributor(contributor, auth=auth)
        # remove_contributor returns false if there is not one admin or visible contributor left after the move.
        if not nodes_removed:
            raise HTTPError(http.BAD_REQUEST, data={
                'message_long': 'Could not remove contributor.'})

        # On parent node, if user has removed herself from project, alert; redirect to user
        # dashboard if node is private, else node dashboard
        if not node.is_contributor(auth.user) and node_id == parent_id:
            status.push_status_message(
                'You have removed yourself as a contributor from this project',
                kind='success',
                trust=False
            )
            if node.is_public:
                redirect_url = {'redirectUrl': node.url}
            # Else stay on current page
            else:
                redirect_url = {'redirectUrl': web_url_for('dashboard')}
    return redirect_url
Exemplo n.º 35
0
 def create(self, validated_data):
     request = self.context['request']
     user = request.user
     auth = Auth(user)
     node = self.context['view'].get_node()
     pointer_node = Node.load(validated_data['node']['_id'])
     if not pointer_node:
         raise exceptions.NotFound('Node not found.')
     try:
         pointer = node.add_pointer(pointer_node, auth, save=True)
         return pointer
     except ValueError:
         raise exceptions.ValidationError(
             'Pointer to node {} already in list'.format(pointer_node._id))
Exemplo n.º 36
0
 def has_object_permission(self, request, view, obj):
     assert isinstance(
         obj, (Node, User)), 'obj must be User or Node, got {}'.format(obj)
     auth = get_user_auth(request)
     context = request.parser_context['kwargs']
     node = Node.load(context[view.node_lookup_url_kwarg])
     user = User.load(context['user_id'])
     if request.method in permissions.SAFE_METHODS:
         return node.is_public or node.can_view(auth)
     elif request.method == 'DELETE':
         return node.has_permission(
             auth.user, osf_permissions.ADMIN) or auth.user == user
     else:
         return node.has_permission(auth.user, osf_permissions.ADMIN)
Exemplo n.º 37
0
def search_contributor(auth):
    user = auth.user if auth else None
    nid = request.args.get('excludeNode')
    exclude = Node.load(nid).contributors if nid else []
    query = bleach.clean(request.args.get('query', ''), tags=[], strip=True)
    page = int(bleach.clean(request.args.get('page', '0'), tags=[],
                            strip=True))
    size = int(bleach.clean(request.args.get('size', '5'), tags=[],
                            strip=True))
    return search.search_contributor(query=query,
                                     page=page,
                                     size=size,
                                     exclude=exclude,
                                     current_user=user)
Exemplo n.º 38
0
def move_pointers(auth):
    """Move pointer from one node to another node.

    """
    NodeRelation = apps.get_model('osf.NodeRelation')

    from_node_id = request.json.get('fromNodeId')
    to_node_id = request.json.get('toNodeId')
    pointers_to_move = request.json.get('pointerIds')

    if from_node_id is None or to_node_id is None or pointers_to_move is None:
        raise HTTPError(http.BAD_REQUEST)

    from_node = Node.load(from_node_id)
    to_node = Node.load(to_node_id)

    if to_node is None or from_node is None:
        raise HTTPError(http.BAD_REQUEST)

    for pointer_to_move in pointers_to_move:
        try:
            node_relation = NodeRelation.objects.get(_id=pointer_to_move)
        except NodeRelation.DoesNotExist:
            raise HTTPError(http.BAD_REQUEST)

        try:
            from_node.rm_pointer(node_relation, auth=auth)
        except ValueError:
            raise HTTPError(http.BAD_REQUEST)

        from_node.save()
        try:
            _add_pointers(to_node, [node_relation.node], auth)
        except ValueError:
            raise HTTPError(http.BAD_REQUEST)

    return {}, 200, None
Exemplo n.º 39
0
def project_contributors_post(auth, node, **kwargs):
    """ Add contributors to a node. """

    user_dicts = request.json.get('users')
    node_ids = request.json.get('node_ids')
    if node._id in node_ids:
        node_ids.remove(node._id)

    if user_dicts is None or node_ids is None:
        raise HTTPError(http.BAD_REQUEST)

    # Prepare input data for `Node::add_contributors`
    try:
        contribs = deserialize_contributors(node, user_dicts, auth=auth, validate=True)
    except ValidationError as e:
        return {'status': 400, 'message': e.message}, 400

    try:
        node.add_contributors(contributors=contribs, auth=auth)
    except NodeStateError as e:
        return {'status': 400, 'message': e.args[0]}, 400

    node.save()

    # Disconnect listener to avoid multiple invite emails
    unreg_contributor_added.disconnect(finalize_invitation)

    for child_id in node_ids:
        child = Node.load(child_id)
        # Only email unreg users once
        try:
            child_contribs = deserialize_contributors(
                child, user_dicts, auth=auth, validate=True
            )
        except ValidationError as e:
            return {'status': 400, 'message': e.message}, 400

        child.add_contributors(contributors=child_contribs, auth=auth)
        child.save()
    # Reconnect listeners
    unreg_contributor_added.connect(finalize_invitation)

    return {
        'status': 'success',
        'contributors': profile_utils.serialize_contributors(
            node.visible_contributors,
            node=node,
        )
    }, 201
Exemplo n.º 40
0
def get_auth(**kwargs):
    try:
        action = request.args['action']
        node_id = request.args['nid']
        provider_name = request.args['provider']
    except KeyError:
        raise HTTPError(httplib.BAD_REQUEST)

    cookie = request.args.get('cookie')
    view_only = request.args.get('view_only')

    if 'auth_user_id' in session.data:
        user = User.load(session.data['auth_user_id'])
    elif cookie:
        user = User.from_cookie(cookie)
    else:
        user = None

    node = Node.load(node_id)
    if not node:
        raise HTTPError(httplib.NOT_FOUND)

    check_access(node, user, action, key=view_only)

    provider_settings = node.get_addon(provider_name)
    if not provider_settings:
        raise HTTPError(httplib.BAD_REQUEST)

    try:
        credentials = provider_settings.serialize_waterbutler_credentials()
        settings = provider_settings.serialize_waterbutler_settings()
    except exceptions.AddonError:
        log_exception()
        raise HTTPError(httplib.BAD_REQUEST)

    return {
        'auth':
        make_auth(user),
        'credentials':
        credentials,
        'settings':
        settings,
        'callback_url':
        node.api_url_for(
            ('create_waterbutler_log'
             if not node.is_registration else 'registration_callbacks'),
            _absolute=True,
        ),
    }
Exemplo n.º 41
0
def claim_user_form(auth, **kwargs):
    """View for rendering the set password page for a claimed user.

    Must have ``token`` as a querystring argument.

    Renders the set password form, validates it, and sets the user's password.
    """
    uid, pid = kwargs['uid'], kwargs['pid']
    token = request.form.get('token') or request.args.get('token')

    # If user is logged in, redirect to 're-enter password' page
    if auth.logged_in:
        return redirect(
            web_url_for('claim_user_registered', uid=uid, pid=pid,
                        token=token))

    user = User.load(uid)  # The unregistered user
    # user ID is invalid. Unregistered user is not in database
    if not user:
        raise HTTPError(http.BAD_REQUEST)
    # If claim token not valid, redirect to registration page
    if not verify_claim_token(user, token, pid):
        return redirect('/account/')
    unclaimed_record = user.unclaimed_records[pid]
    user.fullname = unclaimed_record['name']
    user.update_guessed_names()
    email = unclaimed_record['email']
    form = SetEmailAndPasswordForm(request.form, token=token)
    if request.method == 'POST':
        if form.validate():
            username, password = form.username.data, form.password.data
            user.register(username=username, password=password)
            # Clear unclaimed records
            user.unclaimed_records = {}
            user.save()
            # Authenticate user and redirect to project page
            response = redirect('/settings/')
            node = Node.load(pid)
            status.push_status_message(
                language.CLAIMED_CONTRIBUTOR.format(node=node), 'success')
            return authenticate(user, response)
        else:
            forms.push_errors_to_status(form.errors)
    return {
        'firstname': user.given_name,
        'email': email if email else '',
        'fullname': user.fullname,
        'form': forms.utils.jsonify(form) if is_json_request() else form,
    }
Exemplo n.º 42
0
def get_or_create_node(node_id, sqlite_db):
    """Gets an OSF node from the sqlite cache.  If not found, pulls the node info from mongo and
    saves it.

    :param node_id: OSF node id (e.g. 'mst3k')
    :param sqlite_db: SQLite3 database handle
    :return: node dict
    """

    if node_id is None:
        return None

    cursor = sqlite_db.cursor()
    query = "SELECT * FROM nodes WHERE id='{}'".format(node_id)
    cursor.execute(query)

    nodes = cursor.fetchall()

    if len(nodes) > 1:
        raise Exception("Multiple nodes found for single node ID")

    if nodes:
        return nodes[0]

    node = Node.load(node_id)
    if node is None:
        return None

    node_public_date = None
    privacy_actions = NodeLog.find(
        Q('node', 'eq', node_id)
        & Q('action', 'in', [NodeLog.MADE_PUBLIC, NodeLog.MADE_PRIVATE])
    ).sort('-date')

    try:
        privacy_action = privacy_actions[0]
    except IndexError as e:
        pass
    else:
        if privacy_action.action == NodeLog.MADE_PUBLIC:
            node_public_date = privacy_action.date.isoformat()
            node_public_date = node_public_date[:-3] + 'Z'

    cursor.execute(
        u'INSERT INTO nodes (id, title, category, made_public_date) VALUES (?, ?, ?, ?)',
        (node_id, getattr(node, 'title'), getattr(node, 'category'), node_public_date)
    )
    sqlite_db.commit()
    return get_or_create_node(node_id, sqlite_db)
Exemplo n.º 43
0
def get_dashboard(auth, nid=None, **kwargs):
    user = auth.user
    if nid is None:
        node = find_dashboard(user)
        dashboard_projects = [rubeus.to_project_root(node, auth, **kwargs)]
        return_value = {'data': dashboard_projects}
    elif nid == ALL_MY_PROJECTS_ID:
        return_value = {'data': get_all_projects_smart_folder(**kwargs)}
    elif nid == ALL_MY_REGISTRATIONS_ID:
        return_value = {'data': get_all_registrations_smart_folder(**kwargs)}
    else:
        node = Node.load(nid)
        dashboard_projects = rubeus.to_project_hgrid(node, auth, **kwargs)
        return_value = {'data': dashboard_projects}
    return return_value
Exemplo n.º 44
0
def migrate(dry_run):
    assert settings.SHARE_URL, 'SHARE_URL must be set to migrate.'
    assert settings.SHARE_API_TOKEN, 'SHARE_API_TOKEN must be set to migrate.'
    targets = get_targets()
    target_count = len(targets)
    count = 0

    logger.info('Preparing to migrate {} registrations.'.format(target_count))
    for registration_id in targets:
        node = Node.load(registration_id)
        count += 1
        logger.info('{}/{} - {}'.format(count, target_count, node._id))
        if not dry_run:
            on_registration_updated(node)
        logger.info('Registration {} was sent to SHARE.'.format(node._id))
Exemplo n.º 45
0
    def has_object_permission(self, request, view, obj):
        assert isinstance(
            obj, (NodeLog)), 'obj must be a NodeLog, got {}'.format(obj)

        if obj._backrefs.get('logged'):
            for node_id in obj._backrefs['logged']['node']['logs']:
                node = Node.load(node_id)
                if ContributorOrPublic().has_object_permission(
                        request, view, node):
                    return True

        if getattr(obj, 'node'):
            return ContributorOrPublic().has_object_permission(
                request, view, obj.node)
        return False
Exemplo n.º 46
0
def search_contributor(auth):
    user = auth.user if auth else None
    nid = request.args.get('excludeNode')
    exclude = Node.load(nid).contributors if nid else []
    # TODO: Determine whether bleach is appropriate for ES payload. Also, inconsistent with website.sanitize.util.strip_html
    query = bleach.clean(request.args.get('query', ''), tags=[], strip=True)
    page = int(bleach.clean(request.args.get('page', '0'), tags=[],
                            strip=True))
    size = int(bleach.clean(request.args.get('size', '5'), tags=[],
                            strip=True))
    return search.search_contributor(query=query,
                                     page=page,
                                     size=size,
                                     exclude=exclude,
                                     current_user=user)
Exemplo n.º 47
0
 def test_make_new_node_settings(self):
     node_settings_document = self.node_settings_documents[0]
     node = Node.load(node_settings_document['owner'])
     user_settings_document = database['addons3usersettings'].find_one(
         {'_id': node_settings_document['user_settings']})
     external_account, user, new = migration.migrate_to_external_account(
         user_settings_document)
     user_settings = migration.make_new_user_settings(user)
     node_settings = migration.make_new_node_settings(
         node, node_settings_document, external_account, user_settings)
     assert ('addons3nodesettings' not in node._backrefs['addons'])
     assert_equal(len(node._backrefs['addons']['s3nodesettings']['owner']),
                  1)
     assert_equal(node._backrefs['addons']['s3nodesettings']['owner'][0],
                  node_settings._id)
Exemplo n.º 48
0
    def get_pointers_to_add_remove(self, pointers, new_pointers):
        diff = relationship_diff(
            current_items={pointer.node._id: pointer
                           for pointer in pointers},
            new_items={val['node']['_id']: val
                       for val in new_pointers})

        nodes_to_add = []
        for node_id in diff['add']:
            node = Node.load(node_id)
            if not node:
                raise exceptions.NotFound(
                    detail='Node with id "{}" was not found'.format(node_id))
            nodes_to_add.append(node)

        return nodes_to_add, diff['remove'].values()
Exemplo n.º 49
0
def load_parent(parent_id):
    parent = Node.load(parent_id)
    if parent is None:
        return None
    parent_info = {}
    if parent is not None and parent.is_public:
        parent_info['title'] = parent.title
        parent_info['url'] = parent.url
        parent_info['is_registration'] = parent.is_registration
        parent_info['id'] = parent._id
    else:
        parent_info['title'] = '-- private project --'
        parent_info['url'] = ''
        parent_info['is_registration'] = None
        parent_info['id'] = None
    return parent_info
Exemplo n.º 50
0
def replace_unclaimed_user_with_registered(user):
    """Listens for the user_registered signal. If unreg_user is stored in the
    session, then the current user is trying to claim themselves as a contributor.
    Replaces the old, unregistered contributor with the newly registered
    account.

    """
    unreg_user_info = session.data.get('unreg_user')
    if unreg_user_info:
        unreg_user = User.load(unreg_user_info['uid'])
        pid = unreg_user_info['pid']
        node = Node.load(pid)
        node.replace_contributor(old=unreg_user, new=user)
        node.save()
        status.push_status_message(
            'Successfully claimed contributor.', kind='success', trust=False)
Exemplo n.º 51
0
def add_folder(**kwargs):
    auth = kwargs['auth']
    user = auth.user
    title = strip_html(request.json.get('title'))
    node_id = request.json.get('node_id')
    node = Node.load(node_id)
    if node.is_deleted or node.is_registration or not node.is_folder:
        raise HTTPError(http.BAD_REQUEST)

    folder = new_folder(title, user)
    folders = [folder]
    try:
        _add_pointers(node, folders, auth)
    except ValueError:
        raise HTTPError(http.BAD_REQUEST)
    return {}, 201, None
Exemplo n.º 52
0
def search_node(auth, **kwargs):
    """

    """
    # Get arguments
    node = Node.load(request.json.get('nodeId'))
    include_public = request.json.get('includePublic')
    size = float(request.json.get('size', '5').strip())
    page = request.json.get('page', 0)
    query = request.json.get('query', '').strip()

    start = (page * size)
    if not query:
        return {'nodes': []}

    # Build ODM query
    title_query = Q('title', 'icontains', query)
    not_deleted_query = Q('is_deleted', 'eq', False)
    visibility_query = Q('contributors', 'eq', auth.user)
    no_folders_query = Q('is_folder', 'eq', False)
    if include_public:
        visibility_query = visibility_query | Q('is_public', 'eq', True)
    odm_query = title_query & not_deleted_query & visibility_query & no_folders_query

    # Exclude current node from query if provided
    if node:
        nin = [node._id] + node.node_ids
        odm_query = (
            odm_query &
            Q('_id', 'nin', nin)
        )

    nodes = Node.find(odm_query)
    count = nodes.count()
    pages = math.ceil(count / size)
    validate_page_num(page, pages)

    return {
        'nodes': [
            _serialize_node_search(each)
            for each in islice(nodes, start, start + size)
            if each.contributors
        ],
        'total': count,
        'pages': pages,
        'page': page
    }
Exemplo n.º 53
0
def node_child_tree(user, node_ids):
    """ Format data to test for node privacy settings for use in treebeard.
    """
    items = []
    for node_id in node_ids:
        node = Node.load(node_id)
        assert node, '{} is not a valid Node.'.format(node_id)

        can_read = node.has_permission(user, 'read')
        can_read_children = node.has_permission_on_children(user, 'read')
        if not can_read and not can_read_children:
            continue
        children = []
        # List project/node if user has at least 'read' permissions (contributor or admin viewer) or if
        # user is contributor on a component of the project/node
        can_write = node.has_permission(user, 'admin')
        children.extend(
            node_child_tree(
                user,
                [n._id for n in node.nodes if n.primary and not n.is_deleted]))
        item = {
            'node': {
                'id': node_id,
                'url': node.url if can_read else '',
                'title': node.title if can_read else 'Private Project',
                'is_public': node.is_public,
                'can_write': can_write
            },
            'user_id':
            user._id,
            'children':
            children,
            'kind':
            'folder' if not node.node__parent
            or not node.parent_node.has_permission(user, 'read') else 'node',
            'nodeType':
            node.project_or_component,
            'category':
            node.category,
            'permissions': {
                'view': can_read,
            }
        }

        items.append(item)

    return items
Exemplo n.º 54
0
def do_migration(logs):
    # ... perform the migration using a list of logs ...
    for log in logs:
        registration_id = log.params.get('registration')
        if registration_id:
            registration = Node.load(registration_id)
            if registration.date_modified < log.date:
                registration.date_modified = log.date
                registration.save()
                logger.info('{} date updated to {}'.format(
                    registration, log.date))
            else:
                logger.info('Date modified is more recent than retraction ' +
                            log._id)
        else:
            logger.warning('No parent registration found for retraction log ' +
                           log._id)
Exemplo n.º 55
0
    def create(self, validated_data):
        request = self.context['request']
        user = request.user
        Node = apps.get_model('osf.Node')
        tag_instances = []
        if 'tags' in validated_data:
            tags = validated_data.pop('tags')
            for tag in tags:
                tag_instance, created = Tag.objects.get_or_create(name=tag, defaults=dict(system=False))
                tag_instances.append(tag_instance)
        if 'template_from' in validated_data:
            template_from = validated_data.pop('template_from')
            template_node = Node.load(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 ValidationError as e:
            raise InvalidModelValueError(detail=e.messages[0])
        if len(tag_instances):
            node.tags.add(*tag_instances)
        if is_truthy(request.GET.get('inherit_contributors')) and validated_data['parent'].has_permission(user, 'write'):
            auth = get_user_auth(request)
            parent = validated_data['parent']
            contributors = []
            for contributor in parent.contributor_set.exclude(user=user):
                contributors.append({
                    'user': contributor.user,
                    'permissions': parent.get_permissions(contributor.user),
                    'visible': contributor.visible
                })
                if not contributor.user.is_registered:
                    node.add_unregistered_contributor(
                        fullname=contributor.user.fullname, email=contributor.user.email, auth=auth,
                        permissions=parent.get_permissions(contributor.user), existing_user=contributor.user
                    )
            node.add_contributors(contributors, auth=auth, log=True, save=True)
        return node
Exemplo n.º 56
0
def fix_log_params(targets):
    """
    Restores params['registration'] field and points params['node'] and original_node fields to the node instead of registration
    """
    logger.info('Migrating registration_cancelled, registration_approved, retraction_cancelled, embargo_approved, embargo_cancelled, and embargo_terminated logs.')
    count = 0
    for log in targets:
        node_id = log.params['node']
        node = Node.load(node_id)
        if node.is_registration:
            log.params['node'] = get_registered_from(node)
            log.params['registration'] = node._id
            log.original_node = log.params['node']
            logger.info('Updating params of log {}. params[node]={}, params[registration]={}, and original_node = {}'.format(log._id, log.params['node'], log.params['registration'], log.original_node))
            log.save()
            count += 1
    logger.info('{} logs migrated'.format(count))
Exemplo n.º 57
0
    def wrapped(payload, *args, **kwargs):
        try:
            user = User.load(payload['user'])
            dest_node = Node.load(payload['destination']['node'])
            source = models.OsfStorageFileNode.get(payload['source'], kwargs['node'])
            dest_parent = models.OsfStorageFolder.get(payload['destination']['parent'], dest_node)

            kwargs.update({
                'user': user,
                'source': source,
                'destination': dest_parent,
                'name': payload['destination']['name'],
            })
        except KeyError:
            raise HTTPError(httplib.BAD_REQUEST)

        return func(*args, **kwargs)
Exemplo n.º 58
0
def add_pointers(auth, node, **kwargs):
    """Add pointers to a node.

    """
    node_ids = request.json.get('nodeIds')

    if not node_ids:
        raise HTTPError(http.BAD_REQUEST)

    nodes = [Node.load(node_id) for node_id in node_ids]

    try:
        _add_pointers(node, nodes, auth)
    except ValueError:
        raise HTTPError(http.BAD_REQUEST)

    return {}
Exemplo n.º 59
0
def new_public_project(email):
    """ Will check to make sure the project that triggered this presend is still public
    before sending the email. It also checks to make sure this is the first (and only)
    new public project email to be sent

    :param email: QueuedMail object, with 'nid' in its data field
    :return: boolean based on whether the email should be sent
    """

    # In line import to prevent circular importing
    from website.models import Node

    node = Node.load(email.data['nid'])

    if not node:
        return False
    public = email.find_sent_of_same_type_and_user()
    return node.is_public and not len(public)
Exemplo n.º 60
0
 def has_object_permission(self, request, view, obj):
     node_link = Pointer.load(
         request.parser_context['kwargs']['node_link_id'])
     node = Node.load(
         request.parser_context['kwargs'][view.node_lookup_url_kwarg])
     auth = get_user_auth(request)
     if request.method == 'DELETE' and node.is_registration:
         raise exceptions.MethodNotAllowed(method=request.method)
     if node.is_collection or node.is_registration:
         raise exceptions.NotFound
     if node_link.node.is_registration:
         if request.method not in permissions.SAFE_METHODS:
             raise exceptions.MethodNotAllowed
     if node not in node_link.parent:
         raise exceptions.NotFound
     if request.method == 'DELETE' and not node.can_edit(auth):
         return False
     return True