Google Apps Script (GAS) で毎週 30 分の雑務を自動化した話

Google Apps Script を使って、毎週の雑務を自動化した話を書きます。

## Google Apps Script とは

[Google Apps Script](https://developers.google.com/apps-script/) (GAS) は G Suite 系のサービスをはじめ、Google アプリケーションの API を簡単にクラウドで実行できる環境。言語は JavaScript で書ける。GAS から外部 API も叩けるので、Google アプリケーション以外のサービスとのつなぎこみも可能。無料で使える。

## 自動化したこと

現在のプロジェクトではドキュメントや議事録を残すのに、 [Qiita:Team](https://teams.qiita.com/) を利用している。1 MTG 1 ページでアジェンダページを投稿している。自動化したのは **週初めにその週にある MTG のアジェンダページを一括投稿し、関係者に周知する作業**。参加する MTG の数が増えてくると、この作業だけで時間がかなり取られるので自動化で楽になった。

## 実装方針

Qiita:Team にもテンプレート機能があるが、 MTG によって参加者や時間・タイトルを分けるためにテンプレートを量産したくなかったので、Google Docs でテンプレート管理した。具体的には以下のようなファイルを MTG の種類ごとに持つ。

<img width="860" alt="スクリーンショット 2017-12-19 15.09.52.png" src="https://qiita-image-store.s3.amazonaws.com/0/19698/b9a1e770-b392-62d9-58c0-a6825c0db4fd.png">

サンプルのテンプレートファイルと、全文コードは gist にて。
https://gist.github.com/tanabee/6d42e416c7beef8ecd7288b8b0332edb

以下、各ポイントを説明する。

## 1. Google カレンダーから定例 MTG の予定を抽出

<img width="1170" alt="スクリーンショット 2017-12-11 17.11.01.png" src="https://qiita-image-store.s3.amazonaws.com/0/19698/d3dd0cf7-02eb-873c-2776-1b30c839fb4d.png">

GAS で Google カレンダーからイベント情報を引っぱってくるのは [CalendarApp.getDefaultCalendar().getEvents()](https://developers.google.com/apps-script/reference/calendar/calendar-app#getEvents(Date,Date)) メソッドを使用。ほぼワンラインで書けてしまうところがすごい！

```JavaScript
var now = new Date();
var end = new Date(now.getTime() + (7 * 24 * 60 * 60 * 1000));// 一週間後
CalendarApp.getDefaultCalendar().getEvents(now, end, {search: "MTG名を書く"})[0];
```

## 2. テンプレートから記事のタイトル、本文を生成

テンプレートとして作成した Google Docs のドキュメントを開くのは [DocumentApp.openById()](https://developers.google.com/apps-script/reference/document/document-app#openById(String)) を使用する。 ID は Google Docs を開いたときの URL の
`https://docs.google.com/document/d/[ここがID]/edit`。

日付や時間を設定する部分を `[[DATE]]`, `[[DURATION]]` のようにしており、この文字列を Google カレンダーのイベント情報から取得した値で置換する。

```JavaScript
// Qiita の記事作成
function makeArticle(calendarEvent, docId) {
  var doc = DocumentApp.openById(docId);
  var title = doc.getName().replace('[[DATE]]', getDateFormatted(calendarEvent));
  var body = doc.getBody()
                .getText()
                .replace('[[DATE]]', getDateFormatted(calendarEvent))
                .replace('[[DURATION]]', getDuration(calendarEvent));
  return {
    title: title,
    body: body
  };
}
```

## 3. Qiita:Team に議事録ページを投稿

<img width="796" alt="スクリーンショット 2017-12-11 17.27.48.png" src="https://qiita-image-store.s3.amazonaws.com/0/19698/104bce28-2a58-53ae-16fc-07313786abc1.png">

Qiita API などの外部サービスの API を叩く時には、 [UrlFetchApp.fetch()](https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetch(String,Object)) を使用。 Qiita:Team には [Qiita:Team API ドキュメント](https://qiita.com/api/v2/docs)に従って API トークンを取得し、 [POST /api/v2/items](https://qiita.com/api/v2/docs#post-apiv2items) する。

```JavaScript
// Qiita:Team に投稿する
function postArticle(article) {
  var url = 'http://globis.qiita.com/api/v2/items';
  var token = '[Qiita:Team の API トークン]';

  var data = {
    "title": "記事タイトル",
    "body": "記事本文",
    "coediting": true,// 共同編集を有効化
    "tags": [
      {
        "name": "議事録"
      }
    ]
  };
  var payload = JSON.stringify(data);
  var res = UrlFetchApp.fetch(url, {
    method: 'POST',
    headers: {
      "Content-Type": 'application/json',
      Authorization: 'Bearer ' + token
    },
    payload: payload
  });
  var content = JSON.parse(res.getContentText("UTF-8"));
  return content.url;
}
```

## 4. 投稿したページの URL を Google カレンダーに記入

<img width="596" alt="スクリーンショット 2017-12-11 17.43.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/19698/45abb22a-b2fa-ae6c-ca52-600c61a6ea47.png">

カレンダーの詳細文を更新するのは [CalendarEvent.setDescription()](https://developers.google.com/apps-script/reference/calendar/calendar-event#setDescription(String)) でできる。現状の詳細文を更新する場合は get した文字列に追記して set すればオッケー。

```JavaScript
// カレンダーの説明文の先頭に URL 追記
function updateCalendarDescription(url, event) {
  var description = event.getDescription();
  description = 'アジェンダ＆議事録\n' + url + '\n\n' + description;
  event.setDescription(description);
}
```

## 5. Slack Channel に投稿

<img width="511" alt="スクリーンショット 2017-12-11 18.15.59.png" src="https://qiita-image-store.s3.amazonaws.com/0/19698/c4b64153-5bfa-7298-121d-bd6602f22ef1.png">

Qiita:Team API を叩くところと同じく [UrlFetchApp.fetch()](https://developers.google.com/apps-script/reference/url-fetch/url-fetch-app#fetch(String,Object)) メソッドで Slack に投稿。

```JavaScript
// Slack に POST
function postSlack(name, slackUrl, qiitaUrl) {
  var body = {
    text: '「' + name + '」のアジェンダ＆議事録はこちらです :bow: ' + qiitaUrl
  };
  var payload = JSON.stringify(body);
  var res = UrlFetchApp.fetch(slackUrl, {
    method: 'POST',
    headers: {
      "Content-Type": 'application/json'
    },
    payload: payload
  });
}
```

別途 Slack の Incoming Webhooks を設定する必要がある。 
以下の URL から追加できる。指定の Channel を選んで作成すると Webhook URL が生成される。
`https://[workspace名].slack.com/apps/manage/custom-integrations`

## 毎週実行するための作業

毎週月曜の朝にこのスクリプトを呼びだすようにする。GAS の画面で「編集＞現在のプロジェクトのトリガー」から設定。 cron みたいなのを別で立てる必要がないのはすごく良い。他にも手元で実行（特にデバッグ時に）したり、API として公開したりできるので、ケースに合わせて実行の仕方を選べる。

<img width="856" alt="スクリーンショット 2017-12-11 18.24.17.png" src="https://qiita-image-store.s3.amazonaws.com/0/19698/1c6e40ab-bea4-1e05-07d7-22551edb7f19.png">

## まとめ
これで毎週月曜に出社すると勝手にアジェンダ＆議事録ページが出来上がって、関係者に周知するのを自動化できました。100行程度でこれが書ける GAS はすごいですね！社内の他の MTG でも使われ始めています。Slack にポストする際のユーザーを自分っぽくしておくと仕事やった感を出せて一石二鳥w

G Suite を使っている会社だと、メールやカレンダーなどもゴニョゴニョできるので、いろんな自動化ができそうですね（例えば [Google Apps Scriptで、ラベルがない未読メールを全て既読にする](https://qiita.com/ttyokoyama/items/1aa6977043fb0245342a) とか [SlackとGASを使って会社のお弁当発注を自動化した話](https://qiita.com/kazuooooo/items/3a605a4d0e20df870eaf) とか ）！ 毎週 N 分 x M 人 x L 種類の作業自動化が掛け算的にできてくると、全体の生産性がかなり上がりそうなので、これからも小ネタを見つけてやっていこうと思います。

## 他の GAS ネタ

- [毎月 500 時間の社内ルーティンワークを GAS を使って自動化した話](https://qiita.com/tanabee/items/ce9c3cf9403c4f3f14a9)
- [3 分で作る無料の翻訳 API with Google Apps Script](https://qiita.com/tanabee/items/c79c5c28ba0537112922)
- [GAS ビギナーが GAS を使いこなすために知るべきこと 10 選](https://qiita.com/tanabee/items/2c51681396fe12b6a0e4)
- [社内メンバーの Qiita 新着投稿を Slack で共有するスクリプトを GAS で作った話](https://qiita.com/tanabee/items/665917d9ab976661115c)