]> git.cworth.org Git - turbot/commitdiff
Add a multi-select round field to puzzle creation
authorCarl Worth <cworth@cworth.org>
Fri, 1 Jan 2021 01:00:33 +0000 (17:00 -0800)
committerCarl Worth <cworth@cworth.org>
Fri, 1 Jan 2021 05:47:32 +0000 (21:47 -0800)
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: <HUNT_ID>
        SK: round-<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.

turbot/blocks.py
turbot/interaction.py

index 27e69f4d6d9d61140a16e4fa71cd30fcfe9d75e3..661cff37287d0fbee5a9fddb37220f7c8ef17630 100644 (file)
@@ -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
+            ]
+        }
+    }
index 0c1d8d92de33ded79f33e58914e580b1f430ec69..bb0a8db7947b1b0eafb515317230a901504099b8 100644 (file)
@@ -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