Skip to content

Commit 2d657fa

Browse files
authored
Merge pull request #4004 from Northeastern-Electric-Racing/#3935-create-guest-definition
#3935 create guest definition endpoint
2 parents f933a4a + 50d61b5 commit 2d657fa

5 files changed

Lines changed: 121 additions & 16 deletions

File tree

src/backend/src/controllers/recruitment.controllers.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,4 +96,23 @@ export default class RecruitmentController {
9696
next(error);
9797
}
9898
}
99+
100+
static async createGuestDefinition(req: Request, res: Response, next: NextFunction) {
101+
try {
102+
const { term, description, order, icon, buttonText, buttonLink } = req.body;
103+
const definition = await RecruitmentServices.createGuestDefinition(
104+
req.currentUser,
105+
req.organization,
106+
term,
107+
description,
108+
order,
109+
icon,
110+
buttonText,
111+
buttonLink
112+
);
113+
res.status(200).json(definition);
114+
} catch (error: unknown) {
115+
next(error);
116+
}
117+
}
99118
}

src/backend/src/routes/recruitment.routes.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,16 @@ recruitmentRouter.post(
5050

5151
recruitmentRouter.delete('/faq/:faqId/delete', RecruitmentController.deleteFaq);
5252

53+
recruitmentRouter.post(
54+
'/guestDefinition/create',
55+
nonEmptyString(body('term')),
56+
nonEmptyString(body('description')),
57+
body('order').isInt(),
58+
nonEmptyString(body('icon')).optional(),
59+
nonEmptyString(body('buttonText')).optional(),
60+
nonEmptyString(body('buttonLink')).optional(),
61+
validateInputs,
62+
RecruitmentController.createGuestDefinition
63+
);
64+
5365
export default recruitmentRouter;

src/backend/src/services/recruitment.services.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -212,4 +212,45 @@ export default class RecruitmentServices {
212212

213213
return faq;
214214
}
215+
216+
/**
217+
* Creates a guest definition
218+
* @param creator user creating the definition
219+
* @param organization org the definition is being created in
220+
* @param term the term we are defining
221+
* @param description the definition of the term
222+
* @param order the order the term appears on the page
223+
* @param icon the icon associated with the term
224+
* @param buttonText the text displayed on the terms button
225+
* @param buttonLink where the terms button links to
226+
* @returns
227+
*/
228+
static async createGuestDefinition(
229+
creator: User,
230+
organization: Organization,
231+
term: string,
232+
description: string,
233+
order: number,
234+
icon?: string,
235+
buttonText?: string,
236+
buttonLink?: string
237+
) {
238+
if (!(await userHasPermission(creator.userId, organization.organizationId, isAdmin)))
239+
throw new AccessDeniedAdminOnlyException('create a guest definition');
240+
241+
const definition = await prisma.guest_Definition.create({
242+
data: {
243+
term,
244+
description,
245+
order,
246+
userCreatedId: creator.userId,
247+
organizationId: organization.organizationId,
248+
buttonText,
249+
buttonLink,
250+
icon
251+
}
252+
});
253+
254+
return definition;
255+
}
215256
}

src/backend/tests/test-utils.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ export const createTestUser = async (
101101
};
102102

103103
export const resetUsers = async () => {
104+
await prisma.guest_Definition.deleteMany();
104105
await prisma.part_Review_Popup.deleteMany();
105106
await prisma.part_Review_Request.deleteMany();
106107
await prisma.part_Review.deleteMany();

src/backend/tests/unit/recruitment.test.ts

Lines changed: 48 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import prisma from '../../src/prisma/prisma.js';
2-
import { Organization } from '@prisma/client';
2+
import { Organization, User } from '@prisma/client';
33
import RecruitmentServices from '../../src/services/recruitment.services.js';
44
import { AccessDeniedAdminOnlyException, DeletedException, NotFoundException } from '../../src/utils/errors.utils.js';
55
import {
@@ -23,9 +23,11 @@ import {
2323
describe('Recruitment Tests', () => {
2424
let orgId: string;
2525
let organization: Organization;
26+
let superman: User;
2627
beforeEach(async () => {
2728
organization = await createTestOrganization();
2829
orgId = organization.organizationId;
30+
superman = await createTestUser(supermanAdmin, orgId);
2931
});
3032

3133
afterEach(async () => {
@@ -40,12 +42,7 @@ describe('Recruitment Tests', () => {
4042
'answer',
4143
organization
4244
);
43-
const faq2 = await RecruitmentServices.createOrganizationFaq(
44-
await createTestUser(supermanAdmin, orgId),
45-
'question2',
46-
'answer2',
47-
organization
48-
);
45+
const faq2 = await RecruitmentServices.createOrganizationFaq(superman, 'question2', 'answer2', organization);
4946
const result = await RecruitmentServices.getAllOrganizationFaqs(organization);
5047
expect(result).toHaveLength(2);
5148
expect(result[0].question).toEqual(faq1.question);
@@ -172,7 +169,7 @@ describe('Recruitment Tests', () => {
172169
await expect(
173170
async () =>
174171
await RecruitmentServices.editMilestone(
175-
await createTestUser(supermanAdmin, orgId),
172+
superman,
176173
'name',
177174
'description',
178175
new Date('11/12/24'),
@@ -192,7 +189,7 @@ describe('Recruitment Tests', () => {
192189
);
193190

194191
const updatedMilestone = await RecruitmentServices.editMilestone(
195-
await createTestUser(supermanAdmin, orgId),
192+
superman,
196193
'new name',
197194
'new description',
198195
new Date('11/14/24'),
@@ -217,7 +214,7 @@ describe('Recruitment Tests', () => {
217214
);
218215

219216
const milestone2 = await RecruitmentServices.createMilestone(
220-
await createTestUser(supermanAdmin, orgId),
217+
superman,
221218
'name2',
222219
'description2',
223220
new Date('1/1/1'),
@@ -257,7 +254,7 @@ describe('Recruitment Tests', () => {
257254
});
258255

259256
it('Fails if milestone is already deleted', async () => {
260-
const testSuperman = await createTestUser(supermanAdmin, orgId);
257+
const testSuperman = superman;
261258
const testMilestone = await createTestMilestone(testSuperman, orgId);
262259
await RecruitmentServices.deleteMilestone(testSuperman, testMilestone.milestoneId, organization);
263260

@@ -267,7 +264,7 @@ describe('Recruitment Tests', () => {
267264
});
268265

269266
it('Succeeds and deletes milestone', async () => {
270-
const testSuperman = await createTestUser(supermanAdmin, orgId);
267+
const testSuperman = superman;
271268
const testMilestone1 = await createTestMilestone(testSuperman, orgId);
272269

273270
await RecruitmentServices.deleteMilestone(testSuperman, testMilestone1.milestoneId, organization);
@@ -327,10 +324,9 @@ describe('Recruitment Tests', () => {
327324
const testFaq = await createTestFaq(await createTestUser(batmanAppAdmin, orgId), orgId);
328325
await RecruitmentServices.deleteFaq(await createTestUser(flashAdmin, orgId), testFaq.faqId, organization);
329326

330-
await expect(
331-
async () =>
332-
await RecruitmentServices.deleteFaq(await createTestUser(supermanAdmin, orgId), testFaq.faqId, organization)
333-
).rejects.toThrow(new DeletedException('Faq', testFaq.faqId));
327+
await expect(async () => await RecruitmentServices.deleteFaq(superman, testFaq.faqId, organization)).rejects.toThrow(
328+
new DeletedException('Faq', testFaq.faqId)
329+
);
334330
});
335331

336332
it('Succeeds and deletes an FAQ', async () => {
@@ -345,4 +341,40 @@ describe('Recruitment Tests', () => {
345341
expect(deletedTestFaq?.dateDeleted).not.toBe(null);
346342
});
347343
});
344+
describe('Create Guest Definitions', () => {
345+
it('Successful guest definition creation', async () => {
346+
const def = await RecruitmentServices.createGuestDefinition(
347+
superman,
348+
organization,
349+
'test term',
350+
'test description',
351+
2,
352+
'iconname',
353+
'buttonTxt',
354+
'buttonLink'
355+
);
356+
357+
expect(def.term).toBe('test term');
358+
expect(def.description).toBe('test description');
359+
expect(def.order).toBe(2);
360+
expect(def.icon).toBe('iconname');
361+
expect(def.buttonText).toBe('buttonTxt');
362+
expect(def.buttonLink).toBe('buttonLink');
363+
});
364+
it('Fails when non admin tries to create guest definition', async () => {
365+
await expect(
366+
async () =>
367+
await RecruitmentServices.createGuestDefinition(
368+
await createTestUser(member, orgId),
369+
organization,
370+
'test term',
371+
'test description',
372+
2,
373+
'iconname',
374+
'buttonTxt',
375+
'buttonLink'
376+
)
377+
).rejects.toThrow(new AccessDeniedAdminOnlyException('create a guest definition'));
378+
});
379+
});
348380
});

0 commit comments

Comments
 (0)