""" open/dulcinea/lib/ui/browse.qpy """ from dulcinea.archive import TarFileWrapper, ZipFileWrapper from qp.fill.stored_file import thumbnail_response from qp.fill.directory import Directory from qp.fill.html import htmltag, href from qp.fill.static import FileStream from qp.pub.common import get_request, get_response from qp.pub.common import header, footer, not_found import mimetypes import tarfile import zipfile import sys import os from qp.fill.stored_file import guess_mime_type class ArchiveDirectory (Directory): def __init__(self, path_to_archive, path_in_archive='', archive_wrapper=None, decorate=None, obj=None): self.path_to_archive = path_to_archive self.path_in_archive = path_in_archive self.archive_wrapper = archive_wrapper self.obj = obj if decorate: self.decorate = decorate def get_archive_wrapper(self): if not self.archive_wrapper: if zipfile.is_zipfile(self.path_to_archive): self.archive_wrapper = ZipFileWrapper(self.path_to_archive) else: self.archive_wrapper = TarFileWrapper(self.path_to_archive) return self.archive_wrapper def get_exports(self): if self.path_in_archive: crumb = self.path_in_archive.split('/')[-2] else: crumb = 'Browse' yield ('', '_q_index', crumb, None) def __call__(self): if not self.path_in_archive: get_response().set_content_type('application/octet-stream', None) try: stat = os.stat(self.path_to_archive) except OSError: print(sys.exc_info()[1]) not_found() return FileStream(open(self.path_to_archive, 'rb'), length=stat.st_size) def _q_lookup(self, component): member_name = self.path_in_archive + component if self.get_archive_wrapper().has_member(member_name): # file return self.file_response(member_name) member_name += '/' # if not self.get_archive_wrapper().has_member(member_name): # not found # return None # directory return self.__class__(self.path_to_archive, path_in_archive=member_name, archive_wrapper=self.archive_wrapper, decorate=self.decorate, obj=self.obj) def file_response(self, member_name): mime_type = guess_mime_type(member_name, fallback='text/plain') get_response().set_content_type(mime_type, None) return self.get_archive_wrapper().get_member_response(member_name) def get_children(self): child_name_slashes = self.path_in_archive.count('/') children = [ name[len(self.path_in_archive):] for name in self.get_archive_wrapper().get_names() if (name.startswith(self.path_in_archive) and child_name_slashes == name[:-1].count('/') and name != '/') ] return sorted(children) def _q_index(self): def directory:xml(): if self.path_in_archive.count('/') > 1: href('..', '..') '
' else: href('../..', '..') '
' for child in self.get_children(): href(child, child, css_class="filename") '
' return self.decorate(self.obj, directory(), title=self.path_in_archive) def decorate:xml(self, obj, content, title=None): header(title) '
' content '
' footer(title) class ImageArchiveDirectory (ArchiveDirectory): def file_response(self, member_name): mime_type = guess_mime_type(member_name, fallback='text/plain') if (mime_type.startswith('image/') and not mime_type.endswith('photoshop') and get_request().get_query()): return thumbnail_response( self.get_archive_wrapper().get_member_file(member_name)) get_response().set_content_type(mime_type, None) return self.get_archive_wrapper().get_member_response(member_name) def _q_index(self): def directory:xml(): if self.path_in_archive.count('/') > 0: href('..', '..') '
' else: href('../..', '..') '
' for child in self.get_children(): member_name = self.path_in_archive + child '
' if not child.endswith(str('/')): if guess_mime_type(child).startswith(str('image/')): href(child, htmltag('img', src='%s?50' % child, alt='[Thumbnail]', xml_end=True)) href(child, child, css_class="filename") '
' return self.decorate(self.obj, directory(), title=self.path_in_archive) class IndexArchiveDirectory (ArchiveDirectory): def _q_index(self): index_html = self._q_lookup('index.html') if index_html: return index_html return ArchiveDirectory._q_index(self) def format_browse_css:str(): """ div.archive_file { margin-top: 0.5em; margin-bottom: 0.5em; } div.archive_file img { margin-right: 1ex; vertical-align: top; } """