# coding: utf-8
"""
WSGI frontend/entry point
"""
from svv import pdf
import werkzeug
from werkzeug import exceptions
from werkzeug import Request, Response
from werkzeug.routing import Map, Rule
import logging
import datetime
# logging
log = logging.getLogger('svv.wsgi')
class AppHandler (object):
"""
Per-request handler type, containing the request context and implementing the response.
Works on a generic level, i.e. WSGI/Werkzeug URL-mapped request in, response out.
"""
# default content type for response
CONTENT_TYPE = 'text/html'
def __init__ (self, request) :
"""
Initialize for processing the given Request, to prepare for action-method later on
"""
self.request = request
def respond (self, url_values) :
"""
Handle request that was mapped to ourselves via the URL routing, using given dict of values from URL.
"""
raise NotImplementedError()
import html
from html import tags
class PageHandler (AppHandler) :
"""
Specialized AppHandler for normal HTML page views.
Renders the layout template and HTML.
"""
def respond (self, url_values) :
title = "Index"
css = ["/static/layout.css", "/static/style.css", "/static/treelist.css"]
scripts = [
"/static/js/prototype.js",
"/static/js/scriptaculous/scriptaculous.js",
"/static/js/treelist.js"
]
head = (
tags.title(title),
(tags.link(rel='Stylesheet', type="text/css", href=src) for src in css),
# XXX: script can't self-close >_<
(tags.script(src=src)(" ") for src in scripts),
)
header = ("Foo List")
nav = [tags.ul(tags.li(tags.a(href='#')(name)) for name in ['Nav A', 'Nav B', 'Nav C'])]
menu = [tags.ul(tags.li(tags.a(href='#')(name)) for name in ['Menu A', 'Menu B', 'Menu C'])]
footer = ("Copyright?")
# render page HTML
content = self.render(**url_values)
layout = (
tags.div(id='header')(header),
tags.div(id='container')(
tags.div(id='menu')(menu),
tags.div(id='nav')(nav),
tags.div(id='content')(content),
),
tags.div(id='footer')(footer),
)
# perform the actual rendering (run generators etc.)
html_text = unicode(html.document(head, layout))
# response object
# XXX: unicode?
return Response(html_text, mimetype='text/html')
def render (self, **args) :
"""
Render and return HTML for page content.
XXX: must be HTML object, support just text?
"""
raise NotImplementedError()
class Document (AppHandler) :
"""
PDF generation/export
"""
def respond (self, url_values) :
title = url_values.get('name', "Hello World")
tpl = pdf.PageTemplate('id',
header_columns = (
("", ""),
("", ""),
("", ""),
("Vuokrasopimus", "%(today)s\n" + title + "\n"),
),
footer_columns = (
("Teekkarispeksi Ry", "www.teekkarispeksi.fi"),
("Tekniikkavastaava", "Juha Kallas\n045 xxx yyzz\njskallas@cc.hut.fi"),
("Varastovastaava", "Joel Pirttimaa\n045 xxx yyzz\njhpirtti@cc.hut.fi"),
("", ""),
),
)
doc = pdf.DocumentTemplate([tpl],
title = title, author = "A. N. Onous"
)
# stylesheet
styles = pdf.Styles
# tree root
list_seq = pdf.ListItem.seq
tree = pdf.ListItem("Sopimusehdot", styles.h2, None, list_seq(), [
pdf.ListItem("Osapuolet", styles.list_h2, None, list_seq(), [
pdf.ListItem(None, None, "Teekkarispeksi ry (Y-tunnus 1888541-7), jäljempänä “Vuokranantaja”."),
pdf.ListItem(None, None, title + u", jäljempänä “Vuokraaja”. 1.1 ja 1.2 jäljempänä yhdessä “osapuolet”.")
]),
pdf.ListItem("Kaluston lainaaminen", styles.list_h2, None, list_seq(), [
pdf.ListItem("Yleistä", styles.list_h3, "Tässä sopimuksessa sovitaan toiminnasta Vuokranantajan lainatessa tanssimattoja Vuokraajalle"),
pdf.ListItem("Vuokranantajan velvollisuudet", styles.list_h3, "Vuokranantaja sitoutuu toimittamaan sovittuna ajankohtana Vuokraajalle erikseen sovittava (liite) määrä tanssimattoja."),
pdf.ListItem("Blaa Blaa", styles.list_h3, "Etc."),
]),
pdf.ListItem("Tätä sopimusta ja sitä koskevia erimielisyyksiä koskevat määräykset", styles.list_h2, None, list_seq(), [
pdf.ListItem("Sopimuksen voimassaolo", styles.list_h3, "Sopimus on osapuolia sitova sen jälkeen, kun osapuolet ovat sen allekirjoittaneet."),
pdf.ListItem("Muutosten tekeminen", styles.list_h3, "Muutokset sopimukseen on tehtävä kirjallisesti molempien osapuolten kesken."),
pdf.ListItem("Blaa Blaa", styles.list_h3, "Etc."),
]),
])
from reportlab.platypus import Paragraph as p
elements = [
p("Vuokrasopimus", styles.h1),
p("Teekkarispeksi ry AV-tekniikka", styles.h3),
] + list(tree.render_pdf()) + [
p("Nouto", styles.h2),
p("\t\tAika: _______________\tPaikka: _______________", styles.text),
p("Palautus", styles.h2),
p("\t\tAika: _______________\tPaikka: _______________", styles.text),
pdf.SignatureBlock(("Vuokranantaja", "Vuokraaja"), ("%(column)s", "Nimen selvennys", "Aika ja paikka"), {
('Vuokranantaja', 'Nimen selvennys'): "Joel Pirttimaa",
('Vuokranantaja', 'Aika ja paikka'): 'Otaniemi, %(today)s',
('Vuokraaja', 'Aika ja paikka'): 'Otaniemi, %(today)s',
}),
]
# render elements to buf as PDF code
pdf_code = doc.render_string(elements)
return Response(pdf_code, mimetype='application/pdf')
class Index (PageHandler) :
DATA = (
(100, "Top A", []),
(200, "Top B", [
(210, "Mid BA", [
(211, "Sub BAA", []),
(212, "Sub BAB", []),
]),
(220, "Mid BB", []),
]),
(300, "Top C", [
(310, "Mid CA", []),
(320, "Mid CB", []),
]),
)
def render (self) :
# build data set
data = self.DATA
def render_item (id, text, children) :
return tags.li(
tags.div(class_='item')(
# item text
tags.a(tags.input(type='checkbox', name_=id, checked=(
'checked' if self.request.form.get(str(id)) else None
)), text, class_='text'),
),
# children
tags.ul(render_item(*item) for item in children if item) if children else None,
#
class_=('more open' if children else None),
)
# render it
return (
tags.h3("Item list"),
tags.form(action='.', method='post')(
tags.ul(class_='treelist')(render_item(*item) for item in data),
tags.input(type='submit'),
),
)
class WSGIApp (object) :
"""
Top-level WSGI handler impl
"""
# URL paths
# map to AppHandler-endpoint
URLS = Map((
Rule('/', endpoint=Index),
Rule('/pdf/<string:name>.pdf', endpoint=Document),
))
def __init__ (self) :
pass
# wrap to use werkzeug's Request/Response
@Request.application
def __call__ (self, req) :
"""
Main WSGI entry point, error handling
"""
try :
# wrapped handler
response = self.request(req)
except exceptions.HTTPException, e :
# format properly as response, also includes redirects
return e.get_response(req.environ)
# XXX: except Exception, e :
# XXX: we want to trap errors in prod, but not in dev?
else :
# a-ok
return response
def request (self, req) :
"""
Wrapped request handler, URL mapping
"""
# map URLs against this request
urls = self.URLS.bind_to_environ(req)
# lookup matching URL for handler type and matched values from URL
url_handler, url_values = urls.match()
# the per-request handler (from endpoint)
req_handler = url_handler(req)
# XXX: per-method thing?
response = req_handler.respond(url_values)
# ok
return response