if 'Item' in response:
return (response['Item'], table)
else:
- return None
+ return (None, None)
def channel_is_puzzle(turb, channel_id, channel_name):
"""Given a channel ID/name return the database item for the puzzle
Returns a tuple of (hunt_name, hunt_id) or (None, None)."""
- (hunt, hunts_table) = channel_is_hunt(turb, channel_id)
+ (hunt, _) = channel_is_hunt(turb, channel_id)
if hunt:
return (hunt['hunt_id'], hunt['name'])
# puzzle channel with a hunt-id prefix.
hunt_id = channel_name.split('-')[0]
+ hunts_table = turb.db.Table("hunts")
+
response = hunts_table.scan(
FilterExpression='hunt_id = :hunt_id',
ExpressionAttributeValues={':hunt_id': hunt_id}
)
- if 'Items' in response:
+ if 'Items' in response and len(response['Items']):
item = response['Items'][0]
return (item['hunt_id'], item['name'])
# Validate that the puzzle_id contains no invalid characters
if not re.match(valid_id_re, puzzle_id):
return submission_error("puzzle_id",
- "Puzzle ID can only contain lowercase letters, "
- + "numbers, and underscores")
+ "Puzzle ID can only contain lowercase letters,"
+ + " numbers, and underscores")
# Create a channel for the puzzle
hunt_dash_channel = "{}-{}".format(hunt_id, puzzle_id)
return lambda_ok
commands["/state"] = state
+
+def solved(turb, body, args):
+ """Implementation of the /solved command
+
+ The args string should be a confirmed solution."""
+
+ channel_id = body['channel_id'][0]
+ channel_name = body['channel_name'][0]
+
+ (puzzle, table) = channel_is_puzzle(turb, channel_id, channel_name)
+
+ if not puzzle:
+ return bot_reply("Sorry, this is not a puzzle channel.")
+
+ # Set the status and solution fields in the database
+ puzzle['status'] = 'solved'
+ puzzle['solution'].append(args)
+ table.put_item(Item=puzzle)
+
+ return lambda_ok
+
+commands["/solved"] = solved