--- a/pvl/verkko/hosts.py Wed Oct 10 22:10:16 2012 +0300
+++ b/pvl/verkko/hosts.py Wed Oct 10 22:45:50 2012 +0300
@@ -64,14 +64,14 @@
#_name = db.dhcp_hosts.c.name,
))
-HOST_SORT = {
+HOST_ATTRS = {
'id': Host.id,
'ip': Host.ip,
'mac': Host.mac,
'name': Host.name,
'seen': Host.last_seen,
- None: Host.last_seen.desc(),
}
+HOST_SORT = Host.last_seen.desc()
def render_hosts (hosts, title=None) :
COLS = (
@@ -135,62 +135,86 @@
html.a(href='/hosts')(html('«'), 'Back'),
)
-def respond (request, db, path) :
- """
- Handle request
- """
-
- hosts = db.query(Host)
-
- # sort ?
- sort = request.args.get('sort')
- sort = HOST_SORT[sort]
- log.debug("sort: %s", sort)
-
- hosts = hosts.order_by(sort)
+class Handler (web.Handler) :
+ TITLE = "DHCP Hosts"
- # index
- if not path :
- title = "DHCP Hosts"
- html = render_hosts(hosts)
-
- # id
- elif len(path) == 1 :
- id, = path
- id = int(id)
+ def index (self) :
+ return render_hosts(self.hosts)
- host = hosts.get(id)
- hosts = hosts.filter((Host.ip == host.ip) | (Host.mac == host.mac))
+ def host (self, id) :
+ host = self.hosts.get(id)
- # render
- title = "DHCP Host: {host}".format(host=unicode(host))
- html = render_host(host, hosts)
+ if not host :
+ raise web.NotFound("No such host: {id}".format(id=id))
+
+ hosts = self.hosts.filter((Host.ip == host.ip) | (Host.mac == host.mac))
+
+ # XXX
+ #self.title = "DHCP Host: {host}".format(host=unicode(host))
+
+ return render_host(host, hosts)
- # query
- elif len(path) == 2 :
- attr, value = path
-
+ def list (self, attr, value) :
# fake host
host = { 'ip': None, 'mac': None, 'name': None }
+
+ if attr not in HOST_ATTRS :
+ raise web.BadRequest("Invalid attribute: {attr}".format(attr=attr))
+
host[attr] = value
host = Host(**host)
# query
- attr = HOST_SORT[attr]
+ attr = HOST_ATTRS[attr]
log.debug("%s == %s", attr, value)
- hosts = hosts.filter(attr == value)
+ hosts = self.hosts.filter(attr == value)
- # render
- title = "DHCP Hosts: {value}".format(value=value)
- html = render_host(host, hosts)
+ # XXX
+ #self.title = "DHCP Hosts: {value}".format(value=value)
- else :
- return Response("Not Found", status=404)
+ return render_host(host, hosts)
+
+ def process (self) :
+ hosts = self.db.query(Host)
- # render
- html = web.render_layout(title, html)
+ # sort ?
+ sort = self.request.args.get('sort')
- return web.Response(html, content_type='text/html; charset=UTF-8')
+ if sort :
+ sort = HOST_ATTRS[sort]
+ else :
+ sort = HOST_SORT
+ log.debug("sort: %s", sort)
+
+ hosts = hosts.order_by(sort)
+
+ # store
+ self.hosts = hosts
+
+ def render (self) :
+ # index
+ if not self.path :
+ return self.index()
+
+ # id
+ elif len(self.path) == 1 :
+ try :
+ id, = self.path
+ id = int(id)
+ except ValueError as ex :
+ raise web.BadRequest("Invalid host ID: {id}: {ex}".format(id=id, ex=ex))
+
+ return self.host(id)
+
+ # query
+ elif len(self.path) == 2 :
+ attr, value = self.path
+
+ return self.list(attr, value)
+
+ else :
+ raise web.NotFound
+
--- a/pvl/verkko/web.py Wed Oct 10 22:10:16 2012 +0300
+++ b/pvl/verkko/web.py Wed Oct 10 22:45:50 2012 +0300
@@ -1,31 +1,105 @@
+# encoding: utf-8
+
from werkzeug.wrappers import Response
# view
from pvl.html import tags as html
-def render_layout (title, content) :
- css = [
- "/static/layout.css",
+# errors
+from werkzeug.exceptions import (
+ HTTPException,
+ BadRequest, # 400
+ NotFound, # 404
+)
+
+class Handler (object) :
+ """
+ Per-Request controller/view, containing the request context and generating the response.
+ """
+
+ TITLE = None
+ CSS = (
+ #"/static/layout.css",
"/static/style.css",
- ]
+ )
- return unicode(html.document(html.html(
- html.head(
- html.title(title),
- (
- html.link(rel='Stylesheet', type="text/css", href=src) for src in css
+ def __init__ (self, app, request, path) :
+ """
+ app - wsgi.Application
+ request - werkzeug.Request
+ """
+
+ self.app = app
+ self.db = app.db
+ self.request = request
+
+ # TODO
+ self.path = path
+
+ @property
+ def title (self) :
+ """
+ Render site/page title as text.
+ """
+
+ if self.TITLE :
+ return u"Päivölä Verkko :: {title}".format(title=self.TITLE)
+ else :
+ return u"Päivölä Verkko"
+
+ def render (self) :
+ """
+ Render page content (as <body>...</body>).
+ """
+
+ raise NotImplementedError()
+
+ def render_html (self) :
+ """
+ Render page layout (as <html>).
+ """
+
+ return html.html(
+ html.head(
+ html.title(self.title),
+ (
+ html.link(rel='Stylesheet', type="text/css", href=src) for src in self.CSS
+ ),
),
- ),
- html.body(
- html.h1(title),
- content
+ html.body(
+ html.h1(self.title),
+ self.render()
+ )
)
- )))
-def render_index () :
- return Response(render_layout("Verkko", (
- html.ul(
- html.a(href='/hosts')("DHCP Hosts"),
+ def process (self) :
+ """
+ TODO: process request args to build internal state
+ """
+
+ pass
+
+ def respond (self) :
+ """
+ Generate a response.
+
+ Does an HTML layout'd response per default.
+ """
+
+ try :
+ # XXX: returning e.g. redirect? args?
+ self.process()
+
+ return Response(unicode(html.document(self.render_html())), mimetype='text/html')
+
+ except HTTPException as ex :
+ return ex
+
+class Index (Handler) :
+ def render (self) :
+ return (
+ html.ul(
+ html.a(href='/hosts')("DHCP Hosts"),
+ )
)
- )), content_type='text/html')
--- a/pvl/verkko/wsgi.py Wed Oct 10 22:10:16 2012 +0300
+++ b/pvl/verkko/wsgi.py Wed Oct 10 22:45:50 2012 +0300
@@ -30,13 +30,15 @@
log.debug("path: %s", path)
- # respond
+ # lookup handler/respond
if not path :
- return web.render_index()
+ handler = web.Index
elif path[0] == 'hosts' :
- return hosts.respond(request, self.db, path[1:])
+ handler = hosts.Handler
+ path.pop(0)
else :
return Response("Not Found", status=404)
+ return handler(self, request, path).respond()