Google Apps Script 自動化對 Google Drive 的操作(二)自動列出所有檔案並設定權限 (2021 鐵人賽 D10)

來到了第十天。我們的習慣是先講結論,如果你很急著用,可以直接使用這份 Add-On: Drive Explorer,功能還蠻強大的!自己寫的好處是,如果你想結合其他功能會比較方面。對於想知道怎麼做的人,讓我們開始吧!

目標

讓我們借一下昨天的敘述。現在幾乎每天都會打開 Google Drive,但有時當檔案一多,就會面臨兩個問題——權限設置不清,當一個人加入或離職時,要重複好幾次開開關關。又或是要將不同的線上文件寄信並分享給不同人,抑或是交接時的檔案權限轉移,這些都會需要知道檔案 ID。有沒有一個快速的方式,可以讓我們抓出特定資料夾內的檔案 ID,並用一個表格管理權限呢?

  1. 要怎麼列出 Google Drive 中的檔案 ID 們?
  2. 要怎麼取得 Google Drive 中的檔案們的權限?
  3. 要怎麼設定(刪除與新增)Google Drive 中的檔案們的權限給不同人?

這次的主題我們會分成兩天寫。第一題會在昨天跟大家分享了,今天會針對第二題與第三題。那我們就開始吧!


Q2. 要怎麼取得 Google Drive 中的檔案們的權限?

Step 1 是設定試算表;而 Step 2 則是設定資料夾並讀取檔案,可以參考前一篇文章(D9),今天我們從 Step 3 開始。

Step 3 額外再讀取目前權限

這邊我們介紹讀取權限的幾個功能。 Google 系列的產品基本上有三個角色——編輯者、檢視者、評論者,分別就是可以編輯、可以檢視與可以評論(與檢視)。這邊先不特別談擁有者(Owner)。

那對於「權限操作」,目前比較常見的處理功能就是

編輯者檢視者加註者
新增(單人)addEditor()addViewer()addCommenter()
新增(多人)addEditors()addViewers()addCommenters()
讀取getEditors()getViewers()(沒有特定 API,但可以讀取,待會詳細說明)*
刪除removeEditor()removeViewer()removeCommenter()

Google 的 API 就是這麼樸實無華、簡單易懂。實在是超高境界。那實際上怎麼用呢,我們來看看,首先要先讀到檔案。這邊先設定三個檔案,分別設定一個編輯者、一個檢視者與一個評論者。

權限狀態
Spread Sheet 1有一名編輯者
Spread Sheet 2有一名檢視者
Spread Sheet 3有一名加註者

稍微改一下前一天 D9 的程式碼,來看每份檔案目前的讀取者與編輯者。

function readFiles(){
  let folder = DriveApp.getFolderById(demo_drive_ID);
  let files = folder.getFiles();
  while (files.hasNext()) {
    let file = files.next();
    let file_name = file.getName();
    let editors = file.getEditors();
    let viewers = file.getViewers();
    for(editor of editors){
      Logger.log('File ' +file_name +' has editor: '+editor.getEmail());
    }
    for(viewer of viewers){
      Logger.log('File ' +file_name +' has viewer: '+viewer.getEmail());
    }
  };
}

跑起來長這樣——

仔細看可以發現,它顯示 Spread Sheet 2 和 Spread Sheet 3 都各有一位檢視者,可是明明我們設定的是一位檢視者和一位加註者,為什麼會這樣?那是因為 在讀取使用者時,加註者會被算入檢視者的一種。那有辦法做出區隔嗎?有的,程式碼如下,藉由 file.getAccess 去看原本檔案中,把原本讀 Viewer 的部分再拆成 Viewer 和 Commenter。

    for(viewer of viewers){
      if(file.getAccess(viewer) == "COMMENT"){
        Logger.log('File ' +file_name +' has commenter: '+viewer.getEmail());
      }else{
        Logger.log('File ' +file_name +' has viewer: '+viewer.getEmail());
      }
    }

而結果跑起來者這樣——

接著,我們來將結果寫入 Google Sheet。

Step 4 寫入 Google Sheet

這邊我們借用 D8 的 writeData 程式碼,這邊就先複習一下其功能,完整的文章可以參考 D8。

function writeData(data){
  let starting_row = 2;
  let starting_col = 1;
  let num_row = data.length;
  let num_col = data[0].length;
  let sheet = SpreadsheetApp.getActiveSheet();
  let range = sheet.getRange(starting_row, 
                             starting_col, num_row, num_col);
  range.setValues(data);
}

也複習執行的結果——

好,那接著就是將我們要的 Data 包裝成 Google Sheet 要的格式(Array in array)。我這邊想要知道,檔案名稱、檔案 ID 、擁有的編輯者、擁有的檢視者與擁有的加註者。

這段是目前最長的程式碼,但跟 Step 3 比起來,就是多加了個「放入檔案」的程序。

  1. 在一開始先放一個 ["File Name","File ID", "Editors","Viewers","Commenters"] 做為預設的 Header(會出現在第一列)
  2. 再來對每個檔案都用一個 file_info ,依序放入 Name 和 ID
  3. 並去讀它的 Editors 和 Viewers
  4. 並用一個簡單的 if(editors != []) / if(viewers != []) 來處理如果有編輯、檢視者與加註者的情況。
  5. 同時,用 else 在沒有任何編輯、使用者時,則丟上空白的 Array([])。
  6. 最後再將它寫入 Google Sheet
function readFiles(){
  let folder = DriveApp.getFolderById(demo_drive_ID);
  let files = folder.getFiles();
  let files_arr = [["File Name","File ID", "Editors","Commenters","Viewers"]]
  while (files.hasNext()) {
    let file_info = []
    let file = files.next();
    let file_name = file.getName() 
    file_info.push(file.getName(),file.getId());
    let editors = file.getEditors();
    let viewers = file.getViewers();
    let editors_arr=[]
    let commenters_arr=[]
    let non_commenters_arr=[]
    if(editors != []){
        for(editor of editors){
          editors_arr.push(editor.getEmail())
        }
    }
    if(viewers != []){
        for(viewer of viewers){
          if(file.getAccess(viewer) == "COMMENT"){
            commenters_arr.push(viewer.getEmail())
          }else{
            non_commenters_arr.push(viewer.getEmail())
          }
        }
    }
    file_info.push(editors_arr)
    file_info.push(non_commenters_arr)
    file_info.push(commenters_arr)
    files_arr.push(file_info);
  };
  Logger.log(files_arr);
  writeData(files_arr);
}

跑起來長這樣——

好,那當我們會列出了以後,接著我們來看要怎麼設定。

Q3. 要怎麼設定(刪除與新增)Google Drive 中的檔案們的權限給不同人?

這邊就刪除和新增都講,一樣先用簡單的範例。假設我今天想要將檔案改成——

變更前權限狀態變更後權限狀態
Spread Sheet 1有一名編輯者有一名檢視者
Spread Sheet 2有一名檢視者有一名加註者
Spread Sheet 3有一名加註者有一名編輯者

Step 5 刪除使用者權限

透過 removeEditor()removeViewer() 和 removeCommenter() ,在 () 中放入使用者(或是使用者的 email)可以刪除使用者的權限。在這部步驟可以預期的是——

變更前權限狀態變更後權限狀態
Spread Sheet 1有一名編輯者(沒有使用者)
Spread Sheet 2有一名檢視者(沒有使用者)
Spread Sheet 3有一名加註者(沒有使用者)
function readFileAndRemoveUser(){
  let folder = DriveApp.getFolderById(demo_drive_ID);
  let files = folder.getFiles();
  while (files.hasNext()) {
    let file = files.next();
    let file_name = file.getName();
    let editors = file.getEditors();
    let viewers = file.getViewers();
    for(editor of editors){
      file.removeEditor(editor)
      Logger.log('File ' +file_name +' removed editor: '+editor.getEmail());
    }
    for(viewer of viewers){
      if(file.getAccess(viewer) == "COMMENT"){
        file.removeCommenter(viewer)
        Logger.log('File ' +file_name +' removed commenter: '+viewer.getEmail());
      }else{
        file.removeViewer(viewer)
        Logger.log('File ' +file_name +' removed viewer: '+viewer.getEmail());
      }
    }
  };
};

好,來看看跑出來的結果。

Step 6 對列出使用者(email)設定特定權限

那接下來我們要新增「使用者」對檔案的權限,我會建議先參照今天的 Q2 把所有想處理的檔案名稱、ID 與目前的使用者狀況列出來先。如果要乾淨的處理,甚至可以參考 Q3 的 Step 5 先把所有的權限清理乾淨再來新增。

那新增的方式有三種,分別是 addEditor() 、 addViewer() 和 addCommenter()。我們來試著將前一份有 File Name 和 ID 的表單弄成我們要的順序。在這步驟預計會做的事是…

變更前權限狀態變更後權限狀態
Spread Sheet 1(沒有使用者)有一名檢視者
Spread Sheet 2(沒有使用者)有一名加註者
Spread Sheet 3(沒有使用者)有一名編輯者

首先先取得 Google Sheet 裡面的資料,

function addUsers(){
  // Read Data from sheet
  let sheet = SpreadsheetApp.getActiveSheet();
  let range = sheet.getRange(3,1,3,5);
  let data_arr =  range.getValues();
  for (data of data_arr){
    let file_ID = data[1];
    let editors_mail_arr = data[2];
    let viewers_mail_arr = data[3];
    let commenters_mail_arr = data[4];
    let file = DriveApp.getFileById(file_ID);
    if(editors_mail_arr!=[]) file.addEditor(editors_mail_arr);
    if(viewers_mail_arr!=[]) file.addViewer(viewers_mail_arr);
    if(commenters_mail_arr!=[]) file.addCommenter(commenters_mail_arr);
  };
};

最後運作起來會長這樣——

如果不只新增一個使用者,那填寫方式是如圖,用小逗號隔開。

並將 file.addEditor(editors_mails_arr); 改成 file.addEditors([editors_mails_arr]); 也就是加上 s 並把括弧內包一層 Array []

那這邊示範新增多人的示範程式碼,把上方完整程式碼的三個 if 換成下列即可——

if(editors_mail_arr!=[]) file.addEditors([editors_mail_arr]);
if(viewers_mail_arr!=[]) file.addViewers([viewers_mail_arr]);
if(commenters_mail_arr!=[]) file.addCommenters([commenters_mail_arr]);

好,那今天我們總共學的,概括起來是這個表格。希望有幫助到大家。

編輯者檢視者加註者
讀取目前getEditors()getViewers()(在 getViewers() 中再用 getAccess() 進行區分)
新增(單人)addEditor()addViewer()addCommenter()
新增(多人)addEditors()addViewers()addCommenters()
刪除removeEditor()removeViewer()removeCommenter()

那目前對使用者進行操作目前是沒有 Quota 的限制。

延伸思考題

  1. 如果想要將 Google Drive 內的所有檔案抓出來,並關閉所有的使用權,請問要如何達到?
  2. 如果想要抓出四散在 Google Drive 內中 鐵人 開頭的檔案,並設定使用權限,請問如何達到?
  3. (進階題)要如何將將 Google Drive 內的檔案讀出,並更換擁有者(Owner)(提示:setOwner

好,那就完成了我們的 D10(撒花)。如果還有問題,透過留言之外,也可以到 Facebook Group,想開很久這次鐵人賽才真的開起來哈哈哈,歡迎來當 Founding Member。如果不想錯過可以訂閱按讚小鈴鐺(?),也歡迎留言跟我說你還想知道什麼做法/主題。我們明天見。

目錄

Scroll to Top