【问题标题】:Google sheets. Lock range谷歌表。锁定范围
【发布时间】:2019-11-23 21:18:02
【问题描述】:

我有 2 个范围为 C2:F21 的列表,应该可以在特定时期内为所有用户填写。

列表 A 中的范围 C2:F21 不应从 01.01.2020 锁定到 05.01.2020,但在另一个时间,它应该对除我以外的所有用户锁定。

在列表 B 范围内,C2:F21 不应仅从 01.02.2020 到 05.02.2020 锁定。

如果有任何答案,我将不胜感激

【问题讨论】:

  • 看看Protection
  • @Cooper 您认为在这种情况下也可以使用可安装的、时间驱动的触发器吗?并且可能(如果用户非常“有创意”),脚本应该是独立的,而不是绑定到电子表格 - 我知道这会阻止用户修改触发器(关于 CodeCamper 最近发布的)。跨度>
  • @Tedinoz 我认为任何有权编辑电子表格的人都拥有几乎无限的权力,无论你多么努力。因此,如果要保护诸如此问题中的任何内容,则需要在其他人无权编辑的地方制作电子表格的副本。即使您创建了可安装的触发器或独立应用程序,可以编辑电子表格的人仍然可以创建自己的脚本来破坏您。
  • @Cooper “但我从不使用 [onEdit()]”因此为什么您更喜欢 webapps - 因为您可以预测“onEdit”场景并相应地为数据输入编程?

标签: google-apps-script google-sheets


【解决方案1】:

处理此问题的最“安全”方法是在到期日期将数据实际保存为单独的电子表格(只有您有权编辑),您也可以使用脚本自动执行此操作。然后,如果您需要用户在主表中看到它,您可以使用一系列 importrange 函数来创建只读信息列表。任何编辑电子表格的人都有能力(也许不是知识)以各种创造性的方式绕过您的细胞保护。

如果您仍然坚持使用单元格保护来完成此操作很简单,请使用Protection class 并使用脚本编辑器中的小时钟向项目添加触发器,选择事件源Time-driven 和基于时间的触发器Specific date and time.

【讨论】:

    【解决方案2】:

    首先,您需要保护范围,您可以通过 Web UI 轻松完成此操作,方法是选择要保护的范围,右键单击并选择 Protect range。您也可以通过 Apps Script 执行此操作,方法是运行如下函数:

    function protectRangeA() {
      var ss = SpreadsheetApp.openById("your-spreadsheet-id"); // Change accordingly
      var sheetA = ss.getSheetByName("your-sheet-name"); // Change accordingly
      var protection = sheetA.getRange("C2:F21").protect();
      var me = Session.getEffectiveUser();
      protection.addEditor(me);
      protection.removeEditors(protection.getEditors());
      if (protection.canDomainEdit()) {
        protection.setDomainEdit(false);
      }
    }
    

    此函数从具有特定 ID 的电子表格中获取具有特定名称的工作表(正如其他人在我之前所说,出于安全原因 - 避免人们弄乱你的脚本 - 如果它是独立脚本会更好,而不是绑定到您的电子表格),并使用protect() 保护范围C2:F21,您将是唯一的编辑器。

    其次,您想在某个日期取消保护此范围,并在另一个日期再次保护它。为此,您可以创建time-driven triggers。例如,您可以使用atDate trigger,它将在您指定的年、月和日运行您指定的函数。因此,如果您想取消保护 01.01.2020 的范围,例如,您可以使用以下功能:

    function createUnprotectTriggerA() {
      ScriptApp.newTrigger("unprotectRangeA")
      .timeBased()
      .atDate(2020, 1, 1)
      .create();
    }
    

    这将在 01.01.2020 的午夜附近(+/- 15 分钟)触发一个名为 unprotectRangeA 的函数。此时将运行的函数应该取消对所需范围的保护。可能是以下几行:

    function unprotectRangeA() {
      var ss = SpreadsheetApp.openById("your-spreadsheet-id"); // Change accordingly
      var sheetA = ss.getSheetByName("your-sheet-name"); // Change accordingly
      var protections = sheetA.getProtections(SpreadsheetApp.ProtectionType.RANGE);
      for (var i = 0; i < protections.length; i++) {
        var protection = protections[i];
        if (protection.canEdit()) {
          protection.remove();
        }
      }
    }
    

    此函数使用getProtections 获取工作表中存在的所有范围保护,并在检查当前用户是否可以通过canEdit() 编辑它们之前,使用remove() 删除这些保护。

    为了在05.01.2020 再次保护它,拥有这个触发器,它将在这个日期触发函数protectRangeA(之前定义):

    function createProtectTriggerA() {
      ScriptApp.newTrigger("protectRangeA")
      .timeBased()
      .atDate(2020, 1, 5)
      .create();
    }
    

    最后,因为您想保护/取消保护多个范围并且需要多个触发器,您可以在同一个函数中调用创建触发器的所有函数,您必须运行一次才能设置您需要的所有触发器(我没有定义 createProtectTriggerBcreateUnprotectTriggerB 但它与其他范围相同):

    function createTriggers() {
      createProtectTriggerA();
      createUnprotectTriggerA();
      createProtectTriggerB();
      createUnprotectTriggerB();
    }
    

    请注意,正如 CodeCamper 所说,如果用户有权编辑电子表格,他们可能会使用脚本来破坏您的保护。因此,根据编辑此内容的人员,也许您应该拥有一份只有您可以访问的电子表格副本。

    希望对你有帮助。

    【讨论】: