]> git.cworth.org Git - turbot/commitdiff
Add find_puzzle_for_puzzle_id
authorCarl Worth <cworth@cworth.org>
Tue, 12 Jan 2021 01:53:36 +0000 (17:53 -0800)
committerCarl Worth <cworth@cworth.org>
Tue, 12 Jan 2021 02:02:18 +0000 (18:02 -0800)
This exists so that the puzzle-creation code can ensure that it's not
creating a puzzle with the same puzzle_id as an existing
puzzle. Previously, Turbot was just relying on Slack to guarantee
uniqueness, (which worked when channel names were just made from
hunt_id and puzzle_id).

But more recently, the channel names have round names in them as
well. This set up a possible collision where two puzzle with the same
puzzle_id could be created but with different channel names, (if the
two puzzles were placed in different rounds). To be able to fix this
bug we need this query to be able to find a puzzle by means of using
the puzzle_id.

This does require a new index on the database, so that's here too,
(and we're nuking our database to be able to roll this out).

turbot/interaction.py
turbot/puzzle.py

index 546e59a70a25728b1dcdee92d60f6d5730687fda..a3fe496c81adb8dc1ceca981c04d3d16a911058e 100644 (file)
@@ -572,7 +572,8 @@ def new_hunt_submission(turb, payload, metadata):
                 {'AttributeName': 'SK', 'AttributeType': 'S'},
                 {'AttributeName': 'channel_id', 'AttributeType': 'S'},
                 {'AttributeName': 'is_hunt', 'AttributeType': 'S'},
-                {'AttributeName': 'url', 'AttributeType': 'S'}
+                {'AttributeName': 'url', 'AttributeType': 'S'},
+                {'AttributeName': 'puzzle_id', 'AttributeType': 'S'}
             ],
             ProvisionedThroughput={
                 'ReadCapacityUnits': 5,
@@ -616,6 +617,16 @@ def new_hunt_submission(turb, payload, metadata):
                     'Projection': {
                         'ProjectionType': 'ALL'
                     }
+                },
+                {
+                    'IndexName': 'puzzle_id_index',
+                    'KeySchema': [
+                        {'AttributeName': 'hunt_id', 'KeyType': 'HASH'},
+                        {'AttributeName': 'puzzle_id', 'KeyType': 'RANGE'},
+                    ],
+                    'Projection': {
+                        'ProjectionType': 'ALL'
+                    }
                 }
             ]
         )
index 3a0e312720aad3ad6c76c39abf89e36ab6691f8a..1d1fda85bff975dea6adea33942a5eeaaece7914 100644 (file)
@@ -32,6 +32,34 @@ def find_puzzle_for_sort_key(turb, hunt_id, sort_key):
     else:
         return None
 
+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.
+
+    Note: The sort_key is a modified version of the puzzle_id, (used
+    to make metapuzzles appear in the ordering before non-metapuzzles).
+    If you've been handed a sort_key, then looking up a puzzle by
+    sort_key is the right thing to do. But if you instead have just
+    a puzzle_id, see find_puzzle_for_puzzle_id rather than trying
+    to convert the puzzle_id into a sort_key to use this function.
+    """
+
+    response = turb.table.query(
+        IndexName='puzzle_id_index',
+        KeyConditionExpression=(
+            Key('hunt_id').eq(hunt_id) &
+            Key('puzzle_id').eq(puzzle_id)
+        )
+    )
+
+    if response['Count'] == 0:
+        return None
+
+    return response['Items'][0]
+
 def find_puzzle_for_url(turb, hunt_id, url):
     """Given a hunt_id and URL, return the puzzle with that URL