From f4c643ad51bfc20b8a2e5bae1e04a725dde4ef13 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Mon, 11 Mar 2013 19:54:17 +0100 Subject: [PATCH] Factoids: Add the web interface. --- plugins/Factoids/config.py | 7 ++ plugins/Factoids/plugin.py | 130 +++++++++++++++++++++++++++++++++++++ 2 files changed, 137 insertions(+) diff --git a/plugins/Factoids/config.py b/plugins/Factoids/config.py index 9d02a5c23..a673b2895 100644 --- a/plugins/Factoids/config.py +++ b/plugins/Factoids/config.py @@ -47,6 +47,13 @@ class FactoidFormat(registry.TemplatedString): requiredTemplates = ['value'] 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', registry.String('as', _("""Determines what separator must be used in the learn command. Defaults to 'as' -- learn as . Users might diff --git a/plugins/Factoids/plugin.py b/plugins/Factoids/plugin.py index 5bc9c4ae2..a143a0311 100644 --- a/plugins/Factoids/plugin.py +++ b/plugins/Factoids/plugin.py @@ -31,6 +31,7 @@ import os import time import string +import urllib import supybot.conf as conf import supybot.ircdb as ircdb @@ -39,6 +40,7 @@ from supybot.commands import * import supybot.plugins as plugins import supybot.ircutils as ircutils import supybot.callbacks as callbacks +import supybot.httpserver as httpserver from supybot.i18n import PluginInternationalization, internationalizeDocstring _ = PluginInternationalization('Factoids') @@ -79,10 +81,138 @@ def getFactoidId(irc, msg, args, state): addConverter('factoid', getFactoid) addConverter('factoidId', getFactoidId) + +PAGE_SKELETON = """\ + + + Factoids + + +%s +""" + +DEFAULT_TEMPLATES = { + 'factoids/index.html': PAGE_SKELETON % """\ + +

Factoids

+
+ + + +
+""", + 'factoids/channel.html': PAGE_SKELETON % """\ + +

Factoids of %(channel)s

+ + + + + + + %(rows)s +
""" + _('key') + """""" + _('id') + """""" + _('fact') + """
+""" +} +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 += '' + content += ('' + '%s' + '') % (len(facts), key, key, key) + for id_, fact in facts.items(): + content += '%i' % id_ + content += '%s' % fact + content += '' + content = content[:-len('')] + 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): def __init__(self, irc): callbacks.Plugin.__init__(self, irc) 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): if os.path.exists(filename):