新しい仲間
前回、MNTSQのSlackにいるいくつかのbotを紹介した。
今日、そこに新しい仲間が加わったので紹介しよう。その名も "Hot Docs" だ。
Hot Docsとは
Hot Docsとは、Google Driveのファイルを再帰的に探索し、短時間にたくさんコメントがついたDocsをSlackに通知するbotである。こんな感じだ。
なぜ作ったか
MNTSQではGoogle Docsを使って非同期でコミュニケーションを取ることがある。誰かが提案やログをDocsで作り、他のメンバーがそこにコメントしまくる、というスタイルだ。 しかしこれでは議論がDocsに閉じてしまい、Docsの存在を知らないメンバーから見えないというOpenness観点の問題がある。 そこで議論が活発なDocsをピックし、Slackに通知する仕組みを作った。
導入してみて
好評だった。
筆者自身、異なるドメインのHot Issueを知ることで事業理解に役立っていると実感する。
Hot Docsの仕組み
Hot DocsはGoogle App Scriptで作られており、30分おきにDriveを探索する。
ソースコードは次のとおり。再帰Generator listFiles
で取得したファイルを2users以上かつ5comments以上という条件でフィルタしSlackに投稿する。
function notifyHotDocs() { notifyHotFiles("application/vnd.google-apps.document"); } function notifyHotSlides() { notifyHotFiles("application/vnd.google-apps.presentation"); } function notifyHotFiles(mimeType) { const updatedMin = new Date(new Date().getTime() - 30 * 60 * 1000); const files = Array.from(listFiles(FOLDER_ID, mimeType, updatedMin), file => { const comments = Drive.Comments.list(file.getId(), { maxResults: 100, updatedMin: updatedMin.toISOString() }).items; return { name: file.getName(), url: file.getUrl(), comments: comments, authors: [...new Set(comments.map(x => x.author.displayName))], commentsLength: comments.length + comments.reduce((n, x) => n + x.replies.length, 0) }; }) .filter(x => x.authors.length >= 2 && x.comments.length >= 5) .sort((a, b) => b.comments.length - a.comments.length); if (files.length === 0) return; const colors = ["#fcc800", "#f3981d", "#ea553a"]; // コメント数に応じて色を変える const attachments = files.map(x => { let colorIndex = Math.floor(x.comments.length / 10); colorIndex = colorIndex < 0 ? 0 : colorIndex > 2 ? 2 : colorIndex; return { author_name: x.authors.slice(0, 3).join(", ") + (x.authors.length > 3 ? ", etc." : ""), title: x.name, title_link: x.url, color: colors[colorIndex] }; }); postMessage(CHANNEL_ID, "なんか盛り上がってるみたい!", attachments, ":hotdog:", "Hot Docs"); } function *listFiles(parentFolderId, mimeType, updatedMin) { const folder = DriveApp.getFolderById(parentFolderId); const files = folder.getFilesByType(mimeType); while (files.hasNext()) { const file = files.next(); if (file.getLastUpdated() > updatedMin) { yield file; } } const folders = folder.getFolders(); while (folders.hasNext()) { const folder = folders.next(); yield* listFiles(folder.getId(), mimeType, updatedMin); } } function postMessage(channel, text, attachments, icon_emoji, username) { const url = "https://slack.com/api/chat.postMessage"; let options = { "method" : "post", "contentType": "application/x-www-form-urlencoded", "payload" : { "token": SLACK_BOT_POST_TOKEN, "channel": channel, "text": text, "attachments": JSON.stringify(attachments), "icon_emoji": icon_emoji, "username": username } }; let response = UrlFetchApp.fetch(url, options); let data = JSON.parse(response.getContentText()); return data; }
おしまい
あなたの会社でもぜひ試してほしい。