Exemplo n.º 1
0
    def test_delete_draft_registration_non_admin(self):
        assert_equal(1, DraftRegistration.find().count())
        url = self.node.api_url_for('delete_draft_registration', draft_id=self.draft._id)

        res = self.app.delete(url, auth=self.non_admin.auth, expect_errors=True)
        assert_equal(res.status_code, http.FORBIDDEN)
        assert_equal(1, DraftRegistration.find().count())
Exemplo n.º 2
0
    def test_affiliated_institutions_are_copied_from_user(
            self, app, user, url_draft_registrations, payload):
        project = ProjectFactory(is_public=True, creator=user)
        InstitutionFactory()
        payload['data']['relationships']['branched_from']['data'][
            'id'] = project._id
        res = app.post_json_api(url_draft_registrations,
                                payload,
                                auth=user.auth,
                                expect_errors=True)
        assert res.status_code == 201
        draft_registration = DraftRegistration.load(res.json['data']['id'])
        assert not draft_registration.affiliated_institutions.exists()

        project = ProjectFactory(is_public=True, creator=user)
        payload['data']['relationships']['branched_from']['data'][
            'id'] = project._id
        user.affiliated_institutions.set(Institution.objects.filter(id__lt=3))
        res = app.post_json_api(url_draft_registrations,
                                payload,
                                auth=user.auth,
                                expect_errors=True)
        assert res.status_code == 201
        draft_registration = DraftRegistration.load(res.json['data']['id'])
        assert not draft_registration.affiliated_institutions.all(
        ) == user.affiliated_institutions.all()
Exemplo n.º 3
0
    def test_delete_draft_registration(self):
        assert_equal(1, DraftRegistration.find().count())
        url = self.node.api_url_for('delete_draft_registration', draft_id=self.draft._id)

        res = self.app.delete(url, auth=self.user.auth)
        assert_equal(res.status_code, http.NO_CONTENT)
        assert_equal(0, DraftRegistration.find().count())
Exemplo n.º 4
0
    def test_delete_draft_registration(self):
        assert_equal(1, DraftRegistration.find().count())
        url = self.node.api_url_for('delete_draft_registration',
                                    draft_id=self.draft._id)

        res = self.app.delete(url, auth=self.user.auth)
        assert_equal(res.status_code, http.NO_CONTENT)
        assert_equal(0, DraftRegistration.find().count())
Exemplo n.º 5
0
    def test_only_admin_can_delete_registration(self):
        non_admin = AuthUserFactory()
        assert_equal(1, DraftRegistration.find().count())
        url = self.node.api_url_for('delete_draft_registration',
                                    draft_id=self.draft._id)

        res = self.app.delete(url, auth=non_admin.auth, expect_errors=True)
        assert_equal(res.status_code, http.FORBIDDEN)
        assert_equal(1, DraftRegistration.find().count())
Exemplo n.º 6
0
    def test_delete_draft_registration_approved_and_registration_deleted(self, mock_register_draft):
        self.draft.register(auth=self.auth, save=True)
        self.draft.registered_node.is_deleted = True
        self.draft.registered_node.save()

        assert_equal(1, DraftRegistration.find().count())
        url = self.node.api_url_for('delete_draft_registration', draft_id=self.draft._id)

        res = self.app.delete(url, auth=self.user.auth)
        assert_equal(res.status_code, http.NO_CONTENT)
        assert_equal(0, DraftRegistration.find().count())
    def test_branched_from_must_be_a_node_or_draft_node(self):
        with pytest.raises(DraftRegistrationStateError):
            DraftRegistration.create_from_node(
                user=user,
                node=factories.RegistrationFactory(),
                schema=factories.get_default_metaschema())

        with pytest.raises(DraftRegistrationStateError):
            DraftRegistration.create_from_node(
                user=user,
                node=factories.CollectionFactory(),
                schema=factories.get_default_metaschema())
Exemplo n.º 8
0
    def test_delete_draft_registration_approved_and_registration_deleted(
            self, mock_register_draft):
        self.draft.register(auth=self.auth, save=True)
        self.draft.registered_node.is_deleted = True
        self.draft.registered_node.save()

        assert_equal(1, DraftRegistration.find().count())
        url = self.node.api_url_for('delete_draft_registration',
                                    draft_id=self.draft._id)

        res = self.app.delete(url, auth=self.user.auth)
        assert_equal(res.status_code, http.NO_CONTENT)
        assert_equal(0, DraftRegistration.find().count())
Exemplo n.º 9
0
def delete_draft_registration(auth, node, draft, *args, **kwargs):
    """Permanently delete a draft registration

    :return: None
    :rtype: NoneType
    """
    if draft.registered_node and not draft.registered_node.is_deleted:
        raise HTTPError(
            http.FORBIDDEN,
            data={
                'message_short': 'Can\'t delete draft',
                'message_long': 'This draft has already been registered and cannot be deleted.'
            }
        )
    DraftRegistration.remove_one(draft)
    return None, http.NO_CONTENT
Exemplo n.º 10
0
def delete_draft_registration(auth, node, draft, *args, **kwargs):
    """Permanently delete a draft registration

    :return: None
    :rtype: NoneType
    """
    if draft.registered_node and not draft.registered_node.is_deleted:
        raise HTTPError(
            http.FORBIDDEN,
            data={
                'message_short': 'Can\'t delete draft',
                'message_long': 'This draft has already been registered and cannot be deleted.'
            }
        )
    DraftRegistration.remove_one(draft)
    return None, http.NO_CONTENT
Exemplo n.º 11
0
    def __init__(self, registration, missing_files, *args, **kwargs):
        super(ArchivedFileNotFound, self).__init__(*args, **kwargs)

        self.draft_registration = DraftRegistration.find_one(
            Q('registered_node', 'eq', registration)
        )
        self.missing_files = missing_files
Exemplo n.º 12
0
 def post(self, request, *args, **kwargs):
     try:
         data = json.loads(request.body).get('schema_data', {})
         draft = DraftRegistration.load(self.kwargs.get('draft_pk'))
         draft.update_metadata(data)
         draft.save()
         log_message = list()
         for key, value in data.iteritems():
             comments = data.get(key, {}).get('comments', [])
             for comment in comments:
                 log_message.append('{}: {}'.format(key, comment['value']))
         update_admin_log(
             user_id=request.user.id,
             object_id=draft._id,
             object_repr='Draft Registration',
             message='Comments: <p>{}</p>'.format('</p><p>'.join(log_message)),
             action_flag=COMMENT_PREREG
         )
         return JsonResponse(serializers.serialize_draft_registration(draft))
     except AttributeError:
         raise Http404('{} with id "{}" not found.'.format(
             self.context_object_name.title(),
             self.kwargs.get('draft_pk')
         ))
     except NodeStateError as e:
         return bad_request(request, e)
Exemplo n.º 13
0
def new_draft_registration(auth, node, *args, **kwargs):
    """Create a new draft registration for the node

    :return: Redirect to the new draft's edit page
    :rtype: flask.redirect
    :raises: HTTPError
    """
    if node.is_registration:
        raise HTTPError(http.FORBIDDEN, data={
            'message_short': "Can't create draft",
            'message_long': 'Creating draft registrations on registered projects is not allowed.'
        })
    data = request.values

    schema_name = data.get('schema_name')
    if not schema_name:
        raise HTTPError(
            http.BAD_REQUEST,
            data={
                'message_short': 'Must specify a schema_name',
                'message_long': 'Please specify a schema_name'
            }
        )

    schema_version = data.get('schema_version', 2)

    meta_schema = get_schema_or_fail(Q(name=schema_name, schema_version=int(schema_version)))
    draft = DraftRegistration.create_from_node(
        node,
        user=auth.user,
        schema=meta_schema,
        data={}
    )
    return redirect(node.web_url_for('edit_draft_registration_page', draft_id=draft._id))
Exemplo n.º 14
0
 def post(self, request, *args, **kwargs):
     try:
         data = json.loads(request.body).get('schema_data', {})
         draft = DraftRegistration.load(self.kwargs.get('draft_pk'))
         draft.update_metadata(data)
         draft.save()
         log_message = list()
         for key, value in data.iteritems():
             comments = data.get(key, {}).get('comments', [])
             for comment in comments:
                 log_message.append('{}: {}'.format(key, comment['value']))
         update_admin_log(
             user_id=request.user.id,
             object_id=draft._id,
             object_repr='Draft Registration',
             message='Comments: <p>{}</p>'.format('</p><p>'.join(log_message)),
             action_flag=COMMENT_PREREG
         )
         return JsonResponse(serializers.serialize_draft_registration(draft))
     except AttributeError:
         raise Http404('{} with id "{}" not found.'.format(
             self.context_object_name.title(),
             self.kwargs.get('draft_pk')
         ))
     except NodeStateError as e:
         return bad_request(request, e)
 def make_draft_registration(node=None):
     draft_registration = DraftRegistration.create_from_node(
         user=user,
         schema=get_default_metaschema(),
         data={},
         node=node if node else None
     )
     user.affiliated_institutions.add(institution)
     draft_registration.set_title(title, Auth(user))
     draft_registration.set_description(description, Auth(user))
     draft_registration.category = category
     draft_registration.add_contributor(write_contrib, permissions=WRITE)
     draft_registration.set_node_license(
         {
             'id': license.license_id,
             'year': NEW_YEAR,
             'copyrightHolders': COPYLEFT_HOLDERS
         },
         auth=Auth(user),
         save=True
     )
     draft_registration.add_tag('savanna', Auth(user))
     draft_registration.add_tag('taxonomy', Auth(user))
     draft_registration.set_subjects([[subject._id]], auth=Auth(draft_registration.creator))
     draft_registration.affiliated_institutions.add(institution)
     draft_registration.save()
     return draft_registration
Exemplo n.º 16
0
    def test_can_view_property(self, user):
        project = factories.ProjectFactory(creator=user)

        write_contrib = factories.UserFactory()
        read_contrib = factories.UserFactory()
        non_contrib = factories.UserFactory()

        draft = DraftRegistration.create_from_node(
            user=user,
            node=project,
            schema=factories.get_default_metaschema()
        )
        project.add_contributor(non_contrib, ADMIN, save=True)
        draft.add_contributor(write_contrib, WRITE, save=True)
        draft.add_contributor(read_contrib, READ, save=True)

        assert draft.get_permissions(user) == [READ, WRITE, ADMIN]
        assert draft.get_permissions(write_contrib) == [READ, WRITE]
        assert draft.get_permissions(read_contrib) == [READ]

        assert draft.can_view(Auth(user)) is True
        assert draft.can_view(Auth(write_contrib)) is True
        assert draft.can_view(Auth(read_contrib)) is True

        assert draft.can_view(Auth(non_contrib)) is False
Exemplo n.º 17
0
    def create(self, validated_data):
        node = validated_data.pop('node')
        initiator = validated_data.pop('initiator')
        metadata = validated_data.pop('registration_metadata', None)

        schema_id = validated_data.pop('registration_schema').get('_id')
        schema = get_object_or_error(MetaSchema, schema_id,
                                     self.context['request'])
        if schema.schema_version != LATEST_SCHEMA_VERSION or not schema.active:
            raise exceptions.ValidationError(
                'Registration supplement must be an active schema.')

        draft = DraftRegistration.create_from_node(node=node,
                                                   user=initiator,
                                                   schema=schema)
        reviewer = is_prereg_admin_not_project_admin(self.context['request'],
                                                     draft)

        if metadata:
            try:
                # Required fields are only required when creating the actual registration, not updating the draft.
                draft.validate_metadata(metadata=metadata,
                                        reviewer=reviewer,
                                        required_fields=False)
            except ValidationError as e:
                raise exceptions.ValidationError(e.message)
            draft.update_metadata(metadata)
            draft.save()
        return draft
Exemplo n.º 18
0
def new_draft_registration(auth, node, *args, **kwargs):
    """Create a new draft registration for the node

    :return: Redirect to the new draft's edit page
    :rtype: flask.redirect
    :raises: HTTPError
    """
    if node.is_registration:
        raise HTTPError(http.FORBIDDEN, data={
            'message_short': "Can't create draft",
            'message_long': 'Creating draft registrations on registered projects is not allowed.'
        })
    data = request.values

    schema_name = data.get('schema_name')
    if not schema_name:
        raise HTTPError(
            http.BAD_REQUEST,
            data={
                'message_short': 'Must specify a schema_name',
                'message_long': 'Please specify a schema_name'
            }
        )

    schema_version = data.get('schema_version', 2)

    meta_schema = get_schema_or_fail(schema_name, int(schema_version))
    draft = DraftRegistration.create_from_node(
        node,
        user=auth.user,
        schema=meta_schema,
        data={}
    )
    return redirect(node.web_url_for('edit_draft_registration_page', draft_id=draft._id, _guid=True))
Exemplo n.º 19
0
 def dispatch(self, request, *args, **kwargs):
     self.draft = DraftRegistration.load(self.kwargs.get('draft_pk'))
     if self.draft is None:
         raise Http404('{} with id "{}" not found.'.format(
             self.context_object_name.title(),
             self.kwargs.get('draft_pk')
         ))
     return super(DraftFormView, self).dispatch(request, *args, **kwargs)
Exemplo n.º 20
0
 def dispatch(self, request, *args, **kwargs):
     self.draft = DraftRegistration.load(self.kwargs.get('draft_pk'))
     if self.draft is None:
         raise Http404('{} with id "{}" not found.'.format(
             self.context_object_name.title(),
             self.kwargs.get('draft_pk')
         ))
     return super(DraftFormView, self).dispatch(request, *args, **kwargs)
 def test_create_draft_registration_without_node(self, user):
     data = {'some': 'data'}
     draft = DraftRegistration.create_from_node(
         user=user,
         schema=get_default_metaschema(),
         data=data,
     )
     assert draft.title == 'Untitled'
     assert draft.branched_from.title == 'Untitled'
     assert draft.branched_from.type == 'osf.draftnode'
     assert draft.branched_from.creator == user
     assert len(draft.logs.all()) == 0
Exemplo n.º 22
0
    def test_new_draft_registration_POST(self):
        target = NodeFactory(creator=self.user)
        payload = {
            'schema_name': self.meta_schema.name,
            'schema_version': self.meta_schema.schema_version
        }
        url = target.web_url_for('new_draft_registration')

        res = self.app.post(url, payload, auth=self.user.auth)
        assert_equal(res.status_code, http.FOUND)
        target.reload()
        draft = DraftRegistration.find_one(Q('branched_from', 'eq', target))
        assert_equal(draft.registration_schema, self.meta_schema)
Exemplo n.º 23
0
    def test_new_draft_registration_POST(self):
        target = NodeFactory(creator=self.user)
        payload = {
            'schema_name': self.meta_schema.name,
            'schema_version': self.meta_schema.schema_version
        }
        url = target.web_url_for('new_draft_registration')

        res = self.app.post(url, payload, auth=self.user.auth)
        assert_equal(res.status_code, http.FOUND)
        target.reload()
        draft = DraftRegistration.find_one(Q('branched_from', 'eq', target))
        assert_equal(draft.registration_schema, self.meta_schema)
Exemplo n.º 24
0
    def test_create_draft_with_provider(self, app, user,
                                        url_draft_registrations,
                                        non_default_provider,
                                        payload_with_non_default_provider):
        res = app.post_json_api(url_draft_registrations,
                                payload_with_non_default_provider,
                                auth=user.auth)
        assert res.status_code == 201
        data = res.json['data']
        assert data['relationships']['provider']['links']['related']['href'] == \
               f'{settings.API_DOMAIN}v2/providers/registrations/{non_default_provider._id}/'

        draft = DraftRegistration.load(data['id'])
        assert draft.provider == non_default_provider
Exemplo n.º 25
0
 def test_create_from_node(self):
     proj = NodeFactory()
     user = proj.creator
     schema = MetaSchema.objects.first()
     data = {'some': 'data'}
     draft = DraftRegistration.create_from_node(
         proj,
         user=user,
         schema=schema,
         data=data,
     )
     assert user == draft.initiator
     assert schema == draft.registration_schema
     assert data == draft.registration_metadata
     assert proj == draft.branched_from
Exemplo n.º 26
0
 def test_create_from_node(self):
     proj = NodeFactory()
     user = proj.creator
     schema = MetaSchema.objects.first()
     data = {'some': 'data'}
     draft = DraftRegistration.create_from_node(
         proj,
         user=user,
         schema=schema,
         data=data,
     )
     assert user == draft.initiator
     assert schema == draft.registration_schema
     assert data == draft.registration_metadata
     assert proj == draft.branched_from
    def test_admin_can_create_draft(
            self, app, user, project_public, url_draft_registrations,
            payload, metaschema_open_ended):
        url = '{}embed=branched_from&embed=initiator'.format(url_draft_registrations)
        res = app.post_json_api(url, payload, auth=user.auth)
        assert res.status_code == 201
        data = res.json['data']
        assert metaschema_open_ended._id in data['relationships']['registration_schema']['links']['related']['href']
        assert data['attributes']['registration_metadata'] == {}
        assert data['embeds']['branched_from']['data']['id'] == DraftRegistration.objects.get(_id=data['id']).branched_from._id
        assert data['embeds']['initiator']['data']['id'] == user._id

        draft = DraftRegistration.load(data['id'])
        assert draft.creator == user
        assert draft.has_permission(user, ADMIN) is True
Exemplo n.º 28
0
def bulk_upload_create_draft_registration(auth, initiator, schema, node, data,
                                          provider, row, title, external_id):
    """Create a draft registration from one registration row.
    """
    draft = None
    try:
        draft = DraftRegistration.create_from_node(
            initiator,
            schema,
            node=node,
            data=data,
            provider=provider,
        )
        # Remove all contributors except the initiator if created from an existing node
        if node:
            # Temporarily make initiator contributor visible so that removal of the others can succeed.
            initiator_contributor = draft.contributor_set.get(user=initiator)
            if not initiator_contributor.visible:
                initiator_contributor.visible = True
                initiator_contributor.save()
            contributor_set = draft.contributor_set.all()
            for contributor in contributor_set:
                if initiator != contributor.user:
                    is_removed = draft.remove_contributor(contributor, auth)
                    assert is_removed, 'Removal of an non-initiator contributor from the draft has failed'
            draft.save()
        assert len(draft.contributor_set.all(
        )) == 1, 'Draft should only have one contributor upon creation.'
        # Remove the initiator from the citation list
        initiator_contributor = draft.contributor_set.get(user=initiator)
        initiator_contributor.visible = False
        initiator_contributor.save()
        # Relate the draft to the row
        row.draft_registration = draft
        row.save()
    except Exception as e:
        # If the draft has been created already but failure happens before it is related to the registration row,
        # provide the draft id to the exception object for the caller to delete it after the exception is caught.
        draft_id = draft.id if draft else None
        raise RegistrationBulkCreationRowError(
            row.upload.id,
            row.id,
            title,
            external_id,
            draft_id=draft_id,
            error=repr(e),
        )
    return draft
Exemplo n.º 29
0
def prereg_reminder(email):
    """ Check make sure the draft still exists, has not already received a reminder,
     and has not been submitted.

    :param email: QueuedMail object, with the 'draft_id' in its data field
    :return: boolean based on whether the email should be sent
    """
    # In line import to prevent circular importing
    from osf.models.queued_mail import QueuedMail
    from osf.models import DraftRegistration

    draft_id = email.data['draft_id']
    draft = DraftRegistration.load(draft_id)
    reminders_sent = QueuedMail.objects.filter(data__draft_id=draft_id).exclude(sent_at=None).exists()

    return draft and not draft.deleted and not reminders_sent and not draft.registered_node
Exemplo n.º 30
0
def prereg_reminder(email):
    """ Check make sure the draft still exists, has not already received a reminder,
     and has not been submitted.

    :param email: QueuedMail object, with the 'draft_id' in its data field
    :return: boolean based on whether the email should be sent
    """
    # In line import to prevent circular importing
    from osf.models.queued_mail import QueuedMail
    from osf.models import DraftRegistration

    draft_id = email.data['draft_id']
    draft = DraftRegistration.load(draft_id)
    reminders_sent = QueuedMail.objects.filter(
        data__draft_id=draft_id).exclude(sent_at=None).exists()

    return draft and not draft.deleted and not reminders_sent and not draft.registered_node
Exemplo n.º 31
0
    def test_create_no_project_draft_emails_initiator(self, app, user,
                                                      url_draft_registrations,
                                                      payload):
        post_url = url_draft_registrations + 'embed=branched_from&embed=initiator'

        # Intercepting the send_mail call from website.project.views.contributor.notify_added_contributor
        with mock.patch.object(mails, 'send_mail') as mock_send_mail:
            resp = app.post_json_api(post_url, payload, auth=user.auth)
        assert mock_send_mail.called

        # Python 3.6 does not support mock.call_args.args/kwargs
        # Instead, mock.call_args[0] is positional args, mock.call_args[1] is kwargs
        # (note, this is compatible with later versions)
        mock_send_kwargs = mock_send_mail.call_args[1]
        assert mock_send_kwargs[
            'mail'] == mails.CONTRIBUTOR_ADDED_DRAFT_REGISTRATION
        assert mock_send_kwargs['user'] == user
        assert mock_send_kwargs['node'] == DraftRegistration.load(
            resp.json['data']['id'])
Exemplo n.º 32
0
    def test_create_from_node_draft_node(self, user):
        draft = DraftRegistration.create_from_node(
            user=user,
            schema=factories.get_default_metaschema(),
        )

        assert draft.title == 'Untitled'
        assert draft.description == ''
        assert draft.category == ''
        assert user in draft.contributors.all()
        assert len(draft.contributors.all()) == 1

        assert draft.get_permissions(user) == [READ, WRITE, ADMIN]

        assert draft.node_license is None

        draft_tags = draft.tags.values_list('name', flat=True)
        assert len(draft_tags) == 0
        assert draft.subjects.count() == 0
        assert draft.affiliated_institutions.count() == 0
Exemplo n.º 33
0
 def _create(cls, *args, **kwargs):
     branched_from = kwargs.get('branched_from')
     initiator = kwargs.get('initiator')
     registration_schema = kwargs.get('registration_schema')
     registration_metadata = kwargs.get('registration_metadata')
     if not branched_from:
         project_params = {}
         if initiator:
             project_params['creator'] = initiator
         branched_from = ProjectFactory(**project_params)
     initiator = branched_from.creator
     registration_schema = registration_schema or MetaSchema.find()[0]
     registration_metadata = registration_metadata or {}
     draft = DraftRegistration.create_from_node(
         branched_from,
         user=initiator,
         schema=registration_schema,
         data=registration_metadata,
     )
     return draft
Exemplo n.º 34
0
 def _create(cls, *args, **kwargs):
     branched_from = kwargs.get('branched_from')
     initiator = kwargs.get('initiator')
     registration_schema = kwargs.get('registration_schema')
     registration_metadata = kwargs.get('registration_metadata')
     if not branched_from:
         project_params = {}
         if initiator:
             project_params['creator'] = initiator
         branched_from = ProjectFactory(**project_params)
     initiator = branched_from.creator
     registration_schema = registration_schema or MetaSchema.find()[0]
     registration_metadata = registration_metadata or {}
     draft = DraftRegistration.create_from_node(
         branched_from,
         user=initiator,
         schema=registration_schema,
         data=registration_metadata,
     )
     return draft
Exemplo n.º 35
0
    def create(self, validated_data):
        node = validated_data.pop('node')
        initiator = validated_data.pop('initiator')
        metadata = validated_data.pop('registration_metadata', None)

        schema_id = validated_data.pop('registration_schema').get('_id')
        schema = get_object_or_error(MetaSchema, schema_id)
        if schema.schema_version != LATEST_SCHEMA_VERSION or not schema.active:
            raise exceptions.ValidationError('Registration supplement must be an active schema.')

        draft = DraftRegistration.create_from_node(node=node, user=initiator, schema=schema)
        reviewer = is_prereg_admin_not_project_admin(self.context['request'], draft)

        if metadata:
            try:
                # Required fields are only required when creating the actual registration, not updating the draft.
                draft.validate_metadata(metadata=metadata, reviewer=reviewer, required_fields=False)
            except ValidationError as e:
                raise exceptions.ValidationError(e.message)
            draft.update_metadata(metadata)
            draft.save()
        return draft
Exemplo n.º 36
0
def addon_view_or_download_file(auth, path, provider, **kwargs):
    extras = request.args.to_dict()
    extras.pop('_', None)  # Clean up our url params a bit
    action = extras.get('action', 'view')
    guid = kwargs.get('guid')
    guid_target = getattr(Guid.load(guid), 'referent', None)
    target = guid_target or kwargs.get('node') or kwargs['project']

    provider_safe = markupsafe.escape(provider)
    path_safe = markupsafe.escape(path)

    if not path:
        raise HTTPError(httplib.BAD_REQUEST)

    if hasattr(target, 'get_addon'):

        node_addon = target.get_addon(provider)

        if not isinstance(node_addon, BaseStorageAddon):
            object_text = markupsafe.escape(getattr(target, 'project_or_component', 'this object'))
            raise HTTPError(httplib.BAD_REQUEST, data={
                'message_short': 'Bad Request',
                'message_long': 'The {} add-on containing {} is no longer connected to {}.'.format(provider_safe, path_safe, object_text)
            })

        if not node_addon.has_auth:
            raise HTTPError(httplib.UNAUTHORIZED, data={
                'message_short': 'Unauthorized',
                'message_long': 'The {} add-on containing {} is no longer authorized.'.format(provider_safe, path_safe)
            })

        if not node_addon.complete:
            raise HTTPError(httplib.BAD_REQUEST, data={
                'message_short': 'Bad Request',
                'message_long': 'The {} add-on containing {} is no longer configured.'.format(provider_safe, path_safe)
            })

    savepoint_id = transaction.savepoint()
    file_node = BaseFileNode.resolve_class(provider, BaseFileNode.FILE).get_or_create(target, path)

    # Note: Cookie is provided for authentication to waterbutler
    # it is overriden to force authentication as the current user
    # the auth header is also pass to support basic auth
    version = file_node.touch(
        request.headers.get('Authorization'),
        **dict(
            extras,
            cookie=request.cookies.get(settings.COOKIE_NAME)
        )
    )
    if version is None:
        # File is either deleted or unable to be found in the provider location
        # Rollback the insertion of the file_node
        transaction.savepoint_rollback(savepoint_id)
        if not file_node.pk:
            file_node = BaseFileNode.load(path)

            if file_node.kind == 'folder':
                raise HTTPError(httplib.BAD_REQUEST, data={
                    'message_short': 'Bad Request',
                    'message_long': 'You cannot request a folder from this endpoint.'
                })

            # Allow osfstorage to redirect if the deep url can be used to find a valid file_node
            if file_node and file_node.provider == 'osfstorage' and not file_node.is_deleted:
                return redirect(
                    file_node.target.web_url_for('addon_view_or_download_file', path=file_node._id, provider=file_node.provider)
                )
        return addon_deleted_file(target=target, file_node=file_node, path=path, **kwargs)
    else:
        transaction.savepoint_commit(savepoint_id)

    # TODO clean up these urls and unify what is used as a version identifier
    if request.method == 'HEAD':
        return make_response(('', httplib.FOUND, {
            'Location': file_node.generate_waterbutler_url(**dict(extras, direct=None, version=version.identifier, _internal=extras.get('mode') == 'render'))
        }))

    if action == 'download':
        format = extras.get('format')
        _, extension = os.path.splitext(file_node.name)
        # avoid rendering files with the same format type.
        if format and '.{}'.format(format.lower()) != extension.lower():
            return redirect('{}/export?format={}&url={}'.format(get_mfr_url(target, provider), format, urllib.quote(file_node.generate_waterbutler_url(
                **dict(extras, direct=None, version=version.identifier, _internal=extras.get('mode') == 'render')
            ))))
        return redirect(file_node.generate_waterbutler_url(**dict(extras, direct=None, version=version.identifier, _internal=extras.get('mode') == 'render')))

    if action == 'get_guid':
        draft_id = extras.get('draft')
        draft = DraftRegistration.load(draft_id)
        if draft is None or draft.is_approved:
            raise HTTPError(httplib.BAD_REQUEST, data={
                'message_short': 'Bad Request',
                'message_long': 'File not associated with required object.'
            })
        guid = file_node.get_guid(create=True)
        guid.referent.save()
        return dict(guid=guid._id)

    if len(request.path.strip('/').split('/')) > 1:
        guid = file_node.get_guid(create=True)
        return redirect(furl.furl('/{}/'.format(guid._id)).set(args=extras).url)
    if isinstance(target, Preprint):
        # Redirecting preprint file guids to the preprint detail page
        return redirect('/{}/'.format(target._id))

    return addon_view_file(auth, target, file_node, version)
Exemplo n.º 37
0
def main(guid, creator_username):
    egap_schema = ensure_egap_schema()
    creator, creator_auth = get_creator_auth_header(creator_username)

    egap_assets_path = get_egap_assets(guid, creator_auth)

    # __MACOSX is a hidden file created by the os when zipping
    directory_list = [
        directory for directory in os.listdir(egap_assets_path)
        if directory not in ('egap_assets.zip',
                             '__MACOSX') and not directory.startswith('.')
    ]

    for egap_project_dir in directory_list:
        logger.info('Attempting to import the follow directory: {}'.format(
            egap_project_dir))
        # Node Creation
        try:
            node = create_node_from_project_json(egap_assets_path,
                                                 egap_project_dir,
                                                 creator=creator)
        except Exception as err:
            logger.error(
                'There was an error attempting to create a node from the '
                '{} directory. Attempting to rollback node and contributor creation'
                .format(egap_project_dir))
            logger.error(str(err))
            try:
                rollback_node_from_project_json(egap_assets_path,
                                                egap_project_dir,
                                                creator=creator)
            except Exception as err:
                logger.error(str(err))
            continue

        # Node File Upload
        non_anon_files = os.path.join(egap_assets_path, egap_project_dir,
                                      'data', 'nonanonymous')
        non_anon_metadata = recursive_upload(creator_auth, node,
                                             non_anon_files)

        anon_files = os.path.join(egap_assets_path, egap_project_dir, 'data',
                                  'anonymous')
        if os.path.isdir(anon_files):
            anon_metadata = recursive_upload(creator_auth, node, anon_files)
        else:
            anon_metadata = {}

        # DraftRegistration Metadata Handling
        with open(
                os.path.join(egap_assets_path, egap_project_dir,
                             'registration-schema.json'), 'r') as fp:
            registration_metadata = json.load(fp)

        # add selectedFileName Just so filenames are listed in the UI
        for data in non_anon_metadata:
            data['selectedFileName'] = data['data']['attributes']['name']

        for data in anon_metadata:
            data['selectedFileName'] = data['data']['attributes']['name']

        non_anon_titles = ', '.join(
            [data['data']['attributes']['name'] for data in non_anon_metadata])
        registration_metadata['q37'] = {
            'comments': [],
            'extra': non_anon_metadata,
            'value': non_anon_titles
        }

        anon_titles = ', '.join(
            [data['data']['attributes']['name'] for data in anon_metadata])
        registration_metadata['q38'] = {
            'comments': [],
            'extra': anon_metadata,
            'value': anon_titles
        }

        # DraftRegistration Creation
        draft_registration = DraftRegistration.create_from_node(
            node,
            user=creator,
            schema=egap_schema,
            data=registration_metadata,
        )

        # Registration Creation
        logger.info(
            'Attempting to create a Registration for Project {}'.format(
                node._id))

        # Retrieve EGAP registration date and potential embargo go-public date
        if registration_metadata.get('q4'):
            egap_registration_date_string = registration_metadata['q4'][
                'value']
            egap_registration_date = dt.strptime(
                egap_registration_date_string,
                '%m/%d/%Y - %H:%M').replace(tzinfo=pytz.UTC)
        else:
            logger.error(
                'DraftRegistration associated with Project {} '
                'does not have a valid registration date in registration_metadata'
                .format(node._id))
            continue

        if registration_metadata.get('q12'):
            if bool(registration_metadata['q12'].get('value')):
                egap_embargo_public_date_string = registration_metadata['q12'][
                    'value']
                egap_embargo_public_date = dt.strptime(
                    egap_embargo_public_date_string,
                    '%m/%d/%y').replace(tzinfo=pytz.UTC)
            else:
                egap_embargo_public_date = None
        else:
            egap_embargo_public_date = None

        sanction_type = 'RegistrationApproval'
        if egap_embargo_public_date and (egap_embargo_public_date >
                                         dt.today().replace(tzinfo=pytz.UTC)):
            sanction_type = 'Embargo'

        logger.info('Attempting to register {} silently'.format(node._id))
        try:
            register_silently(draft_registration, Auth(creator), sanction_type,
                              egap_registration_date, egap_embargo_public_date)
        except Exception as err:
            logger.error(
                'Unexpected error raised when attempting to silently register '
                'project {}. Continuing...'.format(node._id))
            logger.info(str(err))
            continue

        # Update contributors on project to Admin
        contributors = node.contributor_set.all()
        for contributor in contributors:
            if contributor.user == creator:
                pass
            else:
                node.update_contributor(contributor.user,
                                        permission=ADMIN,
                                        visible=True,
                                        auth=Auth(creator),
                                        save=True)

    shutil.rmtree(egap_assets_path)
Exemplo n.º 38
0
 def get_object(self, *args, **kwargs):
     return DraftRegistration.load(self.kwargs.get('draft_pk'))
Exemplo n.º 39
0
def draft_reg_util():
    DraftRegistration.remove()
    return MetaSchema.objects.get(name='Prereg Challenge', schema_version=2)
Exemplo n.º 40
0
    def test_create_from_node_existing(self, user):
        node = factories.ProjectFactory(creator=user)

        member = factories.AuthUserFactory()
        osf_group = factories.OSFGroupFactory(creator=user)
        osf_group.make_member(member, auth=Auth(user))
        node.add_osf_group(osf_group, ADMIN)

        write_contrib = factories.AuthUserFactory()
        subject = factories.SubjectFactory()
        institution = factories.InstitutionFactory()
        user.affiliated_institutions.add(institution)

        title = 'A Study of Elephants'
        description = 'Loxodonta africana'
        category = 'Methods and Materials'

        node.set_title(title, Auth(user))
        node.set_description(description, Auth(user))
        node.category = category
        node.add_contributor(write_contrib, permissions=WRITE)

        GPL3 = NodeLicense.objects.get(license_id='GPL3')
        NEW_YEAR = '2014'
        COPYLEFT_HOLDERS = ['Richard Stallman']
        node.set_node_license(
            {
                'id': GPL3.license_id,
                'year': NEW_YEAR,
                'copyrightHolders': COPYLEFT_HOLDERS
            },
            auth=Auth(user),
            save=True
        )
        node.add_tag('savanna', Auth(user))
        node.add_tag('taxonomy', Auth(user))
        node.set_subjects([[subject._id]], auth=Auth(node.creator))
        node.affiliated_institutions.add(institution)
        node.save()

        draft = DraftRegistration.create_from_node(
            node=node,
            user=user,
            schema=factories.get_default_metaschema(),
        )

        # Assert existing metadata-like node attributes are copied to the draft
        assert draft.title == title
        assert draft.description == description
        assert draft.category == category
        assert user in draft.contributors.all()
        assert write_contrib in draft.contributors.all()
        assert member not in draft.contributors.all()
        assert not draft.has_permission(member, 'read')

        assert draft.get_permissions(user) == [READ, WRITE, ADMIN]
        assert draft.get_permissions(write_contrib) == [READ, WRITE]

        assert draft.node_license.license_id == GPL3.license_id
        assert draft.node_license.name == GPL3.name
        assert draft.node_license.copyright_holders == COPYLEFT_HOLDERS

        draft_tags = draft.tags.values_list('name', flat=True)
        assert 'savanna' in draft_tags
        assert 'taxonomy' in draft_tags
        assert subject in draft.subjects.all()
        assert institution in draft.affiliated_institutions.all()
        assert draft.branched_from == node
Exemplo n.º 41
0
 def get_object(self, *args, **kwargs):
     return DraftRegistration.load(self.kwargs.get('draft_pk'))
Exemplo n.º 42
0
def check_access(node, auth, action, cas_resp):
    """Verify that user can perform requested action on resource. Raise appropriate
    error code if action cannot proceed.
    """
    permission = permission_map.get(action, None)
    if permission is None:
        raise HTTPError(httplib.BAD_REQUEST)

    if cas_resp:
        if permission == 'read':
            if node.is_public:
                return True
            required_scope = oauth_scopes.CoreScopes.NODE_FILE_READ
        else:
            required_scope = oauth_scopes.CoreScopes.NODE_FILE_WRITE
        if not cas_resp.authenticated \
           or required_scope not in oauth_scopes.normalize_scopes(cas_resp.attributes['accessTokenScope']):
            raise HTTPError(httplib.FORBIDDEN)

    if permission == 'read':
        if node.can_view(auth):
            return True
        # The user may have admin privileges on a parent node, in which
        # case they should have read permissions
        if node.is_registration and node.registered_from.can_view(auth):
            return True
    if permission == 'write' and node.can_edit(auth):
        return True

    # Users attempting to register projects with components might not have
    # `write` permissions for all components. This will result in a 403 for
    # all `copyto` actions as well as `copyfrom` actions if the component
    # in question is not public. To get around this, we have to recursively
    # check the node's parent node to determine if they have `write`
    # permissions up the stack.
    # TODO(hrybacki): is there a way to tell if this is for a registration?
    # All nodes being registered that receive the `copyto` action will have
    # `node.is_registration` == True. However, we have no way of telling if
    # `copyfrom` actions are originating from a node being registered.
    # TODO This is raise UNAUTHORIZED for registrations that have not been archived yet
    if action == 'copyfrom' or (action == 'copyto' and node.is_registration):
        parent = node.parent_node
        while parent:
            if parent.can_edit(auth):
                return True
            parent = parent.parent_node

    # Users with the PREREG_ADMIN_TAG should be allowed to download files
    # from prereg challenge draft registrations.
    try:
        prereg_schema = MetaSchema.find_one(
            Q('name', 'eq', 'Prereg Challenge') &
            Q('schema_version', 'eq', 2)
        )
        allowed_nodes = [node] + node.parents
        prereg_draft_registration = DraftRegistration.find(
            Q('branched_from', 'in', [n for n in allowed_nodes]) &
            Q('registration_schema', 'eq', prereg_schema)
        )
        if action == 'download' and \
                    auth.user is not None and \
                    prereg_draft_registration.count() > 0 and \
                    settings.PREREG_ADMIN_TAG in auth.user.system_tags:
            return True
    except NoResultsFound:
        pass

    raise HTTPError(httplib.FORBIDDEN if auth.user else httplib.UNAUTHORIZED)
Exemplo n.º 43
0
def draft_reg_util():
    DraftRegistration.remove()
    return MetaSchema.objects.get(name='Prereg Challenge', schema_version=2)
Exemplo n.º 44
0
def draft_reg_util():
    DraftRegistration.remove()
    return MetaSchema.find_one(
        Q('name', 'eq', 'Prereg Challenge') & Q('schema_version', 'eq', 2))
Exemplo n.º 45
0
def main(guid, creator_username):
    egap_schema = ensure_egap_schema()
    creator, creator_auth = get_creator_auth_header(creator_username)

    egap_assets_path = get_egap_assets(guid, creator_auth)

    # __MACOSX is a hidden file created by the os when zipping
    directory_list = [
        directory for directory in os.listdir(egap_assets_path)
        if directory not in ('egap_assets.zip', '__MACOSX')
    ]

    for epag_project_dir in directory_list:
        node = create_node_from_project_json(egap_assets_path,
                                             epag_project_dir,
                                             creator=creator)

        non_anon_files = os.path.join(egap_assets_path, epag_project_dir,
                                      'data', 'nonanonymous')
        non_anon_metadata = recursive_upload(creator_auth, node,
                                             non_anon_files)

        anon_files = os.path.join(egap_assets_path, epag_project_dir, 'data',
                                  'anonymous')
        if os.path.isdir(anon_files):
            anon_metadata = recursive_upload(creator_auth, node, anon_files)
        else:
            anon_metadata = {}

        with open(
                os.path.join(egap_assets_path, epag_project_dir,
                             'registration-schema.json'), 'r') as fp:
            registration_metadata = json.load(fp)

        # add selectedFileName Just so filenames are listed in the UI
        for data in non_anon_metadata:
            data['selectedFileName'] = data['data']['attributes']['name']

        for data in anon_metadata:
            data['selectedFileName'] = data['data']['attributes']['name']

        non_anon_titles = ', '.join(
            [data['data']['attributes']['name'] for data in non_anon_metadata])
        registration_metadata['q37'] = {
            'comments': [],
            'extra': non_anon_metadata,
            'value': non_anon_titles
        }

        anon_titles = ', '.join(
            [data['data']['attributes']['name'] for data in anon_metadata])
        registration_metadata['q38'] = {
            'comments': [],
            'extra': anon_metadata,
            'value': anon_titles
        }

        DraftRegistration.create_from_node(
            node,
            user=creator,
            schema=egap_schema,
            data=registration_metadata,
        )

    shutil.rmtree(egap_assets_path)
Exemplo n.º 46
0
def addon_view_or_download_file(auth, path, provider, **kwargs):
    extras = request.args.to_dict()
    extras.pop('_', None)  # Clean up our url params a bit
    action = extras.get('action', 'view')
    guid = kwargs.get('guid')
    guid_target = getattr(Guid.load(guid), 'referent', None)
    target = guid_target or kwargs.get('node') or kwargs['project']

    provider_safe = markupsafe.escape(provider)
    path_safe = markupsafe.escape(path)

    if not path:
        raise HTTPError(http_status.HTTP_400_BAD_REQUEST)

    if hasattr(target, 'get_addon'):

        node_addon = target.get_addon(provider)

        if not isinstance(node_addon, BaseStorageAddon):
            object_text = markupsafe.escape(
                getattr(target, 'project_or_component', 'this object'))
            raise HTTPError(
                http_status.HTTP_400_BAD_REQUEST,
                data={
                    'message_short':
                    'Bad Request',
                    'message_long':
                    'The {} add-on containing {} is no longer connected to {}.'
                    .format(provider_safe, path_safe, object_text)
                })

        if not node_addon.has_auth:
            raise HTTPError(
                http_status.HTTP_401_UNAUTHORIZED,
                data={
                    'message_short':
                    'Unauthorized',
                    'message_long':
                    'The {} add-on containing {} is no longer authorized.'.
                    format(provider_safe, path_safe)
                })

        if not node_addon.complete:
            raise HTTPError(
                http_status.HTTP_400_BAD_REQUEST,
                data={
                    'message_short':
                    'Bad Request',
                    'message_long':
                    'The {} add-on containing {} is no longer configured.'.
                    format(provider_safe, path_safe)
                })

    savepoint_id = transaction.savepoint()
    file_node = BaseFileNode.resolve_class(provider,
                                           BaseFileNode.FILE).get_or_create(
                                               target, path)

    # Note: Cookie is provided for authentication to waterbutler
    # it is overriden to force authentication as the current user
    # the auth header is also pass to support basic auth
    version = file_node.touch(
        request.headers.get('Authorization'),
        **dict(extras, cookie=request.cookies.get(settings.COOKIE_NAME)))
    if version is None:
        # File is either deleted or unable to be found in the provider location
        # Rollback the insertion of the file_node
        transaction.savepoint_rollback(savepoint_id)
        if not file_node.pk:
            file_node = BaseFileNode.load(path)

            if not file_node:
                raise HTTPError(http_status.HTTP_404_NOT_FOUND,
                                data={
                                    'message_short':
                                    'File Not Found',
                                    'message_long':
                                    'The requested file could not be found.'
                                })

            if file_node.kind == 'folder':
                raise HTTPError(
                    http_status.HTTP_400_BAD_REQUEST,
                    data={
                        'message_short':
                        'Bad Request',
                        'message_long':
                        'You cannot request a folder from this endpoint.'
                    })

            # Allow osfstorage to redirect if the deep url can be used to find a valid file_node
            if file_node.provider == 'osfstorage' and not file_node.is_deleted:
                return redirect(
                    file_node.target.web_url_for('addon_view_or_download_file',
                                                 path=file_node._id,
                                                 provider=file_node.provider))
        return addon_deleted_file(target=target,
                                  file_node=file_node,
                                  path=path,
                                  **kwargs)
    else:
        transaction.savepoint_commit(savepoint_id)

    # TODO clean up these urls and unify what is used as a version identifier
    if request.method == 'HEAD':
        return make_response(('', http_status.HTTP_302_FOUND, {
            'Location':
            file_node.generate_waterbutler_url(
                **dict(extras,
                       direct=None,
                       version=version.identifier,
                       _internal=extras.get('mode') == 'render'))
        }))

    if action == 'download':
        format = extras.get('format')
        _, extension = os.path.splitext(file_node.name)
        # avoid rendering files with the same format type.
        if format and '.{}'.format(format.lower()) != extension.lower():
            return redirect('{}/export?format={}&url={}'.format(
                get_mfr_url(target, provider), format,
                quote(
                    file_node.generate_waterbutler_url(
                        **dict(extras,
                               direct=None,
                               version=version.identifier,
                               _internal=extras.get('mode') == 'render')))))
        return redirect(
            file_node.generate_waterbutler_url(
                **dict(extras,
                       direct=None,
                       version=version.identifier,
                       _internal=extras.get('mode') == 'render')))

    if action == 'get_guid':
        draft_id = extras.get('draft')
        draft = DraftRegistration.load(draft_id)
        if draft is None or draft.is_approved:
            raise HTTPError(http_status.HTTP_400_BAD_REQUEST,
                            data={
                                'message_short':
                                'Bad Request',
                                'message_long':
                                'File not associated with required object.'
                            })
        guid = file_node.get_guid(create=True)
        guid.referent.save()
        return dict(guid=guid._id)

    if len(request.path.strip('/').split('/')) > 1:
        guid = file_node.get_guid(create=True)
        return redirect(
            furl.furl('/{}/'.format(guid._id)).set(args=extras).url)
    if isinstance(target, Preprint):
        # Redirecting preprint file guids to the preprint detail page
        return redirect('/{}/'.format(target._id))

    return addon_view_file(auth, target, file_node, version)
Exemplo n.º 47
0
def draft_reg_util():
    DraftRegistration.remove()
    return MetaSchema.find_one(
        Q('name', 'eq', 'Prereg Challenge') &
        Q('schema_version', 'eq', 2)
    )