actions['multi_static_select'] = {"*": multi_static_select}
def edit(turb, body, args):
+
"""Implementation of the `/edit` command
To edit the puzzle for the current channel.
commands["/state"] = state
+def tag(turb, body, args):
+ """Implementation of the `/tag` command.
+
+ Arg is either a tag to add (optionally prefixed with '+'), or if
+ prefixed with '-' is a tag to remove.
+ """
+
+ if not args:
+ return bot_reply("Usage: `/tag [+]TAG_TO_ADD` "
+ + "or `/tag -TAG_TO_REMOVE`.")
+
+ channel_id = body['channel_id'][0]
+
+ old_puzzle = puzzle_for_channel(turb, channel_id)
+
+ if not old_puzzle:
+ return bot_reply(
+ "Sorry, the /tag command only works in a puzzle channel")
+
+ if args[0] == '-':
+ tag = args[1:]
+ action = 'remove'
+ else:
+ tag = args
+ if tag[0] == '+':
+ tag = tag[1:]
+ action = 'add'
+
+ # Force tag to all uppercase
+ tag = tag.upper()
+
+ # Reject a tag that is not alphabetic or underscore A-Z_
+ if not re.match(r'^[A-Z_]*$', tag):
+ return bot_reply("Sorry, tags can only contain letters "
+ + "and the underscore character.")
+
+ if action == 'remove':
+ if 'tags' not in old_puzzle or tag not in old_puzzle['tags']:
+ return bot_reply("Nothing to do. This puzzle is not tagged "
+ + "with the tag: {}".format(tag))
+ else:
+ if 'tags' in old_puzzle and tag in old_puzzle['tags']:
+ return bot_reply("Nothing to do. This puzzle is already tagged "
+ + "with the tag: {}".format(tag))
+
+ # OK. Error checking is done. Let's get to work
+
+ # Make a copy of the puzzle object
+ puzzle = old_puzzle.copy()
+
+ if action == 'remove':
+ puzzle['tags'] = [t for t in puzzle['tags'] if t != tag]
+ else:
+ if 'tags' not in puzzle:
+ puzzle['tags'] = [tag]
+ else:
+ puzzle['tags'].append(tag)
+
+ turb.table.put_item(Item=puzzle)
+
+ puzzle_update_channel_and_sheet(turb, puzzle, old_puzzle=old_puzzle)
+
+ return lambda_ok
+
+commands["/tag"] = tag
+
def solved(turb, body, args):
"""Implementation of the /solved command
url = puzzle.get('url', None)
sheet_url = puzzle.get('sheet_url', None)
state = puzzle.get('state', None)
+ tags = puzzle.get('tags', [])
status_emoji = ''
solution_str = ''
state_str = ''
if state:
- state_str = "\n{}".format(state)
+ state_str = " State: {}".format(state)
+
+ tags_str = ''
+ if tags:
+ tags_str = " Tags: "+" ".join(["`{}`".format(tag) for tag in tags])
+
+ extra_str = ''
+ if state_str or tags_str:
+ extra_str = "\n{}{}".format(tags_str, state_str)
rounds_str = ''
if include_rounds and 'rounds' in puzzle:
channel_url(channel_id), name,
solution_str,
', '.join(links), rounds_str,
- state_str
+ extra_str
)
# Combining hunt ID and puzzle ID together here is safe because
if len(links):
topic += "({})".format(', '.join(links))
+ tags = puzzle.get('tags', [])
+ if tags:
+ topic += " {}".format(" ".join(["`{}`".format(t) for t in tags]))
+
state = puzzle.get('state', None)
if state:
topic += " {}".format(state)