Esempio n. 1
0
    async def intra_move(
            self,  # type: ignore
            dest_provider: 'DropboxProvider',
            src_path: WaterButlerPath,
            dest_path: WaterButlerPath
    ) -> typing.Tuple[BaseDropboxMetadata, bool]:
        if dest_path.full_path.lower() == src_path.full_path.lower():
            # Dropbox does not support changing the casing in a file name
            raise exceptions.InvalidPathError(
                'In Dropbox to change case, add or subtract other characters.')

        try:
            data = await self.dropbox_request(
                self.build_url('files', 'move'),
                {
                    'from_path': src_path.full_path.rstrip('/'),
                    'to_path': dest_path.full_path.rstrip('/'),
                },
                expects=(200, 201, 409),
                throws=exceptions.IntraMoveError,
            )
        except DropboxNamingConflictError:
            await dest_provider.delete(dest_path)
            resp, _ = await self.intra_move(dest_provider, src_path, dest_path)
            return resp, False

        dest_folder = dest_provider.folder
        if data['.tag'] == 'file':
            return DropboxFileMetadata(data, dest_folder), True
        folder = DropboxFolderMetadata(data, dest_folder)
        folder.children = [
            item for item in await dest_provider.metadata(dest_path)
        ]  # type: ignore
        return folder, True
Esempio n. 2
0
    async def validate_v1_path(self, path, **kwargs):
        """Take a string path from the url and attempt to map it to an entity within this article.
        If the entity is found, returns a FigsharePath object with the entity identifiers included.
        Otherwise throws a 404 Not Found. Will also assert that the entity type inferred from the
        path matches the type of the entity at that url.

        :param str path: entity path from the v1 API
        :rtype FigsharePath:
        """
        if path == '/':
            return FigsharePath('/', _ids=('', ), folder=True, is_public=False)

        path_parts = self._path_split(path)
        if len(path_parts) != 2:
            raise exceptions.InvalidPathError(
                '{} is not a valid Figshare path.'.format(path))

        file_id = path_parts[1]

        resp = await self.make_request(
            'GET',
            self.build_url(False, *self.root_path_parts, 'files', file_id),
            expects=(200, ),
        )
        file_json = await resp.json()
        return FigsharePath('/' + file_json['name'],
                            _ids=('', file_id),
                            folder=False,
                            is_public=False)
Esempio n. 3
0
 def generic_path_validation(cls, path: str) -> None:
     """Validates a WaterButler specific path, e.g. /folder/file.txt, /folder/
     :param str path: WaterButler path
     """
     if not path:
         raise exceptions.InvalidPathError('Must specify path')
     if not path.startswith('/'):
         raise exceptions.InvalidPathError('Invalid path \'{}\' specified'.format(path))
     if '//' in path:
         raise exceptions.InvalidPathError('Invalid path \'{}\' specified'.format(path))
     # Do not allow path manipulation via shortcuts, e.g. '..'
     absolute_path = os.path.abspath(path)
     if not path == '/' and path.endswith('/'):
         absolute_path += '/'
     if not path == absolute_path:
         raise exceptions.InvalidPathError('Invalid path \'{}\' specified'.format(absolute_path))
Esempio n. 4
0
    async def validate_path(self, path, **kwargs):
        """Take a string path from the url and attempt to map it to an entity within this article.
        If the entity is found, returns a FigsharePath object with the entity identifiers included.
        Otherwise returns a FigsharePath with empty identifiers.

        :param str path: identifier path URN as passed through the v0 API
        :rtype FigsharePath:

        Quirks:

        * v0 may pass an identifier_path whose last part is a name and not an identifier, in the
          case of file/folder creation calls.

        * validate_path validates parent and returns a FigsharePath as accurately as possible.
        """
        if path == '/':
            return FigsharePath('/', _ids=('', ), folder=True, is_public=False)

        path_parts = self._path_split(path)
        if len(path_parts) != 2:
            raise exceptions.InvalidPathError(
                '{} is not a valid Figshare path.'.format(path))

        file_id = path_parts[1]

        resp = await self.make_request(
            'GET',
            self.build_url(False, *self.root_path_parts, 'files', file_id),
            expects=(
                200,
                404,
            ),
        )
        if resp.status == 200:
            file_json = await resp.json()
            file_name = file_json['name']
            return FigsharePath('/' + file_name,
                                _ids=('', file_id),
                                folder=False,
                                is_public=False)

        # catch for create file in article root
        await resp.release()
        return FigsharePath('/' + file_id,
                            _ids=('', ''),
                            folder=False,
                            is_public=False)
Esempio n. 5
0
    def intra_move(self, dest_provider, src_path, dest_path):
        if dest_path.full_path.lower() == src_path.full_path.lower():
            # Dropbox does not support changing the casing in a file name
            raise exceptions.InvalidPathError(
                'In Dropbox to change case, add or subtract other characters.')

        dest_folder = dest_provider.folder

        try:
            resp = yield from self.make_request(
                'POST',
                self.build_url('fileops', 'move'),
                data={
                    'root': 'auto',
                    'to_path': dest_path.full_path,
                    'from_path': src_path.full_path,
                },
                expects=(200, ),
                throws=exceptions.IntraMoveError,
            )
        except exceptions.IntraMoveError as e:
            if e.code != 403:
                raise

            yield from dest_provider.delete(dest_path)
            resp, _ = yield from self.intra_move(dest_provider, src_path,
                                                 dest_path)
            return resp, False

        data = yield from resp.json()

        if not data['is_dir']:
            return DropboxFileMetadata(data, dest_folder), True

        folder = DropboxFolderMetadata(data, dest_folder)

        folder.children = []
        for item in data['contents']:
            if item['is_dir']:
                folder.children.append(DropboxFolderMetadata(
                    item, dest_folder))
            else:
                folder.children.append(DropboxFileMetadata(item, dest_folder))

        return folder, True
Esempio n. 6
0
    async def validate_path(self, path, **kwargs):
        """Take a string path from the url and attempt to map it to an entity within this project.
        If the entity is found, returns a FigsharePath object with the entity identifiers included.
        Otherwise returns a FigsharePath with empty identifiers.

        :param str path: identifier_path URN as passed through the v0 API
        :rtype FigsharePath:

        Quirks:

        * v0 may pass an identifier_path whose last part is a name and not an identifier, in the
          case of file/folder creation calls.

        * validate_path validates parent and returns a FigsharePath as accurately as possible.
        """
        if path == '/':
            return FigsharePath('/', _ids=('', ), folder=True, is_public=False)

        path_parts = self._path_split(path)
        if len(path_parts) not in (2, 3):
            raise exceptions.InvalidPathError(
                '{} is not a valid Figshare path.'.format(path))
        article_id = path_parts[1]
        file_id = path_parts[2] if len(path_parts) == 3 else None

        articles = await self._get_all_articles()

        # TODO: need better way to get public/private
        # This call's return value is currently busted at figshare for collections. Figshare always
        # returns private-looking urls.
        is_public = False
        for item in articles:
            if '/articles/' + article_id in item['url']:
                article_name = item['title']
                if settings.PRIVATE_IDENTIFIER not in item['url']:
                    is_public = True

        article_segments = (*self.root_path_parts, 'articles', article_id)
        if file_id:
            file_response = await self.make_request(
                'GET',
                self.build_url(is_public, *article_segments, 'files', file_id),
                expects=(
                    200,
                    404,
                ),
            )
            if file_response.status == 200:
                file_response_json = await file_response.json()
                file_name = file_response_json['name']
                return FigsharePath('/' + article_name + '/' + file_name,
                                    _ids=(self.container_id, article_id,
                                          file_id),
                                    folder=False,
                                    is_public=is_public)
            await file_response.release()

        article_response = await self.make_request(
            'GET',
            self.build_url(is_public, *article_segments),
            expects=(
                200,
                404,
            ),
        )
        if article_response.status == 200:
            article_json = await article_response.json()
            if article_json['defined_type'] in settings.FOLDER_TYPES:
                # Case of v0 file creation
                if file_id:
                    ids = ('', article_id, '')
                    folder = False
                    path_urn = '/' + article_name + '/' + file_id
                else:
                    ids = ('', article_id)
                    folder = True
                    path_urn = '/' + article_name + '/'
                return FigsharePath(path_urn,
                                    _ids=ids,
                                    folder=folder,
                                    is_public=is_public)
        else:
            await article_response.release()

        if file_id:
            # Catch for if neither file nor article exist
            raise exceptions.NotFoundError(path)

        # Return for v0 folder creation
        return FigsharePath(path, _ids=('', ''), folder=True, is_public=False)
Esempio n. 7
0
    async def validate_v1_path(self, path, **kwargs):
        """Take a string path from the url and attempt to map it to an entity within this project.
        If the entity is found, returns a FigsharePath object with the entity identifiers included.
        Otherwise throws a 404 Not Found. Will also assert that the entity type inferred from the
        path matches the type of the entity at that url.

        :param str path: entity path from the v1 API
        :rtype FigsharePath:
        """
        if path == '/':
            return FigsharePath('/', _ids=('', ), folder=True, is_public=False)

        path_parts = self._path_split(path)
        if len(path_parts) not in (2, 3):
            raise exceptions.InvalidPathError(
                '{} is not a valid Figshare path.'.format(path))
        article_id = path_parts[1]
        file_id = path_parts[2] if len(path_parts) == 3 else None

        articles = await self._get_all_articles()

        # TODO: need better way to get public/private
        # This call's return value is currently busted at figshare for collections. Figshare always
        # returns private-looking urls.
        is_public = False
        for item in articles:
            if '/articles/' + article_id in item['url']:
                article_name = item['title']
                if settings.PRIVATE_IDENTIFIER not in item['url']:
                    is_public = True

        article_segments = (*self.root_path_parts, 'articles', article_id)
        if file_id:
            file_response = await self.make_request(
                'GET',
                self.build_url(is_public, *article_segments, 'files', file_id),
                expects=(200, ),
            )
            file_json = await file_response.json()
            file_name = file_json['name']
            if path[-1] == '/':
                raise exceptions.NotFoundError(
                    'File paths must not end with "/". '
                    '{} not found.'.format(path))
            return FigsharePath('/' + article_name + '/' + file_name,
                                _ids=(self.container_id, article_id, file_id),
                                folder=False,
                                is_public=is_public)

        article_response = await self.make_request(
            'GET',
            self.build_url(is_public, *article_segments),
            expects=(200, ),
        )
        article_json = await article_response.json()
        if article_json['defined_type'] in settings.FOLDER_TYPES:
            if not path[-1] == '/':
                raise exceptions.NotFoundError(
                    'Folder paths must end with "/".  {} not found.'.format(
                        path))
            return FigsharePath('/' + article_name + '/',
                                _ids=(self.container_id, article_id),
                                folder=True,
                                is_public=is_public)

        raise exceptions.NotFoundError(
            'This article is not configured as a folder defined_type. '
            '{} not found.'.format(path))
Esempio n. 8
0
    async def validate_v1_path(self, path: str, **kwargs) -> FigsharePath:
        """Take a string path from the url and attempt to map it to an entity within this project.
        If the entity is found, returns a FigsharePath object with the entity identifiers included.
        Otherwise throws a 404 Not Found. Will also assert that the entity type inferred from the
        path matches the type of the entity at that url.

        :param str path: entity path from the v1 API
        :rtype FigsharePath:
        """

        if path == '/':
            # Root path should always be private api-wise since project and collection itself must
            # be owned by the fighsare-OSF OAuth user.
            return FigsharePath('/', _ids=('', ), folder=True, is_public=False)

        # Step 0: Preprocess the string path.
        path_parts = self._path_split(path)
        if len(path_parts) not in (2, 3):
            raise exceptions.InvalidPathError('{} is not a valid Figshare path.'.format(path))
        article_id = path_parts[1]
        file_id = path_parts[2] if len(path_parts) == 3 else None

        # Step 1: Get a list of all articles in the project.
        articles = await self._get_all_articles()

        # Step 2: Find the article; set `article_name`, `is_public`; and prepare `article_segments`.
        is_public = False
        article_name = None
        for article in articles:
            if '/articles/' + article_id in article['url']:
                article_name = article['title']
                is_public = article['published_date'] is not None
                break
        # Raise error earlier instead of on 404.  Please note that this is different than V0.
        if not article_name:
            raise exceptions.NotFoundError('Path {} with article ID {} not found in the project\'s '
                                           'article list'.format(path, article_id))
        article_segments = (*self.root_path_parts, 'articles', article_id)

        # Step 3.1: if the path is a file
        if file_id:
            file_response = await self.make_request(
                'GET',
                self.build_url(is_public, *article_segments, 'files', file_id),
                expects=(200, ),
            )
            file_json = await file_response.json()
            file_name = file_json['name']
            if path[-1] == '/':
                raise exceptions.NotFoundError('File paths must not end with "/". '
                                               '{} not found.'.format(path))
            return FigsharePath('/' + article_name + '/' + file_name,
                                _ids=(self.container_id, article_id, file_id),
                                folder=False,
                                is_public=is_public)

        # Step 3.2: if the path is a folder
        article_response = await self.make_request(
            'GET',
            self.build_url(is_public, *article_segments),
            expects=(200, ),
        )
        article_json = await article_response.json()
        if article_json['defined_type'] in pd_settings.FOLDER_TYPES:
            if not path[-1] == '/':
                raise exceptions.NotFoundError('Folder paths must end with "/". '
                                               '{} not found.'.format(path))
            return FigsharePath('/' + article_name + '/', _ids=(self.container_id, article_id),
                                folder=True, is_public=is_public)
        raise exceptions.NotFoundError('This article is not configured as a folder defined_type. '
                                       '{} not found.'.format(path))