public inbox for gentoo-commits@lists.gentoo.org
 help / color / mirror / Atom feed
* [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/
@ 2011-06-05 20:37 Petteri Räty
  0 siblings, 0 replies; 12+ messages in thread
From: Petteri Räty @ 2011-06-05 20:37 UTC (permalink / raw
  To: gentoo-commits

commit:     d93c2e59b3e1b0a077c34ad9f560b79a9f1670df
Author:     Joachim Filip Ignacy Bartosik <jbartosik <AT> gmail <DOT> com>
AuthorDate: Mon May 23 11:17:40 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Fri Jun  3 17:17:48 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/council-webapp.git;a=commit;h=d93c2e59

Bot obtains voters, agenda items and voting options lists from webapp

---
 bot/ircmeeting/agenda.py         |   91 ++++++++++++++
 bot/ircmeeting/meeting.py        |   26 ++++-
 bot/tests/MeetBot                |    1 +
 bot/tests/ircmeeting             |    1 +
 bot/tests/run_test.py            |   71 +++++++++++
 bot/tests/test-script-1.html     |  256 ++++++++++++++++++++++++++++++++++++++
 bot/tests/test-script-1.log.html |   91 ++++++++++++++
 bot/tests/test-script-1.txt      |   98 +++++++++++++++
 8 files changed, 633 insertions(+), 2 deletions(-)

diff --git a/bot/ircmeeting/agenda.py b/bot/ircmeeting/agenda.py
new file mode 100644
index 0000000..7ee9beb
--- /dev/null
+++ b/bot/ircmeeting/agenda.py
@@ -0,0 +1,91 @@
+import json
+import urllib
+
+class Agenda(object):
+
+    # Messages
+    empty_agenda_msg = "Agenda is empty so I can't help you manage meeting (and voting)."
+    current_item_msg = "Current agenda item is {}."
+    voting_already_open_msg = "Voting is already open. You can end it with #endvote."
+    voting_open_msg = "Voting started. Your choices are: {} Vote #vote <option number>.\n End voting with #endvote."
+    voting_close_msg = "Voting is closed."
+    voting_already_closed_msg = "Voting is already closed. You can start it with #startvote."
+    voting_open_so_item_not_changed_msg = "Voting is currently open so I didn't change item. Please #endvote first"
+    can_not_vote_msg = "You can not vote. Only {} can vote"
+    not_a_number_msg = "Your vote was not recognized as a number. Please retry."
+    out_of_range_msg = "Your vote was out of range!"
+    vote_confirm_msg = "You voted for #{} - {}"
+
+    # Internal
+    _voters     = []
+    _votes      = []
+    _agenda     = []
+    _current_item = 0
+    _vote_open  = False
+
+    def __init__(self, conf):
+      self.conf = conf
+
+    def get_agenda_item(self):
+        if self._current_item < len(self._agenda):
+            return str.format(self.current_item_msg, self._agenda[self._current_item][0])
+        else:
+            return self.empty_agenda_msg
+
+    def next_agenda_item(self):
+        if self._vote_open:
+            return voting_open_so_item_not_changed_msg
+        else:
+            if (self._current_item + 1) < len(self._agenda):
+                self._current_item += 1
+            return(self.get_agenda_item())
+
+    def prev_agenda_item(self):
+        if self._vote_open:
+            return voting_open_so_item_not_changed_msg
+        else:
+            if self._current_item > 0:
+                self._current_item -= 1
+            return(self.get_agenda_item())
+
+    def start_vote(self):
+        if self._vote_open:
+            return self.voting_already_open_msg
+        self._vote_open = True
+        options = "\n"
+        for i in range(len(self._agenda[self._current_item][1])):
+            options += str.format("{}. {}\n", i, self._agenda[self._current_item][i])
+        return str.format(self.voting_open_msg, options)
+
+    def end_vote(self):
+        if self._vote_open:
+            self._vote_open = False
+            return voting_already_closed_msg
+        return voting_close_msg
+
+    def get_data(self):
+        self._voters = self._get_json(self.conf.voters_url)
+        self._agenda = self._get_json(self.conf.agenda_url)
+        self._votes = { }
+        for i in self._agenda:
+            self._votes[i[0]] = { }
+
+    def vote(self, nick, line):
+        if not nick in self._voters:
+            return str.format(self.can_not_vote_msg, ", ".join(self._voters))
+        if not line.isdigit():
+            return self.not_a_number_msg
+
+        opt = int(line)
+
+        if opt < 0 or opt >= len(self._agenda[self._current_item][1]):
+            return self.out_of_range_msg
+
+        self._votes[self._agenda[self._current_item][0]][nick] = self._agenda[self._current_item][1][opt]
+        return str.format(self.vote_confirm_msg, opt, self._agenda[self._current_item][opt])
+
+    def _get_json(self, url):
+        str = urllib.urlopen(url).read()
+        str = urllib.unquote(str)
+        result = json.loads(str)
+        return result

diff --git a/bot/ircmeeting/meeting.py b/bot/ircmeeting/meeting.py
index 85880a6..b22dac6 100644
--- a/bot/ircmeeting/meeting.py
+++ b/bot/ircmeeting/meeting.py
@@ -36,6 +36,7 @@ import stat
 
 import writers
 import items
+import agenda
 reload(writers)
 reload(items)
 
@@ -96,6 +97,11 @@ class Config(object):
     input_codec = 'utf-8'
     output_codec = 'utf-8'
     # Functions to do the i/o conversion.
+
+    # Meeting management urls
+    voters_url = 'http://localhost:3000/users/voters'
+    agenda_url = 'http://localhost:3000/agendas/current_items'
+
     def enc(self, text):
         return text.encode(self.output_codec, 'replace')
     def dec(self, text):
@@ -118,7 +124,6 @@ class Config(object):
         #'.rst.html':writers.HTMLfromReST,
         }
 
-
     def __init__(self, M, writeRawLog=False, safeMode=False,
                  extraConfig={}):
         self.M = M
@@ -134,6 +139,7 @@ class Config(object):
         for extension, writer in self.writer_map.iteritems():
             self.writers[extension] = writer(self.M)
         self.safeMode = safeMode
+        self.agenda = agenda.Agenda(self)
     def filename(self, url=False):
         # provide a way to override the filename.  If it is
         # overridden, it must be a full path (and the URL-part may not
@@ -308,6 +314,22 @@ class MeetingCommands(object):
             self.reply(messageline)
         if line.strip():
             self.do_meetingtopic(nick=nick, line=line, time_=time_, **kwargs)
+        self.config.agenda.get_data()
+        self.reply(self.config.agenda.get_agenda_item())
+
+    def do_nextitem(self, nick, time_, line, **kwargs):
+        self.reply(self.config.agenda.next_agenda_item())
+
+    def do_previtem(self, nick, time_, line, **kwargs):
+        self.reply(self.config.agenda.prev_agenda_item())
+
+    def do_startvote(self, nick, time_, line, **kwargs):
+       for messageline in self.config.agenda.start_vote().split('\n'):
+            self.reply(messageline)
+
+    def do_vote(self, nick, time_, line, **kwargs):
+        self.reply(self.config.agenda.vote(nick, line))
+
     def do_endmeeting(self, nick, time_, **kwargs):
         """End the meeting."""
         if not self.isChair(nick): return
@@ -454,7 +476,7 @@ class MeetingCommands(object):
         commands = [ "#"+x[3:] for x in dir(self) if x[:3]=="do_" ]
         commands.sort()
         self.reply("Available commands: "+(" ".join(commands)))
-            
+
 
 
 class Meeting(MeetingCommands, object):

diff --git a/bot/tests/MeetBot b/bot/tests/MeetBot
new file mode 120000
index 0000000..f06815a
--- /dev/null
+++ b/bot/tests/MeetBot
@@ -0,0 +1 @@
+../MeetBot
\ No newline at end of file

diff --git a/bot/tests/ircmeeting b/bot/tests/ircmeeting
new file mode 120000
index 0000000..90e99f6
--- /dev/null
+++ b/bot/tests/ircmeeting
@@ -0,0 +1 @@
+../ircmeeting
\ No newline at end of file

diff --git a/bot/tests/run_test.py b/bot/tests/run_test.py
index 213cd43..f304a2b 100644
--- a/bot/tests/run_test.py
+++ b/bot/tests/run_test.py
@@ -7,6 +7,7 @@ import shutil
 import sys
 import tempfile
 import unittest
+import time
 
 os.environ['MEETBOT_RUNNING_TESTS'] = '1'
 import ircmeeting.meeting as meeting
@@ -14,6 +15,12 @@ import ircmeeting.writers as writers
 
 running_tests = True
 
+def parse_time(time_):
+    try: return time.strptime(time_, "%H:%M:%S")
+    except ValueError: pass
+    try: return time.strptime(time_, "%H:%M")
+    except ValueError: pass
+
 def process_meeting(contents, extraConfig={}, dontSave=True,
                     filename='/dev/null'):
     """Take a test script, return Meeting object of that meeting.
@@ -337,9 +344,73 @@ class MeetBotTest(unittest.TestCase):
         assert M.config.filename().endswith('somechannel-blah1234'),\
                "Filename not as expected: "+M.config.filename()
 
+    def test_agenda(self):
+        """ Test agenda management
+        """
+        logline_re = re.compile(r'\[?([0-9: ]*)\]? *<[@+]?([^>]+)> *(.*)')
+        loglineAction_re = re.compile(r'\[?([0-9: ]*)\]? *\* *([^ ]+) *(.*)')
+
+        M = process_meeting('#startmeeting')
+        log = []
+        M._sendReply = lambda x: log.append(x)
+        M.config.agenda._voters = ['x', 'z']
+        M.config.agenda._agenda = [['first item', ['opt1', 'opt2']], ['second item', []]]
+        M.config.agenda._votes = { }
+        for i in M.config.agenda._agenda:
+            M.config.agenda._votes[i[0]] = { }
+
+
+        M.starttime = time.gmtime(0)
+        contents = """20:13:50 <x> #nextitem
+        20:13:50 <x> #nextitem
+        20:13:50 <x> #previtem
+        20:13:50 <x> #previtem
+        20:13:50 <x> #startvote
+        20:13:50 <x> #vote 10
+        20:13:50 <x> #vote 1
+        20:13:50 <y> #vote 0
+        20:13:50 <z> #vote 0
+        20:13:50 <x> #endvote
+        20:13:50 <x> #endmeeting"""
+
+        for line in contents.split('\n'):
+            # match regular spoken lines:
+            m = logline_re.match(line)
+            if m:
+                time_ = parse_time(m.group(1).strip())
+                nick = m.group(2).strip()
+                line = m.group(3).strip()
+                if M.owner is None:
+                    M.owner = nick ; M.chairs = {nick:True}
+                M.addline(nick, line, time_=time_)
+            # match /me lines
+            m = loglineAction_re.match(line)
+            if m:
+                time_ = parse_time(m.group(1).strip())
+                nick = m.group(2).strip()
+                line = m.group(3).strip()
+                M.addline(nick, "ACTION "+line, time_=time_)
+
+        self.assert_(M.config.agenda._votes == {'first item': {u'x': 'opt2', u'z': 'opt1'}, 'second item': {}})
+
+        answers = ['Current agenda item is second item.',
+            'Current agenda item is second item.',
+            'Current agenda item is first item.',
+            'Current agenda item is first item.',
+            'Voting started. Your choices are: ',
+            '0. first item',
+            "1. ['opt1', 'opt2']",
+            ' Vote #vote <option number>.',
+            ' End voting with #endvote.',
+            'Your vote was out of range!',
+            "You voted for #1 - ['opt1', 'opt2']",
+            'You can not vote. Only x, z can vote',
+            'You voted for #0 - first item']
+        self.assert_(log[0:len(answers)] == answers)
 
 if __name__ == '__main__':
     os.chdir(os.path.join(os.path.dirname(__file__), '.'))
+
     if len(sys.argv) <= 1:
         unittest.main()
     else:

diff --git a/bot/tests/test-script-1.html b/bot/tests/test-script-1.html
new file mode 100644
index 0000000..fa42143
--- /dev/null
+++ b/bot/tests/test-script-1.html
@@ -0,0 +1,256 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
+<title>#test-script-1 Meeting</title>
+<style type="text/css">
+/* This is for the .html in the HTML2 writer */
+body {
+    font-family: Helvetica, sans-serif;
+    font-size:14px;
+}
+h1 {
+    text-align: center;
+}
+a {
+    color:navy;
+    text-decoration: none;
+    border-bottom:1px dotted navy;
+}
+a:hover {
+    text-decoration:none;
+    border-bottom: 0;
+    color:#0000B9;
+}
+hr {
+    border: 1px solid #ccc;
+}
+/* The (nick, time) item pairs, and other body text things. */
+.details {
+    font-size: 12px;
+    font-weight:bold;
+}
+/* The 'AGREED:', 'IDEA', etc, prefix to lines. */
+.itemtype {
+    font-style: normal;    /* un-italics it */
+    font-weight: bold;
+}
+/* Example: change single item types.  Capitalized command name.
+/* .TOPIC  {  color:navy;  } */
+/* .AGREED {  color:lime;  } */
+
+</style>
+</head>
+
+<body>
+<h1>#test-script-1 Meeting</h1>
+<span class="details">
+Meeting started by MrBeige at 20:13:46 UTC
+(<a href="test-script-1.log.html">full logs</a>).</span>
+
+<br><br>
+
+
+
+<h3>Meeting summary</h3>
+<ol>
+<li>
+<ol type="a">
+  <li><span class="INFO">this command is just before the first
+    topic</span> <span class="details">(<a
+    href='test-script-1.log.html#l-2'>T-Rex</a>, 20:13:50)</span></li>
+</ol>
+<br></li>
+<li><b class="TOPIC">General command tests</b> <span class="details">(<a href='test-script-1.log.html#l-7'>MrBeige</a>, 20:13:50)</span>
+<ol type="a">
+  <li><i class="itemtype">ACCEPTED</i>: <span class="ACCEPTED"><font
+    color="green">we will include this new format if we so
+    choose.</font></span> <span class="details">(<a
+    href='test-script-1.log.html#l-8'>MrBeige</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">REJECTED</i>: <span class="REJECTED"><font
+    color="red">we will not include this new format.</font></span> <span
+    class="details">(<a href='test-script-1.log.html#l-9'>MrBeige</a>,
+    20:13:50)</span></li>
+</ol>
+<br></li>
+<li><b class="TOPIC">Test of all commands with different arguments</b> <span class="details">(<a href='test-script-1.log.html#l-16'>MrBeige</a>, 20:13:50)</span>
+<br></li>
+<li><b class="TOPIC"></b> <span class="details">(<a href='test-script-1.log.html#l-17'>MrBeige</a>, 20:13:50)</span>
+<ol type="a">
+  <li><i class="itemtype">IDEA</i>: <span class="IDEA"></span> <span
+    class="details">(<a href='test-script-1.log.html#l-18'>MrBeige</a>,
+    20:13:50)</span></li>
+  <li><span class="INFO"></span> <span class="details">(<a
+    href='test-script-1.log.html#l-19'>MrBeige</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">ACTION</i>: <span class="ACTION"></span> <span
+    class="details">(<a href='test-script-1.log.html#l-20'>MrBeige</a>,
+    20:13:50)</span></li>
+  <li><i class="itemtype">AGREED</i>: <span class="AGREED"></span> <span
+    class="details">(<a href='test-script-1.log.html#l-21'>MrBeige</a>,
+    20:13:50)</span></li>
+  <li><i class="itemtype">HELP</i>: <span class="HELP"></span> <span
+    class="details">(<a href='test-script-1.log.html#l-22'>MrBeige</a>,
+    20:13:50)</span></li>
+  <li><i class="itemtype">ACCEPTED</i>: <span class="ACCEPTED"><font
+    color="green"></font></span> <span class="details">(<a
+    href='test-script-1.log.html#l-23'>MrBeige</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">REJECTED</i>: <span class="REJECTED"><font
+    color="red"></font></span> <span class="details">(<a
+    href='test-script-1.log.html#l-24'>MrBeige</a>, 20:13:50)</span></li>
+</ol>
+<br></li>
+<li><b class="TOPIC">Commands with non-ascii</b> <span class="details">(<a href='test-script-1.log.html#l-25'>MrBeige</a>, 20:13:50)</span>
+<br></li>
+<li><b class="TOPIC">üáç€</b> <span class="details">(<a href='test-script-1.log.html#l-26'>MrBeige</a>, 20:13:50)</span>
+<ol type="a">
+  <li><i class="itemtype">IDEA</i>: <span class="IDEA">üáç€</span> <span
+    class="details">(<a href='test-script-1.log.html#l-27'>MrBeige</a>,
+    20:13:50)</span></li>
+  <li><span class="INFO">üáç€</span> <span class="details">(<a
+    href='test-script-1.log.html#l-28'>MrBeige</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">ACTION</i>: <span class="ACTION">üáç€</span>
+    <span class="details">(<a
+    href='test-script-1.log.html#l-29'>MrBeige</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">AGREED</i>: <span class="AGREED">üáç€</span>
+    <span class="details">(<a
+    href='test-script-1.log.html#l-30'>MrBeige</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">HELP</i>: <span class="HELP">üáç€</span> <span
+    class="details">(<a href='test-script-1.log.html#l-31'>MrBeige</a>,
+    20:13:50)</span></li>
+  <li><i class="itemtype">ACCEPTED</i>: <span class="ACCEPTED"><font
+    color="green">üáç€</font></span> <span class="details">(<a
+    href='test-script-1.log.html#l-32'>MrBeige</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">REJECTED</i>: <span class="REJECTED"><font
+    color="red">üáç€</font></span> <span class="details">(<a
+    href='test-script-1.log.html#l-33'>MrBeige</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">IDEA</i>: <span class="IDEA">blah</span> <span
+    class="details">(<a href='test-script-1.log.html#l-35'>MrBeige</a>,
+    20:13:50)</span></li>
+  <li><i class="itemtype">ACTION</i>: <span class="ACTION">blah</span>
+    <span class="details">(<a
+    href='test-script-1.log.html#l-36'>MrBeige</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">AGREED</i>: <span class="AGREED">blah</span>
+    <span class="details">(<a
+    href='test-script-1.log.html#l-37'>Utahraptor</a>, 20:13:50)</span></li>
+</ol>
+<br></li>
+<li><b class="TOPIC">Escapes</b> <span class="details">(<a href='test-script-1.log.html#l-38'>MrBeige</a>, 20:13:50)</span>
+<ol type="a">
+  <li><i class="itemtype">IDEA</i>: <span class="IDEA">blah_ blah_ ReST
+    link reference...</span> <span class="details">(<a
+    href='test-script-1.log.html#l-41'>Utahraptor</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">IDEA</i>: <span class="IDEA">blah blah
+    blah</span> <span class="details">(<a
+    href='test-script-1.log.html#l-42'>ReST1_</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">IDEA</i>: <span
+    class="IDEA">under_score</span> <span class="details">(<a
+    href='test-script-1.log.html#l-44'>ReST2_</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">IDEA</i>: <span
+    class="IDEA">under_score</span> <span class="details">(<a
+    href='test-script-1.log.html#l-45'>Re_ST</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">IDEA</i>: <span
+    class="IDEA">under1_1score</span> <span class="details">(<a
+    href='test-script-1.log.html#l-46'>Re_ST</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">IDEA</i>: <span
+    class="IDEA">under1_score</span> <span class="details">(<a
+    href='test-script-1.log.html#l-47'>Re_ST</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">IDEA</i>: <span
+    class="IDEA">under_1score</span> <span class="details">(<a
+    href='test-script-1.log.html#l-48'>Re_ST</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">IDEA</i>: <span
+    class="IDEA">under-_score</span> <span class="details">(<a
+    href='test-script-1.log.html#l-49'>Re_ST</a>, 20:13:50)</span></li>
+  <li><i class="itemtype">IDEA</i>: <span
+    class="IDEA">under_-score</span> <span class="details">(<a
+    href='test-script-1.log.html#l-50'>Re_ST</a>, 20:13:50)</span></li>
+</ol>
+<br></li>
+<li><b class="TOPIC">Links</b> <span class="details">(<a href='test-script-1.log.html#l-51'>MrBeige</a>, 20:13:50)</span>
+<ol type="a">
+  <li><a
+    href="http://test&lt;b&gt;.zgib.net">http://test&lt;b&gt;.zgib.net</a>
+    <span class="details">(<a
+    href='test-script-1.log.html#l-52'>Utahraptor</a>, 20:13:50)</span></li>
+  <li><a
+    href="ftp://test&lt;b&gt;.zgib.net">ftp://test&lt;b&gt;.zgib.net</a>
+    " <span class="details">(<a
+    href='test-script-1.log.html#l-53'>Utahraptor</a>, 20:13:50)</span></li>
+  <li><a href="mailto://a@bla%22h.com">mailto://a@bla"h.com</a> <span
+    class="details">(<a
+    href='test-script-1.log.html#l-54'>Utahraptor</a>, 20:13:50)</span></li>
+  <li><a
+    href="http://test.zgib.net/&amp;testpage">http://test.zgib.net/&amp;testpage</a>
+    <span class="details">(<a
+    href='test-script-1.log.html#l-55'>Utahraptor</a>, 20:13:50)</span></li>
+  <li>prefix <a
+    href="http://test.zgib.net/&amp;testpage">http://test.zgib.net/&amp;testpage</a>
+    suffix <span class="details">(<a
+    href='test-script-1.log.html#l-56'>Utahraptor</a>, 20:13:50)</span></li>
+  <li>prefix <a
+    href="ftp://test.zg%22ib.net/&amp;testpage">ftp://test.zg"ib.net/&amp;testpage</a>
+    suffix <span class="details">(<a
+    href='test-script-1.log.html#l-57'>Utahraptor</a>, 20:13:50)</span></li>
+  <li>prefix <a
+    href="mailto://a@blah.com&amp;testpage">mailto://a@blah.com&amp;testpage</a>
+    suffix <span class="details">(<a
+    href='test-script-1.log.html#l-58'>Utahraptor</a>, 20:13:50)</span></li>
+  <li>prefix <a href="http://google.com/">http://google.com/</a>. suffix
+    <span class="details">(<a
+    href='test-script-1.log.html#l-59'>Utahraptor</a>, 20:13:50)</span></li>
+  <li>prefix (<a href="http://google.com/">http://google.com/</a>)
+    suffix <span class="details">(<a
+    href='test-script-1.log.html#l-60'>Utahraptor</a>, 20:13:50)</span></li>
+</ol>
+<br></li>
+<li><b class="TOPIC">Character sets</b> <span class="details">(<a href='test-script-1.log.html#l-61'>MrBeige</a>, 20:13:50)</span>
+<ol type="a">
+  <li><i class="itemtype">IDEA</i>: <span class="IDEA">Nick with
+    accents.</span> <span class="details">(<a
+    href='test-script-1.log.html#l-63'>Üţáhraptõr</a>, 20:13:50)</span></li>
+</ol>
+</li>
+</ol>
+<br><br>
+
+
+
+<span class="details">
+Meeting ended at 20:13:52 UTC
+(<a href="test-script-1.log.html">full logs</a>).</span>
+
+<br><br>
+
+
+
+<h3>Action items</h3>
+<ol>
+  <li></li>
+  <li>üáç€</li>
+  <li>blah</li>
+</ol>
+<br><br>
+
+
+
+<h3>People present (lines said)</h3>
+<ol>
+  <li>MrBeige (35)</li>
+  <li>Utahraptor (13)</li>
+  <li>Re_ST (6)</li>
+  <li>T-Rex (5)</li>
+  <li>ReST2_ (2)</li>
+  <li>Üţáhraptõr (2)</li>
+  <li>ReST1_ (1)</li>
+  <li>áccents (0)</li>
+  <li>not-here (0)</li>
+  <li>** (0)</li>
+  <li>áccenẗs (0)</li>
+  <li>someone-not-present (0)</li>
+  <li>&lt;b&gt; (0)</li>
+</ol>
+<br><br>
+
+
+
+<span class="details">Generated by <a href="http://wiki.debian.org/MeetBot">MeetBot</a> 0.1.4.</span>
+</body></html>

diff --git a/bot/tests/test-script-1.log.html b/bot/tests/test-script-1.log.html
new file mode 100644
index 0000000..5e7642c
--- /dev/null
+++ b/bot/tests/test-script-1.log.html
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<html>
+<head>
+<meta http-equiv="Content-type" content="text/html;charset=UTF-8">
+<title>#test-script-1 log</title>
+<style type="text/css">
+/* For the .log.html */
+pre { /*line-height: 125%;*/
+      white-space: pre-wrap; }
+body { background: #f0f0f0; }
+
+body .tm  { color: #007020 }                      /* time */
+body .nk  { color: #062873; font-weight: bold }   /* nick, regular */
+body .nka { color: #007020; font-weight: bold }  /* action nick */
+body .ac  { color: #00A000 }                      /* action line */
+body .hi  { color: #4070a0 }                 /* hilights */
+/* Things to make particular MeetBot commands stick out */
+body .topic     { color: #007020; font-weight: bold }
+body .topicline { color: #000080; font-weight: bold }
+body .cmd       { color: #007020; font-weight: bold }
+body .cmdline  { font-weight: bold }
+
+</style>
+</head>
+
+<body>
+<pre><a name="l-1"></a><span class="tm">20:13:46</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#startmeeting</span><span class="cmdline"></span>
+<a name="l-2"></a><span class="tm">20:13:50</span><span class="nk"> &lt;T-Rex&gt;</span> <span class="cmd">#info </span><span class="cmdline">this command is just before the first topic</span>
+<a name="l-3"></a><span class="tm">20:13:50</span><span class="nk"> &lt;T-Rex&gt;</span> <span class="topic">#topic </span><span class="topicline">Test of topics</span>
+<a name="l-4"></a><span class="tm">20:13:50</span><span class="nk"> &lt;T-Rex&gt;</span> <span class="topic">#topic </span><span class="topicline">Second topic</span>
+<a name="l-5"></a><span class="tm">20:13:50</span><span class="nk"> &lt;T-Rex&gt;</span> <span class="cmd">#meetingtopic </span><span class="cmdline">the meeting topic</span>
+<a name="l-6"></a><span class="tm">20:13:50</span><span class="nk"> &lt;T-Rex&gt;</span> <span class="topic">#topic </span><span class="topicline">With áccents</span>
+<a name="l-7"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="topic">#topic </span><span class="topicline">General command tests</span>
+<a name="l-8"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#accepted </span><span class="cmdline">we will include this new format if we so choose.</span>
+<a name="l-9"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#rejected </span><span class="cmdline">we will not include this new format.</span>
+<a name="l-10"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#chair </span><span class="cmdline">Utahraptor T-Rex not-here</span>
+<a name="l-11"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#chair </span><span class="cmdline">Utahraptor T-Rex</span>
+<a name="l-12"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#nick </span><span class="cmdline">someone-not-present</span>
+<a name="l-13"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#chair </span><span class="cmdline">áccents</span>
+<a name="l-14"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#nick </span><span class="cmdline">áccenẗs</span>
+<a name="l-15"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#unchar </span><span class="cmdline">not-here</span>
+<a name="l-16"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="topic">#topic </span><span class="topicline">Test of all commands with different arguments</span>
+<a name="l-17"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="topic">#topic</span><span class="topicline"></span>
+<a name="l-18"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#idea</span><span class="cmdline"></span>
+<a name="l-19"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#info</span><span class="cmdline"></span>
+<a name="l-20"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#action</span><span class="cmdline"></span>
+<a name="l-21"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#agreed</span><span class="cmdline"></span>
+<a name="l-22"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#halp</span><span class="cmdline"></span>
+<a name="l-23"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#accepted</span><span class="cmdline"></span>
+<a name="l-24"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#rejected</span><span class="cmdline"></span>
+<a name="l-25"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="topic">#topic </span><span class="topicline">Commands with non-ascii</span>
+<a name="l-26"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="topic">#topic    </span><span class="topicline">üáç€</span>
+<a name="l-27"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#idea     </span><span class="cmdline">üáç€</span>
+<a name="l-28"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#info     </span><span class="cmdline">üáç€</span>
+<a name="l-29"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#action   </span><span class="cmdline">üáç€</span>
+<a name="l-30"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#agreed   </span><span class="cmdline">üáç€</span>
+<a name="l-31"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#halp     </span><span class="cmdline">üáç€</span>
+<a name="l-32"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#accepted </span><span class="cmdline">üáç€</span>
+<a name="l-33"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#rejected </span><span class="cmdline">üáç€</span>
+<a name="l-34"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#item </span><span class="cmdline">blah</span>
+<a name="l-35"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#idea </span><span class="cmdline">blah</span>
+<a name="l-36"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#action </span><span class="cmdline">blah</span>
+<a name="l-37"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#agreed </span><span class="cmdline">blah</span>
+<a name="l-38"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="topic">#topic </span><span class="topicline">Escapes</span>
+<a name="l-39"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#nick </span><span class="cmdline">&lt;b&gt;</span>
+<a name="l-40"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#nick </span><span class="cmdline">**</span>
+<a name="l-41"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#idea </span><span class="cmdline">blah_ blah_ ReST link reference...</span>
+<a name="l-42"></a><span class="tm">20:13:50</span><span class="nk"> &lt;ReST1_&gt;</span> <span class="cmd">#idea </span><span class="cmdline">blah blah blah</span>
+<a name="l-43"></a><span class="tm">20:13:50</span><span class="nk"> &lt;ReST2_&gt;</span> this is some text
+<a name="l-44"></a><span class="tm">20:13:50</span><span class="nk"> &lt;ReST2_&gt;</span> <span class="cmd">#idea </span><span class="cmdline">under_score</span>
+<a name="l-45"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Re_ST&gt;</span> <span class="cmd">#idea </span><span class="cmdline">under_score</span>
+<a name="l-46"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Re_ST&gt;</span> <span class="cmd">#idea </span><span class="cmdline">under1_1score</span>
+<a name="l-47"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Re_ST&gt;</span> <span class="cmd">#idea </span><span class="cmdline">under1_score</span>
+<a name="l-48"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Re_ST&gt;</span> <span class="cmd">#idea </span><span class="cmdline">under_1score</span>
+<a name="l-49"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Re_ST&gt;</span> <span class="cmd">#idea </span><span class="cmdline">under-_score</span>
+<a name="l-50"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Re_ST&gt;</span> <span class="cmd">#idea </span><span class="cmdline">under_-score</span>
+<a name="l-51"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="topic">#topic </span><span class="topicline">Links</span>
+<a name="l-52"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#link </span><span class="cmdline">http://test&lt;b&gt;.zgib.net</span>
+<a name="l-53"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#link </span><span class="cmdline">ftp://test&lt;b&gt;.zgib.net "</span>
+<a name="l-54"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#link </span><span class="cmdline">mailto://a@bla"h.com</span>
+<a name="l-55"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#link </span><span class="cmdline">http://test.zgib.net/&amp;testpage</span>
+<a name="l-56"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#link </span><span class="cmdline">prefix http://test.zgib.net/&amp;testpage suffix</span>
+<a name="l-57"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#link </span><span class="cmdline">prefix ftp://test.zg"ib.net/&amp;testpage suffix</span>
+<a name="l-58"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#link </span><span class="cmdline">prefix mailto://a@blah.com&amp;testpage suffix</span>
+<a name="l-59"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#link </span><span class="cmdline">prefix http://google.com/. suffix</span>
+<a name="l-60"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Utahraptor&gt;</span> <span class="cmd">#link </span><span class="cmdline">prefix (http://google.com/) suffix</span>
+<a name="l-61"></a><span class="tm">20:13:50</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="topic">#topic </span><span class="topicline">Character sets</span>
+<a name="l-62"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Üţáhraptõr&gt;</span> Nick with accents.
+<a name="l-63"></a><span class="tm">20:13:50</span><span class="nk"> &lt;Üţáhraptõr&gt;</span> <span class="cmd">#idea </span><span class="cmdline">Nick with accents.</span>
+<a name="l-64"></a><span class="tm">20:13:52</span><span class="nk"> &lt;MrBeige&gt;</span> <span class="cmd">#endmeeting</span><span class="cmdline"></span></pre>
+</body></html>

diff --git a/bot/tests/test-script-1.txt b/bot/tests/test-script-1.txt
new file mode 100644
index 0000000..0e279bb
--- /dev/null
+++ b/bot/tests/test-script-1.txt
@@ -0,0 +1,98 @@
+======================
+#test-script-1 Meeting
+======================
+
+
+Meeting started by MrBeige at 20:13:46 UTC.  The full logs are available
+at test-script-1.log.html .
+
+
+
+Meeting summary
+---------------
+
+* this command is just before the first topic  (T-Rex, 20:13:50)
+* General command tests  (MrBeige, 20:13:50)
+  * ACCEPTED: we will include this new format if we so choose.
+    (MrBeige, 20:13:50)
+  * REJECTED: we will not include this new format.  (MrBeige, 20:13:50)
+
+* Test of all commands with different arguments  (MrBeige, 20:13:50)
+
+*   (MrBeige, 20:13:50)
+  * IDEA:   (MrBeige, 20:13:50)
+  *   (MrBeige, 20:13:50)
+  * ACTION:   (MrBeige, 20:13:50)
+  * AGREED:   (MrBeige, 20:13:50)
+  * HELP:   (MrBeige, 20:13:50)
+  * ACCEPTED:   (MrBeige, 20:13:50)
+  * REJECTED:   (MrBeige, 20:13:50)
+
+* Commands with non-ascii  (MrBeige, 20:13:50)
+
+* üáç€  (MrBeige, 20:13:50)
+  * IDEA: üáç€  (MrBeige, 20:13:50)
+  * üáç€  (MrBeige, 20:13:50)
+  * ACTION: üáç€  (MrBeige, 20:13:50)
+  * AGREED: üáç€  (MrBeige, 20:13:50)
+  * HELP: üáç€  (MrBeige, 20:13:50)
+  * ACCEPTED: üáç€  (MrBeige, 20:13:50)
+  * REJECTED: üáç€  (MrBeige, 20:13:50)
+  * IDEA: blah  (MrBeige, 20:13:50)
+  * ACTION: blah  (MrBeige, 20:13:50)
+  * AGREED: blah  (Utahraptor, 20:13:50)
+
+* Escapes  (MrBeige, 20:13:50)
+  * IDEA: blah_ blah_ ReST link reference...  (Utahraptor, 20:13:50)
+  * IDEA: blah blah blah  (ReST1_, 20:13:50)
+  * IDEA: under_score  (ReST2_, 20:13:50)
+  * IDEA: under_score  (Re_ST, 20:13:50)
+  * IDEA: under1_1score  (Re_ST, 20:13:50)
+  * IDEA: under1_score  (Re_ST, 20:13:50)
+  * IDEA: under_1score  (Re_ST, 20:13:50)
+  * IDEA: under-_score  (Re_ST, 20:13:50)
+  * IDEA: under_-score  (Re_ST, 20:13:50)
+
+* Links  (MrBeige, 20:13:50)
+  * LINK: http://test<b>.zgib.net  (Utahraptor, 20:13:50)
+  * LINK: ftp://test<b>.zgib.net "  (Utahraptor, 20:13:50)
+  * LINK: mailto://a@bla"h.com  (Utahraptor, 20:13:50)
+  * LINK: http://test.zgib.net/&testpage  (Utahraptor, 20:13:50)
+  * LINK: prefix http://test.zgib.net/&testpage suffix  (Utahraptor,
+    20:13:50)
+  * LINK: prefix ftp://test.zg"ib.net/&testpage suffix  (Utahraptor,
+    20:13:50)
+  * LINK: prefix mailto://a@blah.com&testpage suffix  (Utahraptor,
+    20:13:50)
+  * LINK: prefix http://google.com/. suffix  (Utahraptor, 20:13:50)
+  * LINK: prefix (http://google.com/) suffix  (Utahraptor, 20:13:50)
+
+* Character sets  (MrBeige, 20:13:50)
+  * IDEA: Nick with accents.  (Üţáhraptõr, 20:13:50)
+
+
+
+Meeting ended at 20:13:52 UTC.
+
+
+
+People present (lines said)
+---------------------------
+
+* MrBeige (35)
+* Utahraptor (13)
+* Re_ST (6)
+* T-Rex (5)
+* ReST2_ (2)
+* Üţáhraptõr (2)
+* ReST1_ (1)
+* áccents (0)
+* not-here (0)
+* ** (0)
+* áccenẗs (0)
+* someone-not-present (0)
+* <b> (0)
+
+
+
+Generated by `MeetBot`_ 0.1.4
\ No newline at end of file



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/
@ 2011-06-18 15:46 Petteri Räty
  0 siblings, 0 replies; 12+ messages in thread
From: Petteri Räty @ 2011-06-18 15:46 UTC (permalink / raw
  To: gentoo-commits

commit:     e2ff317cf9c8832a98d805e7a04e1a2b3ed5520c
Author:     Joachim Filip Ignacy Bartosik <jbartosik <AT> gmail <DOT> com>
AuthorDate: Mon Jun 13 16:25:17 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Mon Jun 13 16:25:17 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/council-webapp.git;a=commit;h=e2ff317c

Make Meetbot tests cleaner, fix one bug found in the process

---
 bot/ircmeeting/agenda.py  |    2 +-
 bot/tests/run_test.py     |   56 +++++++++-------------------------------
 bot/tests/test_meeting.py |   61 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 75 insertions(+), 44 deletions(-)

diff --git a/bot/ircmeeting/agenda.py b/bot/ircmeeting/agenda.py
index 2269f6f..e3f456c 100644
--- a/bot/ircmeeting/agenda.py
+++ b/bot/ircmeeting/agenda.py
@@ -60,7 +60,7 @@ class Agenda(object):
     def end_vote(self):
         if self._vote_open:
             self._vote_open = False
-            return voting_already_closed_msg
+            return self.voting_already_closed_msg
         return voting_close_msg
 
     def get_data(self):

diff --git a/bot/tests/run_test.py b/bot/tests/run_test.py
index f304a2b..79bb9d7 100644
--- a/bot/tests/run_test.py
+++ b/bot/tests/run_test.py
@@ -7,19 +7,14 @@ import shutil
 import sys
 import tempfile
 import unittest
-import time
 
 os.environ['MEETBOT_RUNNING_TESTS'] = '1'
 import ircmeeting.meeting as meeting
 import ircmeeting.writers as writers
 
-running_tests = True
+import test_meeting
 
-def parse_time(time_):
-    try: return time.strptime(time_, "%H:%M:%S")
-    except ValueError: pass
-    try: return time.strptime(time_, "%H:%M")
-    except ValueError: pass
+running_tests = True
 
 def process_meeting(contents, extraConfig={}, dontSave=True,
                     filename='/dev/null'):
@@ -347,21 +342,13 @@ class MeetBotTest(unittest.TestCase):
     def test_agenda(self):
         """ Test agenda management
         """
-        logline_re = re.compile(r'\[?([0-9: ]*)\]? *<[@+]?([^>]+)> *(.*)')
-        loglineAction_re = re.compile(r'\[?([0-9: ]*)\]? *\* *([^ ]+) *(.*)')
-
-        M = process_meeting('#startmeeting')
-        log = []
-        M._sendReply = lambda x: log.append(x)
-        M.config.agenda._voters = ['x', 'z']
-        M.config.agenda._agenda = [['first item', ['opt1', 'opt2']], ['second item', []]]
-        M.config.agenda._votes = { }
-        for i in M.config.agenda._agenda:
-            M.config.agenda._votes[i[0]] = { }
-
 
-        M.starttime = time.gmtime(0)
-        contents = """20:13:50 <x> #nextitem
+        test = test_meeting.TestMeeting()
+        test.set_voters(['x', 'z'])
+        test.set_agenda([['first item', ['opt1', 'opt2']], ['second item', []]])
+        test.process("""
+        20:13:50 <x> #startmeeting
+        20:13:50 <x> #nextitem
         20:13:50 <x> #nextitem
         20:13:50 <x> #previtem
         20:13:50 <x> #previtem
@@ -371,27 +358,8 @@ class MeetBotTest(unittest.TestCase):
         20:13:50 <y> #vote 0
         20:13:50 <z> #vote 0
         20:13:50 <x> #endvote
-        20:13:50 <x> #endmeeting"""
-
-        for line in contents.split('\n'):
-            # match regular spoken lines:
-            m = logline_re.match(line)
-            if m:
-                time_ = parse_time(m.group(1).strip())
-                nick = m.group(2).strip()
-                line = m.group(3).strip()
-                if M.owner is None:
-                    M.owner = nick ; M.chairs = {nick:True}
-                M.addline(nick, line, time_=time_)
-            # match /me lines
-            m = loglineAction_re.match(line)
-            if m:
-                time_ = parse_time(m.group(1).strip())
-                nick = m.group(2).strip()
-                line = m.group(3).strip()
-                M.addline(nick, "ACTION "+line, time_=time_)
-
-        self.assert_(M.config.agenda._votes == {'first item': {u'x': 'opt2', u'z': 'opt1'}, 'second item': {}})
+        20:13:50 <x> #endmeeting""")
+
 
         answers = ['Current agenda item is second item.',
             'Current agenda item is second item.',
@@ -406,7 +374,9 @@ class MeetBotTest(unittest.TestCase):
             "You voted for #1 - ['opt1', 'opt2']",
             'You can not vote. Only x, z can vote',
             'You voted for #0 - first item']
-        self.assert_(log[0:len(answers)] == answers)
+
+        self.assert_(test.votes == {'first item': {u'x': 'opt2', u'z': 'opt1'}, 'second item': {}})
+        self.assert_(test.log[0:len(answers)] == answers)
 
 if __name__ == '__main__':
     os.chdir(os.path.join(os.path.dirname(__file__), '.'))

diff --git a/bot/tests/test_meeting.py b/bot/tests/test_meeting.py
new file mode 100644
index 0000000..9315b63
--- /dev/null
+++ b/bot/tests/test_meeting.py
@@ -0,0 +1,61 @@
+import ircmeeting.meeting as meeting
+import ircmeeting.writers as writers
+import re
+import time
+def process_meeting(contents, extraConfig={}, dontSave=True,
+                    filename='/dev/null'):
+    """Take a test script, return Meeting object of that meeting.
+
+    To access the results (a dict keyed by extensions), use M.save(),
+    with M being the return of this function.
+    """
+class TestMeeting:
+  logline_re = re.compile(r'\[?([0-9: ]*)\]? *<[@+]?([^>]+)> *(.*)')
+  loglineAction_re = re.compile(r'\[?([0-9: ]*)\]? *\* *([^ ]+) *(.*)')
+  M = meeting.process_meeting(contents = '',
+                                channel = "#none",  filename = '/dev/null',
+                                dontSave = True, safeMode = False,
+                                extraConfig = {})
+  log = []
+
+  def __init__(self):
+    self.M._sendReply = lambda x: self.log.append(x)
+    self.M.starttime = time.gmtime(0)
+
+  def set_voters(self, voters):
+    self.M.config.agenda._voters = voters
+
+  def set_agenda(self, agenda):
+    self.M.config.agenda._agenda = agenda
+    self.M.config.agenda._votes = { }
+    for i in agenda:
+      self.M.config.agenda._votes[i[0]] = { }
+
+
+  def parse_time(self, time_):
+    try: return time.strptime(time_, "%H:%M:%S")
+    except ValueError: pass
+    try: return time.strptime(time_, "%H:%M")
+    except ValueError: pass
+
+  def process(self, content):
+    for line in content.split('\n'):
+      # match regular spoken lines:
+      m = self.logline_re.match(line)
+      if m:
+        time_ = self.parse_time(m.group(1).strip())
+        nick = m.group(2).strip()
+        line = m.group(3).strip()
+        if self.M.owner is None:
+            self.M.owner = nick ; self.M.chairs = {nick:True}
+        self.M.addline(nick, line, time_=time_)
+      # match /me lines
+      self.m = self.loglineAction_re.match(line)
+      if m:
+          time_ = self.parse_time(m.group(1).strip())
+          nick = m.group(2).strip()
+          line = m.group(3).strip()
+          self.M.addline(nick, "ACTION "+line, time_=time_)
+
+  def votes(self):
+    return(self.M.config.agenda._votes)



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/
@ 2011-06-18 15:46 Petteri Räty
  0 siblings, 0 replies; 12+ messages in thread
From: Petteri Räty @ 2011-06-18 15:46 UTC (permalink / raw
  To: gentoo-commits

commit:     2460e74c1a09fe988017437bbebdc8c6e5e41694
Author:     Joachim Filip Ignacy Bartosik <jbartosik <AT> gmail <DOT> com>
AuthorDate: Thu Jun 16 14:31:05 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Thu Jun 16 15:06:46 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/council-webapp.git;a=commit;h=2460e74c

Add #option list command

---
 bot/ircmeeting/agenda.py  |   18 ++++++++++----
 bot/ircmeeting/meeting.py |    6 +++++
 bot/tests/run_test.py     |   55 ++++++++++++++++++++++++++++++++------------
 3 files changed, 59 insertions(+), 20 deletions(-)

diff --git a/bot/ircmeeting/agenda.py b/bot/ircmeeting/agenda.py
index cfecc61..32ddb9f 100644
--- a/bot/ircmeeting/agenda.py
+++ b/bot/ircmeeting/agenda.py
@@ -7,7 +7,7 @@ class Agenda(object):
     empty_agenda_msg = "Agenda is empty so I can't help you manage meeting (and voting)."
     current_item_msg = "Current agenda item is {}."
     voting_already_open_msg = "Voting is already open. You can end it with #endvote."
-    voting_open_msg = "Voting started. Your choices are:{}Vote #vote <option number>.\nEnd voting with #endvote."
+    voting_open_msg = "Voting started. {}Vote #vote <option number>.\nEnd voting with #endvote."
     voting_close_msg = "Voting closed."
     voting_already_closed_msg = "Voting is already closed. You can start it with #startvote."
     voting_open_so_item_not_changed_msg = "Voting is currently open so I didn't change item. Please #endvote first"
@@ -60,10 +60,7 @@ class Agenda(object):
         if self._vote_open:
             return self.voting_already_open_msg
         self._vote_open = True
-        options = "\n"
-        for i in range(len(self._agenda[self._current_item][1])):
-            options += str.format("{}. {}\n", i, self._agenda[self._current_item][1][i])
-        return str.format(self.voting_open_msg, options)
+        return str.format(self.voting_open_msg, self.options())
 
     def end_vote(self):
         if not self.conf.manage_agenda:
@@ -104,6 +101,17 @@ class Agenda(object):
         result = json.loads(str)
         return result
 
+    def options(self):
+        options_list = self._agenda[self._current_item][1]
+        n = len(options_list)
+        if n == 0:
+          return 'No voting options available.'
+        else:
+          options = "Available voting options are:\n"
+          for i in range(n):
+              options += str.format("{}. {}\n", i, options_list[i])
+          return options
+
     def post_result(self):
         if not self.conf.manage_agenda:
           return('')

diff --git a/bot/ircmeeting/meeting.py b/bot/ircmeeting/meeting.py
index 26138a2..d8589c4 100644
--- a/bot/ircmeeting/meeting.py
+++ b/bot/ircmeeting/meeting.py
@@ -340,6 +340,12 @@ class MeetingCommands(object):
         for messageline in self.config.agenda.vote(nick, line).split('\n'):
             self.reply(messageline)
 
+    def do_option(self, nick, time_, line, **kwargs):
+        if re.match( ' *?list', line):
+          result = self.config.agenda.options()
+        for messageline in result.split('\n'):
+            self.reply(messageline)
+
     def do_endmeeting(self, nick, time_, **kwargs):
         """End the meeting."""
         if not self.isChair(nick): return

diff --git a/bot/tests/run_test.py b/bot/tests/run_test.py
index 2b6c6f3..c28f1ae 100644
--- a/bot/tests/run_test.py
+++ b/bot/tests/run_test.py
@@ -339,40 +339,65 @@ class MeetBotTest(unittest.TestCase):
         assert M.config.filename().endswith('somechannel-blah1234'),\
                "Filename not as expected: "+M.config.filename()
 
-    def test_agenda(self):
-        """ Test agenda management
-        """
-
+    def get_simple_agenda_test(self):
         test = test_meeting.TestMeeting()
         test.set_voters(['x', 'z'])
         test.set_agenda([['first item', ['opt1', 'opt2']], ['second item', []]])
+        test.M.config.manage_agenda = False
 
-
-        # Test starting meeting. Enable agenda management after that
         test.answer_should_match("20:13:50 <x> #startmeeting",
         "Meeting started .*\nUseful Commands: #action #agreed #help #info #idea #link #topic.\n")
         test.M.config.manage_agenda = True
 
-        # Test moving through items
+        return(test)
+
+    def test_agenda_item_changing(self):
+        test = self.get_simple_agenda_test()
+
+        # Test changing item before vote
         test.answer_should_match('20:13:50 <x> #nextitem', 'Current agenda item is second item.')
         test.answer_should_match('20:13:50 <x> #nextitem', 'Current agenda item is second item.')
         test.answer_should_match('20:13:50 <x> #previtem', 'Current agenda item is first item.')
         test.answer_should_match('20:13:50 <x> #previtem', 'Current agenda item is first item.')
 
-        # Test voting
+        # Test changing item during vote
+        test.process('20:13:50 <x> #startvote')
+        test.answer_should_match('20:13:50 <x> #nextitem', 'Voting is currently ' +\
+                                  'open so I didn\'t change item. Please #endvote first')
+        test.answer_should_match('20:13:50 <x> #previtem', 'Voting is currently ' +\
+                                  'open so I didn\'t change item. Please #endvote first')
+
+        # Test changing item after vote
+        test.process('20:13:50 <x> #endvote')
+        test.answer_should_match('20:13:50 <x> #nextitem', 'Current agenda item is second item.')
+        test.answer_should_match('20:13:50 <x> #nextitem', 'Current agenda item is second item.')
+        test.answer_should_match('20:13:50 <x> #previtem', 'Current agenda item is first item.')
+        test.answer_should_match('20:13:50 <x> #previtem', 'Current agenda item is first item.')
+
+    def test_agenda_option_listing(self):
+        test = self.get_simple_agenda_test()
+
+        test.answer_should_match('20:13:50 <x> #option list', 'Available voting options ' +\
+                                  'are:\n0. opt1\n1. opt2\n')
+        test.process('20:13:50 <x> #nextitem')
+        test.answer_should_match('20:13:50 <x> #option list', 'No voting options available.')
+        test.process('20:13:50 <x> #previtem')
+        test.answer_should_match('20:13:50 <x> #option list', 'Available voting options ' +\
+                                  'are:\n0. opt1\n1. opt2\n')
+
+    def test_agenda_voting(self):
+        test = self.get_simple_agenda_test()
         test.answer_should_match('20:13:50 <x> #startvote', 'Voting started\. ' +\
-                                  'Your choices are:\n0. opt1\n1. opt2\nVote ' +\
+                                  'Available voting options are:\n0. opt1\n1. opt2\nVote ' +\
                                   '#vote <option number>.\nEnd voting with #endvote.')
         test.answer_should_match('20:13:50 <x> #startvote', 'Voting is already open. ' +\
                                   'You can end it with #endvote.')
         test.answer_should_match('20:13:50 <x> #vote 10', 'Your vote was out of range\!')
-        test.answer_should_match('20:13:50 <x> #vote 1', 'You voted for #1 - opt2')
         test.answer_should_match('20:13:50 <x> #vote 0', 'You voted for #0 - opt1')
-        test.answer_should_match('20:13:50 <x> #vote 0', 'You voted for #0 - opt1')
-        test.answer_should_match('20:13:50 <x> #nextitem', 'Voting is currently ' +\
-                                  'open so I didn\'t change item. Please #endvote first')
-        test.answer_should_match('20:13:50 <x> #previtem', 'Voting is currently ' +\
-                                  'open so I didn\'t change item. Please #endvote first')
+        test.answer_should_match('20:13:50 <x> #vote 1', 'You voted for #1 - opt2')
+        test.answer_should_match('20:13:50 <z> #vote 0', 'You voted for #0 - opt1')
+        test.answer_should_match('20:13:50 <x> #option list', 'Available voting options ' +\
+                                  'are:\n0. opt1\n1. opt2\n')
         test.answer_should_match('20:13:50 <x> #endvote', 'Voting closed.')
         test.answer_should_match('20:13:50 <x> #endvote', 'Voting is already closed. ' +\
                                   'You can start it with #startvote.')



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/
@ 2011-06-18 15:46 Petteri Räty
  0 siblings, 0 replies; 12+ messages in thread
From: Petteri Räty @ 2011-06-18 15:46 UTC (permalink / raw
  To: gentoo-commits

commit:     9ccab32b9a8bd934555158115db64a25a266fb53
Author:     Joachim Filip Ignacy Bartosik <jbartosik <AT> gmail <DOT> com>
AuthorDate: Tue Jun 14 14:21:31 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Tue Jun 14 16:45:39 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/council-webapp.git;a=commit;h=9ccab32b

Improve Supybot tests, fix bugs found in the process

---
 bot/ircmeeting/agenda.py  |   12 ++++----
 bot/tests/run_test.py     |   68 +++++++++++++++++++++++---------------------
 bot/tests/test_meeting.py |   16 ++++++----
 3 files changed, 51 insertions(+), 45 deletions(-)

diff --git a/bot/ircmeeting/agenda.py b/bot/ircmeeting/agenda.py
index 247907b..cfecc61 100644
--- a/bot/ircmeeting/agenda.py
+++ b/bot/ircmeeting/agenda.py
@@ -7,8 +7,8 @@ class Agenda(object):
     empty_agenda_msg = "Agenda is empty so I can't help you manage meeting (and voting)."
     current_item_msg = "Current agenda item is {}."
     voting_already_open_msg = "Voting is already open. You can end it with #endvote."
-    voting_open_msg = "Voting started. Your choices are: {} Vote #vote <option number>.\n End voting with #endvote."
-    voting_close_msg = "Voting is closed."
+    voting_open_msg = "Voting started. Your choices are:{}Vote #vote <option number>.\nEnd voting with #endvote."
+    voting_close_msg = "Voting closed."
     voting_already_closed_msg = "Voting is already closed. You can start it with #startvote."
     voting_open_so_item_not_changed_msg = "Voting is currently open so I didn't change item. Please #endvote first"
     can_not_vote_msg = "You can not vote. Only {} can vote"
@@ -38,7 +38,7 @@ class Agenda(object):
         if not self.conf.manage_agenda:
           return('')
         if self._vote_open:
-            return voting_open_so_item_not_changed_msg
+            return self.voting_open_so_item_not_changed_msg
         else:
             if (self._current_item + 1) < len(self._agenda):
                 self._current_item += 1
@@ -48,7 +48,7 @@ class Agenda(object):
         if not self.conf.manage_agenda:
           return('')
         if self._vote_open:
-            return voting_open_so_item_not_changed_msg
+            return self.voting_open_so_item_not_changed_msg
         else:
             if self._current_item > 0:
                 self._current_item -= 1
@@ -70,8 +70,8 @@ class Agenda(object):
           return('')
         if self._vote_open:
             self._vote_open = False
-            return self.voting_already_closed_msg
-        return voting_close_msg
+            return self.voting_close_msg
+        return self.voting_already_closed_msg
 
     def get_data(self):
         if not self.conf.manage_agenda:

diff --git a/bot/tests/run_test.py b/bot/tests/run_test.py
index f4e6e49..2b6c6f3 100644
--- a/bot/tests/run_test.py
+++ b/bot/tests/run_test.py
@@ -344,40 +344,44 @@ class MeetBotTest(unittest.TestCase):
         """
 
         test = test_meeting.TestMeeting()
-        test.M.config.manage_agenda = True
         test.set_voters(['x', 'z'])
         test.set_agenda([['first item', ['opt1', 'opt2']], ['second item', []]])
-        test.process("""
-        20:13:50 <x> #startmeeting
-        20:13:50 <x> #nextitem
-        20:13:50 <x> #nextitem
-        20:13:50 <x> #previtem
-        20:13:50 <x> #previtem
-        20:13:50 <x> #startvote
-        20:13:50 <x> #vote 10
-        20:13:50 <x> #vote 1
-        20:13:50 <y> #vote 0
-        20:13:50 <z> #vote 0
-        20:13:50 <x> #endvote
-        20:13:50 <x> #endmeeting""")
-
-
-        answers = ['Current agenda item is second item.',
-            'Current agenda item is second item.',
-            'Current agenda item is first item.',
-            'Current agenda item is first item.',
-            'Voting started. Your choices are: ',
-            '0. first item',
-            "1. ['opt1', 'opt2']",
-            ' Vote #vote <option number>.',
-            ' End voting with #endvote.',
-            'Your vote was out of range!',
-            "You voted for #1 - ['opt1', 'opt2']",
-            'You can not vote. Only x, z can vote',
-            'You voted for #0 - first item']
-
-        self.assert_(test.votes == {'first item': {u'x': 'opt2', u'z': 'opt1'}, 'second item': {}})
-        self.assert_(test.log[0:len(answers)] == answers)
+
+
+        # Test starting meeting. Enable agenda management after that
+        test.answer_should_match("20:13:50 <x> #startmeeting",
+        "Meeting started .*\nUseful Commands: #action #agreed #help #info #idea #link #topic.\n")
+        test.M.config.manage_agenda = True
+
+        # Test moving through items
+        test.answer_should_match('20:13:50 <x> #nextitem', 'Current agenda item is second item.')
+        test.answer_should_match('20:13:50 <x> #nextitem', 'Current agenda item is second item.')
+        test.answer_should_match('20:13:50 <x> #previtem', 'Current agenda item is first item.')
+        test.answer_should_match('20:13:50 <x> #previtem', 'Current agenda item is first item.')
+
+        # Test voting
+        test.answer_should_match('20:13:50 <x> #startvote', 'Voting started\. ' +\
+                                  'Your choices are:\n0. opt1\n1. opt2\nVote ' +\
+                                  '#vote <option number>.\nEnd voting with #endvote.')
+        test.answer_should_match('20:13:50 <x> #startvote', 'Voting is already open. ' +\
+                                  'You can end it with #endvote.')
+        test.answer_should_match('20:13:50 <x> #vote 10', 'Your vote was out of range\!')
+        test.answer_should_match('20:13:50 <x> #vote 1', 'You voted for #1 - opt2')
+        test.answer_should_match('20:13:50 <x> #vote 0', 'You voted for #0 - opt1')
+        test.answer_should_match('20:13:50 <x> #vote 0', 'You voted for #0 - opt1')
+        test.answer_should_match('20:13:50 <x> #nextitem', 'Voting is currently ' +\
+                                  'open so I didn\'t change item. Please #endvote first')
+        test.answer_should_match('20:13:50 <x> #previtem', 'Voting is currently ' +\
+                                  'open so I didn\'t change item. Please #endvote first')
+        test.answer_should_match('20:13:50 <x> #endvote', 'Voting closed.')
+        test.answer_should_match('20:13:50 <x> #endvote', 'Voting is already closed. ' +\
+                                  'You can start it with #startvote.')
+
+        test.M.config.manage_agenda = False
+        test.answer_should_match('20:13:50 <x> #endmeeting', 'Meeting ended ' +\
+                                  '.*\nMinutes:.*\nMinutes \(text\):.*\nLog:.*')
+
+        assert(test.votes() == {'first item': {u'x': 'opt2', u'z': 'opt1'}, 'second item': {}})
 
 if __name__ == '__main__':
     os.chdir(os.path.join(os.path.dirname(__file__), '.'))

diff --git a/bot/tests/test_meeting.py b/bot/tests/test_meeting.py
index 9315b63..78bd2dc 100644
--- a/bot/tests/test_meeting.py
+++ b/bot/tests/test_meeting.py
@@ -2,13 +2,6 @@ import ircmeeting.meeting as meeting
 import ircmeeting.writers as writers
 import re
 import time
-def process_meeting(contents, extraConfig={}, dontSave=True,
-                    filename='/dev/null'):
-    """Take a test script, return Meeting object of that meeting.
-
-    To access the results (a dict keyed by extensions), use M.save(),
-    with M being the return of this function.
-    """
 class TestMeeting:
   logline_re = re.compile(r'\[?([0-9: ]*)\]? *<[@+]?([^>]+)> *(.*)')
   loglineAction_re = re.compile(r'\[?([0-9: ]*)\]? *\* *([^ ]+) *(.*)')
@@ -57,5 +50,14 @@ class TestMeeting:
           line = m.group(3).strip()
           self.M.addline(nick, "ACTION "+line, time_=time_)
 
+  def answer_should_match(self, line, answer_regexp):
+    self.log = []
+    self.process(line)
+    answer = '\n'.join(self.log)
+    error_msg = "Answer for:\n\t'" + line + "'\n was \n\t'" + answer +\
+                "'\ndid not match regexp\n\t'" + answer_regexp + "'"
+    answer_matches = re.match(answer_regexp, answer)
+    assert answer_matches, error_msg
+
   def votes(self):
     return(self.M.config.agenda._votes)



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/
@ 2011-06-18 15:46 Petteri Räty
  0 siblings, 0 replies; 12+ messages in thread
From: Petteri Räty @ 2011-06-18 15:46 UTC (permalink / raw
  To: gentoo-commits

commit:     758c16c3424aa59c173ccad7ca2c311f1d817001
Author:     Joachim Filip Ignacy Bartosik <jbartosik <AT> gmail <DOT> com>
AuthorDate: Tue Jun 14 12:13:03 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Tue Jun 14 12:13:03 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/council-webapp.git;a=commit;h=758c16c3

Disable agenda management by default

Reasons:
 * Users may not want it, so they should be able to turn it off
 * Tests don't fail when localhost:3000 is unreachable
 * Make tests faster.

---
 bot/ircmeeting/agenda.py  |   16 ++++++++++++++++
 bot/ircmeeting/meeting.py |    1 +
 bot/tests/run_test.py     |    1 +
 3 files changed, 18 insertions(+), 0 deletions(-)

diff --git a/bot/ircmeeting/agenda.py b/bot/ircmeeting/agenda.py
index e3f456c..247907b 100644
--- a/bot/ircmeeting/agenda.py
+++ b/bot/ircmeeting/agenda.py
@@ -27,12 +27,16 @@ class Agenda(object):
       self.conf = conf
 
     def get_agenda_item(self):
+        if not self.conf.manage_agenda:
+          return('')
         if self._current_item < len(self._agenda):
             return str.format(self.current_item_msg, self._agenda[self._current_item][0])
         else:
             return self.empty_agenda_msg
 
     def next_agenda_item(self):
+        if not self.conf.manage_agenda:
+          return('')
         if self._vote_open:
             return voting_open_so_item_not_changed_msg
         else:
@@ -41,6 +45,8 @@ class Agenda(object):
             return(self.get_agenda_item())
 
     def prev_agenda_item(self):
+        if not self.conf.manage_agenda:
+          return('')
         if self._vote_open:
             return voting_open_so_item_not_changed_msg
         else:
@@ -49,6 +55,8 @@ class Agenda(object):
             return(self.get_agenda_item())
 
     def start_vote(self):
+        if not self.conf.manage_agenda:
+          return('')
         if self._vote_open:
             return self.voting_already_open_msg
         self._vote_open = True
@@ -58,12 +66,16 @@ class Agenda(object):
         return str.format(self.voting_open_msg, options)
 
     def end_vote(self):
+        if not self.conf.manage_agenda:
+          return('')
         if self._vote_open:
             self._vote_open = False
             return self.voting_already_closed_msg
         return voting_close_msg
 
     def get_data(self):
+        if not self.conf.manage_agenda:
+          return('')
         self._voters = self._get_json(self.conf.voters_url)
         self._agenda = self._get_json(self.conf.agenda_url)
         self._votes = { }
@@ -71,6 +83,8 @@ class Agenda(object):
             self._votes[i[0]] = { }
 
     def vote(self, nick, line):
+        if not self.conf.manage_agenda:
+          return('')
         if not nick in self._voters:
             return str.format(self.can_not_vote_msg, ", ".join(self._voters))
         if not line.isdigit():
@@ -91,6 +105,8 @@ class Agenda(object):
         return result
 
     def post_result(self):
+        if not self.conf.manage_agenda:
+          return('')
         data = urllib.quote(json.dumps([self._votes]))
         result_url = str.format(self.conf.result_url,
                       self.conf.voting_results_user,

diff --git a/bot/ircmeeting/meeting.py b/bot/ircmeeting/meeting.py
index 108ae1d..26138a2 100644
--- a/bot/ircmeeting/meeting.py
+++ b/bot/ircmeeting/meeting.py
@@ -105,6 +105,7 @@ class Config(object):
     # Credentials for posting voting results
     voting_results_user = 'user'
     voting_results_password = 'password'
+    manage_agenda = False
 
     def enc(self, text):
         return text.encode(self.output_codec, 'replace')

diff --git a/bot/tests/run_test.py b/bot/tests/run_test.py
index 79bb9d7..f4e6e49 100644
--- a/bot/tests/run_test.py
+++ b/bot/tests/run_test.py
@@ -344,6 +344,7 @@ class MeetBotTest(unittest.TestCase):
         """
 
         test = test_meeting.TestMeeting()
+        test.M.config.manage_agenda = True
         test.set_voters(['x', 'z'])
         test.set_agenda([['first item', ['opt1', 'opt2']], ['second item', []]])
         test.process("""



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/
@ 2011-06-18 15:46 Petteri Räty
  0 siblings, 0 replies; 12+ messages in thread
From: Petteri Räty @ 2011-06-18 15:46 UTC (permalink / raw
  To: gentoo-commits

commit:     55cfc31254373f2618a17f73e2923b2503514ecb
Author:     Joachim Filip Ignacy Bartosik <jbartosik <AT> gmail <DOT> com>
AuthorDate: Thu Jun 16 15:36:01 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Thu Jun 16 15:36:01 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/council-webapp.git;a=commit;h=55cfc312

Add '#option add' command to MeetBot

---
 bot/ircmeeting/agenda.py  |   15 ++++++++++++++-
 bot/ircmeeting/meeting.py |    2 ++
 bot/tests/run_test.py     |   10 ++++++++++
 3 files changed, 26 insertions(+), 1 deletions(-)

diff --git a/bot/ircmeeting/agenda.py b/bot/ircmeeting/agenda.py
index 32ddb9f..97bcfcf 100644
--- a/bot/ircmeeting/agenda.py
+++ b/bot/ircmeeting/agenda.py
@@ -1,9 +1,11 @@
 import json
 import urllib
+import re
 
 class Agenda(object):
 
     # Messages
+    added_option_msg = "You added new voting option: {}"
     empty_agenda_msg = "Agenda is empty so I can't help you manage meeting (and voting)."
     current_item_msg = "Current agenda item is {}."
     voting_already_open_msg = "Voting is already open. You can end it with #endvote."
@@ -11,7 +13,7 @@ class Agenda(object):
     voting_close_msg = "Voting closed."
     voting_already_closed_msg = "Voting is already closed. You can start it with #startvote."
     voting_open_so_item_not_changed_msg = "Voting is currently open so I didn't change item. Please #endvote first"
-    can_not_vote_msg = "You can not vote. Only {} can vote"
+    can_not_vote_msg = "You can not vote or change agenda. Only {} can."
     not_a_number_msg = "Your vote was not recognized as a number. Please retry."
     out_of_range_msg = "Your vote was out of range!"
     vote_confirm_msg = "You voted for #{} - {}"
@@ -111,6 +113,17 @@ class Agenda(object):
           for i in range(n):
               options += str.format("{}. {}\n", i, options_list[i])
           return options
+    def add_option(self, nick, line):
+        if not self.conf.manage_agenda:
+            return('')
+        if not nick in self._voters:
+            return str.format(self.can_not_vote_msg, ", ".join(self._voters))
+        options_list = self._agenda[self._current_item][1]
+        option_text = re.match( ' *?add (.*)', line).group(1)
+        options_list.append(option_text)
+        return str.format(self.added_option_msg, option_text)
+
+
 
     def post_result(self):
         if not self.conf.manage_agenda:

diff --git a/bot/ircmeeting/meeting.py b/bot/ircmeeting/meeting.py
index d8589c4..f9c907b 100644
--- a/bot/ircmeeting/meeting.py
+++ b/bot/ircmeeting/meeting.py
@@ -343,6 +343,8 @@ class MeetingCommands(object):
     def do_option(self, nick, time_, line, **kwargs):
         if re.match( ' *?list', line):
           result = self.config.agenda.options()
+        elif re.match( ' *?add .*', line):
+          result = self.config.agenda.add_option(nick, line)
         for messageline in result.split('\n'):
             self.reply(messageline)
 

diff --git a/bot/tests/run_test.py b/bot/tests/run_test.py
index c28f1ae..a80e6ec 100644
--- a/bot/tests/run_test.py
+++ b/bot/tests/run_test.py
@@ -385,6 +385,16 @@ class MeetBotTest(unittest.TestCase):
         test.answer_should_match('20:13:50 <x> #option list', 'Available voting options ' +\
                                   'are:\n0. opt1\n1. opt2\n')
 
+    def test_agenda_option_adding(self):
+        test = self.get_simple_agenda_test()
+        test.process('20:13:50 <x> #nextitem')
+        test.answer_should_match('20:13:50 <not_allowed> #option add first option',
+                                  'You can not vote or change agenda. Only x, z can.')
+        test.answer_should_match('20:13:50 <x> #option add first option',
+                                  'You added new voting option: first option')
+        test.answer_should_match('20:13:50 <x> #option list', 'Available voting options ' +\
+                                  'are:\n0. first option')
+
     def test_agenda_voting(self):
         test = self.get_simple_agenda_test()
         test.answer_should_match('20:13:50 <x> #startvote', 'Voting started\. ' +\



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/
@ 2011-06-18 15:46 Petteri Räty
  0 siblings, 0 replies; 12+ messages in thread
From: Petteri Räty @ 2011-06-18 15:46 UTC (permalink / raw
  To: gentoo-commits

commit:     d7fcb9289fb9403db1c646b4205117d1ba66acfe
Author:     Joachim Filip Ignacy Bartosik <jbartosik <AT> gmail <DOT> com>
AuthorDate: Fri Jun 17 12:06:25 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Fri Jun 17 12:06:25 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/council-webapp.git;a=commit;h=d7fcb928

Add '#option remove' command to MeetBot

---
 bot/ircmeeting/agenda.py  |   31 +++++++++++++++++++++++++------
 bot/ircmeeting/meeting.py |    2 ++
 bot/tests/run_test.py     |    9 +++++++++
 3 files changed, 36 insertions(+), 6 deletions(-)

diff --git a/bot/ircmeeting/agenda.py b/bot/ircmeeting/agenda.py
index 97bcfcf..928ff5f 100644
--- a/bot/ircmeeting/agenda.py
+++ b/bot/ircmeeting/agenda.py
@@ -8,6 +8,7 @@ class Agenda(object):
     added_option_msg = "You added new voting option: {}"
     empty_agenda_msg = "Agenda is empty so I can't help you manage meeting (and voting)."
     current_item_msg = "Current agenda item is {}."
+    removed_option_msg = "You removed voting option {}: {}"
     voting_already_open_msg = "Voting is already open. You can end it with #endvote."
     voting_open_msg = "Voting started. {}Vote #vote <option number>.\nEnd voting with #endvote."
     voting_close_msg = "Voting closed."
@@ -86,13 +87,10 @@ class Agenda(object):
           return('')
         if not nick in self._voters:
             return str.format(self.can_not_vote_msg, ", ".join(self._voters))
-        if not line.isdigit():
-            return self.not_a_number_msg
 
-        opt = int(line)
-
-        if opt < 0 or opt >= len(self._agenda[self._current_item][1]):
-            return self.out_of_range_msg
+        opt = self._to_voting_option_number(line)
+        if opt.__class__ is not int:
+          return(opt)
 
         self._votes[self._agenda[self._current_item][0]][nick] = self._agenda[self._current_item][1][opt]
         return str.format(self.vote_confirm_msg, opt, self._agenda[self._current_item][1][opt])
@@ -103,6 +101,14 @@ class Agenda(object):
         result = json.loads(str)
         return result
 
+    def _to_voting_option_number(self, line):
+        if not line.isdigit():
+            return self.not_a_number_msg
+        opt = int(line)
+        if opt < 0 or opt >= len(self._agenda[self._current_item][1]):
+            return self.out_of_range_msg
+        return(opt)
+
     def options(self):
         options_list = self._agenda[self._current_item][1]
         n = len(options_list)
@@ -113,6 +119,7 @@ class Agenda(object):
           for i in range(n):
               options += str.format("{}. {}\n", i, options_list[i])
           return options
+
     def add_option(self, nick, line):
         if not self.conf.manage_agenda:
             return('')
@@ -123,7 +130,19 @@ class Agenda(object):
         options_list.append(option_text)
         return str.format(self.added_option_msg, option_text)
 
+    def remove_option(self, nick, line):
+        if not self.conf.manage_agenda:
+            return('')
+        if not nick in self._voters:
+            return str.format(self.can_not_vote_msg, ", ".join(self._voters))
+
+        opt_str = re.match( ' *?remove (.*)', line).group(1)
+        opt = self._to_voting_option_number(opt_str)
+        if opt.__class__ is not int:
+          return(opt)
 
+        option = self._agenda[self._current_item][1].pop(opt)
+        return str.format(self.removed_option_msg, str(opt), option)
 
     def post_result(self):
         if not self.conf.manage_agenda:

diff --git a/bot/ircmeeting/meeting.py b/bot/ircmeeting/meeting.py
index f9c907b..84949ed 100644
--- a/bot/ircmeeting/meeting.py
+++ b/bot/ircmeeting/meeting.py
@@ -345,6 +345,8 @@ class MeetingCommands(object):
           result = self.config.agenda.options()
         elif re.match( ' *?add .*', line):
           result = self.config.agenda.add_option(nick, line)
+        elif re.match( ' *?remove .*', line):
+          result = self.config.agenda.remove_option(nick, line)
         for messageline in result.split('\n'):
             self.reply(messageline)
 

diff --git a/bot/tests/run_test.py b/bot/tests/run_test.py
index a80e6ec..9808ee6 100644
--- a/bot/tests/run_test.py
+++ b/bot/tests/run_test.py
@@ -395,6 +395,15 @@ class MeetBotTest(unittest.TestCase):
         test.answer_should_match('20:13:50 <x> #option list', 'Available voting options ' +\
                                   'are:\n0. first option')
 
+    def test_agenda_option_removing(self):
+        test = self.get_simple_agenda_test()
+        test.answer_should_match('20:13:50 <not_allowed> #option remove 1',
+                                  'You can not vote or change agenda. Only x, z can.')
+        test.answer_should_match('20:13:50 <x> #option remove 1',
+                                  'You removed voting option 1: opt2')
+        test.answer_should_match('20:13:50 <x> #option list', 'Available voting options ' +\
+                                  'are:\n0. opt1')
+
     def test_agenda_voting(self):
         test = self.get_simple_agenda_test()
         test.answer_should_match('20:13:50 <x> #startvote', 'Voting started\. ' +\



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/
@ 2011-06-22  7:59 Petteri Räty
  0 siblings, 0 replies; 12+ messages in thread
From: Petteri Räty @ 2011-06-22  7:59 UTC (permalink / raw
  To: gentoo-commits

commit:     bc787b2518ac4fedcffaaf24e14f04839c3d7d3a
Author:     Joachim Filip Ignacy Bartosik <jbartosik <AT> gmail <DOT> com>
AuthorDate: Mon Jun 20 16:58:30 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Wed Jun 22 07:22:05 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/council-webapp.git;a=commit;h=bc787b25

Add #changeitem <no> command to MeetBot

---
 bot/ircmeeting/agenda.py  |   25 +++++++++++++++++++++----
 bot/ircmeeting/meeting.py |    3 +++
 bot/tests/run_test.py     |   20 ++++++++++++++------
 3 files changed, 38 insertions(+), 10 deletions(-)

diff --git a/bot/ircmeeting/agenda.py b/bot/ircmeeting/agenda.py
index 775dfd9..af03c3a 100644
--- a/bot/ircmeeting/agenda.py
+++ b/bot/ircmeeting/agenda.py
@@ -15,8 +15,8 @@ class Agenda(object):
     voting_already_closed_msg = "Voting is already closed. You can start it with #startvote."
     voting_open_so_item_not_changed_msg = "Voting is currently open so I didn't change item. Please #endvote first"
     can_not_vote_msg = "You can not vote or change agenda. Only {} can."
-    not_a_number_msg = "Your vote was not recognized as a number. Please retry."
-    out_of_range_msg = "Your vote was out of range!"
+    not_a_number_msg = "Your choice was not recognized as a number. Please retry."
+    out_of_range_msg = "Your choice was out of range!"
     vote_confirm_msg = "You voted for #{} - {}"
 
     # Internal
@@ -109,14 +109,20 @@ class Agenda(object):
         result = json.loads(str)
         return result
 
-    def _to_voting_option_number(self, line):
+    def _to_number(self, line, upper_limit):
         if not line.isdigit():
             return self.not_a_number_msg
         opt = int(line)
-        if opt < 0 or opt >= len(self._agenda[self._current_item][1]):
+        if opt < 0 or opt >= upper_limit:
             return self.out_of_range_msg
         return(opt)
 
+    def _to_voting_option_number(self, line):
+        return(self._to_number(line, len(self._agenda[self._current_item][1])))
+
+    def _to_agenda_item_number(self, line):
+        return(self._to_number(line, len(self._agenda)))
+
     def options(self):
         options_list = self._agenda[self._current_item][1]
         n = len(options_list)
@@ -138,6 +144,17 @@ class Agenda(object):
         options_list.append(option_text)
         return str.format(self.added_option_msg, option_text)
 
+    def change_agenda_item(self, line):
+        if not self.conf.manage_agenda:
+          return('')
+        if self._vote_open:
+            return self.voting_open_so_item_not_changed_msg
+        opt = self._to_agenda_item_number(line)
+        if opt.__class__ is not int:
+          return(opt)
+        self._current_item = opt
+        return(self.get_agenda_item())
+
     def remove_option(self, nick, line):
         if not self.conf.manage_agenda:
             return('')

diff --git a/bot/ircmeeting/meeting.py b/bot/ircmeeting/meeting.py
index 84949ed..c01176a 100644
--- a/bot/ircmeeting/meeting.py
+++ b/bot/ircmeeting/meeting.py
@@ -328,6 +328,9 @@ class MeetingCommands(object):
     def do_previtem(self, nick, time_, line, **kwargs):
         self.reply(self.config.agenda.prev_agenda_item())
 
+    def do_changeitem(self, nick, time_, line, **kwargs):
+        self.reply(self.config.agenda.change_agenda_item(line))
+
     def do_startvote(self, nick, time_, line, **kwargs):
        for messageline in self.config.agenda.start_vote().split('\n'):
             self.reply(messageline)

diff --git a/bot/tests/run_test.py b/bot/tests/run_test.py
index 3c43fef..1358d47 100644
--- a/bot/tests/run_test.py
+++ b/bot/tests/run_test.py
@@ -342,7 +342,7 @@ class MeetBotTest(unittest.TestCase):
     def get_simple_agenda_test(self):
         test = test_meeting.TestMeeting()
         test.set_voters(['x', 'z'])
-        test.set_agenda([['first item', ['opt1', 'opt2']], ['second item', []]])
+        test.set_agenda([['first item', ['opt1', 'opt2']], ['second item', []], ['third item', []]])
         test.M.config.manage_agenda = False
 
         test.answer_should_match("20:13:50 <x> #startmeeting",
@@ -356,9 +356,16 @@ class MeetBotTest(unittest.TestCase):
 
         # Test changing item before vote
         test.answer_should_match('20:13:50 <x> #nextitem', 'Current agenda item is second item.')
-        test.answer_should_match('20:13:50 <x> #nextitem', 'Current agenda item is second item.')
+        test.answer_should_match('20:13:50 <x> #nextitem', 'Current agenda item is third item.')
+        test.answer_should_match('20:13:50 <x> #nextitem', 'Current agenda item is third item.')
+        test.answer_should_match('20:13:50 <x> #previtem', 'Current agenda item is second item.')
         test.answer_should_match('20:13:50 <x> #previtem', 'Current agenda item is first item.')
         test.answer_should_match('20:13:50 <x> #previtem', 'Current agenda item is first item.')
+        test.answer_should_match('20:13:50 <x> #changeitem 2', 'Current agenda item is third item.')
+        test.answer_should_match('20:13:50 <x> #changeitem 1', 'Current agenda item is second item.')
+        test.answer_should_match('20:13:50 <x> #changeitem 0', 'Current agenda item is first item.')
+        test.answer_should_match('20:13:50 <x> #changeitem 10', 'Your choice was out of range!')
+        test.answer_should_match('20:13:50 <x> #changeitem puppy', 'Your choice was not recognized as a number. Please retry.')
 
         # Test changing item during vote
         test.process('20:13:50 <x> #startvote')
@@ -366,13 +373,14 @@ class MeetBotTest(unittest.TestCase):
                                   'open so I didn\'t change item. Please #endvote first')
         test.answer_should_match('20:13:50 <x> #previtem', 'Voting is currently ' +\
                                   'open so I didn\'t change item. Please #endvote first')
+        test.answer_should_match('20:13:50 <x> #changeitem 2', 'Voting is currently ' +\
+                                  'open so I didn\'t change item. Please #endvote first')
 
         # Test changing item after vote
         test.process('20:13:50 <x> #endvote')
         test.answer_should_match('20:13:50 <x> #nextitem', 'Current agenda item is second item.')
-        test.answer_should_match('20:13:50 <x> #nextitem', 'Current agenda item is second item.')
-        test.answer_should_match('20:13:50 <x> #previtem', 'Current agenda item is first item.')
         test.answer_should_match('20:13:50 <x> #previtem', 'Current agenda item is first item.')
+        test.answer_should_match('20:13:50 <x> #changeitem 2', 'Current agenda item is third item.')
 
     def test_agenda_option_listing(self):
         test = self.get_simple_agenda_test()
@@ -412,7 +420,7 @@ class MeetBotTest(unittest.TestCase):
                                   '#vote <option number>.\nEnd voting with #endvote.')
         test.answer_should_match('20:13:50 <x> #startvote', 'Voting is already open. ' +\
                                   'You can end it with #endvote.')
-        test.answer_should_match('20:13:50 <x> #vote 10', 'Your vote was out of range\!')
+        test.answer_should_match('20:13:50 <x> #vote 10', 'Your choice was out of range\!')
         test.answer_should_match('20:13:50 <x> #vote 0', 'You voted for #0 - opt1')
         test.answer_should_match('20:13:50 <x> #vote 1', 'You voted for #1 - opt2')
         test.answer_should_match('20:13:50 <z> #vote 0', 'You voted for #0 - opt1')
@@ -426,7 +434,7 @@ class MeetBotTest(unittest.TestCase):
         test.answer_should_match('20:13:50 <x> #endmeeting', 'Meeting ended ' +\
                                   '.*\nMinutes:.*\nMinutes \(text\):.*\nLog:.*')
 
-        assert(test.votes() == {'first item': {u'x': 'opt2', u'z': 'opt1'}, 'second item': {}})
+        assert(test.votes() == {'first item': {u'x': 'opt2', u'z': 'opt1'}, 'second item': {}, 'third item': {}})
 
     def test_agenda_close_voting_after_last_vote(self):
         test = self.get_simple_agenda_test()



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/
@ 2011-06-22  7:59 Petteri Räty
  0 siblings, 0 replies; 12+ messages in thread
From: Petteri Räty @ 2011-06-22  7:59 UTC (permalink / raw
  To: gentoo-commits

commit:     1a137e470619a11e14ed9c0be48f24a062890d1b
Author:     Joachim Filip Ignacy Bartosik <jbartosik <AT> gmail <DOT> com>
AuthorDate: Tue Jun 21 15:29:09 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Wed Jun 22 07:22:05 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/council-webapp.git;a=commit;h=1a137e47

Close voting when last user allowed to vote voted.

---
 bot/ircmeeting/agenda.py |   10 +++++++++-
 bot/tests/run_test.py    |   11 +++++++++++
 2 files changed, 20 insertions(+), 1 deletions(-)

diff --git a/bot/ircmeeting/agenda.py b/bot/ircmeeting/agenda.py
index 928ff5f..775dfd9 100644
--- a/bot/ircmeeting/agenda.py
+++ b/bot/ircmeeting/agenda.py
@@ -79,6 +79,7 @@ class Agenda(object):
         self._voters = self._get_json(self.conf.voters_url)
         self._agenda = self._get_json(self.conf.agenda_url)
         self._votes = { }
+        self._voters.sort()
         for i in self._agenda:
             self._votes[i[0]] = { }
 
@@ -93,7 +94,14 @@ class Agenda(object):
           return(opt)
 
         self._votes[self._agenda[self._current_item][0]][nick] = self._agenda[self._current_item][1][opt]
-        return str.format(self.vote_confirm_msg, opt, self._agenda[self._current_item][1][opt])
+
+        users_who_voted = self._votes[self._agenda[self._current_item][0]].keys()
+        users_who_voted.sort()
+
+        reply = str.format(self.vote_confirm_msg, opt, self._agenda[self._current_item][1][opt])
+        if users_who_voted == self._voters:
+          reply += '. ' + self.end_vote()
+        return(reply)
 
     def _get_json(self, url):
         str = urllib.urlopen(url).read()

diff --git a/bot/tests/run_test.py b/bot/tests/run_test.py
index 9808ee6..3c43fef 100644
--- a/bot/tests/run_test.py
+++ b/bot/tests/run_test.py
@@ -406,6 +406,7 @@ class MeetBotTest(unittest.TestCase):
 
     def test_agenda_voting(self):
         test = self.get_simple_agenda_test()
+        test.M.config.agenda._voters.append('t')
         test.answer_should_match('20:13:50 <x> #startvote', 'Voting started\. ' +\
                                   'Available voting options are:\n0. opt1\n1. opt2\nVote ' +\
                                   '#vote <option number>.\nEnd voting with #endvote.')
@@ -427,6 +428,16 @@ class MeetBotTest(unittest.TestCase):
 
         assert(test.votes() == {'first item': {u'x': 'opt2', u'z': 'opt1'}, 'second item': {}})
 
+    def test_agenda_close_voting_after_last_vote(self):
+        test = self.get_simple_agenda_test()
+        test.answer_should_match('20:13:50 <x> #startvote', 'Voting started\. ' +\
+                                  'Available voting options are:\n0. opt1\n1. opt2\nVote ' +\
+                                  '#vote <option number>.\nEnd voting with #endvote.')
+        test.answer_should_match('20:13:50 <x> #startvote', 'Voting is already open. ' +\
+                                  'You can end it with #endvote.')
+        test.answer_should_match('20:13:50 <x> #vote 0', 'You voted for #0 - opt1')
+        test.answer_should_match('20:13:50 <z> #vote 0', 'You voted for #0 - opt1. Voting closed.')
+
 if __name__ == '__main__':
     os.chdir(os.path.join(os.path.dirname(__file__), '.'))
 



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/
@ 2011-06-25 11:55 Petteri Räty
  0 siblings, 0 replies; 12+ messages in thread
From: Petteri Räty @ 2011-06-25 11:55 UTC (permalink / raw
  To: gentoo-commits

commit:     62b3ba6efe4ac1de77f24527e844c9a70ed94b1b
Author:     Joachim Filip Ignacy Bartosik <jbartosik <AT> gmail <DOT> com>
AuthorDate: Wed Jun 22 07:28:20 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Wed Jun 22 18:31:35 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/council-webapp.git;a=commit;h=62b3ba6e

Add support for #timelimit (add|list|remove) commands

---
 bot/ircmeeting/agenda.py  |   46 +++++++++++++++++++++++++++++++++++-
 bot/ircmeeting/meeting.py |   17 +++++++++++++-
 bot/tests/run_test.py     |   56 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 116 insertions(+), 3 deletions(-)

diff --git a/bot/ircmeeting/agenda.py b/bot/ircmeeting/agenda.py
index 928ff5f..220acf9 100644
--- a/bot/ircmeeting/agenda.py
+++ b/bot/ircmeeting/agenda.py
@@ -1,7 +1,15 @@
 import json
+import threading
 import urllib
 import re
 
+class MessageSender:
+  def __init__(self, irc, message):
+    self.irc = irc
+    self.message = message
+  def send_message(self):
+    self.irc.reply(self.message)
+
 class Agenda(object):
 
     # Messages
@@ -18,6 +26,10 @@ class Agenda(object):
     not_a_number_msg = "Your vote was not recognized as a number. Please retry."
     out_of_range_msg = "Your vote was out of range!"
     vote_confirm_msg = "You voted for #{} - {}"
+    timelimit_added_msg = 'Added "{}" reminder in {}:{}'
+    timelimit_list_msg = 'Set reminders: "{}"'
+    timelimit_removed_msg = 'Reminder "{}" removed'
+    timelimit_missing_msg = 'No such reminder "{}"'
 
     # Internal
     _voters     = []
@@ -28,6 +40,7 @@ class Agenda(object):
 
     def __init__(self, conf):
       self.conf = conf
+      self.reminders = {}
 
     def get_agenda_item(self):
         if not self.conf.manage_agenda:
@@ -37,6 +50,12 @@ class Agenda(object):
         else:
             return self.empty_agenda_msg
 
+    def _swich_agenda_item_to(self, new_item):
+      self._current_item = new_item
+      for reminder in self.reminders.values():
+        reminder.cancel()
+      self.reminders = {}
+
     def next_agenda_item(self):
         if not self.conf.manage_agenda:
           return('')
@@ -44,7 +63,7 @@ class Agenda(object):
             return self.voting_open_so_item_not_changed_msg
         else:
             if (self._current_item + 1) < len(self._agenda):
-                self._current_item += 1
+                self._swich_agenda_item_to(self._current_item + 1)
             return(self.get_agenda_item())
 
     def prev_agenda_item(self):
@@ -54,7 +73,7 @@ class Agenda(object):
             return self.voting_open_so_item_not_changed_msg
         else:
             if self._current_item > 0:
-                self._current_item -= 1
+                self._swich_agenda_item_to(self._current_item - 1)
             return(self.get_agenda_item())
 
     def start_vote(self):
@@ -144,6 +163,29 @@ class Agenda(object):
         option = self._agenda[self._current_item][1].pop(opt)
         return str.format(self.removed_option_msg, str(opt), option)
 
+    def add_timelimit(self, minutes, seconds, message, irc):
+      sender = MessageSender(irc, message)
+      reminder = (threading.Timer(60*minutes + seconds, sender.send_message))
+      self.reminders[message] = reminder
+      reminder.start()
+      result = str.format(self.timelimit_added_msg, message, minutes, seconds)
+      return(result)
+
+    def list_timielimits(self):
+      keys = self.reminders.keys()
+      keys_str = '", "'.join(keys)
+      result = str.format(self.timelimit_list_msg, keys_str)
+      return(result)
+
+    def remove_timelimit(self, message):
+      if message in self.reminders:
+        timer = self.reminders.pop(message)
+        timer.cancel()
+        result = str.format(self.timelimit_removed_msg, message)
+      else:
+         result = str.format(self.timelimit_missing_msg, message)
+      return(result)
+
     def post_result(self):
         if not self.conf.manage_agenda:
           return('')

diff --git a/bot/ircmeeting/meeting.py b/bot/ircmeeting/meeting.py
index 84949ed..4bd3221 100644
--- a/bot/ircmeeting/meeting.py
+++ b/bot/ircmeeting/meeting.py
@@ -33,6 +33,7 @@ import time
 import os
 import re
 import stat
+import threading
 
 import writers
 import items
@@ -301,7 +302,6 @@ else:
         # Subclass Config and LocalConfig, new type overrides Config.
         Config = type('Config', (LocalConfig, Config), {})
 
-
 class MeetingCommands(object):
     # Command Definitions
     # generic parameters to these functions:
@@ -328,6 +328,21 @@ class MeetingCommands(object):
     def do_previtem(self, nick, time_, line, **kwargs):
         self.reply(self.config.agenda.prev_agenda_item())
 
+    def do_timelimit(self, nick, time_, line, **kwargs):
+        reply = 'Usage "#timelimit add <minutes>:<seconds> <message>" or ' +\
+                '"#timelimit list" or "#timelimit remove <message>"'
+        match = re.match( ' *?add ([0-9]+):([0-9]+) (.*)', line)
+        if match:
+          reply = self.config.agenda.add_timelimit(int(match.group(1)),
+                       int(match.group(2)), match.group(3), self)
+        elif re.match( ' *?list', line):
+          reply = self.config.agenda.list_timielimits()
+        else:
+          match = re.match( ' *?remove (.*)', line)
+          if(match):
+            reply = self.config.agenda.remove_timelimit(match.group(1))
+        self.reply(reply)
+
     def do_startvote(self, nick, time_, line, **kwargs):
        for messageline in self.config.agenda.start_vote().split('\n'):
             self.reply(messageline)

diff --git a/bot/tests/run_test.py b/bot/tests/run_test.py
index 9808ee6..e3a9030 100644
--- a/bot/tests/run_test.py
+++ b/bot/tests/run_test.py
@@ -6,6 +6,8 @@ import re
 import shutil
 import sys
 import tempfile
+import time
+import threading
 import unittest
 
 os.environ['MEETBOT_RUNNING_TESTS'] = '1'
@@ -427,6 +429,60 @@ class MeetBotTest(unittest.TestCase):
 
         assert(test.votes() == {'first item': {u'x': 'opt2', u'z': 'opt1'}, 'second item': {}})
 
+    def test_agenda_time_limit_adding(self):
+        test = self.get_simple_agenda_test()
+        test.answer_should_match('20:13:50 <x> #timelimit', 'Usage "#timelimit ' +\
+                                  'add <minutes>:<seconds> <message>" or "' +\
+                                  '#timelimit list" or "#timelimit remove ' +\
+                                  '<message>"')
+        test.answer_should_match('20:13:50 <x> #timelimit add 0:1 some other message',
+                                  'Added "some other message" reminder in 0:1')
+        test.answer_should_match('20:13:50 <x> #timelimit add 1:0 some message',
+                                  'Added "some message" reminder in 1:0')
+        time.sleep(2)
+        last_message = test.log[-1]
+        assert(last_message == 'some other message')
+        reminders = test.M.config.agenda.reminders
+        assert(len(reminders) == 2)
+        for reminder in reminders.values():
+          assert(reminder.__class__ == threading._Timer)
+
+        test.process('20:13:50 <x> #nextitem')
+
+    def test_agenda_time_limit_removing_when_changing_item(self):
+        test = self.get_simple_agenda_test()
+
+        test.process('20:13:50 <x> #timelimit add 0:1 message')
+        assert(len(test.M.config.agenda.reminders) == 1)
+        test.process('20:13:50 <x> #nextitem')
+        assert(len(test.M.config.agenda.reminders) == 0)
+        test.process('20:13:50 <x> #timelimit add 0:1 message')
+        assert(len(test.M.config.agenda.reminders) == 1)
+        test.process('20:13:50 <x> #previtem')
+        assert(len(test.M.config.agenda.reminders) == 0)
+
+    def test_agenda_time_limit_manual_removing(self):
+        test = self.get_simple_agenda_test()
+
+        test.process('20:13:50 <x> #timelimit add 0:1 message')
+        test.process('20:13:50 <x> #timelimit add 0:1 other message')
+        keys = test.M.config.agenda.reminders.keys()
+        keys.sort()
+        assert(keys == ['message', 'other message'])
+
+        test.answer_should_match('20:13:50 <x> #timelimit remove other message', 'Reminder "other message" removed')
+        keys = test.M.config.agenda.reminders.keys()
+        assert(keys == ['message'])
+
+    def test_agenda_time_limit_listing(self):
+        test = self.get_simple_agenda_test()
+        test.process('20:13:50 <x> #timelimit add 0:1 message')
+        test.process('20:13:50 <x> #timelimit add 0:1 other message')
+        test.process('20:13:50 <x> #timelimit add 0:1 yet another message')
+        keys = test.M.config.agenda.reminders.keys()
+        test.answer_should_match('20:13:50 <x> #timelimit list',
+                                  'Set reminders: "' + '", "'.join(keys) + '"')
+
 if __name__ == '__main__':
     os.chdir(os.path.join(os.path.dirname(__file__), '.'))
 



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/
@ 2011-06-25 11:55 Petteri Räty
  0 siblings, 0 replies; 12+ messages in thread
From: Petteri Räty @ 2011-06-25 11:55 UTC (permalink / raw
  To: gentoo-commits

commit:     4430af0e8a05b3424b88ee9803034959b5e46dec
Author:     Joachim Filip Ignacy Bartosik <jbartosik <AT> gmail <DOT> com>
AuthorDate: Fri Jun 24 17:37:23 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Fri Jun 24 17:37:23 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/council-webapp.git;a=commit;h=4430af0e

Bot receives reminders from webapp

---
 bot/ircmeeting/agenda.py  |   16 +++++++++++-----
 bot/ircmeeting/meeting.py |    4 ++--
 bot/tests/run_test.py     |   19 ++++++++++++++++++-
 3 files changed, 31 insertions(+), 8 deletions(-)

diff --git a/bot/ircmeeting/agenda.py b/bot/ircmeeting/agenda.py
index 220acf9..101c73c 100644
--- a/bot/ircmeeting/agenda.py
+++ b/bot/ircmeeting/agenda.py
@@ -50,30 +50,36 @@ class Agenda(object):
         else:
             return self.empty_agenda_msg
 
-    def _swich_agenda_item_to(self, new_item):
+    def _swich_agenda_item_to(self, new_item, irc):
       self._current_item = new_item
       for reminder in self.reminders.values():
         reminder.cancel()
       self.reminders = {}
-
-    def next_agenda_item(self):
+      for line in self._agenda[self._current_item][2].split('\n'):
+        match = re.match( '([0-9]+):([0-9]+) (.*)', line)
+        if match:
+          self.add_timelimit(int(match.group(1)), int(match.group(2)),
+                                match.group(3), irc)
+      self._agenda[self._current_item][2] = ''
+
+    def next_agenda_item(self, irc):
         if not self.conf.manage_agenda:
           return('')
         if self._vote_open:
             return self.voting_open_so_item_not_changed_msg
         else:
             if (self._current_item + 1) < len(self._agenda):
-                self._swich_agenda_item_to(self._current_item + 1)
+                self._swich_agenda_item_to(self._current_item + 1, irc)
             return(self.get_agenda_item())
 
-    def prev_agenda_item(self):
+    def prev_agenda_item(self, irc):
         if not self.conf.manage_agenda:
           return('')
         if self._vote_open:
             return self.voting_open_so_item_not_changed_msg
         else:
             if self._current_item > 0:
-                self._swich_agenda_item_to(self._current_item - 1)
+                self._swich_agenda_item_to(self._current_item - 1, irc)
             return(self.get_agenda_item())
 
     def start_vote(self):

diff --git a/bot/ircmeeting/meeting.py b/bot/ircmeeting/meeting.py
index 4bd3221..e3cf38d 100644
--- a/bot/ircmeeting/meeting.py
+++ b/bot/ircmeeting/meeting.py
@@ -323,10 +323,10 @@ class MeetingCommands(object):
         self.reply(self.config.agenda.get_agenda_item())
 
     def do_nextitem(self, nick, time_, line, **kwargs):
-        self.reply(self.config.agenda.next_agenda_item())
+        self.reply(self.config.agenda.next_agenda_item(self))
 
     def do_previtem(self, nick, time_, line, **kwargs):
-        self.reply(self.config.agenda.prev_agenda_item())
+        self.reply(self.config.agenda.prev_agenda_item(self))
 
     def do_timelimit(self, nick, time_, line, **kwargs):
         reply = 'Usage "#timelimit add <minutes>:<seconds> <message>" or ' +\

diff --git a/bot/tests/run_test.py b/bot/tests/run_test.py
index e3a9030..e22516b 100644
--- a/bot/tests/run_test.py
+++ b/bot/tests/run_test.py
@@ -344,7 +344,7 @@ class MeetBotTest(unittest.TestCase):
     def get_simple_agenda_test(self):
         test = test_meeting.TestMeeting()
         test.set_voters(['x', 'z'])
-        test.set_agenda([['first item', ['opt1', 'opt2']], ['second item', []]])
+        test.set_agenda([['first item', ['opt1', 'opt2'], ''], ['second item', [], '']])
         test.M.config.manage_agenda = False
 
         test.answer_should_match("20:13:50 <x> #startmeeting",
@@ -483,6 +483,23 @@ class MeetBotTest(unittest.TestCase):
         test.answer_should_match('20:13:50 <x> #timelimit list',
                                   'Set reminders: "' + '", "'.join(keys) + '"')
 
+    def test_preset_agenda_time_limits(self):
+        test = self.get_simple_agenda_test()
+        test.M.config.agenda._agenda[0][2] = '1:0 message'
+        test.M.config.agenda._agenda[1][2] = '1:0 another message\n0:10 some other message'
+
+        test.process('20:13:50 <x> #nextitem')
+        keys = test.M.config.agenda.reminders.keys()
+        keys.sort()
+        assert(keys == ['another message', 'some other message'])
+
+        test.process('20:13:50 <x> #previtem')
+        keys = test.M.config.agenda.reminders.keys()
+        keys.sort()
+        assert(keys == ['message'])
+
+        test.process('20:13:50 <x> #nextitem')
+
 if __name__ == '__main__':
     os.chdir(os.path.join(os.path.dirname(__file__), '.'))
 



^ permalink raw reply related	[flat|nested] 12+ messages in thread

* [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/
@ 2011-07-18  7:41 Petteri Räty
  0 siblings, 0 replies; 12+ messages in thread
From: Petteri Räty @ 2011-07-18  7:41 UTC (permalink / raw
  To: gentoo-commits

commit:     6fd62e887e49accc1d3189279f0e007fed3f3bd1
Author:     Joachim Filip Ignacy Bartosik <jbartosik <AT> gmail <DOT> com>
AuthorDate: Sat Jul 16 18:21:26 2011 +0000
Commit:     Petteri Räty <betelgeuse <AT> gentoo <DOT> org>
CommitDate: Sat Jul 16 18:21:26 2011 +0000
URL:        http://git.overlays.gentoo.org/gitweb/?p=proj/council-webapp.git;a=commit;h=6fd62e88

Add #command command to MeetBot - shows documentation for other commands

---
 bot/ircmeeting/meeting.py |   31 ++++++++++++++++++++++++++++---
 bot/tests/run_test.py     |   15 +++++++++++----
 2 files changed, 39 insertions(+), 7 deletions(-)

diff --git a/bot/ircmeeting/meeting.py b/bot/ircmeeting/meeting.py
index a15b674..c20fd6d 100644
--- a/bot/ircmeeting/meeting.py
+++ b/bot/ircmeeting/meeting.py
@@ -323,14 +323,20 @@ class MeetingCommands(object):
         self.reply(self.config.agenda.get_agenda_item())
 
     def do_nextitem(self, nick, time_, line, **kwargs):
+        """Go to next agenda item"""
         self.reply(self.config.agenda.next_agenda_item(self))
 
     def do_previtem(self, nick, time_, line, **kwargs):
+        """Go to previous agenda item"""
         self.reply(self.config.agenda.prev_agenda_item(self))
 
     def do_timelimit(self, nick, time_, line, **kwargs):
-        reply = 'Usage "#timelimit add <minutes>:<seconds> <message>" or ' +\
-                '"#timelimit list" or "#timelimit remove <message>"'
+        """ Manage reminders:
+        #timelimit list - list all active reminders
+        #timelimit add <minutes>:<seconds> <message> - add a new reminder
+        #timelimit remove <message> - remove reminder with message"""
+
+        reply = self.do_timelimit.__doc__
         match = re.match( ' *?add ([0-9]+):([0-9]+) (.*)', line)
         if match:
           reply = self.config.agenda.add_timelimit(int(match.group(1)),
@@ -341,24 +347,33 @@ class MeetingCommands(object):
           match = re.match( ' *?remove (.*)', line)
           if(match):
             reply = self.config.agenda.remove_timelimit(match.group(1))
-        self.reply(reply)
+        for line in reply.split("\n"):
+          self.reply(line)
 
     def do_changeitem(self, nick, time_, line, **kwargs):
+        """Change agenda item. Usage: #chengeitem <item number>"""
         self.reply(self.config.agenda.change_agenda_item(line))
 
     def do_startvote(self, nick, time_, line, **kwargs):
+       """Start vote on current item"""
        for messageline in self.config.agenda.start_vote().split('\n'):
             self.reply(messageline)
 
     def do_endvote(self, nick, time_, line, **kwargs):
+       """Close voting for current agenda item. You can resume voting later with #startvote"""
        for messageline in self.config.agenda.end_vote().split('\n'):
             self.reply(messageline)
 
     def do_vote(self, nick, time_, line, **kwargs):
+        """Make a vote. Usage: vote <option number>. Remember to #startvote before voting."""
         for messageline in self.config.agenda.vote(nick, line).split('\n'):
             self.reply(messageline)
 
     def do_option(self, nick, time_, line, **kwargs):
+        """Manage voting options:
+            #option list - lists all available votin options for current item
+            #option add <option text> - adds new voting option
+            #option remove <option number> - removes existing option"""
         if re.match( ' *?list', line):
           result = self.config.agenda.options()
         elif re.match( ' *?add .*', line):
@@ -515,6 +530,16 @@ class MeetingCommands(object):
         commands = [ "#"+x[3:] for x in dir(self) if x[:3]=="do_" ]
         commands.sort()
         self.reply("Available commands: "+(" ".join(commands)))
+    def do_command(self, nick, line, **kwargs):
+        name = "do_" + line.strip()
+        attr = getattr(self, name)
+        if attr is None:
+          return
+        doc = attr.__doc__
+        if doc is None:
+          return
+        for line in doc.split("\n"):
+          self.reply(line)
 
 
 

diff --git a/bot/tests/run_test.py b/bot/tests/run_test.py
index 0d18cce..136e135 100644
--- a/bot/tests/run_test.py
+++ b/bot/tests/run_test.py
@@ -450,10 +450,7 @@ class MeetBotTest(unittest.TestCase):
 
     def test_agenda_time_limit_adding(self):
         test = self.get_simple_agenda_test()
-        test.answer_should_match('20:13:50 <x> #timelimit', 'Usage "#timelimit ' +\
-                                  'add <minutes>:<seconds> <message>" or "' +\
-                                  '#timelimit list" or "#timelimit remove ' +\
-                                  '<message>"')
+        test.answer_should_match('20:13:50 <x> #timelimit', test.M.do_timelimit.__doc__)
         test.answer_should_match('20:13:50 <x> #timelimit add 0:1 some other message',
                                   'Added "some other message" reminder in 0:1')
         test.answer_should_match('20:13:50 <x> #timelimit add 1:0 some message',
@@ -531,6 +528,16 @@ class MeetBotTest(unittest.TestCase):
         error_msg = 'Received messages ' + str(test.log) + \
                     ' didn\'t match expected ' + str(expected_messages)
         assert messages_match, error_msg
+    def test_command_help(self):
+        test = self.get_simple_agenda_test()
+        commands = ['startmeeting', 'startvote', 'vote', 'endvote',
+                    'nextitem', 'previtem', 'changeitem', 'option',
+                    'timelimit', 'endmeeting']
+        for command in commands:
+          desc = getattr(test.M, 'do_' + command).__doc__
+          if desc is None:
+            desc = ''
+          test.answer_should_match('20:13:50 <x> #command ' + command, desc)
 
 if __name__ == '__main__':
     os.chdir(os.path.join(os.path.dirname(__file__), '.'))



^ permalink raw reply related	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2011-07-18  7:41 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-06-05 20:37 [gentoo-commits] proj/council-webapp:master commit in: bot/tests/, bot/ircmeeting/ Petteri Räty
  -- strict thread matches above, loose matches on Subject: below --
2011-06-18 15:46 Petteri Räty
2011-06-18 15:46 Petteri Räty
2011-06-18 15:46 Petteri Räty
2011-06-18 15:46 Petteri Räty
2011-06-18 15:46 Petteri Räty
2011-06-18 15:46 Petteri Räty
2011-06-22  7:59 Petteri Räty
2011-06-22  7:59 Petteri Räty
2011-06-25 11:55 Petteri Räty
2011-06-25 11:55 Petteri Räty
2011-07-18  7:41 Petteri Räty

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox