import datetime import os import shutil import logging from sys import getfilesystemencoding from django.utils.decorators import method_decorator from django_http_auth.decorators import http_basic_auth from djangodav.acls import FullAcl from djangodav.base.resources import BaseDavResource, MetaEtagMixIn from djangodav.locks import DummyLock from djangodav.utils import url_join from djangodav.views import DavView from procat2.models import Catalog # from procat2.settings import ASSET_DIR log = logging.getLogger(__name__) fs_encoding = getfilesystemencoding() @method_decorator(http_basic_auth, name='dispatch') class MarkupDavView(DavView): def __init__(self): super(DavView, self).__init__(resource_class=MarkupDavResource, lock_class=DummyLock, acl_class=FullAcl) class MarkupDavResource(MetaEtagMixIn, BaseDavResource): ROOT_FOLDER = '' MY_CATS_FOLDER = 'My Catalogs' MARKUP_SUBMIT_FOLDER = 'For Markup' #root = '/opt/imagebank/mkbeta/webdav' # TODO replace with settings var def __init__(self, path=None, user=None): super().__init__(path) self.user = user def __str__(self): return f"" def get_children(self): """Return an iterator of all direct children of this resource.""" # make sure the current object is a directory path = self.get_path() log.info(f"get_children of '{path}'") children = [] if path == '/': children = [self.MY_CATS_FOLDER, self.MARKUP_SUBMIT_FOLDER] elif path == f'/{self.MY_CATS_FOLDER}/': children = self.user_catalogs() elif path == f'/{self.MARKUP_SUBMIT_FOLDER}/': children = None # else: # path = self.get_abs_path() # if os.path.isdir(path): # children = os.listdir(path) for child in children: is_unicode = isinstance(child, str) if not is_unicode: child = child.decode(fs_encoding) child_resource = self.clone(path=url_join(*(self.path + [child])), user=self.user) log.info(f'returning kid {child_resource}') yield child_resource def user_catalogs(self): cats = Catalog.objects.filter(owner=self.user).order_by('-updated') return [c.name for c in cats] def get_abs_path(self): """Return the absolute path of the resource. Used internally to interface with an actual file system. If you override all other methods, this one will not be used.""" return os.path.join(self.root, *self.path) @property def getcontentlength(self): """Return the size of the resource in bytes.""" if self.is_collection: return 0 else: return os.path.getsize(self.get_abs_path()) def get_created(self): """Return the create time as datetime object.""" if self.is_collection: return datetime.datetime.now() # TODO last created time of object in there? else: return datetime.datetime.fromtimestamp(os.stat(self.get_abs_path()).st_ctime) def get_modified(self): """Return the modified time as datetime object.""" if self.is_collection: return datetime.datetime.now() # TODO last modified time of object in there? else: return datetime.datetime.fromtimestamp(os.stat(self.get_abs_path()).st_mtime) @property def is_collection(self): """Return True if this resource is a directory (collection in WebDAV parlance).""" path = '/'.join(self.path) # log.info(f"is_collection {self.path}") if path in [self.ROOT_FOLDER, self.MY_CATS_FOLDER, self.MARKUP_SUBMIT_FOLDER]: return True return False # return os.path.isdir(self.get_abs_path()) @property def is_object(self): """Return True if this resource is a file (resource in WebDAV parlance).""" path = '/'.join(self.path) log.info(f"is_object {path}") if self.is_collection: return False # TODO test catalog pdf return True #return os.path.isfile(self.get_abs_path()) @property def exists(self): """Return True if this resource exists.""" path = '/'.join(self.path) log.info(f"exists {path}") if self.is_collection: return True # TODO test catalog pdf return os.path.exists(self.get_abs_path()) # def write(self, content, temp_file=None, range_start=None): # raise NotImplementedError # def read(self): # raise NotImplementedError # def delete(self): # """Delete the resource, recursive is implied.""" # if self.is_collection: # for child in self.get_children(): # child.delete() # os.rmdir(self.get_abs_path()) # elif self.is_object: # os.remove(self.get_abs_path()) # def create_collection(self): # """Create a directory in the location of this resource.""" # os.mkdir(self.get_abs_path()) # def copy_object(self, destination, depth=0): # shutil.copy(self.get_abs_path(), destination.get_abs_path()) # def move_object(self, destination): # os.rename(self.get_abs_path(), destination.get_abs_path()) # def read(self): # return open(self.get_abs_path(), 'rb') # def write(self, request, temp_file=None, range_start=None): # if temp_file: # # move temp file (e.g., coming from nginx) # shutil.move(temp_file, self.get_abs_path()) # elif range_start == None: # # open binary file and write to disk # with open(self.get_abs_path(), 'wb') as dst: # shutil.copyfileobj(request, dst) # else: # # open binary file and write to disk # with open(self.get_abs_path(), 'r+b') as dst: # dst.seek(range_start) # shutil.copyfileobj(request, dst)