【问题标题】:Apps Script - Remove a ProtectionApps 脚本 - 删除保护
【发布时间】:2019-06-20 18:48:13
【问题描述】:

我想限制 Google 表格中的单元格编辑,只允许用户编辑空单元格或由他填写的单元格,但不允许其他编辑者填写的单元格。简单地说:

  1. 如果单元格为空白,任何文档编辑器都可以在其中写入内容
  2. 编辑者将内容放入单元格后,只有他和文档所有者应该能够进一步编辑它
  3. 如果单元格被其作者或文档所有者之一清除,则保护也应自动移除,以便任何编辑者现在都可以对其进行编辑(返回第 1 步)

我正在尝试使用 Apps Script 来执行此操作,但您似乎无法删除 Protection,也无法获取适用于特定单元格的保护列表.

甚至有可能做到这一点吗?

【问题讨论】:

    标签: google-apps-script google-sheets


    【解决方案1】:

    保护类型

    Protection 不必在整个Sheet 上设置,您可以在您选择的Range 上调用protect() 方法,无论是一个单元格还是自定义Range

    解除保护

    有一种专门用于从Sheet/Range 中删除Protection 的方法,称为remove()。它可以在之前通过getProtections() 方法调用获得的任何Protection 上调用(getProtections() 方法返回所有Array 实例中的Array)。

    在您的情况下,生成的流程如下所示:

    1. 单元格被编辑器清除->调用getProtections()->检查目标单元格->remove();
    2. 单元格收到值->调用protect()->通过addEditor()/addEditors()添加编辑器;

    这两个步骤都可以放入可安装的onEdit() 触发器中,例如在编辑单元格时触发。

    示例脚本

    再一次,您尝试实现的目标是可能的,请尝试下面的脚本(不要忘记将其作为可安装触发器的回调包含在内)。在当前用户清空此单元格之前,其他编辑器无法编辑此单元格,反之亦然 [UPD:优化 'getRow()' 和 'getColumn()' 用法]。

    /**
     * Protects and unprotects ranges;
     * @param {Object} e event object;
     */
    function protect(e) {
    
      //access edited range, value and sheet;
      var rng = e.range;
      var val = e.value;
      var sh  = rng.getSheet();
    
      //access edited range row and column;
      var row = rng.getRow();
      var col = rng.getColumn();
    
      //access protections;
      var ps = sh.getProtections(SpreadsheetApp.ProtectionType.RANGE);
    
      //filter out other cells protections;
      ps = ps.filter(function(p){
       var ptd = p.getRange();
       if(row===ptd.getRow()&&col===ptd.getColumn()) {
         return p;
       }
      })[0];
    
      //if protection not set -> protect;
      if(!ps) {
        var protection = rng.protect(); //protect Range;
        var users = protection.getEditors(); //get current editors;
    
        protection.addEditor(Session.getEffectiveUser());
        protection.removeEditors(users); //remove other editors' access;
      }else {
        if(!val) { ps.remove(); } //if cell is empty -> remove protection;
      }
    
    }
    

    假设

    此说明和示例脚本假定getEffectiveUser() 产生影响的环境(例如,脚本项目未部署为WebApp + execute as me 等)。

    addEditor()的重要性

    根据我们在 cmets 中的讨论,如果在 removeEditors() 之前不使用 addEditor() 方法,则应注意可能会将自己锁定在编辑单元格之外(要复制的测试条件是:GSuite 电子表格所有者、Gmail 编辑器用户,权限设置为“关闭”,可安装onEdit() 触发器)。看看会发生什么:

    有用的链接

    1. addEditor()reference;
    2. remove()reference;
    3. getProtections()reference;

    【讨论】:

    • 我完全错过了getProtections(),现在它可以工作了!但是,不需要addEditor(),因为您将始终在您创建的保护(以及所有者)的编辑者列表中。
    • 很高兴它有效!问题是,这个addEditor() 在这里实际上是必需的 - 尝试删除 addEditor() 方法调用 - 你应该被锁定在单元格编辑之外(我在具有编辑权限但不是所有者的帐户上对其进行了测试)
    • 好吧,我用第二个帐户(非所有者编辑)做了完全相同的测试,添加保护后我仍然拥有单元格的编辑权限......奇怪
    • 多么好奇-我的确切测试条件是:Gsuite 帐户所有者 + 消费者 (gmail) 帐户用户,权限“关闭”,消费者帐户设置为“可以编辑”-> 没有此声明消费者帐户锁定本身无法编辑-您的配置是什么?我建议保留它以防万一(不久将制作一个小截屏视频来说明)
    • 好吧,我明白了,这是因为您正在删除从 proctection.getEditors() 获得的编辑器,而我正在使用 SpreadsheetApp.getActiveSpreadsheet().getEditors() :)。另外,我不知道这是否有区别,但就我而言,所有帐户都是简单的 Google / Gmail 帐户,不涉及 G Suite 帐户。
    【解决方案2】:

    使用真正的保护号。

    你能做什么。

    创建一个 OnEdit 函数,在元数据或注释中记录单元格的值和用户。 (注释会不太安全,但更容易调试)。

    在每次编辑单元格时,它都会检查此元数据,如果用户不是同一个/管理员,它会将文本的内容恢复为之前为单元格保存的值(可能会弹出一个说“那个不是您要编辑的单元格")。

    在函数底部添加一些内容,说明如果编辑没有价值,则清除元数据。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-10-05
      • 1970-01-01
      • 2017-09-15
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多