Navigation Menu

Skip to content

Instantly share code, notes, and snippets.

@bellbind
Created July 16, 2009 15:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bellbind/148463 to your computer and use it in GitHub Desktop.
Save bellbind/148463 to your computer and use it in GitHub Desktop.
[GAE] 1File Wiki App
# -*- coding: utf-8 -*-
"""
One File Wiki Script for Google AppEngine
"""
import cgi
import re
import urllib
# use_library() from GAE 1.2.3
from google.appengine.dist import use_library
use_library("django", "1.0")
import google.appengine.ext.db as gaedb
import google.appengine.ext.webapp as gaeapp
import google.appengine.ext.webapp.template as gaetemplate
import google.appengine.api.users as gaeusers
# sync with handler url in app.yml as:
# - url: /wiki(?:/.*)?
urlbase = "/wiki"
class Page(gaedb.Expando):
name = gaedb.StringProperty()
content = gaedb.TextProperty()
pass
class Top(gaeapp.RequestHandler):
urlpattern = r"%s/?" % urlbase
def get(self):
self.redirect("%s/top" % Wiki.urlprefix)
pass
pass
class Wiki(gaeapp.RequestHandler):
urlprefix = "%s/p" % urlbase
urlpattern = r"%s(?:/.*)?" % urlprefix
def get(self):
name = self._name()
if not name:
self.redirect("%s/top" % self.urlprefix)
return
page = Wiki.page(name)
query = self._parse_query()
if "handler" in query:
self._plugin_handle_get(query["handler"], query, page)
return
self._plugin_handle_get("wiki", query, page)
html = self._render_page(page)
self.response.out.write(html)
pass
def post(self):
name = self._name()
if not name:
self.redirect("%s/top" % self.urlprefix)
return
if not Wiki.has_auth(name):
self.redirect(gaeusers.create_login_url(self.request.uri))
return
query = self._parse_query()
if "handler" in query:
self._plugin_handle_post(query["handler"], query, page)
return
page = Wiki.page(name)
self._plugin_handle_post("wiki", query, page)
page.content = gaedb.Text(
self.request.get("content", unicode(page.content)))
page.put()
self.redirect(Wiki.page_url(name))
pass
@staticmethod
def page(name):
#page = Page.gql("WHERE name = :name", name=name).get()
page = Page.all().filter("name =", name).get()
if page is None: page = Page(name=name, content=gaedb.Text(u""))
return page
_auth_pattern = re.compile(
ur"^-\s*\[\[([\w:\.\-\+\/]+)\]\]\s*$", re.M | re.U)
@staticmethod
def require_auth(name, authpagename):
authdata = unicode(Wiki.page(authpagename).content)
authnames = Wiki._auth_pattern.findall(authdata)
for authname in authnames:
if ((authname.endswith(":") and name.startswith(authname)) or
name == authname):
return True
pass
return False
_line_break_pattern = re.compile(ur"\r\n?", re.M | re.U)
@classmethod
def plugin(cls, name):
plugin_name = "plugin:%s" % name
code = unicode(cls.page(plugin_name).content)
code = cls._line_break_pattern.subn("\n", code)[0] + "\n"
compiled = compile(code, plugin_name, "exec")
plugin = {}
exec compiled in globals(), plugin
return plugin
@classmethod
def page_url(cls, name):
return "%s/%s" % (cls.urlprefix, urllib.quote(name.encode("utf-8")))
@staticmethod
def has_auth(name):
auth_admin = Wiki.require_auth(name, "system:auth:admin")
auth_user = Wiki.require_auth(name, "system:auth:user")
if (auth_admin or auth_user) and not gaeusers.get_current_user():
return False
if auth_admin and not gaeusers.is_current_user_admin():
return False
return True
def _render_page(self, page):
ctx = {
"auth": Wiki.has_auth(page.name),
"user": gaeusers.get_current_user(),
"login": gaeusers.create_login_url(self.request.uri),
"logout": gaeusers.create_logout_url(self.request.uri),
"path": Wiki.page_url(page.name),
"title": page.name,
"header": self._process_content(
Wiki.page("template:header"), page),
"top": self._process_content(Wiki.page("template:top"), page),
"content": self._process_content(page, page),
"source": unicode(page.content),
"bottom": self._process_content(
Wiki.page("template:bottom"), page),
}
html = template.render(gaetemplate.Context(ctx))
return html
def _plugin_handle_get(self, name, query, page):
plugin = Wiki.plugin(name)
get = plugin.get("get", lambda p, q, req, res: None)
try:
redirect = get(page, query, self.request, self.response)
if redirect: self.redirect(redirect)
pass
except:
import traceback
self.response.set_status(500)
self.response.headers["Content-Type"] = "text/plain;charset=UTF-8"
self.response.out.write(traceback.format_exc())
pass
pass
def _plugin_handle_post(self, name, query, page):
plugin = Wiki.plugin(name)
post = plugin.get("post", lambda p, q, req, res: None)
try:
redirect = post(page, query, self.request, self.response)
if redirect: self.redirect(redirect)
pass
except:
import traceback
self.response.set_status(500)
self.response.headers["Content-Type"] = "text/plain;charset=UTF-8"
self.response.out.write(traceback.format_exc())
pass
pass
def _parse_query(self):
return dict(cgi.parse_qsl(self.request.query_string))
def _name(self):
if not self.request.path.startswith(self.urlprefix):
return None
name = self.request.path[(len(self.urlprefix)+1):]
return unicode(urllib.unquote(name), "utf-8")
def _process_content(self, content_page, target_page):
content, count = self._process_pattern.subn(
self._wiki_processor(target_page), content_page.content)
return content
_process_pattern = re.compile(
ur"(?:\[\[([\w\s:\.\-\+\/]+)\]\])|(?:{{([\w:]+)(.*?)}})",
re.U | re.M | re.S)
def _wiki_processor(self, page):
def pattern_processor(m):
name = m.group(1)
if name:
display_name = name[(name.rfind(":")+1):]
if display_name == "": display_name = name
link = u"%s/%s" % (self.urlprefix, name)
return u"""<a href='%s'>%s</a>""" % (link, display_name)
plugin_name = m.group(2)
plugin_arg = m.group(3)
return self._render_plugin(page, plugin_name, plugin_arg)
return pattern_processor
def _render_plugin(self, page, name, arg):
plugin = Wiki.plugin(name)
inline = plugin.get("inline", lambda p, d: d)
try:
return inline(page, arg)
except:
import traceback
return traceback.format_exc()
pass
pass
template = gaetemplate.Template(u"""
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8" />
{{header|safe}}
<title>{{title}}</title>
</head>
<body>
{{top|safe}}
<div id="wiki_page">
<h1 id="wiki_name">{{title}}</h1>
<hr id="wiki_separator_content" />
<div id="wiki_content" style="white-space: pre;"
>{{content|safe}}</div>
<hr id="wiki_separator_edit" />
<div id="wiki_edit" {% if not auth %}style="display:none;"{% endif %}>
<form id="wiki_edit_form" action="{{path}}" method="POST">
<div id="wiki_editor_pane">
<textarea id="wiki_editor" name="content" rows="24" style="width:90%;"
>{{source}}</textarea>
</div>
<button id="wiki_edit_submit" type="submit">update</button>
</form>
</div>
<div id="wiki_account">
{% if user %}
<span id="wiki_account_user">{{user}}</span>
<a id="wiki_logout_link" href="{{logout}}">logout</a>
{% else %}
<a id="wiki_login_link" href="{{login}}">login</a>
{% endif %}
</div>
</div>
{{bottom|safe}}
</body>
</html>
""")
application = gaeapp.WSGIApplication(
[(Top.urlpattern, Top), (Wiki.urlpattern, Wiki)])
if __name__ == "__main__":
from google.appengine.ext.webapp.util import run_wsgi_app
run_wsgi_app(application)
pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment