21
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Slack + GASで、サクッとMeet会議リンクを生成しよう

Last updated at Posted at 2020-08-07

😇 Meetのリンクをサクッと作りたい

新型コロナの影響でリモート業務が増えているであろうtec界隈。
リモート会議用のツールは、ZoomやTeamsなどいろいろあると思いますが、今回はMeetのお話です。

SlackからMeetのリンクをサクッと作りたいって思ったことないですか?
Meetのページ開いて、会議を開始して、URLを参加者に配って、、って結構かったるい。だからと言って、いちいち文章に落とし込んで送るのもめんどくさい。
口頭で2,3分で終わるような話だって、気軽にサクッと通話して解決できた方がいいですよね。

というわけで、 Slackとgasを使って、Meetの会議用リンクを生成してくれるボットを作っていきます!

✨ 完成イメージ

「Meetガチャ」っていうと、Meetの部屋のリンクが送られてきます!🎉
image.png
後半では/meetで呼び出せるコマンドも作りますよ!🔥

📚 必要なもの(?)

全部ブラウザ経由でできちゃいます。

💪 GASでMeet会議リンクを生成する

いきなりメイン部分です。gasを使って、Meetの会議リンクを取得します。

1. GoogleAppsScriptを開く

https://script.google.com/create にアクセスして、新しいscriptを作ります。

2. 以下のコードを貼り付け

スニペットにそのまま貼り付けちゃってください(ちなみにこの時点では未完成です)。

getMeetUrl.gs
function getMeetUrl() {
  const calendarId = 'primary'; // 一時的にイベントを作成するカレンダーのID。わからない人はこのままでOK
  const dt = new Date(); // 日付は適当に設定
  const date = dt.getFullYear() + '-' + (dt.getMonth() + 1) + '-' + dt.getDate();
  const requestId = Math.random().toString(32).substring(2); // 適当な文字列を作る
  const response = Calendar.Events.insert({
    summary: "temp_event",
    singleEvents: true,
    allDayEvent: true,
    start: {
      date,
    },
    end: {
      date,
    },
    conferenceData: {
      createRequest: {
        requestId,
        conferenceSolutionKey: {
          type: "hangoutsMeet"
        },
      }
    }
  },calendarId, { conferenceDataVersion: 1 })

  Calendar.Events.remove(calendarId, response.id)
  
  if (response.conferenceData.createRequest.status.statusCode === "success") {
    const meetUrl = response.conferenceData.entryPoints[0].uri
    Logger.log(meetUrl)
  }
}

3. Google Calender APIと接続する

Resources > Advanced Google services....から、Calendar APIONにします。

image.png

4. テストしてみる

ここで一回動かしてみましょう。
実行関数がgetMeetUrlになっていることを確認して、Playボタンを押します。

初回実行時は権限に関するダイアログが出てくると思いますが、ContinueAcceptを押して承認します。
エラーが起きない場合何も出てこないと思いますが、 View > Logsを押すと、下のような画面が出てきて、meetのリンクが取得できていることがわかります。
image.png

gasでやってること自体は単純で、

  1. Google Calendar APIで、会議付きの予定を作る
  2. 会議リンクを取得する
  3. 予定を削除する
    の3つだけです。

Meetの会議リンクは、一度生成すると予定を削除しても使えてしまうので、空のカレンダーを作成してリンクだけ取得します。

🤝 Slackと連携する

1. Outgoing WebHooksの準備

SlackのサイドバーにあるAppから、Outgoing WebHooksを探して追加する。
image.png

image.png
image.png

この時点で、トリガーワードを設定しておきましょう。
image.png
URLは一旦空のままで大丈夫です。
トークンは後で使うので、コピーしておきましょう。

2. SlackAppを作る

Create an Appを押して、アプリを作っていきます。
image.png

アプリ名を適当につけて、Workspaceを選択します。
image.png

Botsから、Botユーザを追加します。Add Display Nameから表示名などを追加するだけです。
image.png

次に、Botに渡す権限を指定します。
メッセージの書き込みをするので、chat:writechat:write.publicを選択します。
image.png

image.png

権限の設定が終わるとInstall App to Workspaceが押せるようになっているので、クリックしてアプリの連携を承認します。
image.png

ようやくトークンが発行されました。 このBot User OAuth Access Tokenはコピーしておきましょう。
image.png

3. GASにライブラリを追加する

とても便利そうなライブラリを見つけたので、ありがたく使わせていただきます🙇🏻‍♂️(https://qiita.com/soundTricker/items/43267609a870fc9c7453)。

Resources > Libraries...を開いて、次の値で検索して追加をします。
M3W5Ut3Q39AaIwLquryEPMwV62A3znfOO
image.png
2020/08時点では最新バージョンは22でした。

次に、 File > Project propertiesScript propertiesを開いて、トークン情報を記入していきます。

Property name Token
SLACK_ACCESS_TOKEN Appを作った時にコピーしたBot User OAuth Access Token
OUTGOING_WEBHOOK_TOKEN Outgoing Webhook連携時にコピーしたトークン
image.png

4. GASのコードを追加する

Slackから呼び出すためのdoPost関数を作ります。
先ほど書いたコードは消して、以下のコードに上書きしてしまってください。

meet_gacha.gs
function getMeetUrl() {
  const calendarId = 'primary';
  const dt = new Date();
  const date = dt.getFullYear() + '-' + (dt.getMonth() + 1) + '-' + dt.getDate();
  const requestId = Math.random().toString(32).substring(2);
  const response = Calendar.Events.insert({
    summary: "temp_event",
    singleEvents: true,
    allDayEvent: true,
    start: {
      date,
    },
    end: {
      date,
    },
    conferenceData: {
      createRequest: {
        requestId,
        conferenceSolutionKey: {
          type: "hangoutsMeet"
        },
      }
    }
  },calendarId, { conferenceDataVersion: 1 })
  
  Calendar.Events.remove(calendarId, response.id)
  
  if (response.conferenceData.createRequest.status.statusCode === "success") {
    return response.conferenceData.entryPoints[0].uri
  }
}

function doPost(e) {
  const token = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN')
  const verifyToken = PropertiesService.getScriptProperties().getProperty('OUTGOING_WEBHOOK_TOKEN')

  if (verifyToken != e.parameter.token) {
    throw new Error("invalid token.")
  }

  const meetUrl = getMeetUrl()
  const message = meetUrl !== undefined ? `Meetの部屋を作ったよ\n${meetUrl}` : "URL生成できなかった。ごめんね"
  
  const slackApp = SlackApp.create(token)
  slackApp.chatPostMessage(e.parameter.channel_id, message)
}

最後に、公開作業です。
Publish > Deploy as web Appを開いて、アクセス可能ユーザーを匿名も可にしてください。
image.png

URLが生成されるので、コピーしましょう。
image.png

Outgoing Webhookのページに戻り、コピーしたURLを貼り付けます。
image.png

これで完成!🎉
Slackでトリガーワードを呟いてみましょう。

💥 プライベートチャンネルやDMで使えない

このままでも十分なんですが、Outgoing WebhookはプライベートチャンネルやDMでは動いてくれません。
応用編として、コマンドを作ってみましょう。

1. Slash Commandを登録する

Appを作った時のページを開いて、Slash Commandを登録します
image.png

好きなコマンドを入れましょう。
Request URLは、先ほど公開したGASのリンクを貼り付けます。
image.png

SlackBotが更新されたから再インストールしてって言われるので、再インストールしてあげましょう。
image.png

ついでに、トークンをコピーしておきましょう。
Basic InformationのページからVerification Tokenの箇所にあるトークンです。
image.png

2. GASのスクリプトを修正

次に、GASをSlash Commandに対応させましょう

meet_gacha.gs
function getMeetUrl() {
  const calendarId = 'primary'; // 一時的にイベントを作成するカレンダーのID
  const dt = new Date(); // 日付は適当に設定
  const date = dt.getFullYear() + '-' + (dt.getMonth() + 1) + '-' + dt.getDate();
  const requestId = Math.random().toString(32).substring(2); // 適当な文字列を作る
  const response = Calendar.Events.insert({
    summary: "temp_event",
    singleEvents: true,
    allDayEvent: true,
    start: {
      date,
    },
    end: {
      date,
    },
    conferenceData: {
      createRequest: {
        requestId,
        conferenceSolutionKey: {
          type: "hangoutsMeet"
        },
      }
    }
  },calendarId, { conferenceDataVersion: 1 })
  
  Calendar.Events.remove(calendarId, response.id)
  
  if (response.conferenceData.createRequest.status.statusCode === "success") {
    return response.conferenceData.entryPoints[0].uri
  }
}

function doPost(e) {
  const slackAccessToken = PropertiesService.getScriptProperties().getProperty('SLACK_ACCESS_TOKEN')
  const outgoingWebhookToken = PropertiesService.getScriptProperties().getProperty('OUTGOING_WEBHOOK_TOKEN')
  const slackAppToken = PropertiesService.getScriptProperties().getProperty('SLACK_APP_TOKEN')
  const verifyTokens = [outgoingWebhookToken, slackAppToken]
  
  const requestToken = e.parameter.token
  if (!verifyTokens.includes(requestToken)) {
    throw new Error("invalid token.")
  }
  
  const meetUrl = getMeetUrl()  
  const message = meetUrl !== undefined ? `Meetの部屋を作ったよ\n${meetUrl}` : "URL生成できなかった。ごめんね"

  if (requestToken === outgoingWebhookToken) {
    const slackApp = SlackApp.create(slackAccessToken)
    slackApp.chatPostMessage(e.parameter.channel_id, message)
  } else if (requestToken === slackAppToken) {
    return ContentService.createTextOutput(JSON.stringify({text: message, response_type: 'in_channel'})).setMimeType(ContentService.MimeType.JSON);
  }
}

また、先ほどコピーしたトークンをプロパティに追加します。
キーは SLACK_APP_TOKENとしてください。
image.png

3. 公開版を更新して完成

Project versionは、必ずNewにしてください(じゃないと更新されない)。
image.png

これでSlash Commandが使えるようになりました!🎉

image.png

🌟 まとめ

SlackからサクッとMeetのリンクを発行することができるようになりました!🎉🎉🎉
参加者に共有するためにURLをコピペする必要がないってのが、個人的にとても嬉しい。

……嬉しいんですが、僕が今働いている会社はTeamsが主流なんですよね🥺(悲しい)

GSuiteをお使いの方は、ぜひ使ってみてください!!

参考

実はGASをまともに触るの初めてで、いろんな方の記事を参考にさせていただきました🙇🏻‍♂️
https://qiita.com/aromanokarisu/items/d7fd00d467812f20e25f
https://qiita.com/soundTricker/items/43267609a870fc9c7453
https://qiita.com/pistaman/items/a542119ea28871960477
https://qiita.com/chikuwa111/items/7a1a349b82318a5861cc

21
21
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
21
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?