Implement simpler API

Move from at/until to now/next API for the bot, which is
simpler to explain. Adapt rendering so that it supports
multiple "next" entries.
Thierry Carrez 6 years ago
parent 42339394d5
commit 465f277ccb
  1. 32
  2. 34
  3. 21
  4. 23

@ -3,12 +3,30 @@ OpenStack PTG Bot
ptgbot is the bot that PTG room moderators use to surface what's
currently happening at the event. It builds a static webpage that
attendees can query for up-to-date information.
currently happening at the event. Commands follow the following format:
Commands follow the following format:
From that information the bot builds a static webpage with discussion
topics currently discussed ("now") and an indicative set of discussion
topics coming up next ("next").
* There can only be one "now" topic at a time. If multiple topics are
discussed at the same time in various corners of the room, they should
all be specified in a single "now" command.
* In order to ensure that information is current, entering a "now" command
wipes out any "next" entry for the same room. You might want to refresh
those after entering a "now" topic.
#swift now discussing ring placement
#swift next at 2pm we plan to discuss #glance support
#swift next around 3pm we plan to cover cold storage features
#swift now discussing #glance support, come over!
#swift next at 3pm we plan to cover cold storage features
@ -28,13 +46,13 @@ port=6667
In one terminal, run the bot:
In one terminal, run the bot::
tox -evenv -- ptgbot -d config.ini
Join that channel and give a command to the bot:
Join that channel and give a command to the bot::
@swift until 10:00 Discussing ring internals
@swift now discussing ring placement
(note, the bot currently only takes commands from Freenode identified users)

@ -18,20 +18,34 @@
<script id="PTGtemplate" type="text/x-handlebars-template">
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">Currently playing</h3></div>
<ul class="list-group">
{{#each until}}
<li class="list-group-item"><span class="label label-primary">{{@key}}</span> {{this.msg}}</li>
<div class="panel-heading"><h3 class="panel-title">Currently playing...</h3></div>
<table class="table">
{{#each now}}
<td class="col-sm-1"><span class="label label-primary">{{@key}}</span></td>
<tr><td><small><i>Nothing yet</i></small><td></tr>
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">Next discussions</h3></div>
<ul class="list-group">
{{#each at}}
<li class="list-group-item"><span class="label label-primary">{{@key}}</span> {{this.msg}}</li>
<div class="panel-heading"><h3 class="panel-title">Coming up next...</h3></div>
<table class="table">
{{#each next as |sessions room|}}
<td class="col-sm-1"><span class="label label-primary">{{room}}</span></td>
{{#each sessions}}
{{ this }}<br/>
<tr><td><small><i>Nothing yet</i></small><td></tr>

@ -88,7 +88,7 @@ class PTGBot(
self.identify_msg_cap = True
def usage(self, channel):
self.send(channel, "Format is '@ROOM [until|at] HOUR SESSION'")
self.send(channel, "Format is '@ROOM [now|next] SESSION'")
def on_pubmsg(self, c, e):
if not self.identify_msg_cap:
@ -100,26 +100,23 @@ class PTGBot(
msg = e.arguments[0][1:]
chan =
if msg.startswith('@') and auth:
if msg.startswith('#') and auth:
words = msg.split()
if len(words) < 4:
if len(words) < 3:
self.send(chan, "%s: Incorrect number of arguments" % (nick,))
room = words[0][1:].lower()
# TODO: Add test for room/day/person match
adverb = words[1].lower()
if adverb not in ['until', 'at']:
session = str.join(' ', words[2:])
if adverb == 'now':, session)
elif adverb == 'next':, session)
self.send(chan, "%s: unknown directive '%s'" % (nick, adverb))
hour = words[2]
# TODO: Add test for hour format
session = str.join(' ', words[3:])
msg = '(%s %s) %s' % (adverb, hour, session), adverb, hour, msg)
def send(self, channel, msg):
self.connection.privmsg(channel, msg)

@ -26,28 +26,25 @@ class PTGDataBase():
with open(filename, 'r') as fp: = json.load(fp)
else: = {} = {'now': {}, 'next': {}}
def add(self, room, adverb, hour, msg):
if adverb not in[adverb] = {}[adverb][room] = {'msg': msg, 'expiry': hour}
def add_now(self, room, session):['now'][room] = session
if room in['next']:
def expire(self, now):
newdata = []
for room, infos in
for info, session in infos:
if session['expiry'] > now:
newdata[room][info] = session = newdata
def add_next(self, room, session):
if room not in['next']:['next'][room] = []['next'][room].append(session)
def from_ethercalc(self):
# TODO: Load from ethercalc
def save(self):
# self.expire()
# self.from_ethercalc()
with open(self.filename, 'w') as fp:
json.dump(, fp)