Skip to content

Commit d27d482

Browse files
committed
✨ feat(sub-calendars): update backend schema and tests
1 parent a5a2164 commit d27d482

File tree

228 files changed

+12696
-14304
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

228 files changed

+12696
-14304
lines changed

packages/backend/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"helmet": "^7.0.0",
1818
"jsonwebtoken": "^9.0.0",
1919
"lodash.mergewith": "^4.6.2",
20+
"lodash.unset": "^4.5.2",
2021
"mongodb": "6.3",
2122
"morgan": "^1.10.0",
2223
"p-limit": "^7.2.0",
Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,3 @@
11
import { mockNodeModules } from "@backend/__tests__/helpers/mock.setup";
22

33
mockNodeModules();
4-
5-
beforeEach(() => jest.clearAllMocks());
6-
7-
afterAll(() => jest.restoreAllMocks());
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import { ObjectId } from "bson";
2+
import { z } from "zod/v4";
3+
import { StringV4Schema, zObjectId } from "@core/types/type.utils";
4+
import { Schema_User } from "@core/types/user.types";
5+
import { UserDriver } from "@backend/__tests__/drivers/user.driver";
6+
import authController from "@backend/auth/controllers/auth.controller";
7+
import { getGcalClient } from "@backend/auth/services/google.auth.service";
8+
import mongoService from "@backend/common/services/mongo.service";
9+
10+
export class AuthDriver {
11+
static async googleSignup(): Promise<Schema_User> {
12+
const { gUser, gRefreshToken } = UserDriver.createGoogleAuthUser();
13+
const response = await authController.signup(gUser, gRefreshToken);
14+
15+
expect(zObjectId.parse(response.cUserId)).toBeInstanceOf(ObjectId);
16+
expect(z.email().parse(response.email)).toBe(gUser.email);
17+
18+
const user = await mongoService.user.findOne({
19+
_id: new ObjectId(response.cUserId),
20+
});
21+
22+
expect(user).not.toBeNull();
23+
expect(user).toBeDefined();
24+
25+
return user!;
26+
}
27+
28+
static async googleLogin(userId: ObjectId): Promise<Schema_User> {
29+
const user = await mongoService.user.findOne({ _id: userId });
30+
31+
expect(user).not.toBeNull();
32+
expect(user).toBeDefined();
33+
34+
const _id = zObjectId.parse(user?._id);
35+
36+
const gRefreshToken = UserDriver.generateGoogleRefreshToken({
37+
sub: StringV4Schema.parse(user?.google.googleId),
38+
email: z.email().parse(user?.email),
39+
});
40+
41+
const gcal = await getGcalClient(_id);
42+
43+
const { cUserId, email } = await authController.login(
44+
user!,
45+
gcal,
46+
gRefreshToken,
47+
);
48+
49+
expect(cUserId).toBe(_id.toString());
50+
expect(z.email().safeParse(email).success).toBe(true);
51+
52+
const authenticatedUser = await mongoService.user.findOne({
53+
_id: new ObjectId(cUserId),
54+
});
55+
56+
expect(user).not.toBeNull();
57+
expect(user).toBeDefined();
58+
59+
return authenticatedUser!;
60+
}
61+
62+
static async signUpGoogleUsers(count: number): Promise<Array<Schema_User>> {
63+
return Promise.all(Array.from({ length: count }, AuthDriver.googleSignup));
64+
}
65+
}
Lines changed: 99 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,101 @@
11
import { ObjectId } from "mongodb";
22
import { faker } from "@faker-js/faker";
3-
import { createMockCalendarListEntry } from "@core/__tests__/helpers/gcal.factory";
4-
import { UserDriver } from "@backend/__tests__/drivers/user.driver";
3+
import {
4+
CompassCalendarSchema,
5+
Schema_Calendar,
6+
} from "@core/types/calendar.types";
7+
import { gSchema$CalendarListEntry } from "@core/types/gcal";
8+
import { StringV4Schema } from "@core/types/type.utils";
9+
import { generateCalendarColorScheme } from "@core/util/color.utils";
10+
import { AuthDriver } from "@backend/__tests__/drivers/auth.driver";
11+
import { CompassGCalCalendarTestState } from "@backend/__tests__/helpers/mock.setup";
12+
import { mockAndCategorizeGcalEvents } from "@backend/__tests__/mocks.gcal/factories/gcal.event.batch";
13+
import { generateGcalId } from "@backend/__tests__/mocks.gcal/factories/gcal.event.factory";
14+
import calendarService from "@backend/calendar/services/calendar.service";
515
import { IS_DEV } from "@backend/common/constants/env.constants";
616
import mongoService from "@backend/common/services/mongo.service";
717

818
export class CalendarDriver {
9-
static async generateV0Data(numUsers = 3) {
10-
const users = await UserDriver.createUsers(numUsers);
11-
12-
const data = users.map((user) => ({
13-
_id: new ObjectId(),
14-
user: user._id.toString(),
15-
google: {
16-
items: Array.from(
17-
{ length: faker.number.int({ min: 1, max: 5 }) },
18-
(_, index) =>
19-
createMockCalendarListEntry({
20-
id: index === 0 ? user.email : faker.string.ulid(),
21-
primary: index === 0,
22-
summaryOverride:
23-
index === 0 ? `${user.firstName} ${user.lastName}` : null,
24-
}),
19+
/**
20+
* Generates a mock Google Calendar calendar entry for a user.
21+
* The calendar is added to the user's mocked google calendars
22+
*/
23+
static createGCalCalendarListEntry(
24+
overrides: Partial<gSchema$CalendarListEntry> = {},
25+
): gSchema$CalendarListEntry {
26+
const { backgroundColor, color } = generateCalendarColorScheme();
27+
28+
const calendar = {
29+
kind: "calendar#calendarListEntry",
30+
id: generateGcalId(),
31+
primary: false,
32+
etag: faker.number.hex({ min: 16, max: 16 }).toString(),
33+
summary: faker.book.title(),
34+
description: faker.lorem.paragraph({ min: 1, max: 3 }),
35+
timeZone: faker.location.timeZone(),
36+
colorId: faker.number.int({ min: 1, max: 24 }).toString(),
37+
backgroundColor,
38+
foregroundColor: color,
39+
selected: true,
40+
accessRole: faker.helpers.arrayElement(["reader", "writer", "owner"]),
41+
defaultReminders: [],
42+
conferenceProperties: {
43+
allowedConferenceSolutionTypes: faker.helpers.arrayElements(
44+
["hangoutsMeet", "eventHangout", "eventNamedHangout"],
45+
{ min: 1, max: 3 },
2546
),
2647
},
27-
}));
48+
...overrides,
49+
};
50+
51+
return calendar;
52+
}
53+
54+
static createCalendarTestState(): Array<
55+
[string, CompassGCalCalendarTestState]
56+
> {
57+
const length = faker.number.int({ min: 2, max: 5 });
58+
59+
return Array.from({ length }, (_, index) => {
60+
const events = Array.from(
61+
{ length },
62+
() => mockAndCategorizeGcalEvents(index % 2 !== 0).gcalEvents.all,
63+
).flat();
64+
65+
const calendar = CalendarDriver.createGCalCalendarListEntry({
66+
primary: index === 0,
67+
});
68+
69+
return [StringV4Schema.parse(calendar.id), { calendar, events }];
70+
});
71+
}
72+
73+
static async generateV0Data(numUsers = 3) {
74+
const users = await AuthDriver.signUpGoogleUsers(numUsers);
75+
76+
const data = await Promise.all(
77+
users.map(async (user) => {
78+
const calendars = await calendarService.getAllByUser(user._id);
79+
80+
return {
81+
_id: new ObjectId(),
82+
user: user._id.toString(),
83+
google: {
84+
items: calendars.map((calendar) =>
85+
CalendarDriver.createGCalCalendarListEntry({
86+
...calendar.metadata,
87+
backgroundColor: calendar.backgroundColor,
88+
foregroundColor: calendar.color,
89+
timeZone: calendar.timezone,
90+
summaryOverride: calendar.primary
91+
? `${user.firstName} ${user.lastName}`
92+
: null,
93+
}),
94+
),
95+
},
96+
};
97+
}),
98+
);
2899

29100
const calendarListCollection = mongoService.db.collection<
30101
(typeof data)[number]
@@ -36,4 +107,13 @@ export class CalendarDriver {
36107

37108
return calendars;
38109
}
110+
111+
static async getRandomUserCalendar(user: ObjectId): Promise<Schema_Calendar> {
112+
const calendars = await calendarService.getAllByUser(user);
113+
114+
const index = faker.number.int({ min: 0, max: calendars.length - 1 });
115+
const calendar = calendars[index];
116+
117+
return CompassCalendarSchema.parse(calendar);
118+
}
39119
}

packages/backend/src/__tests__/drivers/email.driver.ts

Lines changed: 0 additions & 67 deletions
This file was deleted.

packages/backend/src/__tests__/drivers/event.driver.ts

Lines changed: 47 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,34 @@
11
import { ObjectId } from "mongodb";
22
import { z } from "zod/v4";
3-
import Migration from "@scripts/migrations/2025.10.18T20.01.14.migrate-events-to-new-events-collection";
3+
import { faker } from "@faker-js/faker";
44
import { Origin, Priorities } from "@core/constants/core.constants";
5-
import { UserDriver } from "@backend/__tests__/drivers/user.driver";
5+
import {
6+
Schema_Base_Event,
7+
Schema_Instance_Event,
8+
V0EventSchema,
9+
} from "@core/types/event.types";
10+
import { gSchema$Event } from "@core/types/gcal";
11+
import { createRecurrenceSeries } from "@core/util/test/ccal.event.factory";
12+
import { AuthDriver } from "@backend/__tests__/drivers/auth.driver";
613
import { mockGcalEvents } from "@backend/__tests__/mocks.gcal/factories/gcal.event.factory";
714
import { getGcalClient } from "@backend/auth/services/google.auth.service";
815
import calendarService from "@backend/calendar/services/calendar.service";
16+
import gcalService from "@backend/common/services/gcal/gcal.service";
917
import mongoService from "@backend/common/services/mongo.service";
1018

1119
export class EventDriver {
1220
static async generateV0Data(count = 3) {
13-
const users = await UserDriver.createUsers(count);
21+
const users = await AuthDriver.signUpGoogleUsers(count);
1422

1523
const collection = mongoService.db.collection<
16-
z.infer<typeof Migration.OldEventSchema>
24+
z.infer<typeof V0EventSchema>
1725
>(mongoService.event.collectionName);
1826

1927
await Promise.all(
2028
users.map(async (user) =>
2129
calendarService.initializeGoogleCalendars(
2230
user._id,
23-
await getGcalClient(user._id.toString()),
31+
await getGcalClient(user._id),
2432
),
2533
),
2634
);
@@ -29,11 +37,12 @@ export class EventDriver {
2937
const gcalAllDayEvents = mockGcalEvents(true, { count });
3038
const gcalTimedEvents = mockGcalEvents(false, { count });
3139

32-
const somedayEvent = Migration.OldEventSchema.parse({
40+
const somedayEvent = V0EventSchema.parse({
3341
user: user._id.toString(),
3442
title: "Someday Event",
3543
startDate: new Date().toISOString(),
3644
endDate: new Date().toISOString(),
45+
order: faker.number.int({ min: 0, max: 10 }),
3746
isSomeday: true,
3847
isAllDay: false,
3948
origin: Origin.COMPASS,
@@ -64,6 +73,7 @@ export class EventDriver {
6473
title: gcalEvent.summary || "No Title",
6574
startDate: gcalEvent.start?.dateTime ?? gcalEvent.start!.date!,
6675
endDate: gcalEvent.end?.dateTime ?? gcalEvent.end!.date!,
76+
order: faker.number.int({ min: 0, max: 10 }),
6777
isAllDay: !!gcalEvent.start?.date,
6878
isSomeday: false,
6979
origin: Origin.GOOGLE,
@@ -91,7 +101,7 @@ export class EventDriver {
91101
});
92102
}
93103

94-
return Migration.OldEventSchema.parse(event);
104+
return V0EventSchema.parse(event);
95105
}),
96106
];
97107
});
@@ -100,4 +110,34 @@ export class EventDriver {
100110

101111
return events;
102112
}
113+
114+
static async getGCalEvent(
115+
user: ObjectId,
116+
gEventId: string,
117+
gCalendarId: string,
118+
): Promise<gSchema$Event> {
119+
const gcal = await getGcalClient(user);
120+
const gEvent = await gcalService.getEvent(gcal, gEventId, gCalendarId);
121+
122+
return gEvent;
123+
}
124+
125+
static async createSeries(
126+
baseOverrides: Partial<Schema_Base_Event>,
127+
instanceOverrides?: Partial<Schema_Instance_Event>,
128+
instanceCount?: number,
129+
) {
130+
const { base, instances } = createRecurrenceSeries(
131+
baseOverrides,
132+
instanceOverrides,
133+
instanceCount,
134+
);
135+
136+
const meta = await mongoService.event.insertMany([base, ...instances]);
137+
138+
return {
139+
state: { baseEvent: base, instances },
140+
meta,
141+
};
142+
}
103143
}

0 commit comments

Comments
 (0)