diff options
Diffstat (limited to 'python/server.py')
-rw-r--r-- | python/server.py | 166 |
1 files changed, 163 insertions, 3 deletions
diff --git a/python/server.py b/python/server.py index 3c6ddb91..13182836 100644 --- a/python/server.py +++ b/python/server.py @@ -1,13 +1,132 @@ +# -*- coding: utf-8 -*- + import ledger import cgi import sys +import types +import posixpath +import urllib +import shutil +import os +import re from BaseHTTPServer import BaseHTTPRequestHandler, HTTPServer +from os.path import exists, join, isfile + +from Cheetah.Template import Template +from Cheetah.Filters import Filter, WebSafe + +webroot = join(os.getcwd(), 'python', 'res') + +class UnicodeFilter(Filter): + def filter(self, s, **kargs): + return Filter.filter(self, s, str=unicode, **kargs) + +def strip(value): + #return re.sub('\n', '<br />', value.strip_annotations().to_string()) + return value.strip_annotations().to_string() + +templateDef = '''#encoding utf-8 + <html> + <head> + <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> + <title>$title</title> + <link rel="stylesheet" href="/style.css" type="text/css" media="print, projection, screen" /> + <script type="text/javascript" src="/jquery-latest.js"></script> + <script type="text/javascript" src="/jquery.tablesorter.min.js"></script> + <script type="text/javascript" src="/jquery.tablesorter.pager.js"></script> + <script type="text/javascript" src="/jquery.dimensions.min.js"></script> + <script type="text/javascript"> + \$(function() { + \$("table") + .tablesorter({textExtraction: 'complex', + widthFixed: true, + widgets: ['zebra']}) + .tablesorterPager({size: 100, + container: \$("\#pager")}); + }); + </script> + </head> + <body> + <div id="main"> + <h1>Register report</h1> + <table id="register" cellspacing="1" class="tablesorter"> + <thead> + <tr> + <th>Date</th> + <th>Payee</th> + <th>Account</th> + <th>Amount</th> + <th>Total</th> + </tr> + </thead> + <tfoot> + <tr> + <th>Date</th> + <th>Payee</th> + <th>Account</th> + <th>Amount</th> + <th>Total</th> + </tr> + </tfoot> + <tbody> + #for $post in $posts + #set $total = $total + $post.amount + <tr> + <!--<td>${$post.xact.date if $post.xact is not $last_xact else $empty}</td> + <td>${$post.xact.payee if $post.xact is not $last_xact else $empty}</td>--> + <td>$post.xact.date</td> + <td>$post.xact.payee</td> + <td>$post.account</td> + <td>${strip($post.amount)}</td> + <td>${strip($total)}</td> + </tr> + #set $last_xact = $post.xact + #end for + </tbody> + </table> + <div id="pager" class="pager"> + <form> + <img src="/icons/first.png" class="first"/> + <img src="/icons/prev.png" class="prev"/> + <input type="text" class="pagedisplay"/> + <img src="/icons/next.png" class="next"/> + <img src="/icons/last.png" class="last"/> + <select class="pagesize"> + <option selected="selected" value="40">40</option> + <option value="100">100</option> + <option value="200">200</option> + <option value="300">300</option> + </select> + </form> + </div> + </body> + </html> +''' class LedgerHandler(BaseHTTPRequestHandler): + def __init__(self, *args): + self.journal = ledger.Journal(sys.argv[1]) + BaseHTTPRequestHandler.__init__(self, *args) + def do_GET(self): - print "Saw a GET request!" - sys.exit(0) + path = self.translate_path(self.path) + + if path and exists(path) and isfile(path): + self.copyfile(open(path), self.wfile) + else: + tmpl = Template(templateDef, filter=UnicodeFilter) + + tmpl.title = 'Ledger Journal' + tmpl.posts = self.journal.collect(sys.argv[2]) + tmpl.total = ledger.Value(0) + tmpl.strip = strip + tmpl.last_xact = None + tmpl.empty = "" + + html = unicode(tmpl) + html = html.encode('utf-8') + self.wfile.write(html) def do_POST(self): print "Saw a POST request!" @@ -20,6 +139,45 @@ class LedgerHandler(BaseHTTPRequestHandler): except Exception: print "Saw exception in POST handler" + # This code is straight from SimpleHTTPServer.py + def copyfile(self, source, outputfile): + """Copy all data between two file objects. + + The SOURCE argument is a file object open for reading + (or anything with a read() method) and the DESTINATION + argument is a file object open for writing (or + anything with a write() method). + + The only reason for overriding this would be to change + the block size or perhaps to replace newlines by CRLF + -- note however that this the default server uses this + to copy binary data as well. + + """ + shutil.copyfileobj(source, outputfile) + + def translate_path(self, path): + """Translate a /-separated PATH to the local filename syntax. + + Components that mean special things to the local file system + (e.g. drive or directory names) are ignored. (XXX They should + probably be diagnosed.) + + """ + # abandon query parameters + path = path.split('?',1)[0] + path = path.split('#',1)[0] + path = posixpath.normpath(urllib.unquote(path)) + words = path.split('/') + words = filter(None, words) + path = webroot + for word in words: + drive, word = os.path.splitdrive(word) + head, word = os.path.split(word) + if word in (os.curdir, os.pardir): continue + path = os.path.join(path, word) + return path + def main(*args): try: port = 9000 @@ -31,6 +189,8 @@ def main(*args): print "Shutting down server" server.socket.close() -print __name__ if __name__ == '__main__': + if len(sys.argv) < 3: + print "usage: server.py <DATA-FILE> <REPORT-QUERY>" + sys.exit(1) main() |