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:
parent
0ff1a65f6c
commit
3b87290132
45
README.rst
45
README.rst
|
@ -2,8 +2,8 @@
|
||||||
OpenStack PTG Bot
|
OpenStack PTG Bot
|
||||||
=================
|
=================
|
||||||
|
|
||||||
ptgbot is the bot that PTG room moderators use to surface what's
|
ptgbot is the bot that PTG track moderators use to surface what's
|
||||||
currently happening at the event. Room operators send messages to
|
currently happening at the event. Track moderators send messages to
|
||||||
the bot, like::
|
the bot, like::
|
||||||
|
|
||||||
#swift now discussing ring balancing
|
#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 currently discussed ("now") and an indicative set of discussion
|
||||||
topics coming up next ("next").
|
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.
|
You have to have voice in the channel (+v) to send commands to the ptgbot.
|
||||||
Commands follow the following format::
|
Commands follow the following format::
|
||||||
|
|
||||||
#ROOMNAME [now|next] TOPIC
|
#TRACK [now|next] TOPIC
|
||||||
#ROOMNAME [color] CSS_COLOR_SPECIFIER
|
#TRACK [color] CSS_COLOR_SPECIFIER
|
||||||
|
|
||||||
Please note that:
|
Please note that:
|
||||||
|
|
||||||
* There can only be one "now" topic at a time. If multiple topics are
|
* There can only be one "now" discussion topic at a time. If multiple
|
||||||
discussed at the same time in various corners of the room, they should
|
topics are discussed at the same time in various corners of the room,
|
||||||
all be specified in a single "now" command.
|
they should all be specified in a single "now" command.
|
||||||
|
|
||||||
* In order to ensure that information is current, entering a "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.
|
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
|
name. The foreground is always white. Colors can be specified in any
|
||||||
form supported by the CSS attribute background-color.
|
form supported by the CSS attribute background-color.
|
||||||
|
|
||||||
|
@ -50,10 +50,10 @@ Example::
|
||||||
#oslo color #42f4c5
|
#oslo color #42f4c5
|
||||||
#oslo next after lunch we plan to discuss auto-generating config reference docs
|
#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::
|
command::
|
||||||
|
|
||||||
#ROOMNAME clean
|
#TRACK clean
|
||||||
|
|
||||||
|
|
||||||
Admin commands
|
Admin commands
|
||||||
|
@ -62,19 +62,19 @@ Admin commands
|
||||||
You have to be a channel operator (+o) to use admin commands.
|
You have to be a channel operator (+o) to use admin commands.
|
||||||
|
|
||||||
~list
|
~list
|
||||||
List available room names
|
List available track names
|
||||||
|
|
||||||
~add ROOM [ROOM..]
|
~add TRACK [TRACK..]
|
||||||
Add new room name(s)
|
Add new track(s)
|
||||||
|
|
||||||
~del ROOM [ROOM..]
|
~del TRACK [TRACK..]
|
||||||
Deletes room name(s)
|
Deletes track(s)
|
||||||
|
|
||||||
~clean ROOM [ROOM..]
|
~clean TRACK [TRACK..]
|
||||||
Removes active entries for specified room(s)
|
Removes active entries for specified track(s)
|
||||||
|
|
||||||
~wipe
|
~wipe
|
||||||
Resets the database entirely (removes all defined rooms and entries)
|
Resets the database entirely (removes all defined tracks and topics)
|
||||||
|
|
||||||
|
|
||||||
Local testing
|
Local testing
|
||||||
|
@ -98,8 +98,9 @@ In one terminal, run the bot::
|
||||||
|
|
||||||
tox -evenv -- ptgbot -d config.json
|
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
|
#swift now discussing ring placement
|
||||||
|
|
||||||
(note, the bot currently only takes commands from Freenode identified users)
|
(note, the bot currently only takes commands from Freenode identified users)
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
|
|
||||||
<script id="PTGtemplate" type="text/x-handlebars-template">
|
<script id="PTGtemplate" type="text/x-handlebars-template">
|
||||||
<style>
|
<style>
|
||||||
{{#each colors as |color room|}}
|
{{#each colors as |color track|}}
|
||||||
.{{room}} {
|
.{{track}} {
|
||||||
background-color: {{color}};
|
background-color: {{color}};
|
||||||
}
|
}
|
||||||
{{/each}}
|
{{/each}}
|
||||||
|
@ -27,12 +27,12 @@
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"><h3 class="panel-title">Currently playing...</h3></div>
|
<div class="panel-heading"><h3 class="panel-title">Currently playing...</h3></div>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
{{#each rooms as |room| }}
|
{{#each tracks as |track| }}
|
||||||
{{#if (lookup @root.now room) }}
|
{{#if (lookup @root.now track) }}
|
||||||
<tr>
|
<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>{{#hashtag}}{{lookup @root.now room}}{{/hashtag}}</td>
|
<td>{{#hashtag}}{{lookup @root.now track}}{{/hashtag}}</td>
|
||||||
<td>{{lookup @root.location room}}</td>
|
<td>{{lookup @root.location track}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{else}}
|
{{else}}
|
||||||
|
@ -43,12 +43,12 @@
|
||||||
<div class="panel panel-default">
|
<div class="panel panel-default">
|
||||||
<div class="panel-heading"><h3 class="panel-title">Coming up next...</h3></div>
|
<div class="panel-heading"><h3 class="panel-title">Coming up next...</h3></div>
|
||||||
<table class="table">
|
<table class="table">
|
||||||
{{#each rooms as |room| }}
|
{{#each tracks as |track| }}
|
||||||
{{#if (lookup @root.next room) }}
|
{{#if (lookup @root.next track) }}
|
||||||
<tr>
|
<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>
|
<td>
|
||||||
{{#each (lookup @root.next room) as |item|}}
|
{{#each (lookup @root.next track) as |item|}}
|
||||||
{{#hashtag}}{{item}}{{/hashtag}} <br/>
|
{{#hashtag}}{{item}}{{/hashtag}} <br/>
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</td>
|
</td>
|
||||||
|
@ -59,7 +59,7 @@
|
||||||
{{/each}}
|
{{/each}}
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</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>
|
</script>
|
||||||
|
|
||||||
|
|
|
@ -89,15 +89,15 @@ class PTGBot(irc.bot.SingleServerIRCBot):
|
||||||
|
|
||||||
def usage(self, channel):
|
def usage(self, channel):
|
||||||
self.send(channel,
|
self.send(channel,
|
||||||
"Format is '#ROOMNAME [ now ... | next ... "
|
"Format is '#TRACK [ now ... | next ... "
|
||||||
"| location ... | clean ]'")
|
"| location ... | clean ]'")
|
||||||
|
|
||||||
def send_room_list(self, channel):
|
def send_track_list(self, channel):
|
||||||
rooms = self.data.list_rooms()
|
tracks = self.data.list_tracks()
|
||||||
if rooms:
|
if tracks:
|
||||||
self.send(channel, "Active rooms: %s" % str.join(' ', rooms))
|
self.send(channel, "Active tracks: %s" % str.join(' ', tracks))
|
||||||
else:
|
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):
|
def on_pubmsg(self, c, e):
|
||||||
if not self.identify_msg_cap:
|
if not self.identify_msg_cap:
|
||||||
|
@ -121,24 +121,24 @@ class PTGBot(irc.bot.SingleServerIRCBot):
|
||||||
self.usage(chan)
|
self.usage(chan)
|
||||||
return
|
return
|
||||||
|
|
||||||
room = words[0][1:].lower()
|
track = words[0][1:].lower()
|
||||||
if not self.data.is_room_valid(room):
|
if not self.data.is_track_valid(track):
|
||||||
self.send(chan, "%s: unknown room '%s'" % (nick, room))
|
self.send(chan, "%s: unknown track '%s'" % (nick, track))
|
||||||
self.send_room_list(chan)
|
self.send_track_list(chan)
|
||||||
return
|
return
|
||||||
|
|
||||||
adverb = words[1].lower()
|
adverb = words[1].lower()
|
||||||
session = str.join(' ', words[2:])
|
session = str.join(' ', words[2:])
|
||||||
if adverb == 'now':
|
if adverb == 'now':
|
||||||
self.data.add_now(room, session)
|
self.data.add_now(track, session)
|
||||||
elif adverb == 'next':
|
elif adverb == 'next':
|
||||||
self.data.add_next(room, session)
|
self.data.add_next(track, session)
|
||||||
elif adverb == 'clean':
|
elif adverb == 'clean':
|
||||||
self.data.clean_rooms([room])
|
self.data.clean_tracks([track])
|
||||||
elif adverb == 'color':
|
elif adverb == 'color':
|
||||||
self.data.add_color(room, session)
|
self.data.add_color(track, session)
|
||||||
elif adverb == 'location':
|
elif adverb == 'location':
|
||||||
self.data.add_location(room, session)
|
self.data.add_location(track, session)
|
||||||
else:
|
else:
|
||||||
self.send(chan, "%s: unknown directive '%s'" % (nick, adverb))
|
self.send(chan, "%s: unknown directive '%s'" % (nick, adverb))
|
||||||
self.usage(chan)
|
self.usage(chan)
|
||||||
|
@ -153,13 +153,13 @@ class PTGBot(irc.bot.SingleServerIRCBot):
|
||||||
if command == 'wipe':
|
if command == 'wipe':
|
||||||
self.data.wipe()
|
self.data.wipe()
|
||||||
elif command == 'list':
|
elif command == 'list':
|
||||||
self.send_room_list(chan)
|
self.send_track_list(chan)
|
||||||
return
|
return
|
||||||
elif command in ('clean', 'add', 'del'):
|
elif command in ('clean', 'add', 'del'):
|
||||||
if len(words) < 2:
|
if len(words) < 2:
|
||||||
self.send(chan, "this command takes one or more arguments")
|
self.send(chan, "this command takes one or more arguments")
|
||||||
return
|
return
|
||||||
getattr(self.data, command + '_rooms')(words[1:])
|
getattr(self.data, command + '_tracks')(words[1:])
|
||||||
else:
|
else:
|
||||||
self.send(chan, "%s: unknown command '%s'" % (nick, command))
|
self.send(chan, "%s: unknown command '%s'" % (nick, command))
|
||||||
return
|
return
|
||||||
|
|
64
ptgbot/db.py
64
ptgbot/db.py
|
@ -21,7 +21,7 @@ import datetime
|
||||||
|
|
||||||
class PTGDataBase():
|
class PTGDataBase():
|
||||||
|
|
||||||
BASE = {'rooms': [], 'now': {}, 'next': {}, 'colors': {},
|
BASE = {'tracks': [], 'now': {}, 'next': {}, 'colors': {},
|
||||||
'location': {}}
|
'location': {}}
|
||||||
|
|
||||||
def __init__(self, filename):
|
def __init__(self, filename):
|
||||||
|
@ -33,52 +33,52 @@ class PTGDataBase():
|
||||||
self.data = self.BASE
|
self.data = self.BASE
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def add_now(self, room, session):
|
def add_now(self, track, session):
|
||||||
self.data['now'][room] = session
|
self.data['now'][track] = session
|
||||||
if room in self.data['next']:
|
if track in self.data['next']:
|
||||||
del self.data['next'][room]
|
del self.data['next'][track]
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def add_color(self, room, color):
|
def add_color(self, track, color):
|
||||||
self.data['colors'][room] = color
|
self.data['colors'][track] = color
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def add_location(self, room, location):
|
def add_location(self, track, location):
|
||||||
if 'location' not in self.data:
|
if 'location' not in self.data:
|
||||||
self.data['location'] = {}
|
self.data['location'] = {}
|
||||||
self.data['location'][room] = location
|
self.data['location'][track] = location
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def add_next(self, room, session):
|
def add_next(self, track, session):
|
||||||
if room not in self.data['next']:
|
if track not in self.data['next']:
|
||||||
self.data['next'][room] = []
|
self.data['next'][track] = []
|
||||||
self.data['next'][room].append(session)
|
self.data['next'][track].append(session)
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def is_room_valid(self, room):
|
def is_track_valid(self, track):
|
||||||
return room in self.data['rooms']
|
return track in self.data['tracks']
|
||||||
|
|
||||||
def list_rooms(self):
|
def list_tracks(self):
|
||||||
return sorted(self.data['rooms'])
|
return sorted(self.data['tracks'])
|
||||||
|
|
||||||
def add_rooms(self, rooms):
|
def add_tracks(self, tracks):
|
||||||
for room in rooms:
|
for track in tracks:
|
||||||
if room not in self.data['rooms']:
|
if track not in self.data['tracks']:
|
||||||
self.data['rooms'].append(room)
|
self.data['tracks'].append(track)
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def del_rooms(self, rooms):
|
def del_tracks(self, tracks):
|
||||||
for room in rooms:
|
for track in tracks:
|
||||||
if room in self.data['rooms']:
|
if track in self.data['tracks']:
|
||||||
self.data['rooms'].remove(room)
|
self.data['tracks'].remove(track)
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def clean_rooms(self, rooms):
|
def clean_tracks(self, tracks):
|
||||||
for room in rooms:
|
for track in tracks:
|
||||||
if room in self.data['now']:
|
if track in self.data['now']:
|
||||||
del self.data['now'][room]
|
del self.data['now'][track]
|
||||||
if room in self.data['next']:
|
if track in self.data['next']:
|
||||||
del self.data['next'][room]
|
del self.data['next'][track]
|
||||||
self.save()
|
self.save()
|
||||||
|
|
||||||
def wipe(self):
|
def wipe(self):
|
||||||
|
@ -88,6 +88,6 @@ class PTGDataBase():
|
||||||
def save(self):
|
def save(self):
|
||||||
timestamp = datetime.datetime.now()
|
timestamp = datetime.datetime.now()
|
||||||
self.data['timestamp'] = '{:%Y-%m-%d %H:%M:%S}'.format(timestamp)
|
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:
|
with open(self.filename, 'w') as fp:
|
||||||
json.dump(self.data, fp)
|
json.dump(self.data, fp)
|
||||||
|
|
Loading…
Reference in New Issue