class ClientTestCase(TestCase):
    remote_path_file = 'test_dir/test.txt'
    remote_path_file2 = 'test_dir2/test.txt'
    remote_path_dir = 'test_dir'
    remote_path_dir2 = 'test_dir2'
    local_base_dir = 'tests/'
    local_file = 'test.txt'
    local_file_path = local_base_dir + 'test.txt'
    local_path_dir = local_base_dir + 'res/test_dir'

    def setUp(self):
        options = {
            'webdav_hostname': 'https://webdav.yandex.ru',
            'webdav_login': '******',
            'webdav_password': '******'
        }
        self.client = Client(options)
        if path.exists(path=self.local_path_dir):
            shutil.rmtree(path=self.local_path_dir)

    def tearDown(self):
        if path.exists(path=self.local_path_dir):
            shutil.rmtree(path=self.local_path_dir)
        if self.client.check(remote_path=self.remote_path_dir):
            self.client.clean(remote_path=self.remote_path_dir)
        if self.client.check(remote_path=self.remote_path_dir2):
            self.client.clean(remote_path=self.remote_path_dir2)

    def test_list(self):
        self._prepare_for_downloading()
        file_list = self.client.list()
        self.assertIsNotNone(file_list, 'List of files should not be None')
        self.assertGreater(file_list.__len__(), 0,
                           'Expected that amount of files more then 0')

    def test_free(self):
        self.assertGreater(
            self.client.free(), 0,
            'Expected that free space on WebDAV server is more then 0 bytes')

    def test_check(self):
        self.assertTrue(self.client.check(),
                        'Expected that root directory is exist')

    def test_mkdir(self):
        if self.client.check(remote_path=self.remote_path_dir):
            self.client.clean(remote_path=self.remote_path_dir)
        self.client.mkdir(remote_path=self.remote_path_dir)
        self.assertTrue(self.client.check(remote_path=self.remote_path_dir),
                        'Expected the directory is created.')

    @unittest.skip(
        "Yandex brakes response for file it contains property resourcetype as collection but it should "
        "be empty for file")
    def test_download_to(self):
        self._prepare_for_downloading()
        buff = BytesIO()
        self.client.download_from(buff=buff, remote_path=self.remote_path_file)
        self.assertEquals(buff.getvalue(),
                          'test content for testing of webdav client')

    @unittest.skip(
        "Yandex brakes response for file it contains property resourcetype as collection but it should "
        "be empty for file")
    def test_download(self):
        self._prepare_for_downloading()
        self.client.download(local_path=self.local_path_dir,
                             remote_path=self.remote_path_dir)
        self.assertTrue(path.exists(self.local_path_dir),
                        'Expected the directory is downloaded.')
        self.assertTrue(path.isdir(self.local_path_dir),
                        'Expected this is a directory.')
        self.assertTrue(
            path.exists(self.local_path_dir + os.path.sep + self.local_file),
            'Expected the file is downloaded')
        self.assertTrue(
            path.isfile(self.local_path_dir + os.path.sep +
                        self.local_path_file), 'Expected this is a file')

    @unittest.skip(
        "Yandex brakes response for file it contains property resourcetype as collection but it should "
        "be empty for file")
    def test_download_sync(self):
        self._prepare_for_downloading()
        os.mkdir(self.local_path_dir)

        def callback():
            self.assertTrue(
                path.exists(self.local_path_dir + os.path.sep +
                            self.local_file),
                'Expected the file is downloaded')
            self.assertTrue(
                path.isfile(self.local_path_dir + os.path.sep +
                            self.local_file), 'Expected this is a file')

        self.client.download_sync(local_path=self.local_path_dir +
                                  os.path.sep + self.local_file,
                                  remote_path=self.remote_path_file,
                                  callback=callback)
        self.assertTrue(
            path.exists(self.local_path_dir + os.path.sep + self.local_file),
            'Expected the file has already been downloaded')

    @unittest.skip(
        "Yandex brakes response for file it contains property resourcetype as collection but it should "
        "be empty for file")
    def test_download_async(self):
        self._prepare_for_downloading()
        os.mkdir(self.local_path_dir)

        def callback():
            self.assertTrue(
                path.exists(self.local_path_dir + os.path.sep +
                            self.local_file),
                'Expected the file is downloaded')
            self.assertTrue(
                path.isfile(self.local_path_dir + os.path.sep +
                            self.local_file), 'Expected this is a file')

        self.client.download_async(local_path=self.local_path_dir +
                                   os.path.sep + self.local_file,
                                   remote_path=self.remote_path_file,
                                   callback=callback)
        self.assertFalse(
            path.exists(self.local_path_dir + os.path.sep + self.local_file),
            'Expected the file has not been downloaded yet')

    def test_upload_from(self):
        self._prepare_for_uploading()
        buff = StringIO(u'test content for testing of webdav client')
        self.client.upload_to(buff=buff, remote_path=self.remote_path_file)
        self.assertTrue(self.client.check(self.remote_path_file),
                        'Expected the file is uploaded.')

    def test_upload(self):
        self._prepare_for_uploading()
        self.client.upload(remote_path=self.remote_path_file,
                           local_path=self.local_path_dir)
        self.assertTrue(self.client.check(self.remote_path_dir),
                        'Expected the directory is created.')
        self.assertTrue(self.client.check(self.remote_path_file),
                        'Expected the file is uploaded.')

    def test_upload_file(self):
        self._prepare_for_uploading()
        self.client.upload_file(remote_path=self.remote_path_file,
                                local_path=self.local_file_path)
        self.assertTrue(self.client.check(remote_path=self.remote_path_file),
                        'Expected the file is uploaded.')

    def test_upload_sync(self):
        self._prepare_for_uploading()

        def callback():
            self.assertTrue(self.client.check(self.remote_path_dir),
                            'Expected the directory is created.')
            self.assertTrue(self.client.check(self.remote_path_file),
                            'Expected the file is uploaded.')

        self.client.upload(remote_path=self.remote_path_file,
                           local_path=self.local_path_dir)

    def test_upload_async(self):
        self._prepare_for_uploading()

        def callback():
            self.assertTrue(self.client.check(self.remote_path_dir),
                            'Expected the directory is created.')
            self.assertTrue(self.client.check(self.remote_path_file),
                            'Expected the file is uploaded.')

        self.client.upload(remote_path=self.remote_path_file,
                           local_path=self.local_path_dir)

    def test_copy(self):
        self._prepare_for_downloading()
        self.client.mkdir(remote_path=self.remote_path_dir2)
        self.client.copy(remote_path_from=self.remote_path_file,
                         remote_path_to=self.remote_path_file2)
        self.assertTrue(self.client.check(remote_path=self.remote_path_file2))

    def test_move(self):
        self._prepare_for_downloading()
        self.client.mkdir(remote_path=self.remote_path_dir2)
        self.client.move(remote_path_from=self.remote_path_file,
                         remote_path_to=self.remote_path_file2)
        self.assertFalse(self.client.check(remote_path=self.remote_path_file))
        self.assertTrue(self.client.check(remote_path=self.remote_path_file2))

    def test_clean(self):
        self._prepare_for_downloading()
        self.client.clean(remote_path=self.remote_path_dir)
        self.assertFalse(self.client.check(remote_path=self.remote_path_file))
        self.assertFalse(self.client.check(remote_path=self.remote_path_dir))

    def test_info(self):
        self._prepare_for_downloading()
        result = self.client.info(remote_path=self.remote_path_file)
        self.assertEquals(result['name'], 'test.txt')
        self.assertEquals(result['size'], '41')
        self.assertTrue('created' in result)
        self.assertTrue('modified' in result)

    def test_directory_is_dir(self):
        self._prepare_for_downloading()
        self.assertTrue(self.client.is_dir(self.remote_path_dir),
                        'Should return True for directory')

    def test_file_is_not_dir(self):
        self._prepare_for_downloading()
        self.assertFalse(self.client.is_dir(self.remote_path_file),
                         'Should return False for file')

    def test_get_property_of_non_exist(self):
        self._prepare_for_downloading()
        result = self.client.get_property(remote_path=self.remote_path_file,
                                          option={'name': 'aProperty'})
        self.assertEquals(
            result, None, 'For not found property should return value as None')

    def test_set_property(self):
        self._prepare_for_downloading()
        self.client.set_property(remote_path=self.remote_path_file,
                                 option={
                                     'namespace': 'test',
                                     'name': 'aProperty',
                                     'value': 'aValue'
                                 })
        result = self.client.get_property(remote_path=self.remote_path_file,
                                          option={
                                              'namespace': 'test',
                                              'name': 'aProperty'
                                          })
        self.assertEquals(result, 'aValue', 'Property value should be set')

    def test_set_property_batch(self):
        self._prepare_for_downloading()
        self.client.set_property_batch(remote_path=self.remote_path_file,
                                       option=[{
                                           'namespace': 'test',
                                           'name': 'aProperty',
                                           'value': 'aValue'
                                       }, {
                                           'namespace': 'test',
                                           'name': 'aProperty2',
                                           'value': 'aValue2'
                                       }])
        result = self.client.get_property(remote_path=self.remote_path_file,
                                          option={
                                              'namespace': 'test',
                                              'name': 'aProperty'
                                          })
        self.assertEquals(result, 'aValue',
                          'First property value should be set')
        result = self.client.get_property(remote_path=self.remote_path_file,
                                          option={
                                              'namespace': 'test',
                                              'name': 'aProperty2'
                                          })
        self.assertEquals(result, 'aValue2',
                          'Second property value should be set')

    def _prepare_for_downloading(self):
        if not self.client.check(remote_path=self.remote_path_dir):
            self.client.mkdir(remote_path=self.remote_path_dir)
        if not self.client.check(remote_path=self.remote_path_file):
            self.client.upload_file(remote_path=self.remote_path_file,
                                    local_path=self.local_file_path)
        if not path.exists(self.local_path_dir):
            os.makedirs(self.local_path_dir)

    def _prepare_for_uploading(self):
        if not self.client.check(remote_path=self.remote_path_dir):
            self.client.mkdir(remote_path=self.remote_path_dir)
        if not path.exists(path=self.local_path_dir):
            os.makedirs(self.local_path_dir)
        if not path.exists(path=self.local_path_dir + os.sep +
                           self.local_file):
            shutil.copy(src=self.local_file_path,
                        dst=self.local_path_dir + os.sep + self.local_file)
Пример #2
0
class FileBrowserWebdavStorage(StorageMixin, Storage):
    def __init__(self,
                 base_url='/',
                 url_as_download=True,
                 simple_listdir=False,
                 webdav_root='/'):
        self.base_url = base_url
        self.url_as_download = url_as_download
        self.simple_listdir = simple_listdir

        webdav_client_options = {
            'webdav_hostname':
            settings.CONTRAX_FILE_STORAGE_WEBDAV_ROOT_URL.rstrip('/'),
            'webdav_login':
            settings.CONTRAX_FILE_STORAGE_WEBDAV_USERNAME,
            'webdav_password':
            settings.CONTRAX_FILE_STORAGE_WEBDAV_PASSWORD,
        }
        self.client = Client(webdav_client_options)

        try:
            self.client.mkdir('/media')
            self.client.mkdir('/media/photo')
        except:
            pass
        self.client.webdav.root = webdav_root
        self.client.root = webdav_root

    def path(self, name):
        """
        Return a local filesystem path where the file can be retrieved using
        Python's built-in open() function. Storage systems that can't be
        accessed using open() should *not* implement this method.
        """
        # FIXME: this would be useful with self.location != ''
        # in this case use this notation:
        # 1. define self.location in __init__
        # 2. rewrite path() method to be like
        # return os.oath.join(self.location, name)
        # 3. everywhere in other sel.methods use self.path(name) instead of name attr
        return name

    def isdir(self, path):
        """
        Returns true if name exists and is a directory.
        """
        return self.client.check(path) and self.client.is_dir(path)

    def isfile(self, path):
        """
        Returns true if name exists and is a regular file.
        """
        return self.client.check(path) and not self.client.is_dir(path)

    def move(self, old_file_name, new_file_name, allow_overwrite=False):
        """
        Moves safely a file from one location to another.

        If allow_ovewrite==False and new_file_name exists, raises an exception.
        """
        return self.client.move(remote_path_from=old_file_name,
                                remote_path_to=new_file_name,
                                overwrite=allow_overwrite)

    def makedirs(self, path):
        """
        Creates all missing directories specified by name. Analogue to os.mkdirs().
        """
        return self.client.mkdir(path)

    def rmtree(self, path):
        """
        Deletes a directory and everything it contains. Analogue to shutil.rmtree().
        """
        return self.client.clean(path)

    def setpermission(self, path):
        """
        Sets file permission
        """
        pass

    def _open(self, path, mode='rb'):
        tmp = io.BytesIO()
        self.client.download_from(tmp, path)
        tmp.seek(0)
        return File(tmp)

    def _save(self, path, content):
        res = self.client.resource(path)
        res.read_from(content)
        return path

    def get_valid_name(self, name):
        """
        Return a filename, based on the provided filename, that's suitable for
        use in the target storage system.
        """
        return get_valid_filename(name)

    def delete(self, path):
        """
        Delete the specified file from the storage system.
        """
        if self.exists(path):
            self.client.clean(path)

    def exists(self, path):
        """
        Return True if a file referenced by the given name already exists in the
        storage system, or False if the name is available for a new file.
        """
        return self.client.check(path)

    def listdir(self, path):
        """
        List the contents of the specified path. Return a 2-tuple of lists:
        the first item being directories, the second item being files.
        """
        _list = self.client.list(path)

        # for API: iterating over big directory take too much time
        if self.simple_listdir:
            return _list

        # for filebrowser
        directories, files = [], []
        for entry in _list:
            entry_path = os.path.join(path, entry)
            if self.isdir(entry_path):
                directories.append(entry.rstrip('/'))
            else:
                files.append(entry)
        return directories, files

    def size(self, path):
        """
        Return the total size, in bytes, of the file specified by name.
        """
        return self.client.info(path)['size']

    def url(self, path):
        """
        Return an absolute URL where the file's contents can be accessed
        directly by a Web browser.
        """
        url = filepath_to_uri(path)
        if url is not None:
            url = url.lstrip('/')
        url = urljoin(self.base_url, url)
        if self.url_as_download and self.isfile(path):
            url += '?action=download'
        return url

    @staticmethod
    def _datetime_from_timestamp(ts, fmt):
        """
        If timezone support is enabled, make an aware datetime object in UTC;
        otherwise make a naive one in the local timezone.
        """
        dt = datetime.strptime(ts, fmt)
        if settings.USE_TZ:
            # Safe to use .replace() because UTC doesn't have DST
            return dt.replace(tzinfo=timezone.utc)
        else:
            return dt

    def get_accessed_time(self, path):
        """
        Return the last accessed time (as a datetime) of the file specified by
        name. The datetime will be timezone-aware if USE_TZ=True.
        """
        pass

    def get_created_time(self, path):
        """
        Return the creation time (as a datetime) of the file specified by name.
        The datetime will be timezone-aware if USE_TZ=True.
        """
        return self._datetime_from_timestamp(self.client.info(path)['created'],
                                             fmt='%Y-%m-%dT%H:%M:%SZ')

    def get_modified_time(self, path):
        """
        Return the last modified time (as a datetime) of the file specified by
        name. The datetime will be timezone-aware if USE_TZ=True.
        """
        return self._datetime_from_timestamp(
            self.client.info(path)['modified'], fmt='%a, %d %b %Y %H:%M:%S %Z')