Skip to content

Commit ba58ae6

Browse files
authored
Merge pull request #1646 from Northeastern-Electric-Racing/#1522-create-material-type-endpoint
#1522: added create material type endpoint with tests
2 parents 370b8f3 + 9a1e828 commit ba58ae6

5 files changed

Lines changed: 85 additions & 5 deletions

File tree

src/backend/src/controllers/projects.controllers.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,4 +138,15 @@ export default class ProjectsController {
138138
next(error);
139139
}
140140
}
141+
142+
static async createMaterialType(req: Request, res: Response, next: NextFunction) {
143+
try {
144+
const { name } = req.body;
145+
const user = await getCurrentUser(res);
146+
const createdMaterialType = await ProjectsService.createMaterialType(name, user);
147+
res.status(200).json(createdMaterialType);
148+
} catch (error: unknown) {
149+
next(error);
150+
}
151+
}
141152
}

src/backend/src/routes/projects.routes.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,5 +55,6 @@ projectRouter.post(
5555
validateInputs,
5656
ProjectsController.createManufacturer
5757
);
58+
projectRouter.post('/bom/material-type/create', nonEmptyString(body('name')), ProjectsController.createMaterialType);
5859

5960
export default projectRouter;

src/backend/src/services/projects.services.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import { User } from '@prisma/client';
2-
import { isAdmin, isGuest, isProject, LinkCreateArgs, LinkType, Project, WbsNumber, wbsPipe } from 'shared';
1+
import { Material_Type, User } from '@prisma/client';
2+
import { isAdmin, isGuest, isLeadership, isProject, LinkCreateArgs, LinkType, Project, WbsNumber, wbsPipe } from 'shared';
33
import projectQueryArgs from '../prisma-query-args/projects.query-args';
44
import prisma from '../prisma/prisma';
55
import projectTransformer from '../transformers/projects.transformer';
@@ -9,7 +9,8 @@ import {
99
AccessDeniedGuestException,
1010
HttpException,
1111
NotFoundException,
12-
DeletedException
12+
DeletedException,
13+
AccessDeniedException
1314
} from '../utils/errors.utils';
1415
import {
1516
addDescriptionBullets,
@@ -627,4 +628,33 @@ export default class ProjectsService {
627628

628629
return newManufacturer;
629630
}
631+
632+
/**
633+
* Create a new material type
634+
* @param name the name of the new material type
635+
* @param submitter the user who is creating the material type
636+
* @throws if the submitter is not a leader or the material type with the given name already exists
637+
*/
638+
static async createMaterialType(name: string, submitter: User): Promise<Material_Type> {
639+
if (!isLeadership(submitter.role))
640+
throw new AccessDeniedException('Only leadership or above can create a material type');
641+
642+
const materialType = await prisma.material_Type.findUnique({
643+
where: {
644+
name
645+
}
646+
});
647+
648+
if (!!materialType) throw new HttpException(400, `The following material type already exists: ${name}`);
649+
650+
const newMaterialType = await prisma.material_Type.create({
651+
data: {
652+
name,
653+
dateCreated: new Date(),
654+
creatorId: submitter.userId
655+
}
656+
});
657+
658+
return newMaterialType;
659+
}
630660
}

src/backend/tests/projects.test.ts

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,15 @@ import prisma from '../src/prisma/prisma';
22
import { getHighestProjectNumber } from '../src/utils/projects.utils';
33
import * as changeRequestUtils from '../src/utils/change-requests.utils';
44
import { aquaman, batman, wonderwoman } from './test-data/users.test-data';
5-
import { prismaManufacturer1, prismaProject1, sharedProject1 } from './test-data/projects.test-data';
5+
import { prismaManufacturer1, prismaProject1, sharedProject1, toolMaterial } from './test-data/projects.test-data';
66
import { prismaChangeRequest1 } from './test-data/change-requests.test-data';
77
import { prismaTeam1 } from './test-data/teams.test-data';
88
import * as projectTransformer from '../src/transformers/projects.transformer';
99
import ProjectsService from '../src/services/projects.services';
1010
import {
1111
AccessDeniedAdminOnlyException,
1212
AccessDeniedGuestException,
13+
AccessDeniedException,
1314
DeletedException,
1415
HttpException,
1516
NotFoundException
@@ -281,4 +282,29 @@ describe('Projects', () => {
281282
expect(manufacturer.creatorId).toBe(prismaManufacturer1.creatorId);
282283
});
283284
});
285+
286+
describe('materialType', () => {
287+
test('Create material type fails if user is not leader', async () => {
288+
await expect(ProjectsService.createMaterialType('Tools', wonderwoman)).rejects.toThrow(
289+
new AccessDeniedException('Only leadership or above can create a material type')
290+
);
291+
});
292+
293+
test('Create material type fails if the material type with the given name already exists', async () => {
294+
vi.spyOn(prisma.material_Type, 'findUnique').mockResolvedValue(toolMaterial);
295+
296+
await expect(ProjectsService.createMaterialType('NERSoftwareTools', batman)).rejects.toThrow(
297+
new HttpException(400, 'The following material type already exists: NERSoftwareTools')
298+
);
299+
});
300+
301+
test('Create material type works', async () => {
302+
vi.spyOn(prisma.material_Type, 'findUnique').mockResolvedValue(null);
303+
vi.spyOn(prisma.material_Type, 'create').mockResolvedValue(toolMaterial);
304+
305+
const materialType = await ProjectsService.createMaterialType('NERSoftwareTools', batman);
306+
expect(materialType.name).toBe('NERSoftwareTools');
307+
expect(prisma.material_Type.create).toBeCalledTimes(1);
308+
});
309+
});
284310
});

src/backend/tests/test-data/projects.test-data.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
import { Prisma, WBS_Element_Status as PrismaWBSElementStatus, Project, Manufacturer } from '@prisma/client';
1+
import {
2+
Material_Type as PrismaMaterialType,
3+
Prisma,
4+
WBS_Element_Status as PrismaWBSElementStatus,
5+
Project,
6+
Manufacturer
7+
} from '@prisma/client';
28
import { Project as SharedProject, WbsElementStatus } from 'shared';
39
import projectQueryArgs from '../../src/prisma-query-args/projects.query-args';
410
import { prismaTeam1 } from './teams.test-data';
@@ -103,3 +109,9 @@ export const prismaManufacturer1: Manufacturer = {
103109
dateCreated: new Date('10-1-2023'),
104110
creatorId: 1
105111
};
112+
113+
export const toolMaterial: PrismaMaterialType = {
114+
name: 'NERSoftwareTools',
115+
dateCreated: new Date(),
116+
creatorId: batman.userId
117+
};

0 commit comments

Comments
 (0)