Created
August 5, 2010 12:33
-
-
Save Arachnid/509659 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
application: zip-site | |
version: main | |
runtime: python | |
api_version: 1 | |
handlers: | |
- url: /.* | |
script: main.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<html> | |
<head> | |
<title>{% block title %}Zip-site hosting{% endblock %}</title> | |
</head> | |
<body> | |
{% block body %}{% endblock %} | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% 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 %} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
{% 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