この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
定期開催しているオンライン雑談会があります。日時の調整に調整さんが大活躍しています。
- 月初に「調整さんを作ってね」のリマインダーがSlackに自動投稿される(以前に作成した仕組み)
- 人間が調整さんを作成する
- 人間がSlackのチャンネルで案内する(URLと締切)
- Botが締切日に「今日が締切だよ!」と案内する(以前に作成した仕組み)
- 人間が当日に「今日が開催日だよ!」と案内する
そこそこ自動化してきましたが、ツメが甘かったです。5.
も自動化できることに気づきました。やりました!!!
全体概要
前回の仕組みを利用し、Lambda内で処理を分けています。
Slackのワークフローを作成する(開催日の入力)
ワークフローの新規作成
Slackの左上を選択し、ワークフロービルダー
を起動します。
適当に名前を付けます。
人間が起動するためショートカット
を選択します。
チャンネルと短い名前を入力します。
ワークフローのステップを追加(フォーム入力)
ステップを追加
を選択します。
フォームを作成します。
ワークフローのステップを追加(メッセージ送信)
さらにステップを追加
します。今度はメッセージを送信
を選択し、保存します。
ワークフローを公開する
右上の公開する
ボタンを選択すればOKです!
Lambdaの変更
対象日をDynamoDBに保存するLambdaを変更する
前回作成したsrc/save_deadline/app.py
を下記に変更します。DynamoDBに保存するときtype
を設けて区別しています。
deadline
: 調整さんの回答締切日announce
: 同期会の開催日
app.py
import boto3
import json
import logging
import os
import re
from datetime import datetime
logger = logging.getLogger()
logger.setLevel(logging.INFO)
dynamodb = boto3.resource('dynamodb')
SLACK_WORKFLOW_USER_DEADLINE = 'reminder_misc_join_201901_workflow'
SLACK_WORKFLOW_USER_ANNOUNCE = '同期会のお知らせ'
def lambda_handler(event, context):
main(event)
return {
'statusCode': 200
}
def main(event):
logger.info(json.dumps(event))
body = json.loads(event['body'])
logger.info(json.dumps(body))
if 'username' not in body['event']:
logger.info('No username.')
return
# 「締切」と「開催日」が同日の場合は考慮しない(運用上なし)
if body['event']['username'] == SLACK_WORKFLOW_USER_DEADLINE:
# 調整さんの締切とURLを登録する
deadline_timestamp = parse_timestamp_for_deadline(body['event']['text'])
url = parse_url_for_deadline(body['event']['text'])
item = {
'deadline': deadline_timestamp,
'type': 'deadline',
'expiration': deadline_timestamp + 60*60*11, # 当日11時をDynamoDBのTTL期限とする
'url': url
}
logger.info(f'item for deadline: {json.dumps(item)}')
put_item(item)
elif body['event']['username'] == SLACK_WORKFLOW_USER_ANNOUNCE:
# 開催日を登録する
announce_timestamp = parse_timestamp_for_announce(body['event']['text'])
item = {
'deadline': announce_timestamp,
'type': 'announce',
'expiration': announce_timestamp + 60*60*11, # 当日11時をDynamoDBのTTL期限とする
}
logger.info(f'item for announce: {json.dumps(item)}')
put_item(item)
else:
logger.info('No workflow message.')
def parse_timestamp_for_deadline(text):
pattern = r'.+\n期限は \*(\d{4}/\d{1,2}/\d{1,2})\* です!'
res = re.match(pattern, text)
if res:
# 0時のunixtimeを返す
return int(datetime.strptime(res.group(1), '%Y/%m/%d').timestamp())
raise ValueError
def parse_timestamp_for_announce(text):
pattern = r'同期会の開催日は \*(\d{4}/\d{1,2}/\d{1,2})\* です!'
res = re.match(pattern, text)
if res:
# 0時のunixtimeを返す
return int(datetime.strptime(res.group(1), '%Y/%m/%d').timestamp())
raise ValueError
def parse_url_for_deadline(text):
pattern = r'.+\n.+\n<(.+)>'
res = re.match(pattern, text)
if res:
return res.group(1)
raise ValueError
def put_item(item):
table_name = os.environ['REMINDER_TABLE_NAME']
table = dynamodb.Table(table_name)
res = table.put_item(Item=item)
logger.info(res)
告知するLambdaを変更する
前回作成したsrc/notify_deadline_message/app.py
を下記に変更します。type
によって通知文面を変更しています。
app.py
import boto3
import json
import logging
import os
import requests
from botocore.exceptions import ClientError
from datetime import date, datetime
logger = logging.getLogger()
logger.setLevel(logging.INFO)
INCOMMING_WEBHOOK_URL = os.environ['INCOMMING_WEBHOOK_URL']
dynamodb = boto3.resource('dynamodb')
def lambda_handler(event, context):
today = get_today()
logger.info(f'today: {today}')
remind_data = get_remind_data(today)
logger.info(f'get_remind_data(): {remind_data}')
if remind_data is None:
return
message = create_message(remind_data)
post_slack(message)
def get_today():
today = date.today()
# 今日の0時0分0秒のunixtimeを返す
return int(datetime(today.year, today.month, today.day).timestamp())
def get_remind_data(deadline):
table_name = os.environ['REMINDER_TABLE_NAME']
table = dynamodb.Table(table_name)
try:
res = table.get_item(Key={
'deadline': deadline
}
)
except ClientError as e:
logger.error(e.response['Error']['Message'])
return None
else:
return res.get('Item', None)
def create_message(remind_data):
# https://api.slack.com/incoming-webhooks
# https://api.slack.com/docs/message-formatting
# https://api.slack.com/docs/messages/builder
# https://www.webfx.com/tools/emoji-cheat-sheet/
if remind_data['type'] == 'deadline':
return {
'text': '<!here> 今日が締切です!! 記入お願いします!\n',
'attachments': [
{
'text': remind_data['url']
}
]
}
if remind_data['type'] == 'announce':
return {
'text': '<!here> 今日が開催日です!!\n',
}
raise AttributeError('unsupport type')
def post_slack(message):
url = f'https://{INCOMMING_WEBHOOK_URL}'
# http://requests-docs-ja.readthedocs.io/en/latest/user/quickstart/
try:
response = requests.post(url, data=json.dumps(message))
except requests.exceptions.RequestException as e:
logger.error(e)
else:
logger.info(response.status_code)
ビルド&デプロイ
sam build
sam package \
--output-template-file packaged.yaml \
--s3-bucket cm-fujii.genki-chouseisan-reminder-deploy-bucket
sam deploy \
--template-file packaged.yaml \
--stack-name Chouseisan-Reminder-Stack \
--capabilities CAPABILITY_NAMED_IAM \
--no-fail-on-empty-changeset \
--parameter-overrides ChouseisanNotifySlackUrl=/Slack/INCOMING_WEBHOOK_URL/channel_name/choseisan_reminder
動作確認
1. Slackのワークフローで調整さんのURLと締切日を登録する
調整さんを作成し、締切日とURLをSlackのワークフローで入力します。
Slakでは下記のメッセージが自動投稿されます。
DynamooDBには下記が格納されました。
2. 調整さんの入力締切日に通知がくる
3. 開催日を登録する
開催日をSlackのワークフローで入力します。
Slakでは下記のメッセージが自動投稿されます。
DynamooDBには下記が格納されました。
4. 開催日に通知がくる!!!
さいごに
一通りの自動化ができました。よい調整さんライフをお過ごしください!