18
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

posted at

updated at

Organization

オンライン・シャッフルランチを支える技術

はじめに

20卒新卒エンジニアです.コロナの影響で入社式も延期になり,4ヶ月たった今ですら,出社できない状況です.
ついには内定式以来,リアルで同期全員と会ったことがありません...

そこで,強制的にコミュニケーションを取る場を作ろうと,今回シャッフルランチ(リモート)を企画しました!
同期のカレンダーに勝手にランチイベントを突っ込む極悪非道の企画です

この記事では,オンラインシャッフルランチの企画を支える技術としてGASを使って,自動的にGoogle Meetを有効にした状態でGoogleカレンダーランチイベントを登録する方法を紹介します.

やりたいこと

参加メンバーをシャッフルして3人グループを作る

※ オンラインで話すなら,これぐらいが程よかったので1グループ3人としました.
グループ化の様子

グループごとにGoogleカレンダーにランチイベントを登録

共有カレンダーを使ってグループごとにランチを招待します
events.PNG

Googleカレンダーから直接Google Meetにアクセスできるようにする

イベント内容の様子

考えるべきこと

余る人がでた場合

3人で1グループ作るとすると,余りが1人または2人でる可能性があります
グループ化の様子

このような場合,以下のようにグループを再編することでボッチを回避しました.

  • 1人余る場合は,4人グループを1つ作成
  • 2人余る場合は,4人グループを2つ作成

グループ再振り分けの様子

メンバー情報の取得方法

カレンダー登録するためには,メンバーのメールアドレスが必要です.

新卒同期が参加する共有カレンダーを作っているので,そこからメンバー情報(メールアドレス)が取得できないか検討しましたが,直接は無理そうでした.

なので,今回はスプレッドシートメンバーリストを記載して,そこから取得するようにしました.
詳細は後述します.

準備

コーディングを行う前に,いくつか用意することがあります.
このセクションでは,準備事項について詳細に説明します.

カレンダーID

GASからカレンダーを操作するために,カレンダーIDが必要です.

取得方法は,Google Calendarから歯車マーク -> 設定 -> 参加している共有カレンダーを選択すると,ページ下に赤枠で囲ったカレンダーIDが表示されます.これを使うのでコピーしておきます.

calendarid.PNG

スプレッドシート

スプレッドシートの作成

Google Driveの任意の場所にスプレッドシートを作成します.

スプレッドシートの様子

メールアドレスとカレンダーIDを記載

シート名を「test」として,

  • 1列目に参加するユーザのメールアドレス
  • 2列目には,先程コピーしたカレンダーID

スプレッドシートの様子

Calendar API

スプレッドシートのタブからツール -> スクリプトエディタを選択すると,GASエディタが表示されます.
ここで,Calendar APIを利用するために,タブからリソース -> Googleの拡張サービスを選択し,Calendar APIをONにします.

GASの様子

以上で,準備が整いました.

コーディング

最終的なコードはGitHubに上げています.

このセクションでは,作成したコードについてそれぞれ詳細に説明します.

スプレッドシートの操作

メールアドレス一覧の取得

スプレッドシートから情報を取得するために,インスタンスを作成しています.
メールアドレスは,getRangeで2行1列を始点,getLastRowで終点を指定してgetValuesで配列としてすべてのメールアドレスを取得します.

シートの操作
// シートオブジェクトを作成
const ss = SpreadsheetApp.getActiveSpreadsheet();
// 操作するシートのオブジェクトを取得
const sheet = ss.getSheetByName('test');
// ユーザのEmailアドレスをシートから取得
const emails = sheet.getRange(2, 1, sheet.getLastRow() - 1).getValues();

配列のフォーマット

取得したメールアドレス一覧が格納された配列の中身は以下のようになっています.

初期配列の様子
[['xxx@example.com'], ['xxx@example.com'], ['xxx@example.com']]

後述するカレンダー登録でユーザを指定するためには,以下のような形式にフォーマットする必要があります.

フォーマット後の配列
[{'email': 'xxx@example.com'}, {'email': 'xxx@example.com'}, ... , {'email': 'xxx@example.com'}]

そのためのコードは以下のようになります.

配列のフォーマット
// Calendar API用にフォーマット
const formatedEmails = shuffle(emails).map(email => ({'email': email[0]}));

カレンダーIDの取得

スプレッドシートの2行2列目にあるカレンダーIDを取得します.

カレンダーIDの取得
// 共有カレンダーのIDをシートから取得
const calendarId = sheet.getRange(2, 2).getValue();

シャッフル

配列の要素をランダムに並び替えるコードは以下のようになります.

配列をシャッフル
// 配列の要素をシャッフル
function shuffle(array){
  var result = [];
  for(i = array.length; i > 0; i--){
    var index = Math.floor(Math.random() * i);
    var val = array.splice(index, 1)[0];
    result.push(val);
  }

  return result;
}

グループの作成

基本的には,3人で1グループを作成します.
グループは以下のように配列にネストした形で表現しています.

グループ化を行った配列の様子
[
  [
   {'email': 'xxx@example.com'},
   {'email': 'xxx@example.com'},
   {'email': 'xxx@example.com'}
  ],
  [
   {'email': 'xxx@example.com'},
   {'email': 'xxx@example.com'},
   {'email': 'xxx@example.com'}
  ]
]

余りがでた場合は前述したとおり,4人グループを作成します.
Switch文ではその処理をおこなっています.

そもそも人数が少ない場合(5人以下)は,グループ化せずそのまま返すようにします.

グループの作成
// グループ作成
function createLunchGroups(array) {
  const arrayLen = array.length;
  // 作成できるグループ数
  const groupNum = Math.floor(arrayLen / 3);
  var result = [];

  // グループ数が2つ未満だった場合、グループ分けを行わない
  if (groupNum < 2) {
    result.push(array)
    return result;
  }
  // 3人一組でグループ分けを行う
  switch (arrayLen % 3) {
    // 1人余る場合: 4人グループを1つ作る
    case 1:
      // 4人グループを1つ作成
      result.push(array.slice(0, 4));
      // 3人グループを作成
      for (i = 2; i <= groupNum; i++) {
        result.push(array.slice(i*3-2, i*3+1));
      }
      break;
    // 2人余る場合
    case 2:
      // 4人グループを2つ作成
      for (i = 0; i < 2; i++) {
        result.push(array.slice(i*4, i*4+4))
      }
      // 3人グループ作成
      for (i = 3; i <= groupNum; i++) {
        result.push(array.slice(i*3-1, i*3+2));
      }
      break;
    // 3人ちょうどで作れる場合
    default:
      for (i = 1; i <= groupNum; i++) {
        result.push(array.slice(i*3-3, i*3))
      }
      break;
  }

  return result;
}

Googleカレンダーへの登録

カレンダーにイベントを登録をするには「Calendar.Events.insert」を使います.

引数には,イベントの詳細情報をパラメータとして渡すことで細かい制御が可能です.

今回は,

  • タイトルおよびイベントの説明
  • 場所
  • 開始日時および終了日時
  • Google Meetの設定
  • attendsで招待するユーザを指定

をパラメータとして渡しています.

特にGoogle Meetを有効化するには,「conferenceDataVersion」の値として1を指定し,「conferenceData」をパラメータで渡す必要があります.

コード
// イベント登録
function createEvent(calendarId, users) {
  // リクエストIDをランダムに生成
  const requestId = Utilities.formatString("shuffle#%d", Math.random()*100);
  // イベントの詳細設定
  const detail = {
    summary: 'シャッフルランチ',
    location: 'リモート',
    description: '同期との交流を目的としたランチ会です!',
    start: {
      dateTime: new Date('2020/8/3 12:00:00').toISOString()
    },
    end: {
      dateTime: new Date('2020/8/3 12:30:00').toISOString()
    },
    conferenceData: {
      createRequest: {
        conferenceSolutionKey: {
          type: "hangoutsMeet"
        },
        requestId: requestId
      }
    },
    attendees: users
  };
  // イベントの登録
  const event = Calendar.Events.insert(detail, calendarId, { conferenceDataVersion: 1 });
  Logger.log('Event ID: ' + JSON.stringify(event));
}

実行

メイン関数としてmainProcessを定義したので,これを実行します.

メイン関数
function mainProcess() {
  // シートオブジェクトを作成
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  // 操作するシートのオブジェクトを取得
  const sheet = ss.getSheetByName('test');
  // ユーザのEmailアドレスをシートから取得
  const emails = sheet.getRange(2, 1, sheet.getLastRow() - 1).getValues();
  // Calendar API用にフォーマット
  const formatedEmails = shuffle(emails).map(email => ({'email': email[0]}));
  // グループの作成
  const lunchGroups = createLunchGroups(formatedEmails);
  // カレンダーIDをシートから取得
  const calendarId = sheet.getRange(2, 2).getValue();
  // グループごとにイベント登録
  lunchGroups.map(group => createEvent(calendarId, group));
}

スクリプトは「Ctrl + R」で実行できます.

実行すると,反映されるまで多少時間かかりますが,30秒ほどでカレンダーにイベント登録がされていると思います.
events.PNG

おわりに

リモートシャッフルランチをいい感じに登録するスクリプトを紹介しました.

なかなかリアルではコミュニケーションが取りづらい状況なので,少しでもオンライン・ランチのハードルが下がり,誰でも気軽に企画できるようになればと思います.

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
Sign upLogin
18
Help us understand the problem. What are the problem?