puzzle['type'] = 'meta'
else:
puzzle['type'] = 'plain'
- rounds = [option['value'] for option in
- state['rounds']['rounds']['selected_options']]
- if rounds:
- puzzle['rounds'] = rounds
+ if 'rounds' in state:
+ rounds = [option['value'] for option in
+ state['rounds']['rounds']['selected_options']]
+ if rounds:
+ puzzle['rounds'] = rounds
new_rounds = state['new_rounds']['new_rounds']['value']
puzzle_state = state['state']['state']['value']
if puzzle_state:
puzzle['solution'] = []
solution = state['solution']['solution']['value']
if solution:
- puzzle['solution'] = [
+ # Construct a list from a set to avoid any duplicates
+ puzzle['solution'] = list({
sol.strip() for sol in solution.split(',')
- ]
+ })
# Verify that there's a solution if the puzzle is mark solved
if puzzle['status'] == 'solved' and not puzzle['solution']:
puzzle['SK'])
# If we are changing puzzle type (meta -> plain or plain -> meta)
- # the the sort key has to change, so compute the new one and delete
+ # then the sort key has to change, so compute the new one and delete
# the old item from the database.
#
# XXX: We should really be using a transaction here to combine the
return lambda_ok
-actions['button']['new_hunt'] = new_hunt
+actions['button']['new_hunt'] = new_hunt_button
def new_hunt_submission(turb, payload, metadata):
"""Handler for the user submitting the new hunt modal
return bot_reply("Sorry, this channel doesn't appear to "
+ "be a hunt or puzzle channel")
+ # We used puzzle (if available) to select the initial round(s)
+ puzzle = puzzle_for_channel(turb, channel_id)
+ initial_rounds = None
+ if puzzle:
+ initial_rounds=puzzle.get("rounds", None)
+
round_options = hunt_rounds(turb, hunt['hunt_id'])
if len(round_options):
round_options_block = [
multi_select_block("Round(s)", "rounds",
"Existing round(s) this puzzle belongs to",
- round_options)
+ round_options,
+ initial_options=initial_rounds)
]
else:
round_options_block = []
# Set the status and solution fields in the database
puzzle['status'] = 'solved'
- puzzle['solution'].append(args)
+
+ # Don't append a duplicate solution
+ if args not in puzzle['solution']:
+ puzzle['solution'].append(args)
if 'state' in puzzle:
del puzzle['state']
turb.table.put_item(Item=puzzle)
# Report the solution to the puzzle's channel
slack_send_message(
turb.slack_client, channel_id,
- "Puzzle mark solved by <@{}>: `{}`".format(user_id, args))
+ "Puzzle marked solved by <@{}>: `{}`".format(user_id, args))
# Also report the solution to the hunt channel
hunt = find_hunt_for_hunt_id(turb, puzzle['hunt_id'])
commands["/solved"] = solved
+def delete(turb, body, args):
+ """Implementation of the /delete command
+
+ The argument to this command is the ID of a hunt.
+
+ The command will report an error if the specified hunt is active.
+
+ If the hunt is inactive, this command will archive all channels
+ from the hunt.
+ """
+
+ if not args:
+ return bot_reply("Error, no hunt provided. Usage: `/delete HUNT_ID`")
+
+ hunt_id = args
+ hunt = find_hunt_for_hunt_id(turb, hunt_id)
+
+ if not hunt:
+ return bot_reply("Error, no hunt named \"{}\" exists.".format(hunt_id))
+
+ if hunt['active']:
+ return bot_reply(
+ "Error, refusing to delete active hunt \"{}\".".format(hunt_id)
+ )
+
+ if hunt['hunt_id'] != hunt_id:
+ return bot_reply(
+ "Error, expected hunt ID of \"{}\" but found \"{}\".".format(
+ hunt_id, hunt['hunt_id']
+ )
+ )
+
+ puzzles = hunt_puzzles_for_hunt_id(turb, hunt_id)
+
+ for puzzle in puzzles:
+ channel_id = puzzle['channel_id']
+ turb.slack_client.conversations_archive(channel=channel_id)
+
+ turb.slack_client.conversations_archive(channel=hunt['channel_id'])
+
+ return lambda_ok
+
+commands["/delete"] = delete
+
def hunt(turb, body, args):
"""Implementation of the /hunt command
blocks = hunt_blocks(turb, hunt, puzzle_status=status, search_terms=terms)
- requests.post(response_url,
- json = { 'blocks': blocks },
- headers = {'Content-type': 'application/json'}
- )
+ for block in blocks:
+ if len(block) > 100:
+ block = block[:100]
+ requests.post(response_url,
+ json = { 'blocks': block },
+ headers = {'Content-type': 'application/json'}
+ )
return lambda_ok
limit_to_rounds=puzzle.get('rounds', [])
)
- requests.post(response_url,
- json = { 'blocks': blocks },
- headers = {'Content-type': 'application/json'}
- )
+ for block in blocks:
+ if len(block) > 100:
+ block = block[:100]
+ requests.post(response_url,
+ json = { 'blocks': block },
+ headers = {'Content-type': 'application/json'}
+ )
return lambda_ok