Ejemplo n.º 1
0
def resolve_guid(guid, suffix=None):
    """Resolve GUID to corresponding URL and return result of appropriate
    view function. This effectively yields a redirect without changing the
    displayed URL of the page.

    :param guid: GUID value (not the object)
    :param suffix: String to append to GUID route
    :return: Werkzeug response

    """
    # Get prefix; handles API routes
    prefix = request.path.split(guid)[0].rstrip('/')
    # Look up GUID
    guid_object = Guid.load(guid)
    if guid_object:

        # verify that the object is a GuidStoredObject descendant. If a model
        #   was once a descendant but that relationship has changed, it's
        #   possible to have referents that are instances of classes that don't
        #   have a redirect_mode attribute or otherwise don't behave as
        #   expected.
        if not isinstance(guid_object.referent, GuidStoredObject):
            sentry.log_message(
                'Guid `{}` resolved to non-guid object'.format(guid)
            )

            raise HTTPError(http.NOT_FOUND)
        referent = guid_object.referent
        if referent is None:
            logger.error('Referent of GUID {0} not found'.format(guid))
            raise HTTPError(http.NOT_FOUND)
        mode = referent.redirect_mode
        if mode is None:
            raise HTTPError(http.NOT_FOUND)
        url = referent.deep_url if mode == 'proxy' else referent.url
        url = _build_guid_url(url, prefix, suffix)
        # Always redirect API URLs; URL should identify endpoint being called
        if prefix or mode == 'redirect':
            if request.query_string:
                url += '?' + request.query_string
            return redirect(url)
        return proxy_url(url)

    # GUID not found; try lower-cased and redirect if exists
    guid_object_lower = Guid.load(guid.lower())
    if guid_object_lower:
        return redirect(
            _build_guid_url(
                guid.lower(), prefix, suffix
            )
        )

    # GUID not found
    raise HTTPError(http.NOT_FOUND)
Ejemplo n.º 2
0
def resolve_guid(guid, suffix=None):
    """Load GUID by primary key, look up the corresponding view function in the
    routing table, and return the return value of the view function without
    changing the URL.

    :param str guid: GUID primary key
    :param str suffix: Remainder of URL after the GUID
    :return: Return value of proxied view function
    """
    try:
        # Look up
        guid_object = Guid.load(guid)
    except KeyError as e:
        if e.message == 'osfstorageguidfile':  # Used when an old detached OsfStorageGuidFile object is accessed
            raise HTTPError(http.NOT_FOUND)
        else:
            raise e
    if guid_object:

        # verify that the object implements a GuidStoredObject-like interface. If a model
        #   was once GuidStoredObject-like but that relationship has changed, it's
        #   possible to have referents that are instances of classes that don't
        #   have a deep_url attribute or otherwise don't behave as
        #   expected.
        if not hasattr(guid_object.referent, 'deep_url'):
            sentry.log_message(
                'Guid `{}` resolved to an object with no deep_url'.format(guid)
            )
            raise HTTPError(http.NOT_FOUND)
        referent = guid_object.referent
        if referent is None:
            logger.error('Referent of GUID {0} not found'.format(guid))
            raise HTTPError(http.NOT_FOUND)
        if not referent.deep_url:
            raise HTTPError(http.NOT_FOUND)
        if isinstance(referent, PreprintService):
            return send_from_directory(
                os.path.abspath(os.path.join(os.getcwd(), EXTERNAL_EMBER_APPS['preprints']['path'])),
                'index.html'
            )
        url = _build_guid_url(urllib.unquote(referent.deep_url), suffix)
        return proxy_url(url)

    # GUID not found; try lower-cased and redirect if exists
    guid_object_lower = Guid.load(guid.lower())
    if guid_object_lower:
        return redirect(
            _build_guid_url(guid.lower(), suffix)
        )

    # GUID not found
    raise HTTPError(http.NOT_FOUND)
Ejemplo n.º 3
0
def resolve_guid(guid, suffix=None):
    """Load GUID by primary key, look up the corresponding view function in the
    routing table, and return the return value of the view function without
    changing the URL.

    :param str guid: GUID primary key
    :param str suffix: Remainder of URL after the GUID
    :return: Return value of proxied view function
    """
    try:
        # Look up
        guid_object = Guid.load(guid)
    except KeyError as e:
        if e.message == 'osfstorageguidfile':  # Used when an old detached OsfStorageGuidFile object is accessed
            raise HTTPError(http.NOT_FOUND)
        else:
            raise e
    if guid_object:

        # verify that the object implements a GuidStoredObject-like interface. If a model
        #   was once GuidStoredObject-like but that relationship has changed, it's
        #   possible to have referents that are instances of classes that don't
        #   have a deep_url attribute or otherwise don't behave as
        #   expected.
        if not hasattr(guid_object.referent, 'deep_url'):
            sentry.log_message(
                'Guid `{}` resolved to an object with no deep_url'.format(guid)
            )
            raise HTTPError(http.NOT_FOUND)
        referent = guid_object.referent
        if referent is None:
            logger.error('Referent of GUID {0} not found'.format(guid))
            raise HTTPError(http.NOT_FOUND)
        if not referent.deep_url:
            raise HTTPError(http.NOT_FOUND)
        if isinstance(referent, PreprintService):
            return send_from_directory(
                os.path.abspath(os.path.join(os.getcwd(), EXTERNAL_EMBER_APPS['preprints']['path'])),
                'index.html'
            )
        url = _build_guid_url(urllib.unquote(referent.deep_url), suffix)
        return proxy_url(url)

    # GUID not found; try lower-cased and redirect if exists
    guid_object_lower = Guid.load(guid.lower())
    if guid_object_lower:
        return redirect(
            _build_guid_url(guid.lower(), suffix)
        )

    # GUID not found
    raise HTTPError(http.NOT_FOUND)
Ejemplo n.º 4
0
def resolve_guid(guid, suffix=None):
    """Resolve GUID to corresponding URL and return result of appropriate
    view function. This effectively yields a redirect without changing the
    displayed URL of the page.

    :param guid: GUID value (not the object)
    :param suffix: String to append to GUID route
    :return: Werkzeug response

    """
    # Get prefix; handles API routes
    prefix = request.path.split(guid)[0].rstrip('/')

    # Look up GUID
    guid_object = Guid.load(guid)
    if guid_object:

        # verify that the object is a GuidStoredObject descendant. If a model
        #   was once a descendant but that relationship has changed, it's
        #   possible to have referents that are instances of classes that don't
        #   have a redirect_mode attribute or otherwise don't behave as
        #   expected.
        if not isinstance(guid_object.referent, GuidStoredObject):
            sentry.log_message(
                'Guid `{}` resolved to non-guid object'.format(guid))

            raise HTTPError(http.NOT_FOUND)

        referent = guid_object.referent
        if referent is None:
            logger.error('Referent of GUID {0} not found'.format(guid))
            raise HTTPError(http.NOT_FOUND)
        mode = referent.redirect_mode
        if mode is None:
            raise HTTPError(http.NOT_FOUND)
        url = referent.deep_url if mode == 'proxy' else referent.url
        url = _build_guid_url(url, prefix, suffix)
        # Always redirect API URLs; URL should identify endpoint being called
        if prefix or mode == 'redirect':
            if request.query_string:
                url += '?' + request.query_string
            return redirect(url)
        return proxy_url(url)

    # GUID not found; try lower-cased and redirect if exists
    guid_object_lower = Guid.load(guid.lower())
    if guid_object_lower:
        return redirect(_build_guid_url(guid.lower(), prefix, suffix))

    # GUID not found
    raise HTTPError(http.NOT_FOUND)
Ejemplo n.º 5
0
def migrate(targets):
    collections = targets.pop('collections')
    assert len(targets), 'Must specify object to create new guid for'
    assert len(
        targets) == 1, 'Can only create new guid for one object at a time'
    old_id = targets.values()[0]
    node = Node.load(old_id)
    new_guid = Guid.generate(referent=node)
    logger.info('* Created new guid {} for node {}'.format(
        new_guid._id, old_id))
    logger.info('* Preparing to set references.')
    fix_backrefs(node)
    node.reload()
    node._id = new_guid._id
    node.save()
    new_guid.referent = node
    new_guid.save()

    for collection, _id_list in collections.iteritems():
        assert type(
            _id_list
        ) == list, 'Expected type list for collection {} ids, got {}'.format(
            collection, type(_id_list))
        for _id in _id_list:
            logger.info('** Updating {} ({})'.format(_id, collection))
            doc = clean_dict(database[collection].find_one({'_id': _id}))
            replacement = json.loads(
                re.sub(r'\b{}\b'.format(old_id), new_guid._id,
                       json.dumps(doc)))
            database[collection].find_and_modify({'_id': _id},
                                                 {'$set': replacement})
            logger.info('*** Updated {} ({}): \n{}\n'.format(
                _id, collection, replacement))

    logger.info('Successfully migrate {} to {}'.format(old_id, new_guid._id))
Ejemplo n.º 6
0
    def test_restore_file(self):
        root = models.StoredFileNode(
            path='root',
            name='rootfolder',
            is_file=False,
            node=self.node,
            provider='test',
            materialized_path='/long/path/to',
        ).wrapped()
        root.save()

        fn = models.StoredFileNode(
            parent=root._id,
            path='afile',
            name='name',
            is_file=True,
            node=self.node,
            provider='test',
            materialized_path='/long/path/to/name',
        ).wrapped()

        guid = Guid.generate(fn)

        before = fn.to_storage()
        trashed = fn.delete(user=self.user)

        restored = trashed.restore()
        assert_equal(restored.to_storage(), before)

        assert_equal(models.TrashedFileNode.load(trashed._id), None)

        # Guid is repointed
        guid.reload()
        assert_equal(guid.referent, restored)
Ejemplo n.º 7
0
def resolve_target(node, guid):

    if not guid:
        return node
    target = Guid.load(guid)
    if target is None:
        raise HTTPError(http.BAD_REQUEST)
    return target.referent
Ejemplo n.º 8
0
def resolve_target(node, guid):

    if not guid:
        return node
    target = Guid.load(guid)
    if target is None:
        raise HTTPError(http.BAD_REQUEST)
    return target.referent
Ejemplo n.º 9
0
 def test_migrate(self):
     # Sanity check
     for obj in self.legacy_objs:
         guid_obj = Guid.load(obj._id)
         assert_equal(guid_obj.referent, obj)
     nobjs = OsfStorageGuidFile.find().count()
     main(dry_run=False)
     Guid._clear_caches()
     for obj in self.legacy_objs:
         guid_obj = Guid.load(obj._id)
         assert_not_equal(guid_obj.referent, obj)
         assert_true(isinstance(guid_obj.referent, OsfStorageGuidFile))
         assert_equal(guid_obj.referent.node, self.project)
         assert_equal(guid_obj.referent.path, obj.name)
         assert_equal(guid_obj.referent._id, obj._id)
     assert_equal(OsfStorageGuidFile.find().count(), nobjs + 3)
     # Test idempotence
     main(dry_run=False)
     assert_equal(OsfStorageGuidFile.find().count(), nobjs + 3)
Ejemplo n.º 10
0
 def test_migrate(self):
     # Sanity check
     for obj in self.legacy_objs:
         guid_obj = Guid.load(obj._id)
         assert_equal(guid_obj.referent, obj)
     nobjs = OsfStorageGuidFile.find().count()
     main(dry_run=False)
     Guid._clear_caches()
     for obj in self.legacy_objs:
         guid_obj = Guid.load(obj._id)
         assert_not_equal(guid_obj.referent, obj)
         assert_true(isinstance(guid_obj.referent, OsfStorageGuidFile))
         assert_equal(guid_obj.referent.node, self.project)
         assert_equal(guid_obj.referent.path, obj.name)
         assert_equal(guid_obj.referent._id, obj._id)
     assert_equal(OsfStorageGuidFile.find().count(), nobjs + 3)
     # Test idempotence
     main(dry_run=False)
     assert_equal(OsfStorageGuidFile.find().count(), nobjs + 3)
Ejemplo n.º 11
0
def resolve_guid(guid, suffix=None):
    """Load GUID by primary key, look up the corresponding view function in the
    routing table, and return the return value of the view function without
    changing the URL.

    :param str guid: GUID primary key
    :param str suffix: Remainder of URL after the GUID
    :return: Return value of proxied view function
    """
    # Look up GUID
    guid_object = Guid.load(guid)
    if guid_object:

        # verify that the object is a GuidStoredObject descendant. If a model
        #   was once a descendant but that relationship has changed, it's
        #   possible to have referents that are instances of classes that don't
        #   have a redirect_mode attribute or otherwise don't behave as
        #   expected.
        if not isinstance(guid_object.referent, GuidStoredObject):
            sentry.log_message(
                'Guid `{}` resolved to non-guid object'.format(guid)
            )
            raise HTTPError(http.NOT_FOUND)
        referent = guid_object.referent
        if referent is None:
            logger.error('Referent of GUID {0} not found'.format(guid))
            raise HTTPError(http.NOT_FOUND)
        if not referent.deep_url:
            raise HTTPError(http.NOT_FOUND)
        url = _build_guid_url(referent.deep_url, suffix)
        return proxy_url(url)

    # GUID not found; try lower-cased and redirect if exists
    guid_object_lower = Guid.load(guid.lower())
    if guid_object_lower:
        return redirect(
            _build_guid_url(guid.lower(), suffix)
        )

    # GUID not found
    raise HTTPError(http.NOT_FOUND)
Ejemplo n.º 12
0
def resolve_guid(guid, suffix=None):
    """Load GUID by primary key, look up the corresponding view function in the
    routing table, and return the return value of the view function without
    changing the URL.

    :param str guid: GUID primary key
    :param str suffix: Remainder of URL after the GUID
    :return: Return value of proxied view function
    """
    # Look up GUID
    guid_object = Guid.load(guid)
    if guid_object:

        # verify that the object implements a GuidStoredObject-like interface. If a model
        #   was once GuidStoredObject-like but that relationship has changed, it's
        #   possible to have referents that are instances of classes that don't
        #   have a deep_url attribute or otherwise don't behave as
        #   expected.
        if not hasattr(guid_object.referent, 'deep_url'):
            sentry.log_message(
                'Guid `{}` resolved to an object with no deep_url'.format(guid)
            )
            raise HTTPError(http.NOT_FOUND)
        referent = guid_object.referent
        if referent is None:
            logger.error('Referent of GUID {0} not found'.format(guid))
            raise HTTPError(http.NOT_FOUND)
        if not referent.deep_url:
            raise HTTPError(http.NOT_FOUND)
        url = _build_guid_url(urllib.unquote(referent.deep_url), suffix)
        return proxy_url(url)

    # GUID not found; try lower-cased and redirect if exists
    guid_object_lower = Guid.load(guid.lower())
    if guid_object_lower:
        return redirect(
            _build_guid_url(guid.lower(), suffix)
        )

    # GUID not found
    raise HTTPError(http.NOT_FOUND)
Ejemplo n.º 13
0
def migrate():
    for target in targets:
        guid = Guid.load(target['guid'])
        good_sfn = StoredFileNode.load(target['good'])
        bad_sfn = StoredFileNode.load(target['bad'])

        logger.info('Repointing Guid {} referent to StoredFileNode {}'.format(target['guid'], target['good']))
        guid.referent = good_sfn
        guid.save()

        logger.info('Removing StoredFileNode {}'.format(target['bad']))
        StoredFileNode.remove_one(bad_sfn)
Ejemplo n.º 14
0
def restore_file(guid):
    guid_obj = Guid.load(guid)
    trashed_file_node = guid_obj.referent
    assert isinstance(trashed_file_node, TrashedFileNode), 'Guid does not point to a trashedfilenode'
    logger.info('Loaded trashedfilenode {}'.format(trashed_file_node._id))
    try:
        logger.info('Calling restore()')
        trashed_file_node.restore()
    except KeyExistsException:  # File with same name exists; user most likely re-uploaded file
        logger.warn('File with name {} exists. Renaming...'.format(trashed_file_node.name))
        rename_file(trashed_file_node)
        logger.info('Calling restore()')
        trashed_file_node.restore()
    return True
Ejemplo n.º 15
0
def migrate_legacy_obj(legacy_guid_file):
    """Create `OsfStorageGuidFile` object corresponding to provided `OsfGuidFile`
    object, then set the `referent` of the `Guid` object to the newly created
    record.
    """
    logger.info('Migrating legacy Guid {0}'.format(legacy_guid_file._id))
    storage_obj = get_or_create_storage_file(
        legacy_guid_file.node,
        legacy_guid_file.name,
        _id=legacy_guid_file._id,
    )
    guid_obj = Guid.load(legacy_guid_file._id)
    guid_obj.referent = storage_obj
    guid_obj.save()

    return storage_obj
Ejemplo n.º 16
0
def migrate_legacy_obj(legacy_guid_file):
    """Create `OsfStorageGuidFile` object corresponding to provided `OsfGuidFile`
    object, then set the `referent` of the `Guid` object to the newly created
    record.
    """
    logger.info('Migrating legacy Guid {0}'.format(legacy_guid_file._id))
    storage_obj = get_or_create_storage_file(
        legacy_guid_file.node,
        legacy_guid_file.name,
        _id=legacy_guid_file._id,
    )
    guid_obj = Guid.load(legacy_guid_file._id)
    guid_obj.referent = storage_obj
    guid_obj.save()

    return storage_obj
Ejemplo n.º 17
0
    def test_restore_file(self):
        root = models.StoredFileNode(
            path='root',
            name='rootfolder',
            is_file=False,
            node=self.node,
            provider='test',
            materialized_path='/long/path/to',
        ).wrapped()
        root.save()

        fn = models.StoredFileNode(
            parent=root._id,
            path='afile',
            name='name',
            is_file=True,
            node=self.node,
            provider='test',
            materialized_path='/long/path/to/name',
        ).wrapped()

        guid = Guid.generate(fn)

        before = fn.to_storage()
        trashed = fn.delete(user=self.user)

        restored = trashed.restore()
        assert_equal(
            restored.to_storage(),
            before
        )

        assert_equal(models.TrashedFileNode.load(trashed._id), None)

        # Guid is repointed
        guid.reload()
        assert_equal(guid.referent, restored)
Ejemplo n.º 18
0
def resolve_guid(guid, suffix=None):
    """Load GUID by primary key, look up the corresponding view function in the
    routing table, and return the return value of the view function without
    changing the URL.

    :param str guid: GUID primary key
    :param str suffix: Remainder of URL after the GUID
    :return: Return value of proxied view function
    """
    try:
        # Look up
        guid_object = Guid.load(guid)
    except KeyError as e:
        if e.message == 'osfstorageguidfile':  # Used when an old detached OsfStorageGuidFile object is accessed
            raise HTTPError(http.NOT_FOUND)
        else:
            raise e
    if guid_object:
        # verify that the object implements a GuidStoredObject-like interface. If a model
        #   was once GuidStoredObject-like but that relationship has changed, it's
        #   possible to have referents that are instances of classes that don't
        #   have a deep_url attribute or otherwise don't behave as
        #   expected.
        if not hasattr(guid_object.referent, 'deep_url'):
            sentry.log_message(
                'Guid `{}` resolved to an object with no deep_url'.format(
                    guid))
            raise HTTPError(http.NOT_FOUND)
        referent = guid_object.referent
        if referent is None:
            logger.error('Referent of GUID {0} not found'.format(guid))
            raise HTTPError(http.NOT_FOUND)
        if not referent.deep_url:
            raise HTTPError(http.NOT_FOUND)

        # Handle file `/download` shortcut with supported types.
        if suffix and suffix.rstrip('/').lower() == 'download':
            file_referent = None
            if isinstance(referent, PreprintService) and referent.primary_file:
                if not referent.is_published:
                    # TODO: Ideally, permissions wouldn't be checked here.
                    # This is necessary to prevent a logical inconsistency with
                    # the routing scheme - if a preprint is not published, only
                    # admins should be able to know it exists.
                    auth = Auth.from_kwargs(request.args.to_dict(), {})
                    if not referent.node.has_permission(
                            auth.user, permissions.ADMIN):
                        raise HTTPError(http.NOT_FOUND)
                file_referent = referent.primary_file
            elif isinstance(referent, BaseFileNode) and referent.is_file:
                file_referent = referent

            if file_referent:
                # Extend `request.args` adding `action=download`.
                request.args = request.args.copy()
                request.args.update({'action': 'download'})
                # Do not include the `download` suffix in the url rebuild.
                url = _build_guid_url(urllib.unquote(file_referent.deep_url))
                return proxy_url(url)

        # Handle Ember Applications
        if isinstance(referent, PreprintService):
            if referent.provider.domain_redirect_enabled:
                # This route should always be intercepted by nginx for the branded domain,
                # w/ the exception of `<guid>/download` handled above.
                return redirect(referent.absolute_url, http.MOVED_PERMANENTLY)

            return send_from_directory(preprints_dir, 'index.html')
        url = _build_guid_url(urllib.unquote(referent.deep_url), suffix)
        return proxy_url(url)

    # GUID not found; try lower-cased and redirect if exists
    guid_object_lower = Guid.load(guid.lower())
    if guid_object_lower:
        return redirect(_build_guid_url(guid.lower(), suffix))

    # GUID not found
    raise HTTPError(http.NOT_FOUND)