これはTECOTEC Advent Calendar 2019の24日目の記事です。
残すところあと2日です!
はじめに
ブロックチェーン事業部の飯田です。
さて、いきなりですがSlack便利ですよね!
弊社でもSlackを導入して丸2年ぐらいになります。
いまでは運用ルールなども策定されており安定して使われていると思われます。
ただ運用していくと色々と問題も出てきています。
その中で今回はこちらの問題に対応した話を紹介しようと思います。
チャンネルに流入しない問題
弊社では基本的に自由にチャンネルが作成できるため、様々な目的のチャンネルが多数作成されており、public
チャンネルで140個ほど確認できました。
private
チャンネルも入れるともっと多くのチャンネルが存在することになります。
public
チャンネルであれば自由に参加できるので、興味がある内容のチャンネルであればどんどん参加していくといいと思うのですが、実際複数のチャンネルに参加している人はあまりいないようです。
業務で使っているツールなので、業務連絡以外で使うのはどうなの?、っていう人もいたりするのかと思いますが、実はチャンネル数が多くて探すのが面倒、もしくは探し方がわからないっていう人の方が多いんじゃないでしょうか?
定期的にチャンネルを紹介する仕組みを作る
ということで、定期的にチャンネルを紹介する仕組みを作りました!
弊社では、雑談
・共有
・相談
といったプレフィクスをつけてチャンネルを作成するルールになっているので、チャンネル一覧をSlackAPIで取得して、プレフィクスでフィルタリングしてからランダムでチャンネルを1件取得してチャンネルに投稿する仕様にしました。
開発環境構築
今回、SlackBot
を作成するにあたってGoogle Apps Script
を利用しました。
スクリプトはローカルPCのエディタを使ってTypeScript
で記述し、Google謹製のCLIツールClasp
で反映するという構成で開発しました。
詳しい説明は参考資料を見ていただくとして、つまったところを説明したいと思います。
SlackAPIトークン取得
どこで取得するのかが非常に分かりづらかったです。
API トークンの生成と再生成の「ボットユーザートークン」の手順にある「古いカスタムインテグレーション」ページで作成できます。
TypeScriptの設定
こちらの「clasp が Typescript をサポートした!」を参考にしましたが、実は何も設定しなくていいです。
clasp push
するだけでts
ファイルをトランスパイルしてくれます!
ESLintとprettierの設定
コードの品質を保つためにESlint
とprettier
を導入しました。
色々試したところ最終的に以下のような設定になりました。
module.exports = {
root: true,
env: {
node: true,
es6: true,
'googleappsscript/googleappsscript': true
},
globals: {
SlackApp: false
},
extends: [
'eslint:recommended',
'plugin:prettier/recommended',
'prettier',
'prettier/@typescript-eslint'
],
plugins: [
'prettier',
'@typescript-eslint',
'googleappsscript'
],
parser: '@typescript-eslint/parser',
parserOptions: {
sourceType: 'module'
},
rules: {
'no-console': 'off',
'no-debugger': 'off',
'no-unused-vars': 'off',
'prettier/prettier': ['error', {printWidth: 120, semi: false, singleQuote: true}]
}
}
要点としては以下になります。
関数を定義だけしてファイル内で使用しないのでno-unused-vars
のエラーがどうしてもでてしまうのでoff
にしてあります。
また、後述するライブラリを利用すると以下のエラーがでるので、globals
の設定を追加しています。
7:18 error 'SlackApp' is not defined no-undef
スクリプトの説明
まずはスクリプト全容です。
const slackToken = PropertiesService.getScriptProperties().getProperty('SLACK_TOKEN')
const username = PropertiesService.getScriptProperties().getProperty('USERNAME')
const iconUrl = PropertiesService.getScriptProperties().getProperty('ICON_URL')
const channelToPostRecommendations = PropertiesService.getScriptProperties().getProperty(
'CHANNEL_TO_POST_RECOMMENDATIONS'
)
const slackApp = SlackApp.create(slackToken)
function postSlack(channelId, message, options) {
options.username = username
options.icon_url = iconUrl
slackApp.postMessage(channelId, message, options)
}
function postRecommendChannel() {
const { channels } = slackApp.channelsList(true)
const filteredChannels = channels.filter(filterChannel).map(channel => {
return {
id: channel.id,
name: channel.name,
description: channel.purpose.value.replace(/\r?\n/g, '').slice(0, 100)
}
})
const channel = filteredChannels[Math.floor(Math.random() * filteredChannels.length)]
const attachments = [
{
pretext: '今日のおすすめチャンネル!',
color: '#ffa500',
title: `<#${channel.id}|${channel.name}>`,
text: `${channel.description}`
}
]
const options = {
attachments: JSON.stringify(attachments)
}
postSlack(channelToPostRecommendations, '', options)
}
function filterChannel(channel) {
if (!channel.purpose.value) {
return false
}
const name = channel.name
if (name.match(/^雑談-/)) {
if (name !== '雑談-全体') {
return true
}
} else if (name.match(/^共有-/)) {
if (name !== '共有-全体') {
return true
}
} else if (name.match(/^相談-/)) {
return true
}
return false
}
以下に上記コードで取り入れた内容を説明していきます。
ライブラリを使用する
SlackAPI
との通信を楽にするためにSlackApp
というライブラリを使いたかったので、こちらの「[GAS]Claspでライブラリを使う方法」方法を参考にして導入しました。
上記記事でも説明されていますが、Google Apps Scriptのコンソールでライブラリの設定をしてからclasp pull
するのが簡単だと思います。
コードに埋め込みたくない情報の設定
SlackAPIのトークンなど、コードに直接書きたくない情報については、PropertiesService.getScriptProperties()
を利用することでスクリプトのプロパティから取得できます。
設定方法はこちらの「【初心者向けGAS】プロパティストアの概要とスクリプトプロパティの編集方法」を参考にしました。
attachmentsの設定
なかなかできなくて困ったのですが、こちらの「お天気ババアをリッチにした話」にかかれているように、attachments
に設定する際にJSON.stringify()
するだけでした。
まとめ
今回作成したボットで定期的に全員が参加しているチャンネルへメッセージを送るようにしてみたところ、それなりに流入しているようです。
Google Apps Script
は久しぶりに使いましたが、Clasp
のようなツールがあったりTypeScript
で記述できたりとかなり進化していてびっくりしました。
今回は時間がなく試せませんでしたが、Jest
でテストを書くこともできるようなので、今度はテストの作成にも挑戦したいです。
Google Apps Script
を利用するモチベーションがあがったのでまた何か作りたいと思います!
参考資料
API トークンの生成と再生成
google/clasp
GAS ビギナーが GAS を使いこなすために知るべきこと 10 選
clasp が Typescript をサポートした!
[GAS]Claspでライブラリを使う方法
【初心者向けGAS】プロパティストアの概要とスクリプトプロパティの編集方法
お天気ババアをリッチにした話
Step by Stepで始めるESLint