Start: Google Calendar: Event Started
This item starts a process when an event’s start time has passed on Google Calendar.
Configs: Common
  • Step Name
  • Note
Configs
  • C1: User connects to Google Calendar (must be App Administrator) *
  • C2: Calendar ID (Primary Calendar if blank)
  • C3: Data item to save Event ID *
  • C4: Data item to save Event Start Datetime
  • C5: Data item to save Event End Datetime
  • C6: Data item to save Event Title
  • C7: Data item to save Description
  • C8: Data item to save Event URL

Notes

  • Users specified in C1 need to have a configured connection with Google Calendar in [Account Settings] > [Google Connectivity]
    • Google Workspace Connectivity ([System Settings] > [Google Connectivity]) must be enabled on the workflow platform ([System Administrator Authorization] required)
  • Refer to the following page for the Calendar ID [Calendar Settings] > [Calendar Address]
  • Questetra BPM Suite will periodically poll the Google Calendar to check for newly-started events. If any event’s start time has passed, a process will be started.
  • A Process will not be started on the first check; only the check will be done. You can confirm the check status from the “Process Log”.
  • If a large number of events have started in a short period of time, the processes may not be started for all events. Approx. 90 processes can start every 15 minutes.

Capture

See also

Script (click to open)
  • An XML file that contains the code below is available to download
    • google-calendar-event-started.xml (C) Questetra, Inc. (MIT License)
      • Just use it for a reference for the codes
      • This file cannot be imported into a Workflow App as an Add-on

/**
 * @typedef {Object} timestamp java.sql.Timestamp オブジェクト
 */

/**
 * 開始時刻を経過したイベントの検索
 * @param limit イベント数の上限
 * @param timestampLowerLimit timestamp の下限
 * @return {Array} events イベント一覧
 */
const list = (limit, timestampLowerLimit) => {
    //// == 工程コンフィグの参照 / Config Retrieving ==
    const quser = configs.getObject("conf_User");
    if (quser === null) {
        throw `User not found.`;
    }
    let calendarId = configs.get("conf_CalendarId");
    if (calendarId === "" || calendarId === null) {
        calendarId = "primary";
    } else if (calendarId.search(/[^\w.@]/) !== -1) {
        throw "Invalid Calendar ID";
    }

    const events = getEvents(quser, calendarId, limit, timestampLowerLimit);
    logEvents(events);
    return events;
}

/** 日時フォーマッター */
const datetimeFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssX");
/**
 * @param {string} str 日時文字列
 * @return {timestamp} java.sql.Timestamp オブジェクト
 */
const parseDatetime = str => new java.sql.Timestamp(datetimeFormatter.parse(str).getTime());

/**
 * イベントのログ出力
 * @param {Array} events イベント一覧
 */
const logEvents = (events) => {
    if (events.length === 0) {
        engine.log('no events');
        return;
    }
    const replacer = (key, value) => value instanceof java.sql.Timestamp ? datetimeFormatter.format(value) : value;
    events.forEach(event => {
        engine.log(JSON.stringify(event, replacer));
    });
};

/**
 * イベント取得の GET リクエストを送信する
 * @param {QuserView} quser 実行ユーザ
 * @param {String} calendarId カレンダーID
 * @param {Number} limit 結果件数の上限
 * @param {timestamp} timestampLowerLimit イベント開始日時の下限
 * @return {Array} events イベント一覧
 * @return {string} events[].id イベント ID + 開始日時
 * @return {string} events[].eventId イベント ID
 * @return {timestamp} events[].timestamp 開始日時
 * @return {timestamp} events[].endTimestamp 終了日時
 * @return {string} events[].summary タイトル
 * @return {string} events[].description 詳細説明
 * @return {string} events[].htmlLink WebLink
 */
const getEvents = (quser, calendarId, limit, timestampLowerLimit) => {
    const eventsUrl = `https://www.googleapis.com/calendar/v3/calendars/${calendarId}/events`;
    engine.log(`API URI: ${eventsUrl}`);

    const response = httpClient
        .begin()
        .googleOAuth2(quser, "Calendar")
        .queryParam('maxResults', `${limit}`)
        .queryParam('orderBy', 'startTime')
        .queryParam('singleEvents', 'true')
        .queryParam('timeMin', datetimeFormatter.format(timestampLowerLimit))
        .queryParam('timeMax', datetimeFormatter.format(new java.sql.Timestamp(Date.now())))
        .queryParam('timeZone', engine.getTimeZoneId())
        .get(eventsUrl);

    //when error thrown
    const responseTxt = response.getResponseAsString();
    const status = response.getStatusCode();
    if (status >= 300) {
        engine.log(`---GET request--- ${status}`);
        engine.log(responseTxt);
        throw `Failed to get events. status: ${status}`;
    }
    const json = JSON.parse(responseTxt);

    // レコードオブジェクトを整形して返す
    const formatItem = (item) => {
        const eventId = String(item.id);
        const timestamp = parseStartEndDatetime(item.start);
        // eventId と timestamp の組み合わせを id に。予定の開始日時変更に対応するため。
        const id = `${eventId}_${timestamp.getTime()}`;
        return {
            id,
            eventId,
            timestamp,
            endTimestamp: parseStartEndDatetime(item.end),
            summary: item.summary,
            description: item.description,
            htmlLink: item.htmlLink
        };
    };

    return json.items.map(formatItem).reverse();
};

/** 終日予定用フォーマッター */
const allDayFormatter = new java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

/**
 * start or end のパース
 * @param start
 * @returns {timestamp} 日時
 */
const parseStartEndDatetime = (start) => {
    if (start.dateTime !== undefined) {
        return parseDatetime(start.dateTime);
    }
    // 「終日予定」の処理。「終日予定」はタイムゾーンの概念がない。
    // 終日予定の日付は、QBPMS タイムゾーンにおいて、「その日の 00:00:00」と解釈する。
    const time = allDayFormatter.parse(`${start.date} 00:00:00`).getTime();
    return new java.sql.Timestamp(time);
};
%d bloggers like this: