- save refreshed tokens of both calendar integrations
- Office365 expiry check was off by *1000 - log errors from calendar integrations with console.error - improved google calendar integration performance further when calendars are selected
This commit is contained in:
parent
6d7ec7fa66
commit
ded27d17ea
1 changed files with 88 additions and 47 deletions
|
@ -1,14 +1,44 @@
|
||||||
|
import prisma from "./prisma";
|
||||||
|
|
||||||
const {google} = require('googleapis');
|
const {google} = require('googleapis');
|
||||||
import createNewEventEmail from "./emails/new-event";
|
import createNewEventEmail from "./emails/new-event";
|
||||||
|
|
||||||
const googleAuth = () => {
|
const googleAuth = (credential) => {
|
||||||
const {client_secret, client_id, redirect_uris} = JSON.parse(process.env.GOOGLE_API_CREDENTIALS).web;
|
const {client_secret, client_id, redirect_uris} = JSON.parse(process.env.GOOGLE_API_CREDENTIALS).web;
|
||||||
return new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);
|
const myGoogleAuth = new google.auth.OAuth2(client_id, client_secret, redirect_uris[0]);
|
||||||
|
myGoogleAuth.setCredentials(credential.key);
|
||||||
|
|
||||||
|
const isExpired = () => myGoogleAuth.isTokenExpiring();
|
||||||
|
|
||||||
|
const refreshAccessToken = () => myGoogleAuth.refreshToken(credential.key.refresh_token).then(res => {
|
||||||
|
const token = res.res.data;
|
||||||
|
credential.key.access_token = token.access_token;
|
||||||
|
credential.key.expiry_date = token.expiry_date;
|
||||||
|
return prisma.credential.update({
|
||||||
|
where: {
|
||||||
|
id: credential.id
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
key: credential.key
|
||||||
|
}
|
||||||
|
}).then(() => {
|
||||||
|
myGoogleAuth.setCredentials(credential.key);
|
||||||
|
return myGoogleAuth;
|
||||||
|
});
|
||||||
|
}).catch(err => {
|
||||||
|
console.error("Error refreshing google token", err);
|
||||||
|
return myGoogleAuth;
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
getToken: () => !isExpired() ? Promise.resolve(myGoogleAuth) : refreshAccessToken()
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function handleErrorsJson(response) {
|
function handleErrorsJson(response) {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
response.json().then(console.log);
|
response.json().then(e => console.error("O365 Error", e));
|
||||||
throw Error(response.statusText);
|
throw Error(response.statusText);
|
||||||
}
|
}
|
||||||
return response.json();
|
return response.json();
|
||||||
|
@ -16,7 +46,7 @@ function handleErrorsJson(response) {
|
||||||
|
|
||||||
function handleErrorsRaw(response) {
|
function handleErrorsRaw(response) {
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
response.text().then(console.log);
|
response.text().then(e => console.error("O365 Error", e));
|
||||||
throw Error(response.statusText);
|
throw Error(response.statusText);
|
||||||
}
|
}
|
||||||
return response.text();
|
return response.text();
|
||||||
|
@ -24,9 +54,10 @@ function handleErrorsRaw(response) {
|
||||||
|
|
||||||
const o365Auth = (credential) => {
|
const o365Auth = (credential) => {
|
||||||
|
|
||||||
const isExpired = (expiryDate) => expiryDate < +(new Date());
|
const isExpired = (expiryDate) => expiryDate < Math.round((+(new Date()) / 1000));
|
||||||
|
|
||||||
const refreshAccessToken = (refreshToken) => fetch('https://login.microsoftonline.com/common/oauth2/v2.0/token', {
|
const refreshAccessToken = (refreshToken) => {
|
||||||
|
return fetch('https://login.microsoftonline.com/common/oauth2/v2.0/token', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
headers: {'Content-Type': 'application/x-www-form-urlencoded'},
|
||||||
body: new URLSearchParams({
|
body: new URLSearchParams({
|
||||||
|
@ -41,8 +72,16 @@ const o365Auth = (credential) => {
|
||||||
.then((responseBody) => {
|
.then((responseBody) => {
|
||||||
credential.key.access_token = responseBody.access_token;
|
credential.key.access_token = responseBody.access_token;
|
||||||
credential.key.expiry_date = Math.round((+(new Date()) / 1000) + responseBody.expires_in);
|
credential.key.expiry_date = Math.round((+(new Date()) / 1000) + responseBody.expires_in);
|
||||||
return credential.key.access_token;
|
return prisma.credential.update({
|
||||||
|
where: {
|
||||||
|
id: credential.id
|
||||||
|
},
|
||||||
|
data: {
|
||||||
|
key: credential.key
|
||||||
|
}
|
||||||
|
}).then(() => credential.key.access_token)
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getToken: () => !isExpired(credential.key.expiry_date) ? Promise.resolve(credential.key.access_token) : refreshAccessToken(credential.key.refresh_token)
|
getToken: () => !isExpired(credential.key.expiry_date) ? Promise.resolve(credential.key.access_token) : refreshAccessToken(credential.key.refresh_token)
|
||||||
|
@ -173,7 +212,7 @@ const MicrosoftOffice365Calendar = (credential): CalendarApiAdapter => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
).catch((err) => {
|
).catch((err) => {
|
||||||
console.log(err);
|
console.error(err);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
createEvent: (event: CalendarEvent) => auth.getToken().then(accessToken => fetch('https://graph.microsoft.com/v1.0/me/calendar/events', {
|
createEvent: (event: CalendarEvent) => auth.getToken().then(accessToken => fetch('https://graph.microsoft.com/v1.0/me/calendar/events', {
|
||||||
|
@ -206,32 +245,32 @@ const MicrosoftOffice365Calendar = (credential): CalendarApiAdapter => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const GoogleCalendar = (credential): CalendarApiAdapter => {
|
const GoogleCalendar = (credential): CalendarApiAdapter => {
|
||||||
const myGoogleAuth = googleAuth();
|
const auth = googleAuth(credential);
|
||||||
myGoogleAuth.setCredentials(credential.key);
|
|
||||||
const integrationType = "google_calendar";
|
const integrationType = "google_calendar";
|
||||||
|
|
||||||
return {
|
return {
|
||||||
getAvailability: (dateFrom, dateTo, selectedCalendars) => new Promise((resolve, reject) => {
|
getAvailability: (dateFrom, dateTo, selectedCalendars) => new Promise((resolve, reject) => auth.getToken().then(myGoogleAuth => {
|
||||||
const calendar = google.calendar({version: 'v3', auth: myGoogleAuth});
|
const calendar = google.calendar({version: 'v3', auth: myGoogleAuth});
|
||||||
calendar.calendarList
|
const selectedCalendarIds = selectedCalendars.filter(e => e.integration === integrationType).map(e => e.externalId);
|
||||||
.list()
|
if (selectedCalendarIds.length == 0 && selectedCalendars.length > 0){
|
||||||
.then(cals => {
|
|
||||||
const filteredItems = cals.data.items.filter(i => selectedCalendars.findIndex(e => e.externalId === i.id) > -1)
|
|
||||||
if (filteredItems.length == 0 && selectedCalendars.length > 0){
|
|
||||||
// Only calendars of other integrations selected
|
// Only calendars of other integrations selected
|
||||||
resolve([]);
|
resolve([]);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
(selectedCalendarIds.length == 0
|
||||||
|
? calendar.calendarList.list().then(cals => cals.data.items.map(cal => cal.id))
|
||||||
|
: Promise.resolve(selectedCalendarIds)).then(calsIds => {
|
||||||
calendar.freebusy.query({
|
calendar.freebusy.query({
|
||||||
requestBody: {
|
requestBody: {
|
||||||
timeMin: dateFrom,
|
timeMin: dateFrom,
|
||||||
timeMax: dateTo,
|
timeMax: dateTo,
|
||||||
items: filteredItems.length > 0 ? filteredItems : cals.data.items
|
items: calsIds.map(id => ({id: id}))
|
||||||
}
|
}
|
||||||
}, (err, apires) => {
|
}, (err, apires) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
resolve(
|
resolve(
|
||||||
Object.values(apires.data.calendars).flatMap(
|
Object.values(apires.data.calendars).flatMap(
|
||||||
(item) => item["busy"]
|
(item) => item["busy"]
|
||||||
|
@ -240,11 +279,12 @@ const GoogleCalendar = (credential): CalendarApiAdapter => {
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
console.error('There was an error contacting google calendar service: ', err);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
|
|
||||||
}),
|
})),
|
||||||
createEvent: (event: CalendarEvent) => new Promise((resolve, reject) => {
|
createEvent: (event: CalendarEvent) => new Promise((resolve, reject) => auth.getToken().then(myGoogleAuth => {
|
||||||
const payload = {
|
const payload = {
|
||||||
summary: event.title,
|
summary: event.title,
|
||||||
description: event.description,
|
description: event.description,
|
||||||
|
@ -276,13 +316,13 @@ const GoogleCalendar = (credential): CalendarApiAdapter => {
|
||||||
resource: payload,
|
resource: payload,
|
||||||
}, function (err, event) {
|
}, function (err, event) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log('There was an error contacting the Calendar service: ' + err);
|
console.error('There was an error contacting google calendar service: ', err);
|
||||||
return reject(err);
|
return reject(err);
|
||||||
}
|
}
|
||||||
return resolve(event.data);
|
return resolve(event.data);
|
||||||
});
|
});
|
||||||
}),
|
})),
|
||||||
updateEvent: (uid: String, event: CalendarEvent) => new Promise((resolve, reject) => {
|
updateEvent: (uid: String, event: CalendarEvent) => new Promise((resolve, reject) => auth.getToken().then(myGoogleAuth => {
|
||||||
const payload = {
|
const payload = {
|
||||||
summary: event.title,
|
summary: event.title,
|
||||||
description: event.description,
|
description: event.description,
|
||||||
|
@ -317,13 +357,13 @@ const GoogleCalendar = (credential): CalendarApiAdapter => {
|
||||||
resource: payload
|
resource: payload
|
||||||
}, function (err, event) {
|
}, function (err, event) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log('There was an error contacting the Calendar service: ' + err);
|
console.error('There was an error contacting google calendar service: ', err);
|
||||||
return reject(err);
|
return reject(err);
|
||||||
}
|
}
|
||||||
return resolve(event.data);
|
return resolve(event.data);
|
||||||
});
|
});
|
||||||
}),
|
})),
|
||||||
deleteEvent: (uid: String) => new Promise( (resolve, reject) => {
|
deleteEvent: (uid: String) => new Promise( (resolve, reject) => auth.getToken().then(myGoogleAuth => {
|
||||||
const calendar = google.calendar({version: 'v3', auth: myGoogleAuth});
|
const calendar = google.calendar({version: 'v3', auth: myGoogleAuth});
|
||||||
calendar.events.delete({
|
calendar.events.delete({
|
||||||
auth: myGoogleAuth,
|
auth: myGoogleAuth,
|
||||||
|
@ -333,13 +373,13 @@ const GoogleCalendar = (credential): CalendarApiAdapter => {
|
||||||
sendUpdates: 'all',
|
sendUpdates: 'all',
|
||||||
}, function (err, event) {
|
}, function (err, event) {
|
||||||
if (err) {
|
if (err) {
|
||||||
console.log('There was an error contacting the Calendar service: ' + err);
|
console.error('There was an error contacting google calendar service: ', err);
|
||||||
return reject(err);
|
return reject(err);
|
||||||
}
|
}
|
||||||
return resolve(event.data);
|
return resolve(event.data);
|
||||||
});
|
});
|
||||||
}),
|
})),
|
||||||
listCalendars: () => new Promise((resolve, reject) => {
|
listCalendars: () => new Promise((resolve, reject) => auth.getToken().then(myGoogleAuth => {
|
||||||
const calendar = google.calendar({version: 'v3', auth: myGoogleAuth});
|
const calendar = google.calendar({version: 'v3', auth: myGoogleAuth});
|
||||||
calendar.calendarList
|
calendar.calendarList
|
||||||
.list()
|
.list()
|
||||||
|
@ -352,9 +392,10 @@ const GoogleCalendar = (credential): CalendarApiAdapter => {
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.catch((err) => {
|
||||||
|
console.error('There was an error contacting google calendar service: ', err);
|
||||||
reject(err);
|
reject(err);
|
||||||
});
|
});
|
||||||
})
|
}))
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue