X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=turbot%2Finteraction.py;h=6e353c120e1ba3d2a8a5dbca4584b2aa3033f750;hb=0e2a822502037c80985bccf99e378f41f38ed1b3;hp=3254f24587508953f7bf19d32905b5ea194dd68d;hpb=915b439e07c5b4aaef754f5f41360d862149a3fc;p=turbot diff --git a/turbot/interaction.py b/turbot/interaction.py index 3254f24..6e353c1 100644 --- a/turbot/interaction.py +++ b/turbot/interaction.py @@ -7,7 +7,8 @@ from turbot.puzzle import ( find_puzzle_for_url, find_puzzle_for_puzzle_id, puzzle_update_channel_and_sheet, - puzzle_id_from_name + puzzle_id_from_name, + puzzle_blocks ) import turbot.rot import turbot.sheets @@ -74,7 +75,25 @@ def multi_static_select(turb, payload): actions['multi_static_select'] = {"*": multi_static_select} -def edit_puzzle(turb, payload): +def edit_puzzle_command(turb, body): + """Implementation of the `/puzzle edit` command + + As dispatched from the puzzle() function. + """ + + channel_id = body['channel_id'][0] + trigger_id = body['trigger_id'][0] + + puzzle = puzzle_for_channel(turb, channel_id) + + if not puzzle: + return bot_reply("Sorry, this does not appear to be a puzzle channel.") + + return edit_puzzle(turb, puzzle, trigger_id) + + return lambda_ok + +def edit_puzzle_button(turb, payload): """Handler for the action of user pressing an edit_puzzle button""" action_id = payload['actions'][0]['action_id'] @@ -91,7 +110,18 @@ def edit_puzzle(turb, payload): headers = {"Content-type": "application/json"}) return bot_reply("Error: Puzzle not found.") - round_options = hunt_rounds(turb, hunt_id) + return edit_puzzle(turb, puzzle, trigger_id) + +actions['button']['edit_puzzle'] = edit_puzzle_button + +def edit_puzzle(turb, puzzle, trigger_id): + """Common code for implementing an edit puzzle dialog + + This implementation is common whether the edit operation was invoked + by a button (edit_puzzle_button) or a command (edit_puzzle_command). + """ + + round_options = hunt_rounds(turb, puzzle['hunt_id']) if len(round_options): round_options_block = [ @@ -115,9 +145,9 @@ def edit_puzzle(turb, payload): view = { "type": "modal", "private_metadata": json.dumps({ - "hunt_id": hunt_id, + "hunt_id": puzzle['hunt_id'], "SK": puzzle["SK"], - "puzzle_id": puzzle_id, + "puzzle_id": puzzle['puzzle_id'], "channel_id": puzzle["channel_id"], "channel_url": puzzle["channel_url"], "sheet_url": puzzle["sheet_url"], @@ -157,8 +187,6 @@ def edit_puzzle(turb, payload): 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 @@ -178,6 +206,7 @@ def edit_puzzle_submission(turb, payload, metadata): puzzle['sheet_url'] = meta['sheet_url'] state = payload['view']['state']['values'] + user_id = payload['user']['id'] puzzle['name'] = state['name']['name']['value'] url = state['url']['url']['value'] @@ -237,6 +266,27 @@ def edit_puzzle_submission(turb, payload, metadata): # Update the puzzle in the database turb.table.put_item(Item=puzzle) + # Inform the puzzle channel about the edit + edit_message = "Puzzle edited by <@{}>".format(user_id) + blocks = ([section_block(text_block(edit_message+":\n"))] + + puzzle_blocks(puzzle, include_rounds=True)) + slack_send_message( + turb.slack_client, puzzle['channel_id'], + edit_message, blocks=blocks) + + # Also inform the hunt if the puzzle's solved status changed + if puzzle['status'] != old_puzzle['status']: + hunt = find_hunt_for_hunt_id(turb, puzzle['hunt_id']) + if puzzle['status'] == 'solved': + message = "Puzzle <{}|{}> has been solved!".format( + puzzle['channel_url'], + puzzle['name']) + else: + message = "Oops. Puzzle <{}|{}> has been marked unsolved!".format( + puzzle['channel_url'], + puzzle['name']) + slack_send_message(turb.slack_client, hunt['channel_id'], message) + # 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. @@ -546,8 +596,63 @@ def hunt_rounds(turb, hunt_id): def puzzle(turb, body, args): """Implementation of the /puzzle command - The args string is currently ignored (this command will bring up - a modal dialog for user input instead).""" + The args string can be a sub-command: + + /puzzle new: Bring up a dialog to create a new puzzle + + /puzzle edit: Edit the puzzle for the current channel + + Or with no argument at all: + + /puzzle: Print details of the current puzzle (if in a puzzle channel) + """ + + if args == 'new': + return new_puzzle(turb, body) + + if args == 'edit': + return edit_puzzle_command(turb, body) + + if len(args): + return bot_reply("Unknown syntax for `/puzzle` command. " + + "Valid commands are: `/puzzle`, `/puzzle edit`, " + + "and `/puzzle new` to display, edit, or create " + + "a puzzle.") + + # For no arguments we print the current puzzle as a reply + channel_id = body['channel_id'][0] + response_url = body['response_url'][0] + + puzzle = puzzle_for_channel(turb, channel_id) + + if not puzzle: + hunt = hunt_for_channel(turb, channel_id) + if hunt: + return bot_reply( + "This is not a puzzle channel, but is a hunt channel. " + + "If you want to create a new puzzle for this hunt, use " + + "`/puzzle new`.") + else: + return bot_reply( + "Sorry, this channel doesn't appear to be a hunt or a puzzle " + + "channel, so the `/puzzle` command cannot work here.") + + blocks = puzzle_blocks(puzzle, include_rounds=True) + + requests.post(response_url, + json = {'blocks': blocks}, + headers = {'Content-type': 'application/json'} + ) + + return lambda_ok + +commands["/puzzle"] = puzzle + +def new_puzzle(turb, body): + """Implementation of the "/puzzle new" command + + This brings up a dialog box for creating a new puzzle. + """ channel_id = body['channel_id'][0] trigger_id = body['trigger_id'][0] @@ -593,17 +698,16 @@ def puzzle(turb, body, args): view=view) if (result['ok']): - submission_handlers[result['view']['id']] = puzzle_submission + submission_handlers[result['view']['id']] = new_puzzle_submission return lambda_ok -commands["/puzzle"] = puzzle - -def puzzle_submission(turb, payload, metadata): +def new_puzzle_submission(turb, payload, metadata): """Handler for the user submitting the new puzzle modal - This is the modal view presented to the user by the puzzle function - above.""" + This is the modal view presented to the user by the new_puzzle + function above. + """ # First, read all the various data from the request meta = json.loads(metadata)