Aggiungere docenti a calendario condiviso

Nel mio Istituto gli impegni collegiali vengono gestiti tramite un calendario condiviso di Calendar: modalità di lavoro utile, ma finora non era mai stato possibile aggiungere di default i docenti a questo calendario. G Suite prevede che gli utenti debbano inserire in prima persona il calendario condiviso nella sezione I miei calendari. Al più si possono invitare tramite mail, ma ognuno di loro deve poi cliccare sul link perché la procedura venga completata. Con il problema evidente che chi non lo fa, o aspetta a farlo, non viene aggiornato degli impegni collegiali con l’immediatezza che sarebbe richiesta.

Dopo numerosi tentativi, siamo riusciti a mettere insieme una procedura per aggiungere automaticamente i docenti al calendario, senza passare per accettazione da parte dell’utente. In questo articolo vediamo un foglio di lavoro con script annesso che gestisce il processo. Si può facilmente riadattare il tutto a scenari diversi, con poche modifiche.

Se sei esperto e conosci già la struttura di Google Apps Script, e le diverse modalità di autenticazione e accesso ai dati degli utenti, puoi saltare la premessa. Se invece queste idee non ti sono familiari, è bene dare un’occhiata per avere quantomeno un’idea generale di cosa farà lo script qui proposto. Come evidenzierò sotto, il meccanismo è molto delicato: dà grandi vantaggi, ma se mal impostato può fare anche gravi danni.

Le procedure indicate in questa pagina si basano sull’esecuzione di azioni con privilegi elevati e ad ampio spettro sull’amministrazione di G Suite. Prima di applicarle verifica che rispondano alle tue esigenze, ed accertati di aver compreso i meccanismi le regolano. Ne va della sicurezza di tutta la piattaforma di G Suite. Maggiori informazioni a questo link: Controllare l’accesso all’API di G Suite con la delega a livello di dominio.

Premessa

Servizi di base e servizi avanzati per gli script

Quando si parla di script, Calendar è un osso più duro di altre applicazioni. I dati hanno una strutturazione piuttosto articolata, e i metodi che agiscono su di essi richiedono un po’ di studio per comprenderne bene i meccanismi di funzionamento. Oltre a questo primo dato, se ne aggiunge un secondo ad aumentare la complessità della procedura che vediamo qui.

Quasi tutte le app di Google possono essere manipolate tramite script in due modi, come si vede dallo schema della Reference di Google Apps Script – il manuale di base per chi vuole inoltrarsi nel mondo degli script di G Suite. Una prima modalità viene fornita dalla sezione Google Workspace Services: qui troviamo metodi più semplici per accedere ai dati delle app, facilmente utilizzabili negli script, ma che offrono solo alcune delle funzionalità di manipolazione. Nella sezione Advanced Google Services troviamo metodi più complessi per accedere ai dati delle app G Suite, ma molto più versatili e completi. A prezzo di uno studio più approfondito, possiamo portare a termine compiti articolati e tagliati su misura delle nostre esigenze.

Nella procedura di questa pagina utilizzeremo i servizi avanzati di Calendar.

Agire sugli utenti vs impersonare gli utenti

Molti dei metodi utilizzabili da script – tanto dei servizi base quanto di quelli avanzati – permettono di modificare i dati di tutti gli utenti, se eseguiti da un account superadmin. Non tutti, però. Alcuni metodi agiscono solo sui dati dell’utente che esegue lo script.

Per aggiungere il calendario condiviso ai docenti, abbiamo bisogno di inserirlo tra i suoi calendari: da script, dobbiamo agire sulla classe CalendarList. Questa classe rispecchia esattamente la situazione appena descritta: i metodi che la modificano agiscono solo su CalendarList dell’utente che li esegue. Non possiamo quindi modificare direttamente CalendarList di altri utenti all’interno di uno script, anche se eseguito da superadmin.

In questi casi è necessario adottare un altro approccio, più complesso ma molto versatile. Anziché agire sui dati di un altro utente – essendo impossibile con alcuni metodi – lo script deve impersonare quell’utente, e modificare i dati – CalendarList nel nostro caso – ‘fingendo’ di essere quell’utente specifico.

Sommario

Per ottenere il risultato finale dovremo:

  • creare un account di servizio su Google Cloud Platform, ed ottenere le credenziali
  • delegare a quell’account permessi di intervento sull’intero dominio (domain-wide delegation)
  • importare nello script la libreria per la gestione dell’autenticazione con OAuth, ed impostare la funzione che ottiene il token per impersonare l’utente
  • creare la funzione principale che per ognuno dei docenti richiede il token ed aggiunge il calendario condiviso nella lista dei calendari

La procedura

1. Creare account di servizio con domain-wide delegation

Impersonare un altro utente richiede procedure complesse.
Anzitutto bisogna creare un utente di servizio dedicato su Google Cloud Platform, per ragioni di sicurezza la cui trattazione va oltre gli scopi di questo post. In secondo luogo, bisogna autorizzare quell’account ad agire su tutti gli utenti del dominio.

La procedura per entrambe le azioni è ben documentata nella guida di Google: Perform Google Workspace Domain-Wide Delegation of Authority. Segui passo passo le indicazioni di primi due paragrafi di questa pagina – Create the service account and credentials e Delegate domain-wide authority to your service account.

Ad un certo punto della procedura descritta nel primo paragrafo, verrà scaricato sul computer in uso un file in formato .json contenente le credenziali di utilizzo dell’account di servizio appena creato. È fondamentale archiviare quel file in modo sicuro e non diffonderlo: con quelle credenziali è possibile avere accesso globale a tutte le impostazioni di G Suite e modificarle, con grossa compromissione della sicurezza in caso finisca in mani sbagliate. Le credenziali verranno usate nello script più sotto.

Nel secondo paragrafo, al punto 5, viene indicato di aggiungere gli ambiti (scopes) di utilizzo dell’account di servizio: di fatto, sono le autorizzazioni sulle app che stiamo dando a quell’account. Il consiglio è sempre di autorizzare il minimo indispensabile, a maggior tutela della sicurezza della piattaforma. Per la procedura indicata in questo post è sufficiente inserire lo scope

https://www.googleapis.com/auth/calendar

Se si vorrà espandere lo script con funzionalità aggiuntive su altre applicazioni, dovranno eventualmente essere aggiunti anche gli altri ambiti necessari al funzionamento.

2. Importare la libreria per la gestione dell’autenticazione con OAuth

Si potrebbe gestire interamente dal proprio script il processo di autenticazione, ma l’utilizzo di una libreria semplifica notevolmente questo passaggio. Esistono diverse librerie sul web per l’autenticazione tramite protocollo OAuth; io ho utilizzato Apps Script OAuth2 su GitHub soprattutto per la comodità di utilizzo e di integrazione con il proprio progetto. Per aggiungerla basta visitare il link appena riportato, e seguire le brevi istruzioni della sezione Setup. Riassumendo:

  • creiamo un nuovo foglio di lavoro, lo rinominiamo a piacere, e clicchiamo su Strumenti > Editor di script
  • clicchiamo sull’icona Salva, e diamo un nome al progetto dello script
  • clicchiamo sul menu Risorse > Librerie, e nel campo Add a library inseriamo il codice identificativo copiato dalla sezione Setup della guida della libreria indicata sopra
  • scegliamo ora dal menu a tendina il numero di versione da utilizzare – inseriamo l’ultima disponibile

Ora la libreria è integrata e funzionante.

3. Impostare le autorizzazioni e copiare lo script

Dallo stesso menu Risorse utilizzato prima, clicchiamo su Servizi avanzati di Google: attiviamo con lo slider sulla destra Admin SDK Directory e Calendar API, clicchiamo su OK e attendiamo qualche istante. Una notifica in alto ci avvisa che le autorizzazioni sono state aggiornate.

Possiamo ora eliminare la funzione vuota predefinita nel corpo della pagina, e copiare lo script per aggiungere i docenti al calendario:

function aggiungiCalendarioAiDocenti(){
  var calendarId = 'iddelcalendariodacondividere@group.calendar.google.com'; //sostituisci l'id con quello del calendario che vuoi condividere
  var groupEmail = 'gruppo@miodominio.edu.it'; // sostituisci il nome del gruppo 
  
  // recupera gli indirizzi email dei membri del gruppo 
  var userEmails = getUserEmailsInGroup(groupEmail);
  
  var calendarlistResource = {
    "kind": "calendar#calendarListEntry",
    "id": calendarId,
    "hidden": false,
    "selected": true
  };

  for (var user in userEmails){
      var utente = userEmails[user];
    
    try{
    addUserToCalendar(utente,calendarlistResource, calendarId);
    }
    catch(e){
      Logger.log("addGroupToCalendar: Errore nell'indirizzo email o nell'ID calendario: "+ e)
    };
  };      
};



// ----- funzione che recupera gli indirizzi email dei membri del gruppo

function getUserEmailsInGroup(groupID){
  
  try{
    var groupMembers = AdminDirectory.Members.list(groupID);

    var groupMemberEmails = groupMembers.members.map(function(user){
      return user.email
    });
  }
  catch(e){
    Logger.log("getUserEmailsInGroup: Nessun gruppo con questo ID: "+ e);
  }
  
  return groupMemberEmails

};


// -------------------

function addUserToCalendar(user, calendarListResource, calendarId) {
  
    var service = getOAuthService(user);
    service.reset();
    if (service.hasAccess()) {
      
      var url = 'https://www.googleapis.com/calendar/v3/users/me/calendarList';
      
      var resource = calendarListResource;
      
      var requestBody                = {};
      requestBody.headers            = {'Authorization': 'Bearer ' + service.getAccessToken()};
      requestBody.contentType        = "application/json";
      requestBody.method             = "POST";
      requestBody.payload            = JSON.stringify(resource);
      requestBody.muteHttpExceptions = false;
      
      try {
      var aggiungiCalendario = UrlFetchApp.fetch(url, requestBody);
        Logger.log(aggiungiCalendario);
      }
      catch(e) {
        Logger.log(e);
      }
              
    } else {
      Logger.log('Accesso al servizio negato.');
    }
}


// -------- funzione di autenticazione per calendario
// -----------------------------------

function getOAuthService(user) {
  
  var JSON = {
    // modifica le prossime 3 righe con i dati giusti
    "private_key": "-----BEGIN PRIVATE KEY-----\INSERISCI QUI LA PRIVATE KEY DEL FILE JSON CON LE CREDENZIALI\n-----END PRIVATE KEY-----\n",
    "client_email": "INSERISCI QUI L'INDIRIZZO EMAIL DELL'ACCOUNT DI SERVIZIO CREATO SU GOOGLE CLOUD PLATFORM",
    "client_id": "INSERISCI QUI IL CLIENT ID DEL FILE JSON CON LE CREDENZIALI",
    "user_email": user
  };
  
    return OAuth2.createService("Service Account")
        .setTokenUrl('https://accounts.google.com/o/oauth2/token')
        .setPrivateKey(JSON.private_key)
        .setIssuer(JSON.client_email)
        .setSubject(JSON.user_email)
        .setPropertyStore(PropertiesService.getScriptProperties())
        .setParam('access_type', 'offline')
        .setScope('https://www.googleapis.com/auth/calendar');
}



// -----------

function reset() {
    var service = getOAuthService();
    service.reset();
}

Il testo dello script è già commentato, e sono indicate le parti da modificare, che riassumiamo qui:

  • calendarId: inserire qui l’id del calendario che si vuole condividere con tutto il gruppo dei docenti. Per trovare l’id bisogna aprire Calendar, nel menu a sinistra cercare il nome del calendario e cliccare sui 3 puntini verticali a fianco, quindi scegliere Impostazioni e condivisione. Scorrendo in basso nella schermata che si apre, alla sezione Integra calendario troviamo l’id, nel formato lungastringaalfanumerica@group.calendar.google.com
  • groupEmail: il gruppo che contiene gli utenti con cui condividere il calendario
  • private_key: la chiave privata contenuta nel file json, generato con la creazione dell’account di servizio. È una stringa molto lunga, racchiusa tra le diciture —–BEGIN PRIVATE KEY—–\n e \n—–END PRIVATE KEY—–\n, che vanno incluse
  • client_email: l’indirizzo email dell’account di servizio generato all’inizio
  • client_id: ricavabile dallo stesso file json, è una sequenza solo numerica

Ricordarsi di inserire tutti questi dati tra virgolette.

4. Eseguire lo script

Prima di eseguire lo script con i parametri reali, è bene fare una prova con un gruppo ristretto (meglio se account di prova) e un calendario diverso. Verificato che tutto funzioni, si possono modificare nuovamente calendarId e groupEmail con i dati definitivi, quindi procedere.

Per lanciare lo script basta cliccare sul menu a tendina Seleziona una funzione e scegliere aggiungiCalendarioAiDocenti, quindi cliccare l’icona Play a sinistra. La prima volta verrà chiesto di concedere le autorizzazioni, che vanno accettate.

In caso di errori, vengono indicati in alto con notifica a sfondo rosso.

Per verificare se tutto ha funzionato, accedere a Calendar con un account appartenente al gruppo di prova. Nella sezione I miei calendari dovrebbe comparire il calendario indicato nello script; questo dovrebbe essere già selezionato e visibile. Sulla destra devono già essere mostrati gli eventi di questo calendario.

Questa presentata è una versione semplificata dello script che ho eseguito e testato solo personalmente, e solo sul mio dominio. Se riscontri errori o problemi, puoi segnalarli più sotto tra i commenti. Ogni suggerimento per migliorare la procedura è gradito.

Per proseguire…

Lo script qui presentato è volutamente grezzo, e non sarebbe necessario legarlo ad un foglio di lavoro. Ho voluto impostarlo in questo modo perché, come si può notare, è possibile con poche modifiche adattarlo ad innumerevoli scenari.

Banalmente, per iniziare si può scrivere una funzione onOpen per integrare l’esecuzione dello script in un menu personalizzato del foglio di lavoro. Eseguita una prima volta la funzione su tutto il gruppo, non sarà poi necessario ripetere ogni volta l’intero ciclo. Ecco che con qualche variazione si potrebbe far eseguire la funzione principale su un elenco di utenti presi da un range del foglio di lavoro – magari i nuovi utenti che abbiamo appena creato ed inserito tramite file csv. Oppure, con una funzione onEdit, si potrebbe creare una cella con menu a tendina a fianco di una lista di nomi utente, per far eseguire la funzione solo su alcune righe di un elenco.

Per i più esperti, si potrebbe perfezionare la funzione separata getOAuthService(user) che gestisce l’autenticazione. In questo script la funzione è già tagliata sulle operazioni di Calendar, e imposta solo l’ambito – scope – relativo. Si potrebbe generalizzare la funzione inserendo tra i parametri in entrata lo scope, oltre che l’utente. La riga

.setScope('https://www.googleapis.com/auth/calendar');

verrebbe quindi modificata, magari da un ciclo iterativo o con un elenco nel formato case… switch, in modo da impostare l’ambito adeguato per l’applicazione che si vuole utilizzare. Si aprono così le porte alla manipolazione dei dati dell’utente in modi anche molto complessi e raffinati: una funzione di autenticazione unica ci permette di impostare servizi diversi a seconda delle esigenze. Dopo l’aggiunta del calendario, si possono performare sui docenti altre operazioni preliminari per l’attivazione dei servizi G Suite in uso nel nostro Istituto.


Credits

Questo lavoro – così come il codice – deve molto a tante risorse e contributi sul web. Prima di tutto al blog Yagisanatode, fonte di ispirazione e luogo di confronto con l’autore sul codice implementato. Molte discussioni su Stackoverflow mi hanno permesso di affinare la parte relativa alla domain-wide delegation. E in particolar modo il contributo su GitHub della libreria già citata OAuth2 mi ha permesso di semplificare la gestione dell’autenticazione per impersonare l’utente.

Se vuoi essere avvisato dei prossimi articoli, iscriviti alla Newsletter: riceverai una notifica quando viene pubblicato un nuovo post su questo sito.

Condividi questo contenuto

Taggato come

Lascia un commento

Il tuo indirizzo email non sarà pubblicato. I campi obbligatori sono contrassegnati *

Questo sito usa Akismet per ridurre lo spam. Scopri come i tuoi dati vengono elaborati.

Iscriviti alla Newsletter

I tuoi dati rimarranno privati; verranno condivisi solo con chi rende possibile questo servizio. Leggi la privacy policy.