Preencher a agenda de férias da equipe

Nível de programação: iniciante
Duração: 15 min
Tipo de projeto: automação com um acionador baseado em tempo

Objetivos

  • Entender o que a solução faz.
  • Entender o que os serviços do Google Apps Script fazem na solução.
  • Configurar o script.
  • Executar o script.

Sobre esta solução

Uma agenda de férias compartilhada é uma ótima ferramenta para ajudar sua equipe a colaborar. Com ela, qualquer pessoa pode determinar quem está fora do escritório rapidamente. Com essa solução, você pode ver quando seus colegas estão fora do escritório sem precisar fazer entradas manuais.

Exemplo de uma agenda de férias da equipe preenchida com eventos fora do escritório

Como funciona

Essa solução preenche uma agenda de férias compartilhada com base nas agendas individuais de cada pessoa em um Grupo do Google. Quando alguém reserva um período de folga, adiciona um evento ao Google Agenda pessoal usando uma palavra-chave como "Férias" ou "Fora do escritório".

A cada hora, o script verifica as agendas dos membros do grupo e sincroniza os eventos adequados com a agenda compartilhada. Você pode mudar a frequência com que o script verifica novos eventos.

Essa solução só acessa eventos da agenda que seus colegas tornaram visíveis para você usando as configurações de privacidade.

Serviços do Apps Script

Essa solução usa os seguintes serviços:

Pré-requisitos

Para usar esse exemplo, você precisa dos seguintes pré-requisitos:

  • Uma Conta do Google (as contas do Google Workspace podem exigir a aprovação do administrador).
  • Um navegador da Web com acesso à Internet.

Configurar o script

Para configurar o script para preencher a agenda de férias da equipe, siga estas etapas:

Criar uma agenda de férias da equipe

  1. Abra o Google Agenda.
  2. Crie uma nova agenda chamada "Férias da equipe".
  3. Nas configurações da agenda, em Integrar agenda, copie o ID da agenda.

Criar o projeto do Apps Script

  1. Para abrir o projeto do Apps Script Agenda de férias, clique no botão a seguir: Abrir o projeto
  2. Clique em Visão geral .
  3. Na página de visão geral, clique em Fazer uma cópia O ícone para fazer uma cópia.
  4. No projeto do Apps Script copiado, defina a variável TEAM_CALENDAR_ID como o ID da agenda que você criou anteriormente.
  5. Defina a variável GROUP_EMAIL como o endereço de e-mail de um grupo do Grupos do Google que contenha os membros da sua equipe.
  6. Ao lado de Serviços, clique em Adicionar um serviço .
  7. Selecione API Google Calendar e clique em Adicionar.

Executar o script

  1. No projeto do Apps Script copiado, no menu suspenso de funções, selecione configuração.
  2. Clique em Executar.
  3. Quando solicitado, autorize o script. <<../_snippets/oauth.md>>
  4. Quando terminar, volte ao Google Agenda para confirmar se a agenda de férias da equipe está preenchida com eventos.

Revisar o código

Para revisar o código do Apps Script dessa solução, clique em Acessar o código-fonte:

Acessar o código-fonte

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;
}

Modificações

Você pode editar a automação da agenda de férias da equipe conforme necessário. A seguir, apresentamos uma mudança opcional para modificar o acionador.

Mudar a frequência com que o script verifica novos eventos

Para mudar a frequência com que o script é executado, siga estas etapas:

  1. No projeto do Apps Script, clique em Acionadores .
  2. Ao lado do acionador, clique em Editar acionador .
  3. Selecione as mudanças e clique em Salvar.

Colaboradores

Este exemplo é mantido pelo Google com a ajuda de Especialistas do Google Developers.

Próximas etapas