From e874730679592331c481bf7137f62250e46e6e93 Mon Sep 17 00:00:00 2001 From: shortcutme <tamas@zeronet.io> Date: Wed, 2 May 2018 02:31:31 +0200 Subject: [PATCH] Rev3464, Download site as zip --- plugins/Sidebar/SidebarPlugin.py | 33 +++++++++++++++++++++++- plugins/Sidebar/ZipStream.py | 43 ++++++++++++++++++++++++++++++++ src/Config.py | 2 +- 3 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 plugins/Sidebar/ZipStream.py diff --git a/plugins/Sidebar/SidebarPlugin.py b/plugins/Sidebar/SidebarPlugin.py index 4bf716f2..962edba0 100644 --- a/plugins/Sidebar/SidebarPlugin.py +++ b/plugins/Sidebar/SidebarPlugin.py @@ -17,6 +17,7 @@ from Plugin import PluginManager from Debug import Debug from Translate import Translate from util import helper +from ZipStream import ZipStream plugin_dir = "plugins/Sidebar" media_dir = plugin_dir + "/media" @@ -62,6 +63,28 @@ class UiRequestPlugin(object): for part in super(UiRequestPlugin, self).actionUiMedia(path): yield part + def actionZip(self): + address = self.get["address"] + site = self.server.site_manager.get(address) + if not site: + return self.error404("Site not found") + + title = site.content_manager.contents.get("content.json", {}).get("title", "").encode('ascii', 'ignore') + filename = "%s-backup-%s.zip" % (title, time.strftime("%Y-%m-%d_%H_%M")) + self.sendHeader(content_type="application/zip", extra_headers={'Content-Disposition': 'attachment; filename="%s"' % filename}) + + return self.streamZip(site.storage.getPath(".")) + + def streamZip(self, file_path): + zs = ZipStream(file_path) + while 1: + data = zs.read() + if not data: + break + yield data + + + @PluginManager.registerTo("UiWebsocket") class UiWebsocketPlugin(object): @@ -137,7 +160,15 @@ class UiWebsocketPlugin(object): """)) def sidebarRenderFileStats(self, body, site): - body.append(_(u"<li><label>{_[Files]} <small><a href='#Site+directory' id='link-directory' class='link-right'>{_[Open site directory]}</a></small></label><ul class='graph graph-stacked'>")) + body.append(_(u""" + <li> + <label> + {_[Files]} + <small><a href='#Site+directory' id='link-directory' class='link-right'>{_[Open site directory]}</a> + <a href='/ZeroNet-Internal/Zip?address={site.address}' id='link-zip' class='link-right'>{_[Download as .zip]}</a></small> + </label> + <ul class='graph graph-stacked'> + """)) extensions = ( ("html", "yellow"), diff --git a/plugins/Sidebar/ZipStream.py b/plugins/Sidebar/ZipStream.py new file mode 100644 index 00000000..a78eac2b --- /dev/null +++ b/plugins/Sidebar/ZipStream.py @@ -0,0 +1,43 @@ +import cStringIO as StringIO +import os +import zipfile + + +class ZipStream(file): + def __init__(self, dir_path): + self.dir_path = dir_path + self.pos = 0 + self.zf = zipfile.ZipFile(self, 'w', zipfile.ZIP_DEFLATED) + self.buff = StringIO.StringIO() + self.file_list = self.getFileList() + + def getFileList(self): + for root, dirs, files in os.walk(self.dir_path): + for file in files: + file_path = root + "/" + file + relative_path = os.path.join(os.path.relpath(root, self.dir_path), file) + yield file_path, relative_path + self.zf.close() + + def read(self, size=60 * 1024): + for file_path, relative_path in self.file_list: + self.zf.write(file_path, relative_path) + if self.buff.tell() >= size: + break + self.buff.seek(0) + back = self.buff.read() + self.buff.truncate(0) + return back + + def write(self, data): + self.pos += len(data) + self.buff.write(data) + + def tell(self): + return self.pos + + def seek(self, pos, type): + pass + + def flush(self): + pass diff --git a/src/Config.py b/src/Config.py index 0de9c3bf..0c00c84d 100644 --- a/src/Config.py +++ b/src/Config.py @@ -10,7 +10,7 @@ class Config(object): def __init__(self, argv): self.version = "0.6.2" - self.rev = 3465 + self.rev = 3467 self.argv = argv self.action = None self.config_file = "zeronet.conf"