From 81a69df9ff87eedb0ce56f9d6740266033ba25a8 Mon Sep 17 00:00:00 2001 From: Valentin Lorentz Date: Sun, 7 Jul 2013 13:44:47 +0200 Subject: [PATCH] WebDoc: First commit. Closes GH-103. --- WebDoc/README.txt | 2 + WebDoc/__init__.py | 69 +++++++++++++++++ WebDoc/config.py | 56 ++++++++++++++ WebDoc/local/__init__.py | 1 + WebDoc/plugin.py | 162 +++++++++++++++++++++++++++++++++++++++ WebDoc/test.py | 37 +++++++++ 6 files changed, 327 insertions(+) create mode 100644 WebDoc/README.txt create mode 100644 WebDoc/__init__.py create mode 100644 WebDoc/config.py create mode 100644 WebDoc/local/__init__.py create mode 100644 WebDoc/plugin.py create mode 100644 WebDoc/test.py diff --git a/WebDoc/README.txt b/WebDoc/README.txt new file mode 100644 index 0000000..39500fd --- /dev/null +++ b/WebDoc/README.txt @@ -0,0 +1,2 @@ +This plugins displays help of Supybot commands via the HTTP server. + diff --git a/WebDoc/__init__.py b/WebDoc/__init__.py new file mode 100644 index 0000000..d675ba9 --- /dev/null +++ b/WebDoc/__init__.py @@ -0,0 +1,69 @@ +### +# Copyright (c) 2013, Valentin Lorentz +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +### + +""" +Add a description of the plugin (to be presented to the user inside the wizard) +here. This should describe *what* the plugin does. +""" + +import supybot +import supybot.world as world + +# Use this for the version of this plugin. You may wish to put a CVS keyword +# in here if you're keeping the plugin in CVS or some similar system. +__version__ = "" + +# XXX Replace this with an appropriate author or supybot.Author instance. +__author__ = supybot.authors.unknown + +# This is a dictionary mapping supybot.Author instances to lists of +# contributions. +__contributors__ = {} + +# This is a url where the most recent plugin package can be downloaded. +__url__ = '' # 'http://supybot.com/Members/yourname/WebDoc/download' + +from . import config +from . import plugin +from imp import reload +# In case we're being reloaded. +reload(config) +reload(plugin) +# Add more reloads here if you add third-party modules and want them to be +# reloaded when this plugin is reloaded. Don't forget to import them as well! + +if world.testing: + from . import test + +Class = plugin.Class +configure = config.configure + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/WebDoc/config.py b/WebDoc/config.py new file mode 100644 index 0000000..8f069cc --- /dev/null +++ b/WebDoc/config.py @@ -0,0 +1,56 @@ +### +# Copyright (c) 2013, Valentin Lorentz +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +### + +import supybot.conf as conf +import supybot.registry as registry +try: + from supybot.i18n import PluginInternationalization + _ = PluginInternationalization('WebDoc') +except: + # Placeholder that allows to run the plugin on a bot + # without the i18n module + _ = lambda x:x + +def configure(advanced): + # This will be called by supybot to configure this module. advanced is + # a bool that specifies whether the user identified himself as an advanced + # user or not. You should effect your configuration by manipulating the + # registry as appropriate. + from supybot.questions import expect, anything, something, yn + conf.registerPlugin('WebDoc', True) + + +WebDoc = conf.registerPlugin('WebDoc') +# This is where your configuration variables (if any) should go. For example: +# conf.registerGlobalValue(WebDoc, 'someConfigVariableName', +# registry.Boolean(False, _("""Help for someConfigVariableName."""))) + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: diff --git a/WebDoc/local/__init__.py b/WebDoc/local/__init__.py new file mode 100644 index 0000000..e86e97b --- /dev/null +++ b/WebDoc/local/__init__.py @@ -0,0 +1 @@ +# Stub so local is a module, used for third-party modules diff --git a/WebDoc/plugin.py b/WebDoc/plugin.py new file mode 100644 index 0000000..a7fb6f7 --- /dev/null +++ b/WebDoc/plugin.py @@ -0,0 +1,162 @@ +### +# Copyright (c) 2013, Valentin Lorentz +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +### + +import cgi +import sys +import supybot.conf as conf +import supybot.utils as utils +from supybot.commands import * +import supybot.plugins as plugins +import supybot.ircutils as ircutils +import supybot.callbacks as callbacks +import supybot.httpserver as httpserver +try: + from supybot.i18n import PluginInternationalization + _ = PluginInternationalization('WebDoc') +except: + # Placeholder that allows to run the plugin on a bot + # without the i18n module + _ = lambda x:x + +PAGE_SKELETON = """\ + + + + + Supybot web documentation + + + +%s + + +""" + +DEFAULT_TEMPLATES = { + 'webdoc/index.html': PAGE_SKELETON % ('purelisting', """\ +

Loaded plugins

+ +"""), + 'webdoc/plugin.html': PAGE_SKELETON % ('puretable', """\ +Plugin list + +

%(plugin)s

+ + + + + + +%(table)s +
CommandHelp
"""), + } + +httpserver.set_default_templates(DEFAULT_TEMPLATES) + +class WebDocServerCallback(httpserver.SupyHTTPServerCallback): + def __init__(self, irc): + super(WebDocServerCallback, self).__init__() + self._irc = irc + name = 'WebDoc' + def doGet(self, handler, path): + splitted_path = path.split('/') + if len(splitted_path) == 2: + names = filter(lambda x: conf.supybot.plugins.get(x).public(), + map(lambda cb:cb.name(), self._irc.callbacks)) + plugins = ''.join(map(lambda x:'
  • %s
  • '%(x,x), + sorted(names))) + response = 200 + output = httpserver.get_template('webdoc/index.html') % { + 'plugins': plugins, + } + elif len(splitted_path) == 3: + name = splitted_path[1] + cbs = dict(map(lambda cb:(cb.name(), cb), + self._irc.callbacks)) + if name not in cbs or \ + not conf.supybot.plugins.get(name).public(): + response = 404 + output = httpserver.get_template('generic/error.html') % \ + {'title': 'PluginsDoc', + 'error': 'Requested plugin is not found. Sorry.'} + else: + response = 200 + callback = cbs[name] + commands = callback.listCommands() + if commands: + commands.sort() + def formatter(command): + command = list(map(callbacks.canonicalName, + command.split(' '))) + doc = callback.getCommandMethod(command).__doc__ + doclines = doc.splitlines() + s = cgi.escape('%s %s' % (name, doclines.pop(0))) + if doclines: + help_ = cgi.escape('\n'.join(doclines)) + s = '%s
    %s' % \ + (ircutils.bold(s), help_) + return '%s%s' % \ + (' '.join(command), s) + + table = ''.join(map(formatter, commands)) + output = httpserver.get_template('webdoc/plugin.html') % { + 'plugin': name, + 'table': table, + } + + self.send_response(response) + self.send_header('Content-type', 'text/html; charset=utf-8') + self.end_headers() + if sys.version_info[0] >= 3: + output = output.encode() + self.wfile.write(output) + + +class WebDoc(callbacks.Plugin): + """Add the help for "@plugin help WebDoc" here + This should describe *how* to use this plugin.""" + def __init__(self, irc): + self.__parent = super(WebDoc, self) + callbacks.Plugin.__init__(self, irc) + + callback = WebDocServerCallback(irc) + httpserver.hook('plugindoc', callback) + + def die(self): + httpserver.unhook('plugindoc') + self.__parent.die() + + +Class = WebDoc + + +# vim:set shiftwidth=4 softtabstop=4 expandtab textwidth=79: diff --git a/WebDoc/test.py b/WebDoc/test.py new file mode 100644 index 0000000..019e47e --- /dev/null +++ b/WebDoc/test.py @@ -0,0 +1,37 @@ +### +# Copyright (c) 2013, Valentin Lorentz +# All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# * Redistributions of source code must retain the above copyright notice, +# this list of conditions, and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions, and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the author of this software nor the name of +# contributors to this software may be used to endorse or promote products +# derived from this software without specific prior written consent. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. + +### + +from supybot.test import * + +class WebDocTestCase(PluginTestCase): + plugins = ('WebDoc',) + + +# vim:set shiftwidth=4 tabstop=4 expandtab textwidth=79: