All pastes #190143 Raw Edit

Stuff

public python v1 · immutable
·published 2006-10-03 19:22 UTC
rendered paste body
"""tw.cgiA Python-based backend for TiddlyWiki."""__author__ = "Joseph Reisinger (joeraii@cs.utexas.edu)"__copyright__ = "Copyright 2005, Joseph Reisinger"__contributors__ = ['Andrew Nelis (andrew.nelis@gmail.com)', 'Devon Jones (soulcatcher@evilsoft.org)', 'Rodney Gomes (rodneygomes@gmail.com)']__version__ = "1.1.0.1 $Rev:$"__license__ = "GPL"__history__ = """Version 1.1.0.1:    - Cleaned up revisions handling (Rodney)    - Fix a newline bug with IE (Devon)    - Sync to TW 1.2.38Version 1.1:    - Architecture change: added a type to each tiddler to track what importer      handles it. (Joe)    - Cleaned up/optimized refresh.js. (Joe)    - Bugfix: Fixed a small newline bug (Joe) and a similar bug with \s (Devon)    - Bugfix: disabled "save changes" (Devon)    - Added a mysql database backend (Devon)    - Added a set of plugins for displaying revisions (Rodney)See README for older versions."""import os, sys, time################################################################################ Configuration and Global Parameters################################################################################ The base html file from http://www.tiddlywiki.com (sans the last few lines)TWBase = 'tiddlywiki-1.2.38.html'# Javascript plugins. remote.js is mandatory for pytw to work, but can be# removed to disable serverside functionality cleanly.TWPlugins = ['remote.js', 'refresh.js', 'revisions.js']# Importers for turning other kinds of files into tiddlers. pytw uses pickle# Static importers are cached on write, while Dynamic importers are not.StaticContent  = ['pickleimporter', 'lockimporter'] DynamicContent = ['pdfimporter'] # Handlers for cgi requests. Format is CGIFormAttribute:python module .Handlers = {'save':'save', 'delete':'delete', 'refresh':'refresh', 'revisions':'revisions'}# Where the html div cache is stored. CachePath = 'store/tiddler_divs_html.cache'# Used for timestamping on save. Best not to change this.CurrentTime = time.strftime('%Y%m%d%H%M')################################################################################ Code###############################################################################def escape_html(text):    """Does the same as cgi.escape but doesn't require the cgi module to be    loaded."""    return text.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')def extract( form, name ):    """    Safe Extraction from a CGI form. All unicode encoding is done here.    """    return unicode( form.getvalue(name, '').replace(r'\s', '\ss').replace(r'\n','\sn').replace('\n','\\n'), 'utf-8' ).encode('utf-8')def form_to_tiddler( form ):    """    Set up the Tiddler content variables. Not Pythonic, I'm sure.    """    return {'title': extract( form, 'title' ),            'oldtitle': extract( form, 'oldtitle' ),            'body': extract( form, 'body' ),            'author': extract( form, 'author' ),            'tags': extract( form, 'tags' ),            'modified': CurrentTime}def tiddler_to_markup( content, type='undefined' ):    """    Returns the <div/> for the tiddler.    """    fields = tuple(map(escape_html, (content['title'], content['modified'], content['author'], content['tags'], type, content['body'].replace('\n','\\n'))))    return '<div tiddler="%s" modified="%s" modifier="%s" tags="%s" type="%s">%s</div>\n' % fieldsdef get_html_content( content_type, store_files=None ):    """Runs load_tiddlers on each plugin in content_type, sending them    store_files, if available. Very proud of this."""    return ''.join( [__import__(plugin).load_tiddlers( store_files ) for plugin in content_type] )def get_divs( force_reload = False ):    """    Reads all the entries in the store and returns them as a set of <divs> for    direct HTML inclusion.    """    store_files = os.listdir( 'store/' )        # Read static tiddlers from cache if we are allowed/can    if not force_reload and os.path.exists( CachePath ):        div_html = open( CachePath ).read()     else: # Otherwise read and re-cache the static tiddlers.        div_html = get_html_content( StaticContent, store_files )                # Cache the static tiddlers. TODO: fcntl here too?        try:            open( CachePath, 'w' ).write( div_html )        except:            print 'Error writing cache "%s".' % CachePath        # Always refresh dynamic tiddlers.     div_html += get_html_content( DynamicContent, store_files )        return div_htmldef handle_post():    """Handle a save/delete from the client. cgi is massive, use it sparingly."""    from cgi import FieldStorage    form = FieldStorage()        # Look through our handlers to find a (single) match.    for (key, handler) in Handlers.items():        if form.has_key( key ):            __import__(handler).handle( form )            breakdef render_page( ):    """     Send out the page contents. TODO: HACK: Removed the last three tags    present in the tiddlywiki base file. """    print 'Content-type: text/html; charset=utf-8\n'    print open( TWBase ).read()    # Read each filename from the TOC and inject it into the markup at load.    print get_divs()    # Close the markup.    print '</div></body></html>'    # Include the plugins:    print '<script type="text/javascript">'    for plugin in TWPlugins:        print open( 'plugins/%s' % plugin ).read()    print '</script>'def execute():    """    Actually runs the cgi script.    """    # Add the handler and importer paths.    sys.path.append( 'importers/' )    sys.path.append( 'handlers/' )    # Forbid certain kinds of interactions, and fail elegantly, e.g. on 405 request methods.    request_method = os.environ['REQUEST_METHOD']    if request_method == 'POST':        handle_post()    elif request_method == 'GET':        render_page()