見出し画像

会議資料追加を自動通知!Google ドライブ の神機能!

というタイトルで、久しぶりに GAS によるプログラムを公開です!!!

最近は、ChatGPT や Bard で、誰でもサクッとプログラミングができてしましますね笑
でも、こういう手の込んだものは、やはり基礎知識が必要になってきます!

というのも、適切に指示をしてあげたり、どうしてもエラーが出てしまうところを、デバッグしていかないといけないですからね。

デバッグの指示も、エラーの原因となっている箇所を指摘してあげるとよかったりと、誰でも簡単という感じだけではないんですよね😅

まぁ、これも時間の問題かなと思いますが😎笑
プログラミング的な思考の重要さは、これからも続くと思います!!!


本題です!!

この機能は何かというと。

Google ドライブ に新しいフォルダやファイルが追加されたときに、それを任意の相手にメールすることができます!

ドライブ を使って、会議資料などを共有されている場合、データが追加されたかをわざわざ確認しにいかないといけなかったりしますよね。

もちろん!ドライブ には検索機能がついていて、とても優秀なので、ほしい資料があれば、

↓のような ドライブ で検索 というところから検索をかけてあげればヒットします!

それ以外に、学校だと教務の先生や管理職の先生が資料をまとめたり、職員にメールをしたりと、煩雑な作業があったりもしますよね…。

そういった時に、少しでも楽にできるかなと思います!

DX の観点から、いろんな改善の視点がありますが、今回は自動化をテーマにして、プログラミングをしてみました!

動画はこちら!


[0] 準備

下記のリンクからプログラム入り Google スプレッドシート のコピーを作成してください!

プログラムは中に入っています!

[1] 通知が欲しい ドライブ のURLをコピー

例えば、6月会議資料、7月会議資料のようなフォルダを作ってあげて、
そのフォルダのURLをコピーします。

コピーしたURLをB列に貼り付けます!

[2] 送信相手の決定

次に、このフォルダに新しいファイルが追加された時に、通知を送る先を決定します!

該当行のF列にメール送信先がありますので、ここにアドレスを入力してください!

実際には、会議資料まとめる担当の先生や、全職員の Google グループ のアドレスなんかを入れると良いですね!😊

[3] 実行したいフォルダを選択

A列にチェックを入れると、その行にあるフォルダに対して、プログラムが働きます!!

不要になったらチェックを外しましょう!!

実行数が多いとエラーが出てしまいます😓

[4] 実行

拡張機能 ▶️ AppsScript からプログラムを開きましょう!

プログラムはこんな感じ。

/**
 * Google Driveの特定のフォルダ内のファイルとフォルダ情報を取得し、各フォルダ名のシートに出力します
 * 新しいファイルやフォルダが追加された場合には、メールで通知されます
 *
 * 使い方:
 * 1. ドライブ内の監視したいフォルダディレクトリのURLをmainシートのB列に入力します
 * 2. mainシートのA列には、その行のフォルダ監視が有効かどうかを表すTRUE/FALSEを入力します
 * 3. mainシートのF列にはメール送信先のアドレスを入力します
 * 4. スクリプトのトリガーを設定して、定期的にcheckNewFiles()関数が実行されるように設定します
 *
 * 注意点:
 * - Google App Scriptのプロジェクト名は任意です 
 * - フォルダの階層が変わると影響してしまうため、可能であればフォルダ構成は変更しないでください
 * - フォルダに新しいファイルやフォルダが追加されずに更新された場合、メール送信は行われません
 */

// Googleドライブの新規ファイルやフォルダの変更をチェックする関数
function checkNewFiles() {
  // 現在のスプレッドシートを取得します
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var mainSheet = ss.getSheetByName('main');
  var data = mainSheet.getDataRange().getValues();

  // データの行数分ループします
  for (var i = 0; i < data.length; i++) {
    var row = data[i];
    // 通知フラグを取得します
    var notifyFlag = row[0];

    // 通知フラグがtrueの場合、以下の処理を行います
    if (notifyFlag) {
      // フォルダURLを取得します
      var folderUrl = row[1];
      // フォルダURLが有効でない場合、次のループへスキップします
      if (!isValidFolderUrl(folderUrl)) {
        continue;
      }
      // フォルダIDを取得します
      var folderId = getIdFromUrl(folderUrl);
      // フォルダIDからフォルダを取得します
      var folder = DriveApp.getFolderById(folderId);
      // フォルダ名を取得します
      var folderName = folder.getName();

      // フォルダ名、最終更新日、オーナーを更新します (列 3, 4, 5)
      mainSheet.getRange(i + 1, 3, 1, 3).setValues([
        [folderName, new Date(), folder.getOwner().getEmail()]  // 最終更新日は現在の日付と時刻に更新します
      ]);

      // 新しいフォルダの内容を出力し、新しいURLを取得します
      var sheet = ss.getSheetByName(folderName);
      if (!sheet) {
        // 指定名のシートが存在しない場合、新しく作成します
        sheet = createSheet(ss, folderName);
      }

      // 既存のURLを取得します
      var existingUrls = getExistingUrls(ss, folderName);
      // フォルダ内容を出力し、新規のファイルとフォルダを取得します
      var newFilesAndFolders = outputFolderContents(folderId, sheet, existingUrls);

      // 新しいファイルやフォルダがある場合、メールを送信します
      if (newFilesAndFolders.length > 0) {
        var emailRecipient = row[5];
        var emailBody = '以下のファイルまたはフォルダが新たに追加されました:\n\n';
        for (var j = 0; j < newFilesAndFolders.length; j++) {
          var fileData = newFilesAndFolders[j];
          emailBody += '名前: ' + fileData.name + '\n';
          emailBody += 'URL: ' + fileData.url + '\n';
          emailBody += '種類: ' + fileData.type + '\n';
          emailBody += '最終更新日時: ' + fileData.lastUpdated + '\n';
          emailBody += 'オーナー: ' + fileData.owner + '\n';
          emailBody += 'フォルダ構成: ' + fileData.ancestry + '\n\n';
        }

        MailApp.sendEmail(emailRecipient, '新しいファイルまたはフォルダが追加されました: ' + folderName, emailBody);
      }
    }
  }
}

// シートに存在するURLを取得する関数
function getExistingUrls(ss, folderName) {
  var sheet = ss.getSheetByName(folderName);
  // シートが存在しない、またはシートの行数が2未満の場合、空の配列を返します
  if (!sheet || sheet.getLastRow() < 2) {
    return [];
  }

  var urls = sheet.getRange(2, 2, sheet.getLastRow() - 1, 1).getValues();
  return urls.flat();
}

// フォルダの内容を出力し、新しいファイルとフォルダをフィルタリングする関数
function outputFolderContents(folderId, sheet, existingUrls) {
  var folder = DriveApp.getFolderById(folderId);

  // フォルダの階層を取得します
  var ancestry = folder.getName();

  var fileDataList = [];
  outputFolderInfo(folder, ancestry, fileDataList);

  // シートの内容をクリアし、すべてのファイルデータを一度に書き込みます
  sheet.clearContents();
  sheet.appendRow(['名前', 'URL', '種類', '最終更新日時', 'オーナー', 'フォルダ構成']);
  fileDataList.forEach(function(fileData) {
    sheet.appendRow([fileData.name, fileData.url, fileData.type, fileData.lastUpdated, fileData.owner, fileData.ancestry]);
  });

  // 新しいファイルとフォルダをフィルタリングします
  var newFilesAndFolders = fileDataList.filter(function (fileData) {
    return !existingUrls.includes(fileData.url);
  });

  return newFilesAndFolders;
}

// フォルダの情報を出力し、その内容をリストに追加する関数
function outputFolderInfo(folder, ancestry, fileDataList) {
  var files = folder.getFiles();
  var childFolders = folder.getFolders();

  // フォルダ内のファイルをリストに追加します
  while (files.hasNext()) {
    var file = files.next();
    var fileData = getFileData(file, 'ファイル', ancestry);
    fileDataList.push(fileData);
  }

  // フォルダ内のサブフォルダをリストに追加し、その内容を出力します
  while (childFolders.hasNext()) {
    var subFolder = childFolders.next();
    var subFolderAncestry = ancestry + ' > ' + subFolder.getName();
    var subFolderData = getFileData(subFolder, 'フォルダ', subFolderAncestry);
    fileDataList.push(subFolderData);
    outputFolderInfo(subFolder, subFolderAncestry, fileDataList);
  }
}

// フォルダURLが有効かどうかを検証する関数
function isValidFolderUrl(url) {
  if (!url) {
    return false;
  }

  // Google DriveのフォルダURLのパターンを用いて検証します
  var regex = /^https:\/\/drive\.google\.com\/drive\/folders\/[\w_\-]+$/;
  return regex.test(url);
}

// URLからフォルダのIDを取得する関数
function getIdFromUrl(url) {
  // URLの 'folders/' 以降がフォルダのIDとなります
  var id = url.split('folders/')[1];
  return id;
}

// ファイルまたはフォルダの情報を取得する関数
function getFileData(fileOrFolder, type, ancestry) {
  var fileData = {};
  fileData.name = fileOrFolder.getName();
  fileData.url = fileOrFolder.getUrl();
  fileData.type = type;
  fileData.lastUpdated = fileOrFolder.getLastUpdated();
  fileData.owner = fileOrFolder.getOwner().getEmail();
  fileData.ancestry = ancestry;
  return fileData;
}

// 指定名で新しいシートを作成する関数
function createSheet(ss, folderName) {
  var sheet = ss.insertSheet(folderName);
  sheet.appendRow(['名前', 'URL', '種類', '最終更新日時', 'オーナー', 'フォルダ構成']);
  return sheet;
}

まずは ▶️ 実行をクリックしてみましょう!

初めての実行の場合は、権限の承認がありますので、↓を参考にしてください!

[5] 実行結果

新しいシートが作成されて、

そのフォルダ内のファイルが一覧になります!
(フォルダにも対応しています!サブフォルダ内のファイルやフォルダもOKです✨)

そしてメールが届きます!

[6] こんな機能がついてます

では、新しいデータを追加してみましょう。

このように、新しいデータやフォルダを入れて、再び実行してみると…。

下記のように、追加されます!
ちゃんとフォルダ構成も出すようにしているのが良いですよね🤣笑

新しいデータのみをメールで教えてくれます!!👍

最初に、URLで指定したフォルダの名前のシートが、自動で作成されるので。
会議の名前のフォルダを作っておくと、↓のように。

スプレッドシートに過去の会議の資料のリンクが一覧でまとまるようになります!

見返す時も楽ですよね!

[7] 自動化の設定

自動化するためには、左側の⏰(トリガー)を設定する必要があります!

次に、右下のトリガーを追加をクリックします!

イベントのソースを選択時間主導型 に変更します!

時間ベースで1時間がデフォルトになっているので、このままでいいのかな?と思います。

分ベース にしたりも変更できますが、そこまで頻繁にメールが来なくてもいいですよね。

ここでまた権限の承認プロセスがあったりしますので、先ほどと同じように許可をしてあげてください!

これでプログラムの解説は終了です!!

このように、ちょっとした工夫や GAS の組み込むことで、作業を楽にしたりすることができますね!

こんなことできないかな??

などなど、ご質問やご依頼がありましたらご連絡ください!!

Twitter

Facebook

ポートフォリオ

YouTube チャンネル

いちばんやさしい Google Apps Script


何かと0から1を作るのは大変だと思います。学校はどこも似たような問題課題に対応していると思います。それなのに、先生って自分だけで頑張ろうとするんですよね。ボクの資料やnoteが1になって、学校ごとの現状に合わせてカスタムしていただければと思います‼️