aboutsummaryrefslogtreecommitdiff
path: root/src/gapi.js
diff options
context:
space:
mode:
authorDeterminant <ted.sybil@gmail.com>2019-01-31 14:48:28 -0500
committerDeterminant <ted.sybil@gmail.com>2019-01-31 14:48:28 -0500
commitf9f537e3dd28aa543770aea158e4eff65be0b261 (patch)
treeddaafeec02f2fe66fb913c0cf4795b7b41d06bde /src/gapi.js
parente458b7a692d9ac4ab91b2ef6ee36ff439c528c50 (diff)
impl GCalendar sync model
Diffstat (limited to 'src/gapi.js')
-rw-r--r--src/gapi.js167
1 files changed, 151 insertions, 16 deletions
diff --git a/src/gapi.js b/src/gapi.js
index 975d4d9..c66a9ff 100644
--- a/src/gapi.js
+++ b/src/gapi.js
@@ -12,28 +12,163 @@ export function getAuthToken() {
}
export function getCalendars(token) {
- return fetch(gapi_base + '/users/me/calendarList?' + to_params({access_token: token}),
+ return fetch(`${gapi_base}/users/me/calendarList?${to_params({access_token: token})}`,
{ method: 'GET', async: true })
.then(response => response.json())
.then(data => data.items);
}
-export function genEventsGetter(calId, timeMin, timeMax) {
- return token => fetch(gapi_base + '/calendars/' + calId + '/events?' + to_params({
- access_token: token,
- timeMin,
- timeMax
- }), { method: 'GET', async: true })
- .then(response => {
- if (response.status === 200)
- return response.json()
- else throw `got response ${response.status}`;
- })
- .catch(e => { console.log(e); return []; })
- .then(data => data.items);
+export function getColors(token) {
+ return fetch(`${gapi_base}/colors?${to_params({access_token: token})}`,
+ { method: 'GET', async: true })
+ .then(response => response.json());
}
-export function getColors(token) {
- return fetch(gapi_base + '/colors?' + to_params({access_token: token}), { method: 'GET', async: true })
+function getEvent(calId, eventId, token) {
+ return fetch(`${gapi_base}/calendars/${calId}/events/${eventId}?${to_params({access_token: token})}`,
+ { method: 'GET', async: true })
.then(response => response.json());
}
+
+function getEvents(calId, token, syncToken, resultsPerRequest = '') {
+ let results = [];
+ const singleFetch = (pageToken, syncToken) => fetch(`${gapi_base}/calendars/${calId}/events?${to_params({
+ access_token: token,
+ pageToken,
+ syncToken,
+ maxResults: resultsPerRequest
+ })}`, { method: 'GET', async: true })
+ .then(response => {
+ if (response.status === 200)
+ return response.json();
+ else throw {};
+ })
+ .catch(e => e)
+ .then(data => {
+ if (!data.items)
+ return ({
+ nextSyncToken: '',
+ results: []
+ });
+ results.push(...data.items);
+ if (data.nextPageToken) {
+ return singleFetch(data.nextPageToken, '');
+ } else {
+ return ({
+ nextSyncToken: data.nextSyncToken,
+ results
+ });
+ }
+ })
+
+ return singleFetch('', syncToken);
+}
+
+export class GCalendar {
+ constructor(calId, name) {
+ this.calId = calId;
+ this.name = name;
+ this.token = getAuthToken();
+ this.syncToken = '';
+ this.cache = {};
+ }
+
+ static dateToCacheKey(date) {
+ return Math.floor(date / 8.64e7);
+ }
+
+ getSlot(k) {
+ if (!this.cache[k])
+ this.cache[k] = {};
+ return this.cache[k];
+ }
+
+ static slotStartDate(k) { return new Date(k * 8.64e7); }
+ static slotEndDate(k) { return new Date((k + 1) * 8.64e7); }
+
+ addEvent(e) {
+ let ks = GCalendar.dateToCacheKey(e.start);
+ let ke = GCalendar.dateToCacheKey(new Date(e.end.getTime() - 1));
+ if (ks === ke)
+ this.getSlot(ks)[e.id] = {
+ start: e.start,
+ end: e.end,
+ id: e.id };
+ else
+ {
+ this.getSlot(ks)[e.id] = {
+ start: e.start,
+ end: GCalendar.slotEndDate(ks),
+ id: e.id };
+ this.getSlot(ke)[e.id] = {
+ start: GCalendar.slotStartDate(ke),
+ end: e.end,
+ id: e.id };
+ for (let k = ks + 1; k < ke; k++)
+ this.getSlot(k)[e.id] = {
+ start: GCalendar.slotStartDate(k),
+ end: GCalendar.slotEndDate(k),
+ id: e.id };
+ }
+ }
+
+ removeEvent(e) {
+ let ks = GCalendar.dateToCacheKey(e.start);
+ let ke = GCalendar.dateToCacheKey(new Date(e.end.getTime() - 1));
+ for (let k = ks; k <= ke; k++)
+ delete this.getSlot(k)[e.id];
+ }
+
+ getSlotEvents(k, start, end) {
+ let s = this.getSlot(k);
+ let results = [];
+ for (let id in s) {
+ if (!(s[id].start >= end || s[id].end <= start))
+ {
+ let nstart = s[id].start < start ? start: s[id].start;
+ let nend = s[id].end > end ? end: s[id].end;
+ if (nstart > nend) console.log(s[id], start, end);
+ results.push({
+ id,
+ start: s[id].start < start ? start: s[id].start,
+ end: s[id].end > end ? end: s[id].end
+ });
+ }
+ }
+ return results;
+ }
+
+ getCachedEvents(start, end) {
+ let ks = GCalendar.dateToCacheKey(start);
+ let ke = GCalendar.dateToCacheKey(new Date(end.getTime() - 1));
+ let results = this.getSlotEvents(ks, start, end);
+ for (let k = ks + 1; k < ke; k++)
+ {
+ let s = this.getSlot(k);
+ for (let id in s)
+ results.push(s[id]);
+ }
+ if (ke > ks)
+ results.push(...this.getSlotEvents(ke, start, end));
+ return results;
+ }
+
+ sync() {
+ return this.token.then(token => getEvents(this.calId, token, this.syncToken).then(r => {
+ this.syncToken = r.nextSyncToken;
+ let pm_results = r.results.map(e => e.start ? Promise.resolve(e) : getEvent(this.calId, e.id, token));
+ return Promise.all(pm_results).then(results => results.forEach(e => {
+ e.start = new Date(e.start.dateTime);
+ e.end = new Date(e.end.dateTime);
+ if (e.status === 'confirmed')
+ this.addEvent(e);
+ else if (e.status === 'cancelled')
+ this.removeEvent(e);
+ }));
+ }));
+ }
+
+ getEvents(start, end) {
+ return this.sync().then(() => this.getCachedEvents(start, end));
+ }
+}