7

我尝试根据在此Google 支持线程中找到的此 SHEET实现一个简单的“Multi selector sidebar”扩展

当我复制工作表时它工作正常,但是当我尝试将完全相同的代码放入我的真实工作表时,它不再工作了。当我尝试从模板中访问 GA 函数时,它会引发错误。

我创建了一个简化的测试项目,它也无法为我工作。

要重现错误:

  1. 在https://docs.google.com/spreadsheets/创建一个新的电子表格
  2. 创建第二张工作表(标签左下角)并将其命名为 CATEGORIES
  3. 在第一列中填写几个字段。内容不重要 类别
  4. 转到工具 -> 脚本编辑器

在“code.gs”中输入

function doGet() {
  var html = HtmlService.createHtmlOutputFromFile('Index')
      .setTitle('Multiple selector')
      .setWidth(300);
  SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
      .showSidebar(html);
}

function onOpen(e) {
    SpreadsheetApp.getUi().createMenu('Index')
        .addItem('Show Sidebar', 'doGet')
        .addToUi();
        doGet();
}

function getOptions() {
  var validation = {
    sheet: 'CATEGORIES',
    range: 'A2:A'
}

  Logger.log("running getOptions");
  Logger.log(SpreadsheetApp.getActive().getSheetByName(validation.sheet).getRange(validation.range).getDisplayValues());
    return SpreadsheetApp.getActive().getSheetByName(validation.sheet).getRange(validation.range).getDisplayValues()
        .filter(String)
        .reduce(function(a, b) {
            return a.concat(b)
        })
}

并创建名为 Index.html 的第二个文件(HTML 文件)

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>
      function onFailure(error) {
        var div = document.getElementById('output');
        div.innerHTML = "ERROR: " + error.message;
      }

      google.script.run.withFailureHandler(onFailure)
          .getOptions();
    </script>
  </head>
  <body>
    <div id="output"></div>
  </body>
</html>

带有代码的测试项目

  1. 保存项目
  2. 单击 Run-> Run function -> "onOpen"(第一次运行时您可能需要授权应用程序)

现在在工作表中应该有一个边栏,对我来说打开时出现错误PERMISSION_DENIED

在此处输入图像描述

即使我在资源 -> 云平台项目中选择了一个项目,它也不起作用。

奇怪的是,如果我使用原始链接(工作)电子表格并更改代码中的某些内容,它将不再适用于我。

我现在知道的事情: - 它不适用于我的 gmail 或 google 应用程序帐户 - 对于使用相同文档的其他人,它有效 - 如果我禁用 Adblocker 仍然无效 - 如果我从以下位置访问工作表则无效隐身模式 - 如果我使用 Firefox 而不是 Chrome,它确实有效

来自浏览器的控制台日志

我错过了什么?

4

2 回答 2

8

我对“权限被拒绝”错误消息有同样的问题,我发现了这个

https://github.com/burnnat/page-sizer/issues/3

我认为问题在于我在处理此问题时登录了多个谷歌帐户。我注销了所有谷歌帐户,然后只登录了我尝试使用 formMule 的一个帐户并且它有效。

所以我在chrome中使用隐身模式尝试了完全相同的代码,只登录了一个帐户,它可以工作!

我希望这可以帮助您解决您的问题。

于 2020-03-04T09:17:49.993 回答
1

我遇到过同样的问题。问题确实是由登录到一个会话的两个或多个 Google 帐户引起的。

问题是前端由登录用户 X 加载和执行,而后端(Code.gs 文件)由登录用户 Y 执行。

因此,解决方法是检查执行后端代码的用户是否与查看前端代码的用户相同。(在这种情况下:前端是您的侧边栏)

我发现此解决方法适用于我的一个附加组件:

将此函数添加到您的 Code.gs 文件中。它将检查“前端用户”(发起者),即查看html侧边栏“是否与“后端用户”(userEmailAddress)相同。如果不是同一个用户,则会抛出错误。如果是是同一用户,不会引发错误。

function checkMultipleAccountIssue(initiator) {

var userEmailAddress = Session.getEffectiveUser().getEmail();
if (initiator) {
// check if effective user matches the initiator (the account who 
triggered the display of the UI)
// Due to a Google bug, if user is connected with multiple accounts 
inside the same browser session
// google.script.run can be executed by another account than the 
initiator

 if (initiator != userEmailAddress) {
   console.error({
    message: "Client side calls initiated from wrong account",
    initiator:initiator, // user in frontend (sidebar)
    effectiveUser: userEmailAddress // user in backend (code.gs)
   });
 
 var errorMessage = "You are logged in with multiple accounts.<br>";
     errorMessage+= "This causes errors. Log out with account " + 
                   userEmailAddress;
     errorMessage+= " if you want to continue with the account: " +
     initiator;
 throw new Error(errorMessage);
 }
 else{
   return 'No conflicts found. Good to go.'
  }  
 }
}

在前端(html 侧边栏)中添加在加载侧边栏时运行的这段 javascript:

<!DOCTYPE html>
<html>
  <head>
    <base target="_top">
    <script>

var initiator = '<?!= Session.getEffectiveUser().getEmail() ?>'
        console.log('FRONTEND USER: ' + initiator)    
          google.script.run.
            withFailureHandler(function(error){
              alert(error); 
    // or prompt the user to logout! 
    //(HINT: let them click this link: https://google.com/accounts/Logout and login with the correct user.)
            })
            .withSuccessHandler(function(ret){
              console.log(ret)
            })
            .checkMultipleAccountIssue(initiator)



      function onFailure(error) {
        var div = document.getElementById('output');
        div.innerHTML = "ERROR: " + error.message;
      }

      google.script.run.withFailureHandler(onFailure)
          .getOptions();
    </script>
  </head>
  <body>
    <div id="output"></div>
  </body>
</html>

那个部分

var initiator = '<?!= Session.getEffectiveUser().getEmail() ?>'

是一个应用程序脚本 scriptlet,当 HTML 被准备好之后,它会被“注入”到最终用户手中。如果您想使用这样的 scriptlet,您需要将 HTML 侧边栏加载为模板。要将您的 HTML 侧边栏加载为模板化 HTML,请更改 doGet() 函数,如下所示:

function doGet() {
  var html = HtmlService.createTemplateFromFile('Index').evaluate()
      
      .setTitle('Multiple selector')
      .setWidth(300);
       
   SpreadsheetApp.getUi() // Or DocumentApp or SlidesApp or FormApp.
      .showSidebar(html);
}

可以在此处找到有关 scriptlet 和模板化 HTML 的更多信息:https ://developers.google.com/apps-script/guides/html/templates#code.gs

这是我找到解决方法的地方:https ://sites.google.com/site/scriptsexamples/home/announcements/multiple-accounts-issue-with-google-apps-script

您可以在https://issuetracker.google.com/issues/69270374?pli=1为这个问题加注星标,以便“更快”地解决它。:)

于 2021-10-22T16:01:41.947 回答