changeset 578:1306f7d8ed35

Add support for serving zip file containing all levels.
author Simon Cross <hodgestar@gmail.com>
date Sun, 06 Oct 2013 22:47:45 +0200
parents 486c7ae141ea
children 1ba3cb3d2a93
files mamba/forest.py
diffstat 1 files changed, 62 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/mamba/forest.py	Sun Oct 06 22:46:41 2013 +0200
+++ b/mamba/forest.py	Sun Oct 06 22:47:45 2013 +0200
@@ -11,54 +11,88 @@
 import sys
 import socket
 import json
+import StringIO
+import zipfile
 
 app = Flask(__name__)
 
 
-def path(ctype):
-    main = app.config.forest.main
-    if ctype == "curated":
-        return os.path.join(main.level_folder, 'curated')
-    elif ctype == "uncurated":
-        return os.path.join(main.level_folder, 'uncurated')
-    abort(404, "Not found")
+class LevelSet(object):
+    def __init__(self, ctype):
+        self.ctype = ctype
+        self.folder = self._path(ctype)
+
+    @classmethod
+    def _path(cls, ctype):
+        main = app.config.forest.main
+        if ctype == "curated":
+            return os.path.join(main.level_folder, 'curated')
+        elif ctype == "uncurated":
+            return os.path.join(main.level_folder, 'uncurated')
+        abort(404, "Not found")
+
+    def _level_path(self, levelname):
+        filename = "%s.txt" % secure_filename(levelname)
+        return os.path.join(self.folder, filename)
+
+    def list_levels(self):
+        endl = len(".txt")
+        files = [x[:-endl] for x in os.listdir(self.folder)
+                 if not x.startswith('.') and x.endswith('.txt')]
+        return files
 
+    def read_level(self, levelname):
+        level_path = self._level_path(levelname)
+        if not os.path.isfile(level_path):
+            abort(404, "Level not found. Hsss.")
+        with open(level_path) as level:
+            return level.read()
 
-def list_levels(folder):
-    endl = len(".txt")
-    files = [x[:-endl] for x in os.listdir(folder)
-             if not x.startswith('.') and x.endswith('.txt')]
-    return "\n".join(files)
+    def write_level(self, levelname, leveldata):
+        level_path = self._level_path(levelname)
+        if os.path.exists(level_path):
+            abort(409, "Mamba already resident.")
+        with open(level_path, 'w') as level:
+            level.write(leveldata)
+
+    def zip_levels(self):
+        levels_raw = StringIO.StringIO()
+        levels_zip = zipfile.ZipFile(
+            levels_raw, "w", compression=zipfile.ZIP_DEFLATED)
+        for levelname in self.list_levels():
+            levels_zip.writestr(
+                "%s.txt" % levelname, self.read_level(levelname))
+        levels_zip.close()
+        return levels_raw.getvalue()
 
 
 @app.route("/<ctype>/index")
 def index(ctype):
-    ctype = path(ctype)
-    return list_levels(ctype)
+    ls = LevelSet(ctype)
+    levels = ls.list_levels()
+    return "\n".join(levels)
 
 
 @app.route("/<ctype>/level/<levelname>")
 def level(ctype, levelname):
-    ctype = path(ctype)
-    levelname = "%s.txt" % secure_filename(levelname)
-    levelpath = os.path.join(ctype, levelname)
-    if not os.path.isfile(levelpath):
-        abort(404, "Level not found. Hsss.")
-    with open(levelpath) as level:
-        return level.read()
+    ls = LevelSet(ctype)
+    return ls.read_level(levelname)
+
+
+@app.route("/<ctype>/levels.zip")
+def levels_zip(ctype):
+    ls = LevelSet(ctype)
+    return ls.zip_levels()
 
 
 @app.route("/save/<levelname>", methods=['GET', 'POST'])
 def save(levelname):
     ts = datetime.now().strftime("%Y%m%d.%H%M%S")
-    levelname = "%s.%s.txt" % (secure_filename(levelname), ts)
-    levelpath = os.path.join(path("uncurated"), levelname)
+    levelname = "%s.%s" % (levelname, ts)
+    ls = LevelSet("uncurated")
     if request.method == 'POST':
-        if os.path.exists(levelpath):
-            abort(409, "Mamba already resident.")
         leveldata = request.form['data'].encode('ascii')
-        with open(levelpath, 'w') as level:
-            level.write(leveldata)
+        ls.write_level(levelname, leveldata)
         inform_cia(levelname, "New level uploaded.", branch="uncurated")
         inform_irker(levelname, "New level uploaded.", branch="uncurated")
         return "Ssss."
@@ -117,7 +151,7 @@
         'author': 'unknown',
         'file': filename,
         'log': log,
-        }
+    }
     srv = xmlrpclib.Server(cia.url)
     srv.hub.deliver(msg)