Factoids: Add the web interface.

This commit is contained in:
Valentin Lorentz 2013-03-11 19:54:17 +01:00
parent 24252bc69f
commit f4c643ad51
2 changed files with 137 additions and 0 deletions

View File

@ -47,6 +47,13 @@ class FactoidFormat(registry.TemplatedString):
requiredTemplates = ['value'] requiredTemplates = ['value']
Factoids = conf.registerPlugin('Factoids') Factoids = conf.registerPlugin('Factoids')
conf.registerGroup(Factoids, 'web')
conf.registerGlobalValue(Factoids.web, 'enable',
registry.Boolean(False, _("""Determines whether the Factoids plugins will
be browsable on the HTTP server.""")))
conf.registerChannelValue(Factoids.web, 'channel',
registry.Boolean(False, _("""Determines whether factoids can be displayed
via the web server.""")))
conf.registerChannelValue(Factoids, 'learnSeparator', conf.registerChannelValue(Factoids, 'learnSeparator',
registry.String('as', _("""Determines what separator must be used in the registry.String('as', _("""Determines what separator must be used in the
learn command. Defaults to 'as' -- learn <key> as <value>. Users might learn command. Defaults to 'as' -- learn <key> as <value>. Users might

View File

@ -31,6 +31,7 @@
import os import os
import time import time
import string import string
import urllib
import supybot.conf as conf import supybot.conf as conf
import supybot.ircdb as ircdb import supybot.ircdb as ircdb
@ -39,6 +40,7 @@ from supybot.commands import *
import supybot.plugins as plugins import supybot.plugins as plugins
import supybot.ircutils as ircutils import supybot.ircutils as ircutils
import supybot.callbacks as callbacks import supybot.callbacks as callbacks
import supybot.httpserver as httpserver
from supybot.i18n import PluginInternationalization, internationalizeDocstring from supybot.i18n import PluginInternationalization, internationalizeDocstring
_ = PluginInternationalization('Factoids') _ = PluginInternationalization('Factoids')
@ -79,10 +81,138 @@ def getFactoidId(irc, msg, args, state):
addConverter('factoid', getFactoid) addConverter('factoid', getFactoid)
addConverter('factoidId', getFactoidId) addConverter('factoidId', getFactoidId)
PAGE_SKELETON = """\
<html>
<head>
<title>Factoids</title>
<link rel="stylesheet" href="/default.css" />
</head>
%s
</html>"""
DEFAULT_TEMPLATES = {
'factoids/index.html': PAGE_SKELETON % """\
<body class="purelisting">
<h1>Factoids</h1>
<form action="." method="post">
<label for="chan">Channel name:</label>
<input type="text" placeholder="#channel" name="chan" id="chan" />
<input type="submit" name="submit" value="view" />
</form>
</body>""",
'factoids/channel.html': PAGE_SKELETON % """\
<body class="puretable">
<h1>Factoids of %(channel)s</h1>
<table>
<tr class="header">
<th class="key">""" + _('key') + """</th>
<th class="id">""" + _('id') + """</th>
<th class="fact">""" + _('fact') + """</th>
</tr>
%(rows)s
</table>
</body>"""
}
httpserver.set_default_templates(DEFAULT_TEMPLATES)
class FactoidsCallback(httpserver.SupyHTTPServerCallback):
name = 'Factoids web interface'
def doGet(self, handler, path):
parts = path.split('/')[1:]
if path == '/':
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(httpserver.get_template('factoids/index.html'))
elif len(parts) == 2:
channel = urllib.unquote(parts[0])
if not ircutils.isChannel(channel):
self.send_response(404)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(httpserver.get_template('generic/error.html')%
{'title': 'Factoids - not a channel',
'error': 'This is not a channel'})
return
if not self._plugin.registryValue('web.channel', channel):
self.send_response(403)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(httpserver.get_template('generic/error.html')%
{'title': 'Factoids - unavailable',
'error': 'This channel does not exist or its factoids '
'are not available here.'})
return
db = self._plugin.getDb(channel)
cursor = db.cursor()
cursor.execute("""SELECT keys.key, factoids.id, factoids.fact
FROM factoids, keys, relations
WHERE relations.key_id=keys.id AND relations.fact_id=factoids.id
""")
factoids = {}
for (key, id_, fact) in cursor.fetchall():
if key not in factoids:
factoids[key] = {}
factoids[key][id_] = fact
content = ''
keys = factoids.keys()
keys.sort()
for key in keys:
facts = factoids[key]
content += '<tr>'
content += ('<td rowspan="%i" class="key">'
'<a name="%s" href="#%s">%s</a>'
'</td>') % (len(facts), key, key, key)
for id_, fact in facts.items():
content += '<td class="id">%i</td>' % id_
content += '<td class="fact">%s</td>' % fact
content += '</tr><tr>'
content = content[:-len('<tr>')]
self.send_response(200)
self.send_header('Content-type', 'text/html')
self.end_headers()
self.wfile.write(httpserver.get_template('factoids/channel.html')%
{'channel': channel, 'rows': content})
def doPost(self, handler, path, form):
if 'chan' in form:
self.send_response(303)
self.send_header('Location',
'./%s/' % urllib.quote(form['chan'].value))
self.end_headers()
else:
self.send_response(400)
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write('Missing field \'chan\'.')
class Factoids(callbacks.Plugin, plugins.ChannelDBHandler): class Factoids(callbacks.Plugin, plugins.ChannelDBHandler):
def __init__(self, irc): def __init__(self, irc):
callbacks.Plugin.__init__(self, irc) callbacks.Plugin.__init__(self, irc)
plugins.ChannelDBHandler.__init__(self) plugins.ChannelDBHandler.__init__(self)
conf.supybot.plugins.Factoids.web.enable.addCallback(self._doHttpConf)
if self.registryValue('web.enable'):
self._startHttp()
def _doHttpConf(self, *args, **kwargs):
if self.registryValue('web.enable'):
if not self._http_running:
self._startHttp()
else:
if self._http_running:
self._stopHttp()
def _startHttp(self):
callback = FactoidsCallback()
callback._plugin = self
httpserver.hook('factoids', callback)
self._http_running = True
def _stopHttp(self):
httpserver.unhook('factoids')
self._http_running = False
def die(self):
if self.registryValue('web.enable'):
self._stopHttp()
super(self.__class__, self).die()
def makeDb(self, filename): def makeDb(self, filename):
if os.path.exists(filename): if os.path.exists(filename):