GASを利用した定例議事録作成の自動化

# 目標
- 以下の手順で作成している定例議事録を自動化します
    1. 前回の議事録（Googleドキュメント）から新規議事録を手動コピー
    2. 議事録ファイル名を変更
    3. 議事録内の日付を手動で更新
    4. 古い議事録を別フォルダに移動

# 前提
- 定例日は、毎週の月・水・金
- スケジュールされたGASより先に手動で議事録を作成しても問題なく動作すること
- 以下ファイル・フォルダ構成

| 名称 | 種別 | 役割 |
|:-----------------|:-----------------|:-----------------|
| old | フォルダ | 過去議事録保管用フォルダ |
| 2017-02-15 | ファイル | 前回の議事録 |
| 2017-02-13 | ファイル | 過去議事録 |
| 2017-02-10 | ファイル | 過去議事録 |
| 2017-02-08 | ファイル | 過去議事録 |
| 2017-02-06 | ファイル | 過去議事録 |
| 議事録自動生成用GAS | ファイル | GAS本体 |
| その他フォルダ | フォルダ | その他議事録とは関連しないフォルダ |
| その他ファイル | ファイル | その他議事録とは関連しないファイル |

# おおまかな手順
1. [GoogleドライブのフォルダIDのコピー](#google%E3%83%89%E3%83%A9%E3%82%A4%E3%83%96%E3%81%AE%E3%83%95%E3%82%A9%E3%83%AB%E3%83%80id%E3%81%AE%E3%82%B3%E3%83%94%E3%83%BC)
2. [GAS（Google Apps Script）の作成](#gasgoogle-apps-script%E3%81%AE%E4%BD%9C%E6%88%90)
3. [GASの実行をスケジュール化](#gas%E3%81%AE%E5%AE%9F%E8%A1%8C%E3%82%92%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E5%8C%96)

## GoogleドライブのフォルダIDのコピー
特定フォルダ内のファイル検索や指定したフォルダ内の操作のためフォルダIDをコピーします。
コピーするフォルダIDは、「前回の議事録が入っているフォルダ」と「oldフォルダ」が対象です。
以下イメージの赤枠部分がフォルダIDです。
![folder_id.png](https://qiita-image-store.s3.amazonaws.com/0/128800/e1f97f6a-4c11-40b7-6320-e04f3e66419a.png)


## GAS（Google Apps Script）の作成
1. 「議事録自動生成用GAS」Googleドキュメントを開きます
2. メニュー「ツール＞スクリプト エディタ...」を選択します
3. 以下GASコードを入力します

```gas:Code.gs
var folder = DriveApp.getFolderById('ご利用の環境のフォルダIDを指定ください');
var old_folder = DriveApp.getFolderById('ご利用の環境のフォルダIDを指定ください');

/*
* 議事録内の日付を更新
*/
function updateContentDate(file, last_date, date) {
  var content = DocumentApp.openById(file.getId()).getBody();
  return content.replaceText(last_date, date);
}

/*
* 新規作成する議事録ファイル名の取得
*/
function getNewFileName() {
  var date = new Date();
  var day = date.getDay();
  // GASの実行日を判定し、新規作成する議事録の日付を決定する
  var run_day = 0;
  switch(day) {
    case 2:// 火曜日
    case 4:// 木曜日
      run_day = 1;
      break;
    case 6:// 土曜日
      run_day = 2;
      break;
    default:
      return false;
  }
  date.setDate(date.getDate() + run_day);
  
  return Utilities.formatDate(date, 'JST', 'yyyy-MM-dd');
}

/*
* 議事録を作成
*/
function copyAgenda(last_filename, remove_filename) {
  var new_filename = getNewFileName();
  // GASの実行日が予定日と異なっていた場合
  if(!new_filename) {
    return false;
  }
  
  var last_file = folder.getFilesByName(last_filename).next();
  var remove_file = folder.getFilesByName(remove_filename).next();
  
  // すでに議事録が存在していた場合
  if(new_filename == last_file) {
    return false;
  }
  var new_file = last_file.makeCopy(new_filename, folder);
  
  old_folder.addFile(remove_file);
  folder.removeFile(remove_file);
  
  updateContentDate(new_file, last_filename, new_filename);
  
  return true;
}

/*
* コピー対象ファイル名の取得
*/
function getLastFileName() {
  var contents = folder.getFiles();
  var file;
  var name;
  var last_file = new Date("1970-01-01 T00:00:00.000Z");
  last_file = Utilities.formatDate(last_file, "JST", "yyyy-MM-dd")

  while(contents.hasNext()) {
    file = contents.next();
    name =  file.getName() + "T00:00:00.000Z";
    date = new Date(name);
    date = Utilities.formatDate(date, "JST", "yyyy-MM-dd");
    if(last_file < date) {
      last_file = date;
    }
  }

  return last_file;
}

/*
* 削除対象ファイル名の取得
*/
function getRemoveFileName() {
  var contents = folder.getFiles();
  var file;
  var name;
  var remove_file = new Date();
  var date_month_ago = new Date(remove_file.getDate() - 30);
  remove_file = Utilities.formatDate(remove_file, "JST", "yyyy-MM-dd")
  date_month_ago = Utilities.formatDate(date_month_ago, "JST", "yyyy-MM-dd")

  while(contents.hasNext()) {
    file = contents.next();
    name =  file.getName() + "T00:00:00.000Z";
    date = new Date(name);
    date = Utilities.formatDate(date, "JST", "yyyy-MM-dd");
    if((remove_file > date) && (date_month_ago < date)) {
      remove_file = date;
    }
  }

  return remove_file;
}

/*
* メイン処理
*/
function createNewAgenda() {
  var last_filename = getLastFileName();
  var remove_filename = getRemoveFileName();
  var result = copyAgenda(last_filename, remove_filename);
  Logger.log("コピー対象ファイル：" + last_filename);
  Logger.log("削除対象ファイル：" + remove_filename);
  if(result) {
    Logger.log("新規議事録の作成成功しました。");
  } else {
    Logger.log("すでに議事録が存在しています。");
  }
}
```

入力後は、ねんのためGASを実行し、実行した日付のファイル名で議事録が前回の議事録からコピーされていることを確認します。
また、一番古い日付の過去議事録がoldフォルダに移動されていることを確認します。

## GASの実行をスケジュール化
GASのスケジュール化は、以前記事にしているので[こちら](#gas%E3%81%AE%E5%AE%9F%E8%A1%8C%E3%82%92%E3%82%B9%E3%82%B1%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB%E5%8C%96)を参照ください。
今回は、定例後の深夜に実行されるようスケジュールを組みました。
<img width="847" alt="スクリーンショット 2017-02-17 17.48.53.png" src="https://qiita-image-store.s3.amazonaws.com/0/128800/3d90e2db-706f-b11a-25d9-0805b8b4590e.png">


## 発展
以下、祝日や任意の日は議事録を作成しない対応です。

```Code.gs
var public_holiday = ['2017-04-28', '2017-05-01', '2017-05-02'];

/*
* 祝日をGoogleカレンダーから取得
*/
function getHolidayByGoogleCalendar() {
  var url = "https://calendar.google.com/calendar/ical/ja.japanese%23holiday%40group.v.calendar.google.com/public/basic.ics";
  var response = UrlFetchApp.fetch(url);
  var myRegexp = /DTSTART;VALUE=DATE:\d+(?!\.)/g;
  var match;
  var date;
  var dates = [];
  while ((match = myRegexp.exec(response)) != null) {
    date = match[0].replace(/DTSTART;VALUE=DATE:/,"");
    dates.push(date.slice(0,4) + "-" + date.slice(4,6) + "-" + date.slice(6,8));
  }
  return dates;
}

/*
* 新規作成する議事録ファイル名の取得
*/
function getNewFileName() {
  var date = new Date();
  var day = date.getDay();
  // GASの実行日を判定し、新規作成する議事録の日付を決定する
  var run_day = 0;
  var return_date;
  // 祝日をGoogleカレンダーから取得
  Array.prototype.push.apply(public_holiday, getHolidayByGoogleCalendar());
  
  true_holiday: while(1) {
    switch(day) {
      case 2:// 火曜日
      case 4:// 木曜日
        run_day = 1;
        break;
      case 6:// 土曜日
        run_day = 2;
        break;
      default:
        return false;
    }
    date.setDate(date.getDate() + run_day);
    return_date = Utilities.formatDate(date, 'JST', 'yyyy-MM-dd');
    
    for each(var holiday in public_holiday){
      if(holiday == return_date) {
        // GAS実行日に日付をずらす
        date.setDate(date.getDate() + 1);
        day = date.getDay();
        continue true_holiday;
      }
    }
    break;
  }
  
  return return_date;
}
```

グローバル変数（public_holiday）と新規メソッド（getHolidayByGoogleCalendar）を追加し、既存メソッド（getNewFileName）を改修しています。
祝日情報はGoogleカレンダーから取得し、任意の日（議事録を作成したくない日）はグローバル変数であるpublic_holiday配列に指定します。