From 65d277e6962108c5fdfe30cae4d66e4db29ce150 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Fri, 8 Jan 2021 22:38:26 -0800 Subject: [PATCH] Unify code to rename channel, set channel description, and rename sheet With this code, all of those changes are made consistently regardless of whether the change happens from /state, /solved, or a puzzle edit (which could set status to either "solved" or "unsolved"). --- TODO | 9 ++++-- turbot/interaction.py | 69 +++++++------------------------------------ turbot/puzzle.py | 64 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 80 insertions(+), 62 deletions(-) diff --git a/TODO b/TODO index 7d61da5..6b23816 100644 --- a/TODO +++ b/TODO @@ -1,13 +1,13 @@ Ordered punch-list (aiming to complete by 2021-01-08) ----------------------------------------------------- -• Ensure that both spreadsheet and channel are updated in response to - any changes. - • Rename puzzle creation command from /puzzle to /puzzle new • Add new /puzzle giving puzzle status (and including :pencil:) +• Put a message in the puzzle channel when a user edits something + (maybe just spit out the /puzzle output) + • Add new /puzzle edit as a shortcut instead of /puzzle followed by clicking :pencil: @@ -30,6 +30,9 @@ Ordered punch-list (aiming to complete by 2021-01-08) Specifically, this should be "/tag TAG_NAME" or "/tag +TAG_NAME" to add a tag and "/tag -TAG_NAME" to remove a tag. +• Make the /hunt command drop from the database any rounds that have 0 + puzzles in them + Recently-proposed ideas (not yet prioritized) --------------------------------------------- • Set-up an announcements Slack channel that's auto fed by email to a diff --git a/turbot/interaction.py b/turbot/interaction.py index 417066a..0b2f30e 100644 --- a/turbot/interaction.py +++ b/turbot/interaction.py @@ -3,7 +3,12 @@ from turbot.blocks import ( input_block, section_block, text_block, multi_select_block, checkbox_block ) from turbot.hunt import find_hunt_for_hunt_id, hunt_blocks -from turbot.puzzle import find_puzzle_for_url, find_puzzle_for_puzzle_id +from turbot.puzzle import ( + find_puzzle_for_url, + find_puzzle_for_puzzle_id, + puzzle_update_channel_and_sheet, + puzzle_id_from_name +) import turbot.rot import turbot.sheets import turbot.slack @@ -230,14 +235,7 @@ def edit_puzzle_submission(turb, payload, metadata): # We need to set the channel topic if any of puzzle name, url, # state, status, or solution, has changed. Let's just do that # unconditionally here. - - # XXX: What we really want here is a single function that sets the - # channel name, the channel topic, and the sheet name. That single - # function should be called anywhere there is code changing any of - # these things. This function could then also accept an optional - # "old_puzzle" argument and avoid changing any of those things - # that are unnecessary. - set_channel_topic(turb, puzzle) + puzzle_update_channel_and_sheet(turb, puzzle) return lambda_ok @@ -626,7 +624,7 @@ def puzzle_submission(turb, payload, metadata): "Error: A puzzle with this URL already exists.") # Create a Slack-channel-safe puzzle_id - puzzle_id = re.sub(r'[^a-zA-Z0-9_]', '', name).lower() + puzzle_id = puzzle_id_from_name(name) # Create a channel for the puzzle hunt_dash_channel = "{}-{}".format(hunt_id, puzzle_id) @@ -676,41 +674,6 @@ def puzzle_submission(turb, payload, metadata): return lambda_ok -# XXX: This duplicates functionality eith events.py:set_channel_description -def set_channel_topic(turb, puzzle): - channel_id = puzzle['channel_id'] - name = puzzle['name'] - url = puzzle.get('url', None) - sheet_url = puzzle.get('sheet_url', None) - state = puzzle.get('state', None) - status = puzzle['status'] - - description = '' - - if status == 'solved': - description += "SOLVED: `{}` ".format('`, `'.join(puzzle['solution'])) - - description += name - - links = [] - if url: - links.append("<{}|Puzzle>".format(url)) - if sheet_url: - links.append("<{}|Sheet>".format(sheet_url)) - - if len(links): - description += "({})".format(', '.join(links)) - - if state: - description += " {}".format(state) - - # Slack only allows 250 characters for a topic - if len(description) > 250: - description = description[:247] + "..." - - turb.slack_client.conversations_setTopic(channel=channel_id, - topic=description) - def state(turb, body, args): """Implementation of the /state command @@ -729,7 +692,7 @@ def state(turb, body, args): puzzle['state'] = args turb.table.put_item(Item=puzzle) - set_channel_topic(turb, puzzle) + puzzle_update_channel_and_sheet(turb, puzzle) return lambda_ok @@ -774,19 +737,7 @@ def solved(turb, body, args): ) # And update the puzzle's description - set_channel_topic(turb, puzzle) - - # And rename the sheet to suffix with "-SOLVED" - turbot.sheets.renameSheet(turb, puzzle['sheet_url'], - puzzle['name'] + "-SOLVED") - - # Finally, rename the Slack channel to add the suffix '-solved' - channel_name = "{}-{}-solved".format( - puzzle['hunt_id'], - puzzle['puzzle_id']) - turb.slack_client.conversations_rename( - channel=puzzle['channel_id'], - name=channel_name) + puzzle_update_channel_and_sheet(turb, puzzle) return lambda_ok diff --git a/turbot/puzzle.py b/turbot/puzzle.py index b6e7883..1a36bfb 100644 --- a/turbot/puzzle.py +++ b/turbot/puzzle.py @@ -3,6 +3,7 @@ from turbot.blocks import ( ) from turbot.channel import channel_url from boto3.dynamodb.conditions import Key +import turbot.sheets import re def find_puzzle_for_puzzle_id(turb, hunt_id, puzzle_id): @@ -148,3 +149,66 @@ def puzzle_matches_all(puzzle, patterns): return False return True + +def puzzle_id_from_name(name): + return re.sub(r'[^a-zA-Z0-9_]', '', name).lower() + +def puzzle_update_channel_and_sheet(turb, puzzle): + + channel_id = puzzle['channel_id'] + name = puzzle['name'] + url = puzzle.get('url', None) + sheet_url = puzzle.get('sheet_url', None) + state = puzzle.get('state', None) + status = puzzle['status'] + + topic = '' + + if status == 'solved': + topic += "SOLVED: `{}` ".format('`, `'.join(puzzle['solution'])) + + topic += name + + links = [] + if url: + links.append("<{}|Puzzle>".format(url)) + if sheet_url: + links.append("<{}|Sheet>".format(sheet_url)) + + if len(links): + topic += "({})".format(', '.join(links)) + + if state: + topic += " {}".format(state) + + # Slack only allows 250 characters for a topic + if len(topic) > 250: + topic = topic[:247] + "..." + + turb.slack_client.conversations_setTopic(channel=channel_id, + topic=topic) + + # Rename the sheet to include indication of solved/solution status + sheet_name = puzzle['name'] + if puzzle['status'] == 'solved': + sheet_name += " - Solved {}".format(", ".join(puzzle['solution'])) + + turbot.sheets.renameSheet(turb, puzzle['sheet_url'], sheet_name) + + # Finally, rename the Slack channel to reflect the latest name and + # the solved status + # + # Note: We don't use puzzle['hunt_id'] here because we're keeping + # that as a persistent identifier in the database. Instead we + # create a new ID-like identifier from the current name. + channel_name = "{}-{}".format( + puzzle['hunt_id'], + puzzle_id_from_name(puzzle['name']) + ) + if puzzle['status'] == 'solved': + channel_name += "-solved" + + turb.slack_client.conversations_rename( + channel=puzzle['channel_id'], + name=channel_name + ) -- 2.43.0