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)
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')