简体   繁体   中英

How to find a time for a meeting with several participants using Google Calendar API and Apps Script?

I am working on a chatbot project using Dialogflow API, Apps Script, Calendar API. The chatbot should be able to organize a meeting between two or more participants directly from the chat. For example, the user says something like "organize a meeting with john.smith@mail.com for tomorrow at 5 pm" and the chatbot should go to both my and John's calendars, check availability for this time frame and book the meeting. So far so good. I already have the solution up to this stage (check the code snippet below). My question is if the users are busy for this time frame, how can I get the suggested time where all the participants are free. I am using the Free/Busy call but it only returns when the users are busy.

//the function search in spreadshet containing all timezones and selects the corresponding offset
function setCorrectTimeZone(rawTime,rawDate){
  var spreadSheet = SpreadsheetApp.openById("10tJCi5bRHs3Cl8Gvw8NGMeHhfRBDnvPD338peH2MWyg"); //the timezones sheed ID stored in CEE Google Assistant shared drive
  var sheet = spreadSheet.getSheetByName("timezones");
  var timezoneRange = sheet.getRange(2, 1, 513, 2).getValues();
 
  //getting the user's timezone
  var userTimeZone = CalendarApp.getDefaultCalendar().getTimeZone();
  Logger.log("User time zone: " + userTimeZone);
  
  var userTimeZoneOffset = "";
  var correctDateTimeAndZone = "";

  //iterating over the timezones from the sheet and comparing with user's to find the correct offset
  for(var i = 0; i<timezoneRange.length; i++){
    if(timezoneRange[i][1] == userTimeZone){
      userTimeZoneOffset = timezoneRange[i][0];
    }
  }
  
  //taking the date only
  var date = rawDate.split('T')[0];
  //taking the time only
   var timeNoTimeZone = rawTime.split('+')[0].split('T')[1];
  //concatenating the date, time and the correct timezone together
  correctDateTimeAndZone = date + 'T' + timeNoTimeZone + userTimeZoneOffset;
  return correctDateTimeAndZone;
}


function organizeMeeting(dialogflowRawResponse, email) {  
  var guestEmail = dialogflowRawResponse.queryResult.parameters.email; //the list of all guests
  var rawDate = dialogflowRawResponse.queryResult.parameters.date; 
  var rawTime = dialogflowRawResponse.queryResult.parameters.time;
  var eventTitle = dialogflowRawResponse.queryResult.parameters.meetingName;
  var hasAllParams = dialogflowRawResponse.queryResult.hasOwnProperty('allRequiredParamsPresent'); //checker for all parameters
  var correctedTimezone = setCorrectTimeZone(rawTime,rawDate);
  Logger.log("Has all required parameters? " + hasAllParams);
  
  //check if all parameters are passed
  while(hasAllParams == false){
    Logger.log("Parameters are missing");
    Logger.log(dialogflowRawResponse.queryResult.fulfillmentText);
    return { text: dialogflowRawResponse.queryResult.fulfillmentText };
  }
  
  Logger.log("Guests email list detected: " + JSON.stringify(guestEmail) + "\nDate-time detected: " + rawTime + "\nCorrect date-time timezone: " + correctedTimezone +"\nTitle detected: " + eventTitle);

  //setting the date-time for the start and the end of the event
  var dateTimeStart = new Date(correctedTimezone);
  var dateTimeEnd = new Date(correctedTimezone);
  dateTimeEnd.setHours(dateTimeEnd.getHours() + 1);
  dateTimeStart = dateTimeStart.toISOString();
  dateTimeEnd = dateTimeEnd.toISOString();
  Logger.log("ISO dateTimeStart: " + dateTimeStart);
  Logger.log("ISO dateTimeEnd: " + dateTimeEnd);
  
  
  var participants = [{"id": email}]; //array of objects. Each object is a particpant for the event
  for(var i = 0; i < guestEmail.length; i++){
    participants.push({"id": guestEmail[i]}); //filling the participant array
  }
 
  //preparing the body for the Calendar API free-busy request
  var requestBody = {
    "timeMin": dateTimeStart,
    "timeMax": dateTimeEnd,
    "items": participants
  }
  
  //Calendar freebusy request to check if the slot is available for all particiaptns
  var response = Calendar.Freebusy.query(requestBody);
  
  for(var i = 0; i < participants.length; i++){
    var calendarId = participants[i].id;
    if(response.calendars[calendarId]['busy'].length != 0){
      Logger.log(calendarId + " is busy at this time");
      return { text: calendarId + " is busy at this time" };
      break;
    }
  } 
  
  //guest array of objects for each participant
  var guestsArr = [{"email":email}];
  for(var i = 0; i < guestEmail.length; i++){
    guestsArr.push({"email": guestEmail[i]});
  }
  
  //preparing the event details for the Calendar API call
  var event = {
    "summary": eventTitle,
    "end": {
      "dateTime": dateTimeEnd
    },
    "start": {
      "dateTime": dateTimeStart
    },
    "attendees": guestsArr
  }
  
  //preapring the event options for the Calendar API call
  var eventOptions = {
    "sendNotifications": true,
    "sendUpdates": "all"
  }
  
  //Calendar API call
  var calendarEventRequest = Calendar.Events.insert(event, "primary",eventOptions);
  
  //logs the Calendar API response to the logs
  Logger.log(JSON.stringify(calendarEventRequest));
  
  
  return { text: "Done! Check you calendar." };
}

The code above takes the parameters from Dialogflow API - date, time, meeting title, and participants and uses this information to make free/busy call and then Calendar API call eventually. It is also using spreadsheet db to find the correct user timezone based on the user location.

Any help will be highly appreciated if someone has already done such feature to get available time slots.

You can check each one-hour timeslot if everyone is free, if they are all free, then send the invitations in Calendar.

Sample Code:

    var dateTimeStart = new Date(correctedTimezone);
    var dateTimeEnd = new Date(correctedTimezone);

do {

    dateTimeEnd.setHours(dateTimeStart.getHours() + 1);
    dateTimeStart = dateTimeStart.toISOString();
    dateTimeEnd = dateTimeEnd.toISOString();
    Logger.log("ISO dateTimeStart: " + dateTimeStart);
    Logger.log("ISO dateTimeEnd: " + dateTimeEnd);
  
  
    var participants = [{"id": email}]; //array of objects. Each object is a particpant for the event
    for(var i = 0; i < guestEmail.length; i++){
        participants.push({"id": guestEmail[i]}); //filling the participant array
    }
 
  //preparing the body for the Calendar API free-busy request
    var requestBody = {
        "timeMin": dateTimeStart,
        "timeMax": dateTimeEnd,
        "items": participants
    }
  
  //Calendar freebusy request to check if the slot is available for all particiaptns
    var response = Calendar.Freebusy.query(requestBody);
  
    for(var i = 0; i < participants.length; i++){
        var calendarId = participants[i].id;
        if(response.calendars[calendarId]['busy'].length != 0){
           dateTimeStart.setHours(dateTimeStart.getHours() + 1);
           Logger.log(calendarId + " is busy at this time");
           //return { text: calendarId + " is busy at this time" };
        break;
    }
  } 

}
while (response.calendars[calendarId]['busy'].length != 0);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM