Skip to content

Commit 5bd5e3c

Browse files
authored
Merge pull request #2186 from Northeastern-Electric-Racing/1998-CaioDaSilva-UserScheduleEndpoint
1998 User Schedule Set Endpoint
2 parents 7bf109a + 6301d5e commit 5bd5e3c

4 files changed

Lines changed: 91 additions & 2 deletions

File tree

src/backend/src/controllers/users.controllers.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,24 @@ export default class UsersController {
146146
}
147147
}
148148

149+
static async setUserScheduleSettings(req: Request, res: Response, next: NextFunction) {
150+
try {
151+
const { personalGmail, personalZoomLink, availability } = req.body;
152+
const user = await getCurrentUser(res);
153+
154+
const updatedScheduleSettings = await UsersService.setUserScheduleSettings(
155+
user,
156+
personalGmail,
157+
personalZoomLink,
158+
availability
159+
);
160+
161+
return res.status(200).json(updatedScheduleSettings);
162+
} catch (error: unknown) {
163+
next(error);
164+
}
165+
}
166+
149167
static async getUserScheduleSettings(req: Request, res: Response, next: NextFunction) {
150168
try {
151169
const userId: number = parseInt(req.params.userId);

src/backend/src/routes/users.routes.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import express from 'express';
33
import { body } from 'express-validator';
44
import UsersController from '../controllers/users.controllers';
55
import { validateInputs } from '../utils/utils';
6-
import { isRole, nonEmptyString } from '../utils/validation.utils';
6+
import { isRole, nonEmptyString, intMinZero } from '../utils/validation.utils';
77

88
const userRouter = express.Router();
99

@@ -32,6 +32,18 @@ userRouter.post(
3232
nonEmptyString(body('phoneNumber')),
3333
UsersController.setUserSecureSettings
3434
);
35+
36+
userRouter.post(
37+
'/schedule-settings/set',
38+
nonEmptyString(body('personalGmail')).isEmail(),
39+
nonEmptyString(body('personalZoomLink')).isURL(),
40+
body('availability').isArray(),
41+
intMinZero(body('availibility.*')),
42+
validateInputs,
43+
UsersController.setUserScheduleSettings
44+
);
45+
3546
userRouter.get('/:userId/secure-settings', UsersController.getUserSecureSettings);
3647
userRouter.get('/:userId/schedule-settings', UsersController.getUserScheduleSettings);
48+
3749
export default userRouter;

src/backend/src/services/users.services.ts

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { User_Settings, User as PrismaUser } from '@prisma/client';
1+
import { User_Settings, User as PrismaUser, Schedule_Settings } from '@prisma/client';
22
import { OAuth2Client } from 'google-auth-library/build/src/auth/oauth2client';
33
import {
44
AuthenticatedUser,
@@ -339,4 +339,43 @@ export default class UsersService {
339339

340340
return userScheduleSettingsTransformer(scheduleSettings);
341341
}
342+
343+
/**
344+
*
345+
* @param user the user to set the schedule settings for
346+
* @param personalGmail the user's personal gmail
347+
* @param personalZoomLink the user's personal zoom link
348+
* @param availability the user's availibility
349+
* @returns the id of the user's schedule settings
350+
*/
351+
static async setUserScheduleSettings(
352+
user: User,
353+
personalGmail: string,
354+
personalZoomLink: string,
355+
availability: number[]
356+
): Promise<Schedule_Settings> {
357+
const existingUser = await prisma.schedule_Settings.findFirst({
358+
where: { personalGmail, userId: { not: user.userId } } // excludes the current user from check
359+
});
360+
361+
if (existingUser) {
362+
throw new HttpException(400, 'Email already in use');
363+
}
364+
365+
const newUserScheduleSettings = await prisma.schedule_Settings.upsert({
366+
where: { userId: user.userId },
367+
update: {
368+
personalGmail,
369+
personalZoomLink,
370+
availability
371+
},
372+
create: {
373+
userId: user.userId,
374+
personalGmail,
375+
personalZoomLink,
376+
availability
377+
}
378+
});
379+
return newUserScheduleSettings;
380+
}
342381
}

src/backend/tests/users.test.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,5 +167,25 @@ describe('Users', () => {
167167
expect(prisma.schedule_Settings.findUnique).toHaveBeenCalledTimes(1);
168168
expect(res).toStrictEqual(batmanUserScheduleSettings);
169169
});
170+
171+
test('setUserScheduleSettings works successfully', async () => {
172+
vi.spyOn(prisma.schedule_Settings, 'findFirst').mockResolvedValue(null);
173+
vi.spyOn(prisma.schedule_Settings, 'upsert').mockResolvedValue(batmanScheduleSettings);
174+
const res = await UsersService.setUserScheduleSettings(batman, 'batman@gmail.com', 'https://zoom.com', [1, 2]);
175+
176+
expect(res).toBe(batmanScheduleSettings);
177+
});
178+
179+
test('setting same email does not work', async () => {
180+
vi.spyOn(prisma.schedule_Settings, 'findFirst').mockResolvedValue(batmanScheduleSettings);
181+
await expect(() =>
182+
UsersService.setUserScheduleSettings(
183+
batmanWithScheduleSettings,
184+
batmanScheduleSettings.personalGmail,
185+
batmanScheduleSettings.personalZoomLink,
186+
batmanScheduleSettings.availability
187+
)
188+
).rejects.toThrow(new HttpException(400, 'Email already in use'));
189+
});
170190
});
171191
});

0 commit comments

Comments
 (0)