Python、Slack、Lambda、DynamoDBを使って簡単勤怠管理システムを作ってみた①

#はじめに
SlackとAWSを使用して、勤怠管理システムを作成してみました！
使用したサービスは、Slack、API Gateway、Lambda、DyanmoDBの4つです。
システム構成図は以下です。
（新しいAWSアイコン使ってみました！）

![system.png](https://qiita-image-store.s3.amazonaws.com/0/247957/35d01bcd-db72-d92f-ee35-d289e36c0c6f.png)


#目次
1.IAMロールを作る
2.Lambdaを作る
3.LambdaからSlackに投稿する
4.API Gatewayを作る
5.SlackからLambdaに通知する
6.DynamoDBを作る
7.SlackからDynamoDBに書き込む
8.DynamoDBの情報をSlackで確認する

#1.IAMロールを作る
Lambdaで使用するIAMロールを作成しておきます。
今回は、LambdaとDynamoDBのフルアクセス権限を付けておきます。
ロール名は、LambdaDynamoAccessRoleとします。

#2.Lambdaを作る
WorkTimeManagementという名前で、Lambda関数を作成します。
ランタイムは、Python3.6です。
IAMロールには、先程作成したLambdaDynamoAccessRoleを利用します。
<img width="1291" alt="1.png" src="https://qiita-image-store.s3.amazonaws.com/0/247957/496b8416-d10c-4ece-822e-a6dde6dd592b.png">
Lambda関数には、デフォルトでPython標準外のモジュールが含まれていないので、ZIPファイルにしてアップロードする必要があります。
ローカル環境で下記のコードを実行し、ZIPファイルを作成します。

```:terminal
$ mkdir environment
$ cd environment
$ pip install requests -t .
$ zip -r environment.zip *
```

コードエントリタイプの「.ZIPファイルをアップロード」を選択し、先程作成したenvironment.zipをアップロードします。
<img width="1294" alt="2.png" src="https://qiita-image-store.s3.amazonaws.com/0/247957/e0b28d4a-7a57-1efc-7640-f179c0570c71.png">
ここまでで、Lambda関数の作成は完了です。
<img width="1300" alt="3.png" src="https://qiita-image-store.s3.amazonaws.com/0/247957/c00e0b9a-8796-bf75-581d-1190fb19da61.png">


#3.LambdaからSlackに投稿する
SlackのIncoming Webhooksページに移動します。
<img width="1076" alt="4.png" src="https://qiita-image-store.s3.amazonaws.com/0/247957/398a4f0b-a4a8-6fcb-2668-addfe412276e.png">
ポストするチャンネルを指定すると、Webhook URLを取得することができます。
![5_edit.png](https://qiita-image-store.s3.amazonaws.com/0/247957/c9c7323f-c187-7a2c-024b-7ea4c54c92a6.png)
このURLを利用して、LambdaからSlackにリクエストを投げます。
続いて、左上のFileタブから新規ファイルを作成し、ファイル名をlambda_function.pyとして保存します。
![6_edit.png](https://qiita-image-store.s3.amazonaws.com/0/247957/e008e206-d351-7502-7c3a-eb2d83e46206.png)
lambda_function.pyのコードは、以下のように記述します。

```lambda_function.py
import os
import json
import requests
import boto3

# Slack Incomming Webhooks URL
SLACK_POST_URL = "https://hooks.slack.com/services/~"

# Post to Slack
def PostSlack(message, icon=':smile:', username='user', channel="#worktime"):
    
    Dict_Payload = {
    "text": message,
    "username": username,
    "icon_emoji": icon,
    "channel": channel,
    }
    
    return requests.post(SLACK_POST_URL, data=json.dumps(Dict_Payload))

# Main Function
def lambda_handler(event, context):
    
    PostSlack(message="This is a 1st test!")
    
    return "success!"
```

プログラムを実行すると、Slackに「This is a 1st test!」とポストすることができます。
<img width="796" alt="7.png" src="https://qiita-image-store.s3.amazonaws.com/0/247957/dd93ffe7-df23-05dc-63ad-19c2f25f0981.png">
PostSlack関数の引数で指定するiconで、Slackポスト時のアイコンを指定することができます。
以下のURLにて、Slackの絵文字チートシートを確認できます。
https://www.webpagefx.com/tools/emoji-cheat-sheet/

#4.API Gatewayを作る
Lambda→Slackはできましたが、Slack→Lambdaも必要です。
具体的には、Slackに書いた情報をLambdaで受け取り、データベースに書き込む必要があります。
上記操作を実現するため、今回はAPI Gatewayを使用します。
まずは、「WorkTimeAPI」という名前で、新たなAPIを作成します。
<img width="1219" alt="8.png" src="https://qiita-image-store.s3.amazonaws.com/0/247957/b74c3dcd-90f6-c7dc-d047-a695a8d4eeab.png">
次に、アクションタブからリソースの作成を選択し、all-actionというリソースを作成します。
<img width="1150" alt="9.png" src="https://qiita-image-store.s3.amazonaws.com/0/247957/7b21e6cc-4637-93f5-8867-7cde4b1f0233.png">
リソースを作成しましたら、再びアクションタブを選択し、次はメソッドの作成をクリックします。
<img width="1124" alt="10.png" src="https://qiita-image-store.s3.amazonaws.com/0/247957/fd82d1af-2ec6-57b5-8b43-7416f2824c0d.png">
メソッドの種類は、一先ずANYとしておきます。
先程作成したLambdaと連携したいので、Lambda関数名を「WorkTimeManagement」としておきます。
<img width="1167" alt="11.png" src="https://qiita-image-store.s3.amazonaws.com/0/247957/486a924b-bc63-d3d3-6cff-241f30d7e7ac.png">
リソース、メソッドの作成が完了しましたら、いよいよAPIをデプロイします。
アクションタブから、APIのデプロイを選択します。
![12_edit.png](https://qiita-image-store.s3.amazonaws.com/0/247957/d40b0565-2263-d826-8e94-e02a31f7507e.png)
ステージについて情報を記載し、右下の完了ボタンを押すと、APIのデプロイが完了します。
<img width="592" alt="13.png" src="https://qiita-image-store.s3.amazonaws.com/0/247957/3eb4c732-f6b8-5895-22b0-360718c98e8b.png">
APIのデプロイが完了すると、ページ上部にURLが自動的に作成されます。
このURLを使用することで、APIの呼び出しが可能になります。
![14_edit.png](https://qiita-image-store.s3.amazonaws.com/0/247957/b53d40fb-42be-7b41-fb68-0f049eb3eef5.png)
続いて、API GatewayとSlackを連携します。
SlackのOutgoing Webhooksページに移動し、Add Outgoing WebHooks integretionを選択します。
<img width="998" alt="15.png" src="https://qiita-image-store.s3.amazonaws.com/0/247957/2c92cec1-a39a-0f04-61ef-80c909bdafd2.png">
チャンネルは#worktime、APIを呼び出すトリガーワードは、workとします。
URLには「~/dev/all-action」を記載し、下部のSave Settingsをクリックすると、SlackとAPI Gatewayの連携は完了です。
![16_edit.png](https://qiita-image-store.s3.amazonaws.com/0/247957/da57d2d9-0950-5520-f10f-b32ba70d088b.png)


#5.SlackからLambdaに通知する
Outgoing Webhooks URLを作成する際、トリガーワードをworkと設定しました。
従って「work （message）」とSlackにポストすれば、Lambdaへその内容が届きます。
今回はテストとして、「work test」とSlackにポストし、そのユーザー名、メッセージ、日付、時刻を表示します。
lambda_function.pyは下記の通り更新します。

```lambda_function.py
import os
import json
import requests
import boto3
from datetime import datetime, timedelta, timezone

# Slack Incomming Webhooks URL
SLACK_POST_URL = "https://hooks.slack.com/services/~"

#KEYWORD
USER_KEY = 'user_name='
TEXT_KEY = 'text='
TRIG_KEY = 'trigger_word='

# Post to Slack
def PostSlack(message, icon=':smile:', username='manager', channel="#worktime"):
    
    Dict_Payload = {
    "text": message,
    "username": username,
    "icon_emoji": icon,
    "channel": channel,
    }
    
    return requests.post(SLACK_POST_URL, data=json.dumps(Dict_Payload))

# Get body from event
def __getBody(event):
    body = event['body']
    return body
    
# Get user name who posted on Slack  
def GetUserName(event, user_key, text_key):
    body = __getBody(event)
    user = body[body.find(user_key)+len(user_key):body.find(text_key)-1]
    return user
    
# Get posted message on Slack
def GetMessage(event, text_key, trig_key):
    body = __getBody(event)
    text = body[body.find(text_key)+len(text_key):body.find(trig_key)-1]
    word_list = text.split("+")
    message = word_list[1]
    return message

# Get posted time on Slack
def GetDateTime():
    JST = timezone(timedelta(hours=+9), 'JST')
    now = str(datetime.now(JST))
    date = now[:now.find(" ")]
    time = now[now.find(" "):now.find(".")]
    return date, time

# Main Function
def lambda_handler(event, context):
    
    user = GetUserName(event, USER_KEY, TEXT_KEY)
    message = GetMessage(event, TEXT_KEY, TRIG_KEY)
    date, time = GetDateTime()
    
    PostSlack(message="User : "+str(user))
    PostSlack(message="Message : "+str(message))
    PostSlack(message="Date : "+str(date))
    PostSlack(message="Time : "+str(time))
    
    return "success!"
```
Slackで「work test」と投稿したところ、Lambdaから投稿者のユーザー名、メッセージ、日付、時刻が返ってきました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/247957/4d93aa07-e2e4-fb72-46c1-29e44c61470a.png)


#6.DynamoDBを作る

#7.SlackからDynamoDBに書き込む

#8.DynamoDBの情報をSlackで確認する

#おわりに
Chapter6のDynamoDB以降は、別記事にまとめようと思いますので、乞うご期待！
参考になった方は、是非いいね！をお願いします。