]> git.cworth.org Git - turbot/blobdiff - turbot/hunt.py
Put a message into the channel when a user edits a puzzle
[turbot] / turbot / hunt.py
index 6d44662b3d44f53e8ca5c654d4c5ca6177e09673..ccab28daa4e004de56229291de50dc7b2b50e926 100644 (file)
@@ -1,6 +1,6 @@
 from turbot.blocks import section_block, text_block, divider_block
 from turbot.round import round_blocks
-from turbot.puzzle import puzzle_block
+from turbot.puzzle import puzzle_blocks, puzzle_matches_all
 from turbot.channel import channel_url
 from boto3.dynamodb.conditions import Key
 
@@ -23,16 +23,26 @@ def find_hunt_for_hunt_id(turb, hunt_id):
     else:
         return None
 
-def hunt_blocks(turb, hunt, puzzle_status='unsolved'):
+def hunt_blocks(turb, hunt, puzzle_status='unsolved', search_terms=[]):
     """Generate Slack blocks for a hunt
 
     The hunt argument should be a dictionary as returned from the
     database.
 
-    Option 'puzzle_status' indicates which puzzles to include. If
-    either 'solved' or 'unsolved' only puzzles with that status from
-    the hunt will be included in the result. If any other value, all
-    puzzles in the hunt will be included.
+    Two optional arguments can be used to filter which puzzles to
+    include in the result:
+
+      puzzle_status: If either 'solved' or 'unsolved' only puzzles
+                     with that status will be included in the
+                     result. If any other value, all puzzles in the
+                     hunt will be considered.
+
+      search_terms: A list of search terms. Only puzzles that match
+                    all of these terms will be included in the
+                    result. A match will be considered on any of
+                    puzzle title, round title, puzzle URL, puzzle
+                    state or solution string. Terms can include
+                    regular expression syntax.
 
     The return value can be used in a Slack command expecting blocks to
     provide all the details of a hunt, (puzzles, their state,
@@ -55,6 +65,12 @@ def hunt_blocks(turb, hunt, puzzle_status='unsolved'):
     # Filter the set of puzzles according the the requested puzzle_status
     if puzzle_status in ('solved', 'unsolved'):
         puzzles = [p for p in puzzles if p['status'] == puzzle_status]
+    else:
+        puzzle_status = 'all'
+
+    if search_terms:
+        puzzles = [puzzle for puzzle in puzzles
+                   if puzzle_matches_all(puzzle, search_terms)]
 
     # Compute the set of rounds across all puzzles
     rounds = set()
@@ -64,12 +80,24 @@ def hunt_blocks(turb, hunt, puzzle_status='unsolved'):
         for round in puzzle['rounds']:
             rounds.add(round)
 
-    hunt_text = "*<{}|{}>*".format(channel_url(channel_id), name)
+    hunt_text = "*{} puzzles in hunt <{}|{}>*".format(
+        puzzle_status.capitalize(),
+        channel_url(channel_id),
+        name
+    )
+    if search_terms:
+        quoted_terms = ['`{}`'.format(term) for term in search_terms]
+        hunt_text += " matching {}".format(" AND ".join(quoted_terms))
 
     blocks = [
         section_block(text_block(hunt_text)),
     ]
 
+    if not len(puzzles):
+        blocks += [
+            section_block(text_block("No puzzles found."))
+        ]
+
     # Construct blocks for each round
     for round in rounds:
         blocks += round_blocks(round, puzzles)
@@ -77,10 +105,10 @@ def hunt_blocks(turb, hunt, puzzle_status='unsolved'):
     # Also blocks for any puzzles not in any round
     stray_puzzles = [puzzle for puzzle in puzzles if 'rounds' not in puzzle]
     if len(stray_puzzles):
-        stray_text = "*Puzzles with no asigned round*"
+        stray_text = "*Puzzles with no assigned round*"
         blocks.append(section_block(text_block(stray_text)))
         for puzzle in stray_puzzles:
-            blocks.append(puzzle_block(puzzle))
+            blocks += puzzle_blocks(puzzle)
 
     blocks.append(divider_block())