X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=turbot%2Finteraction.py;h=8ae4a53556d45542ec19dca22471e46b89f8f702;hb=c6ce6535d35284aad823b9f325e54ddb67ea1f3e;hp=f9fcedee34b174dcc4bc2bd0669e3214c9ea72c9;hpb=4b3efe6fde2dd926f5b54eb357ed732e9e04d9e0;p=turbot diff --git a/turbot/interaction.py b/turbot/interaction.py index f9fcede..8ae4a53 100644 --- a/turbot/interaction.py +++ b/turbot/interaction.py @@ -1,9 +1,9 @@ from slack.errors import SlackApiError from turbot.blocks import ( - input_block, section_block, text_block, multi_select_block + 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 +from turbot.puzzle import find_puzzle_for_url, find_puzzle_for_puzzle_id import turbot.rot import turbot.sheets import turbot.slack @@ -72,12 +72,166 @@ actions['multi_static_select'] = {"*": multi_static_select} def edit_puzzle(turb, payload): """Handler for the action of user pressing an edit_puzzle button""" - print("DEBUG: In edit_puzzle with payload: {}".format(str(payload))) + action_id = payload['actions'][0]['action_id'] + response_url = payload['response_url'] + trigger_id = payload['trigger_id'] + + (hunt_id, puzzle_id) = action_id.split('-', 1) + + puzzle = find_puzzle_for_puzzle_id(turb, hunt_id, puzzle_id) + + if not puzzle: + requests.post(response_url, + json = {"text": "Error: Puzzle not found!"}, + headers = {"Content-type": "application/json"}) + return bot_reply("Error: Puzzle not found.") + + round_options = hunt_rounds(turb, hunt_id) + + if len(round_options): + round_options_block = [ + multi_select_block("Round(s)", "rounds", + "Existing round(s) this puzzle belongs to", + round_options, + initial_options=puzzle.get("rounds", None)), + ] + else: + round_options_block = [] + + solved = False + if puzzle.get("status", "unsolved") == solved: + solved = True + + solution_str = None + solution_list = puzzle.get("solution", []) + if solution_list: + solution_str = ", ".join(solution_list) + + view = { + "type": "modal", + "private_metadata": json.dumps({ + "hunt_id": hunt_id, + "SK": puzzle["SK"], + "puzzle_id": puzzle_id, + "channel_id": puzzle["channel_id"], + "channel_url": puzzle["channel_url"], + "sheet_url": puzzle["sheet_url"], + }), + "title": {"type": "plain_text", "text": "Edit Puzzle"}, + "submit": { "type": "plain_text", "text": "Save" }, + "blocks": [ + input_block("Puzzle name", "name", "Name of the puzzle", + initial_value=puzzle["name"]), + input_block("Puzzle URL", "url", "External URL of puzzle", + initial_value=puzzle.get("url", None), + optional=True), + * round_options_block, + input_block("New round(s)", "new_rounds", + "New round(s) this puzzle belongs to " + + "(comma separated)", + optional=True), + input_block("State", "state", + "State of this puzzle (partial progress, next steps)", + initial_value=puzzle.get("state", None), + optional=True), + checkbox_block( + "Puzzle status", "Solved", "solved", + checked=(puzzle.get('status', 'unsolved') == 'solved')), + input_block("Solution", "solution", + "Solution(s) (comma-separated if multiple)", + initial_value=solution_str, + optional=True), + ] + } + + result = turb.slack_client.views_open(trigger_id=trigger_id, + view=view) + + if (result['ok']): + submission_handlers[result['view']['id']] = edit_puzzle_submission return lambda_ok actions['button']['edit_puzzle'] = edit_puzzle +def edit_puzzle_submission(turb, payload, metadata): + """Handler for the user submitting the edit puzzle modal + + This is the modal view presented to the user by the edit_puzzle + function above. + """ + + puzzle={} + + # First, read all the various data from the request + meta = json.loads(metadata) + puzzle['hunt_id'] = meta['hunt_id'] + puzzle['SK'] = meta['SK'] + puzzle['puzzle_id'] = meta['puzzle_id'] + puzzle['channel_id'] = meta['channel_id'] + puzzle['channel_url'] = meta['channel_url'] + puzzle['sheet_url'] = meta['sheet_url'] + + state = payload['view']['state']['values'] + + puzzle['name'] = state['name']['name']['value'] + url = state['url']['url']['value'] + if url: + puzzle['url'] = url + rounds = [option['value'] for option in + state['rounds']['rounds']['selected_options']] + if rounds: + puzzle['rounds'] = rounds + new_rounds = state['new_rounds']['new_rounds']['value'] + puzzle_state = state['state']['state']['value'] + if puzzle_state: + puzzle['state'] = puzzle_state + if state['solved']['solved']['selected_options']: + puzzle['status'] = 'solved' + else: + puzzle['status'] = 'unsolved' + puzzle['solution'] = [] + solution = state['solution']['solution']['value'] + if solution: + puzzle['solution'] = [ + sol.strip() for sol in solution.split(',') + ] + + # Add any new rounds to the database + if new_rounds: + if 'rounds' not in puzzle: + puzzle['rounds'] = [] + for round in new_rounds.split(','): + # Drop any leading/trailing spaces from the round name + round = round.strip() + # Ignore any empty string + if not len(round): + continue + puzzle['rounds'].append(round) + turb.table.put_item( + Item={ + 'hunt_id': puzzle['hunt_id'], + 'SK': 'round-' + round + } + ) + + # Update the puzzle in the database + turb.table.put_item(Item=puzzle) + + # 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) + + return lambda_ok + def new_hunt(turb, payload): """Handler for the action of user pressing the new_hunt button"""