class connector: def __init__(self, config): self.config = config options = { 'webdav_hostname': config['Connector']['Host'], 'webdav_login': config['Connector']['Username'], 'webdav_password': config['Connector']['Password'] } self.client = Client(options) self.client.verfiy = False self.base = config['Connector']['Base'] def listdir(self): l = self.client.list(self.base) l.pop(l.index(self.base + '/')) print(l) return l def remove(self, name): self.client.clean(self.base + '/' + name) def check(self, name): return self.client.check(self.base + '/' + name) def get(self, name): return self.client.resource(self.base + '/' + name) def create(self, name): self.client.upload_to(None, self.base + '/' + name) def upload(self, name): self.client.upload_file(self.base + '/' + name, name)
class OwncloudUser: """ This represents an owncloud user. It initialize only one connection to owncloud for one user and holds the current access token. """ _access_token = None _user_id = None def __init__(self, userId, apiKey=None): self._user_id = userId self._access_token = (apiKey if apiKey is not None else Util.loadToken( userId, "port-owncloud")) options = { "webdav_hostname": "{}/remote.php/webdav".format( os.getenv("OWNCLOUD_INSTALLATION_URL", "http://localhost:3000")), "webdav_token": self._access_token, } self.client = Client(options) self.client.verify = os.environ.get("VERIFY_SSL", "True") == "True" def getFolder(self, foldername): """Returns the files within the foldername. If a folder is in there, it returns all files within recursive. Args: foldername (str): Represents the searched foldername Returns: list: Represents all files as strings in a list. """ logger.debug("foldername {}".format(foldername)) from urllib.parse import quote, unquote if unquote(foldername) is not foldername: foldername = unquote(foldername) files = self.client.list(foldername) logger.debug("found files: {}".format(files)) # remove the first element, because this is the searched folder. del files[0] indexList = [] # TODO: needs tests. for index, file in enumerate(files): if file.endswith("/"): # save index for later removal, because we do not want the folderpaths indexList.append(index) fullname = file logger.debug( f"recursive getFolder for inner folders: {fullname}") tmpFiles = self.getFolder(foldername + "/" + fullname) for appendFile in tmpFiles: # add full filepath in context of folder files.append(fullname + appendFile) for index in indexList: del files[index] return files def getFile(self, filename): """ Returns bytesIO content from specified owncloud filepath. The path does not start with /. """ logger.debug("filename {}".format(filename)) from urllib.parse import quote, unquote # check if string is already urlencoded # if unquote is equal to string, then it is not urlencoded (unquote respects plus sign) if unquote(filename) != filename: filename = unquote(filename) from io import BytesIO buffer = BytesIO(b"") res1 = self.client.resource(filename) res1.write_to(buffer) buffer.seek(0) logger.debug("file content: {}".format(buffer.getvalue())) return buffer
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')