在 Apps 脚本中导入日历事件时如何调试 BadRequest 错误?

问题描述 投票:0回答:1

我使用了 https://developers.google.com/apps-script/samples/automations/vacation-calendar 上的“填充团队假期日历”示例来构建一个 Apps 脚本来提取所有外出事件进入共享日历。该脚本几个月来一直运行良好。在不对脚本进行任何更改的情况下,现在在调用

Calendar.Events.import(event, TEAM_CALENDAR_ID);
时出现错误:

GoogleJsonResponseException:对 calendar.events.import 的 API 调用失败并出现错误:错误请求

我已经在调试器中运行了脚本,并且该错误并没有提供任何有关错误实际是什么的信息,除了 400 错误请求之外。还有很多与日期/时间格式相关的其他问答,但我导入的

event
变量来自之前对
Calendar.Events.list(...)
的调用,因此它已经是 api 本身生成的 JS 事件对象。

这是一个最小的可重现示例:

let TEAM_CALENDAR_ID = '<calendar id goes here>';

function testImport() {
  const now = new Date();
  let user = Session.getActiveUser();
  
  // Fetch next 10 events
  let events = Calendar.Events.list(user.getEmail(), {
    timeMin: now.toISOString(),
    singleEvents: true,
    orderBy: 'startTime',
    maxResults: 10
  });

  if (events.items.length === 0) {
    console.error('No events found');
    return;
  }

  // Use next upcoming event for this user
  let event = events.items[0];

  // Set event fields
  event.organizer = { id: TEAM_CALENDAR_ID };
  event.attendees = [];

  try {
    Calendar.Events.import(event, TEAM_CALENDAR_ID);
  } catch (e) {
    console.error('Error attempting to import event: %s.', e.toString());
  }
}

如何调试这个?

这是整个脚本:

// Set the ID of the team calendar to add events to. You can find the calendar's
// ID on the settings page.
let TEAM_CALENDAR_ID = '<calendar ID here>';
// Set the email address of the Google Group that contains everyone in the team.
// Ensure the group has less than 500 members to avoid timeouts.
let GROUP_EMAIL = '<group email address here>';
let MONTHS_IN_ADVANCE = 3;
 
/**
 * Sets up the script to run automatically every hour.
 */
function setup() {
  let triggers = ScriptApp.getProjectTriggers();
  if (triggers.length > 0) {
    throw new Error('Triggers are already setup.');
  }
  ScriptApp.newTrigger('sync').timeBased().everyHours(1).create();
  // Runs the first sync immediately.
  sync();
}
 
/**
 * Looks through the group members' public calendars and adds any
 * 'vacation' or 'out of office' events to the team calendar.
 */
function sync() {
  // Defines the calendar event date range to search.
  let today = new Date();
  let maxDate = new Date();
  maxDate.setMonth(maxDate.getMonth() + MONTHS_IN_ADVANCE);
 
  // Determines the time the the script was last run.
  let lastRun = PropertiesService.getScriptProperties().getProperty('lastRun');
  lastRun = lastRun ? new Date(lastRun) : null;
 
  // Gets the list of users in the Google Group.
  let users = GroupsApp.getGroupByEmail(GROUP_EMAIL).getUsers();
 
  // For each user, finds Out Of Office events, and import
  // each to the team calendar.
  let count = 0;
  users.forEach(function(user) {
    let events = findEvents(user, today, maxDate, lastRun);
    events.forEach(function(event) {
      importEvent(user, event);
      count++;
    });
  });
 
  PropertiesService.getScriptProperties().setProperty('lastRun', today);
  console.log('Updated ' + count + ' events');
}
 
/**
 * In a given user's calendar, looks for Out Of Office events within the 
 * specified date range and returns any such events found.
 * @param {Session.User} user The user to retrieve events for.
 * @param {Date} start The starting date of the range to examine.
 * @param {Date} end The ending date of the range to examine.
 * @param {Date} optSince A date indicating the last time this script was run.
 * @return {Calendar.Event[]} An array of calendar events.
 */
function findEvents(user, start, end, optSince) {
  let params = {
    timeMin: formatDateAsRFC3339(start),
    timeMax: formatDateAsRFC3339(end),
    showDeleted: true,
  };
  if (optSince) {
    // This prevents the script from examining events that have not been
    // modified since the specified date (that is, the last time the
    // script was run).
    params.updatedMin = formatDateAsRFC3339(optSince);
  }
  let pageToken = null;
  let events = [];
  do {
    params.pageToken = pageToken;
    let response;
    try {
      response = Calendar.Events.list(user.getEmail(), params);
    } catch (e) {
      console.error('Error retriving events for %s: %s; skipping',
          user, e.toString());
      continue;
    }
    events = events.concat(response.items.filter(function(item) {
      return shoudImportEvent(user, item);
    }));
    pageToken = response.nextPageToken;
  } while (pageToken);
  return events;
}
 
/**
 * Determines if the given event should be imported into the shared team
 * calendar.
 * @param {Session.User} user The user that is attending the event.
 * @param {Calendar.Event} event The event being considered.
 * @return {boolean} True if the event should be imported.
 */
function shoudImportEvent(user, event) {
  
  // Skip events that are not Out Of Office
  if (event.eventType != "outOfOffice") {
    return false;
  }
  
  // If the user is the creator of the event, always imports it.
  if (!event.organizer || event.organizer.email == user.getEmail()) {
    return true;
  }
  
  // Only imports events the user has accepted.
  if (!event.attendees) {
    return false;
  }
  let matching = event.attendees.filter(function(attendee) {
    return attendee.self;
  });
  
  return matching.length > 0 && matching[0].responseStatus == 'accepted';
}
 
/**
 * Imports the given event from the user's calendar into the shared team
 * calendar.
 * @param {string} username The team member that is attending the event.
 * @param {Calendar.Event} event The event to import.
 */
function importEvent(user, event) {
  let username = user.getEmail().split('@')[0];
  username = username.charAt(0).toUpperCase() + username.slice(1);
  event.summary = '[' + username + '] ' + event.summary;
  event.organizer = {
    id: TEAM_CALENDAR_ID,
  };
  event.attendees = [];
  let action = event.status == "confirmed" ? "Importing" : "Removing";
  console.log('%s: %s on %s', action, event.summary, event.start.getDateTime());
  try {
    Calendar.Events.import(event, TEAM_CALENDAR_ID);
  } catch (e) {
    console.error('Error attempting to import event: %s. Skipping.',
        e.toString());
  }
}
 
/**
 * Returns an RFC3339 formated date String corresponding to the given
 * Date object.
 * @param {Date} date a Date.
 * @return {string} a formatted date string.
 */
function formatDateAsRFC3339(date) {
  return Utilities.formatDate(date, 'UTC', 'yyyy-MM-dd\'T\'HH:mm:ssZ');
}
google-apps-script google-calendar-api http-status-code-400 bad-request
1个回答
0
投票

自 2023 年 11 月 29 日起,已报告关于 Calendar.Events.import() 失败并出现“

错误请求”错误的 Google 问题

根据最新更新,

outOfOfficeProperties
(通过删除 event.outOfOfficeProperties) 确实解决了问题。


参考

    自 11 月 29 日起,Calendar.Events.import() 因“错误请求”而失败

© www.soinside.com 2019 - 2024. All rights reserved.