如何防止任何编辑器在谷歌工作表工作簿中添加新工作表



如何防止任何匿名编辑器在工作簿中添加新工作表。我希望允许他们只编辑一张工作表,但有些编辑错误地插入了不需要的工作表,把工作簿搞砸了。提前谢谢。我尝试了下面这个链接中的脚本,但似乎不起作用。

阻止用户在共享的谷歌电子表格中创建新工作表

// Deletes any tab named "SheetN" where N is a number 
function DeleteNewSheets() {
  var newSheetName = /^Sheet[d]+$/
  var ssdoc = SpreadsheetApp.getActiveSpreadsheet();
  var sheets = ssdoc.getSheets();
  
  // is the change made by the owner ?
  if (Session.getActiveUser().getEmail() == ssdoc.getOwner().getEmail()) {
    return;
  }
  // if not the owner, delete all unauthorised sheets
  for (var i = 0; i < sheets.length; i++) {
    if (newSheetName.test(sheets[i].getName())) {
      ssdoc.deleteSheet(sheets[i])
    }
  }
}

我创建了此电子表格https://docs.google.com/spreadsheets/d/1EdF8I0tyfQagfw1cxHCWgsr2umXi6-vbu7GvM8SJQSM/edit#gid=0使用上面的代码并设置触发器,但任何人都可以创建新的工作表。

我相信你目前的情况和目标如下。

  • 谷歌电子表格中有一张表格
  • 您不希望匿名用户插入新的工作表

问题和解决方法:

不幸的是,在当前阶段,没有明确检测匿名用户编辑的方法。在您的脚本中,我认为该脚本可以用于特殊许可的用户。在这种情况下,无法包括匿名用户。我想这可能就是你问题的原因。因此,为了实现您的目标,需要准备一个变通方法。在这个答案中,我想提出一个变通办法。

当检测到图纸插入时,可以使用OnChange触发器。但是,识别用户有点困难。当通过OnChange触发器执行函数installedOnChange(e)时,可以获得以下条件。并且,为了检查活动用户,使用Session.getActiveUser().getEmail()Session.getEffectiveUser().getEmail()

  1. 当所有者插入新的工作表时,

    installedOnChange(e)
    • e具有"user":{"email":"### owner's email ###","nickname":"### owner name ###"}的性质
    • Session.getActiveUser().getEmail()Session.getEffectiveUser().getEmail()返回所有者的电子邮件
  2. 当特殊许可用户插入新的纸张时,

    CCD_ 10的
    • CCD_ 9具有CCD_ 11的性质。在这种情况下,不会返回任何电子邮件地址和姓名
    • Session.getActiveUser().getEmail()返回空,Session.getEffectiveUser().getEmail()返回所有者的电子邮件
  3. 当匿名用户插入新表单时,

    CCD_ 15的
    • CCD_ 14具有CCD_ 16的性质
    • CCD_ 17和CCD_ 18返回所有者的电子邮件
    • 在这种情况下,所有者的情况也是一样的。但是,为了识别这一点,这里使用了简单的触发器。因为匿名用户无法使用简单触发器。例如,当匿名用户编辑单元格时,不会运行简单触发器。使用这种情况

当这些条件反映在示例脚本中时,情况如下。

用法:

1.准备示例脚本

请将以下脚本复制并粘贴到电子表格的脚本编辑器中。并且,请使用脚本编辑器直接运行onOpen函数。这样,初始图纸名称将存储在Properties Service中。此外,当电子表格打开时,onOpen将运行。这样就可以保存初始条件。

function onOpen() {
  PropertiesService.getScriptProperties().setProperty("sheetName", JSON.stringify(SpreadsheetApp.getActiveSpreadsheet().getSheets().map(s => s.getSheetName())));
}
function onSelectionChange(e) {
  CacheService.getScriptCache().put("simpleTrigger", JSON.stringify(e), 30);
}
function deleteSheet(e) {
  if (e.changeType != "INSERT_GRID") return;
  const sheetNames = JSON.parse(PropertiesService.getScriptProperties().getProperty("sheetName"));
  e.source.getSheets().forEach(s => {
    if (!sheetNames.includes(s.getSheetName())) e.source.deleteSheet(s);
  });
}
function installedOnChange(e) {
  const lock = LockService.getDocumentLock();
  if (lock.tryLock(350000)) {
    try {
      Utilities.sleep(3000); // Please increase this wait time when the identification is not correct.
      const c = CacheService.getScriptCache();
      const simpleTrigger = c.get("simpleTrigger");
      const activeUser = Session.getActiveUser().getEmail();
      const effectiveUser = Session.getEffectiveUser().getEmail();
      if (activeUser && effectiveUser && simpleTrigger) {
        // Operation by owner.
        // do something.
        PropertiesService.getScriptProperties().setProperty("sheetName", JSON.stringify(SpreadsheetApp.getActiveSpreadsheet().getSheets().map(s => s.getSheetName())));
      } else if (!activeUser && effectiveUser && simpleTrigger) {
        // Operation by permitted user.
        // do something.
        deleteSheet(e); // If you want to make the permitted user not insert new sheet, please use this line.
      } else {
        // Operation by anonymous user.
        // do something.
        deleteSheet(e);
      }
      c.remove("simpleTrigger");
    } catch (e) {
      throw new Error(JSON.stringify(e));
    } finally {
      lock.releaseLock();
    }
  } else {
    throw new Error("timeout");
  }
}
  • 在这个示例脚本中,所有者、特殊许可用户和匿名用户被识别。并且,所有者可以插入新的工作表。但是,当特殊允许用户和匿名用户插入新的工作表时,插入的工作表将被删除。通过这种方法,作为一种变通方法,您的目标可能能够实现。

  • 在这个脚本中,onSelectionChange被用作检测匿名用户的简单触发器。

3.将OnChange触发器作为可安装的触发器安装

请为函数installedOnChange安装一个触发器作为OnChange可安装触发器。参考

3.测试

为了测试此脚本,请插入一个由特殊许可用户和匿名用户创建的新工作表。这样,插入的图纸将被删除。而且,当所有者插入新图纸时,插入的图纸不会被删除。

注:

  • 在这个示例脚本中,为了检查是否执行了简单触发器,使用了Utilities.sleep(3000)。因此,识别用户的时间有点长。我认为这可能是一个限制。

  • 例如,如果不需要识别插入新工作表的用户,也可以使用以下简单脚本。在使用此脚本之前,请将OnChange触发器安装到installedOnChange,并使用脚本编辑器运行onOpen。在此示例脚本中,所有用户都无法插入新工作表。

      function onOpen() {
        PropertiesService.getScriptProperties().setProperty("sheetName", JSON.stringify(SpreadsheetApp.getActiveSpreadsheet().getSheets().map(s => s.getSheetName())));
      }
      function installedOnChange(e) {
        const lock = LockService.getDocumentLock();
        if (lock.tryLock(350000)) {
          try {
            if (e.changeType != "INSERT_GRID") return;
            const sheetNames = JSON.parse(PropertiesService.getScriptProperties().getProperty("sheetName"));
            e.source.getSheets().forEach(s => {
              if (!sheetNames.includes(s.getSheetName())) e.source.deleteSheet(s);
            });
          } catch (e) {
            throw new Error(JSON.stringify(e));
          } finally {
            lock.releaseLock();
          }
        } else {
          throw new Error("timeout");
        }
      }
    

参考文献:

  • 可安装触发器
  • 简单触发器
  • getActiveUser((
  • getEffectiveUser((

最新更新