Beispiel #1
0
 def test_mfr_url(self):
     user = UserFactory()
     project = ProjectFactory(creator=user)
     comment = CommentFactory()
     assert get_mfr_url(project, 'github') == MFR_SERVER_URL
     assert get_mfr_url(project, 'osfstorage') == project.osfstorage_region.mfr_url
     assert get_mfr_url(comment, 'osfstorage') == MFR_SERVER_URL
Beispiel #2
0
 def test_mfr_url(self):
     user = UserFactory()
     project = ProjectFactory(creator=user)
     comment = CommentFactory()
     assert get_mfr_url(project, 'github') == MFR_SERVER_URL
     assert get_mfr_url(project,
                        'osfstorage') == project.osfstorage_region.mfr_url
     assert get_mfr_url(comment, 'osfstorage') == MFR_SERVER_URL
Beispiel #3
0
    def test_serialize_preprint_file(self, preprint, primary_file):
        req = make_drf_request_with_version(version='2.2')
        data = FileSerializer(primary_file, context={
            'request': req
        }).data['data']
        mfr_url = get_mfr_url(preprint, 'osfstorage')

        # Check render file link with path
        download_link = data['links']['download']
        assert data['links']['render'] == build_expected_render_link(
            mfr_url, download_link, with_version=False)

        # Check render file link with guid
        primary_file.get_guid(create=True)._id
        req = make_drf_request_with_version()
        data = FileSerializer(primary_file, context={
            'request': req
        }).data['data']
        download_link = data['links']['download']
        assert data['links']['render'] == build_expected_render_link(
            mfr_url, download_link, with_version=False)

        # Check html link
        assert data['links']['html'] == '{}{}/files/osfstorage/{}'.format(
            settings.DOMAIN, preprint._id, primary_file._id)
Beispiel #4
0
    def get_render_link(self, obj):
        file = self.context['file']
        mfr_url = get_mfr_url(file.target, file.provider)
        download_url = self.get_download_link(obj)

        return get_file_render_link(mfr_url,
                                    download_url,
                                    version=obj.identifier)
Beispiel #5
0
    def test_load_and_property(self, app, user, file):
        # test_by_id
        res = app.get(
            '/{}files/{}/versions/1/'.format(API_BASE, file._id),
            auth=user.auth,
        )
        assert res.status_code == 200
        assert res.json['data']['id'] == '1'

        mfr_url = get_mfr_url(file, 'osfstorage')

        render_link = res.json['data']['links']['render']
        download_link = res.json['data']['links']['download']
        assert mfr_url in render_link
        assert download_link in render_link
        assert 'revision=1' in render_link

        guid = file.get_guid(create=True)._id
        res = app.get(
            '/{}files/{}/versions/1/'.format(API_BASE, file._id),
            auth=user.auth,
        )
        render_link = res.json['data']['links']['render']
        download_link = res.json['data']['links']['download']
        assert mfr_url in render_link
        assert download_link in render_link
        assert guid in render_link
        assert 'revision=1' in render_link

        # test_read_only
        assert app.put(
            '/{}files/{}/versions/1/'.format(API_BASE, file._id),
            expect_errors=True,
            auth=user.auth,
        ).status_code == 405

        assert app.post(
            '/{}files/{}/versions/1/'.format(API_BASE, file._id),
            expect_errors=True,
            auth=user.auth,
        ).status_code == 405

        assert app.delete(
            '/{}files/{}/versions/1/'.format(API_BASE, file._id),
            expect_errors=True,
            auth=user.auth,
        ).status_code == 405
    def test_load_and_property(self, app, user, file):
        # test_by_id
        res = app.get(
            '/{}files/{}/versions/1/'.format(API_BASE, file._id),
            auth=user.auth,
        )
        assert res.status_code == 200
        assert res.json['data']['id'] == '1'

        mfr_url = get_mfr_url(file, 'osfstorage')

        render_link = res.json['data']['links']['render']
        download_link = res.json['data']['links']['download']
        assert mfr_url in render_link
        assert download_link in render_link
        assert 'revision=1' in render_link

        guid = file.get_guid(create=True)._id
        res = app.get(
            '/{}files/{}/versions/1/'.format(API_BASE, file._id),
            auth=user.auth,
        )
        render_link = res.json['data']['links']['render']
        download_link = res.json['data']['links']['download']
        assert mfr_url in render_link
        assert download_link in render_link
        assert guid in render_link
        assert 'revision=1' in render_link

        # test_read_only
        assert app.put(
            '/{}files/{}/versions/1/'.format(API_BASE, file._id),
            expect_errors=True, auth=user.auth,
        ).status_code == 405

        assert app.post(
            '/{}files/{}/versions/1/'.format(API_BASE, file._id),
            expect_errors=True, auth=user.auth,
        ).status_code == 405

        assert app.delete(
            '/{}files/{}/versions/1/'.format(API_BASE, file._id),
            expect_errors=True, auth=user.auth,
        ).status_code == 405
Beispiel #7
0
    def test_get_file_download_and_render_links(self, file_one, node):
        mfr_link = get_mfr_url(file_one.target, 'osfstorage')

        # file links with path
        download_link = get_file_download_link(file_one)
        assert download_link == '{}download/{}/'.format(
            settings.DOMAIN, file_one._id)
        assert get_file_render_link(
            mfr_link,
            download_link) == build_expected_render_link(mfr_link,
                                                         download_link,
                                                         with_version=False)

        # file versions link with path
        download_link = get_file_download_link(file_one, version=2)
        assert download_link == '{}download/{}/?revision=2'.format(
            settings.DOMAIN, file_one._id)
        assert get_file_render_link(mfr_link, download_link,
                                    version=2) == build_expected_render_link(
                                        mfr_link, download_link)

        # file links with guid
        file_one.get_guid(create=True)
        download_link = get_file_download_link(file_one)
        assert download_link == '{}download/{}/'.format(
            settings.DOMAIN,
            file_one.get_guid()._id)
        assert get_file_render_link(
            mfr_link,
            download_link) == build_expected_render_link(mfr_link,
                                                         download_link,
                                                         with_version=False)

        # file version links with guid
        download_link = get_file_download_link(file_one, version=2)
        assert download_link == '{}download/{}/?revision=2'.format(
            settings.DOMAIN,
            file_one.get_guid()._id)
        assert get_file_render_link(mfr_link, download_link,
                                    version=2) == build_expected_render_link(
                                        mfr_link, download_link)
Beispiel #8
0
def addon_deleted_file(auth, target, error_type='BLAME_PROVIDER', **kwargs):
    """Shows a nice error message to users when they try to view a deleted file
    """
    # Allow file_node to be passed in so other views can delegate to this one
    file_node = kwargs.get('file_node') or TrashedFileNode.load(
        kwargs.get('trashed_id'))

    deleted_by, deleted_on, deleted = None, None, None
    if isinstance(file_node, TrashedFileNode):
        deleted_by = file_node.deleted_by
        deleted_by_guid = file_node.deleted_by._id if deleted_by else None
        deleted_on = file_node.deleted_on.strftime('%c') + ' UTC'
        deleted = deleted_on
        if getattr(file_node, 'suspended', False):
            error_type = 'FILE_SUSPENDED'
        elif file_node.deleted_by is None or (auth.private_key
                                              and auth.private_link.anonymous):
            if file_node.provider == 'osfstorage':
                error_type = 'FILE_GONE_ACTOR_UNKNOWN'
            else:
                error_type = 'BLAME_PROVIDER'
        else:
            error_type = 'FILE_GONE'
    else:
        error_type = 'DONT_KNOW'

    file_path = kwargs.get('path', file_node.path)
    file_name = file_node.name or os.path.basename(file_path)
    file_name_title, file_name_ext = os.path.splitext(file_name)
    provider_full = settings.ADDONS_AVAILABLE_DICT[
        file_node.provider].full_name
    try:
        file_guid = file_node.get_guid()._id
    except AttributeError:
        file_guid = None

    format_params = dict(file_name=markupsafe.escape(file_name),
                         deleted_by=markupsafe.escape(
                             getattr(deleted_by, 'fullname', None)),
                         deleted_on=markupsafe.escape(deleted_on),
                         provider=markupsafe.escape(provider_full),
                         deleted=markupsafe.escape(deleted))
    if deleted_by:
        format_params['deleted_by_guid'] = markupsafe.escape(deleted_by_guid)

    error_msg = ERROR_MESSAGES[error_type].format(**format_params)
    if isinstance(target, AbstractNode):
        error_msg += format_last_known_metadata(auth, target, file_node,
                                                error_type)
        ret = serialize_node(target, auth, primary=True)
        ret.update(rubeus.collect_addon_assets(target))
        ret.update({
            'error':
            error_msg,
            'urls': {
                'render': None,
                'sharejs': None,
                'mfr': get_mfr_url(target, file_node.provider),
                'profile_image': get_profile_image_url(auth.user, 25),
                'files': target.web_url_for('collect_file_trees'),
            },
            'extra': {},
            'size':
            9966699,  # Prevent file from being edited, just in case
            'sharejs_uuid':
            None,
            'file_name':
            file_name,
            'file_path':
            file_path,
            'file_name_title':
            file_name_title,
            'file_name_ext':
            file_name_ext,
            'target_deleted':
            getattr(target, 'is_deleted', False),
            'version_id':
            None,
            'file_guid':
            file_guid,
            'file_id':
            file_node._id,
            'provider':
            file_node.provider,
            'materialized_path':
            file_node.materialized_path or file_path,
            'private':
            getattr(target.get_addon(file_node.provider), 'is_private', False),
            'file_tags':
            list(
                file_node.tags.filter(system=False).values_list(
                    'name', flat=True)) if not file_node._state.adding else
            [],  # Only access ManyRelatedManager if saved
            'allow_comments':
            file_node.provider in settings.ADDONS_COMMENTABLE,
        })
    else:
        # TODO - serialize deleted metadata for future types of deleted file targets
        ret = {'error': error_msg}

    return ret, http_status.HTTP_410_GONE
Beispiel #9
0
 def get_render_link(self, obj):
     if obj.is_file:
         mfr_url = get_mfr_url(obj.target, obj.provider)
         download_url = self.get_download_link(obj)
         return get_file_render_link(mfr_url, download_url)
Beispiel #10
0
    def test_file_serializer(self, file_one, node):
        created = file_one.versions.last().created
        modified = file_one.versions.first().created
        created_tz_aware = created.replace(tzinfo=utc)
        modified_tz_aware = modified.replace(tzinfo=utc)
        new_format = '%Y-%m-%dT%H:%M:%S.%fZ'

        download_base = '/download/{}'
        path = file_one._id
        mfr_url = get_mfr_url(file_one, 'osfstorage')

        # test_date_modified_formats_to_old_format
        req = make_drf_request_with_version(version='2.0')
        data = FileSerializer(file_one, context={'request': req}).data['data']
        assert modified_tz_aware == data['attributes']['date_modified']

        # test_date_modified_formats_to_new_format
        req = make_drf_request_with_version(version='2.2')
        data = FileSerializer(file_one, context={'request': req}).data['data']
        assert datetime.strftime(
            modified, new_format) == data['attributes']['date_modified']

        # test_date_created_formats_to_old_format
        req = make_drf_request_with_version(version='2.0')
        data = FileSerializer(file_one, context={'request': req}).data['data']
        assert created_tz_aware == data['attributes']['date_created']

        # test_date_created_formats_to_new_format
        req = make_drf_request_with_version(version='2.2')
        data = FileSerializer(file_one, context={'request': req}).data['data']
        assert datetime.strftime(
            created, new_format) == data['attributes']['date_created']

        # check download file link with path
        assert download_base.format(path) in data['links']['download']

        # check render file link with path
        assert download_base.format(path) in data['links']['render']
        assert mfr_url in data['links']['render']

        # check download file link with guid
        guid = file_one.get_guid(create=True)._id
        req = make_drf_request_with_version()
        data = FileSerializer(file_one, context={'request': req}).data['data']
        assert download_base.format(guid) in data['links']['download']

        # check render file link with guid
        assert download_base.format(guid) in data['links']['render']
        assert mfr_url in data['links']['render']

        # check html link in file serializer
        assert data['links']['html'] == '{}{}/files/osfstorage/{}'.format(
            settings.DOMAIN, node._id, file_one._id)

        # check download/render/html link for folder
        folder = node.get_addon('osfstorage').get_root().append_folder(
            'Test_folder')
        folder.save()
        req = make_drf_request_with_version(version='2.2')
        data = FileSerializer(folder, context={'request': req}).data['data']
        assert 'render' not in data['links']
        assert 'download' not in data['links']
        assert 'html' not in data['links']
Beispiel #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(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)
Beispiel #12
0
def addon_deleted_file(auth, target, error_type='BLAME_PROVIDER', **kwargs):
    """Shows a nice error message to users when they try to view a deleted file
    """
    # Allow file_node to be passed in so other views can delegate to this one
    file_node = kwargs.get('file_node') or TrashedFileNode.load(kwargs.get('trashed_id'))

    deleted_by, deleted_on = None, None
    if isinstance(file_node, TrashedFileNode):
        deleted_by = file_node.deleted_by
        deleted_by_guid = file_node.deleted_by._id if deleted_by else None
        deleted_on = file_node.deleted_on.strftime('%c') + ' UTC'
        if getattr(file_node, 'suspended', False):
            error_type = 'FILE_SUSPENDED'
        elif file_node.deleted_by is None or (auth.private_key and auth.private_link.anonymous):
            if file_node.provider == 'osfstorage':
                error_type = 'FILE_GONE_ACTOR_UNKNOWN'
            else:
                error_type = 'BLAME_PROVIDER'
        else:
            error_type = 'FILE_GONE'
    else:
        error_type = 'DONT_KNOW'

    file_path = kwargs.get('path', file_node.path)
    file_name = file_node.name or os.path.basename(file_path)
    file_name_title, file_name_ext = os.path.splitext(file_name)
    provider_full = settings.ADDONS_AVAILABLE_DICT[file_node.provider].full_name
    try:
        file_guid = file_node.get_guid()._id
    except AttributeError:
        file_guid = None

    format_params = dict(
        file_name=markupsafe.escape(file_name),
        deleted_by=markupsafe.escape(getattr(deleted_by, 'fullname', None)),
        deleted_on=markupsafe.escape(deleted_on),
        provider=markupsafe.escape(provider_full)
    )
    if deleted_by:
        format_params['deleted_by_guid'] = markupsafe.escape(deleted_by_guid)

    error_msg = ERROR_MESSAGES[error_type].format(**format_params)
    if isinstance(target, AbstractNode):
        error_msg += format_last_known_metadata(auth, target, file_node, error_type)
        ret = serialize_node(target, auth, primary=True)
        ret.update(rubeus.collect_addon_assets(target))
        ret.update({
            'error': error_msg,
            'urls': {
                'render': None,
                'sharejs': None,
                'mfr': get_mfr_url(target, file_node.provider),
                'profile_image': get_profile_image_url(auth.user, 25),
                'files': target.web_url_for('collect_file_trees'),
            },
            'extra': {},
            'size': 9966699,  # Prevent file from being edited, just in case
            'sharejs_uuid': None,
            'file_name': file_name,
            'file_path': file_path,
            'file_name_title': file_name_title,
            'file_name_ext': file_name_ext,
            'target_deleted': getattr(target, 'is_deleted', False),
            'version_id': None,
            'file_guid': file_guid,
            'file_id': file_node._id,
            'provider': file_node.provider,
            'materialized_path': file_node.materialized_path or file_path,
            'private': getattr(target.get_addon(file_node.provider), 'is_private', False),
            'file_tags': list(file_node.tags.filter(system=False).values_list('name', flat=True)) if not file_node._state.adding else [],  # Only access ManyRelatedManager if saved
            'allow_comments': file_node.provider in settings.ADDONS_COMMENTABLE,
        })
    else:
        # TODO - serialize deleted metadata for future types of deleted file targets
        ret = {'error': error_msg}

    return ret, httplib.GONE
Beispiel #13
0
def addon_view_file(auth, node, file_node, version):
    # TODO: resolve circular import issue
    from addons.wiki import settings as wiki_settings

    if isinstance(version, tuple):
        version, error = version
        error = error.replace('\n', '').strip()
    else:
        error = None

    ret = serialize_node(node, auth, primary=True)

    if file_node._id + '-' + version._id not in node.file_guid_to_share_uuids:
        node.file_guid_to_share_uuids[file_node._id + '-' +
                                      version._id] = uuid.uuid4()
        node.save()

    if ret['user']['can_edit']:
        sharejs_uuid = str(node.file_guid_to_share_uuids[file_node._id + '-' +
                                                         version._id])
    else:
        sharejs_uuid = None

    internal_furl = furl.furl(settings.INTERNAL_DOMAIN)
    download_url = furl.furl(request.url.encode('utf-8')).set(
        netloc=internal_furl.netloc,
        args=dict(
            request.args, **{
                'direct': None,
                'mode': 'render',
                'action': 'download',
                'public_file': node.is_public,
            }))

    # Verify file
    verify_result = {'verify_result': '', 'verify_result_title': ''}
    cookie = auth.user.get_or_create_cookie()
    headers = {'content-type': 'application/json'}
    file_data_request = requests.get(file_node.generate_waterbutler_url(
        version=version.identifier, meta='', _internal=True),
                                     headers=headers,
                                     cookies={settings.COOKIE_NAME: cookie})
    if file_data_request.status_code == 200:
        file_data = file_data_request.json().get('data')
        file_info = {
            'provider': file_node.provider,
            'file_id': file_node._id,
            'file_name': file_data['attributes'].get('name'),
            'file_path': file_data['attributes'].get('materialized'),
            'size': file_data['attributes'].get('size'),
            'created': file_data['attributes'].get('created_utc'),
            'modified': file_data['attributes'].get('modified_utc'),
            'version': ''
        }
        if file_node.provider == 'osfstorage':
            file_info['version'] = file_data['attributes']['extra'].get(
                'version')
        verify_result = timestamp.check_file_timestamp(auth.user.id, node,
                                                       file_info)

    mfr_url = get_mfr_url(node, file_node.provider)
    render_url = furl.furl(mfr_url).set(path=['render'],
                                        args={'url': download_url.url})

    ret.update({
        'urls': {
            'render':
            render_url.url,
            'mfr':
            mfr_url,
            'sharejs':
            wiki_settings.SHAREJS_URL,
            'profile_image':
            get_profile_image_url(auth.user, 25),
            'files':
            node.web_url_for('collect_file_trees'),
            'archived_from':
            get_archived_from_url(node, file_node)
            if node.is_registration else None,
        },
        'error':
        error,
        'file_name':
        file_node.name,
        'file_name_title':
        os.path.splitext(file_node.name)[0],
        'file_name_ext':
        os.path.splitext(file_node.name)[1],
        'version_id':
        version.identifier,
        'file_path':
        file_node.path,
        'sharejs_uuid':
        sharejs_uuid,
        'provider':
        file_node.provider,
        'materialized_path':
        file_node.materialized_path,
        'extra':
        version.metadata.get('extra', {}),
        'size':
        version.size if version.size is not None else 9966699,
        'private':
        getattr(node.get_addon(file_node.provider), 'is_private', False),
        'file_tags':
        list(
            file_node.tags.filter(system=False).values_list('name', flat=True))
        if not file_node._state.adding else
        [],  # Only access ManyRelatedManager if saved
        'file_guid':
        file_node.get_guid()._id,
        'file_id':
        file_node._id,
        'allow_comments':
        file_node.provider in settings.ADDONS_COMMENTABLE,
        'checkout_user':
        file_node.checkout._id if file_node.checkout else None,
        'pre_reg_checkout':
        is_pre_reg_checkout(node, file_node),
        'timestamp_verify_result':
        verify_result['verify_result'],
        'timestamp_verify_result_title':
        verify_result['verify_result_title'],
    })

    ret.update(rubeus.collect_addon_assets(node))
    return ret
    def get_render_link(self, obj):
        file = self.context['file']
        mfr_url = get_mfr_url(file.target, file.provider)
        download_url = self.get_download_link(obj)

        return get_file_render_link(mfr_url, download_url, version=obj.identifier)
 def get_render_link(self, obj):
     if obj.is_file:
         mfr_url = get_mfr_url(obj.target, obj.provider)
         download_url = self.get_download_link(obj)
         return get_file_render_link(mfr_url, download_url)
Beispiel #16
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)
Beispiel #17
0
def addon_view_file(auth, node, file_node, version):
    # TODO: resolve circular import issue
    from addons.wiki import settings as wiki_settings

    if isinstance(version, tuple):
        version, error = version
        error = error.replace('\n', '').strip()
    else:
        error = None

    ret = serialize_node(node, auth, primary=True)

    if file_node._id + '-' + version._id not in node.file_guid_to_share_uuids:
        node.file_guid_to_share_uuids[file_node._id + '-' +
                                      version._id] = uuid.uuid4()
        node.save()

    if ret['user']['can_edit']:
        sharejs_uuid = str(node.file_guid_to_share_uuids[file_node._id + '-' +
                                                         version._id])
    else:
        sharejs_uuid = None

    internal_furl = furl.furl(settings.INTERNAL_DOMAIN)
    download_url = furl.furl(request.url).set(netloc=internal_furl.netloc,
                                              args=dict(
                                                  request.args, **{
                                                      'direct':
                                                      None,
                                                      'mode':
                                                      'render',
                                                      'action':
                                                      'download',
                                                      'public_file':
                                                      node.is_public,
                                                  }))

    mfr_url = get_mfr_url(node, file_node.provider)
    render_url = furl.furl(mfr_url).set(path=['render'],
                                        args={'url': download_url.url})

    version_names = BaseFileVersionsThrough.objects.filter(
        basefilenode_id=file_node.id).order_by('-fileversion_id').values_list(
            'version_name', flat=True)

    ret.update({
        'urls': {
            'render':
            render_url.url,
            'mfr':
            mfr_url,
            'sharejs':
            wiki_settings.SHAREJS_URL,
            'profile_image':
            get_profile_image_url(auth.user, 25),
            'files':
            node.web_url_for('collect_file_trees'),
            'archived_from':
            get_archived_from_url(node, file_node)
            if node.is_registration else None,
        },
        'error':
        error,
        'file_name':
        file_node.name,
        'file_name_title':
        os.path.splitext(file_node.name)[0],
        'file_name_ext':
        os.path.splitext(file_node.name)[1],
        'version_id':
        version.identifier,
        'file_path':
        file_node.path,
        'sharejs_uuid':
        sharejs_uuid,
        'provider':
        file_node.provider,
        'materialized_path':
        file_node.materialized_path,
        'extra':
        version.metadata.get('extra', {}),
        'size':
        version.size if version.size is not None else 9966699,
        'private':
        getattr(node.get_addon(file_node.provider), 'is_private', False),
        'file_tags':
        list(
            file_node.tags.filter(system=False).values_list('name', flat=True))
        if not file_node._state.adding else
        [],  # Only access ManyRelatedManager if saved
        'file_guid':
        file_node.get_guid()._id,
        'file_id':
        file_node._id,
        'allow_comments':
        file_node.provider in settings.ADDONS_COMMENTABLE,
        'checkout_user':
        file_node.checkout._id if file_node.checkout else None,
        'version_names':
        list(version_names)
    })

    ret.update(rubeus.collect_addon_assets(node))
    return ret
Beispiel #18
0
def addon_view_file(auth, node, file_node, version):
    # TODO: resolve circular import issue
    from addons.wiki import settings as wiki_settings

    if isinstance(version, tuple):
        version, error = version
        error = error.replace('\n', '').strip()
    else:
        error = None

    ret = serialize_node(node, auth, primary=True)

    if file_node._id + '-' + version._id not in node.file_guid_to_share_uuids:
        node.file_guid_to_share_uuids[file_node._id + '-' + version._id] = uuid.uuid4()
        node.save()

    if ret['user']['can_edit']:
        sharejs_uuid = str(node.file_guid_to_share_uuids[file_node._id + '-' + version._id])
    else:
        sharejs_uuid = None

    internal_furl = furl.furl(settings.INTERNAL_DOMAIN)
    download_url = furl.furl(request.url.encode('utf-8')).set(
        netloc=internal_furl.netloc,
        args=dict(request.args, **{
            'direct': None,
            'mode': 'render',
            'action': 'download',
            'public_file': node.is_public,
        })
    )

    mfr_url = get_mfr_url(node, file_node.provider)
    render_url = furl.furl(mfr_url).set(
        path=['render'],
        args={'url': download_url.url}
    )

    ret.update({
        'urls': {
            'render': render_url.url,
            'mfr': mfr_url,
            'sharejs': wiki_settings.SHAREJS_URL,
            'profile_image': get_profile_image_url(auth.user, 25),
            'files': node.web_url_for('collect_file_trees'),
            'archived_from': get_archived_from_url(node, file_node) if node.is_registration else None,
        },
        'error': error,
        'file_name': file_node.name,
        'file_name_title': os.path.splitext(file_node.name)[0],
        'file_name_ext': os.path.splitext(file_node.name)[1],
        'version_id': version.identifier,
        'file_path': file_node.path,
        'sharejs_uuid': sharejs_uuid,
        'provider': file_node.provider,
        'materialized_path': file_node.materialized_path,
        'extra': version.metadata.get('extra', {}),
        'size': version.size if version.size is not None else 9966699,
        'private': getattr(node.get_addon(file_node.provider), 'is_private', False),
        'file_tags': list(file_node.tags.filter(system=False).values_list('name', flat=True)) if not file_node._state.adding else [],  # Only access ManyRelatedManager if saved
        'file_guid': file_node.get_guid()._id,
        'file_id': file_node._id,
        'allow_comments': file_node.provider in settings.ADDONS_COMMENTABLE,
        'checkout_user': file_node.checkout._id if file_node.checkout else None,
        'pre_reg_checkout': is_pre_reg_checkout(node, file_node),
    })

    ret.update(rubeus.collect_addon_assets(node))
    return ret