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()
Exemple #2
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)
Exemple #3
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)
Exemple #4
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)
Exemple #5
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_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
    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
Exemple #8
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
Exemple #9
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
    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'])
Exemple #11
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)
Exemple #12
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)
Exemple #13
0
 def get_object(self, *args, **kwargs):
     return DraftRegistration.load(self.kwargs.get('draft_pk'))
Exemple #14
0
 def get_object(self, *args, **kwargs):
     return DraftRegistration.load(self.kwargs.get('draft_pk'))
 def get_resource(self, kwargs):
     resource_id = kwargs.get('draft_id')
     return DraftRegistration.load(resource_id)
Exemple #16
0
 def load_resource(self, context, view):
     return DraftRegistration.load(context['draft_id'])