Rooms are now called Tracks

Since a given theme/team may meet in several different
locations during the week, let's call that a "track"
rather than a "room" (which was a confusing concept
since we had "location" as well).

Change-Id: I0978f4c8b33954f53698d8a058b9a802556e56c1
This commit is contained in:
Thierry Carrez 2017-11-29 17:55:43 +01:00
parent 0ff1a65f6c
commit 3b87290132
4 changed files with 84 additions and 83 deletions

View File

@ -2,8 +2,8 @@
OpenStack PTG Bot
=================
ptgbot is the bot that PTG room moderators use to surface what's
currently happening at the event. Room operators send messages to
ptgbot is the bot that PTG track moderators use to surface what's
currently happening at the event. Track moderators send messages to
the bot, like::
#swift now discussing ring balancing
@ -12,26 +12,26 @@ and 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").
Room operators commands
=======================
Track moderators commands
=========================
You have to have voice in the channel (+v) to send commands to the ptgbot.
Commands follow the following format::
#ROOMNAME [now|next] TOPIC
#ROOMNAME [color] CSS_COLOR_SPECIFIER
#TRACK [now|next] TOPIC
#TRACK [color] CSS_COLOR_SPECIFIER
Please note that:
* 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.
* There can only be one "now" discussion 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
wipes out any "next" entry for the same topic. You might want to refresh
those after entering a "now" topic.
* The color command only sets the background color for the room
* The color command only sets the background color for the track
name. The foreground is always white. Colors can be specified in any
form supported by the CSS attribute background-color.
@ -50,10 +50,10 @@ Example::
#oslo color #42f4c5
#oslo next after lunch we plan to discuss auto-generating config reference docs
You can also remove all entries related to your room by issuing the following
You can also remove all entries related to your track by issuing the following
command::
#ROOMNAME clean
#TRACK clean
Admin commands
@ -62,19 +62,19 @@ Admin commands
You have to be a channel operator (+o) to use admin commands.
~list
List available room names
List available track names
~add ROOM [ROOM..]
Add new room name(s)
~add TRACK [TRACK..]
Add new track(s)
~del ROOM [ROOM..]
Deletes room name(s)
~del TRACK [TRACK..]
Deletes track(s)
~clean ROOM [ROOM..]
Removes active entries for specified room(s)
~clean TRACK [TRACK..]
Removes active entries for specified track(s)
~wipe
Resets the database entirely (removes all defined rooms and entries)
Resets the database entirely (removes all defined tracks and topics)
Local testing
@ -98,8 +98,9 @@ In one terminal, run the bot::
tox -evenv -- ptgbot -d config.json
Join that channel and give a command to the bot::
Join that channel and give commands to the bot::
~add swift
#swift now discussing ring placement
(note, the bot currently only takes commands from Freenode identified users)

View File

@ -18,8 +18,8 @@
<script id="PTGtemplate" type="text/x-handlebars-template">
<style>
{{#each colors as |color room|}}
.{{room}} {
{{#each colors as |color track|}}
.{{track}} {
background-color: {{color}};
}
{{/each}}
@ -27,12 +27,12 @@
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">Currently playing...</h3></div>
<table class="table">
{{#each rooms as |room| }}
{{#if (lookup @root.now room) }}
{{#each tracks as |track| }}
{{#if (lookup @root.now track) }}
<tr>
<td class="col-sm-1"><span class="label label-primary {{room}}">{{room}}</span></td>
<td>{{#hashtag}}{{lookup @root.now room}}{{/hashtag}}</td>
<td>{{lookup @root.location room}}</td>
<td class="col-sm-1"><span class="label label-primary {{track}}">{{track}}</span></td>
<td>{{#hashtag}}{{lookup @root.now track}}{{/hashtag}}</td>
<td>{{lookup @root.location track}}</td>
</tr>
{{/if}}
{{else}}
@ -43,12 +43,12 @@
<div class="panel panel-default">
<div class="panel-heading"><h3 class="panel-title">Coming up next...</h3></div>
<table class="table">
{{#each rooms as |room| }}
{{#if (lookup @root.next room) }}
{{#each tracks as |track| }}
{{#if (lookup @root.next track) }}
<tr>
<td class="col-sm-1"><span class="label label-primary {{room}}">{{room}}</span></td>
<td class="col-sm-1"><span class="label label-primary {{track}}">{{track}}</span></td>
<td>
{{#each (lookup @root.next room) as |item|}}
{{#each (lookup @root.next track) as |item|}}
{{#hashtag}}{{item}}{{/hashtag}} <br/>
{{/each}}
</td>
@ -59,7 +59,7 @@
{{/each}}
</table>
</div>
<p class="text-muted">Content on this page is being driven by room operators through the openstackptg bot on the #openstack-ptg IRC channel. It was last refreshed on {{timestamp}}.</p>
<p class="text-muted">Content on this page is being driven by track moderators through the openstackptg bot on the #openstack-ptg IRC channel. It was last refreshed on {{timestamp}}.</p>
</script>

View File

@ -89,15 +89,15 @@ class PTGBot(irc.bot.SingleServerIRCBot):
def usage(self, channel):
self.send(channel,
"Format is '#ROOMNAME [ now ... | next ... "
"Format is '#TRACK [ now ... | next ... "
"| location ... | clean ]'")
def send_room_list(self, channel):
rooms = self.data.list_rooms()
if rooms:
self.send(channel, "Active rooms: %s" % str.join(' ', rooms))
def send_track_list(self, channel):
tracks = self.data.list_tracks()
if tracks:
self.send(channel, "Active tracks: %s" % str.join(' ', tracks))
else:
self.send(channel, "There are no active rooms defined yet")
self.send(channel, "There are no active tracks defined yet")
def on_pubmsg(self, c, e):
if not self.identify_msg_cap:
@ -121,24 +121,24 @@ class PTGBot(irc.bot.SingleServerIRCBot):
self.usage(chan)
return
room = words[0][1:].lower()
if not self.data.is_room_valid(room):
self.send(chan, "%s: unknown room '%s'" % (nick, room))
self.send_room_list(chan)
track = words[0][1:].lower()
if not self.data.is_track_valid(track):
self.send(chan, "%s: unknown track '%s'" % (nick, track))
self.send_track_list(chan)
return
adverb = words[1].lower()
session = str.join(' ', words[2:])
if adverb == 'now':
self.data.add_now(room, session)
self.data.add_now(track, session)
elif adverb == 'next':
self.data.add_next(room, session)
self.data.add_next(track, session)
elif adverb == 'clean':
self.data.clean_rooms([room])
self.data.clean_tracks([track])
elif adverb == 'color':
self.data.add_color(room, session)
self.data.add_color(track, session)
elif adverb == 'location':
self.data.add_location(room, session)
self.data.add_location(track, session)
else:
self.send(chan, "%s: unknown directive '%s'" % (nick, adverb))
self.usage(chan)
@ -153,13 +153,13 @@ class PTGBot(irc.bot.SingleServerIRCBot):
if command == 'wipe':
self.data.wipe()
elif command == 'list':
self.send_room_list(chan)
self.send_track_list(chan)
return
elif command in ('clean', 'add', 'del'):
if len(words) < 2:
self.send(chan, "this command takes one or more arguments")
return
getattr(self.data, command + '_rooms')(words[1:])
getattr(self.data, command + '_tracks')(words[1:])
else:
self.send(chan, "%s: unknown command '%s'" % (nick, command))
return

View File

@ -21,7 +21,7 @@ import datetime
class PTGDataBase():
BASE = {'rooms': [], 'now': {}, 'next': {}, 'colors': {},
BASE = {'tracks': [], 'now': {}, 'next': {}, 'colors': {},
'location': {}}
def __init__(self, filename):
@ -33,52 +33,52 @@ class PTGDataBase():
self.data = self.BASE
self.save()
def add_now(self, room, session):
self.data['now'][room] = session
if room in self.data['next']:
del self.data['next'][room]
def add_now(self, track, session):
self.data['now'][track] = session
if track in self.data['next']:
del self.data['next'][track]
self.save()
def add_color(self, room, color):
self.data['colors'][room] = color
def add_color(self, track, color):
self.data['colors'][track] = color
self.save()
def add_location(self, room, location):
def add_location(self, track, location):
if 'location' not in self.data:
self.data['location'] = {}
self.data['location'][room] = location
self.data['location'][track] = location
self.save()
def add_next(self, room, session):
if room not in self.data['next']:
self.data['next'][room] = []
self.data['next'][room].append(session)
def add_next(self, track, session):
if track not in self.data['next']:
self.data['next'][track] = []
self.data['next'][track].append(session)
self.save()
def is_room_valid(self, room):
return room in self.data['rooms']
def is_track_valid(self, track):
return track in self.data['tracks']
def list_rooms(self):
return sorted(self.data['rooms'])
def list_tracks(self):
return sorted(self.data['tracks'])
def add_rooms(self, rooms):
for room in rooms:
if room not in self.data['rooms']:
self.data['rooms'].append(room)
def add_tracks(self, tracks):
for track in tracks:
if track not in self.data['tracks']:
self.data['tracks'].append(track)
self.save()
def del_rooms(self, rooms):
for room in rooms:
if room in self.data['rooms']:
self.data['rooms'].remove(room)
def del_tracks(self, tracks):
for track in tracks:
if track in self.data['tracks']:
self.data['tracks'].remove(track)
self.save()
def clean_rooms(self, rooms):
for room in rooms:
if room in self.data['now']:
del self.data['now'][room]
if room in self.data['next']:
del self.data['next'][room]
def clean_tracks(self, tracks):
for track in tracks:
if track in self.data['now']:
del self.data['now'][track]
if track in self.data['next']:
del self.data['next'][track]
self.save()
def wipe(self):
@ -88,6 +88,6 @@ class PTGDataBase():
def save(self):
timestamp = datetime.datetime.now()
self.data['timestamp'] = '{:%Y-%m-%d %H:%M:%S}'.format(timestamp)
self.data['rooms'] = sorted(self.data['rooms'])
self.data['tracks'] = sorted(self.data['tracks'])
with open(self.filename, 'w') as fp:
json.dump(self.data, fp)