Skip to content

Commit

Permalink
Initial import of working PylonsTemplates module
Browse files Browse the repository at this point in the history
  • Loading branch information
countergram committed Aug 30, 2009
0 parents commit dfb0aaf
Show file tree
Hide file tree
Showing 41 changed files with 1,370 additions and 0 deletions.
1 change: 1 addition & 0 deletions MANIFEST.in
@@ -0,0 +1 @@
recursive-include PylonsTemplates/pylons_repoze_what *
44 changes: 44 additions & 0 deletions PylonsTemplates/__init__.py
@@ -0,0 +1,44 @@
import pylons.configuration
from paste.deploy.converters import asbool
from paste.script.templates import Template, var
from tempita import paste_script_template_renderer

class PylonsRepozeWhat(Template):
_template_dir = ('PylonsTemplates', 'pylons_repoze_what')
template_renderer = staticmethod(paste_script_template_renderer)
summary = 'Pylons application template with SQL-based repoze.what authorization'
egg_plugins = ['PasteScript', 'Pylons']
vars = [
var('template_engine', 'mako/genshi/jinja2/etc: Template language',
default='mako'),
]
ensure_names = ['description', 'author', 'author_email', 'url']

def pre(self, command, output_dir, vars):
"""Called before template is applied."""
package_logger = vars['package']
if package_logger == 'root':
# Rename the app logger in the rare case a project is named 'root'
package_logger = 'app'
vars['package_logger'] = package_logger

template_engine = \
vars.setdefault('template_engine',
pylons.configuration.default_template_engine)

if template_engine == 'mako':
# Support a Babel extractor default for Mako
vars['babel_templates_extractor'] = \
("('templates/**.mako', 'mako', {'input_encoding': 'utf-8'})"
",\n%s#%s" % (' ' * 4, ' ' * 8))
else:
vars['babel_templates_extractor'] = ''

# Ensure these exist in the namespace
for name in self.ensure_names:
vars.setdefault(name, '')

vars['version'] = vars.get('version', '0.1')
vars['zip_safe'] = asbool(vars.get('zip_safe', 'false'))
vars['sqlalchemy'] = True

Empty file.
Empty file.
@@ -0,0 +1,67 @@
#
# {{project}} - Pylons configuration
#
# The %(here)s variable will be replaced with the parent directory of this file
#
[DEFAULT]
debug = true
email_to = you@yourdomain.com
smtp_server = localhost
error_email_from = paste@localhost

[server:main]
use = egg:Paste#http
host = 0.0.0.0
port = 5000

[app:main]
use = egg:{{project}}
full_stack = true
static_files = true

cache_dir = %(here)s/data
beaker.session.key = {{package}}
beaker.session.secret = ${app_instance_secret}
app_instance_uuid = ${app_instance_uuid}

# If you'd like to fine-tune the individual locations of the cache data dirs
# 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

{{if sqlalchemy}}

# SQLAlchemy database URL
sqlalchemy.url = sqlite:///production.db

{{endif}}

# 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
@@ -0,0 +1,72 @@
"""Pylons environment configuration"""
import os


{{if template_engine == 'mako'}}
from mako.lookup import TemplateLookup
{{elif template_engine == 'genshi'}}
from genshi.template import TemplateLoader
{{elif template_engine == 'jinja2'}}
from jinja2 import ChoiceLoader, Environment, FileSystemLoader
{{endif}}
from pylons import config
{{if template_engine == 'mako'}}
from pylons.error import handle_mako_error
{{endif}}
{{if sqlalchemy}}
from sqlalchemy import engine_from_config
{{endif}}

import {{package}}.lib.app_globals as app_globals
import {{package}}.lib.helpers
from {{package}}.config.routing import make_map
{{if sqlalchemy}}
from {{package}}.model import init_model
{{endif}}

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='{{package}}', paths=paths)

config['routes.map'] = make_map()
config['pylons.app_globals'] = app_globals.Globals()
config['pylons.h'] = {{package}}.lib.helpers
{{if template_engine == 'mako'}}

# Create the Mako TemplateLookup, with the default auto-escaping
config['pylons.app_globals'].mako_lookup = TemplateLookup(
directories=paths['templates'],
error_handler=handle_mako_error,
module_directory=os.path.join(app_conf['cache_dir'], 'templates'),
input_encoding='utf-8', default_filters=['escape'],
imports=['from webhelpers.html import escape'])
{{elif template_engine == 'genshi'}}

# Create the Genshi TemplateLoader
config['pylons.app_globals'].genshi_loader = TemplateLoader(
paths['templates'], auto_reload=True)
{{elif template_engine == 'jinja2'}}

# Create the Jinja2 Environment
config['pylons.app_globals'].jinja2_env = Environment(loader=ChoiceLoader(
[FileSystemLoader(path) for path in paths['templates']]))
# Jinja2's unable to request c's attributes without strict_c
config['pylons.strict_c'] = True
{{endif}}{{if sqlalchemy}}
# Setup the SQLAlchemy database engine
engine = engine_from_config(config, 'sqlalchemy.')
init_model(engine)
{{endif}}

# CONFIGURATION OPTIONS HERE (note: all config options will override
# any Pylons config options)
@@ -0,0 +1,80 @@
"""Pylons middleware initialization"""
from logging import INFO
from beaker.middleware import CacheMiddleware, SessionMiddleware
from paste.cascade import Cascade
from paste.registry import RegistryManager
from paste.urlparser import StaticURLParser
from paste.deploy.converters import asbool
from pylons import config
from pylons.middleware import ErrorHandler, StatusCodeRedirect
from pylons.wsgiapp import PylonsApp
from routes.middleware import RoutesMiddleware
from repoze.what.plugins.quickstart import setup_sql_auth

from {{package}}.config.environment import load_environment
from {{package}}.model import meta, Group, Permission, User

def make_app(global_conf, full_stack=True, static_files=True, **app_conf):
"""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 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.

``static_files``
Whether this application serves its own static files; disable
when another web server is responsible for serving them.

``app_conf``
The application's local configuration. Normally specified in
the [app:<name>] section of the Paste ini file (where <name>
defaults to main).

"""
# Configure the Pylons environment
load_environment(global_conf, app_conf)

# The Pylons WSGI app
app = PylonsApp()

# Routing/Session/Cache Middleware
app = RoutesMiddleware(app, config['routes.map'])
app = SessionMiddleware(app, config)
app = CacheMiddleware(app, config)

# CUSTOM MIDDLEWARE HERE (filtered by error handling middlewares)

if asbool(full_stack):
# repoze.what authentication
app = setup_sql_auth(app, User, Group, Permission, meta.Session,
logout_handler='/logout',
post_login_url='/post_login',
post_logout_url='/post_logout',
log_level=INFO,
skip_authentication=config.get('skip_authentication', False))

# Handle Python exceptions
app = ErrorHandler(app, global_conf, **config['pylons.errorware'])

# Display error documents for 401, 403, 404 status codes (and
# 500 when debug is disabled)
if asbool(config['debug']):
app = StatusCodeRedirect(app)
else:
app = StatusCodeRedirect(app, [400, 401, 403, 404, 500])

# Establish the Registry for this application
app = RegistryManager(app)

if asbool(static_files):
# Serve static files
static_app = StaticURLParser(config['pylons.paths']['static_files'])
app = Cascade([static_app, app])

return app
@@ -0,0 +1,30 @@
"""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/
"""
from pylons import config
from routes import Mapper

def make_map():
"""Create, configure and return the routes Mapper"""
map = Mapper(directory=config['pylons.paths']['controllers'],
always_scan=config['debug'])
map.minimization = False

# 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}', controller='error')
map.connect('/error/{action}/{id}', controller='error')

map.connect('/login', controller='login', action='login')
map.connect('/post_login', controller='login', action='post_login')
map.connect('/post_logout', controller='login', action='post_logout')

# CUSTOM ROUTES HERE

map.connect('/{controller}/{action}')
map.connect('/{controller}/{action}/{id}')

return map
Empty file.
@@ -0,0 +1,46 @@
import cgi

from paste.urlparser import PkgResourcesParser
from pylons import request
from pylons.controllers.util import forward
from pylons.middleware import error_document_template
from webhelpers.html.builder import literal

from {{package}}.lib.base import BaseController

class ErrorController(BaseController):

"""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):
"""Render the error document"""
resp = request.environ.get('pylons.original_response')
content = literal(resp.body) or cgi.escape(request.GET.get('message', ''))
page = error_document_template % \
dict(prefix=request.environ.get('SCRIPT_NAME', ''),
code=cgi.escape(request.GET.get('code', str(resp.status_int))),
message=content)
return page

def img(self, id):
"""Serve Pylons' stock images"""
return self._serve_file('/'.join(['media/img', id]))

def style(self, id):
"""Serve Pylons' stock stylesheets"""
return self._serve_file('/'.join(['media/style', id]))

def _serve_file(self, path):
"""Call Paste's FileApp (a WSGI application) to serve the file
at the specified path
"""
request.environ['PATH_INFO'] = '/%s' % path
return forward(PkgResourcesParser('pylons', 'pylons'))
@@ -0,0 +1,38 @@
import logging

from pylons import request, response, url, session, tmpl_context as c
from pylons.controllers.util import abort, redirect_to

from {{package}}.lib.base import BaseController, render

log = logging.getLogger(__name__)

class LoginController(BaseController):
def login(self):
"""This is where the login form should be rendered."""

# Number of times the user has tried to log in
c.login_counter = request.environ['repoze.who.logins']

# Previous URL, if we were redirected to login by an unauhorized error
c.came_from = request.params.get('came_from') or url('/')

return render('auth/login.html')

def post_login(self):
identity = request.environ.get('repoze.who.identity')
came_from = str(request.params.get('came_from', '')) or url('/')
if not identity:
# The user provided the wrong credentials
login_counter = request.environ['repoze.who.logins'] + 1
redirect_to(url('/login', came_from=came_from,
__logins=login_counter))

# Uncomment if you are going to use flash() in your application
# userid = identity['repoze.who.userid']
# flash('Welcome back, %s!' % userid)

redirect_to(url(came_from))

def post_logout(self):
return render('auth/post_logout.html')
Empty file.

0 comments on commit dfb0aaf

Please sign in to comment.