]> git.cworth.org Git - turbot/commitdiff
Rework code to map channel IDs to hunt or puzzle objects from the database
authorCarl Worth <cworth@cworth.org>
Thu, 31 Dec 2020 22:43:07 +0000 (14:43 -0800)
committerCarl Worth <cworth@cworth.org>
Fri, 1 Jan 2021 05:46:27 +0000 (21:46 -0800)
The old functions were named things like channel_is_puzzle,
channel_is_hunt, and fund_hunt_for_channel. These were still expecting
the old multi-table database schema so they were broken, (as was all
functionality built on top of them such as the /state and /solved
commands).

The new functions are built on the all-one-table database schema, so
should actually work again. They also have a cleaner interface in that
they only rely only on channel ID (and never put any special stock in
the channel name). Instead of doing magic with the channel name, the
code looks up the hunt_id from the database entry for a puzzle as
needed.

The new functions are named puzzle_for_channel and hunt_for_channel
and are implemented on top of a common, internal function:
db_entry_for_channel.

turbot/interaction.py

index b6fa7d7e12efc8cfd5c4809d3ea5ee91ef98413b..0d2743e20fe3ddc8a5703d71435cf99f75d02b33 100644 (file)
@@ -249,46 +249,50 @@ def get_table_item(turb, table_name, key, value):
     else:
         return (None, None)
 
-def channel_is_puzzle(turb, channel_id, channel_name):
-    """Given a channel ID/name return the database item for the puzzle
+def db_entry_for_channel(turb, channel_id):
+    """Given a channel ID return the database item for this channel
 
-    If this channel is a puzzle, this function returns a tuple:
+    If this channel is a registered hunt or puzzle channel, return the
+    corresponding row from the database for this channel. Otherwise,
+    return None.
 
-        (puzzle, table)
+    Note: If you need to specifically ensure that the channel is a
+    puzzle or a hunt, please call puzzle_for_channel or
+    hunt_for_channel respectively.
+    """
 
-    Where puzzle is dict filled with database entries, and table is a
-    database table that can be used to update the puzzle in the
-    database.
+    response = turb.table.query(
+        IndexName = "channel_id_index",
+        KeyConditionExpression=Key("channel_id").eq(channel_id)
+    )
 
-    Otherwise, this function returns (None, None)."""
+    if response['Count'] == 0:
+        return None
 
-    hunt_id = channel_name.split('-')[0]
+    return response['Items'][0]
 
-    # Not a puzzle channel if there is no hyphen in the name
-    if hunt_id == channel_name:
-        return (None, None)
 
-    return get_table_item(turb, hunt_id, 'channel_id', channel_id)
+def puzzle_for_channel(turb, channel_id):
 
-def channel_is_hunt(turb, channel_id):
+    """Given a channel ID return the puzzle from the database for this channel
 
-    """Given a channel ID/name return the database item for the hunt
+    If the given channel_id is a puzzle's channel, this function
+    returns a dict filled with the attributes from the puzzle's entry
+    in the database.
 
-    Returns a dict (filled with database entries) if there is a hunt
-    for this channel, otherwise returns None."""
+    Otherwise, this function returns None.
+    """
 
-    response = turb.table.query(
-        IndexName = "channel_id_index",
-        KeyConditionExpression=Key("channel_id").eq(channel_id)
-    )
+    entry = db_entry_for_channel(turb, channel_id)
 
-    if 'Items' not in response:
+    if entry and entry['SK'].startswith('puzzle-'):
+        return entry
+    else:
         return None
 
-    return response['Items'][0]
+def hunt_for_channel(turb, channel_id):
 
-def find_hunt_for_channel(turb, channel_id, channel_name):
-    """Given a channel ID/name find the id/name of the hunt for this channel
+    """Given a channel ID return the hunt from the database for this channel
 
     This works whether the original channel is a primary hunt channel,
     or if it is one of the channels of a puzzle belonging to the hunt.
@@ -296,19 +300,21 @@ def find_hunt_for_channel(turb, channel_id, channel_name):
     Returns None if channel does not belong to a hunt, otherwise a
     dictionary with all fields from the hunt's row in the table,
     (channel_id, active, hunt_id, name, url, sheet_url, etc.).
-
     """
 
-    hunt = channel_is_hunt(turb, channel_id)
+    entry = db_entry_for_channel(turb, channel_id)
 
-    if hunt:
-        return hunt
+    # We're done if this channel doesn't exist in the database at all
+    if not entry:
+        return None
 
-    # So we're not a hunt channel, let's look to see if we are a
-    # puzzle channel with a hunt-id prefix.
-    hunt_id = channel_name.split('-')[0]
+    # Also done if this channel is a hunt channel
+    if entry['SK'].startswith('hunt-'):
+        return entry
 
-    return find_hunt_for_hunt_id(turb, hunt_id)
+    # Otherwise, (the channel is in the database, but is not a hunt),
+    # we expect this to be a puzzle channel instead
+    return find_hunt_for_hunt_id(turb, entry['hunt_id'])
 
 def puzzle(turb, body, args):
     """Implementation of the /puzzle command
@@ -317,12 +323,9 @@ def puzzle(turb, body, args):
     a modal dialog for user input instead)."""
 
     channel_id = body['channel_id'][0]
-    channel_name = body['channel_name'][0]
     trigger_id = body['trigger_id'][0]
 
-    hunt = find_hunt_for_channel(turb,
-                                 channel_id,
-                                 channel_name)
+    hunt = hunt_for_channel(turb, channel_id)
 
     if not hunt:
         return bot_reply("Sorry, this channel doesn't appear to "
@@ -437,16 +440,15 @@ def state(turb, body, args):
     stand or what's needed."""
 
     channel_id = body['channel_id'][0]
-    channel_name = body['channel_name'][0]
 
-    (puzzle, table) = channel_is_puzzle(turb, channel_id, channel_name)
+    puzzle = puzzle_for_channel(turb, channel_id)
 
     if not puzzle:
         return bot_reply("Sorry, this is not a puzzle channel.")
 
     # Set the state field in the database
     puzzle['state'] = args
-    table.put_item(Item=puzzle)
+    turb.table.put_item(Item=puzzle)
 
     set_channel_topic(turb, puzzle)
 
@@ -460,10 +462,9 @@ def solved(turb, body, args):
     The args string should be a confirmed solution."""
 
     channel_id = body['channel_id'][0]
-    channel_name = body['channel_name'][0]
     user_name = body['user_name'][0]
 
-    (puzzle, table) = channel_is_puzzle(turb, channel_id, channel_name)
+    puzzle = puzzle_for_channel(turb, channel_id)
 
     if not puzzle:
         return bot_reply("Sorry, this is not a puzzle channel.")
@@ -471,7 +472,7 @@ def solved(turb, body, args):
     # Set the status and solution fields in the database
     puzzle['status'] = 'solved'
     puzzle['solution'].append(args)
-    table.put_item(Item=puzzle)
+    turb.table.put_item(Item=puzzle)
 
     # Report the solution to the puzzle's channel
     slack_send_message(