【问题标题】:Google Apps Script - Editors Execute Script on SpreadsheetGoogle Apps 脚本 - 编辑器在电子表格上执行脚本
【发布时间】:2013-11-05 19:18:57
【问题描述】:

我创建了一个 Google 电子表格来帮助我的团队跟踪下一周的日历。该电子表格有 2 个选项卡:“概览”选项卡和“详细信息”选项卡。在“详细信息”选项卡上,顶行列出了到年底的所有工作日,左列列出了团队成员的姓名。对于每一天,团队成员都会写下他们将就读的学校以及支持的描述。

“概览”标签与“详细信息”标签具有相同的结构(即顶部的日期和左侧列出的姓名),但提供了每个人所在位置的直观摘要。我编写了一个脚本,该脚本从“详细信息”选项卡中获取学校名称,并将其输入到与“概述”选项卡上正确的人/日期相对应的单元格中。然后它获取支持的描述并在“概述”选项卡上创建一个带有描述的注释。它还在“概述”选项卡上为单元格添加阴影,因此我可以看到已计划支持。因此,在“概览”选项卡中,我只需将鼠标悬停在单元格上,它就会向我显示计划中的支持。

它在我自己的帐户中运行良好。但是,我已与一些团队成员共享电子表格,但它无法正常工作。我不希望我的团队能够编辑“概述”选项卡,因为我只希望他们在“详细信息”选项卡上输入他们的信息。如果我授予他们“概览”选项卡的编辑权限,那么他们可以更改注释、单元格颜色、工作表结构等(这就是我希望“概览”选项卡仅供查看的原因)。因此,我保护了“概述”选项卡,因此他们无法进行编辑。但是,由于他们无法编辑此工作表,因此当他们编辑“详细信息”选项卡时,脚本似乎不会运行并更新“概述”选项卡。我认为这是因为他们没有权限(因为工作表受到保护)。当我删除工作表保护时,脚本对他们来说运行得很好。

关于如何解决这个问题有什么想法吗?我真的需要保留“概述”选项卡仅查看。谢谢。

【问题讨论】:

  • 你的脚本是如何触发的?
  • onEdit...但我创建了自己的 (onEdit1) 而不是使用默认的 onEdit。

标签: google-apps-script


【解决方案1】:

如果,如您在 cmets 中所述,您使用 可在编辑触发器上安装,您描述的问题应该不会发生,因为 “当脚本运行时触发器,脚本使用安装触发器的人的身份运行,而不是其操作触发事件的用户的身份。这是出于安全原因。例如,如果您在脚本中安装触发器,但您的同事执行触发事件的操作时,脚本会以您的身份运行,而不是您同事的身份。有关这方面的完整信息,请参阅了解权限和脚本执行。"

见文档here


编辑:抱歉,我没有看到关于这种特殊情况的问题:issue 1562 posted on july 2012, status "triaged"


编辑 2:我尝试了 @tracon6 建议暂时删除保护,但它也不起作用......脚本在尝试应用保护时生成错误。

但是

作为 EDIT 3

我找到了一个可行的解决方法!我们可以在写入 targetSheet 时添加一个编辑器,然后在之后立即删除它......在它之间使用 flush 可以工作。

这是我用来测试的代码:

function onEditInstallable(event) {
  var sheet = event.source.getActiveSheet();
  if(sheet.getName()=='Sheet1'){return};
  var r = event.source.getActiveRange();
  var column = r.getColumn();
  var ss = SpreadsheetApp.getActiveSpreadsheet();
  var targetSheet = ss.getSheetByName("TFA");
  var targetSheet = ss.getSheetByName("Sheet1");
  var user = SpreadsheetApp.getActive().getEditors()[1];
  var permission = targetSheet.getSheetProtection();
  permission.addUser(user);
  targetSheet.setSheetProtection(permission);
  SpreadsheetApp.flush();
  targetSheet.getRange(1,column).setValue('value change on sheet 2, column  : '+column);
  SpreadsheetApp.flush();
  permission.removeUser(user)
  targetSheet.setSheetProtection(permission)
}

编辑 4:

由于似乎许多编辑者都可以访问这些工作表(请参阅最后的 cmets),因此必须有一种方法可以知道谁在电子表格上处于活动状态。在非域环境中,使用触发函数是不可能的,因此我建议使用带有列表的小型 uiApp,用户必须从中选择,使用可安装的 onOpen 触发它,并将值存储在主函数中使用它。

这是处理该方面的一段代码。

function SpecialonOpen(){
  var s = SpreadsheetApp.getActive();
  var app = UiApp.createApplication().setTitle('Please select your email in this list').setWidth(300).setHeight(300);
  var list = app.createListBox().setName('list')
  var editors = s.getEditors();
  for(var n in editors){
    list.addItem(editors[n].getEmail());
  }
  var handler = app.createServerHandler('getMail').addCallbackElement(list);
  var btn = app.createButton('select',handler);
  s.show(app.add(list).add(btn))
}

function getMail(e){
  var email = e.parameter.list;
  var editors = ScriptProperties.getProperty('currentEditors')||' ';
  if(editors.indexOf(email)==-1){
    editors+=(','+email);
  ScriptProperties.setProperty('currentEditors',editors);
  }
  var app = UiApp.getActiveApplication().close();
  var editors = ScriptProperties.getProperty('currentEditors').split(',');
  if(editors[0].length<2){editors.splice(0,1)};
  Logger.log(editors)
  return app
}

您还应该添加一个功能来在某个时刻重置此列表...不知道什么是最好的?也许每天都有?我会把这个交给你;-)

【讨论】:

  • 是的,谢谢分享……我也看到了那个信息。所以这就是为什么我认为它会起作用。当在详细信息选项卡上输入文本时,部分脚本会更改单元格颜色。这一直有效。但是,一旦我保护了“概览”选项卡,脚本就不会将“详细信息”中的文本推送到“概览”选项卡。也许“工作表保护”胜过用户(即使脚本作为所有者 [我] 运行)。还是一头雾水……
  • 您知道我是否需要“部署为 Web 应用程序”吗?我的脚本中目前没有任何“doGet”代码。谢谢。
  • 不,您不需要,部署仅适用于独立应用程序。如果我有时间,我会尝试重现您的情况以提供进一步帮助。
  • 非常感谢。如果有帮助,我可以与您共享文件。
  • 是的,这样会更容易...我的电子邮件是 sergegabet 并且是一个 gmail 帐户。
【解决方案2】:

“概览”标签和“详细信息”标签是否需要位于同一个电子表格中?

也许您可以在只有您可以访问的电子表格中拥有“概述”标签,并在其他人可以访问的电子表格中拥有“详细信息”标签 - 然后您可以修改脚本以使用新的“详细信息电子表格”中的信息更新新的“概览电子表格”。

或者,在您的脚本中,您可以关闭概览选项卡上的保护,然后运行脚本的主要部分,然后在脚本结束前再次打开概览选项卡上的保护(请参阅https://developers.google.com/apps-script/reference/spreadsheet/page-protection#setProtected(Boolean)

诚然,这些选项都不像 onEdit 选项那样干净。

【讨论】:

  • 嗯,我没有想过让脚本关闭保护,然后推送数据,然后重新打开工作表保护。我明天试试。我想知道是否允许用户更改工作表保护(即使脚本应该作为所有者 [我] 运行)。此外,如果多人同时编辑“详细信息”选项卡(这种情况会经常发生),您是否知道这将如何工作?
  • 你知道我是否需要“部署为 Web 应用程序”吗?我的脚本中目前没有任何“doGet”代码。谢谢。
  • 您可以单独设置电子表格中每张工作表的保护。右键单击屏幕底部的概述表选项卡,然后选择“保护表”,然后选择“仅限我”。这允许您让多个人继续在“详细信息”选项卡上工作,并且无法修改“概述”选项卡。如果您需要,这里是有关 PageProtection 功能的附加信息:developers.google.com/apps-script/reference/spreadsheet/…
  • 我看到您关于“部署为 Web 应用程序”的问题。你能提供更多的背景吗?为什么您认为您需要(或想要)“部署为 Web 应用程序”?
  • 我不熟悉部署为 Web 应用程序,但我不知道这是否能帮助我规避编辑器能够运行 onEdit 脚本并让它编辑受保护选项卡的问题(他们无权编辑)。似乎当您部署为 Web 应用程序时,您可以选择让脚本作为所有者执行(这是我想要的)。但是,从 Google 的文本看来,所有可安装的触发器都应该作为所有者(我)执行。如果是这样的话,似乎“工作表保护”胜过这一点!
【解决方案3】:

您可以尝试以下 hacky workarround:将脚本发布为具有匿名访问权限的内容服务,并使用触发器中的 urlFetch 调用它,将必要的参数传递给您的服务。 这应该会导致代码在不同的上下文中执行,其中有效用户是脚本发布者而不是用户。你会慢一点。

【讨论】:

  • Zig,我该怎么做(我是 GAS 新手)?我基本上只是将所有代码放在 doGet() 函数中并将其部署为 Web 应用程序吗?然后我用 urlFetch 调用那个地址?
  • 更具体地说,我假设我的参数是“事件”,对吧?
  • 基本上是的,以前onEdit上的代码。然后在 doGet(e) 中,e 将具有您在 urlFetch("yourserviceurl?x=5") 中传递的参数,将在 doGet(e) 中获得 e.parameter.x=5。您的参数是在正确位置完成写入所需的任何内容。
  • 我必须补充一点,上次我尝试的时候就像 2 年前一样,我发现应用程序脚本不喜欢像那样递归地 cslled。我尝试了 5 级递归,但几乎没有达到第 5 级。但是只有一个 urlFetch 级别你应该没问题。
  • 函数 onEdit1(event) { UrlFetchApp.fetch("script.google.com/macros/s/…", event);
【解决方案4】:

您为什么不使用“数据”选项卡中的选项保护概览表并将编辑权限设置为“仅限您”。这将保护工作表不受所有人的影响,甚至是编辑者,使工作表对除您自己以外的所有人保持“仅查看”模式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-27
    • 2021-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多