From 8db59b56dad42087514e933591eadb4c974f1518 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Thu, 31 Dec 2020 14:43:07 -0800 Subject: [PATCH] Rework code to map channel IDs to hunt or puzzle objects from the database 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 | 87 ++++++++++++++++++++++--------------------- 1 file changed, 44 insertions(+), 43 deletions(-) diff --git a/turbot/interaction.py b/turbot/interaction.py index b6fa7d7..0d2743e 100644 --- a/turbot/interaction.py +++ b/turbot/interaction.py @@ -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( -- 2.43.0