-from turbot.blocks import section_block, text_block
+from turbot.blocks import (
+ section_block, text_block, button_block, accessory_block
+)
from turbot.channel import channel_url
from boto3.dynamodb.conditions import Key
import re
+def find_puzzle_for_puzzle_id(turb, hunt_id, puzzle_id):
+ """Given a hunt_id and puzzle_id, return that puzzle
+
+ Returns None if no puzzle with the given hunt_id and puzzle_id
+ exists in the database, otherwise a dictionary with all fields
+ from the puzzle's row in the database.
+ """
+
+ response = turb.table.get_item(
+ Key={
+ 'hunt_id': hunt_id,
+ 'SK': 'puzzle-{}'.format(puzzle_id)
+ })
+
+ if 'Item' in response:
+ return response['Item']
+ else:
+ return None
+
def find_puzzle_for_url(turb, hunt_id, url):
"""Given a hunt_id and URL, return the puzzle with that URL
return response['Items'][0]
-def puzzle_block(puzzle):
+def puzzle_blocks(puzzle):
"""Generate Slack blocks for a puzzle
The puzzle argument should be a dictionary as returned from the
', '.join(links), state_str
)
- return section_block(text_block(puzzle_text))
+ # Combining hunt ID and puzzle ID together here is safe because
+ # both IDs are restricted to not contain a hyphen, (see
+ # valid_id_re in interaction.py)
+ hunt_and_puzzle = "{}-{}".format(puzzle['hunt_id'], puzzle['puzzle_id'])
+
+ return [
+ accessory_block(
+ section_block(text_block(puzzle_text)),
+ button_block("✏", "edit_puzzle", hunt_and_puzzle)
+ )
+ ]
def puzzle_matches_one(puzzle, pattern):
"""Returns True if this puzzle matches the given string (regexp)
A match will be considered on any of puzzle title, round title,
- puzzle URL, or solution string. The string can include regular
- expression syntax. Matching is case insensitive.
+ puzzle URL, puzzle state, or solution string. The string can
+ include regular expression syntax. Matching is case insensitive.
"""
p = re.compile('.*'+pattern+'.*', re.IGNORECASE)
if p.match(round):
return True
- if p.match(puzzle['url']):
- return True
+ if 'url' in puzzle:
+ if p.match(puzzle['url']):
+ return True
- for solution in puzzle['solution']:
- if p.match(solution):
+ if 'state' in puzzle:
+ if p.match(puzzle['state']):
return True
+ if 'solution' in puzzle:
+ for solution in puzzle['solution']:
+ if p.match(solution):
+ return True
+
return False
def puzzle_matches_all(puzzle, patterns):
"""Returns True if this puzzle matches all of the given list of patterns
A match will be considered on any of puzzle title, round title,
- puzzle URL, or solution string. All patterns must match the puzzle
- somewhere, (that is, there is an implicit logical AND between
- patterns). Patterns can include regular expression
+ puzzle URL, puzzle state, or solution string. All patterns must
+ match the puzzle somewhere, (that is, there is an implicit logical
+ AND between patterns). Patterns can include regular expression
syntax. Matching is case insensitive.
"""