Google Driveにファイルが追加/削除されたらメールを送るプログラム

# Google Driveにファイルが追加されたら、その情報をメールで送る

##背景
* 会社がまだFAXという前時代的な代物を使っている。
* ただ、[このFAXにはGoogleDriveへのアップロードという素晴らしい機能がついている。Brotherさんありがとう！！](https://download.brother.com/welcome/doc012333/cv_dcp940n_jpn_wcg_a.pdf)
* 会社のみんなに共有するためにFAXが届いたらメールが届く（何が届いているのかも合わせて。）

というのが欲しかった。

## 参考にした情報（と言い訳）
http://yamap55.hatenablog.com/entry/2016/01/24/171331
この方は、Google Driveに写真をアップロードされたらフォルダの更新をメールで通知する、ということを実現していた。
プログラムをきれいに変更する暇はなかったので（今やれよ）パクったコードそのままの名前になっているのをご了承ください。

https://boomin.yokohama/archives/797
こちらの方のソースも参考にしました。（というかあとから気づいたんですがこっちのソースの方をメインにパクっていました）

https://www.pre-practice.net/2018/03/blog-post_89.html
あと、ファイルを削除された時（もしくは移動した時）に何度もメールが来る、という現象になって困っていたのだが、最初は削除するデータを昇順で消していたのだが、コレをすると「2行目」「3行目」「4行目」・・・と消していくときに行自体が消えるので複数データがあったとき、半分ずつしか消えず何度もメールが送られてくる、という現象になっていた。この現象が解消されたので、今回公開することにした。


## 実装方法（準備１）
Googleのアカウントは、「マルチアカウント」であるがGASを利用するコードエディタが正常に動くために、Chromeの「ユーザ」機能を使って、別のログインをするほうがいいです。
（Google アカウントが1つしか無いよ、という人はコレをスキップしてok）

1. Google Chromeの右上の「︙」の左どなりに自分のアイコン or 名前の1文字があると思うのでクリック
2. 下の方に「他のユーザー」があるので、「＋追加」をクリックして目的のGoogle アカウントでログインしてください。


## 実装方法（準備２）
1. Google Driveに[アクセス](https://drive.google.com/drive/my-drive)
2. 任意の場所に、スプレッドシートを作成
3. また、FAXがアップロードされるフォルダ場所も作成（もしくは写真とか、ファイルとか）

## 実装方法（作成したスプレッドシート）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29550/0f119114-c72b-be96-2a2e-52228bc3928d.png)

上記のような感じのを作る

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29550/145236ad-3515-f426-76b7-8cb1041cf941.png)

メニューの、「ツール」→「<>スクリプトエディタ」をクリック

スクリプトを作成する画面が表示されたら次のコードを貼り付ける

```javascript
//対象とするGoogleDriveフォルダのID　ブラウザでアクセスしてURL見れば分かる
var PHOTO_FOLDER_ID = "$GoogleDriveフォルダID";
//更新日時を記録するのスプレッドシートのID　ブラウザでアクセスしてURL見れば分かる
var UPDATE_SHEET_ID = "$スプレッドシートID";
//スプレッドシートのシート名（下に表示されるタブのやつ）
var UPDATE_SHEET_NAME = "シート2";
//宛先
var DIST_MAIL_ADDRESS = "hogehoge@sample.com";
//送り主
var SENDER_MAIL_ADDRESS = ["hogehoge@gmail.com"];

function sorting(a, b){
  if(a > b){
    return -1;
  }else if(a < b ){
    return 1;
  }else{
   return 0;
  }
}

function updateFileCheck() {
  var photoFolder = DriveApp.getFolderById(PHOTO_FOLDER_ID);
  var fileData = {};

  // フォルダ内のファイルの最終更新日時が新しい場合もあるのでそれに対応
  var files = photoFolder.getFiles();
  while (files.hasNext()) {
    var fileobj = files.next();
    var lastFolderUpdateDate = fileobj.getLastUpdated();
      
    // 情報を連想配列に格納
    fileData[fileobj.getName()] = {
      name: fileobj.getName(),
      lastUpdate: lastFolderUpdateDate, // ファイル最終更新日時
      url: fileobj.getUrl(), // ファイルのURL
      diff: 0
    };
  }

  // スプレッドシートに記載されているファイル名と更新日時を取得。
  var spreadsheet = SpreadsheetApp.openById(UPDATE_SHEET_ID);
  var sheet = spreadsheet.getSheetByName(UPDATE_SHEET_NAME);
  var data = sheet.getDataRange().getValues();

  // 取得したデータをMapに変換。
  var sheetData = {};
  //  headerがあるので2から開始
  for (var i = 1; i < data.length; i++) {
    sheetData[data[i][0]] = {
      name: data[i][0],
      lastUpdate: data[i][1],
      url: data[i][3],
      rowNo: i + 1
    };
  }

  // 実際のファイルとスプレッドシート情報を比較。
  var updateFileList = [];
  for (key in fileData) {
    if (key in sheetData) {
      // ファイル名がシートに存在する場合。
      if (fileData[key].lastUpdate > sheetData[key].lastUpdate) {
        //ファイルが更新されている場合。
        updateFileList.push(key);
        sheet.getRange(sheetData[key].rowNo, 2).setValue(fileData[key].lastUpdate);
        sheet.getRange(sheetData[key].rowNo, 3).setValue(fileData[key].url);
      }
    } else {
      // ファイル名がシートに存在しない場合。
      var lowno = sheet.getLastRow() + 1
      sheet.getRange(lowno, 1).setValue(key);
      sheet.getRange(lowno, 2).setValue(fileData[key].lastUpdate);
      sheet.getRange(lowno, 3).setValue(fileData[key].url);
      updateFileList.push(key);
    }
  }

  // 削除されたファイルをチェックして、ファイル一覧から削除
  var deleteFileList = [];
  var rowNos = [];
  for (key in sheetData) {
    if (!(key in fileData)) {
      Logger.log(key + " is deleted. row" + sheetData[key].rowNo);
      rowNos.push(sheetData[key].rowNo);
      deleteFileList.push(key);
    }
  }
  
  if(rowNos.length > 0){
    // Logger.log(rowNos);
    var descending = rowNos.sort(sorting);
    for(key in descending){
      // Logger.log(descending[key]);
      sheet.deleteRow(descending[key]);
    }
    SpreadsheetApp.flush();
  }
     


  // 新規及び更新された情報をメール送信
  if (updateFileList.length != 0 | deleteFileList.length != 0) {

    var bodyText = photoFolder.getName() + "フォルダに、" + updateFileList.length + "個のファイルが追加(変更)されました。\n";
    bodyText += photoFolder.getUrl() + "\n\n";

    // フォルダ名、フォルダ更新日時、フォルダ内のファイル数
    if (updateFileList != 0) {
      bodyText += "ファイル名        \t更新日時\tURL\n";
      for (key in updateFileList) {
        fld = updateFileList[key];
        bodyText += fld + "\t";
        bodyText += fileData[fld].lastUpdate + "\n";
        bodyText += fileData[fld].url + "\n";
      }
    }

    if (deleteFileList != 0) {
      bodyText += "\n以下のファイルが削除されています。" + "\n";
      for (key in deleteFileList) {
        fld = deleteFileList[key];
        bodyText += fld + "\n";
      }
    }

    bodyText += "\n\nこのメールに返信しても見れませんので返信しないでください。";
    // Logger.log(bodyText)

    var titletext = "（更新：" + updateFileList.length + "、削除:" + deleteFileList.length +"） FAX共有フォルダ【" + photoFolder.getName() + "】更新連絡通知";
    MailApp.sendEmail({to:DIST_MAIL_ADDRESS,subject:titletext, body:bodyText});
  } else {
    Logger.log("通知する更新情報がありません")
  }
}
```

## Google DriveのIDとスプレッドシートIDの取得方法
### GoogleDriveのID
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29550/ee22292a-fe31-0072-1eb8-30cc855dd174.png)

フォルダにアクセスしたときのURLをみて、上記のURL部分をコピペしてソースコードの「$GoogleDriveフォルダID」部分に貼り付けてください。

```javascript
//対象とするGoogleDriveフォルダのID　ブラウザでアクセスしてURL見れば分かる
var PHOTO_FOLDER_ID = "1t51lCRBzxxxxxxxxxxxxxxxxxxxxxP_Swq";
```

### スプレッドシートのID

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29550/a3a673a7-36f1-4f4f-6490-415962aaffd3.png)


```javascript
//更新日時を記録するのスプレッドシートのID　ブラウザでアクセスしてURL見れば分かる
var UPDATE_SHEET_ID = "1ebxzdxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxAZM";
```

## 他の変更すべきところ

```javascript
//宛先
var DIST_MAIL_ADDRESS = "hogehoge@sample.com";
//送り主
var SENDER_MAIL_ADDRESS = ["hogehoge@gmail.com"];
```
送り主は、自分のGmailじゃないとうまく行かないと思うぞ。
宛先は、好きにやればいい。だいたいのメールアドレスには送信可能なはずだ。


## トリガーを設定する
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29550/e67c4e68-92e0-41ed-cdc9-5874fa522eac.png)

メニューの「編集」→「現在のプロジェクトのトリガー」に行くと右下に「トリガーを追加」という青いボタンがあるのでクリック

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29550/738beba8-1926-a1b0-452d-26d2dbc8974c.png)

すでに動いているトリガーはたぶん最初はないと思うので次の設定を追加する。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29550/e40210b7-2aa5-a6b0-0096-b8b022380751.png)

１時間おきでよかったり、５分ごとで良かったりするのは、自分で好きに設定してくださいませ。

うまく行けば、定期的に実行される。

## テストとか
手っ取り早くトリガーまで設定してしまっているけれども、もしかしたら何処かが間違っていてうまく行かないとかがあれば、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/29550/d8bdf09e-bf0f-2f03-9268-2161b11f907d.png)
関数を「updateFileCheck」を選択して、「再生マーク」を押してログを確認しつつ頑張ってくださいませ。


以上