この記事は ハンズラボ AdventCalendar2022 8日目の記事です。
はじめに
私がハンズラボに入社した当時、Slackの #random チャンネルには多種多様のおもしろbotが動いていました。その中の一つが EmojiBot です。
このbotはGASで作成されており、その日に新規に登録された絵文字を自動的に検知して通知してくれるというものでした。Slackでのコミュニケーションの活性化に一役買っており私も大好きなbotでした。しかし、SlackのAPIの仕様が変更されたためか、またはGASの管理者の退職の影響か、ある日動かなくなってしまいました。
とてもとても寂しかったので、AWS+Pythonで書き直しました。名付けて「帰ってきたEmojibot」。
事前準備(Slack)
SlackのApp管理画面を開き、Appを新規作成してOAuth token を入手してください。必要な権限は以下の通りです。
- chat:write
- chat:write.public
- emoji:read
OAuth token の詳細な入手手順は本記事では説明しませんので、各自検索してみてください。
トークンだけでなく、アイコンや表示名も必要に応じてここで設定します。
コード(Python)
import os
from datetime import datetime, timezone
from dotenv import load_dotenv
import boto3
from slack_sdk.web import WebClient
# ローカル起動とLambda起動で環境変数を切替
if os.environ.get('AWS_LAMBDA_FUNCTION_NAME'):
dynamodb = boto3.resource('dynamodb')
else:
load_dotenv()
dynamodb = boto3.resource('dynamodb', endpoint_url='http://localhost:8000')
table = dynamodb.Table('SlackEmojiList')
slack = WebClient(token=os.environ["SLACK_API_TOKEN"])
def getEmojiList():
# emoji一覧の入手
response = slack.emoji_list()
if not response['ok']:
print(f'emoji_list failed: {response}')
return
# DynamoDBに登録済みかチェック
for emoji, url in response['emoji'].items():
result = table.get_item(
Key={
'emoji': emoji
}
)
# 新規絵文字の場合はSlackへ投稿
if 'Item' not in result:
postSlack(emoji, url)
return
def postSlack(emoji, url):
# エイリアスの追加は通知しない
if 'alias' not in url:
text = "Here comes new emoji!!\n" + "`:" + emoji + ":` " + url
response = slack.chat_postMessage(text=text, channel="#random")
if not response['ok']:
print(f'{emoji} chat_postMessage failed: {response}')
return
# DynamoDBに保存
now = datetime.now(timezone.utc)
table.put_item(
Item={
'emoji': emoji,
'url': url,
'create_at': now.isoformat()
}
)
return
def handler(event, context):
getEmojiList()
return
if __name__ == "__main__":
getEmojiList()
解説
- SlackSDKを利用しての絵文字一覧APIを実行して絵文字一覧を入手
- DynamoDBに保存してある前日分との差分との比較
- 新規絵文字の場合はSlackへ投稿
- 投稿したらDynamoDBに保存
という、非常にシンプルなコードです。絵文字一覧APIには画像URLが含まれていますので、IDと合わせてSlackに投稿しています。絵文字の画像URLはパブリック(!)のため、URLを投稿すればSlack上でプレビューされます。
コード(AWS)
service: emojibot
frameworkVersion: ">=2.0.0 <3.0.0"
plugins:
- serverless-python-requirements
custom:
defaultStage: common
pythonRequirements:
dockerizePip: true
slackAPIToken: ${ssm:/emojibot/slackAPIToken}
provider:
name: aws
runtime: python3.8
region: ap-northeast-1
stage: ${opt:stage, self:custom.defaultStage}
environment:
TZ: Asia/Tokyo
SLACK_API_TOKEN: ${self:custom.slackAPIToken}
lambdaHashingVersion: 20201221
logRetentionInDays: 7
iam:
role:
statements:
- Effect: Allow
Action:
- dynamodb:Query
- dynamodb:GetItem
- dynamodb:PutItem
- dynamodb:UpdateItem
- dynamodb:DeleteItem
- dynamodb:DescribeTable
- dynamodb:Scan
Resource:
- !GetAtt EmojiListDynamoDBTable.Arn
package:
patterns:
- '!node_modules/**'
- '!.github/'
- '!.vscode/'
- '!.venv/'
- '!tests/'
- '!Pipfile'
- '!Pipfile.lock'
- '!README.md'
- '!package.json'
- '!yarn.lock'
functions:
EmojiBot:
handler: emojibot.handler
timeout: 900
events:
# 毎日18:00に起動
- schedule: cron(0 9 * * ? *)
resources:
Resources:
# -----
# DynamoDB作成
# -----
EmojiListDynamoDBTable:
Type: 'AWS::DynamoDB::Table'
Properties:
TableName: SlackEmojiList
BillingMode: PAY_PER_REQUEST
AttributeDefinitions:
- AttributeName: emoji
AttributeType: S
KeySchema:
- AttributeName: emoji
KeyType: HASH
PointInTimeRecoverySpecification:
PointInTimeRecoveryEnabled: true
解説
毎度おなじみのServerless Frameworkです。serverless-python-requirementsを利用してPythonコードをLambdaとしてデプロイするほか、DynamoDBも新規作成しています。slackAPITokenにセットする OAuth token は秘密情報にあたるため、ssmパラメタストアに格納してデプロイ時に参照させています。
※ Serverless Framework の詳細な使い方はこの記事では説明しません
※ 少し前に書いたコードのため、最新バージョンの Serverless Framework で動作させたい場合は修正が必要かもしれません
上記コードをデプロイ後、リリース当日までに登録済みの絵文字データをDynamoDBに移行してやれば準備は完了です。
動作確認
新規に絵文字を登録後、18時まで待つと……
やったぜ。
おわりに
絵文字の追加が通知されるようになると、絵文字の追加を利用者の皆に気づいてもらえるようになりコミュニケーションが活性化します。ネタ絵文字をこっそり追加して、通知されるのを黙って待つなどの奥ゆかしい使い方もできます笑。また、個人の権限に依存しがちなGASからAWSでの管理に切り替えたこともあり、複数人でのメンテナンスが容易になったこともメリットの一つです。今後も止まることなくずっと動き続けて欲しいものです。