Skip to content

Commit 466d7b8

Browse files
wip(api): update future recurring meetings by default
Our API follows the "update this and future events" Google Calendar option by default. However, to do this properly, our API needs to know the original start time of the meeting instance being updated (the start time before the update).
1 parent 5945919 commit 466d7b8

File tree

2 files changed

+58
-18
lines changed

2 files changed

+58
-18
lines changed

lib/api/routes/meetings/update.ts

Lines changed: 55 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { NextApiRequest as Req, NextApiResponse as Res } from 'next';
2+
import { RRule } from 'rrule';
23

34
import { Meeting, MeetingJSON, isMeetingJSON } from 'lib/model';
5+
import createMeetingDoc from 'lib/api/create/meeting-doc';
6+
import createMeetingSearchObj from 'lib/api/create/meeting-search-obj';
7+
import createZoom from 'lib/api/create/zoom';
8+
import getLastTime from 'lib/api/get/last-time';
49
import getOrg from 'lib/api/get/org';
510
import getPeople from 'lib/api/get/people';
611
import getPerson from 'lib/api/get/person';
@@ -31,11 +36,11 @@ export default async function updateMeeting(
3136
Meeting
3237
);
3338

34-
await Promise.all([
39+
const [matchDoc, meetingDoc] = await Promise.all([
3540
verifyDocExists('matches', body.match.id),
36-
verifyDocExists('meetings', body.id),
41+
verifyDocExists('meetings', body.parentId || body.id),
3742
]);
38-
43+
const original = Meeting.fromFirestoreDoc(meetingDoc);
3944
const people = await getPeople(body.match.people);
4045

4146
// TODO: Actually implement availability verification.
@@ -57,20 +62,54 @@ export default async function updateMeeting(
5762
// - Admins can change 'approved' to 'pending' or 'logged'.
5863
// - Meeting people can change 'pending' to 'logged'.
5964

60-
body.venue = await updateZoom(body, people);
61-
62-
// TODO: Should I send a 200 status code *and then* send emails? Would that
63-
// make the front-end feel faster? Or is that a bad development practice?
64-
await Promise.all([
65-
updateMatchDoc(body.match),
66-
updateMatchSearchObj(body.match),
67-
updateMeetingDoc(body),
68-
updateMeetingSearchObj(body),
69-
sendEmails(body, people, updater, org),
70-
updatePeopleRoles(people),
71-
]);
65+
if (original.time.recur) {
66+
// User is updating a recurring meeting. By default, we only update this
67+
// meeting and all future meetings:
68+
// 1. Create a new recurring meeting using this meeting's data.
69+
// 2. Add 'until' to original's recur rule to exclude this meeting.
70+
// 3. Send the created meeting data to the client.
71+
72+
body.id = '';
73+
body.parentId = undefined;
74+
body.venue = await createZoom(body, people);
75+
body.time.last = getLastTime(body.time);
76+
77+
const meeting = await createMeetingDoc(body);
78+
await createMeetingSearchObj(meeting);
79+
80+
// TODO: We need to know the start time of the meeting instance before it
81+
// was updated. Otherwise, we can't properly exclude it from the original.
82+
original.time.recur = RRule.optionsToString({
83+
...RRule.parseString(original.time.recur),
84+
until: body.time.from, // TODO: Replace with time before update.
85+
});
86+
original.time.last = getLastTime(original.time);
87+
88+
await Promise.all([
89+
updateMeetingDoc(original),
90+
updateMeetingSearchObj(original),
91+
sendEmails(meeting, people, updater, org),
92+
updatePeopleRoles(people),
93+
]);
94+
95+
res.status(200).json(meeting.toJSON());
96+
} else {
97+
body.venue = await updateZoom(body, people);
98+
body.time.last = getLastTime(body.time);
99+
100+
// TODO: Should I send a 200 status code *and then* send emails? Would that
101+
// make the front-end feel faster? Or is that a bad development practice?
102+
await Promise.all([
103+
updateMatchDoc(body.match),
104+
updateMatchSearchObj(body.match),
105+
updateMeetingDoc(body),
106+
updateMeetingSearchObj(body),
107+
sendEmails(body, people, updater, org),
108+
updatePeopleRoles(people),
109+
]);
72110

73-
res.status(200).json(body.toJSON());
111+
res.status(200).json(body.toJSON());
112+
}
74113
} catch (e) {
75114
handle(e, res);
76115
}

lib/api/verify/doc-exists.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,13 @@
1+
import { DocumentSnapshot, db } from 'lib/api/firebase';
12
import { APIError } from 'lib/api/error';
2-
import { db } from 'lib/api/firebase';
33

44
export default async function verifyDocExists(
55
...path: string[]
6-
): Promise<void> {
6+
): Promise<DocumentSnapshot> {
77
const doc = await db.doc(path.join('/')).get();
88
if (!doc.exists) {
99
const msg = `Document (${path.join('/')}) does not exist in database`;
1010
throw new APIError(msg, 400);
1111
}
12+
return doc;
1213
}

0 commit comments

Comments
 (0)