--- a/candolint/handlers.py Wed Oct 26 06:52:26 2016 +0800
+++ b/candolint/handlers.py Wed Oct 26 07:33:36 2016 +0800
self.render('project.html', project=project, checks=checks)
+class AtomHandler(BaseHandler):
+ def get(self, domain, user, name):
+ project = get_project_or_404(domain, user, name)
+ .select(Change, *Check.get_light_fields())
+ .where(Check.project == project))
+ elif check.errors or check.warnings:
+ msg = self.locale.translate(
+ '{} error', '{} errors', check.errors)
+ status.append(msg.format(check.errors))
+ msg = self.locale.translate(
+ '{} warning', '{} warnings', check.warnings)
+ status.append(msg.format(check.warnings))
+ return ', '.join(status)
+ self.set_header('Content-Type', 'application/atom+xml; charset=utf-8')
+ self.render('atom.xml', project=project, checks=checks, status=status)
class CheckHandler(BaseHandler):
def get(self, domain, user, name, check_num, format_='html'):
project = get_project_or_404(domain, user, name)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/templates/atom.xml Wed Oct 26 07:33:36 2016 +0800
+<?xml version="1.0" encoding="UTF-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom">
+ <icon>{{ request.protocol }}://{{ request.host }}/static/favicon-cat.png</icon>
+ <title>{{ project.name }} feed</title>
+ <id>{{ project.get_url(request) }}/atom</id>
+ <link href="{{ project.get_url(request) }}/atom" rel="self"/>
+ <link href="{{ project.get_url(request) }}"/>
+ {% set last = checks.first() %}
+ <updated>{{ last.finished.isoformat() }}Z</updated>
+ <updated>1970-01-01T08:00:00</updated>
+ {% for check in checks.limit(20) %}
+ <title>Check #{{ check.ordinal }}: {{ status(check) }}</title>
+ <id>{{ project.get_url(request) }}/{{ check.ordinal }}</id>
+ <link href="{{ project.get_url(request) }}/{{ check.ordinal }}"/>
+ <updated>{{ check.finished.isoformat() }}Z</updated>
--- a/tests/test_viewer.py Wed Oct 26 06:52:26 2016 +0800
+++ b/tests/test_viewer.py Wed Oct 26 07:33:36 2016 +0800
assert '1 warning' in response.body
assert '<a href="#">default</a>' in response.body
+ response = self.fetch('/example.com/alice/test-viewer/atom')
+ assert response.code == 200
+ assert 'atom+xml' in response.headers['Content-Type']
+ root = ElementTree.fromstring(response.body)
+ ns = {'atom': 'http://www.w3.org/2005/Atom'}
+ title = root.find('./atom:entry/atom:title', ns)
+ assert title is not None
+ assert title.text == 'Check #1: 1 error, 1 warning'
+ updates = [el.text for el in root.findall('.//atom:updated', ns)]
+ assert len(updates) == 2
+ assert updates[0] == updates[1] == '2016-08-20T02:38:53Z'
response = self.fetch('/butt.cloud/cyber/wizard-attack/latest')
assert response.code == 404
--- a/viewer.py Wed Oct 26 06:52:26 2016 +0800
+++ b/viewer.py Wed Oct 26 07:33:36 2016 +0800
from tornado.web import Application
from candolint import uimodules
-from candolint.handlers import IndexHandler, ProjectHandler, CheckHandler, StatusHandler, ErrorHandler
+from candolint.handlers import IndexHandler, ProjectHandler, AtomHandler, CheckHandler, StatusHandler, ErrorHandler
from candolint.models import database
from candolint.utils import rel
(project_re, ProjectHandler),
+ (project_re + r'/atom', AtomHandler),
(project_re + r'/(\d+|latest)(?:/(raw))?', CheckHandler),
(project_re + r'/status\.svg', StatusHandler),
(r'.*', ErrorHandler, {'status_code': 404})