This completes the puzzle edit form so that all state that can be
manipulated with slash commands can also be directly edited with the
interactive dialog form.
"New round(s) this puzzle belongs to " +
"(comma separated)",
optional=True),
"New round(s) this puzzle belongs to " +
"(comma separated)",
optional=True),
+ input_block("Tag(s)", "tags",
+ "Tags for this puzzle (comma separated)",
+ initial_value=", ".join(puzzle.get("tags", [])),
+ optional=True),
input_block("State", "state",
"State of this puzzle (partial progress, next steps)",
initial_value=puzzle.get("state", None),
input_block("State", "state",
"State of this puzzle (partial progress, next steps)",
initial_value=puzzle.get("state", None),
if rounds:
puzzle['rounds'] = rounds
new_rounds = state['new_rounds']['new_rounds']['value']
if rounds:
puzzle['rounds'] = rounds
new_rounds = state['new_rounds']['new_rounds']['value']
+ tags = state['tags']['tags']['value']
puzzle_state = state['state']['state']['value']
if puzzle_state:
puzzle['state'] = puzzle_state
puzzle_state = state['state']['state']['value']
if puzzle_state:
puzzle['state'] = puzzle_state
+ # Process any tags
+ puzzle['tags'] = []
+ if tags:
+ for tag in tags.split(','):
+ # Drop any leading/trailing spaces from the tag
+ tag = tag.strip().upper()
+ # Ignore any empty string
+ if not len(tag):
+ continue
+ # Reject a tag that is not alphabetic or underscore A-Z_
+ if not re.match(r'^[A-Z0-9_]*$', tag):
+ return submission_error(
+ "tags",
+ "Error: Tags can only contain letters, numbers, "
+ + "and the underscore character."
+ )
+ puzzle['tags'].append(tag)
+
# Get old puzzle from the database (to determine what's changed)
old_puzzle = find_puzzle_for_sort_key(turb,
puzzle['hunt_id'],
# Get old puzzle from the database (to determine what's changed)
old_puzzle = find_puzzle_for_sort_key(turb,
puzzle['hunt_id'],
input_block("New round(s)", "new_rounds",
"New round(s) this puzzle belongs to " +
"(comma separated)",
input_block("New round(s)", "new_rounds",
"New round(s) this puzzle belongs to " +
"(comma separated)",
+ optional=True),
+ input_block("Tag(s)", "tags",
+ "Tags for this puzzle (comma separated)",
+ optional=True),
else:
rounds = []
new_rounds = state['new_rounds']['new_rounds']['value']
else:
rounds = []
new_rounds = state['new_rounds']['new_rounds']['value']
+ tags = state['tags']['tags']['value']
# Create a Slack-channel-safe puzzle_id
puzzle['puzzle_id'] = puzzle_id_from_name(puzzle['name'])
# Create a Slack-channel-safe puzzle_id
puzzle['puzzle_id'] = puzzle_id_from_name(puzzle['name'])
+ # Process any tags
+ puzzle['tags'] = []
+ if tags:
+ for tag in tags.split(','):
+ # Drop any leading/trailing spaces from the tag
+ tag = tag.strip().upper()
+ # Ignore any empty string
+ if not len(tag):
+ continue
+ # Reject a tag that is not alphabetic or underscore A-Z_
+ if not re.match(r'^[A-Z0-9_]*$', tag):
+ return submission_error(
+ "tags",
+ "Error: Tags can only contain letters, numbers, "
+ + "and the underscore character."
+ )
+ puzzle['tags'].append(tag)
+
if rounds:
puzzle['rounds'] = rounds
if rounds:
puzzle['rounds'] = rounds