← Back to team overview

ubuntu-bots team mailing list archive

[Merge] lp:~lderan/ubuntu-bots/meeetingology-output into lp:~ubuntu-bots/ubuntu-bots/meetingology

 

Thomas Molloy has proposed merging lp:~lderan/ubuntu-bots/meeetingology-output into lp:~ubuntu-bots/ubuntu-bots/meetingology.

Requested reviews:
  Ubuntu IRC Bots (ubuntu-bots)

For more details, see:
https://code.launchpad.net/~lderan/ubuntu-bots/meeetingology-output/+merge/195883

Commands that are not publicly useable are privately sent to the chairs, and when a new chair gets added they are sent the list as well. This does result in a list that will have to be maintained if new public commands are added.

DONE meeting item added.

Meeting notifications when they end sent to preset irc nicks.

Votes now link to the HTML log url to the point where the voting begins in the MoinMoin output.

Votes are now in chronological order in the MoinMoin output.
-- 
https://code.launchpad.net/~lderan/ubuntu-bots/meeetingology-output/+merge/195883
Your team Ubuntu IRC Bots is requested to review the proposed merge of lp:~lderan/ubuntu-bots/meeetingology-output into lp:~ubuntu-bots/ubuntu-bots/meetingology.
=== modified file 'items.py'
--- items.py	2013-04-21 19:25:19 +0000
+++ items.py	2013-11-20 00:00:42 +0000
@@ -235,6 +235,9 @@
     moin_template = """ * '''%(line)s''' (%(time)s)"""
 class Help(GenericItem):
     itemtype = 'HELP'
+class Done(GenericItem):
+    itemtype = 'DONE'
+    moin_template = """''ACTION:'' %(line)s"""
 class Accepted(GenericItem):
     itemtype = 'ACCEPTED'
     starthtml = '<font color="green">'

=== modified file 'meeting.py'
--- meeting.py	2013-07-24 18:38:57 +0000
+++ meeting.py	2013-11-20 00:00:42 +0000
@@ -89,6 +89,8 @@
     endMeetingMessage = ("Meeting ended %(endtime)s %(timeZone)s.  "
                          "\n"
                          "Minutes:        %(urlBasename)s.moin.txt")
+    endMeetingNotification = ("Meeting in %(channel)s has just ended")
+    endMeetingNotificationList = ["lderan"]
                          
     #TODO: endMeetingMessage should get filenames from the writers
 
@@ -285,6 +287,9 @@
         message = self.config.startMeetingMessage%repl
         for messageline in message.split('\n'):
             self.reply(messageline)
+        self.do_private_commands(self.owner)
+        for chair in self.chairs:
+            self.do_private_commands(chair)
         self.do_commands()
         if line.strip():
             self.do_meetingtopic(nick=nick, line=line, time_=time_, **kwargs)
@@ -294,7 +299,7 @@
         if not self.isChair(nick): return
         #close any open votes
         if not self.activeVote=="":
-            self.do_endvote(nick=nick,line=line,**kwargs)
+            self.do_endvote(nick, line, **kwargs)
         if self.oldtopic:
             self.topic(self.oldtopic)
         self.endtime = time_
@@ -304,7 +309,9 @@
         for messageline in message.split('\n'):
             self.reply(messageline)
         self._meetingIsOver = True
-
+        for nickToPM in self.config.endMeetingNotificationList:
+            self.privateReply(nickToPM, self.config.endMeetingNotification%repl)
+        
         
     def do_topic(self, nick, line, **kwargs):
         """Set a new topic in the channel."""
@@ -370,6 +377,7 @@
                     self.reply("Warning: Nick not in channel: %s"%chair)
                 self.addnick(chair, lines=0)
                 self.chairs.setdefault(chair, True)
+                self.do_private_commands(chair)
         chairs = dict(self.chairs) # make a copy
         chairs.setdefault(self.owner, True)
         self.reply("Current chairs: %s"%(" ".join(sorted(chairs.keys()))))
@@ -422,6 +430,10 @@
         self.reply("Public votes can be registered by saying +1, +0 or -1 in channel, (for private voting, private message me with 'vote +1/-1/+0 #channelname)")
         self.activeVote=line.strip()
         self.currentVote={}
+        self.publicVoters[self.activeVote] = []
+        #Need the line number for linking to the html output
+        self.currentVoteStartLine = 0
+        self.currentVoteStartLine = len(self.lines)
         #need to set up a structure to hold vote results
         #people can vote by saying +1 0 or -1
         #if voters have been specified then only they can vote
@@ -453,7 +465,7 @@
         for v in self.currentVote:
             if re.match("-1",self.currentVote[v]):
                 vagainst+=1
-            elif re.match("0|\+0",self.currentVote[v]):
+            elif re.match("0|\+0|-0",self.currentVote[v]):
                 vabstain+=1
             elif re.match("\+1",self.currentVote[v]):
                 vfor+=1
@@ -474,7 +486,8 @@
             else:
                 self.reply("Motion carried")
                 voteResult = "Carried"
-        self.votes[self.activeVote]=[vfor,vabstain,vagainst]#store the results
+        #store the results
+        self.votes[self.activeVote]=[vfor, vabstain, vagainst, self.currentVoteStartLine]
         
         """Add informational item to the minutes."""
         voteResultLog = "''Vote:'' "+self.activeVote+" ("+voteResult+")"
@@ -484,6 +497,7 @@
         
         self.activeVote=""#allow another vote to be called
         self.currentVote={}
+        self.currentVoteStartLine = 0
         
         
 
@@ -510,7 +524,11 @@
         voters = dict(self.voters) # make a copy
         #voters.setdefault(self.owner, True)#not sure about this if resetting voters to everyone - in fact why auto add the person calling #voters at all?
         self.reply("Current voters: %s"%(" ".join(sorted(voters.keys()))))
-
+    def do_private_commands(self, nick, **kwargs):
+        commands = [ "#"+x[3:] for x in dir(self) if x[:3]=="do_" ]
+        commands.sort()
+        message = "Available commands: "+(" ".join(commands))
+        self.privateReply(nick, message)
     # Commands for Anyone:
     def do_action(self, **kwargs):
         """Add action item to the minutes.
@@ -551,9 +569,14 @@
         m = items.Link(**kwargs)
         self.additem(m)
     def do_commands(self, **kwargs):
-        commands = [ "#"+x[3:] for x in dir(self) if x[:3]=="do_" ]
+        commands = ["action", "info", "idea", "nick", "link", "commands"]
         commands.sort()
         self.reply("Available commands: "+(" ".join(commands)))
+    def do_done(self, nick, **kwargs):
+        """Add aggreement to the minutes - chairs only."""
+        if not self.isChair(nick): return
+        m = items.Done(**kwargs)
+        self.additem(m)
 
 
 class Meeting(MeetingCommands, object):
@@ -561,7 +584,8 @@
     _restrictlogs = False
     def __init__(self, channel, owner, oldtopic=None,
                  filename=None, writeRawLog=False,
-                 setTopic=None, sendReply=None, getRegistryValue=None,
+                 setTopic=None, sendReply=None, sendPrivateReply=None,
+                 getRegistryValue=None,
                  safeMode=False, channelNicks=None,
                  extraConfig={}, network='nonetwork'):
         self.config = Config(self, writeRawLog=writeRawLog, safeMode=safeMode,
@@ -570,6 +594,8 @@
             self._registryValue = getRegistryValue
         if sendReply is not None:
             self._sendReply = sendReply
+        if sendPrivateReply is not None:
+            self._sendPrivateReply = sendPrivateReply
         if setTopic is not None:
             self._setTopic = setTopic
         self.owner = owner
@@ -585,8 +611,9 @@
         self.attendees = {}
         self.chairs = {}
         self.voters = {}
-        self.votes={}
-        self.votesrequired=0
+        self.publicVoters = {}
+        self.votes = {}
+        self.votesrequired = 0
         self.activeVote = ""
         self._writeRawLog = writeRawLog
         self._meetingTopic = None
@@ -604,6 +631,10 @@
             self._sendReply(self.config.enc(x))
         else:
             print "REPLY:", self.config.enc(x)
+    def privateReply(self, nick, x):
+        """Send a reply to nick"""
+        if hasattr(self, '_sendPrivateReply') and not self._lurk:
+            self._sendPrivateReply(self.config.enc(nick), self.config.enc(x))
     def topic(self, x):
         """Set the topic in the IRC channel."""
         if hasattr(self, '_setTopic') and not self._lurk:
@@ -656,7 +687,7 @@
                 self.do_link(nick=nick, line=line,
                              linenum=linenum, time_=time_)
         self.save(realtime_update=True)
-        if re.match("\+1|0|\+0|-1",line):
+        if re.match("\+1|0|\+0|-0|-1",line):
             self.doCastVote(nick,line,time_)
     def doCastVote(self, nick, line, time_=None, private=False):
             """if a vote is underway and the nick is a registered voter
@@ -669,6 +700,7 @@
                 if self.activeVote:
                     self.currentVote[nick]=line
                     if private is False:
+                        self.publicVoters[self.activeVote].append(nick)
                         self.reply(line + " received from " + nick)
 						
             #if the vote was in a private message - how do we do that??

=== modified file 'plugin.py'
--- plugin.py	2013-07-24 18:38:57 +0000
+++ plugin.py	2013-11-20 00:00:42 +0000
@@ -100,12 +100,15 @@
                 irc.sendMsg(ircmsgs.topic(channel, x))
             def _sendReply(x):
                 irc.sendMsg(ircmsgs.privmsg(channel, x))
+            def _sendPrivateReply(nick, x):
+                irc.sendMsg(ircmsgs.privmsg(nick, x))
             def _channelNicks():
                 return irc.state.channels[channel].users
             M = meeting.Meeting(channel=channel, owner=nick,
                                 oldtopic=irc.state.channels[channel].topic,
                                 writeRawLog=True,
                                 setTopic = _setTopic, sendReply = _sendReply,
+                                sendPrivateReply = _sendPrivateReply,
                                 getRegistryValue = self.registryValue,
                                 safeMode=True, channelNicks=_channelNicks,
                                 network=network,

=== modified file 'writers.py'
--- writers.py	2013-07-13 10:36:00 +0000
+++ writers.py	2013-11-20 00:00:42 +0000
@@ -1214,17 +1214,21 @@
         # Votes
         Votes = [ ]
         Votes.append(self.heading('Vote results'))
-        for m in M.votes:
-            #differentiate denied votes somehow, strikethrough perhaps?
-            Votes.append(" * "+m)
+        # reversed to show the oldest first
+        for m in reversed(M.votes):
+            # differentiate denied votes somehow, strikethrough perhaps?
+            Votes.append(" * [[%(fullLogsFullURL)s#"+str(M.votes[m][3])+" "+m+"]]")
             motion = "Deadlock"
             if(M.votes[m][0] > M.votes[m][1]):
                 motion = "Motion carried"
             elif(M.votes[m][0] < M.votes[m][2]):
                 motion = "Motion denied"
-                
+            
             Votes.append("  * " + motion + " (For/Against/Abstained "+str(M.votes[m][0])+"/"+str(M.votes[m][2])+"/"+str(M.votes[m][1]) + ")")
-        Votes = "\n".join(Votes)
+            if len(M.publicVoters[m]) > 0:
+                publicVoters = ', '.join(set(M.publicVoters[m]))
+                Votes.append("   *  Voters " + publicVoters)
+        Votes = "\n".join(Votes) 
         return Votes
 
     def actionItems(self):
@@ -1281,6 +1285,23 @@
             return None
         else:
             return ActionItemsPerson
+            
+    def doneItems(self):
+        M = self.M
+        # Action Items
+        DoneItems = [ ]
+        numActionItems = 0
+        DoneItems.append(self.heading('Done items'))
+        for m in M.minutes:
+            # The hack below is needed because of pickling problems
+            if m.itemtype != "DONE": continue
+            #already escaped
+            DoneItems.append(" * %s"%moin(m.line))
+            numActionItems += 1
+        if numActionItems == 0:
+            DoneItems.append(" * (none)")
+        DoneItems = "\n".join(DoneItems)
+        return DoneItems
 
     def peoplePresent(self):
         M = self.M
@@ -1315,9 +1336,10 @@
         body = [ ]
         body.append(self.body_start%repl)
         body.append(self.meetingItems())
-        body.append(self.votes())
+        body.append(self.votes()%repl)
         body.append(self.actionItems())
         body.append(self.actionItemsPerson())
+        body.append(self.doneItems())
         body.append(self.peoplePresent())
         body.append(self.fullLog())
         body.append(textwrap.dedent("""\


Follow ups