Completa un calendario delle vacanze di team

Livello di codifica: principiante
Durata: 15 minuti
Tipo di progetto: automazione con un attivatore basato sul tempo

Obiettivi

  • Comprendere il funzionamento della soluzione.
  • Comprendere il funzionamento dei servizi Google Apps Script all'interno della soluzione.
  • Configurare lo script.
  • Eseguire lo script.

Informazioni su questa soluzione

Un calendario delle ferie condiviso è uno strumento ideale per aiutare il tuo team a collaborare: chiunque può determinare chi è fuori sede a colpo d'occhio. Questa soluzione ti consente di vedere quando i tuoi colleghi sono fuori sede, senza dover inserire manualmente i dati.

Esempio di un calendario delle ferie del team compilato con eventi fuori sede

Come funziona

Questa soluzione popola un calendario delle ferie condiviso in base ai calendari individuali di ogni persona in un gruppo Google. Quando qualcuno prenota un periodo di ferie, aggiunge un evento al proprio Google Calendar personale utilizzando una parola chiave come "Ferie" o "Fuori sede".

Ogni ora, lo script esamina i calendari dei membri del gruppo e sincronizza gli eventi appropriati con il calendario condiviso. Puoi modificare la frequenza con cui lo script cerca nuovi eventi.

Questa soluzione accede solo agli eventi di Calendar che i tuoi colleghi hanno reso visibili a te utilizzando le impostazioni sulla privacy.

Servizi Apps Script

Questa soluzione utilizza i seguenti servizi:

Prerequisiti

Per utilizzare questo esempio, devi soddisfare i seguenti prerequisiti:

  • Un Account Google (gli account Google Workspace potrebbero richiedere l'approvazione dell'amministratore).
  • Un browser web con accesso a internet.

Configurare lo script

Per configurare lo script per popolare il calendario delle ferie del team, completa i seguenti passaggi:

Creare un calendario delle ferie del team

  1. Apri Calendar.
  2. Crea un nuovo calendario denominato "Ferie del team".
  3. Nelle impostazioni del calendario, in Integra calendario, copia l' ID calendario.

Creare il progetto Apps Script

  1. Per aprire il progetto Apps Script Calendario delle ferie, fai clic sul pulsante seguente: Apri il progetto
  2. Fai clic su Panoramica .
  3. Nella pagina di panoramica, fai clic su Crea una copia L'icona per creare una copia.
  4. Nel progetto Apps Script copiato, imposta la variabile TEAM_CALENDAR_ID sull'ID del calendario che hai creato in precedenza.
  5. Imposta la variabile GROUP_EMAIL sull'indirizzo email di un gruppo Gruppi Google contenente i membri del tuo team.
  6. Accanto a Servizi, fai clic su Aggiungi un servizio .
  7. Seleziona API Google Calendar e fai clic su Aggiungi.

Eseguire lo script

  1. Nel progetto Apps Script copiato, seleziona setup nel menu a discesa della funzione.
  2. Fai clic su Esegui.
  3. Quando ti viene richiesto, autorizza lo script. <<../_snippets/oauth.md>>
  4. Al termine, torna a Calendar per verificare che il calendario Ferie del team sia popolato con gli eventi.

Esaminare il codice

Per esaminare il codice Apps Script per questa soluzione, fai clic su Visualizza codice sorgente:

Visualizza codice sorgente

Code.gs

solutions/automations/vacation-calendar/Code.js
// To learn how to use this script, refer to the documentation:
// https://developers.google.com/apps-script/samples/automations/vacation-calendar

/*
Copyright 2022 Google LLC

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    https://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

// Set the ID of the team calendar to add events to. You can find the calendar's
// ID on the settings page.
const TEAM_CALENDAR_ID = "ENTER_TEAM_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.
// Change to an array in order to add indirect members frrm multiple groups, for example:
// let GROUP_EMAIL = ['ENTER_GOOGLE_GROUP_EMAIL_HERE', 'ENTER_ANOTHER_GOOGLE_GROUP_EMAIL_HERE'];
const GROUP_EMAIL = "ENTER_GOOGLE_GROUP_EMAIL_HERE";

const ONLY_DIRECT_MEMBERS = false;

const KEYWORDS = ["vacation", "ooo", "out of office", "offline"];
const MONTHS_IN_ADVANCE = 3;

/**
 * Sets up the script to run automatically every hour.
 */
function setup() {
  const 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.
  const today = new Date();
  const 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 = getAllMembers(GROUP_EMAIL);
  if (ONLY_DIRECT_MEMBERS) {
    users = GroupsApp.getGroupByEmail(GROUP_EMAIL).getUsers();
  } else if (Array.isArray(GROUP_EMAIL)) {
    users = getUsersFromGroups(GROUP_EMAIL);
  }

  // For each user, finds events having one or more of the keywords in the event
  // summary in the specified date range. Imports each of those to the team
  // calendar.
  let count = 0;
  for (const user of users) {
    const username = user.getEmail().split("@")[0];
    const events = findEvents(user, today, maxDate, lastRun);
    for (const event of events) {
      importEvent(username, event);
      count++;
    }
  }

  PropertiesService.getScriptProperties().setProperty("lastRun", today);
  console.log(`Imported ${count} events`);
}

/**
 * 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(username, event) {
  event.summary = `[${username}] ${event.summary}`;
  event.organizer = {
    id: TEAM_CALENDAR_ID,
  };
  event.attendees = [];

  // If the event is not of type 'default', it can't be imported, so it needs
  // to be changed.
  if (event.eventType !== "default") {
    event.eventType = "default";
    event.outOfOfficeProperties = undefined;
    event.focusTimeProperties = undefined;
  }

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

/**
 * In a given user's calendar, looks for occurrences of the given keyword
 * in events within the specified date range and returns any such events
 * found.
 * @param {Session.User} user The user to retrieve events for.
 * @param {string} keyword The keyword to look 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) {
  const params = {
    eventTypes: "outOfOffice",
    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: %s; skipping",
        user,
        keyword,
        e.toString(),
      );
      continue;
    }
    events = events.concat(response.items);
    pageToken = response.nextPageToken;
  } while (pageToken);
  return events;
}

/**
 * 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");
}

/**
 * Get both direct and indirect members (and delete duplicates).
 * @param {string} the e-mail address of the group.
 * @return {object} direct and indirect members.
 */
function getAllMembers(groupEmail) {
  const group = GroupsApp.getGroupByEmail(groupEmail);
  let users = group.getUsers();
  const childGroups = group.getGroups();
  for (let i = 0; i < childGroups.length; i++) {
    const childGroup = childGroups[i];
    users = users.concat(getAllMembers(childGroup.getEmail()));
  }
  // Remove duplicate members
  const uniqueUsers = [];
  const userEmails = {};
  for (let i = 0; i < users.length; i++) {
    const user = users[i];
    if (!userEmails[user.getEmail()]) {
      uniqueUsers.push(user);
      userEmails[user.getEmail()] = true;
    }
  }
  return uniqueUsers;
}

/**
 * Get indirect members from multiple groups (and delete duplicates).
 * @param {array} the e-mail addresses of multiple groups.
 * @return {object} indirect members of multiple groups.
 */
function getUsersFromGroups(groupEmails) {
  const users = [];
  for (const groupEmail of groupEmails) {
    const groupUsers = GroupsApp.getGroupByEmail(groupEmail).getUsers();
    for (const user of groupUsers) {
      if (!users.some((u) => u.getEmail() === user.getEmail())) {
        users.push(user);
      }
    }
  }
  return users;
}

Modifiche

Puoi modificare l'automazione del calendario delle ferie del team in base alle tue esigenze. Di seguito è riportata una modifica facoltativa per modificare l'attivatore.

Modificare la frequenza con cui lo script cerca nuovi eventi

Per modificare la frequenza di esecuzione dello script:

  1. Nel progetto Apps Script, fai clic su Attivatori .
  2. Accanto all'attivatore, fai clic su Modifica attivatore .
  3. Seleziona le modifiche e fai clic su Salva.

Collaboratori

Questo esempio è gestito da Google con l'aiuto di Esperti Google Developers.

Passaggi successivi