#!/usr/bin/python ''' rstiki - a minimalist wiki, using reStructuredText_ syntax via docutils_, inspired by pwyky_. +-------------------------------+------------------+ | Method + URL | Action | +-------------------------------+------------------+ | GET /rst-wiki/FooBar | normal rendering | | GET /rst-wiki/FooBar?edit | edit form | | POST /rst-wiki/FooBar | edit submission | +-------------------------------+------------------+ .. _docutils: http://docutils.sourceforge.net/docs/index.html .. _reStructuredText: http://docutils.sourceforge.net/docs/user/rst/cheatsheet.txt .. _pwyky: http://infomesh.net/pwyky/ @author Josh Sled @since 2007-02-03 @license GNU GPL version 2. ''' import cgi import cgitb import docutils.core import os import os.path import textwrap class Response (object): def __init__(self, **kwargs): kwargs.setdefault('response_code', '200') kwargs.setdefault('content_type', 'text/html') kwargs.setdefault('content', '') kwargs.setdefault('headers', []) self._response_code = kwargs['response_code'] self._content_type = kwargs['content_type'] self._headers = kwargs['headers'] self._content = kwargs['content'] def _set_content_type(self, content_type): self._content_type = content_type def _set_content(self, content): self._content = content content_type = property(lambda s: s._content_type, _set_content_type) content = property(lambda s: s._content, _set_content) response_code = property(lambda s: s._response_code) headers = property(lambda s: s._headers) def get_node_name(request_uri = None): if not request_uri: request_uri = os.environ.get('REDIRECT_URL') if not request_uri: return 'index' rel_path = '/'.join(request_uri.split('/')[2:]) return rel_path def edit_fetch(form): node_name = get_node_name() node_content = '' if os.path.exists(node_name): node_file = file(node_name, 'r') node_content = node_file.read(-1) node_file.close() r = Response() r.content = common_header() + textwrap.dedent('''

syntax quickref - cheatsheet
''' % (cgi.escape(node_content))) + common_footer() return r def render(form): node_name = get_node_name() if not os.path.exists(node_name): r = Response(content=common_header() + '

[%s] does not exist; create it?

' % (node_name) + common_footer()) return r node_file = file(node_name, 'r') node_content = node_file.read(-1) node_file.close() # http://docutils.sourceforge.net/docs/howto/security.html heightened_security_settings = {'file_insertion_enabled': 0, 'raw_enabled': 0} # http://docutils.sourceforge.net/docs/api/publisher.html parts = docutils.core.publish_parts(source=node_content, writer_name='html', settings_overrides=heightened_security_settings) r = Response(content=common_header(parts['title']) + parts['html_body'] + common_footer()) return r def edit_submit(form): node_name = get_node_name() node_file = file(node_name, 'w+') node_file.write(form['content'].value) node_file.close() return render(form) # fixme, this should really be a redirect... something like: #path = os.environ.get('REQUEST_URI') #rel_url = path.split('?')[0] #new_url = 'http://%s%s' % (os.environ.get('HTTP_HOST'), rel_url) #return Response(response_code='201', # headers=[('Location',new_url)], # content= common_header('created!') + '

%(url)s created.

' % {'url':rel_url} + common_footer()) def dispatch(): form = cgi.FieldStorage(keep_blank_values=True) fn = render if form.has_key('edit'): if os.environ.get('REQUEST_METHOD') == 'POST': fn = edit_submit else: fn = edit_fetch return fn(form) def common_header(title=None): if not title: title = '(unknown)' title = 'rstiki > %s' % (title) return textwrap.dedent(''' %s ''' % (cgi.escape(title))) def common_footer(): return textwrap.dedent('''
[Edit]
''') def check_install(): if os.path.exists('.htaccess'): return None htaccess = file('.htaccess', 'w+') htaccess.write(textwrap.dedent(''' # cribbed from pwyky... DirectoryIndex index.cgi Options -MultiViews RewriteEngine on RewriteRule ^([A-Za-z0-9-]+)$ index.cgi [L] ''')) htaccess.close() return Response(content=common_header('install') + textwrap.dedent('''

rstiki installed

rstiki has been installed. You should edit the first page.

''') + common_footer()) def main(): rtn = check_install() if rtn: return rtn return dispatch() def print_response(resp): print 'Status: %s' % (resp.response_code) print 'Content-Type: ' + resp.content_type if resp.headers: for name,value in resp.headers: print '%s: %s' % (name,value) if resp.content: print '' print resp.content if __name__ == '__main__': # cgi.test() cgitb.enable() resp = main() print_response(resp)