Introduction:
- The integration between Google Meet and Java is a great way for developers to create applications for users that are tailored to their specific needs.
- Google Meet is an incredibly useful platform for joining meetings and keeping track of events.
- The Google Console provides a comprehensive range of capabilities to manage and control the events, such as creating, updating, and deleting events.
- They also allow for customization of the events, such as setting up reminders, adding notes, and inviting participants.
Prerequisites:
- Liferay (Any version)
- An Google account
- Knowledge of API
Environmental Requirements:
- Browser
- Liferay
- Eclipse IDE
- Gradle
Google Cloud Project Creation and Enable API
We can create Google Meet links using the Google Calendar API. There are a few ways to connect the Google Calendar APIs with the Liferay portal, which are as follows.- We can generate the Google Calendar event with Java code.
- We need the “credentials.json” file for the authentication and with the help of this authentication, we can authenticate with Google.
- To generate the credentials.json file we have to follow the following steps:
- Sign in as a Google developer account.
-
- Visit the following link
- Please sign in with your Google account.
-
- After signing in, we have to hit “Authorize requests to the Google Calendar API”.
-
- You will get the following screen access the “go to OAuth consent screen” button.
- You will get the following accept request with your google account name.
- Create Project
- Please select the CREATE PROJECT.
-
- Google Meet integration with Liferay-5
-
- Please fill it up and then press the create button. You will get the following screen. Please select the external option.
- Internal:
- External:
- Please fill it up and then press the create button. You will get the following screen. Please select the external option.
- After creating the application you will get the following form.
- Please fill in the required field which is following in the form.
- App name:- You can set the app name to whatever you want.
- User support email:- You have to provide the sign-in email address.
- Developer Contact Information:- You can provide your email address or admin email address
- After filling in the required fields, please click on “Save and Continue”.
- Please fill in the required field which is following in the form.
- After creating the application you will get the following form.
-
- You will get the scope screen of the form you just have to press the SAVE AND CONTINUE button.
- You will get the Test User screen of the form you just have to press the SAVE AND CONTINUE button.
- You will get the summary screen of the form and you just have to go to the dashboard.
- Your newly created application will be displayed like the following, with user type.
- Create OAuth 2.0 credentials.
- Now go to the credentials section.
-
- You will get the following screen. Now we have to create new client credentials.
- Click on the CREATE CREDENTIALS BUTTON
- You will get the following screen. Now we have to create new client credentials.
-
- You have to select the “OAuth 2.0 Client ID” option to create the OAuth 2.0 client credentials.
-
- Now Select the Application Type -> Web Application.
- Now enter the Authorized JavaScript origins
http://localhost
-
- Now enter the Authorized redirect URIs
-
- Now create the OAuth client ID. You will be redirected to the credentials page with one record added to the OAuth2.0 client.
- Download the JSON File
- Now we have to enable the google calendar API.
- Go to the “Enabled API & Services ”
-
- Select “ENABLE APIS AND SERVICES”
-
- Now search for “Google Calendar API” in the search bar.
-
- You will get the following results.
-
- Select the “Google Calendar API”.
-
- Enable the Google Calendar API.
Liferay Rest Builder
Here I’m creating one rest builder to perform create, update, get, and delete operations on Google Calendar events. Follow these steps to create a Liferay rest builder and call the Google Calendar APIs:- First, Create Liferay Workspace and a rest builder (If you don’t know how to create a rest builder then take reference from here).
- Here I have created “google-calendar-rest” named Rest Builder.
- Go to the google-calendar-rest-impl -> rest-openapi.yaml file and write the below text.
// rest-openapi.yaml
info:
description: "GoogleCalendarRest REST API"
license:
name: "Apache 2.0"
url: "http://www.apache.org/licenses/LICENSE-2.0.html"
title: "GoogleCalendarRest"
version: v1.0
openapi: 3.0.1
paths:
"/update-google-meet-link":
post:
operationId: updateGoogleMeetLink
requestBody:
content:
application/json:
schema:
$ref: "#/components/schemas/Meet"
application/xml:
schema:
$ref: "#/components/schemas/Meet"
responses:
200:
content:
application/json:
schema:
$ref: "#/components/schemas/Meet"
application/xml:
schema:
$ref: "#/components/schemas/Meet"
description: ""
tags: ["Meet"]
"/get-google-meet-link":
get:
operationId: getGoogleMeetLink
parameters:
- in: query
name: eventId
required: true
schema:
type: string
responses:
200:
content:
application/json:
schema:
$ref: "#/components/schemas/Meet"
application/xml:
schema:
$ref: "#/components/schemas/Meet"
description: ""
404:
description: "Meet not found"
500:
description: "Internal server error"
tags: ["Meet"]
"/delete-google-meet-link":
delete:
operationId: deleteGoogleMeetLink
parameters:
- in: query
name: eventId
required: true
schema:
type: string
responses:
200:
content:
application/json:
schema:
$ref: "#/components/schemas/Meet"
application/xml:
schema:
$ref: "#/components/schemas/Meet"
description: ""
tags: ["Meet"]
components:
schemas:
Meet:
description: adding or updating google meet link
properties:
eventId:
description: The eventId.
type: string
title:
description: The title.
type: string
description:
description: The description.
type: string
setDate:
description: The setDate in "yyyy-MM-dd HH:mm" format.
type: string
endDate:
description: The endDate in "yyyy-MM-dd HH:mm" format.
type: string
timeZone:
description: The timeZone.
type: string
location:
description: The location.
type: string
meetLink:
description: The meetLink.
type: string
repeat:
description: The MeetLink.
type: integer
emailAddress:
description: The emailAddress.
type: array
items:
type: string
status:
$ref: "#/components/schemas/Status"
Status:
properties:
statusMessage:
type: string
statusCode:
type: integer
- Now, build rest of it, and you will see the below files. Open the “MeetResourceImpl” class file.
- Add methods in the “MeetResourceImpl” class file (updateGoogleMeetLink, getGoogleMeetLink, and deleteGoogleMeetLink).
- Now go to modules -> google-calendar-rest -> google-calendar-rest-impl -> build.gradle. And replace with the below lines.
// build.gradle
dependencies {
compile project(":modules:google-calendar-rest:google-calendar-rest-api")
compileOnly group: "com.liferay.portal", name: "release.portal.api"
compileOnly group: "javax.xml.bind", name: "jaxb-api", version: "2.3.0"
compile group: 'org.apache.httpcomponents', name: 'httpclient'
compile group: 'org.apache.httpcomponents', name: 'httpcore'
compileOnly group: 'javax.websocket', name: 'javax.websocket-api'
implementation group: 'javax.mail', name: 'mail', version: '1.4.1'
cssBuilder group: "com.liferay", name: "com.liferay.css.builder", version: "3.0.3"
implementation 'com.google.api-client:google-api-client:2.0.0'
implementation 'com.google.oauth-client:google-oauth-client-jetty:1.34.1'
implementation 'com.google.apis:google-api-services-calendar:v3-rev20220715-2.0.0'
}
group = "google.calendar.rest"
- Now go to modules -> google-calendar-rest -> google-calendar-rest-impl -> bnd.bnd (source) file and replace with below lines.
// bnd.bnd
Bundle-Name: google-calendar-rest-impl
Bundle-SymbolicName: google.calendar.rest.impl
Bundle-Version: 1.0.0
-privatepackage: \
com.google.api.client.*,\
com.google.api.services.*,\
com.google.common.base.*,\
com.google.common.cache,\
com.google.common.collect,\
com.google.common.io,\
com.google.common.graph,\
com.google.common.hash,\
com.google.common.math,\
com.google.common.primitives,\
com.google.common.util,\
com.google.common.util.concurrent,\
com.google.common.util.concurrent.internal,\
com.google.errorprone.annotations,\
com.google.errorprone.annotations.concurrent,\
com.google.gson.*,\
io.opencensus.common,\
io.opencensus.contrib.http.util,\
io.opencensus.stats,\
io.opencensus.internal,\
io.opencensus.metrics.data,\
io.opencensus.tags.*,\
io.grpc,\
io.opencensus.trace.*,\
javax.annotation.*,\
org.apache.http.config,\
org.apache.http.conn.*,\
org.apache.http.concurrent,\
org.apache.http.impl.conn.tsccm,\
org.apache.http.ssl,\
org.checkerframework.checker.nullness.qual,\
org.checkerframework.framework.qual
- Now, create a package “com.ignek.google.meet” in the “google-calendar-rest-impl/src/main/java” folder.
- Now, add an interface “GoogleMeetService” and a class “GoogleMeetServiceImpl” which implements “GoogleMeetService”.
- Now, create a package “com.ignek.google.meet.model” in the “google-calendar-rest-impl/src/main/java” folder. and create a class “ResponseDTO” that implements serializable.
// ResponseDTO.java
package com.ignek.google.meet.model;
import java.io.Serializable;
import javax.ws.rs.core.Response;
public class ResponseDTO implements Serializable {
protected static Response.Status STATUS_OK = Response.Status.OK;
protected static Response.Status STATUS_ERROR = Response.Status.INTERNAL_SERVER_ERROR;
private final int status;
private final String message;
private ResponseDTO(int status, String message) {
this.status = status;
this.message = message;
}
protected ResponseDTO(Response.Status status) {
this(status.getStatusCode(), status.getReasonPhrase());
}
protected ResponseDTO(Response.Status status, String message) {
this(status.getStatusCode(), status.getReasonPhrase() + ": " + message);
}
public static ResponseDTO ok() {
return new ResponseDTO(STATUS_OK);
}
public static ResponseDTO fail() {
return new ResponseDTO(STATUS_ERROR);
}
public static ResponseDTO error(String message) {
return new ResponseDTO(STATUS_ERROR, message);
}
public int getStatus() {
return status;
}
public String getMessage() {
return message;
}
}
- Now, In the same package “com.ignek.google.meet.model” create a class “GoogleMeetResponse” that extends ResponseDTO.
// GoogleMeetResponse.java
package com.ignek.google.meet.model;
import com.liferay.petra.string.StringPool;
public class GoogleMeetResponse extends ResponseDTO {
private final String eventId;
private final String link;
private GoogleMeetResponse(String link, String eventId) {
super(STATUS_OK);
this.eventId = eventId;
this.link = link;
}
private GoogleMeetResponse(String message) {
super(STATUS_ERROR, message);
this.eventId = StringPool.BLANK;
this.link = StringPool.BLANK;
}
public static GoogleMeetResponse of(String link, String eventId) {
return new GoogleMeetResponse(link, eventId);
}
public static GoogleMeetResponse fail(String message) {
return new GoogleMeetResponse(message);
}
public String getEventId() {
return eventId;
}
public String getLink() {
return link;
}
}
- Now, go to the “GoogleMeetService” file. And write the below code.
// GoogleMeetService.java
package com.ignek.google.meet;
import com.ignek.google.meet.model.GoogleMeetResponse;
public interface GoogleMeetService {
GoogleMeetResponse updateGoogleMeetEvent(String eventId, String title, String location, String[] emails,
String description, String startTime, String endTime, String timeZone, Integer repeat);
String getGoogleMeetLink(String eventId);
void deleteGoogleMeetEvent(String eventId);
}
- Now, go to the “GoogleMeetServiceImpl” file. And write the below code.
// GoogleMeetServiceImpl.java
package com.ignek.google.meet;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import java.util.UUID;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.client.util.DateTime;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.calendar.Calendar;
import com.google.api.services.calendar.CalendarScopes;
import com.google.api.services.calendar.model.ConferenceData;
import com.google.api.services.calendar.model.ConferenceSolutionKey;
import com.google.api.services.calendar.model.CreateConferenceRequest;
import com.google.api.services.calendar.model.Event;
import com.google.api.services.calendar.model.EventAttendee;
import com.google.api.services.calendar.model.EventDateTime;
import com.google.api.services.calendar.model.EventReminder;
import com.ignek.google.meet.model.GoogleMeetResponse;
import com.liferay.petra.string.StringPool;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.kernel.util.Validator;
@Component(immediate = true, service = GoogleMeetService.class)
public class GoogleMeetServiceImpl implements GoogleMeetService {
@Override
public GoogleMeetResponse updateGoogleMeetEvent(String eventId, String title, String location, String[] emails,
String description, String startTime, String endTime, String timeZone, Integer repeat) {
try {
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
Calendar service = new Calendar.Builder(HTTP_TRANSPORT, GsonFactory.getDefaultInstance(),
getCredentials(HTTP_TRANSPORT)).setApplicationName(APPLICATION_NAME).build();
String calendarId = "primary";
Event event = Validator.isNull(eventId) ? new Event() : service.events().get(calendarId, eventId).execute();
event.setSummary(title);
event.setLocation(location);
event.setDescription(description);
TimeZone userTimeZone = TimeZone.getTimeZone(timeZone);
DateTime startDateTime = new DateTime(new Date(convertDate(startTime).getTime()
- userTimeZone.getRawOffset()));
EventDateTime start = new EventDateTime().setDateTime(startDateTime).setTimeZone(timeZone);
event.setStart(start);
DateTime endDateTime = new DateTime(new Date(convertDate(endTime).getTime()
- userTimeZone.getRawOffset()));
EventDateTime end = new EventDateTime().setDateTime(endDateTime).setTimeZone(timeZone);
event.setEnd(end);
ConferenceSolutionKey conferenceSKey = new ConferenceSolutionKey();
conferenceSKey.setType( "hangoutsMeet");
CreateConferenceRequest createConferenceReq = new CreateConferenceRequest();
createConferenceReq.setRequestId(UUID.randomUUID().toString());
createConferenceReq.setConferenceSolutionKey(conferenceSKey);
ConferenceData conferenceData = new ConferenceData();
conferenceData.setCreateRequest(createConferenceReq);
event.setConferenceData(conferenceData);
List recurrences = new ArrayList<>();
recurrences.add(getrecurrenceByRepeatType(repeat));
event.setRecurrence(recurrences);
List attendees = new ArrayList<>();
for (String email : emails) {
EventAttendee attendee = new EventAttendee();
attendees.add(attendee.setEmail(email));
}
event.setAttendees(attendees);
EventReminder[] reminderOverrides = new EventReminder[] {
new EventReminder().setMethod("email").setMinutes(24 * 60),
new EventReminder().setMethod("popup").setMinutes(10) };
Event.Reminders reminders = new Event.Reminders().setUseDefault(false)
.setOverrides(Arrays.asList(reminderOverrides));
event.setReminders(reminders);
event = Validator.isNull(eventId)
? service.events().insert(calendarId, event).setConferenceDataVersion(1)
.setSendNotifications(true).execute()
: service.events().update(calendarId, eventId, event).execute();
return GoogleMeetResponse.of(event.getHangoutLink(), event.getId());
} catch (Exception e) {
log.error(e.getMessage(), e);
return GoogleMeetResponse.fail(e.getMessage());
}
}
@Override
public String getGoogleMeetLink(String eventId) {
try {
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
Calendar service = new Calendar.Builder(HTTP_TRANSPORT, GsonFactory.getDefaultInstance(),
getCredentials(HTTP_TRANSPORT)).setApplicationName(APPLICATION_NAME).build();
String calendarId = "primary";
Event event = Validator.isNull(eventId) ? new Event() : service.events().get(calendarId, eventId)
.execute();
return event.getHangoutLink();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
return StringPool.BLANK;
}
@Override
public void deleteGoogleMeetEvent(String eventId) {
try {
final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
Calendar service = new Calendar.Builder(HTTP_TRANSPORT, GsonFactory.getDefaultInstance(),
getCredentials(HTTP_TRANSPORT)).setApplicationName(APPLICATION_NAME).build();
String calendarId = "primary";
service.events().delete(calendarId, eventId).execute();
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
private String getrecurrenceByRepeatType(int repeat) {
if (repeat == REPEAT_TYPE_NO) {
return "RRULE:FREQ=DAILY;COUNT=1";
}
if (repeat == REPEAT_TYPE_DAILY) {
return "RRULE:FREQ=DAILY;INTERVAL=1";
}
if (repeat == REPEAT_TYPE_WEEKLY) {
return "RRULE:FREQ=WEEKLY;BYDAY=MO;INTERVAL=1";
}
if (repeat == REPEAT_TYPE_MONTHLY) {
return "RRULE:FREQ=MONTHLY;BYMONTHDAY=1;INTERVAL=1";
}
if (repeat == REPEAT_TYPE_YEARLY) {
return "RRULE:FREQ=YEARLY;BYMONTH=1;BYMONTHDAY=1";
}
return StringPool.BLANK;
}
private Date convertDate(String date) throws ParseException {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm");
return formatter.parse(date);
}
private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
InputStream inputStream = GoogleMeetServiceImpl.class.getResourceAsStream("/credentials.json");
// Add credentials.json to */src/main/resources/credentials.json
if (Validator.isNull(inputStream)) {
throw new FileNotFoundException("Resource not found: credentials.json");
}
GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(GsonFactory.getDefaultInstance(),
new InputStreamReader(inputStream));
GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow
.Builder(HTTP_TRANSPORT, GsonFactory.getDefaultInstance(), clientSecrets,
Collections.singletonList(CalendarScopes.CALENDAR))
.setDataStoreFactory(new FileDataStoreFactory(new java.io.File("tokens")))
.setAccessType("offline")
.setApprovalPrompt("force")
.setScopes(CalendarScopes.all())
.build();
LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(9080).build();
//check port is already assigned or not and put same port number as entered in redirect URIs for Callback
return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
}
private static final String APPLICATION_NAME = "Testing Application";
private static final int REPEAT_TYPE_NO = 0;
private static final int REPEAT_TYPE_DAILY = 1;
private static final int REPEAT_TYPE_WEEKLY = 2;
private static final int REPEAT_TYPE_MONTHLY = 3;
private static final int REPEAT_TYPE_YEARLY = 4;
private static final Log log = LogFactoryUtil.getLog(GoogleMeetServiceImpl.class);
}
- Please replace APPLICATION_NAME in above file with your data that we renamed while creating the application in Google Console.
- Now, go to the “MeetResourceImpl” file. And write the below code.
//MeetResourceImpl.java
package google.calendar.rest.internal.resource.v1_0;
import javax.validation.constraints.NotNull;
import javax.ws.rs.core.Response;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ServiceScope;
import com.ignek.google.meet.GoogleMeetService;
import com.ignek.google.meet.model.GoogleMeetResponse;
import google.calendar.rest.dto.v1_0.Meet;
import google.calendar.rest.dto.v1_0.Status;
import google.calendar.rest.resource.v1_0.MeetResource;
/**
* @author ignek
*/
@Component(properties = "OSGI-INF/liferay/rest/v1_0/meet.properties", scope = ServiceScope.PROTOTYPE, service = MeetResource.class)
public class MeetResourceImpl extends BaseMeetResourceImpl {
@Reference
private GoogleMeetService googleMeetService;
@Override
public Meet updateGoogleMeetLink(Meet meet) throws Exception {
String eventId = meet.getEventId();
String title = meet.getTitle();
String description = meet.getDescription();
String location = meet.getLocation();
String setDate = meet.getSetDate();
String endDate = meet.getEndDate();
String timeZone = meet.getTimeZone();
int repeat = meet.getRepeat();
String[] emailAddresses = meet.getEmailAddress();
GoogleMeetResponse googleMeetResponse = googleMeetService.updateGoogleMeetEvent(eventId, title, location,
emailAddresses, description, setDate, endDate, timeZone, repeat);
String meetLink = googleMeetResponse.getLink();
eventId = googleMeetResponse.getEventId();
Status status = new Status();
status.setStatusCode(googleMeetResponse.getStatus());
status.setStatusMessage(googleMeetResponse.getMessage());
meet.setStatus(status);
meet.setEventId(eventId);
meet.setMeetLink(meetLink);
return meet;
}
@Override
public Meet getGoogleMeetLink(@NotNull String eventId) throws Exception {
Meet meet = new Meet();
String meetLink = googleMeetService.getGoogleMeetLink(eventId);
meet.setMeetLink(meetLink);
meet.setEventId(eventId);
return meet;
}
@Override
public Meet deleteGoogleMeetLink(@NotNull String eventId) throws Exception {
Meet meet = new Meet();
Status status = new Status();
try {
googleMeetService.deleteGoogleMeetEvent(eventId);
status.setStatusCode(Response.Status.OK.getStatusCode());
status.setStatusMessage("Deleted Successfully");
} catch (Exception e) {
status.setStatusCode(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
status.setStatusMessage(e.getMessage());
}
meet.setStatus(status);
return meet;
}
}
- Now, deploy the rest module and you can test the above rest-apis using graphQL.
- Here, you can find graphQL for adding or updating Google Calendar events. For adding an event you have to pass “eventId” as blank and for updating an event you have to pass the eventId of that event.
mutation ($meet: InputMeet!) {
updateGoogleMeetLink(meet: $meet) {
eventId
meetLink
status {
statusCode
statusMessage
}
}
}
/* Query Variables */
{
"meet": {
"title": "My first meet link",
"description": "test google meet link",
"emailAddress": [
"test@yopmail.com",
"test1@yopmail.com"
],
"setDate": "2023-05-16 13:15",
"endDate": "2023-05-16 14:15",
"eventId": "",
"location": "my house",
"timeZone": "GMT+5:30",
"repeat": 0
}
}
- Here is what you can pass in “repeat”:
- Repeat No = 0;
- Repeat Daily = 1;
- Repeat Weekly = 2;
- Repeat Monthly = 3;
- Repeat Yearly = 4;
- When you run this API for the first time, it will ask for authentication. A url can be found in terminal for authentication.
- Run that url in your browser. You will be asked to select a Google account.
- The following screen will appear after that.
- Just click on “Allow”. It will redirect to the url that is entered in “redirect url” In my case, it will redirect to “localhost:9099/Callback”.
- Here, you can find graphQL for getting Google Meet link.
{
googleMeetLink(eventId: "") {
meetLink
eventId
}
}
- Here, you can find graphQL for deleting Google Meet events.
mutation {
deleteGoogleMeetLink(eventId: "") {
status {
statusCode
statusMessage
}
}
}
Note*: Google APIs return many parameters in their responses. As an eventId, we are taking “id” and as a team link, we are taking “hangoutLink”.
Here is an example response:
{
"kind": "calendar#event",
"etag": etag,
"id": string,
"status": string,
"htmlLink": string,
"created": datetime,
"updated": datetime,
"summary": string,
"description": string,
"location": string,
"colorId": string,
"creator": {
"id": string,
"email": string,
"displayName": string,
"self": boolean
},
"organizer": {
"id": string,
"email": string,
"displayName": string,
"self": boolean
},
"start": {
"date": date,
"dateTime": datetime,
"timeZone": string
},
"end": {
"date": date,
"dateTime": datetime,
"timeZone": string
},
"endTimeUnspecified": boolean,
"recurrence": [
string
],
"recurringEventId": string,
"originalStartTime": {
"date": date,
"dateTime": datetime,
"timeZone": string
},
"transparency": string,
"visibility": string,
"iCalUID": string,
"sequence": integer,
"attendees": [
{
"id": string,
"email": string,
"displayName": string,
"organizer": boolean,
"self": boolean,
"resource": boolean,
"optional": boolean,
"responseStatus": string,
"comment": string,
"additionalGuests": integer
}
],
"attendeesOmitted": boolean,
"extendedProperties": {
"private": {
(key): string
},
"shared": {
(key): string
}
},
"hangoutLink": string,
"conferenceData": {
"createRequest": {
"requestId": string,
"conferenceSolutionKey": {
"type": string
},
"status": {
"statusCode": string
}
},
"entryPoints": [
{
"entryPointType": string,
"uri": string,
"label": string,
"pin": string,
"accessCode": string,
"meetingCode": string,
"passcode": string,
"password": string
}
],
"conferenceSolution": {
"key": {
"type": string
},
"name": string,
"iconUri": string
},
"conferenceId": string,
"signature": string,
"notes": string,
},
"gadget": {
"type": string,
"title": string,
"link": string,
"iconLink": string,
"width": integer,
"height": integer,
"display": string,
"preferences": {
(key): string
}
},
"anyoneCanAddSelf": boolean,
"guestsCanInviteOthers": boolean,
"guestsCanModify": boolean,
"guestsCanSeeOtherGuests": boolean,
"privateCopy": boolean,
"locked": boolean,
"reminders": {
"useDefault": boolean,
"overrides": [
{
"method": string,
"minutes": integer
}
]
},
"source": {
"url": string,
"title": string
},
"workingLocationProperties": {
"homeOffice": (value),
"customLocation": {
"label": string
},
"officeLocation": {
"buildingId": string,
"floorId": string,
"floorSectionId": string,
"deskId": string,
"label": string
}
},
"attachments": [
{
"fileUrl": string,
"title": string,
"mimeType": string,
"iconLink": string,
"fileId": string
}
],
"eventType": string
}