diff options
author | Joachim Filip Ignacy Bartosik <jbartosik@gmail.com> | 2011-05-18 16:44:11 +0200 |
---|---|---|
committer | Joachim Filip Ignacy Bartosik <jbartosik@gmail.com> | 2011-05-24 19:03:00 +0200 |
commit | e8c39d513356e14b60813c54824a63a6ad516348 (patch) | |
tree | dba08b74ad8470b3d36d813d14e310e512acea57 /bot/ircmeeting/items.py | |
parent | Basic meeting participation tracing (diff) | |
download | council-webapp-e8c39d513356e14b60813c54824a63a6ad516348.tar.gz council-webapp-e8c39d513356e14b60813c54824a63a6ad516348.tar.bz2 council-webapp-e8c39d513356e14b60813c54824a63a6ad516348.zip |
MeetBot plugin from Debian
Diffstat (limited to 'bot/ircmeeting/items.py')
-rw-r--r-- | bot/ircmeeting/items.py | 292 |
1 files changed, 292 insertions, 0 deletions
diff --git a/bot/ircmeeting/items.py b/bot/ircmeeting/items.py new file mode 100644 index 0000000..1109fb0 --- /dev/null +++ b/bot/ircmeeting/items.py @@ -0,0 +1,292 @@ +# Richard Darst, June 2009 + +### +# Copyright (c) 2009, Richard Darst +# 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 os +import re +import time + +import writers +#from writers import html, rst +import itertools + +def inbase(i, chars='abcdefghijklmnopqrstuvwxyz', place=0): + """Converts an integer into a postfix in base 26 using ascii chars. + + This is used to make a unique postfix for ReStructured Text URL + references, which must be unique. (Yes, this is over-engineering, + but keeps it short and nicely arranged, and I want practice + writing recursive functions.) + """ + div, mod = divmod(i, len(chars)**(place+1)) + if div == 0: + return chars[mod] + else: + return inbase2(div, chars=chars, place=place+1)+chars[mod] + + + +# +# These are objects which we can add to the meeting minutes. Mainly +# they exist to aid in HTML-formatting. +# +class _BaseItem(object): + itemtype = None + starthtml = '' + endhtml = '' + startrst = '' + endrst = '' + starttext = '' + endtext = '' + startmw = '' + endmw = '' + def get_replacements(self, M, escapewith): + replacements = { } + for name in dir(self): + if name[0] == "_": continue + replacements[name] = getattr(self, name) + replacements['nick'] = escapewith(replacements['nick']) + replacements['link'] = self.logURL(M) + for key in ('line', 'prefix', 'suffix', 'topic'): + if key in replacements: + replacements[key] = escapewith(replacements[key]) + if 'url' in replacements: + replacements['url_quoteescaped'] = \ + escapewith(self.url.replace('"', "%22")) + + return replacements + def template(self, M, escapewith): + template = { } + for k,v in self.get_replacements(M, escapewith).iteritems(): + if k not in ('itemtype', 'line', 'topic', + 'url', 'url_quoteescaped', + 'nick', 'time', 'link', 'anchor'): + continue + template[k] = v + return template + def makeRSTref(self, M): + if self.nick[-1] == '_': + rstref = rstref_orig = "%s%s"%(self.nick, self.time) + else: + rstref = rstref_orig = "%s-%s"%(self.nick, self.time) + count = 0 + while rstref in M.rst_refs: + rstref = rstref_orig + inbase(count) + count += 1 + link = self.logURL(M) + M.rst_urls.append(".. _%s: %s"%(rstref, link+"#"+self.anchor)) + M.rst_refs[rstref] = True + return rstref + @property + def anchor(self): + return 'l-'+str(self.linenum) + def logURL(self, M): + return M.config.basename+'.log.html' + +class Topic(_BaseItem): + itemtype = 'TOPIC' + html_template = """<tr><td><a href='%(link)s#%(anchor)s'>%(time)s</a></td> + <th colspan=3>%(starthtml)sTopic: %(topic)s%(endhtml)s</th> + </tr>""" + #html2_template = ("""<b>%(starthtml)s%(topic)s%(endhtml)s</b> """ + # """(%(nick)s, <a href='%(link)s#%(anchor)s'>%(time)s</a>)""") + html2_template = ("""%(starthtml)s%(topic)s%(endhtml)s """ + """<span class="details">""" + """(<a href='%(link)s#%(anchor)s'>%(nick)s</a>, """ + """%(time)s)""" + """</span>""") + rst_template = """%(startrst)s%(topic)s%(endrst)s (%(rstref)s_)""" + text_template = """%(starttext)s%(topic)s%(endtext)s (%(nick)s, %(time)s)""" + mw_template = """%(startmw)s%(topic)s%(endmw)s (%(nick)s, %(time)s)""" + startrst = '**' + endrst = '**' + startmw = "'''" + endmw = "'''" + starthtml = '<b class="TOPIC">' + endhtml = '</b>' + def __init__(self, nick, line, linenum, time_): + self.nick = nick ; self.topic = line ; self.linenum = linenum + self.time = time.strftime("%H:%M:%S", time_) + def _htmlrepl(self, M): + repl = self.get_replacements(M, escapewith=writers.html) + repl['link'] = self.logURL(M) + return repl + def html(self, M): + return self.html_template%self._htmlrepl(M) + def html2(self, M): + return self.html2_template%self._htmlrepl(M) + def rst(self, M): + self.rstref = self.makeRSTref(M) + repl = self.get_replacements(M, escapewith=writers.rst) + if repl['topic']=='': repl['topic']=' ' + repl['link'] = self.logURL(M) + return self.rst_template%repl + def text(self, M): + repl = self.get_replacements(M, escapewith=writers.text) + repl['link'] = self.logURL(M) + return self.text_template%repl + def mw(self, M): + repl = self.get_replacements(M, escapewith=writers.mw) + return self.mw_template%repl + +class GenericItem(_BaseItem): + itemtype = '' + html_template = """<tr><td><a href='%(link)s#%(anchor)s'>%(time)s</a></td> + <td>%(itemtype)s</td><td>%(nick)s</td><td>%(starthtml)s%(line)s%(endhtml)s</td> + </tr>""" + #html2_template = ("""<i>%(itemtype)s</i>: %(starthtml)s%(line)s%(endhtml)s """ + # """(%(nick)s, <a href='%(link)s#%(anchor)s'>%(time)s</a>)""") + html2_template = ("""<i class="itemtype">%(itemtype)s</i>: """ + """<span class="%(itemtype)s">""" + """%(starthtml)s%(line)s%(endhtml)s</span> """ + """<span class="details">""" + """(<a href='%(link)s#%(anchor)s'>%(nick)s</a>, """ + """%(time)s)""" + """</span>""") + rst_template = """*%(itemtype)s*: %(startrst)s%(line)s%(endrst)s (%(rstref)s_)""" + text_template = """%(itemtype)s: %(starttext)s%(line)s%(endtext)s (%(nick)s, %(time)s)""" + mw_template = """''%(itemtype)s:'' %(startmw)s%(line)s%(endmw)s (%(nick)s, %(time)s)""" + def __init__(self, nick, line, linenum, time_): + self.nick = nick ; self.line = line ; self.linenum = linenum + self.time = time.strftime("%H:%M:%S", time_) + def _htmlrepl(self, M): + repl = self.get_replacements(M, escapewith=writers.html) + repl['link'] = self.logURL(M) + return repl + def html(self, M): + return self.html_template%self._htmlrepl(M) + def html2(self, M): + return self.html2_template%self._htmlrepl(M) + def rst(self, M): + self.rstref = self.makeRSTref(M) + repl = self.get_replacements(M, escapewith=writers.rst) + repl['link'] = self.logURL(M) + return self.rst_template%repl + def text(self, M): + repl = self.get_replacements(M, escapewith=writers.text) + repl['link'] = self.logURL(M) + return self.text_template%repl + def mw(self, M): + repl = self.get_replacements(M, escapewith=writers.mw) + return self.mw_template%repl + + +class Info(GenericItem): + itemtype = 'INFO' + html2_template = ("""<span class="%(itemtype)s">""" + """%(starthtml)s%(line)s%(endhtml)s</span> """ + """<span class="details">""" + """(<a href='%(link)s#%(anchor)s'>%(nick)s</a>, """ + """%(time)s)""" + """</span>""") + rst_template = """%(startrst)s%(line)s%(endrst)s (%(rstref)s_)""" + text_template = """%(starttext)s%(line)s%(endtext)s (%(nick)s, %(time)s)""" + mw_template = """%(startmw)s%(line)s%(endmw)s (%(nick)s, %(time)s)""" +class Idea(GenericItem): + itemtype = 'IDEA' +class Agreed(GenericItem): + itemtype = 'AGREED' +class Action(GenericItem): + itemtype = 'ACTION' +class Help(GenericItem): + itemtype = 'HELP' +class Accepted(GenericItem): + itemtype = 'ACCEPTED' + starthtml = '<font color="green">' + endhtml = '</font>' +class Rejected(GenericItem): + itemtype = 'REJECTED' + starthtml = '<font color="red">' + endhtml = '</font>' +class Link(_BaseItem): + itemtype = 'LINK' + html_template = """<tr><td><a href='%(link)s#%(anchor)s'>%(time)s</a></td> + <td>%(itemtype)s</td><td>%(nick)s</td><td>%(starthtml)s%(prefix)s<a href="%(url)s">%(url_readable)s</a>%(suffix)s%(endhtml)s</td> + </tr>""" + html2_template = ("""%(starthtml)s%(prefix)s<a href="%(url)s">%(url_readable)s</a>%(suffix)s%(endhtml)s """ + """<span class="details">""" + """(<a href='%(link)s#%(anchor)s'>%(nick)s</a>, """ + """%(time)s)""" + """</span>""") + rst_template = """*%(itemtype)s*: %(startrst)s%(prefix)s%(url)s%(suffix)s%(endrst)s (%(rstref)s_)""" + text_template = """%(itemtype)s: %(starttext)s%(prefix)s%(url)s%(suffix)s%(endtext)s (%(nick)s, %(time)s)""" + mw_template = """''%(itemtype)s:'' %(startmw)s%(prefix)s%(url)s%(suffix)s%(endmw)s (%(nick)s, %(time)s)""" + def __init__(self, nick, line, linenum, time_, M): + self.nick = nick ; self.linenum = linenum + self.time = time.strftime("%H:%M:%S", time_) + self.line = line + + protocols = M.config.UrlProtocols + protocols = '|'.join(re.escape(p) for p in protocols) + protocols = '(?:'+protocols+')' + # This is gross. + # (.*?) - any prefix, non-greedy + # (%s//[^\s]+ - protocol://... until the next space + # (?<!\.|\)) - but the last character can NOT be . or ) + # (.*) - any suffix + url_re = re.compile(r'(.*?)(%s//[^\s]+(?<!\.|\)))(.*)'%protocols) + m = url_re.match(line) + if m: + self.prefix = m.group(1) + self.url = m.group(2) + self.suffix = m.group(3) + else: + # simple matching, the old way. + self.url, self.suffix = (line+' ').split(' ', 1) + self.suffix = ' '+self.suffix + self.prefix = '' + # URL-sanitization + self.url_readable = self.url # readable line version + self.url = self.url + self.line = self.line.strip() + def _htmlrepl(self, M): + repl = self.get_replacements(M, escapewith=writers.html) + # special: replace doublequote only for the URL. + repl['url'] = writers.html(self.url.replace('"', "%22")) + repl['url_readable'] = writers.html(self.url) + repl['link'] = self.logURL(M) + return repl + def html(self, M): + return self.html_template%self._htmlrepl(M) + def html2(self, M): + return self.html2_template%self._htmlrepl(M) + def rst(self, M): + self.rstref = self.makeRSTref(M) + repl = self.get_replacements(M, escapewith=writers.rst) + repl['link'] = self.logURL(M) + #repl['url'] = writers.rst(self.url) + return self.rst_template%repl + def text(self, M): + repl = self.get_replacements(M, escapewith=writers.text) + repl['link'] = self.logURL(M) + return self.text_template%repl + def mw(self, M): + repl = self.get_replacements(M, escapewith=writers.mw) + return self.mw_template%repl |