]> git.cworth.org Git - turbot/blobdiff - turbot/puzzle.py
Update TODO file now that puzzle edit dialog has been edited
[turbot] / turbot / puzzle.py
index 8f044b1ca7996fb6f24793639c84621d6413bebd..b6e78833098f9ed2c4d5251a82400d01941c9b07 100644 (file)
@@ -1,8 +1,29 @@
-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
 
@@ -24,7 +45,7 @@ def find_puzzle_for_url(turb, hunt_id, 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
@@ -67,14 +88,24 @@ def puzzle_block(puzzle):
         ', '.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)
@@ -87,22 +118,28 @@ def puzzle_matches_one(puzzle, pattern):
             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.
     """