如何防止任何匿名编辑器在工作簿中添加新工作表。我希望允许他们只编辑一张工作表,但有些编辑错误地插入了不需要的工作表,把工作簿搞砸了。提前谢谢。我尝试了下面这个链接中的脚本,但似乎不起作用。
阻止用户在共享的谷歌电子表格中创建新工作表
// 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()
。
-
当所有者插入新的工作表时,
installedOnChange(e)
的e
具有"user":{"email":"### owner's email ###","nickname":"### owner name ###"}
的性质Session.getActiveUser().getEmail()
和Session.getEffectiveUser().getEmail()
返回所有者的电子邮件
-
当特殊许可用户插入新的纸张时,
CCD_ 10的- CCD_ 9具有CCD_ 11的性质。在这种情况下,不会返回任何电子邮件地址和姓名
Session.getActiveUser().getEmail()
返回空,Session.getEffectiveUser().getEmail()
返回所有者的电子邮件
-
当匿名用户插入新表单时,
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((