【问题标题】:Google Apps Script create calendar event from sheet forbidden?Google Apps 脚本禁止从工作表创建日历事件?
【发布时间】:2017-12-28 17:05:56
【问题描述】:

在我们公司的一个电子表格中的文档绑定 Google Appscript 中,我创建了一个脚本,可以将电子表格行转换为 Google 日历约会。该功能对我来说很好,但对我的同事却不适用,即使我们都有编辑日历和更改共享权限的权限,而且我的同事证明他可以从 calendar.google.com 在日历上创建约会。

他在运行脚本时收到以下错误消息:

{"message":"Forbidden","name":"GoogleJsonResponseException","fileName":"SCHEDULER","lineNumber":204,"stack":"\tat SCHEDULER:204 (createAppointments)\n"}

第204行对应命令:

 Calendar.Events.insert(event, CAL, {sendNotifications: true, supportsAttachments:true});

如果他拥有日历的编辑权限,为什么会被禁止? Google Apps 脚本中的日历服务是否存在问题?更重要的是,我将 CAL 变量更改为我个人创建并以相同权限共享给他的日历。他可以很好地编辑那个日历。

这是函数的伪代码

function createAppointments() {
    
   var CAL = 'companyname.com_1v033gttnxe2r3eakd8t9sduqg@group.calendar.google.com';
  
    for(/*each row in spreadsheet*/) 
    { 
      if(/*needs appointment*/)
      { 
        var object = {/*...STUFF...*/};
        var coworker = 'coworker@companyname.com';
        var timeArgs = {start: /*UTC Formatted time*/, end: /*UTC Formatted time*/}
        
        if(/*All the data checks out*/{
          var summary = 'Name of appointment'
          var notes = 'Stuff to put in the body of the calendar appointment';
          var location = '123 Happy Trail, Monterrey, TX 12345'
          
          //BUILD GOOGLE CALENDAR OBJECT
          var event = {
            "summary": summary,
            "description": notes,
            "start": {
              "dateTime": timeArgs.start,
              "timeZone": TZ
            },
            "end": {
              "dateTime": timeArgs.end,
              "timeZone": TZ
            },
            "guestsCanInviteOthers": true,
            "reminders": {
              "useDefault": true
            },
            "location": location
            //,"attendees": []
          };
          event.attendees = [{coworker@companyname.com, displayName: 'coworker name'}];
          
          //CREATE CALENDAR IN GOOGLE CALENDAR OF CONST CAL
          Calendar.Events.insert(event, CAL, {sendNotifications: true, supportsAttachments:true});
        
      } else{/*Tell user to fix data*/}
    }  
  }

非常感谢!


2017 年 12 月 29 日更新:

我已尝试根据 Jason Allshorn 和 Crazy Ivan 调整应用程序。感谢您的帮助,到目前为止!有趣的是,我在使用 Advanced Calendar Service 和 CalendarApp 时遇到了相同的响应。

错误是,如下图:

<!DOCTYPE html><html><head><link rel="shortcut icon" href="//ssl.gstatic.com/docs/script/images/favicon.ico"><title>Error</title><style type="text/css">body {background-color: #fff; margin: 0; padding: 0;}.errorMessage {font-family: Arial,sans-serif; font-size: 12pt; font-weight: bold; line-height: 150%; padding-top: 25px;}</style></head><body style="margin:20px"><div><img alt="Google Apps Script" src="//ssl.gstatic.com/docs/script/images/logo.png"></div><div style="text-align:center;font-family:monospace;margin:50px auto 0;max-width:600px">Object does not allow properties to be added or changed.</div></body></html>

或者,在通过 html 编辑器解析之后:

这到底是什么意思?我启用了高级服务,并且脚本可以从任何人运行。有什么想法吗?

我已经确认在尝试运行 calendarApp/Advanced Calendar 事件创建命令后返回的错误。

这是让我走到这一步的代码:

function convertURItoObject(url){  
      url = url.replace(/\+/g,' ')
      url = decodeURIComponent(url)
      var parts = url.split("&");
      var paramsObj = {};
      parts.forEach(function(item){
         var keyAndValue = item.split("=");
         paramsObj[keyAndValue[0]] = keyAndValue[1]
      })  
     return paramsObj; // here's your object
    }


function doPost(e) { 
  var data = e.postData.contents;
  data = convertURItoObject(data);
  
  var CAL = data.cal;
  var event = JSON.parse(data.event);
  var key = data.key;
  
  var start = new Date(event.start.dateTime);
  
  if(ACCEPTEDPROJECTS.indexOf(key) > -1)
  {
    try{
    var calendar = CalendarApp.getCalendarById(CAL);
    calendar.createEvent(event.summary, new Date(event.start.dateTime), new Date(event.end.dateTime), {description: event.description, location: event.location, guests: event.guests, sendInvites: true});}
    
    
    /*try {Calendar.Events.insert(event, CAL, {sendNotifications: true, supportsAttachments:true});} Same error when I use this command*/ 
    catch(fail){return ContentService.createTextOutput(JSON.stringify(fail));}
    
    e.postData.result = 'pass';
    return ContentService.createTextOutput(JSON.stringify(e)); 
  }
  else {
    return ContentService.createTextOutput('Execution not authorized from this source. See CONFIG of target project for details.'); 
  }
}

【问题讨论】:

    标签: google-apps-script google-sheets permissions calendar google-calendar-api


    【解决方案1】:

    您的脚本正在使用Advanced Google Services,特别是Calendar。阅读“启用高级服务”部分;每个人都必须按照这些步骤来使用该脚本。

    或者(在我看来,这是一个更好的解决方案),重写脚本,使其使用标准的CalendarApp 服务。它还允许您create an event,然后您可以add various reminders 参加该活动。

    【讨论】:

      【解决方案2】:

      我这边的一个解决方案是将日历事件创建功能从您的电子表格绑定脚本抽象为一个单独的独立应用程序脚本,该脚本以您的名义在您的权限下运行。

      然后从您的工作表绑定脚本调用独立脚本,其中包含更新日历所需的信息的 PUT 请求。这样,任何使用您的工作表插件的人都可以更新日历,而不会弄乱权限。

      工作表绑定脚本可能如下所示:

      function updateCalander(){
          var data = {
           'event': EVENT,
          };
          var options = {
            'method' : 'post',
            'contentType': 'application/json',
            'payload' : data
          };
      
          var secondScriptID = 'STANDALONE_SCRIPT_ID'
          var response = UrlFetchApp.fetch("https://script.google.com/macros/s/" + secondScriptID + "/exec", options);
          Logger.log(response) // Expected to see sent data sent back
      

      那么您的独立脚本将如下所示:

      function convertURItoObject(url){  
            url = url.replace(/\+/g,' ')
            url = decodeURIComponent(url)
            var parts = url.split("&");
            var paramsObj = {};
            parts.forEach(function(item){
               var keyAndValue = item.split("=");
               paramsObj[keyAndValue[0]] = keyAndValue[1]
            })  
           return paramsObj; // here's your object
          }
      
      
      function doPost(e) { 
        var CAL = 'companyname.com_1v033gttnxe2r3eakd8t9sduqg@group.calendar.google.com';
        var data = e.postData.contents;
        data = convertURItoObject(data)
        var event = data.event;
        try {
         Calendar.Events.insert(event, CAL, {sendNotifications: true, supportsAttachments:true});
        }
        catch(e){
         Logger.log(e)
        } 
        return ContentService.createTextOutput(JSON.stringify(e)); 
      }
      

      请注意,独立脚本需要设置为任何人都可以访问,并且当您对代码进行更新时,请务必重新发布代码。如果您不重新发布对独立脚本的调用,则不会对最新代码进行。

      【讨论】:

        【解决方案3】:

        这是一个延迟响应,但感谢所有推荐使用 POST 方法的人。事实证明,正确的方法是使用 URLFetchApp 并传递脚本的项目密钥来授权日历访问(我相信您只需要确保执行脚本的人有权编辑实际日历)。

        这里基本上是如何以一种功能性的方式做到这一点:

             //GCALENDAR is th e unique ID of the project int it's URL when the script is open for editing
             
             //PROJECTKEY is the unique ID of the project, found in the Project Properties Menu under FILE.
                
                
                //CREATE CALENDAR IN GOOGLE CALENDAR OF CONST CAL
                  var data = {
                    'event': JSON.stringify(event),
                    'cal': CAL,
                    'key': PROJECTKEY
                  };
                  
                  var options = {
                    'method' : 'post',
                    'contentType': 'application/json',
                    'payload' : data,
                    'muteHttpExceptions': true
                  };
                  
                  
                  var answer = UrlFetchApp.fetch("https://script.google.com/macros/s/" + GCALENDAR + "/exec", options).getContentText();
                  Logger.log(answer);

        【讨论】:

          猜你喜欢
          • 2014-11-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多