Skip to content

Commit 556347e

Browse files
authored
Merge pull request #1684 from Northeastern-Electric-Racing/#1524-Delete-Material-Type-Endpoint
1524 Created the delete materials type endpoint and tested it
2 parents 155fb7a + c1fbae9 commit 556347e

7 files changed

Lines changed: 92 additions & 4 deletions

File tree

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,16 @@ export default class ProjectsController {
213213
next(error);
214214
}
215215
}
216+
static async deleteMaterialType(req: Request, res: Response, next: NextFunction) {
217+
try {
218+
const { materialTypeId } = req.params;
219+
const user = await getCurrentUser(res);
220+
const deletedMaterial = await ProjectsService.deleteMaterialType(materialTypeId, user);
221+
res.status(200).json(deletedMaterial);
222+
} catch (error: unknown) {
223+
next(error);
224+
}
225+
}
216226

217227
static async editMaterial(req: Request, res: Response, next: NextFunction) {
218228
try {

src/backend/src/prisma/migrations/20231119042617_add_bom/migration.sql renamed to src/backend/src/prisma/migrations/20231119054311_add_bom/migration.sql

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ CREATE TABLE "Material" (
5151
CREATE TABLE "Material_Type" (
5252
"name" TEXT NOT NULL,
5353
"dateCreated" TIMESTAMP(3) NOT NULL,
54+
"dateDeleted" TIMESTAMP(3),
5455
"creatorId" INTEGER NOT NULL,
5556

5657
CONSTRAINT "Material_Type_pkey" PRIMARY KEY ("name")

src/backend/src/prisma/schema.prisma

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,6 +519,7 @@ model Material {
519519
model Material_Type {
520520
name String @id
521521
dateCreated DateTime
522+
dateDeleted DateTime?
522523
creatorId Int
523524
materials Material[]
524525
}

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,4 +101,6 @@ projectRouter.post(
101101
ProjectsController.editMaterial
102102
);
103103

104+
projectRouter.delete('/bom/material-type/:materialTypeId/delete', ProjectsController.deleteMaterialType);
105+
104106
export default projectRouter;

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

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,16 @@
1+
import {
2+
isAdmin,
3+
isGuest,
4+
isHead,
5+
isLeadership,
6+
isProject,
7+
LinkCreateArgs,
8+
LinkType,
9+
Project,
10+
WbsNumber,
11+
wbsPipe
12+
} from 'shared';
113
import { Manufacturer, Role, Material_Type, User, Assembly, Material_Status, Material } from '@prisma/client';
2-
import { isAdmin, isGuest, isLeadership, isProject, LinkCreateArgs, LinkType, Project, WbsNumber, wbsPipe } from 'shared';
314
import projectQueryArgs from '../prisma-query-args/projects.query-args';
415
import prisma from '../prisma/prisma';
516
import projectTransformer from '../transformers/projects.transformer';
@@ -832,6 +843,38 @@ export default class ProjectsService {
832843
return newMaterialType;
833844
}
834845

846+
/**
847+
* Deletes a material type based on the given Id
848+
* @param submitter the user who is deleting the material type
849+
* @param materialTypeId the Id of the material type being deleted
850+
* @throws if the submitter is not an admin/head or if the material type is not found
851+
* @returns the deleted material type
852+
*/
853+
static async deleteMaterialType(materialTypeId: string, submitter: User): Promise<Material_Type> {
854+
if (!isHead(submitter.role) && !isAdmin(submitter.role)) {
855+
throw new AccessDeniedException('Only an admin or head can delete a material type');
856+
}
857+
const materialType = await prisma.material_Type.findUnique({
858+
where: {
859+
name: materialTypeId
860+
}
861+
});
862+
863+
if (!materialType) throw new NotFoundException('Material Type', materialTypeId);
864+
if (materialType.dateDeleted) throw new DeletedException('Material Type', materialTypeId);
865+
866+
const deletedMaterialType = await prisma.material_Type.update({
867+
where: {
868+
name: materialTypeId
869+
},
870+
data: {
871+
dateDeleted: new Date()
872+
}
873+
});
874+
875+
return deletedMaterialType;
876+
}
877+
835878
/**
836879
* Update a material
837880
* @param submitter the submitter of the request

src/backend/tests/projects.test.ts

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import prisma from '../src/prisma/prisma';
22
import { getHighestProjectNumber } from '../src/utils/projects.utils';
33
import * as changeRequestUtils from '../src/utils/change-requests.utils';
4-
import { aquaman, batman, superman, theVisitor, wonderwoman } from './test-data/users.test-data';
4+
import { aquaman, batman, wonderwoman, superman, theVisitor } from './test-data/users.test-data';
55
import {
66
prismaProject1,
77
sharedProject1,
@@ -685,6 +685,35 @@ describe('Projects', () => {
685685
});
686686
});
687687

688+
describe('Deleting material type', () => {
689+
test('Delete Material Type does not work if user is not an admin or head', async () => {
690+
await expect(ProjectsService.deleteMaterialType('NERSoftwareTools', theVisitor)).rejects.toThrow(
691+
new AccessDeniedException('Only an admin or head can delete a material type')
692+
);
693+
});
694+
695+
test('Delete Material Type does not work if material type does not exist', async () => {
696+
await expect(ProjectsService.deleteMaterialType('NERSoftwareTools', batman)).rejects.toThrow(
697+
new NotFoundException('Material Type', 'NERSoftwareTools')
698+
);
699+
});
700+
701+
test('Deleted Material Tye does not work if the material type is already deleted', async () => {
702+
vi.spyOn(prisma.material_Type, 'findUnique').mockResolvedValue({ ...toolMaterial, dateDeleted: new Date() });
703+
await expect(ProjectsService.deleteMaterialType('NERSoftwareTools', batman)).rejects.toThrow(
704+
new DeletedException('Material Type', 'NERSoftwareTools')
705+
);
706+
});
707+
708+
test('Delete Material Type works', async () => {
709+
vi.spyOn(prisma.material_Type, 'findUnique').mockResolvedValue(toolMaterial);
710+
vi.spyOn(prisma.material_Type, 'update').mockResolvedValue({ ...toolMaterial, dateDeleted: new Date() });
711+
const deletedMaterialType = await ProjectsService.deleteMaterialType('NERSoftwareTools', superman);
712+
expect(deletedMaterialType.name).toBe('NERSoftwareTools');
713+
expect(prisma.material_Type.update).toBeCalledTimes(1);
714+
});
715+
});
716+
688717
describe('updateMaterial', () => {
689718
test('Update material fails if the given material does not exists', async () => {
690719
vi.spyOn(prisma.material, 'findUnique').mockResolvedValue(null);

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

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,8 @@ export const prismaAssembly1: Assembly = {
121121
export const prismaMaterialType: PrismaMaterialType = {
122122
name: 'name',
123123
dateCreated: new Date('10-18-2023'),
124-
creatorId: 1
124+
creatorId: 1,
125+
dateDeleted: null
125126
};
126127

127128
export const prismaUnit: Unit = {
@@ -164,7 +165,8 @@ export const prismaManufacturer2: Manufacturer = {
164165
export const toolMaterial: PrismaMaterialType = {
165166
name: 'NERSoftwareTools',
166167
dateCreated: new Date(),
167-
creatorId: batman.userId
168+
creatorId: batman.userId,
169+
dateDeleted: null
168170
};
169171

170172
export const prismaMaterial2: Material = {

0 commit comments

Comments
 (0)