Skip to content
Browse files

Factoids: Add the web interface.

  • Loading branch information...
1 parent 24252bc commit f4c643ad51bfc20b8a2e5bae1e04a725dde4ef13 @ProgVal committed Mar 11, 2013
Showing with 137 additions and 0 deletions.
  1. +7 −0 plugins/Factoids/config.py
  2. +130 −0 plugins/Factoids/plugin.py
View
7 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 <key> as <value>. Users might
View
130 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 @@
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 = """\
+<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):
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):

0 comments on commit f4c643a

Please sign in to comment.
Something went wrong with that request. Please try again.