Skip to content

Instantly share code, notes, and snippets.

@Arachnid
Created August 5, 2010 12:33
Show Gist options
  • Star 7 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Arachnid/509659 to your computer and use it in GitHub Desktop.
Save Arachnid/509659 to your computer and use it in GitHub Desktop.
application: zip-site
version: main
runtime: python
api_version: 1
handlers:
- url: /.*
script: main.py
<html>
<head>
<title>{% block title %}Zip-site hosting{% endblock %}</title>
</head>
<body>
{% block body %}{% endblock %}
</body>
</html>
{% extends "base.html" %}
{% block body %}
<h1>Zip-site hosting</h1>
<p>This is a demo app for BlobReader and other features. See the article
<a href="http://blog.notdot.net/2010/08/Using-BlobReader-wildcard-subdomains-and-webapp2">here</a>,
and get the complete source <a href="http://gist.github.com/509659">here</a>.</p>
{% if sites %}
<h2>Your sites</h2>
<table>
<tr><th>Site Name</th><th>Last Updated</th><th>Actions</th></tr>
{% for site in sites %}
<tr>
<th><a href="http://{{site.url}}/">{{site.key.name|escape}}</a></th>
<td>{{site.last_updated}}</td>
<td><a href="/upload?site={{site.key.name|escape}}">Upload</a></td>
</tr>
{% endfor %}
</table>
{% endif %}
<h2><a href="{{upload_url}}">Upload a new site</a></h2>
{% endblock %}
from google.appengine.api import users
from google.appengine.ext import blobstore
from google.appengine.ext import db
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template
import logging
import mimetypes
import os
import re
import zipfile
import webapp2
BASE_DOMAIN = "%s.appspot.com" % os.environ['APPLICATION_ID']
class Site(db.Model):
owner = db.UserProperty(required=True)
last_updated = db.DateTimeProperty(required=True, auto_now=True)
zipfile = blobstore.BlobReferenceProperty(required=True)
@property
def url(self):
return '%s.%s' % (self.key().name(), BASE_DOMAIN)
class BaseHandler(webapp2.RequestHandler):
def __call__(self, *args, **kwargs):
self.user = users.get_current_user()
if not self.user:
self.redirect(users.create_login_url(self.request.url))
else:
return super(BaseHandler, self).__call__(*args, **kwargs)
def render_template(self, file, template_vars):
path = os.path.join(os.path.dirname(__file__), 'templates', file)
self.response.out.write(template.render(path, template_vars))
class MainHandler(BaseHandler):
def get(self):
sites = Site.all().filter('owner =', self.user).fetch(20)
self.render_template('index.html', {
'sites': sites,
'upload_url': self.url_for('upload'),
})
class UploadHandler(BaseHandler):
def get(self):
self.render_template('upload.html', {
'upload_url': blobstore.create_upload_url(self.url_for('upload')),
'site_name': self.request.GET.get('site', None),
})
def post(self):
site = self.request.POST['site']
blob_key = blobstore.parse_blob_info(self.request.POST['file'])
db.run_in_transaction(self.upload_tx, site, blob_key)
self.redirect_to('main')
def upload_tx(self, site_name, blob_key):
site = Site.get_by_key_name(site_name)
if site:
if site.owner != self.user: return
site.zipfile.delete()
site.zipfile = blob_key
else:
site = Site(key_name=site_name, owner=self.user, zipfile=blob_key)
db.put(site)
INDEX_FILES = ['index.html', 'index.htm']
SUBDOMAIN_RE = re.compile("^([^.]+)\.%s\.appspot\.com$"
% os.environ['APPLICATION_ID'])
class SiteHandler(webapp2.RequestHandler):
def get(self, path):
site_name = SUBDOMAIN_RE.search(self.request.host).group(1)
site = Site.get_by_key_name(site_name)
if not site:
self.abort(404)
zip_key = Site.zipfile.get_value_for_datastore(site)
site_zip = zipfile.ZipFile(blobstore.BlobReader(zip_key))
path, data = self.get_contents(site_zip, path)
self.response.headers['Content-Type'] = mimetypes.guess_type(path)[0]
self.response.out.write(data)
def get_contents(self, site_zip, path):
if path.endswith('/'):
for idx in INDEX_FILES:
newpath = os.path.join(path, idx)[1:]
try:
data = site_zip.read(newpath)
return newpath, data
except KeyError:
pass
self.abort(404)
else:
try:
return path, site_zip.read(path[1:])
except KeyError:
self.abort(404)
main_app = webapp2.WSGIApplication([
webapp2.Route(r'/', MainHandler, name='main'),
webapp2.Route(r'/upload', UploadHandler, name='upload'),
])
site_app = webapp2.WSGIApplication([
webapp2.Route(r'<path:.*>', SiteHandler),
])
def domain_middleware(domain_map):
domain_map = [(re.compile('^%s$' % x) if isinstance(x, basestring) else x, y)
for x, y in domain_map]
def middleware(environ, start_response):
domain = environ['SERVER_NAME']
for regex, app in domain_map:
if regex.match(domain):
return app(environ, start_response)
return middleware
app = domain_middleware([
(SUBDOMAIN_RE, site_app),
('.*', main_app),
])
def main():
run_wsgi_app(app)
if __name__ == '__main__':
main()
{% extends "base.html" %}
{% block body %}
<h1>Zip-site hosting</h1>
<h2>Upload zipped site</h2>
<form action="{{upload_url}}" method="POST" enctype="multipart/form-data">
<table>
<tr>
<th>Site name:</th>
<td>{% if site_name %}
{{site_name|escape}}
<input type="hidden" name="site" value="{{site_name|escape}}" />
{% else %}
<input type="text" name="site" />
{% endif %}</td>
</tr>
<tr>
<th>Zip file</th>
<td><input type="file" name="file" /></td>
</tr>
</table>
<input type="submit" value="Upload" />
</form>
{% endblock %}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment