From 7d98a0d74781c4771907952b0a2dcaf06d638664 Mon Sep 17 00:00:00 2001 From: Carl Worth Date: Mon, 11 Jan 2021 17:56:47 -0800 Subject: [PATCH] Use consistent channel naming at puzzle creation time We've had a bug for some time where the puzzle editing code would construct a name for the puzzle channel based on hunt, and round, and puzzle type, and puzzle_id but the puzzle creation code was only using hunt and puzzle_id. In this commit, we fix the puzzle creation code to use the same puzzle_channel_name function so that channel names are created consistently. This commit also adds a check to reject a puzzle if it has the same puzzle_id as an existing puzzle. --- turbot/interaction.py | 71 +++++++++++++++++++++++-------------------- 1 file changed, 38 insertions(+), 33 deletions(-) diff --git a/turbot/interaction.py b/turbot/interaction.py index a3fe496..507da76 100644 --- a/turbot/interaction.py +++ b/turbot/interaction.py @@ -10,7 +10,9 @@ from turbot.hunt import ( from turbot.puzzle import ( find_puzzle_for_url, find_puzzle_for_sort_key, + find_puzzle_for_puzzle_id, puzzle_update_channel_and_sheet, + puzzle_channel_name, puzzle_id_from_name, puzzle_blocks, puzzle_sort_key, @@ -978,12 +980,18 @@ def new_puzzle_submission(turb, payload, metadata): hunt_id = meta['hunt_id'] state = payload['view']['state']['values'] - name = state['name']['name']['value'] + + # And start loading data into a puzzle dict + puzzle = {} + puzzle['hunt_id'] = hunt_id + puzzle['name'] = state['name']['name']['value'] url = state['url']['url']['value'] + if url: + puzzle['url'] = url if state['meta']['meta']['selected_options']: - puzzle_type = 'meta' + puzzle['type'] = 'meta' else: - puzzle_type = 'plain' + puzzle['type'] = 'plain' if 'rounds' in state: rounds = [option['value'] for option in state['rounds']['rounds']['selected_options']] @@ -991,8 +999,17 @@ def new_puzzle_submission(turb, payload, metadata): rounds = [] new_rounds = state['new_rounds']['new_rounds']['value'] + # Create a Slack-channel-safe puzzle_id + puzzle['puzzle_id'] = puzzle_id_from_name(puzzle['name']) + # Before doing anything, reject this puzzle if a puzzle already - # exists with the same URL. + # exists with the same puzzle_id or url + existing = find_puzzle_for_puzzle_id(turb, hunt_id, puzzle['puzzle_id']) + if existing: + return submission_error( + "name", + "Error: This name collides with an existing puzzle.") + if url: existing = find_puzzle_for_url(turb, hunt_id, url) if existing: @@ -1000,23 +1017,6 @@ def new_puzzle_submission(turb, payload, metadata): "url", "Error: A puzzle with this URL already exists.") - # Create a Slack-channel-safe puzzle_id - puzzle_id = puzzle_id_from_name(name) - - # Create a channel for the puzzle - hunt_dash_channel = "{}-{}".format(hunt_id, puzzle_id) - - try: - response = turb.slack_client.conversations_create( - name=hunt_dash_channel) - except SlackApiError as e: - return submission_error( - "name", - "Error creating Slack channel {}: {}" - .format(hunt_dash_channel, e.response['error'])) - - channel_id = response['channel']['id'] - # Add any new rounds to the database if new_rounds: for round in new_rounds.split(','): @@ -1033,21 +1033,26 @@ def new_puzzle_submission(turb, payload, metadata): } ) - # Construct a puzzle dict - puzzle = { - "hunt_id": hunt_id, - "puzzle_id": puzzle_id, - "channel_id": channel_id, - "solution": [], - "status": 'unsolved', - "name": name, - "type": puzzle_type - } - if url: - puzzle['url'] = url if rounds: puzzle['rounds'] = rounds + puzzle['solution'] = [] + puzzle['status'] = 'unsolved' + + # Create a channel for the puzzle + channel_name = puzzle_channel_name(puzzle) + + try: + response = turb.slack_client.conversations_create( + name=channel_name) + except SlackApiError as e: + return submission_error( + "name", + "Error creating Slack channel {}: {}" + .format(channel_name, e.response['error'])) + + puzzle['channel_id'] = response['channel']['id'] + # Finally, compute the appropriate sort key puzzle["SK"] = puzzle_sort_key(puzzle) -- 2.43.0