diff --git a/src/repdav/textgrid_dav_provider.py b/src/repdav/textgrid_dav_provider.py index 893f2b3960aee035672e53118c2019da74bc25dd..5f4ad4a14b5069451e5c94b16816fc52fd8fa6c9 100644 --- a/src/repdav/textgrid_dav_provider.py +++ b/src/repdav/textgrid_dav_provider.py @@ -1,41 +1,69 @@ +"""The DAV resource provider and its resources. +""" +import io import logging from wsgidav.dav_provider import DAVCollection, DAVNonCollection, DAVProvider -from wsgidav.util import join_uri +from wsgidav.util import join_uri, pop_path -from .tgapi import TextgridAuth + +from .tgapi import TextgridAuth, TextgridCRUD, TextgridSearch _logger = logging.getLogger(__name__) -class TextgridRootCollection(DAVCollection): - """top level collection that incorporates so called "projects" +# TODO think about caching with the session ID as key + +class TextgridRoot(DAVCollection): + """Top level collection that incorporates Textgrid projects. - this is implemented as READ-ONLY as project may not be created with webDAV + This is implemented as READ-ONLY as projects may not be created with webDAV. """ - def __init__(self, environ): - DAVCollection.__init__(self, "/", environ) + def __init__(self, path, environ): + DAVCollection.__init__(self, path, environ) self._sid = environ["wsgidav.auth.user_name"] _logger.debug("MY SID: %s", self._sid) - self._tg_auth = TextgridAuth() - self._projects = tuple(self._tg_auth.assigned_projects(self._sid)) - _logger.debug("MY PROJECTS: %s", self._projects) + + def get_display_info(self): + return {"type": "Textgrid root collection"} def get_member_names(self): - _logger.debug("Called get_member_names(self).") - return self._projects + _logger.debug("Called TextgridRoot.get_member_names(self).") + projects = tuple(TextgridAuth().assigned_projects(self._sid)) + _logger.debug("MY PROJECTS: %s", projects) + return projects def get_member(self, name): - _logger.debug("Called get_member(self, name).") - if name in self._projects: - return TextgridCollection(join_uri(self.path, name), self.environ) - return None - - -class TextgridCollection(DAVCollection): + _logger.debug("Called TextgridRoot.get_member(self, %s).", name) + return TextgridProject(join_uri(self.path, name), self.environ) + + # temporary override for debugging + def resolve(self, script_name, path_info): + """Return a _DAVResource object for the path (None, if not found). + `path_info`: is a URL relative to this object. + """ + _logger.debug("Called TextgridRoot.resolve(self, %s, %s).", + script_name, path_info) + if path_info in ("", "/"): + return self + assert path_info.startswith("/") + name, rest = pop_path(path_info) + res = self.get_member(name) + _logger.debug("TextgridRoot_NAME: %s, REST: %s, RES: %s", + name, rest, res) + if res is None or rest in ("", "/"): + return res + _logger.debug("RES: %s", res) + return res.resolve(join_uri(script_name, name), rest) + + +class TextgridProject(DAVCollection): def __init__(self, path, environ): + _logger.debug( + "Called TextgridProject.__init__(self, %s, environ).", path) DAVCollection.__init__(self, path, environ) + self._sid = environ["wsgidav.auth.user_name"] def create_empty_resource(self, name): pass @@ -43,28 +71,137 @@ class TextgridCollection(DAVCollection): def create_collection(self, name): pass + def get_display_info(self): + return {"type": "Textgrid project"} + def get_member_names(self): + _logger.debug("Called TextgridProject.get_member_names(self).") + # names = [] + # the item keys are textgrid uris but we want the resource titles only + # for _, member_dict in self._resources.items(): + # names.append(member_dict.get("title")) + # return names + # + # path resolution has to be rewritten before we can work with resource titles + resources = TextgridSearch().get_project_contents( + self._sid, self.path.split("/")[-1]) + _logger.debug("RESOURCES: %s", resources) + return resources.keys() + + def get_member(self, name): + _logger.debug("Called TextgridProject.get_member(self, %s).", name) + info = TextgridSearch().info(self._sid, name) + _logger.info("INFO: %s", info) + if "aggregation" in info[name]["format"]: + return TextgridAggregation(join_uri(self.path, name), self.environ, info) + return TextgridResource(join_uri(self.path, name), self.environ, info) + + def delete(self): + pass + + def copy_move_single(self, dest_path, is_move): + pass + + # temporary override for debugging + def resolve(self, script_name, path_info): + """Return a _DAVResource object for the path (None, if not found). + `path_info`: is a URL relative to this object. + """ + _logger.debug( + "Called TextgridProject.resolve(self, %s, %s).", script_name, path_info) + if path_info in ("", "/"): + return self + assert path_info.startswith("/") + name, rest = pop_path(path_info) + res = self.get_member(name) + _logger.debug( + "TextgridProject_NAME: %s, REST: %s, RES: %s", name, rest, res) + if res is None or rest in ("", "/"): + return res + return res.resolve(join_uri(script_name, name), rest) + +# TODO: merge TextgridProject with TextgridAggregation and/or derive from a common base class. + + +class TextgridAggregation(DAVCollection): + def __init__(self, path, environ, info): + _logger.debug( + "Called TextgridAggregation.__init__(self, %s, environ).", path) + DAVCollection.__init__(self, path, environ) + self._sid = environ["wsgidav.auth.user_name"] + self._info = info + + def create_empty_resource(self, name): + pass + + def create_collection(self, name): pass + def get_display_info(self): + return {"type": "Textgrid aggregation"} + + def get_member_names(self): + _logger.debug("Called TextgridAggregation.get_member_names(self).") + resources = TextgridSearch().get_aggregation_contents( + self._sid, self.path.split("/")[-1]) + #_logger.debug("RESOURCES: %s", resources) + return resources.keys() + + def get_member(self, name): + _logger.debug("Called TextgridAggregation.get_member(self, %s).", name) + info = TextgridSearch().info(self._sid, name) + _logger.info("INFO: %s", info) + if "aggregation" in info[name]["format"]: + return TextgridAggregation(join_uri(self.path, name), self.environ, info) + return TextgridResource(join_uri(self.path, name), self.environ, info) + def delete(self): pass def copy_move_single(self, dest_path, is_move): pass + # temporary override for debugging + def resolve(self, script_name, path_info): + """Return a _DAVResource object for the path (None, if not found). + `path_info`: is a URL relative to this object. + """ + _logger.debug( + "Called TextgridAggregation.resolve(self, %s, %s).", script_name, path_info) + if path_info in ("", "/"): + return self + assert path_info.startswith("/") + name, rest = pop_path(path_info) + res = self.get_member(name) + _logger.debug( + "TextgridAggregation_NAME: %s, REST: %s, RES: %s", name, rest, res) + if res is None or rest in ("", "/"): + return res + return res.resolve(join_uri(script_name, name), rest) + class TextgridResource(DAVNonCollection): - def __init__(self, path, environ): + """Non-Aggregation resources.""" + + def __init__(self, path, environ, info): + _logger.debug( + "Called TextgridResource.__init__(self, %s, environ).", path) DAVNonCollection.__init__(self, path, environ) + self._sid = environ["wsgidav.auth.user_name"] + self._info = info def get_content_length(self): - pass + _logger.debug("Called TextgridResource.get_content_length(self).") + # return TextgridCRUD().get_metadata(self._sid, self.path.split("/")[-1])["content-length"] + return self._info[self.name]["extent"] def get_content_type(self): - pass + _logger.debug("Called TextgridResource.get_content_type(self).") + # return TextgridCRUD().get_metadata(self._sid, self.path.split("/")[-1])["content-type"] + return self._info[self.name]["format"] def get_content(self): - pass + return io.BytesIO(TextgridCRUD().get_data(self._sid, self.path.split("/")[-1])) def begin_write(self, content_type=None): pass @@ -74,17 +211,16 @@ class TextgridResource(DAVNonCollection): # TextgridResourceProvider # ============================================================================ class TextgridResourceProvider(DAVProvider): - """ - DAV provider that serves Textgrid resources + """DAV provider that serves Textgrid resources. """ def __init__(self): super(TextgridResourceProvider, self).__init__() def get_resource_inst(self, path, environ): - _logger.debug("PATH: %s", path) - _logger.debug("ENVIRON: %s", environ) + _logger.debug( + "Called TextgridResourceProvider.get_resource_inst(self, %s, %s).", path, environ) self._count_get_resource_inst += 1 - root = TextgridRootCollection(environ) + root = TextgridRoot("/", environ) # an instance of _DAVResource (i.e. either DAVCollection or DAVNonCollection) - return root.resolve("", path) + return root.resolve("/", path)