やったこと
DocBase APIとslack WebhookURLを利用してAWS lambdaで、1日前(月曜日だけは金、土、日曜日の3日間)にDocBaseの自分が所属する事業部宛に投稿された記事を取得して、slackに通知するシステムを作成しました。
背景
以下の記事に書かれている通り、DocBaseのオーナー管理者権限を持っていればDocBaseのWebhookURLを利用して簡単にslackと連携することができます。
今回、私は上記の権限がなかったため、DocBaseのメモ検索APIをlambdaで呼び出し、slackのwebhookURLを利用して通知するシステムを作成しました。
この先、同じようなシステムを作りたいという人が現れた際に、この記事が少しでもお役に立てれば幸いです。
手順
①slackのWebhookURL発行
1.slack API( https://api.slack.com/apps )にアクセスする
2.Create an Appを押して、From scratchを選択する


3.App Nameに任意の名前を付け、Pick a workspace to develop your app in:からワークスペースを選択して、create Appを押す

4.作成したアプリの設定画面に遷移し、右下にあるPermissionsを選択する

5.ページ中部にあるScopesの中のAdd an OAuth Scopeを押下し、出現したプルダウンからchat:writeを選択する


6.左サイドバーのApp Homeから、App Display NameのEditを選択する

7.Display Name(Bot Name)にbotの表示名を、Default usernameにユーザー名を入れてAddを選択する

8.slackに移動して通知botを導入したいチャンネルを右クリックし、チャンネル詳細を表示するを選択する

9.インテグレーションを選び、Appカテゴリ内にあるアプリを追加するを押下する

10.検索窓で先ほど作ったbot名を入れ検索。下に表示されたbotの追加を押下する
※画像では既に追加済みのため、「表示する」ボタンになっている

11.チャンネルにbotが追加されたことを確認する

12.slackAPI設定画面に戻り、左サイドバーのIncoming Webhookを選択、Activate Incoming WebhooksをOnにしてAdd New Webhook to Workspaceを押下する

13.botの投稿先を聞かれるため、プルダウンから投稿したいチャンネルを選択して許可するボタンを押下する

14.WebhookURLが発行されたことを確認する

ここで発行したWebhookURLはlambdaからメッセージを送信する際に使用します。
②DocBaseのアクセストークンを発行
1.DocBaseのアカウント設定のページを開き、サイドバーにあるアクセストークンを選択する

2.トークンを作成を選択する

3.任意の名前と有効期限を入力して作成ボタンを押す
※有効期限は特に必要なければ空欄でOK

4.表示されたアクセストークンをコピーする

ここで作成したアクセストークンはDocBaseAPIを利用する際に使用します。
③lambdaの設定
1.AWSコンソールにログインして、リソースの中からlambdaを選択する

2.画面右側にある関数の作成ボタンを押下する

3.関数の作成画面で「一から作成」を選択。任意の関数名を付け、ランタイム(使用する言語)とアーキテクチャを選択し、右下の関数を作成ボタンを押下する
※今回ランタイムはpython3.9、アーキテクチャはx86_64を選択している

4.関数が正常に作成されたのを確認する

④コードを記述する前の下準備
DocBaseのAPIを利用する際とslackへのメッセージ送信の際にrequestsモジュールを利用するため、コードの最初でimport requestsをします。

しかし、初期のlambdaにはrequestsモジュールが存在しないため、実行すると以下のエラーが表示されます。

そこでライブラリを追加するために以下の手順を行う必要があります。
参考:https://aws.amazon.com/jp/premiumsupport/knowledge-center/lambda-import-module-error-python/
1.pythonという名前でフォルダを作成する
※ここでフォルダ名がpythonでないと、lambdaのレイヤーに追加した際に読み取ってもらえないためエラーになります。
2.python環境を用意し、pip install -t /python requestsコマンドで先ほど作成したpythonフォルダ内にライブラリをダウンロードする
3.ダウンロードが完了したら、pythonフォルダをzip化する
4.lambda画面に戻り、ハンバーガーメニューからレイヤーを選択。レイヤーの作成ボタンを押下する

5.任意のレイヤー名と説明を記入し、先ほどzip化したpythonフォルダをアップロード。アーキテクチャとランタイムは関数を作成したときのものを参照に選択する。必要事項を記載したら作成ボタンを押下する

6.作成した関数の画面に戻り、一番下のレイヤーからレイヤーの追加ボタンを押下する

7.レイヤーソースはカスタムレイヤーを選択。カスタムレイヤーの下のプルダウンから先ほど作成したレイヤーとバージョンを選択して追加ボタンを押下する

8.レイヤーが追加されたことを確認する

これでrequestsモジュールを利用できるようになります。
環境変数の設定
ここではDocBaseのアクセストークンやslackのWebhookURLを直接コードに記述するのを避けるために、環境変数を設定します。
環境変数について詳しく知りたい方は以下を参照してください。
参考:https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/configuration-envvars.htmlしてください。
1.lambdaの関数の設定から環境変数を選択。画面右側の編集ボタンを押下する

2.環境変数の追加ボタンを押し、キーと値の入力欄を表示する。キーに任意の名前を入れ、値に先ほど取得したDocBaseのアクセストークンとslackのWebhookURLを入力し、保存ボタンを押下する

3.環境変数が追加されていることを確認する

⑤コードの記述
lambdaのコードソースを以下に書き換えます。
※グループ名となっているところは、実際は自分の所属する事業部名になっています。
import urllib3
import json
import requests
import os
from datetime import datetime, timedelta
http = urllib3.PoolManager()
def lambda_handler(event, context):
# DocBaseのメモ検索APIを利用
docbase_secret = os.environ['DOCBASE_TOKEN']
headers = {"X-DocBaseToken" : docbase_secret}
url = "https://api.docbase.io/teams/iret/posts?"
# jstとutcの時差+9時間
DIFF_JST_FROM_UTC = 9
jst_yesterday = (datetime.now() - timedelta(1) + timedelta(hours=DIFF_JST_FROM_UTC)).strftime('%Y-%m-%d')
jst_friday = (datetime.now() - timedelta(3) + timedelta(hours=DIFF_JST_FROM_UTC)).strftime('%Y-%m-%d')
yesterday = (datetime.now() - timedelta(1) + timedelta(hours=DIFF_JST_FROM_UTC)).strftime('%Y年%m月%d日')
friday =(datetime.now() - timedelta(3) + timedelta(hours=DIFF_JST_FROM_UTC)).strftime('%Y年%m月%d日')
saturday = (datetime.now() - timedelta(2) + timedelta(hours=DIFF_JST_FROM_UTC)).strftime('%Y年%m月%d日')
# 月曜日は金曜日、土曜日、日曜日の3日分を取得する
week_num = datetime.today().weekday()
if week_num == 0:
params = {"q" : "group:グループ名 created_at:" + jst_friday + '~' + jst_yesterday}
text = '*' + friday + '~' + yesterday + 'に投稿された記事一覧です!* \n \n'
else:
#月曜日以外は昨日投稿された記事を取得する
params = {"q" : "group:グループ名 created_at:" + jst_yesterday}
text = '*' + yesterday + 'に投稿された記事一覧です!* \n \n'
res = requests.get(url, headers = headers, params = params)
if res.json()['meta']['total'] == 0:
pass
else:
for item in res.json()['posts']:
text += '<' + item['url'] + '|' + item['title'] + ':' + item['user']['name'] + '>' + '\n'
#取得したデータをslackに送信
slack_url = os.environ['SLACK_URL']
msg = {
"channel": "#time-keisuke",
"username": "投稿通知ボット",
"text": text,
"icon_emoji": "",
}
encoded_msg = json.dumps(msg).encode('utf-8')
resp = http.request('POST', slack_url, body=encoded_msg)
print({
"status_code": resp.status,
"response": resp.data,
})
params = {"q" : "group:グループ名 created_at:" + jst_yesterday}
ここで絞込の条件を指定しています。
今回はgroupとcreated_atをパラメータに入れていますが、検索オプションは他にもあり、ここで絞込の条件を変えられます。
参照:https://help.docbase.io/posts/1827704
text += '<' + item['url'] + '|' + item['title'] + ':' + item['user']['name'] + '>' + '\n'では、DocBaseの検索APIを利用して記事のURL、タイトル、著者名を取得したうえで、slackのマークダウン記法を利用して、文字リンクで表示されるようにしています。
⑥トリガーの追加
毎日決まった時間に通知されるように、Event Bridgeをトリガーに設定します。
今回は月曜から金曜日までの昼の12:00に通知が送られるように設定します。
1.関数の概要から+トリガーを追加ボタンを押下する

2.トリガーはプルダウンからEventBridge(CloudWatch Events)を選択し、ルールは新規ルールの作成を選択する。ルール名とルールの説明に任意のものを入力し、ルールタイプはスケジュール式を選択する。スケジュール式の下の入力欄にcron(0 3 ? * MON-FRI *)と入力して追加ボタンを押下する。
※cron()の引数については以下を参照してください。
参考:https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/events/ScheduledEvents.html

結果
slackのチャンネル上では以下のように表示されます。

文字リンクになっているためクリックすると、DocBaseの該当記事に遷移します。

あとがき
AWS lambdaで目的を持ったシステムを作成するのは今回が初めてだったため、最初は分からないことだらけでしたが、同期や先輩のサポートを受け、1か月ほどの期間でなんとか形にすることができました。
サポートをしてくださった皆様、本当にありがとうございました!
これからも、このシステムの改修に力を入れていきたいと思います!
さいごに
アイレット株式会社 22新卒 Advent Calendar 2022は本日が最終日でした。
22卒の皆さん、業務と並行しながらの記事の執筆お疲れ様でした!
広報や裏方でサポートをしてくださった皆様、ここまで記事を読んでくださった皆様、そしてアイレット株式会社 22新卒 Advent Calendar 2022を企画し、何かあったときにはすぐに対応してくれた@Michinosukeくんには、この場を借りて心から感謝を申し上げます。
本当にありがとうございました!