【やってみた】Trelloから期限が近づいているタスクをslackに定期通知するアプリを作ってみた。

# 前説
うちのチームは、全員がやらなければならないタスクをTrelloで管理しています。
（カードにタスク、チェックリストに個人名が並び、タスク完了者は☑をつける形式）

上司は、毎回Trello開いて、各カード開いて、進捗を確認しなければなりません。
絶対面倒くさい。
そして、Trello Alertでは、カードの変更や新規作成、リストに☑をつけた時などにslack通知を出せますが、☑を付けるたびに通知が来るし、完了者と未完了者が一覧で見れるわけではありません。
基本的に、通知はslackのチャンネルを汚していきます（個人的な見解）。
そして、一覧で見れないのはやっぱり面倒くさい。

じゃあ、定期的に（チャンネルを汚さない範囲で）タスク未完了者を通知するアプリを作ってしまおう。
そして、やるならAWS使って実装しよう。と思いつき、作ってみました。

# 開発
## 開発フロー
大まかな開発フローは、

①TrelloのAPI叩く
②コード書く
③AWS lambdaに実装
④EventBridge(CloudWatch Events)をトリガーにする
⑤Slack appを作成する
⑥slackに投稿する
というような感じです。一つずつ見ていきます。

## TrelloのAPI叩く
[ここ](https://trello.com/app-key)にアクセスします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/4dec7e65-cdac-34cc-ebf1-c202d46d0796.png)

### Trello API Keys
一番上にあるKeyをコピーしておきます。（メモ帳なんかにおいておくと◎）
### Trello API Token
Key:の下のToKen:内にあるTokenのリンクをクリック。
そうすると、
`Would you like to give the following application access to your account? `
と聞いてくるので、スクロールしてAllowします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/70011f41-1468-e1d2-be34-4ba80bb3a663.png)
上記ページに移動したら、Token Keyが書いてあるので、これもコピーしておきます。

次は、ライブラリ(py-trello)のインストールをしていきましょう。
今回は、Lambdaを使う予定なので、ライブラリをpythonコードと同じフォルダ内（trello_alert）にインストールします。（フォルダ内が汚くなるのは置いておきます）

```powershell:powershell
mkdir trello_alert
cd trello_alert
pip install py-trello --target .
```

これで、APIをたたく準備ができました。
実際に叩いていきましょう。

```python:trello_api.py

from trello import TrelloClient
#trelloにAPI接続
client=TrelloClient(
    api_key='ここにAPI Key書く',
    api_secret='ここにAPI Token書く'
)
print(client.list_boards())
```
これで実行して、trelloのリストの一覧が出力されていればAPIをたたくタスクは完了です。

## コード書く
では、リストを取得して、期限が近いタスクが未完了な人を出力していきます。
基本的に、[このGitHub](https://github.com/sarumont/py-trello/blob/master/trello/trelloclient.py)にTrelloClientのクラスのコードが上がっているので、必要に応じて確認してみてください。
自分の書いたコードを参考に挙げておきます。
（lamdaに上げるので、lamda用のコードになってます）

```python:lambda_function.py
#Dateが近づいているTask未完了者を取得
import re
import datetime
from trello import TrelloClient
import json

def lambda_handler(event, context):
    result = {}
    
    #今日と来週の日付を取得
    today = datetime.date.today()
    next_week = today + datetime.timedelta(weeks=1)
    
    #trelloにAPI接続
    client = TrelloClient(
        api_key='ここにAPI Key書く',
        api_secret='ここにAPI Token書く'
    )
    
    #trelloのカードを取得する
    board = client.get_board(`注①:ここにボードidを書く`) #ボードを取得
    target_list = board.get_list(`注②:ここにリストidを書く`) #リストを取得
    cards = target_list.list_cards() #リスト上のカードの一覧を取得
    
    #カード毎のタスク未完了者と期限を取得
    #期限が1週間後のものと今日のものを通知
    for c in cards:
        #カードを取得
        card = client.get_card(c.id)
        card.fetch()
        #カードの期限を取得
        due = re.match("[0-9]{4}-[0-9]{2}-[0-9]{2}", c.due).group()
        #期限が今日のものと1週間後のもののチェックリストを取得
        if(str(due) == str(today) or str(due) == str(next_week)):
            #チェックリストを1件ずつ取得
            for checklist in card.checklists:
                not_finish = []
                for i, item in enumerate(checklist.items):
                    #タスク未完了者を出力
                    if(item["checked"]== False):
                        not_finish.append(item["name"])
            #カード名とタスク未完了者を辞書形式で格納
            result[c.name] = not_finish
    return {
        'statusCode': 200,
        'body': json.dumps(result, ensure_ascii=False)
    }
```
注1:trelloのboardを開いたときのurlのbの後ろがボードidです。
`https://trello.com/b/ボードid/ボード名`
注2:boardクラスにall_list関数があるので、それを出力してリストidを探します。
`print(board.all_list())`

こんな感じで、期限の近いタスクとタスク未完了者を取得することができました。
（ローカルで実行してみたいよという方は、`8行目、45行目~48行目`をコメントアウトして`print(result)を最後に付け加えれば実行できます。）
ファイル名を'lambda_function'にしておかないと、lamdaにアップしたときに動かないので注意しましょう。

とりあえず、コードができました。
lambdaに上げていきます。

## AWS lambdaに実装
### zipファイル化
lambdaにコードを上げるのにzipファイルにする必要があるので、
trello_alertフォルダ内にあるすべてを選択し、圧縮し、zipファイルにしましょう。
zipファイル名はtrelloとかにしておきましょう。

### AWSにログイン
Find Servicesからlambdaと検索するとAWS Lambdaが候補に出てくるので選択。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/e5bb2146-9db4-3eda-77e5-cf28a535a3c1.png)

このページに移動したら、`create function`をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/7f6a2a4c-3458-74fa-b84c-35b6782c25a5.png)

次のページでは、一番左を選択し、下にスクロール。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/ac25933e-9120-67dd-fdb7-0632ceba2f0a.png)

こんな感じに記入します。（trello_alert既にあるよって言われてるので赤字ですね）
そして、create functionをクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/f9dfcac3-ca2b-78df-1984-f955c2a777b7.png)

Lambdaのところに、trello_alertが追加されます。
trello_alertをクリックして、コードをアップしていきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/55d662c8-755d-cbbc-88e1-f95424a51eea.png)

このページに移動したら、右下のActionの部分をクリック。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/45c75674-6b5d-7aa2-fa6b-ec33af513e4c.png)

`Upload a .zip file`を選択し、先ほど作っておいたtrello.zipをアップロードします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/7c97bb43-ad1a-8a99-6cfd-ecd69c5c87cf.png)

こんな感じで、ファイルがアップされます。
（デフォルトで用意されているlambda_functionが邪魔してきたらdeleteしておきましょう）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/0cf867ee-4923-c0c3-1eae-b31e7ce9bead.png)


あとは、上記画面のsaveを押して、testを実行します。
テストを押すと以下のような画面になるので、Event nameをtestにして、createします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/ba93f5e6-290b-e3a6-b5ad-31d1f5ada517.png)
前の画面に戻るので、もう一度testを実行します。

Execution Resultに200応答が返ってきていればlambdaにアップ完了です。

### 環境変数設定（オプション）
API KeyやAPI Tokenを生のままコードに書いておくのは..という方は、
Function codeの下に、Enviroment variablesがあるので、
そこに環境変数を設定し、コード上では、
`api_key=os.environ['API_KEY']`
と書けば、問題なく実行されます。

## EventBridge(CloudWatch Events)をトリガーにする
定期実行したいのでCloudWatch Eventsを利用します。

Lambda(trello_alert)の画面からAdd triggerを選択します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/d492aba6-e7f4-4abe-e2f6-365380491f8a.png)

設定画面は、以下のように記入し、addします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/253412/aeaf5ef9-c405-1c1a-fa85-47dc1aced7e4.png)

今回は、平日の朝9時に定期的に投稿したかったので、
`cron(0 9 ? * MON-FRI *)`
とSchedule expressionを書いています。
毎分したい場合は、
`rate(1 minute)`
と設定すればOK!

##Slack appを作成
以下の記事を参考にSlack appを作成しました。
[【2020年版】slackAPIでメッセージ投稿するボットアプリ作成・設定(スコープ権限を詳細解説)](https://auto-worker.com/blog/?p=825)

## slackに投稿する
lambda_function.py以下のコードを書き加えます。

```python:lambda_function.py
import requests

# slackに投稿
url = "https://slack.com/api/chat.postMessage"
msg = {
   "token": "ここにACCESS TOKEN書きます",
   "channel": "ここに投稿したいチャンネルID書きます",
   "text": result
}
requests.post(url, data=msg)
```


# まとめ
AWSも使えて、APIも叩けて、業務も改善が見込めていい経験でした。