D10 - 如何用 Google Apps Script 自动化对 Google Drive 的操作?(二)自动列出所有档案并设定权限

来到了第十天。我们的习惯是先讲结论,如果你很急着用,可以直接使用这份 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. 并去读它的 EditorsViewers
  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。如果不想错过可以订阅按赞小铃铛(?),也欢迎留言跟我说你还想知道什麽做法/主题。我们明天见。


<<:  引言与大纲

>>:  Azure - Day4 Cosmos DB

IOS、Python自学心得30天 Day-29 连接Firebase辨识

前言: 衔接完成 程序码: // // ViewController.swift // Dog Br...

就先在这边帮他上了一个主题了 Day1

今天是自己开始铁人赛的第一天,目标其实很简单,想要把之前学到的,之前没学到的 全部整合整理成一个作品...

D2: [漫画]工程师太师了-第1.5话

工程师太师了: 第1.5话 杂记: 因为这是IT铁人赛,总是希望可以有些技术的。 我会在D2、D4、...

用React刻自己的投资Dashboard Day24 - styled components

tags: 2021铁人赛 React 因为下一篇要让导览列在手机版网页呈现汉堡选单的样式,在参考其...

【左京淳的JAVA学习笔记】第三章 运算子与分歧文

运算子 运算子即计算、比较、位移用的种种符号,欲知详情请自行google。 让我们先来看看算数运算子...