Skip to content

Commit

Permalink
Merge pull request #2613 from Northeastern-Electric-Racing/Feature-Ve…
Browse files Browse the repository at this point in the history
…rification

Feature verification
  • Loading branch information
Peyton-McKee authored May 27, 2024
2 parents caf2537 + d0da23f commit d70bb5e
Show file tree
Hide file tree
Showing 73 changed files with 2,011 additions and 596 deletions.
2 changes: 2 additions & 0 deletions src/backend/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import reimbursementRequestsRouter from './src/routes/reimbursement-requests.rou
import notificationsRouter from './src/routes/notifications.routes';
import designReviewsRouter from './src/routes/design-reviews.routes';
import workPackageTemplatesRouter from './src/routes/work-package-templates.routes';
import carsRouter from './src/routes/cars.routes';

const app = express();
const port = process.env.PORT || 3001;
Expand Down Expand Up @@ -58,6 +59,7 @@ app.use('/reimbursement-requests', reimbursementRequestsRouter);
app.use('/design-reviews', designReviewsRouter);
app.use('/notifications', notificationsRouter);
app.use('/templates', workPackageTemplatesRouter);
app.use('/cars', carsRouter);
app.use('/', (_req, res) => {
res.json('Welcome to FinishLine');
});
Expand Down
31 changes: 31 additions & 0 deletions src/backend/src/controllers/cars.controllers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { NextFunction, Request, Response } from 'express';
import CarsService from '../services/car.services';
import { getCurrentUser } from '../utils/auth.utils';
import { getOrganizationId } from '../utils/utils';

export default class CarsController {
static async getAllCars(req: Request, res: Response, next: NextFunction) {
try {
const organizationId = getOrganizationId(req.headers);
await getCurrentUser(res);
const cars = await CarsService.getAllCars(organizationId);

res.status(200).json(cars);
} catch (error: unknown) {
next(error);
}
}

static async createCar(req: Request, res: Response, next: NextFunction) {
try {
const organizationId = getOrganizationId(req.headers);
const user = await getCurrentUser(res);
const { name } = req.body;
const car = await CarsService.createCar(organizationId, user, name);

res.status(201).json(car);
} catch (error: unknown) {
next(error);
}
}
}
5 changes: 2 additions & 3 deletions src/backend/src/controllers/projects.controllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -428,13 +428,12 @@ export default class ProjectsController {

static async editLinkType(req: Request, res: Response, next: NextFunction) {
try {
const { linkId } = req.params;
const { iconName, required, linkTypeName } = req.body;
const { linkTypeName } = req.params;
const { iconName, required } = req.body;
const submitter = await getCurrentUser(res);
const organizationId = getOrganizationId(req.headers);

const linkTypeUpdated = await ProjectsService.editLinkType(
linkId,
linkTypeName,
iconName,
required,
Expand Down
2 changes: 1 addition & 1 deletion src/backend/src/controllers/users.controllers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { getOrganizationId } from '../utils/utils';
export default class UsersController {
static async getAllUsers(req: Request, res: Response, next: NextFunction) {
try {
const { organizationId } = req.headers as { organizationId?: string };
const organizationId = getOrganizationId(req.headers);

const users = await UsersService.getAllUsers(organizationId);

Expand Down
27 changes: 27 additions & 0 deletions src/backend/src/prisma-query-args/cars.query-args.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Prisma } from '@prisma/client';
import { getAssemblyQueryArgs, getMaterialQueryArgs } from './bom.query-args';
import { getDescriptionBulletQueryArgs } from './description-bullets.query-args';
import { getLinkQueryArgs } from './links.query-args';
import { getUserQueryArgs } from './user.query-args';

export type CarQueryArgs = ReturnType<typeof getCarQueryArgs>;

export const getCarQueryArgs = (organizationId: string) =>
Prisma.validator<Prisma.CarDefaultArgs>()({
include: {
wbsElement: {
include: {
lead: getUserQueryArgs(organizationId),
descriptionBullets: getDescriptionBulletQueryArgs(organizationId),
manager: getUserQueryArgs(organizationId),
links: getLinkQueryArgs(organizationId),
changes: {
where: { changeRequest: { dateDeleted: null } },
include: { implementer: getUserQueryArgs(organizationId) }
},
materials: getMaterialQueryArgs(organizationId),
assemblies: getAssemblyQueryArgs(organizationId)
}
}
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ export const getChangeRequestQueryArgs = (organizationId: string) =>
teams: true
}
},
descriptionBullets: true,
links: true
descriptionBullets: { where: { dateDeleted: null } },
links: { where: { dateDeleted: null } }
}
},
reviewer: getUserQueryArgs(organizationId),
Expand Down
18 changes: 12 additions & 6 deletions src/backend/src/prisma-query-args/projects.query-args.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ export const getProjectQueryArgs = (organizationId: string) =>
include: {
lead: getUserQueryArgs(organizationId),
manager: getUserQueryArgs(organizationId),
descriptionBullets: getDescriptionBulletQueryArgs(organizationId),
descriptionBullets: { where: { dateDeleted: null }, ...getDescriptionBulletQueryArgs(organizationId) },
tasks: { where: { dateDeleted: null }, ...getTaskQueryArgs(organizationId) },
links: getLinkQueryArgs(organizationId),
links: { where: { dateDeleted: null }, ...getLinkQueryArgs(organizationId) },
changes: {
where: { changeRequest: { dateDeleted: null } },
include: { implementer: getUserQueryArgs(organizationId) }
Expand All @@ -43,15 +43,21 @@ export const getProjectQueryArgs = (organizationId: string) =>
wbsElement: {
include: {
lead: getUserQueryArgs(organizationId),
descriptionBullets: getDescriptionBulletQueryArgs(organizationId),
descriptionBullets: { where: { dateDeleted: null }, ...getDescriptionBulletQueryArgs(organizationId) },
manager: getUserQueryArgs(organizationId),
links: getLinkQueryArgs(organizationId),
links: { where: { dateDeleted: null }, ...getLinkQueryArgs(organizationId) },
changes: {
where: { changeRequest: { dateDeleted: null } },
include: { implementer: getUserQueryArgs(organizationId) }
},
materials: getMaterialQueryArgs(organizationId),
assemblies: getAssemblyQueryArgs(organizationId)
materials: {
where: { dateDeleted: null },
...getMaterialQueryArgs(organizationId)
},
assemblies: {
where: { dateDeleted: null },
...getAssemblyQueryArgs(organizationId)
}
}
},
blockedBy: { where: { dateDeleted: null } }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { getTeamQueryArgs } from './teams.query-args';

export type ProjectProposedChangesQueryArgs = ReturnType<typeof getProjectProposedChangesQueryArgs>;

export type WorkPackageProposedChangesQueryArgs = typeof workPackageProposedChangesQueryArgs;
export type WorkPackageProposedChangesQueryArgs = ReturnType<typeof getWorkPackageProposedChangesQueryArgs>;

export type WbsProposedChangeQueryArgs = ReturnType<typeof getWbsProposedChangeQueryArgs>;

Expand All @@ -17,6 +17,7 @@ const getProjectProposedChangesQueryArgs = (organizationId: string) =>
Prisma.validator<Prisma.Project_Proposed_ChangesDefaultArgs>()({
include: {
teams: getTeamQueryArgs(organizationId),
workPackageProposedChanges: getWorkPackageProposedChangesQueryArgs(organizationId),
car: {
include: {
wbsElement: true
Expand All @@ -25,17 +26,26 @@ const getProjectProposedChangesQueryArgs = (organizationId: string) =>
}
});

export const workPackageProposedChangesQueryArgs = Prisma.validator<Prisma.Work_Package_Proposed_ChangesDefaultArgs>()({
include: {
blockedBy: true
}
});
export const getWorkPackageProposedChangesQueryArgs = (organizationId: string) =>
Prisma.validator<Prisma.Work_Package_Proposed_ChangesDefaultArgs>()({
include: {
blockedBy: true,
wbsProposedChanges: {
include: {
links: getLinkQueryArgs(organizationId),
lead: getUserQueryArgs(organizationId),
manager: getUserQueryArgs(organizationId),
proposedDescriptionBulletChanges: getDescriptionBulletQueryArgs(organizationId)
}
}
}
});

export const getWbsProposedChangeQueryArgs = (organizationId: string) =>
Prisma.validator<Prisma.Wbs_Proposed_ChangesDefaultArgs>()({
include: {
projectProposedChanges: getProjectProposedChangesQueryArgs(organizationId),
workPackageProposedChanges: workPackageProposedChangesQueryArgs,
workPackageProposedChanges: getWorkPackageProposedChangesQueryArgs(organizationId),
links: getLinkQueryArgs(organizationId),
lead: getUserQueryArgs(organizationId),
manager: getUserQueryArgs(organizationId),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
-- AlterTable
ALTER TABLE "Work_Package_Proposed_Changes" ADD COLUMN "projectProposedChangesId" TEXT;

-- AddForeignKey
ALTER TABLE "Work_Package_Proposed_Changes" ADD CONSTRAINT "Work_Package_Proposed_Changes_projectProposedChangesId_fkey" FOREIGN KEY ("projectProposedChangesId") REFERENCES "Project_Proposed_Changes"("projectProposedChangesId") ON DELETE SET NULL ON UPDATE CASCADE;
18 changes: 11 additions & 7 deletions src/backend/src/prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -780,18 +780,22 @@ model Project_Proposed_Changes {
teams Team[] @relation(name: "proposedProjectTeams")
wbsProposedChanges Wbs_Proposed_Changes @relation(name: "projectProposedChanges", fields: [wbsProposedChangesId], references: [wbsProposedChangesId])
wbsProposedChangesId String @unique
carId String?
car Car? @relation(fields: [carId], references: [carId])
workPackageProposedChanges Work_Package_Proposed_Changes[]
carId String?
car Car? @relation(fields: [carId], references: [carId])
}

model Work_Package_Proposed_Changes {
workPackageProposedChangesId String @id @default(uuid())
startDate DateTime @db.Date
workPackageProposedChangesId String @id @default(uuid())
startDate DateTime @db.Date
duration Int
blockedBy WBS_Element[] @relation(name: "proposedBlockedBy")
blockedBy WBS_Element[] @relation(name: "proposedBlockedBy")
stage Work_Package_Stage?
wbsProposedChanges Wbs_Proposed_Changes @relation(name: "wpProposedChanges", fields: [wbsProposedChangesId], references: [wbsProposedChangesId])
wbsProposedChangesId String @unique
wbsProposedChanges Wbs_Proposed_Changes @relation(name: "wpProposedChanges", fields: [wbsProposedChangesId], references: [wbsProposedChangesId])
wbsProposedChangesId String @unique
projectProposedChanges Project_Proposed_Changes? @relation(fields: [projectProposedChangesId], references: [projectProposedChangesId])
projectProposedChangesId String?
}

model Work_Package_Template {
Expand Down
12 changes: 4 additions & 8 deletions src/backend/src/prisma/seed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,6 @@ const performSeed: () => Promise<void> = async () => {
include: { userSettings: true, userSecureSettings: true }
});

const regina = await prisma.user.create({
data: dbSeedAllUsers.regina,
include: { userSettings: true, userSecureSettings: true }
});

const ner = await prisma.organization.create({
data: {
name: 'NER',
Expand Down Expand Up @@ -180,6 +175,7 @@ const performSeed: () => Promise<void> = async () => {
const norbury = await createUser(dbSeedAllUsers.norbury, RoleEnum.LEADERSHIP, organizationId);
const carr = await createUser(dbSeedAllUsers.carr, RoleEnum.LEADERSHIP, organizationId);
const trang = await createUser(dbSeedAllUsers.trang, RoleEnum.LEADERSHIP, organizationId);
const regina = await createUser(dbSeedAllUsers.regina, RoleEnum.LEADERSHIP, organizationId);

await UsersService.updateUserRole(cyborg.userId, thomasEmrax, 'APP_ADMIN', organizationId);

Expand Down Expand Up @@ -403,11 +399,11 @@ const performSeed: () => Promise<void> = async () => {
);

/** Link Types */
const confluenceLinkType = await ProjectsService.createLinkType(batman, 'Confluence', 'doc', true, organizationId);
const confluenceLinkType = await ProjectsService.createLinkType(batman, 'Confluence', 'description', true, organizationId);

const bomLinkType = await ProjectsService.createLinkType(batman, 'Bill of Materials', 'doc', true, organizationId);
const bomLinkType = await ProjectsService.createLinkType(batman, 'Bill of Materials', 'bar_chart', true, organizationId);

await ProjectsService.createLinkType(batman, 'Google Drive', 'doc', true, organizationId);
await ProjectsService.createLinkType(batman, 'Google Drive', 'folder', true, organizationId);

/**
* Projects
Expand Down
10 changes: 10 additions & 0 deletions src/backend/src/routes/cars.routes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import express from 'express';
import CarsController from '../controllers/cars.controllers';

const carsRouter = express.Router();

carsRouter.get('/', CarsController.getAllCars);

carsRouter.post('/create', CarsController.createCar);

export default carsRouter;
2 changes: 1 addition & 1 deletion src/backend/src/routes/change-requests.routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ changeRequestsRouter.post(
body('proposedSolutions.*.timelineImpact').isInt(),
body('proposedSolutions.*.budgetImpact').isInt(),
...projectProposedChangesValidators,
...workPackageProposedChangesValidators,
...workPackageProposedChangesValidators('workPackageProposedChanges'),
validateInputs,
ChangeRequestsController.createStandardChangeRequest
);
Expand Down
66 changes: 66 additions & 0 deletions src/backend/src/services/car.services.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { User } from '@prisma/client';
import { isAdmin } from 'shared';
import { getCarQueryArgs } from '../prisma-query-args/cars.query-args';
import prisma from '../prisma/prisma';
import { carTransformer } from '../transformers/cars.transformer';
import { AccessDeniedAdminOnlyException, NotFoundException } from '../utils/errors.utils';
import { userHasPermission } from '../utils/users.utils';

export default class CarsService {
static async getAllCars(organizationId: string) {
const cars = await prisma.car.findMany({
where: {
wbsElement: {
organizationId
}
},
...getCarQueryArgs(organizationId)
});

return cars.map(carTransformer);
}

static async createCar(organizationId: string, user: User, name: string) {
if (!(await userHasPermission(user.userId, organizationId, isAdmin)))
throw new AccessDeniedAdminOnlyException('create a car');

const organization = await prisma.organization.findUnique({
where: {
organizationId
}
});

if (!organization) {
throw new NotFoundException('Organization', organizationId);
}

const numExistingCars = await prisma.car.count({
where: {
wbsElement: {
organizationId
}
}
});

const car = await prisma.car.create({
data: {
wbsElement: {
create: {
name,
carNumber: numExistingCars,
projectNumber: 0,
workPackageNumber: 0,
organization: {
connect: {
organizationId
}
}
}
}
},
...getCarQueryArgs(organizationId)
});

return carTransformer(car);
}
}
Loading

0 comments on commit d70bb5e

Please sign in to comment.