From: Carl Worth Date: Fri, 1 Jan 2021 01:00:33 +0000 (-0800) Subject: Add a multi-select round field to puzzle creation X-Git-Url: https://git.cworth.org/git?a=commitdiff_plain;h=fc6a00f58bfc526e327c41bf989275b824004a88;hp=7a68a1c7360a30d046d9e415dd3ab6294db97173;p=turbot Add a multi-select round field to puzzle creation Actually, there are two round fields. The first is a free-form text field for a comma-separated list of rounds. Each of these rounds will be added to the database as an item with only two attributes: hunt_id: SK: round- The other field is a multi-select field populated with the names of all rounds that already exist in the hunt. This makes for easy selection without having to worry about typing in names identical with what others typed previously. --- diff --git a/turbot/blocks.py b/turbot/blocks.py index 27e69f4..661cff3 100644 --- a/turbot/blocks.py +++ b/turbot/blocks.py @@ -52,3 +52,30 @@ def input_block(label, name, placeholder, optional=False): "text": label } } + +def multi_select_block(label, name, placeholder, options, default=None): + return { + "type": "section", + "block_id": name, + "text": { + "type": "mrkdwn", + "text": "*{}*".format(label) + }, + "accessory": { + "action_id": name, + "type": "multi_static_select", + "placeholder": { + "type": "plain_text", + "text": placeholder + }, + "options": [ + { + "text": { + "type": "plain_text", + "text": option + }, + "value": option + } for option in options + ] + } + } diff --git a/turbot/interaction.py b/turbot/interaction.py index 0c1d8d9..bb0a8db 100644 --- a/turbot/interaction.py +++ b/turbot/interaction.py @@ -1,5 +1,7 @@ from slack.errors import SlackApiError -from turbot.blocks import input_block, section_block, text_block +from turbot.blocks import ( + input_block, section_block, text_block, multi_select_block +) from turbot.hunt import find_hunt_for_hunt_id import turbot.rot import turbot.sheets @@ -323,6 +325,28 @@ def hunt_for_channel(turb, channel_id): # we expect this to be a puzzle channel instead return find_hunt_for_hunt_id(turb, entry['hunt_id']) +# python3.9 has a built-in removeprefix but AWS only has python3.8 +def remove_prefix(text, prefix): + if text.startswith(prefix): + return text[len(prefix):] + return text + +def hunt_rounds(turb, hunt_id): + """Returns array of strings giving rounds that exist in the given hunt""" + + response = turb.table.query( + KeyConditionExpression=( + Key('hunt_id').eq(hunt_id) & + Key('SK').begins_with('round-') + ) + ) + + if response['Count'] == 0: + return [] + + return [remove_prefix(option['SK'], 'round-') + for option in response['Items']] + def puzzle(turb, body, args): """Implementation of the /puzzle command @@ -338,6 +362,17 @@ def puzzle(turb, body, args): return bot_reply("Sorry, this channel doesn't appear to " + "be a hunt or puzzle channel") + round_options = hunt_rounds(turb, hunt['hunt_id']) + + if len(round_options): + round_options_block = [ + multi_select_block("Round(s)", "rounds", + "Existing round(s) this puzzle belongs to", + round_options) + ] + else: + round_options_block = [] + view = { "type": "modal", "private_metadata": json.dumps({ @@ -349,6 +384,11 @@ def puzzle(turb, body, args): section_block(text_block("*For {}*".format(hunt['name']))), input_block("Puzzle name", "name", "Name of the puzzle"), input_block("Puzzle URL", "url", "External URL of puzzle", + optional=True), + * round_options_block, + input_block("New round(s)", "new_rounds", + "New round(s) this puzzle belongs to " + + "(comma separated)", optional=True) ] } @@ -375,6 +415,12 @@ def puzzle_submission(turb, payload, metadata): state = payload['view']['state']['values'] name = state['name']['name']['value'] url = state['url']['url']['value'] + if 'rounds' in state: + rounds = [option['value'] for option in + state['rounds']['rounds']['selected_options']] + else: + rounds = [] + new_rounds = state['new_rounds']['new_rounds']['value'] # Create a Slack-channel-safe puzzle_id puzzle_id = re.sub(r'[^a-zA-Z0-9_]', '', name).lower() @@ -393,6 +439,17 @@ def puzzle_submission(turb, payload, metadata): channel_id = response['channel']['id'] + # Add any new rounds to the database + if new_rounds: + for round in new_rounds.split(','): + rounds += round + turb.table.put_item( + Item={ + 'hunt_id': hunt_id, + 'SK': 'round-' + round + } + ) + # Insert the newly-created puzzle into the database item={ "hunt_id": hunt_id, @@ -405,6 +462,8 @@ def puzzle_submission(turb, payload, metadata): } if url: item['url'] = url + if rounds: + item['rounds'] = rounds turb.table.put_item(Item=item) return lambda_ok