Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

SlackBotに各人毎のGoogle MeetのURLを出してもらう

突然ですがこんな経験はないですか?

Slack上でのやりとりでは限界があってビデオ通話で会話がしたいときに

  1. Slackで相手にMeetしましょうと声を掛ける
  2. ブラウザで新しいタブ開く
  3. MeetのURLを作成する
  4. Slackに戻ってMeetのURLを共有してルームに入る

という流れ

画面移動とか地味にめんどくさくないですか?
僕はめんどくさいです
なのでSlackBotに自分専用のMeetのURLを出してもらうことにしました

実際に動いてるもの

塗りつぶし多くてちょっと見辛いですがslackから移動する必要がなくMeetのURLを共有できます

スクリーンショット 2020-12-09 2.01.14.png

どうやっているのか

  1. Slack
  2. GAS
  3. Sheets API / Calendar API
  4. Slack

という流れでGAS経由でスプレッドシートで管理している個人ごとのURLを返します
スプレッドシートにURLがない場合はカレンダーAPIを使ってMeetのURLを生成してスプレッドシートに保存して返します
サーバレスで、GASは無料ホスティングできてとってもお手軽

設定していく

さっそくやってみたい!と思ってくれた人がいるかもしれないと信じてなるべく丁寧に手順書いていきます

1. Slackからの認証のためにGASを仮置きする

1-1. GoogleDriveで適当に右クリックしてGoogle Apps Scriptを作る

function doPost(e) {
  return ContentService.createTextOutput(JSON.stringify(e));
}

スクリーンショット 2020-12-12 17.52.26.png

1-2. GASをアプリとして公開する

ウェブアプリケーションとして導入 を選択
スクリーンショット 2020-12-12 17.47.00.png
スクリーンショット 2020-12-12 17.47.39.png
スクリーンショット 2020-12-12 17.47.47.png

ここで最後に発行されたURLをメモっておく

2. SlackBotを作る

2-1. https://api.slack.com/apps にアクセスしCreate New App からBotを作る

スクリーンショット 2020-12-09 12.42.42.png

スクリーンショット 2020-12-09 12.44.38.png

2-2. 左のメニューの OAuth & Permissions から Scopeを設定する

Bot Token Scopes

  • app_mentions:read
  • chat:write

を追加する

スクリーンショット 2020-12-09 12.43.38.png

2-3. 続けて、アクセストークンを発行する

スクリーンショット 2020-12-12 18.08.39.png
スクリーンショット 2020-12-12 18.08.57.png

  • Install To Workspace を押す
  • Botのアクセストークンが発行されるのでメモっておく

2-4. 左のメニューの Event Subscriptions から イベントの設定とGASエンドポイントの認証をする

スクリーンショット 2020-12-12 17.49.36.png

  • Enable Events をOnにする
  • 1-2で発行したGASアプリのURLを Request URL へ入力する(成功すれば Verified になる)
  • Subscribe to bot eventsapp_mention を追加する
  • Save Changes で保存

3. スプレッドシートを作る

3-1. GAS同様に適当にドライブにスプレッドシートを作成する

3-2. URLからスプレッドシートのIDをメモる

https://docs.google.com/spreadsheets/d/*************/edit#gid=0
*************の部分がIDとなる
GASで使うのでメモっておく

4. Google CalendarでAPI経由でMeetのURLを作るために適当にカレンダーを作る

4-1. 新しいカレンダーを作成 から適当にカレンダーを作る

https://calendar.google.com/calendar/u/0/r/settings/createcalendar にアクセスして作る

スクリーンショット 2020-12-12 21.09.39.png

4-2. カレンダーに登録 からさっき作ったカレンダーIDを確認する

https://calendar.google.com/calendar/u/0/r/settings/addcalendar にアクセスして確認

  • さっき入力したカレンダー名でを入力して選択するとカレンダーの選択画面が出る

スクリーンショット 2020-12-12 21.14.13.png

スクリーンショット 2020-12-12 21.09.55.png

  • 下にスクロールするとカレンダーIDが確認できるのでメモしておく

スクリーンショット 2020-12-12 21.06.55.png

5. GASを修正

5-1. スクリプトを修正 ※1〜4を適宜置換

const slackBotAccessToken = '※1 2-3で発行したSlackBotのアクセストークン';
const spreadSheetId = '※2 3-2でメモっておいたスプレッドシートのID';
const calendarId = '※3 4で作った作ったカレンダーのID@group.calendar.google.com';
const attendees = [ { email: '※4 適当に自分のGsuiteのメアド' } ];

function doPost(e) {
  const slackApp = SlackApp.create(slackBotAccessToken);
  const contents = JSON.parse(e.postData.contents);

  // スレッドの中からだったらスレッドに返信する
  const opt = contents.event.thread_ts ? { thread_ts: contents.event.thread_ts } : {};
  slackApp.postMessage(contents.event.channel, buildResponseMessage(contents.event.user), opt);

  // 最初の認証でchallengeを返すのに必要だった
  return ContentService.createTextOutput(JSON.stringify(e));
}

// select or upsert してメッセージ返す
function buildResponseMessage(userId) {
  const sheet = SpreadsheetApp.openById(spreadSheetId).getSheets()[0];
  let url = '';

  // selectして
  url = selectUrl(sheet, userId);
  // なければ作ってinsert(upsertなのは名残)
  if (!url) {
    url = generateMeetUrl();
    upsertUrl(sheet, userId, url);
  }

  return `${mention(userId)} ${url}`;
}

// select
function selectUrl(sheet, userId) {
  // A列をuserIdで検索してB列をURLとみなして返す
  const record = sheet.getDataRange().getValues().find(el => el[0] === userId);
  return record ? record[1] : null;
}

function mention(userId) {
  return `<@${userId}>`;
}

// upsert
function upsertUrl(sheet, userId, url) {
  const index = sheet.getDataRange().getValues().findIndex(el => el[0] === userId);

  if (index !== -1) {
    // すでにuserIdあるならupdate
    sheet.getRange(index + 1, 2).setValue(url);
  } else {
    // なければinsert
    sheet.appendRow([userId, url]);
  }
}

// カレンダー作ってMeetUrlとって消す
function generateMeetUrl() {
  let event = Calendar.Events.insert(
    {
      start: { dateTime: new Date('2020/10/17 10:00:00').toISOString() },
      end: { dateTime: new Date('2020/10/17 12:00:00').toISOString() },
      attendees,
      conferenceData: {
        createRequest: {
          conferenceSolutionKey: {
            type: "hangoutsMeet"
          },
          requestId: 'リクエストID',
        },
      },
    },
    calendarId,
    { conferenceDataVersion: 1 },
  );

  const meetsUrl = event.hangoutLink;

  Calendar.Events.remove(calendarId, event.id)

  return meetsUrl;
}

5-2. SlackAppライブラリを入れる

Slack BotをGASでいい感じで書くためのライブラリを作った
M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO

スクリーンショット 2020-12-12 22.53.52.png

スクリーンショット 2020-12-12 22.54.11.png

5-3. Google Calendar のAPIを叩けるようにする

スクリーンショット 2020-12-13 0.21.40.png

スクリーンショット 2020-12-13 0.21.49.png

5-4. デプロイする

  • 最初に仮置きした時と同じ手順で
  • Project versionNew を選択してリリース スクリーンショット 2020-12-12 21.19.16.png

6. あとはslackでbotをチャンネルに追加してメンション飛ばせばurlをくれる!

社内でもユーザがだいぶ増えてスプレッドシートはこんな感じになってます
スクリーンショット 2020-12-13 0.59.46.png

TODO

  • GASの権限などが実装者(自分)依存になっているので自分が退職してGSuiteアカウント消えても動き続けるようにする必要がある
  • がんばればTerraformでコード管理できそうなきがする
rh_taro
timee
日本の労働力の減少を若者の働き方改革で解決します。好きな時に好きなだけ働けるプラットフォームタイミーを作り、人々が好きなことをできる世界を実現します。
https://timee.co.jp/
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away