def copy_file_content(self, file_id, source_file):
        '''Copy file content from source file to target file.

        Args:
            file_id (str): The UUID of the file whose content is written.
            source_file (str): The UUID of the file whose content is copied.

        Returns:
            None

        Raises:
        StorageArgumentException: Invalid arguments
        StorageForbiddenException: Server response code 403
        StorageNotFoundException: Server response code 404
        StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(file_id):
            raise StorageArgumentException(
                'Invalid UUID for file_id: {0}'.format(file_id))

        if not is_valid_uuid(source_file):
            raise StorageArgumentException(
                'Invalid UUID for source_file: {0}'.format(source_file))

        self._authenticated_request \
            .to_endpoint('file/{}/content/'.format(file_id)) \
            .with_headers({'X-Copy-From': source_file}) \
            .put()
    def get_folder_details(self, folder):
        '''Get information on a given folder.

        Args:
            folder (str): The UUID of the requested folder.

        Returns:
            A dictionary of the folder details if found::

                {
                    u'created_by': u'303447',
                    u'created_on': u'2017-03-21T14:06:32.293902Z',
                    u'description': u'',
                    u'entity_type': u'folder',
                    u'modified_by': u'303447',
                    u'modified_on': u'2017-03-21T14:06:32.293967Z',
                    u'name': u'myfolder',
                    u'parent': u'3abd8742-d069-44cf-a66b-2370df74a682',
                    u'uuid': u'2516442e-1e26-4de1-8ed8-94523224cc40'
                }

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(folder):
            raise StorageArgumentException(
                'Invalid UUID for folder: {0}'.format(folder))
        return self._authenticated_request \
            .to_endpoint('folder/{}/'.format(folder)) \
            .return_body() \
            .get()
    def get_signed_url(self, file_id):
        '''Get a signed unauthenticated URL.

        It can be used to download the file content without the need for a
        token. The signed URL expires after 5 seconds.

        Args:
            file_id (str): The UUID of the file to get the link for.

        Returns:
            The signed url as a string

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(file_id):
            raise StorageArgumentException(
                'Invalid UUID for file_id: {0}'.format(file_id))

        return self._authenticated_request \
            .to_endpoint('file/{}/content/secure_link/'.format(file_id)) \
            .return_body() \
            .get()['signed_url']
    def get_entity_path(self, entity_id):
        '''Retrieve entity path.

        Args:
            entity_id (str): The UUID of the requested entity.

        Returns:
            The path of the entity as a string::

                u'/12345/folder_1'

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(entity_id):
            raise StorageArgumentException(
                'Invalid UUID for entity_id: {0}'.format(entity_id))

        return self._authenticated_request \
            .to_endpoint('entity/{}/path/'.format(entity_id)) \
            .return_body() \
            .get()["path"]
    def get_entity_details(self, entity_id):
        '''Get generic entity by UUID.

        Args:
            entity_id (str): The UUID of the requested entity.

        Returns:
            A dictionary describing the entity::

                {
                     u'collab_id': 2271,
                     u'created_by': u'303447',
                     u'created_on': u'2017-03-10T12:50:06.077891Z',
                     u'description': u'',
                     u'entity_type': u'project',
                     u'modified_by': u'303447',
                     u'modified_on': u'2017-03-10T12:50:06.077946Z',
                     u'name': u'2271',
                     u'uuid': u'3abd8742-d069-44cf-a66b-2370df74a682'
                 }

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(entity_id):
            raise StorageArgumentException(
                'Invalid UUID for entity_id: {0}'.format(entity_id))
        return self._authenticated_request \
            .to_endpoint('entity/{}/'.format(entity_id)) \
            .return_body() \
            .get()
    def get_metadata(self, entity_type, entity_id):
        '''Get metadata of an entity.

        Args:
            entity_type (str): Type of the entity. Admitted values: ['project',
                'folder', 'file'].
            entity_id (str): The UUID of the entity to be modified.

        Returns:
            A dictionary of the metadata::

                {
                    u'bar': u'200',
                    u'foo': u'100'
                }

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(entity_id):
            raise StorageArgumentException(
                'Invalid UUID for entity_id: {0}'.format(entity_id))

        return self._authenticated_request \
            .to_endpoint('{}/{}/metadata/'.format(entity_type, entity_id)) \
            .return_body() \
            .get()
    def get_file_details(self, file_id):
        '''Get information on a given file.

        Args:
            file_id (str): The UUID of the requested file.

        Returns:
            A dictionary of the file details if found::

                {
                    u'content_type': u'plain/text',
                    u'created_by': u'303447',
                    u'created_on': u'2017-03-13T10:52:23.275087Z',
                    u'description': u'',
                    u'entity_type': u'file',
                    u'modified_by': u'303447',
                    u'modified_on': u'2017-03-13T10:52:23.275126Z',
                    u'name': u'myfile',
                    u'parent': u'3abd8742-d069-44cf-a66b-2370df74a682',
                    u'uuid': u'e2c25c1b-f6a9-4cf6-b8d2-271e628a9a56'
                }

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(file_id):
            raise StorageArgumentException(
                'Invalid UUID for file_id: {0}'.format(file_id))
        return self._authenticated_request \
            .to_endpoint('file/{}/'.format(file_id)) \
            .return_body() \
            .get()
    def upload_file_content(self,
                            file_id,
                            etag=None,
                            source=None,
                            content=None):
        '''Upload a file content. The file entity must already exist.

        If an ETag is provided the file stored on the server is verified
        against it. If it does not match, StorageException is raised.
        This means the client needs to update its knowledge of the resource
        before attempting to update again. This can be used for optimistic
        concurrency control.

        Args:
            file_id (str): The UUID of the file whose content is written.
            etag (str): The etag to match the contents against.
            source (str): The path of the local file whose content to be uploaded.
            content (str): A string of the content to be uploaded.

        Note:
            ETags should be enclosed in double quotes::

                my_etag = '"71e1ed9ee52e565a56aec66bc648a32c"'

        Returns:
            The ETag of the file upload::

                '"71e1ed9ee52e565a56aec66bc648a32c"'

        Raises:
            IOError: The source cannot be opened.
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(file_id):
            raise StorageArgumentException(
                'Invalid UUID for file_id: {0}'.format(file_id))

        if not (source or content) or (source and content):
            raise StorageArgumentException(
                'Either one of source file or content '
                'has to be provided.')

        resp = self._authenticated_request \
            .to_endpoint('file/{}/content/upload/'.format(file_id)) \
            .with_body(content or open(source, 'rb')) \
            .with_headers({'If-Match': etag} if etag else {}) \
            .post()

        if 'ETag' not in resp.headers:
            raise StorageException(
                'No ETag received from the service after the upload')

        return resp.headers['ETag']
    def get_entity_by_query(self, uuid=None, path=None, metadata=None):
        '''Retrieve entity by query param which can be either uuid/path/metadata.

        Args:
            uuid (str): The UUID of the requested entity.
            path (str): The path of the requested entity.
            metadata (dict): A dictionary of one metadata {key: value} of the
                requested entitity.

        Returns:
            The details of the entity, if found::

                {
                    u'content_type': u'plain/text',
                    u'created_by': u'303447',
                    u'created_on': u'2017-03-13T10:52:23.275087Z',
                    u'description': u'',
                    u'entity_type': u'file',
                    u'modified_by': u'303447',
                    u'modified_on': u'2017-03-13T10:52:23.275126Z',
                    u'name': u'myfile',
                    u'parent': u'3abd8742-d069-44cf-a66b-2370df74a682',
                    u'uuid': u'e2c25c1b-f6a9-4cf6-b8d2-271e628a9a56'
                }

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not (uuid or path or metadata):
            raise StorageArgumentException('No parameter given for the query.')
        if uuid and not is_valid_uuid(uuid):
            raise StorageArgumentException(
                'Invalid UUID for uuid: {0}'.format(uuid))
        params = locals().copy()
        if metadata:
            if not isinstance(metadata, dict):
                raise StorageArgumentException(
                    'The metadata needs to be provided'
                    ' as a dictionary.')
            key, value = next(iter(metadata.items()))
            params[key] = value
            del params['metadata']
        params = self._prep_params(params)

        return self._authenticated_request \
            .to_endpoint('entity/') \
            .with_params(params) \
            .return_body() \
            .get()
Esempio n. 10
0
    def download_file_content(self, file_id, etag=None):
        '''Download file content.

        Args:
            file_id (str): The UUID of the file whose content is requested
            etag (str): If the content is not changed since the provided ETag,
                the content won't be downloaded. If the content is changed, it
                will be downloaded and returned with its new ETag.

        Note:
            ETags should be enclosed in double quotes::

                my_etag = '"71e1ed9ee52e565a56aec66bc648a32c"'


        Returns:
            A tuple of ETag and content (etag, content) if the content was
            retrieved. If an etag was provided, and content didn't change
            returns (None, None)::

                ('"71e1ed9ee52e565a56aec66bc648a32c"', 'Hello world!')

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(file_id):
            raise StorageArgumentException(
                'Invalid UUID for file_id: {0}'.format(file_id))

        headers = {'Accept': '*/*'}
        if etag:
            headers['If-None-Match'] = etag

        resp = self._authenticated_request \
            .to_endpoint('file/{}/content/'.format(file_id)) \
            .with_headers(headers) \
            .get()

        if resp.status_code == 304:
            return (None, None)

        if 'ETag' not in resp.headers:
            raise StorageException(
                'No ETag received from the service with the download')

        return (resp.headers['ETag'], resp.content)
Esempio n. 11
0
    def delete_folder(self, folder):
        '''Delete a folder. It will recursively delete all the content.

        Args:
            folder_id (str): The UUID of the folder to be deleted.

        Returns:
            None

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: 403
            StorageNotFoundException: 404
            HTTPError: other non-20x error codes
        '''
        if not is_valid_uuid(folder):
            raise StorageArgumentException(
                'Invalid UUID for folder: {0}'.format(folder))
        self._authenticated_request \
            .to_endpoint('folder/{}/'.format(folder)) \
            .delete()
Esempio n. 12
0
    def delete_project(self, project):
        '''Delete a project. It will recursively delete all the content.

        Args:
            project (str): The UUID of the project to be deleted.

        Returns:
            None

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: 403
            StorageNotFoundException: 404
            HTTPError: other non-20x error codes
        '''
        if not is_valid_uuid(project):
            raise StorageArgumentException(
                'Invalid UUID for project: {0}'.format(project))
        self._authenticated_request \
            .to_endpoint('project/{}/'.format(project)) \
            .delete()
Esempio n. 13
0
    def set_metadata(self, entity_type, entity_id, metadata):
        '''Set metadata for an entity.

        Args:
            entity_type (str): Type of the entity. Admitted values: ['project',
                'folder', 'file'].
            entity_id (str): The UUID of the entity to be modified.
            metadata (dict): A dictionary of key/value pairs to be written as
                metadata.

        Warning:
            It will replace all existing metadata with the provided dictionary.

        Returns:
            A dictionary of the updated metadata::

                {
                    u'bar': u'200',
                    u'foo': u'100'
                }

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(entity_id):
            raise StorageArgumentException(
                'Invalid UUID for entity_id: {0}'.format(entity_id))
        if not isinstance(metadata, dict):
            raise StorageArgumentException(
                'The metadata was not provided as a '
                'dictionary')

        return self._authenticated_request \
            .to_endpoint('{}/{}/metadata/'.format(entity_type, entity_id)) \
            .with_json_body(metadata) \
            .return_body() \
            .post()
Esempio n. 14
0
    def create_file(self, name, content_type, parent):
        '''Create a new file.

        Args:
            name (str): The name of the file.
            content_type (str): the content type of the file. E.g. "plain/text"
            parent (str): The UUID of the parent entity. The parent must be a
                project or a folder.

        Returns:
            A dictionary describing the created file::

                {
                    u'content_type': u'plain/text',
                    u'created_by': u'303447',
                    u'created_on': u'2017-03-13T10:52:23.275087Z',
                    u'description': u'',
                    u'entity_type': u'file',
                    u'modified_by': u'303447',
                    u'modified_on': u'2017-03-13T10:52:23.275126Z',
                    u'name': u'myfile',
                    u'parent': u'3abd8742-d069-44cf-a66b-2370df74a682',
                    u'uuid': u'e2c25c1b-f6a9-4cf6-b8d2-271e628a9a56'
                }

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: 403
            StorageNotFoundException: 404
            HTTPError: other non-20x error codes
        '''
        if not is_valid_uuid(parent):
            raise StorageArgumentException(
                'Invalid UUID for parent: {0}'.format(parent))
        return self._authenticated_request \
            .to_endpoint('file/') \
            .with_json_body(self._prep_params(locals())) \
            .return_body() \
            .post()
Esempio n. 15
0
    def delete_file(self, file_id):
        '''Delete a file.

        Args:
            file_id (str): The UUID of the file to delete.

        Returns:
            None

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(file_id):
            raise StorageArgumentException(
                'Invalid UUID for file_id: {0}'.format(file_id))

        self._authenticated_request \
            .to_endpoint('file/{}/'.format(file_id)) \
            .delete()
Esempio n. 16
0
    def delete_metadata(self, entity_type, entity_id, metadata_keys):
        '''Delete the selected metadata entries of an entity.

        Only deletes selected metadata keys, for a complete wipe, use set_metadata.

        Args:
            entity_type (str): Type of the entity. Admitted values: ['project',
                'folder', 'file'].
            entity_id (srt): The UUID of the entity to be modified.
            metadata_keys (lst): A list of metada keys to be deleted.

        Returns:
            A dictionary of the updated object metadata::

                {
                    u'bar': u'200',
                    u'foo': u'100'
                }

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(entity_id):
            raise StorageArgumentException(
                'Invalid UUID for entity_id: {0}'.format(entity_id))
        if not isinstance(metadata_keys, list):
            raise StorageArgumentException(
                'The metadata was not provided as a '
                'dictionary')

        return self._authenticated_request \
            .to_endpoint('{}/{}/metadata/'.format(entity_type, entity_id)) \
            .with_json_body({'keys': metadata_keys}) \
            .return_body() \
            .delete()
Esempio n. 17
0
    def create_folder(self, name, parent):
        '''Create a new folder.

        Args:
            name (srt): The name of the folder.
            parent (str): The UUID of the parent entity. The parent must be a
                project or a folder.

        Returns:
            A dictionary of details of the created folder::

                {
                    u'created_by': u'303447',
                    u'created_on': u'2017-03-21T14:06:32.293902Z',
                    u'description': u'',
                    u'entity_type': u'folder',
                    u'modified_by': u'303447',
                    u'modified_on': u'2017-03-21T14:06:32.293967Z',
                    u'name': u'myfolder',
                    u'parent': u'3abd8742-d069-44cf-a66b-2370df74a682',
                    u'uuid': u'2516442e-1e26-4de1-8ed8-94523224cc40'
                }

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(parent):
            raise StorageArgumentException(
                'Invalid UUID for parent: {0}'.format(parent))

        return self._authenticated_request \
            .to_endpoint('folder/') \
            .with_json_body(self._prep_params(locals())) \
            .return_body() \
            .post()
Esempio n. 18
0
    def get_entity_collab_id(self, entity_id):
        '''Retrieve entity Collab ID.

        Args:
            entity_id (str): The UUID of the requested entity.

        Returns:
            The id as interger of the Collebaration to which the entity belongs

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(entity_id):
            raise StorageArgumentException(
                'Invalid UUID for entity_id: {0}'.format(entity_id))

        return self._authenticated_request \
            .to_endpoint('entity/{}/collab/'.format(entity_id)) \
            .return_body() \
            .get()["collab_id"]
Esempio n. 19
0
    def list_folder_content(self,
                            folder,
                            name=None,
                            entity_type=None,
                            content_type=None,
                            page_size=DEFAULT_PAGE_SIZE,
                            page=None,
                            ordering=None):
        '''List files and folders (not recursively) contained in the folder.

        This function does not retrieve all results, pages have
        to be manually retrieved by the caller.

        Args:
            folder (str): The UUID of the requested folder.
            name (str): Optional filter on entity name.
            entity_type (str): Optional filter on entity type.
                Admitted values: ['file', 'folder'].
            content_type (str): Optional filter on entity content type (only
                files are returned).
            page_size (int): Number of elements per page.
            page (int): Number of the page.
            ordering (str): Indicate on which fields to sort the result. Prepend
                '-' to invert order. Multiple values can be provided.
                Ordering is supported on: ['name', 'created_on', 'modified_on'].
                Example: 'ordering=name,created_on'

        Returns:
            A dictionary of the results::

                {
                u'count': 1,
                u'next': None,
                u'previous': None,
                u'results': [{u'content_type': u'plain/text',
                    u'created_by': u'303447',
                    u'created_on': u'2017-03-13T10:17:01.688472Z',
                    u'description': u'',
                    u'entity_type': u'file',
                    u'modified_by': u'303447',
                    u'modified_on': u'2017-03-13T10:17:01.688632Z',
                    u'name': u'file_1',
                    u'parent': u'eac11058-4ae0-4ea9-ada8-d3ea23887509',
                    u'uuid': u'0e17eaac-cb00-4336-b9d7-657026844281'}]
                }

        Raises:
            StorageArgumentException: Invalid arguments
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(folder):
            raise StorageArgumentException(
                'Invalid UUID for folder: {0}'.format(folder))
        params = self._prep_params(locals())
        del params['folder']  # not a query parameter
        return self._authenticated_request \
            .to_endpoint('folder/{}/children/'.format(folder)) \
            .with_params(params) \
            .return_body() \
            .get()
Esempio n. 20
0
    def list_project_content(self,
                             project_id,
                             name=None,
                             entity_type=None,
                             content_type=None,
                             page_size=DEFAULT_PAGE_SIZE,
                             page=None,
                             ordering=None):
        '''List all files and folders (not recursively) contained in the project.

        This function does not retrieve all results, pages have
        to be manually retrieved by the caller.

        Args:
            project_id (str): The UUID of the requested project.
            name (str): Optional filter on entity name.
            entity_type (str): Optional filter on entity type.
                Admitted values: ['file', 'folder'].
            content_type (str): Optional filter on entity content type (only
                files are returned).
            page_size (int): Number of elements per page.
            page (int): Number of the page
            ordering (str): Indicate on which fields to sort the result.
                Prepend '-' to invert order. Multiple values can be provided.
                Ordering is supported on: ['name', 'created_on', 'modified_on'].
                Example: 'ordering=name,created_on'

        Returns:
            A dictionary of the results::

                {
                    u'count': 3,
                    u'next': u'http://link.to.next/page',
                    u'previous': None,
                    u'results': [{u'created_by': u'303447',
                        u'created_on': u'2017-03-10T17:41:31.618496Z',
                        u'description': u'',
                        u'entity_type': u'folder',
                        u'modified_by': u'303447',
                        u'modified_on': u'2017-03-10T17:41:31.618553Z',
                        u'name': u'folder_1',
                        u'parent': u'3abd8742-d069-44cf-a66b-2370df74a682',
                        u'uuid': u'eac11058-4ae0-4ea9-ada8-d3ea23887509'}]
                }

        Raises:
            StorageArgumentException: Ivalid parameters
            StorageForbiddenException: Server response code 403
            StorageNotFoundException: Server response code 404
            StorageException: other 400-600 error codes
        '''
        if not is_valid_uuid(project_id):
            raise StorageArgumentException(
                'Invalid UUID for project_id: {0}'.format(project_id))
        params = self._prep_params(locals())
        del params['project_id']  # not a query parameter
        return self._authenticated_request \
            .to_endpoint('project/{}/children/'.format(project_id)) \
            .with_params(params) \
            .return_body() \
            .get()