cmlenz@611: #!/usr/bin/env python cmlenz@611: cmlenz@628: import operator, os, pickle, sys cmlenz@611: cmlenz@611: import cherrypy cmlenz@611: from formencode import Invalid cmlenz@631: from genshi.input import HTML cmlenz@631: from genshi.filters import HTMLFormFiller, HTMLSanitizer cmlenz@611: cmlenz@619: from geddit.form import LinkForm, CommentForm cmlenz@625: from geddit.lib import ajax, template cmlenz@619: from geddit.model import Link, Comment cmlenz@611: cmlenz@611: cmlenz@611: class Root(object): cmlenz@611: cmlenz@611: def __init__(self, data): cmlenz@611: self.data = data cmlenz@611: cmlenz@611: @cherrypy.expose cmlenz@615: @template.output('index.html') cmlenz@611: def index(self): cmlenz@619: links = sorted(self.data.values(), key=operator.attrgetter('time')) cmlenz@619: return template.render(links=links) cmlenz@611: cmlenz@611: @cherrypy.expose cmlenz@615: @template.output('submit.html') cmlenz@611: def submit(self, cancel=False, **data): cmlenz@611: if cherrypy.request.method == 'POST': cmlenz@611: if cancel: cmlenz@611: raise cherrypy.HTTPRedirect('/') cmlenz@619: form = LinkForm() cmlenz@611: try: cmlenz@611: data = form.to_python(data) cmlenz@619: link = Link(**data) cmlenz@619: self.data[link.id] = link cmlenz@611: raise cherrypy.HTTPRedirect('/') cmlenz@611: except Invalid, e: cmlenz@611: errors = e.unpack_errors() cmlenz@611: else: cmlenz@611: errors = {} cmlenz@611: cmlenz@611: return template.render(errors=errors) | HTMLFormFiller(data=data) cmlenz@611: cmlenz@611: @cherrypy.expose cmlenz@627: @template.output('info.html') cmlenz@627: def info(self, id): cmlenz@627: link = self.data.get(id) cmlenz@627: if not link: cmlenz@627: raise cherrypy.NotFound() cmlenz@627: return template.render(link=link) cmlenz@627: cmlenz@627: @cherrypy.expose cmlenz@615: @template.output('comment.html') cmlenz@622: def comment(self, id, cancel=False, **data): cmlenz@622: link = self.data.get(id) cmlenz@619: if not link: cmlenz@611: raise cherrypy.NotFound() cmlenz@611: if cherrypy.request.method == 'POST': cmlenz@611: if cancel: cmlenz@619: raise cherrypy.HTTPRedirect('/info/%s' % link.id) cmlenz@611: form = CommentForm() cmlenz@611: try: cmlenz@611: data = form.to_python(data) cmlenz@631: markup = HTML(data['content']) | HTMLSanitizer() cmlenz@631: data['content'] = markup.render('xhtml') cmlenz@619: comment = link.add_comment(**data) cmlenz@625: if not ajax.is_xhr(): cmlenz@625: raise cherrypy.HTTPRedirect('/info/%s' % link.id) cmlenz@625: return template.render('_comment.html', comment=comment, cmlenz@625: num=len(link.comments)) cmlenz@611: except Invalid, e: cmlenz@611: errors = e.unpack_errors() cmlenz@611: else: cmlenz@611: errors = {} cmlenz@611: cmlenz@625: if ajax.is_xhr(): cmlenz@625: stream = template.render('_form.html', link=link, errors=errors) cmlenz@625: else: cmlenz@625: stream = template.render(link=link, comment=None, errors=errors) cmlenz@625: return stream | HTMLFormFiller(data=data) cmlenz@611: cmlenz@628: @cherrypy.expose cmlenz@628: @template.output('index.xml', method='xml') cmlenz@628: def feed(self, id=None): cmlenz@628: if id: cmlenz@628: link = self.data.get(id) cmlenz@628: if not link: cmlenz@628: raise cherrypy.NotFound() cmlenz@628: return template.render('info.xml', link=link) cmlenz@628: else: cmlenz@628: links = sorted(self.data.values(), key=operator.attrgetter('time')) cmlenz@628: return template.render(links=links) cmlenz@628: cmlenz@611: cmlenz@611: def main(filename): cmlenz@611: # load data from the pickle file, or initialize it to an empty list cmlenz@611: if os.path.exists(filename): cmlenz@611: fileobj = open(filename, 'rb') cmlenz@611: try: cmlenz@611: data = pickle.load(fileobj) cmlenz@611: finally: cmlenz@611: fileobj.close() cmlenz@611: else: cmlenz@618: data = {} cmlenz@611: cmlenz@611: def _save_data(): cmlenz@611: # save data back to the pickle file cmlenz@611: fileobj = open(filename, 'wb') cmlenz@611: try: cmlenz@611: pickle.dump(data, fileobj) cmlenz@611: finally: cmlenz@611: fileobj.close() cmlenz@611: cherrypy.engine.on_stop_engine_list.append(_save_data) cmlenz@611: cmlenz@628: # Some global configuration; note that this could be moved into a cmlenz@619: # configuration file cmlenz@611: cherrypy.config.update({ cmlenz@611: 'tools.encode.on': True, 'tools.encode.encoding': 'utf-8', cmlenz@611: 'tools.decode.on': True, cmlenz@611: 'tools.trailing_slash.on': True, cmlenz@611: 'tools.staticdir.root': os.path.abspath(os.path.dirname(__file__)), cmlenz@611: }) cmlenz@611: cmlenz@619: cherrypy.quickstart(Root(data), '/', { cmlenz@611: '/media': { cmlenz@611: 'tools.staticdir.on': True, cmlenz@611: 'tools.staticdir.dir': 'static' cmlenz@611: } cmlenz@611: }) cmlenz@611: cmlenz@611: if __name__ == '__main__': cmlenz@611: import formencode cmlenz@611: formencode.api.set_stdtranslation(languages=['en']) cmlenz@611: main(sys.argv[1])