Commits

Anonymous committed 2198106

[svn] Merged 0.1.5 into trunk

  • Participants
  • Parent commits 2b3dd8b

Comments (0)

Files changed (37)

+recursive-include quickwiki/public *
+recursive-include quickwiki/templates *

QuickWiki.egg-info/entry_points.txt

 
     [paste.app_factory]
-    main=quickwiki:make_app
+    main=quickwiki.config.middleware:make_app
     [paste.app_install]
     main=paste.script.appinstall:Installer
     

QuickWiki.egg-info/paste_deploy_config.ini_tmpl

 
 [app:main]
 use = egg:QuickWiki
-session_key = quickwiki
-session_secret = ${app_instance_secret}
+full_stack = true
+cache_dir = %(here)s/data
+beaker.session.key = quickwiki
+beaker.session.secret = ${app_instance_secret}
 app_instance_uuid = ${app_instance_uuid}
-cache_dir = %(here)s/data
+
+# Specify the database for SQLAlchemy to use.
+# %(here) may include a ':' character on Windows environments; this can
+# invalidate the URI when specifying a SQLite db via path name
+#sqlalchemy.default.url = sqlite:///%(here)s/quickwiki.db
+#sqlalchemy.echo = true
 
 # If you'd like to fine-tune the individual locations of the cache data dirs
-# for Myghty, the Cache data, or the Session saves, un-comment the desired
-# settings here:
-#myghty_data_dir = %(here)s/data/templates
-#cache_data_dir = %(here)s/data/cache
-#session_data_dir = %(here)s/data/sessions
-
-# Specify the database for SQLAlchemy to use via
-# pylons.database.session_context.
-# %(here) may include a ':' character on Windows environments; this can
-# invalidate the URI when specifying a SQLite db via path name
-sqlalchemy.dburi = postgres://username:password@localhost/quickwiki_test
-# Uncomment the line below to have SQLAlchemy echo SQL for debugging  
-#sqlalchemy.echo = true
-
-# Specify the database for SQLObject to use via pylons.database.PackageHub.
-#sqlobject.dburi = sqlite://%(here)s/somedb.db
+# for the Cache data, or the Session saves, un-comment the desired settings
+# here:
+#beaker.cache.data_dir = %(here)s/data/cache
+#beaker.session.data_dir = %(here)s/data/sessions
 
 # WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
 # Debug mode will enable the interactive debugging tool, allowing ANYONE to
 # execute malicious code after an exception is raised.
 set debug = false
+
+
+# Logging configuration
+[loggers]
+keys = root
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s %(levelname)-5.5s [%(name)s] %(message)s
 Make a config file as follows::
 
     paster make-config QuickWiki config.ini
-    
+
 Tweak the config file as appropriate and then setup the application::
 
     paster setup-app config.ini
-    
+
 Then you are ready to go.
 #
 [DEFAULT]
 debug = true
-email_to = you@yourdomain.com
+# Uncomment and replace with the address which should receive any error reports
+#email_to = you@yourdomain.com
 smtp_server = localhost
 error_email_from = paste@localhost
 
 
 [app:main]
 use = egg:QuickWiki
-session_key = quickwiki
-session_secret = somesecret
-cache_dir = %(here)s/data/cache
+full_stack = true
+cache_dir = %(here)s/data
+beaker.session.key = quickwiki
+beaker.session.secret = somesecret
+
+# Specify the database for SQLAlchemy to use.
+# %(here) may include a ':' character on Windows environments; this can
+# invalidate the URI when specifying a SQLite db via path name
+sqlalchemy.default.url = sqlite:///%(here)s/quickwiki.db
+sqlalchemy.echo = true
 
 # If you'd like to fine-tune the individual locations of the cache data dirs
-# for Myghty, the Cache data, or the Session saves, un-comment the desired
-# settings here:
-#myghty_data_dir = %(here)s/data/templates
-#cache_data_dir = %(here)s/data/cache
-#session_data_dir = %(here)s/data/sessions
-
-# Specify the database for SQLAlchemy to use via
-# pylons.database.session_context.
-# %(here) may include a ':' character on Windows environments; this can
-# invalidate the URI when specifying a SQLite db via path name
-sqlalchemy.dburi = postgres://@localhost/quickwiki_test
-# Uncomment the line below to have SQLAlchemy echo SQL for debugging  
-#sqlalchemy.echo = true
-
-# Specify the database for SQLObject to use via pylons.database.PackageHub.
-#sqlobject.dburi = sqlite://%(here)s/somedb.db
+# for the Cache data, or the Session saves, un-comment the desired settings
+# here:
+#beaker.cache.data_dir = %(here)s/data/cache
+#beaker.session.data_dir = %(here)s/data/sessions
 
 # WARNING: *THE LINE BELOW MUST BE UNCOMMENTED ON A PRODUCTION ENVIRONMENT*
 # Debug mode will enable the interactive debugging tool, allowing ANYONE to
 # execute malicious code after an exception is raised.
 #set debug = false
+
+
+# Logging configuration
+[loggers]
+keys = root, quickwiki
+
+[handlers]
+keys = console
+
+[formatters]
+keys = generic
+
+[logger_root]
+level = INFO
+handlers = console
+
+[logger_quickwiki]
+level = DEBUG
+handlers =
+qualname = quickwiki
+
+[handler_console]
+class = StreamHandler
+args = (sys.stderr,)
+level = NOTSET
+formatter = generic
+
+[formatter_generic]
+format = %(asctime)s,%(msecs)03d %(levelname)-5.5s [%(name)s] %(message)s
+datefmt = %H:%M:%S
+quickwiki
++++++++++
+
+This is the main index page of your documentation. It should be written in
+`reStructuredText format <http://docutils.sourceforge.net/rst.html>`_.
+
+You can generate your documentation in HTML format by running this command::
+
+    setup.py pudge
+
+For this to work you will need to download and install ``buildutils`` and
+``pudge``.

quickwiki/__init__.py

-"""
-quickwiki
-
-This file loads the finished app from quickwiki.config.middleware.
-
-"""
-
-from quickwiki.config.middleware import make_app

quickwiki/config/__init__.py

-#

quickwiki/config/environment.py

+"""Pylons environment configuration"""
 import os
 
-import pylons.config
-import webhelpers
+from pylons import config
+from sqlalchemy import engine_from_config
 
+import quickwiki.lib.app_globals as app_globals
+import quickwiki.lib.helpers
 from quickwiki.config.routing import make_map
 
-def load_environment(global_conf={}, app_conf={}):
-    map = make_map(global_conf, app_conf)
-    # Setup our paths
-    root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
-    paths = {'root_path': root_path,
-             'controllers': os.path.join(root_path, 'controllers'),
-             'templates': [os.path.join(root_path, path) for path in \
-                           ('components', 'templates')],
-             'static_files': os.path.join(root_path, 'public')
-             }
-    
-    # The following options are passed directly into Myghty, so all configuration options
-    # available to the Myghty handler are available for your use here
-    myghty = {}
-    myghty['log_errors'] = True
-    myghty['escapes'] = dict(l=webhelpers.auto_link, s=webhelpers.simple_format)
-    
-    # Add your own Myghty config options here, note that all config options will override
-    # any Pylons config options
-    
-    # Return our loaded config object
-    return pylons.config.Config(myghty, map, paths)
+def load_environment(global_conf, app_conf):
+    """Configure the Pylons environment via the ``pylons.config`` object"""
+    # Pylons paths
+    root = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+    paths = dict(root=root,
+                 controllers=os.path.join(root, 'controllers'),
+                 static_files=os.path.join(root, 'public'),
+                 templates=[os.path.join(root, 'templates')])
+
+    # Initialize config with the basic options
+    config.init_app(global_conf, app_conf, package='quickwiki',
+                    template_engine='mako', paths=paths)
+
+    config['pylons.g'] = app_globals.Globals()
+    config['pylons.h'] = quickwiki.lib.helpers
+    config['routes.map'] = make_map()
+
+    # Customize templating options via this variable
+    tmpl_options = config['buffet.template_options']
+
+    # CONFIGURATION OPTIONS HERE (note: all config options will override any
+    # Pylons config options)
+    config['pylons.g'].sa_engine = engine_from_config(config, 'sqlalchemy.default.')

quickwiki/config/middleware.py

-from paste import httpexceptions
+"""Pylons middleware initialization"""
 from paste.cascade import Cascade
+from paste.registry import RegistryManager
 from paste.urlparser import StaticURLParser
-from paste.registry import RegistryManager
-from paste.deploy.config import ConfigMiddleware, CONFIG
 from paste.deploy.converters import asbool
 
+from pylons import config
 from pylons.error import error_template
-from pylons.middleware import ErrorHandler, ErrorDocuments, StaticJavascripts, error_mapper
-import pylons.wsgiapp
+from pylons.middleware import error_mapper, ErrorDocuments, ErrorHandler, \
+    StaticJavascripts
+from pylons.wsgiapp import PylonsApp
 
 from quickwiki.config.environment import load_environment
-import quickwiki.lib.helpers
-import quickwiki.lib.app_globals as app_globals
 
 def make_app(global_conf, full_stack=True, **app_conf):
-    """Create a WSGI application and return it
-    
-    global_conf is a dict representing the Paste configuration options, the
-    paste.deploy.converters should be used when parsing Paste config options
-    to ensure they're treated properly.
-    
+    """Create a Pylons WSGI application and return it
+
+    ``global_conf``
+        The inherited configuration for this application. Normally from the
+        [DEFAULT] section of the Paste ini file.
+
+    ``full_stack``
+        Whether or not this application provides a full WSGI stack (by default,
+        meaning it handles its own exceptions and errors). Disable full_stack
+        when this application is "managed" by another WSGI middleware.
+
+    ``app_conf``
+        The application's local configuration. Normally specified in the
+        [app:<name>] section of the Paste ini file (where <name> defaults to
+        main).
     """
-    # Setup the Paste CONFIG object
-    CONFIG.push_process_config({'app_conf': app_conf,
-                                'global_conf': global_conf})
+    # Configure the Pylons environment
+    load_environment(global_conf, app_conf)
 
-    # Load our Pylons configuration defaults
-    config = load_environment(global_conf, app_conf)
-    config.init_app(global_conf, app_conf, package='quickwiki')
-        
-    # Load our default Pylons WSGI app and make g available
-    app = pylons.wsgiapp.PylonsApp(config, helpers=quickwiki.lib.helpers,
-                                   g=app_globals.Globals)
-    g = app.globals
-    app = ConfigMiddleware(app, {'app_conf':app_conf,
-        'global_conf':global_conf})
-    
-    # YOUR MIDDLEWARE
-    # Put your own middleware here, so that any problems are caught by the error
-    # handling middleware underneath
-    
-    # If errror handling and exception catching will be handled by middleware
-    # for multiple apps, you will want to set full_stack = False in your config
-    # file so that it can catch the problems.
+    # The Pylons WSGI app
+    app = PylonsApp()
+
+    # CUSTOM MIDDLEWARE HERE (filtered by the error handling middlewares)
+
     if asbool(full_stack):
-        # Change HTTPExceptions to HTTP responses
-        app = httpexceptions.make_middleware(app, global_conf)
-    
-        # Error Handling
-        app = ErrorHandler(app, global_conf, error_template=error_template, **config.errorware)
-    
-        # Display error documents for 401, 403, 404 status codes (if debug is disabled also
-        # intercepts 500)
+        # Handle Python exceptions
+        app = ErrorHandler(app, global_conf, error_template=error_template,
+                           **config['pylons.errorware'])
+
+        # Display error documents for 401, 403, 404 status codes (and 500 when
+        # debug is disabled)
         app = ErrorDocuments(app, global_conf, mapper=error_mapper, **app_conf)
-    
+
     # Establish the Registry for this application
     app = RegistryManager(app)
-    
-    static_app = StaticURLParser(config.paths['static_files'])
+
+    # Static files
     javascripts_app = StaticJavascripts()
+    static_app = StaticURLParser(config['pylons.paths']['static_files'])
     app = Cascade([static_app, javascripts_app, app])
     return app

quickwiki/config/routing.py

+"""Routes configuration
+
+The more specific and detailed routes should be defined first so they may take
+precedent over the more generic routes. For more information refer to the
+routes manual at http://routes.groovie.org/docs/
 """
-Setup your Routes options here
-"""
-import os
+from pylons import config
 from routes import Mapper
 
-def make_map(global_conf={}, app_conf={}):
-    root_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+def make_map():
+    """Create, configure and return the routes Mapper"""
+    map = Mapper(directory=config['pylons.paths']['controllers'],
+                 always_scan=config['debug'])
 
-    map = Mapper(directory=os.path.join(root_path, 'controllers'))
-    
-    # This route handles displaying the error page and graphics used in the 404/500
-    # error pages. It should likely stay at the top to ensure that the error page is
-    # displayed properly.
+    # The ErrorController route (handles 404/500 error pages); it should likely
+    # stay at the top, ensuring it can always be resolved
     map.connect('error/:action/:id', controller='error')
-    
-    # Define your routes. The more specific and detailed routes should be defined first,
-    # so they may take precedent over the more generic routes. For more information, refer
-    # to the routes manual @ http://routes.groovie.org/docs/
+
+    # CUSTOM ROUTES HERE
+
     map.connect(':controller/:action/:title', controller='page', action='index', title='FrontPage')
     map.connect(':title', controller='page', action='index', title='FrontPage')
     map.connect('*url', controller='template', action='view')

quickwiki/controllers/error.py

 import os.path
-from paste import fileapp
-from pylons.middleware import media_path, error_document_template
-from pylons.util import get_prefix
+
+import paste.fileapp
+from pylons.middleware import error_document_template, media_path
+
 from quickwiki.lib.base import *
 
 class ErrorController(BaseController):
-    """
-    Class to generate error documents as and when they are required. This behaviour of this
-    class can be altered by changing the parameters to the ErrorDocuments middleware in 
-    your config/middleware.py file.
+    """Generates error documents as and when they are required.
+
+    The ErrorDocuments middleware forwards to ErrorController when error
+    related status codes are returned from the application.
+
+    This behaviour can be altered by changing the parameters to the
+    ErrorDocuments middleware in your config/middleware.py file.
     """
 
     def document(self):
-        """
-        Change this method to change how error documents are displayed
-        """
-        page = error_document_template % {
-            'prefix': get_prefix(request.environ),
-            'code': request.params.get('code', ''),
-            'message': request.params.get('message', ''),
-        }
-        return Response(page)
+        """Render the error document"""
+        page = error_document_template % \
+            dict(prefix=request.environ.get('SCRIPT_NAME', ''),
+                 code=request.params.get('code', ''),
+                 message=request.params.get('message', ''))
+        return page
 
     def img(self, id):
+        """Serve Pylons' stock images"""
         return self._serve_file(os.path.join(media_path, 'img', id))
-        
+
     def style(self, id):
+        """Serve Pylons' stock stylesheets"""
         return self._serve_file(os.path.join(media_path, 'style', id))
 
     def _serve_file(self, path):
-        fapp = fileapp.FileApp(path)
+        """Call Paste's FileApp (a WSGI application) to serve the file at the
+        specified path
+        """
+        fapp = paste.fileapp.FileApp(path)
         return fapp(request.environ, self.start_response)

quickwiki/controllers/page.py

+import logging
+
 from quickwiki.lib.base import *
+from quickwiki.model import Session, Page
+
+log = logging.getLogger(__name__)
+
+class PageController(BaseController):
     
-class PageController(BaseController):
-
-    def __before__(self):
-        model.session_context.current.clear()
-
     def index(self, title):
-        page = model.Page.get_by(title=title)
-        if page: 
+        page_q = Session.query(Page)
+        page = page_q.filter_by(title=title).first()
+        if page:
             c.content = page.get_wiki_content()
-            return render_response('/page.myt')
+            return render('/page.mako')
         elif model.wikiwords.match(title):
-            return render_response('/new_page.myt')
+            return render('/new_page.mako')
         abort(404)
 
     def edit(self, title):
-        page = model.Page.get_by(title=title)
+        page_q = Session.query(Page)
+        page = page_q.filter_by(title=title).first()
         if page:
             c.content = page.content
-        return render_response('/edit.myt')
-    
+        return render('/edit.mako')
+        
     def save(self, title):
-        page = model.Page.get_by(title=title)
+        page_q = Session.query(Page)
+        page = page_q.filter_by(title=title).first()
         if not page:
-            page = model.Page()
+            page = Page()
             page.title = title
-        page.content = request.params['content']
+        page.content = request.params.get('content','')
         c.title = page.title
         c.content = page.get_wiki_content()
         c.message = 'Successfully saved'
-        page.flush()
-        return render_response('/page.myt')
+        Session.save(page)
+        Session.commit()
+        return render('/page.mako')
 
     def list(self):
-        c.titles = [page.title for page in model.Page.select()]
-        return render_response('/titles.myt')
+        c.titles = [page.title for page in Session.query(Page).all()]
+        return render('/list.mako')
 
     def delete(self):
+        page_q = Session.query(Page)
         title = request.params['id'][5:]
-        page = model.Page.get_by(title=title)
-        page.delete()
-        page.flush()
-        c.titles = model.Page.select()
-        return render_response('/list.myt', fragment=True)
+        page = page_q.filter_by(title=title).one()
+        Session.delete(page)
+        Session.commit()
+        c.titles = page_q.all()
+        return render('/list-titles.mako')

quickwiki/controllers/template.py

 from quickwiki.lib.base import *
 
 class TemplateController(BaseController):
+
     def view(self, url):
-        """
-        This is the last place which is tried during a request to try to find a 
-        file to serve. It could be used for example to display a template::
-        
+        """By default, the final controller tried to fulfill the request when
+        no other routes match. It may be used to display a template when all
+        else fails, e.g.::
+
             def view(self, url):
-                return render_response(url)
-        
-        Or, if you're using Myghty and would like to catch the component not
-        found error which will occur when the template doesn't exist; you
-        can use the following version which will provide a 404 if the template
-        doesn't exist::
-        
-            import myghty.exception
-            
+                return render('/%s' % url)
+
+        Or if you're using Mako and want to explicitly send a 404 (Not Found)
+        response code when the requested template doesn't exist::
+
+            import mako.exceptions
+
             def view(self, url):
                 try:
-                    return render_response('/'+url)
-                except myghty.exception.ComponentNotFound:
-                    return Response(code=404)
-        
-        The default is just to abort the request with a 404 File not found
-        status message.
+                    return render('/%s' % url)
+                except mako.exceptions.TopLevelLookupException:
+                    abort(404)
+
+        By default this controller aborts the request with a 404 (Not Found)
         """
         abort(404)

quickwiki/lib/app_globals.py

+"""The application's Globals object"""
+from pylons import config
+
 class Globals(object):
+    """Globals acts as a container for objects available throughout the life of
+    the application.
+    """
 
-    def __init__(self, global_conf, app_conf, **extra):
-        """
-        Globals acts as a container for objects available throughout
-        the life of the application.
-
-        One instance of Globals is created by Pylons during
-        application initialization and is available during requests
-        via the 'g' variable.
-        
-        ``global_conf``
-            The same variable used throughout ``config/middleware.py``
-            namely, the variables from the ``[DEFAULT]`` section of the
-            configuration file.
-            
-        ``app_conf``
-            The same ``kw`` dictionary used throughout
-            ``config/middleware.py`` namely, the variables from the
-            section in the config file for your application.
-            
-        ``extra``
-            The configuration returned from ``load_config`` in 
-            ``config/middleware.py`` which may be of use in the setup of
-            your global variables.
-            
+    def __init__(self):
+        """One instance of Globals is created during application initialization
+        and is available during requests via the 'g' variable.
         """
         pass
-        
-    def __del__(self):
-        """
-        Put any cleanup code to be run when the application finally exits 
-        here.
-        """
-        pass

quickwiki/lib/base.py

-from pylons import Response, c, g, cache, request, session
+"""The base Controller API
+
+Provides the BaseController class for subclassing, as well as functions and
+objects for use by Controllers.
+"""
+from pylons import c, cache, config, g, request, response, session
 from pylons.controllers import WSGIController
+from pylons.controllers.util import abort, etag_cache, redirect_to
 from pylons.decorators import jsonify, validate
-from pylons.templating import render, render_response
-from pylons.helpers import abort, redirect_to, etag_cache
-from pylons.i18n import N_, _, ungettext
-import quickwiki.models as model
+from pylons.i18n import _, ungettext, N_
+from pylons.templating import render
+
 import quickwiki.lib.helpers as h
+import quickwiki.model as model
 
 class BaseController(WSGIController):
+
     def __call__(self, environ, start_response):
-        # Insert any code to be run per request here. The Routes match
-        # is under environ['pylons.routes_dict'] should you want to check
-        # the action or route vars here
-        return WSGIController.__call__(self, environ, start_response)
+        """Invoke the Controller"""
+        # WSGIController.__call__ dispatches to the Controller method the
+        # request is routed to. This routing information is available in
+        # environ['pylons.routes_dict']
+        try:
+            return WSGIController.__call__(self, environ, start_response)
+        finally:
+            model.Session.remove()
 
 # Include the '_' function in the public names
 __all__ = [__name for __name in locals().keys() if not __name.startswith('_') \

quickwiki/lib/helpers.py

-"""
-Helper functions
+"""Helper functions
 
-All names available in this module will be available under the Pylons h object.
+Consists of functions to typically be used within templates, but also available
+to Controllers. This module is available to both as 'h'.
 """
 from webhelpers import *
-from pylons.helpers import log
-from pylons.i18n import get_lang, set_lang

quickwiki/model/__init__.py

+from pylons import config
+from sqlalchemy import Column, MetaData, Table, types
+from sqlalchemy.orm import mapper, relation
+from sqlalchemy.orm import scoped_session, sessionmaker
+
+import re
+import sets
+import quickwiki.lib.helpers as h
+from docutils.core import publish_parts
+
+# Global session manager for SQLAlchemy. Session() returns the session
+# object appropriate for the current web request.
+Session = scoped_session(sessionmaker(autoflush=True,
+                         transactional=True, bind=config['pylons.g'].sa_engine))
+
+# Global metadata. If you have multiple databases with overlapping 
+# table names, you'll need a metadata for each database.
+metadata = MetaData()
+
+wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
+
+pages_table = Table('pages', metadata,
+    Column('title', types.String(40), primary_key=True),
+    Column('content', types.String(), default='')
+)
+
+class Page(object):
+    content = None
+
+    def __str__(self):
+        return self.title
+
+    def get_wiki_content(self):
+        content = publish_parts(self.content, writer_name="html")["html_body"]
+        titles = sets.Set(wikiwords.findall(content))
+        for title in titles:
+            title_url = h.url_for(controller='page', action='index', 
+                                  title=title)
+            content = content.replace(title, h.link_to(title, title_url))
+        return content
+                    
+mapper(Page, pages_table)

quickwiki/models/__init__.py

-import re
-import sets
-from docutils.core import publish_parts
-from sqlalchemy import *
-from sqlalchemy.ext.assignmapper import assign_mapper
-from pylons.database import session_context
-import quickwiki.lib.helpers as h
-
-wikiwords = re.compile(r"\b([A-Z]\w+[A-Z]+\w+)")
-
-meta = DynamicMetaData()
-
-pages_table = Table('pages', meta,
-    Column('title', String(40), primary_key=True),
-    Column('content', String(), default='')
-)
-
-class Page(object):
-    content = None
-    
-    def __str__(self):
-        return self.title
-        
-    def get_wiki_content(self):
-        content = publish_parts(self.content, writer_name="html")["html_body"]
-        titles = sets.Set(wikiwords.findall(content))
-        for title in titles:
-            title_url = h.url_for(controller='page', action='index', 
-                                  title=title)
-            content = content.replace(title, h.link_to(title, title_url))
-        return content
-        
-page_mapper = assign_mapper(session_context, Page, pages_table)

quickwiki/public/quick.css

 body {
-	background-color: #888;
-	margin: 25px;
+  background-color: #888;
+  margin: 25px;
 }
 div.content{
-	margin: 0;
-	margin-bottom: 10px;
-	background-color: #d3e0ea;
-	border: 5px solid #333;
-	padding: 5px 25px 25px 25px;
+  margin: 0;
+  margin-bottom: 10px;
+  background-color: #d3e0ea;
+  border: 5px solid #333;
+  padding: 5px 25px 25px 25px;
 }
 h1.main{
-	width: 100%;
-	border-bottom: 1px solid #000;
+  width: 100%;
+  border-bottom: 1px solid #000;
 }
 p.footer{
-	width: 100%;
-	padding-top: 3px;
-	border-top: 1px solid #000;
+  width: 100%;
+  padding-top: 3px;
+  border-top: 1px solid #000;
 }
 div#message{
-	color: orangered;
+  color: orangered;
 }
 div#trash{
-	float: right;
-	margin: 0px 20px 20px 20px;
-	background: #eee;
-	border: 1px solid #000;
-	padding: 15px;
+  float: right;
+  margin: 0px 20px 20px 20px;
+  background: #eee;
+  border: 2px solid #000;
+  padding: 15px;
+  font-family: sans-serif;
 }

quickwiki/templates/autohandler

-<html>
-<head>
-<title>QuickWiki</title>
-<% h.stylesheet_link_tag('/quick.css') %>
-<% h.javascript_include_tag('/javascripts/effects.js', builtins=True)  %>
-</head>
-<body>
-<div class="content">
-% m.call_next()
-<p class="footer">
-    Return to the <% h.link_to('FrontPage', h.url_for(action="index", title="FrontPage")) %>
-% if h.url_for() != '/page/list':
-    | <% h.link_to('Edit '+c.title, h.url_for(title=c.title, action='edit')) %>
-    | <% h.link_to('Title List', h.url_for(action='list', title=None)) %>
-% # end if
-</p>
-</div>
-</body>
-</html>

quickwiki/templates/base.mako

+# -*- coding: utf-8 -*-
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
+  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
+<html>
+<head>
+  <title>QuickWiki</title>
+  ${h.stylesheet_link_tag('/quick.css')}
+  ${h.javascript_include_tag('/javascripts/effects.js', builtins=True)}
+</head>
+<body>
+  <div class="content">
+    ${next.body()}\
+    <p class="footer">
+    ${footer(request.environ['pylons.routes_dict']['action'])}\
+    </p>
+  </div>
+</body>
+</html>
+
+## Don't show links that are redundant for particular pages
+<%def name="footer(action)">\
+  Return to the ${h.link_to('FrontPage', h.url_for(action="index", title="FrontPage"))}
+  % if action == "list":
+    <% return '' %>
+  % endif
+  % if action != "edit":
+    | ${h.link_to('Edit '+c.title, h.url_for(title=c.title, action='edit'))}
+  % endif
+  | ${h.link_to('Title List', h.url_for(action='list', title=None))}
+</%def>

quickwiki/templates/edit.mako

+<%inherit file="base.mako"/>
+
+<h1 class="main">Editing ${c.title}</h1>
+
+${h.start_form(h.url_for(action='save', title=c.title), method="get")}
+  ${h.text_area(name='content', rows=7, cols=40, content=c.content)} <br />
+  ${h.submit(value="Save changes", name='commit')}
+${h.end_form()}

quickwiki/templates/edit.myt

-<h1 class="main">Editing <% c.title %></h1>
-
-<% h.start_form(h.url_for(action='save', title=c.title),method="post") %>
-    <% h.text_area(name='content', rows=7, cols=40, content=c.content)%> <br /> 
-    <% h.submit(value="Save changes", name='commit') %>
-<% h.end_form() %>

quickwiki/templates/list-titles.mako

+% for title in c.titles:
+<li>
+  <span id="page-${title}">${title}</span>
+  &nbsp;[${h.link_to('visit', h.url_for(title=title, action="index"))}]
+  ${h.draggable_element("page-"+ str(title), revert=True)}
+</li>
+% endfor

quickwiki/templates/list.mako

+<%inherit file="base.mako"/>
+
+<h1 class="main">Title List</h1>
+<div id="trash">
+  Delete a page by dragging its title here
+</div>
+${h.drop_receiving_element("trash", update="titles", url=h.url_for(action="delete"))}
+
+<ul id="titles">
+  <%include file="list-titles.mako"/>
+</ul>

quickwiki/templates/list.myt

-% for title in c.titles:
-<li>
-    <span id="page-<% title %>"><% title %></span>&nbsp;[<% h.link_to('visit', h.url_for(title=title, action="index")) %>]
-    <% h.draggable_element("page-"+ str(title), revert=True) %>
-</li>
-% #end for

quickwiki/templates/new_page.mako

+<%inherit file="base.mako"/>  
+
+<h1 class="main">${c.title}</h1>
+<p>This page doesn't exist yet.
+  <a href="${h.url_for(action='edit', title=c.title)}">Create the page</a>.</p>

quickwiki/templates/new_page.myt

-<h1 class="main"><% c.title %></h1>
-<p>This page doesn't exist yet. 
-   <a href="<% h.url_for(action='edit', title=c.title) %>">Create the page</a>.</p>

quickwiki/templates/page.mako

+<%inherit file="base.mako"/>\
+
+<h1 class="main">${c.title}</h1>
+% if c.message:
+<p><div id="message">${c.message}</div></p>
+% endif
+${c.content}

quickwiki/templates/page.myt

-<h1 class="main"><% c.title %></h1>
-% if c.message:
-<p><div id="message"><% c.message %></div></p>
-% #end if
-<% c.content %>

quickwiki/templates/titles.myt

-<h1 class="main">Title List</h1>
-<div id="trash">
-    Delete a page by dragging its title here
-</div>
-<% h.drop_receiving_element("trash", update="titles", url=h.url_for(action="delete")) %>
-<ul id="titles">
-<% render('/list.myt', fragment=True) %>
-</ul>

quickwiki/tests/__init__.py

+"""Pylons application test package
+
+When the test runner finds and executes tests within this directory, this file
+will be loaded to setup the test environment.
+
+It registers the root directory of the project in sys.path and pkg_resources,
+in case the project hasn't been installed with setuptools. It also initializes
+the application via websetup (paster setup-app) with the project's test.ini
+configuration file.
+"""
 import os
 import sys
 from unittest import TestCase
 
+import pkg_resources
+import paste.fixture
+import paste.script.appinstall
+from paste.deploy import loadapp
+from routes import url_for
+
+__all__ = ['url_for', 'TestController']
+
 here_dir = os.path.dirname(os.path.abspath(__file__))
 conf_dir = os.path.dirname(os.path.dirname(here_dir))
 
 sys.path.insert(0, conf_dir)
-
-import pkg_resources
-
 pkg_resources.working_set.add_entry(conf_dir)
-
 pkg_resources.require('Paste')
 pkg_resources.require('PasteScript')
 
-from paste.deploy import loadapp, CONFIG
-import paste.deploy
-import paste.fixture
-import paste.script.appinstall
-
-from quickwiki.config.routing import *
-from routes import request_config, url_for
-
 test_file = os.path.join(conf_dir, 'test.ini')
-conf = paste.deploy.appconfig('config:' + test_file)
-CONFIG.push_process_config({'app_conf': conf.local_conf,
-                            'global_conf': conf.global_conf}) 
-
 cmd = paste.script.appinstall.SetupCommand('setup-app')
 cmd.run([test_file])
 
 class TestController(TestCase):
-    def __init__(self, *args):
+
+    def __init__(self, *args, **kwargs):
         wsgiapp = loadapp('config:test.ini', relative_to=conf_dir)
         self.app = paste.fixture.TestApp(wsgiapp)
-        TestCase.__init__(self, *args)
-
-__all__ = ['url_for', 'TestController']
+        TestCase.__init__(self, *args, **kwargs)

quickwiki/websetup.py

-import paste.deploy
-from pylons.database import create_engine
-import quickwiki.models as model
+"""Setup the QuickWiki application"""
+import logging
+
+from paste.deploy import appconfig
+from pylons import config
+
+from quickwiki.config.environment import load_environment
+
+log = logging.getLogger(__name__)
 
 def setup_config(command, filename, section, vars):
-    """
-    Place any commands to setup quickwiki here.
-    """
-    conf = paste.deploy.appconfig('config:' + filename)
-    paste.deploy.CONFIG.push_process_config({'app_conf':conf.local_conf,
-                                             'global_conf':conf.global_conf})
+    """Place any commands to setup quickwiki here"""
+    conf = appconfig('config:' + filename)
+    load_environment(conf.global_conf, conf.local_conf)
+    
+    # Populate the DB on 'paster setup-app'
+    import quickwiki.model as model
 
-    uri = conf['sqlalchemy.dburi']
-    engine = create_engine(uri)
-    print "Connecting to database %s" % uri
-    model.meta.connect(engine)
-    print "Creating tables"
-    model.meta.create_all()
+    print "Setting up database connectivity..."
+    engine = config['pylons.g'].sa_engine
+    print "Creating tables..."
+    model.metadata.create_all(bind=engine)
+    print "Successfully set up."
 
-    print "Adding front page data"
+    print "Adding front page data..."
     page = model.Page()
     page.title = 'FrontPage'
     page.content = 'Welcome to the QuickWiki front page.'
-    page.flush()
-    print "Successfully setup."
+    model.Session.save(page)
+    model.Session.commit()
+    print "Successfully set up."
+[egg_info]
+tag_build = dev
+tag_svn_revision = true
+
 [easy_install]
 find_links = http://www.pylonshq.com/download/
 
 theme = pythonpaste.org
 
 # Add extra doc files here with spaces between them
-docs = quickwiki/docs/index.txt 
+docs = docs/index.txt
 
 # Doc Settings
-doc_base = quickwiki/docs/
-dest = quickwiki/docs/html
+doc_base = docs/
+dest = docs/html
 
 # Add extra modules here separated with commas
 modules = quickwiki
 title = Quickwiki
 organization = Pylons
 
+# Highlight code-block sections with Pygments
+highlighter = pygments
+
 # Optionally add extra links
-#organization_url = http://pylons.groovie.org/
-#trac_url=http://pylons.groovie.org/
+#organization_url = http://pylonshq.com/
+#trac_url = http://pylonshq.com/project
 settings = no_about=true
 
-# Optionally add extra settings 
+# Optionally add extra settings
 #           link1=/community/ Community
 #           link2=/download/ Download
- 
+
 [publish]
-doc-dir=quickwiki/docs/html
+doc-dir=docs/html
 make-dirs=1
+
+# Babel configuration
+[compile_catalog]
+domain = quickwiki
+directory = quickwiki/i18n
+statistics = true
+
+[extract_messages]
+add_comments = TRANSLATORS:
+output_file = quickwiki/i18n/quickwiki.pot
+width = 80
+
+[init_catalog]
+domain = quickwiki
+input_file = quickwiki/i18n/quickwiki.pot
+output_dir = quickwiki/i18n
+
+[update_catalog]
+domain = quickwiki
+input_file = quickwiki/i18n/quickwiki.pot
+output_dir = quickwiki/i18n
+previous = true
-from setuptools import setup, find_packages
+try:
+    from setuptools import setup, find_packages
+except ImportError:
+    from ez_setup import use_setuptools
+    use_setuptools()
+    from setuptools import setup, find_packages
 
 setup(
     name='QuickWiki',
-    version="0.1.3",
-    description="Result of following the Pylons 0.9.4.1 Tutorial",
-    url="http://www.pylonshq.com/docs/quick_wiki.html",
-    author="James Gardner",
+    version="0.1.5",
+    description="QuickWiki - Pylons 0.9.6 Tutorial application",
+    #author="",
     #author_email="",
-    install_requires=["Pylons==dev,>=0.9.4.1dev-r1772", "docutils==0.4", "SQLAlchemy>=0.2.6"],
-    packages=find_packages(),
+    url="http://wiki.pylonshq.com/display/pylonsdocs/QuickWiki+Tutorial",
+    install_requires=["Pylons>=0.9.6rc3", "docutils==0.4", "SQLAlchemy>=0.4.0beta3"],
+    packages=find_packages(exclude=['ez_setup']),
     include_package_data=True,
-    test_suite = 'nose.collector',
+    test_suite='nose.collector',
     package_data={'quickwiki': ['i18n/*/LC_MESSAGES/*.mo']},
+    message_extractors = {'quickwiki': [
+            ('**.py', 'python', None),
+            ('templates/**.mako', 'mako', None),
+            ('public/**', 'ignore', None)]},
     entry_points="""
     [paste.app_factory]
-    main=quickwiki:make_app
+    main = quickwiki.config.middleware:make_app
+
     [paste.app_install]
-    main=pylons.util:PylonsInstaller
+    main = pylons.util:PylonsInstaller
     """,
 )
 #
 [DEFAULT]
 debug = true
-email_to = you@yourdomain.com
+# Uncomment and replace with the address which should receive any error reports
+#email_to = you@yourdomain.com
 smtp_server = localhost
 error_email_from = paste@localhost