From: Carl Worth Date: Mon, 19 Oct 2020 21:43:40 +0000 (-0700) Subject: Create a sheet for the hunt when creating a new hunt X-Git-Url: https://git.cworth.org/git?p=turbot;a=commitdiff_plain;h=c5b9b6e3ae85b40b79c0650eeee93cf79b1d23b5 Create a sheet for the hunt when creating a new hunt I don't know how much we'll need this, but here it is for consistency. This commit adds support for the Google sheets API (accessed via a pickled token from an encrypted SSM parameter). This will be very handy in the future when creating sheets for each puzzle channel, etc. --- diff --git a/turbot/actions.py b/turbot/actions.py index 30ae676..b586d39 100644 --- a/turbot/actions.py +++ b/turbot/actions.py @@ -1,5 +1,6 @@ from turbot.blocks import input_block import uuid +import turbot.sheets def new_hunt(turb, payload): """Handler for the action of user pressing the new_hunt button""" @@ -37,6 +38,7 @@ def new_hunt_submission(turb, payload): slug = state['slug']['slug']['value'] url = state['url']['url']['value'] + # Create a channel for the hunt response = turb.slack_client.conversations_create(name=slug) if not response['ok']: @@ -49,6 +51,10 @@ def new_hunt_submission(turb, payload): user_id = payload['user']['id'] channel_id = response['channel']['id'] + # Create a sheet for the channel + sheet = turbot.sheets.sheets_create(turb, slug) + + # Insert the newly-created hunt into the database turb.hunts_table = turb.db.Table("hunts") turb.hunts_table.put_item( Item={ @@ -60,6 +66,7 @@ def new_hunt_submission(turb, payload): } ) + # Invite the initiating user to the channel turb.slack_client.conversations_invite(channel=channel_id, users=user_id) return { diff --git a/turbot/sheets.py b/turbot/sheets.py index a578b10..8ab302d 100644 --- a/turbot/sheets.py +++ b/turbot/sheets.py @@ -1,44 +1,11 @@ -from flask import current_app -import pickle -import os.path -import os +PUZZLE_TEMPLATE_ID = "1drSoyrE4gM3JaGweDkOybwXWdKPIDTfUmB1gQCYS3Uw" +PUZZLE_TEMPLATE_SHEETS = ["Text", "Grid"] -from google.auth.transport.requests import Request -from googleapiclient.discovery import build - -TEMPLATE_SHEET_ID = "1drSoyrE4gM3JaGweDkOybwXWdKPIDTfUmB1gQCYS3Uw" -TEMPLATE_SHEET_SHEETS = ["Text", "Grid"] - -turbot_deploy_dir = os.environ.get('TURBOT_DEPLOY_DIR', '.') -TOKEN_FILE = "{}/.gsheets-token.pickle".format(turbot_deploy_dir) - -creds = None - -def sheets_create(name): +def sheets_create(turb, name): """Create a new sheet with the given name. - Returns the URL for the spreadsheet. + Returns the dict with 'id' and 'url'of the spreadsheet. """ - global creds - - # The token file stores token from last login/refresh - if not creds: - if os.path.exists(TOKEN_FILE): - with open(TOKEN_FILE, 'rb') as token: - creds = pickle.load(token) - - # Refresh credentials if necessary - if creds and not creds.valid: - creds.refresh(Request()) - - # If there are no (valid) credentials available, give up - if not creds or not creds.valid: - current_app.logger.error("No token found in {}".format(TOKEN_FILE)) - current_app.logger.error("Try running ./gsheets-authenticate.py") - return None - - service = build('sheets', 'v4', credentials=creds) - sheets = service.spreadsheets() # Create a new spreadsheet spreadsheet_body = { @@ -47,21 +14,32 @@ def sheets_create(name): } } - new_sheet = sheets.create(body=spreadsheet_body).execute() - spreadsheet_url = new_sheet["spreadsheetUrl"] - spreadsheet_id = new_sheet["spreadsheetId"] + new_sheet = turb.sheets.create(body=spreadsheet_body).execute() + + return { + 'id': new_sheet["spreadsheetId"], + 'url': new_sheet["spreadsheetUrl"] + } + +def sheets_create_for_puzzle(turb, name): + """Creates a new sheet for a puzzle of the given name + + Like sheets_create(), but also copies the puzzle template sheet.""" + + # First create the new sheet + new_sheet = sheets_create(turb, name) # Copy some sheets from the Template spreadsheet - response = sheets.get(spreadsheetId=TEMPLATE_SHEET_ID).execute() + response = turb.sheets.get(spreadsheetId=PUZZLE_TEMPLATE_ID).execute() for sheet in response["sheets"]: - if sheet["properties"]["title"] in TEMPLATE_SHEET_SHEETS: - sheets.sheets().copyTo(spreadsheetId=TEMPLATE_SHEET_ID, - sheetId=sheet["properties"]["sheetId"], - body={ - "destinationSpreadsheetId": - spreadsheet_id - }).execute() - - return spreadsheet_url + if sheet["properties"]["title"] in PUZZLE_TEMPLATE_SHEETS: + turb.sheets.sheets().copyTo(spreadsheetId=PUZZLE_TEMPLATE_ID, + sheetId=sheet["properties"]["sheetId"], + body={ + "destinationSpreadsheetId": + new_sheet['id'] + }).execute() + + return new_sheet diff --git a/turbot_lambda/turbot_lambda.py b/turbot_lambda/turbot_lambda.py index 9d878af..ab670d3 100644 --- a/turbot_lambda/turbot_lambda.py +++ b/turbot_lambda/turbot_lambda.py @@ -1,10 +1,14 @@ from urllib.parse import parse_qs from slack import WebClient +import base64 import boto3 import requests import json import os +import pickle from types import SimpleNamespace +from google.auth.transport.requests import Request +from googleapiclient.discovery import build import turbot.actions import turbot.commands @@ -23,11 +27,34 @@ response = ssm.get_parameter(Name='SLACK_BOT_TOKEN', WithDecryption=True) slack_bot_token = response['Parameter']['Value'] slack_client = WebClient(slack_bot_token) +response = ssm.get_parameter(Name='GSHEETS_PICKLE_BASE64', WithDecryption=True) +gsheets_pickle_base64 = response['Parameter']['Value'] +gsheets_pickle = base64.b64decode(gsheets_pickle_base64) +gsheets_creds = pickle.loads(gsheets_pickle) +if gsheets_creds: + if gsheets_creds.valid: + print("Loaded valid GSheets credentials from SSM") + else: + gsheets_creds.refresh(Request()) + gsheets_pickle = pickle.dumps(gsheets_creds) + gsheets_pickle_base64 = base64.b64encode(gsheets_pickle) + print("Storing refreshed GSheets credentials into SSM") + ssm.put_parameter(Name='GSHEETS_PICKLE_BASE64', + Type='SecureString', + Value=gsheets_pickle_base64, + Overwrite=True) +service = build('sheets', + 'v4', + credentials=gsheets_creds, + cache_discovery=False) +sheets = service.spreadsheets() + db = boto3.resource('dynamodb') turb = SimpleNamespace() turb.slack_client = slack_client turb.db = db +turb.sheets = sheets def error(message): """Generate an error response for a Slack request