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 core_exceptions.InvalidPathError(
                'In Dropbox to change case, add or subtract other characters.')

        try:
            data = await self.dropbox_request(
                self.build_url('files', 'move_v2'),
                {
                    'from_path': src_path.full_path.rstrip('/'),
                    'to_path': dest_path.full_path.rstrip('/'),
                },
                expects=(200, 201, 409),
                throws=core_exceptions.IntraMoveError,
            )
            data = data['metadata']
        except pd_exceptions.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
示例#2
0
    async 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.')

        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)]
        return folder, True
示例#3
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
示例#4
0
    async def test_intra_copy_folder(self, provider, provider_fixtures):
        src_path = WaterButlerPath('/pfile/', prepend=provider.folder)
        dest_path = WaterButlerPath('/pfile_renamed/', prepend=provider.folder)

        url = provider.build_url('files', 'copy_v2')
        data = {
            'from_path': src_path.full_path.rstrip('/'),
            'to_path': dest_path.full_path.rstrip('/')
        }
        aiohttpretty.register_json_uri(
            'POST',
            url,
            data=data,
            body=provider_fixtures['intra_move_copy_folder_metadata_v2'])

        url = provider.build_url('files', 'list_folder')
        data = {'path': dest_path.full_path}
        aiohttpretty.register_json_uri(
            'POST',
            url,
            data=data,
            status=HTTPStatus.OK,
            body=provider_fixtures['folder_children'])

        result = await provider.intra_copy(provider, src_path, dest_path)
        expected = DropboxFolderMetadata(
            provider_fixtures['intra_move_copy_folder_metadata_v2']
            ['metadata'], provider.folder)
        expected.children = [
            DropboxFileMetadata(item, provider.folder)
            for item in provider_fixtures['folder_children']['entries']
        ]

        assert expected == result[0]
示例#5
0
    def intra_copy(self, dest_provider, src_path, dest_path):
        dest_folder = dest_provider.folder

        try:
            if self == dest_provider:
                resp = yield from self.make_request(
                    'POST',
                    self.build_url('fileops', 'copy'),
                    data={
                        'root': 'auto',
                        'from_path': src_path.full_path,
                        'to_path': dest_path.full_path,
                    },
                    expects=(200, 201),
                    throws=exceptions.IntraCopyError,
                )
            else:
                from_ref_resp = yield from self.make_request(
                    'GET',
                    self.build_url('copy_ref', 'auto', src_path.full_path),
                )
                from_ref_data = yield from from_ref_resp.json()
                resp = yield from self.make_request(
                    'POST',
                    self.build_url('fileops', 'copy'),
                    data={
                        'root': 'auto',
                        'from_copy_ref': from_ref_data['copy_ref'],
                        'to_path': dest_path,
                    },
                    headers=dest_provider.default_headers,
                    expects=(200, 201),
                    throws=exceptions.IntraCopyError,
                )
        except exceptions.IntraCopyError as e:
            if e.code != 403:
                raise

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

        # TODO Refactor into a function
        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
示例#6
0
    async def intra_copy(self, dest_provider, src_path, dest_path):
        dest_folder = dest_provider.folder

        try:
            if self == dest_provider:
                resp = await self.make_request(
                    'POST',
                    self.build_url('fileops', 'copy'),
                    data={
                        'root': 'auto',
                        'from_path': src_path.full_path,
                        'to_path': dest_path.full_path,
                    },
                    expects=(200, 201),
                    throws=exceptions.IntraCopyError,
                )
            else:
                from_ref_resp = await self.make_request(
                    'GET',
                    self.build_url('copy_ref', 'auto', src_path.full_path),
                )
                from_ref_data = await from_ref_resp.json()
                resp = await self.make_request(
                    'POST',
                    self.build_url('fileops', 'copy'),
                    data={
                        'root': 'auto',
                        'from_copy_ref': from_ref_data['copy_ref'],
                        'to_path': dest_path,
                    },
                    headers=dest_provider.default_headers,
                    expects=(200, 201),
                    throws=exceptions.IntraCopyError,
                )
        except exceptions.IntraCopyError as e:
            if e.code != 403:
                raise

            await dest_provider.delete(dest_path)
            resp, _ = await self.intra_copy(dest_provider, src_path, dest_path)
            return resp, False

        # TODO Refactor into a function
        data = await 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
    async def test_intra_move_replace_folder(self, provider, provider_fixtures, error_fixtures):
        url = provider.build_url('files', 'delete_v2')
        path = await provider.validate_path('/newfolder/')
        data = {'path': path.full_path}
        aiohttpretty.register_json_uri('POST', url, data=data, status=HTTPStatus.OK)

        url = provider.build_url('files', 'list_folder')
        data = {'path': path.full_path}
        aiohttpretty.register_json_uri(
            'POST',
            url,
            data=data,
            body=provider_fixtures['folder_children'],
            status=HTTPStatus.OK
        )

        src_path = WaterButlerPath('/pfile/', prepend=provider.folder)
        dest_path = WaterButlerPath('/pfile_renamed/', prepend=provider.folder)

        url = provider.build_url('files', 'move_v2')
        data = {
            'from_path': src_path.full_path.rstrip('/'),
            'to_path': dest_path.full_path.rstrip('/')
        }
        aiohttpretty.register_json_uri('POST', url, **{
            "responses": [
                {
                    'headers': {'Content-Type': 'application/json'},
                    'data': data,
                    'body': json.dumps(error_fixtures['rename_conflict_folder_metadata']).encode('utf-8'),
                    'status': HTTPStatus.CONFLICT
                },
                {
                    'headers': {'Content-Type': 'application/json'},
                    'data': data,
                    'body': json.dumps(
                        provider_fixtures['intra_move_copy_folder_metadata_v2']).encode('utf-8')
                },
            ]
        })

        result = await provider.intra_move(provider, src_path, dest_path)
        expected = DropboxFolderMetadata(
            provider_fixtures['intra_move_copy_folder_metadata_v2']['metadata'],
            provider.folder
        )
        expected.children = [
            DropboxFileMetadata(item, provider.folder)
            for item in provider_fixtures['folder_children']['entries']
        ]

        assert expected == result[0]
示例#8
0
    async def create_folder(self, path, **kwargs):
        """
        :param str path: The path to create a folder at
        """
        WaterButlerPath.validate_folder(path)

        response = await self.make_request(
            'POST',
            self.build_url('fileops', 'create_folder'),
            params={
                'root': 'auto',
                'path': path.full_path
            },
            expects=(200, 403),
            throws=exceptions.CreateFolderError
        )

        data = await response.json()

        if response.status == 403:
            if 'because a file or folder already exists at path' in data.get('error'):
                raise exceptions.FolderNamingConflict(str(path))
            raise exceptions.CreateFolderError(data, code=403)

        return DropboxFolderMetadata(data, self.folder)
示例#9
0
    def metadata(self, path, **kwargs):
        resp = yield from self.make_request(
            'GET',
            self.build_url('metadata', 'auto', path.full_path),
            expects=(200, ),
            throws=exceptions.MetadataError
        )

        data = yield from resp.json()

        # Dropbox will match a file or folder by name within the requested path
        if path.is_file and data['is_dir']:
            raise exceptions.MetadataError(
                "Could not retrieve file '{}'".format(path),
                code=http.client.NOT_FOUND,
            )

        if data.get('is_deleted'):
            raise exceptions.MetadataError(
                "Could not retrieve {kind} '{path}'".format(
                    kind='folder' if data['is_dir'] else 'file',
                    path=path,
                ),
                code=http.client.NOT_FOUND,
            )

        if data['is_dir']:
            ret = []
            for item in data['contents']:
                if item['is_dir']:
                    ret.append(DropboxFolderMetadata(item, self.folder).serialized())
                else:
                    ret.append(DropboxFileMetadata(item, self.folder).serialized())
            return ret
        return DropboxFileMetadata(data, self.folder).serialized()
示例#10
0
    async def intra_copy(self,  # type: ignore
                         dest_provider: 'DropboxProvider',
                         src_path: WaterButlerPath,
                         dest_path: WaterButlerPath) \
            -> typing.Tuple[typing.Union[DropboxFileMetadata, DropboxFolderMetadata], bool]:
        dest_folder = dest_provider.folder
        try:
            if self == dest_provider:
                data = await self.dropbox_request(
                    self.build_url('files', 'copy'),
                    {
                        'from_path': src_path.full_path.rstrip('/'),
                        'to_path': dest_path.full_path.rstrip('/'),
                    },
                    expects=(200, 201, 409),
                    throws=exceptions.IntraCopyError,
                )
            else:
                from_ref_data = await self.dropbox_request(
                    self.build_url('files', 'copy_reference', 'get'),
                    {'path': src_path.full_path.rstrip('/')},
                    throws=exceptions.IntraCopyError,
                )
                from_ref = from_ref_data['copy_reference']

                data = await dest_provider.dropbox_request(
                    self.build_url('files', 'copy_reference', 'save'),
                    {
                        'copy_reference': from_ref,
                        'path': dest_path.full_path.rstrip('/')
                    },
                    expects=(200, 201, 409),
                    throws=exceptions.IntraCopyError,
                )
                data = data['metadata']
        except DropboxNamingConflictError:
            await dest_provider.delete(dest_path)
            resp, _ = await self.intra_copy(dest_provider, src_path, dest_path)
            return resp, False

        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
示例#11
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
    async def intra_copy(self,  # type: ignore
                         dest_provider: 'DropboxProvider',
                         src_path: WaterButlerPath,
                         dest_path: WaterButlerPath) \
            -> typing.Tuple[typing.Union[DropboxFileMetadata, DropboxFolderMetadata], bool]:
        dest_folder = dest_provider.folder
        try:
            if self == dest_provider:
                data = await self.dropbox_request(
                    self.build_url('files', 'copy_v2'),
                    {
                        'from_path': src_path.full_path.rstrip('/'),
                        'to_path': dest_path.full_path.rstrip('/'),
                    },
                    expects=(200, 201, 409),
                    throws=core_exceptions.IntraCopyError,
                )
            else:
                from_ref_data = await self.dropbox_request(
                    self.build_url('files', 'copy_reference', 'get'),
                    {'path': src_path.full_path.rstrip('/')},
                    throws=core_exceptions.IntraCopyError,
                )
                from_ref = from_ref_data['copy_reference']

                data = await dest_provider.dropbox_request(
                    self.build_url('files', 'copy_reference', 'save'),
                    {'copy_reference': from_ref, 'path': dest_path.full_path.rstrip('/')},
                    expects=(200, 201, 409),
                    throws=core_exceptions.IntraCopyError,
                )
            data = data['metadata']
        except pd_exceptions.DropboxNamingConflictError:
            await dest_provider.delete(dest_path)
            resp, _ = await self.intra_copy(dest_provider, src_path, dest_path)
            return resp, False

        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
示例#13
0
    async 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 = await 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

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

        data = await 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
示例#14
0
 async def create_folder(self, path: WaterButlerPath,
                         **kwargs) -> DropboxFolderMetadata:
     """
     :param str path: The path to create a folder at
     """
     WaterButlerPath.validate_folder(path)
     data = await self.dropbox_request(
         self.build_url('files', 'create_folder'),
         {'path': path.full_path.rstrip('/')},
         throws=exceptions.CreateFolderError,
     )
     return DropboxFolderMetadata(data, self.folder)
示例#15
0
    async def metadata(self,  # type: ignore
                       path: WaterButlerPath,
                       revision: str=None,
                       **kwargs) \
                       -> typing.Union[BaseDropboxMetadata, typing.List[BaseDropboxMetadata]]:
        full_path = path.full_path.rstrip('/')
        url = self.build_url('files', 'get_metadata')
        body = {'path': full_path}
        if revision:
            body = {'path': 'rev:' + revision}
        elif path.is_folder:
            url = self.build_url('files', 'list_folder')

        if path.is_folder:
            ret = []  # type: typing.List[BaseDropboxMetadata]
            has_more = True
            page_count = 0
            while has_more:
                page_count += 1
                data = await self.dropbox_request(
                    url, body, throws=exceptions.MetadataError)
                for entry in data['entries']:
                    if entry['.tag'] == 'folder':
                        ret.append(DropboxFolderMetadata(entry, self.folder))
                    else:
                        ret.append(DropboxFileMetadata(entry, self.folder))
                if not data['has_more']:
                    has_more = False
                else:
                    url = self.build_url('files', 'list_folder', 'continue')
                    body = {'cursor': data['cursor']}
            self.metrics.add('metadata.folder.pages', page_count)
            return ret

        data = await self.dropbox_request(url,
                                          body,
                                          throws=exceptions.MetadataError)
        # Dropbox v2 API will not indicate file/folder if path "deleted"
        if data['.tag'] == 'deleted':
            raise exceptions.MetadataError(
                "Could not retrieve '{}'".format(path),
                code=HTTPStatus.NOT_FOUND,
            )

        # Dropbox will match a file or folder by name within the requested path
        if path.is_file and data['.tag'] == 'folder':
            raise exceptions.MetadataError(
                "Could not retrieve file '{}'".format(path),
                code=HTTPStatus.NOT_FOUND,
            )

        return DropboxFileMetadata(data, self.folder)
示例#16
0
    def test_folder_metadata(self, root_provider_fixtures):
        data = DropboxFolderMetadata(root_provider_fixtures['folder_metadata'],
                                     '/Photos')

        assert data.name == 'newfolder'
        assert data.path == '/newfolder/'
        assert data.etag is None
        assert data.serialized() == {
            'extra': {},
            'kind':
            'folder',
            'name':
            'newfolder',
            'path':
            '/newfolder/',
            'provider':
            'dropbox',
            'materialized':
            '/newfolder/',
            'etag':
            'bbd6cc654c4a3ca1124b69fccb392ec9754e18e9094effb525192509f8e1b901'
        }

        link_url = 'http://localhost:7777/v1/resources/mucuew/providers/dropbox/newfolder/'
        assert data.json_api_serialized('mucuew') == {
            'id': 'dropbox/newfolder/',
            'type': 'files',
            'attributes': {
                'extra': {},
                'kind': 'folder',
                'name': 'newfolder',
                'path': '/newfolder/',
                'provider': 'dropbox',
                'materialized': '/newfolder/',
                'etag':
                'bbd6cc654c4a3ca1124b69fccb392ec9754e18e9094effb525192509f8e1b901',
                'resource': 'mucuew',
                'size': None,
            },
            'links': {
                'move': link_url,
                'upload': '{}?kind=file'.format(link_url),
                'delete': link_url,
                'new_folder': '{}?kind=folder'.format(link_url),
            }
        }
        assert data._json_api_links('mucuew') == {
            'move': link_url,
            'upload': '{}?kind=file'.format(link_url),
            'delete': link_url,
            'new_folder': '{}?kind=folder'.format(link_url),
        }
        assert data.children is None
        assert data._entity_url('mucuew') == link_url
        assert data.is_folder is True
        assert data.is_file is False
        assert data.provider == 'dropbox'
        assert data.materialized_path == '/newfolder/'
        assert data.extra == {}
示例#17
0
    async def intra_copy(self, dest_provider, src_path, dest_path):
        dest_folder = dest_provider.folder
        try:
            if self == dest_provider:
                data = await self.dropbox_request(
                    self.build_url('files', 'copy'),
                    {
                        'from_path': src_path.full_path.rstrip('/'),
                        'to_path': dest_path.full_path.rstrip('/'),
                    },
                    expects=(200, 201, 409),
                    throws=exceptions.IntraCopyError,
                )
            else:
                from_ref_data = await self.dropbox_request(
                    self.build_url('files', 'copy_reference', 'get'),
                    {'path': src_path.full_path.rstrip('/')},
                    throws=exceptions.IntraCopyError,
                )
                from_ref = from_ref_data['copy_reference']

                data = await dest_provider.dropbox_request(
                    self.build_url('files', 'copy_reference', 'save'),
                    {'copy_reference': from_ref, 'path': dest_path.full_path.rstrip('/')},
                    expects=(200, 201, 409),
                    throws=exceptions.IntraCopyError,
                )
                data = data['metadata']
        except DropboxNamingConflictError:
            await dest_provider.delete(dest_path)
            resp, _ = await self.intra_copy(dest_provider, src_path, dest_path)
            return resp, False

        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)]
        return folder, True
示例#18
0
    async def metadata(self, path, revision=None, **kwargs):
        if revision:
            url = self.build_url('revisions',
                                 'auto',
                                 path.full_path,
                                 rev_limit=250)

        else:
            url = self.build_url('metadata', 'auto', path.full_path)
        resp = await self.make_request('GET',
                                       url,
                                       expects=(200, ),
                                       throws=exceptions.MetadataError)

        data = await resp.json()

        if revision:
            try:
                data = next(v for v in (await resp.json())
                            if v['rev'] == revision)
            except StopIteration:
                raise exceptions.NotFoundError(str(path))

        # Dropbox will match a file or folder by name within the requested path
        if path.is_file and data['is_dir']:
            raise exceptions.MetadataError(
                "Could not retrieve file '{}'".format(path),
                code=http.client.NOT_FOUND,
            )

        if data.get('is_deleted'):
            raise exceptions.MetadataError(
                "Could not retrieve {kind} '{path}'".format(
                    kind='folder' if data['is_dir'] else 'file',
                    path=path,
                ),
                code=http.client.NOT_FOUND,
            )

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

        return DropboxFileMetadata(data, self.folder)