diff --git a/src/backend/src/controllers/description-bullets.controllers.ts b/src/backend/src/controllers/description-bullets.controllers.ts index ff46ab75f0..d0a0689a2f 100644 --- a/src/backend/src/controllers/description-bullets.controllers.ts +++ b/src/backend/src/controllers/description-bullets.controllers.ts @@ -1,64 +1,16 @@ -import { WBS_Element_Status } from '@prisma/client'; -import { Request, Response } from 'express'; -import prisma from '../prisma/prisma'; -import { hasBulletCheckingPermissions } from '../utils/description-bullets.utils'; - -export const checkDescriptionBullet = async (req: Request, res: Response) => { - const { body } = req; - const { userId, descriptionId } = body; - - const originalDB = await prisma.description_Bullet.findUnique({ - where: { descriptionId }, - include: { - workPackageDeliverables: { include: { wbsElement: true } }, - workPackageExpectedActivities: { include: { wbsElement: true } } +import { NextFunction, Request, Response } from 'express'; +import DescriptionBulletsService from '../services/description-bullets.services'; +import { getCurrentUser } from '../utils/utils'; + +export default class DescriptionBulletsController { + static async checkDescriptionBullet(req: Request, res: Response, next: NextFunction) { + try { + const { descriptionId } = req.body; + const user = await getCurrentUser(res); + const updatedDB = await DescriptionBulletsService.checkDescriptionBullet(user, descriptionId); + res.status(200).json(updatedDB); + } catch (error: unknown) { + next(error); } - }); - - if (!originalDB) { - return res.status(404).json({ message: `Description Bullet with id ${descriptionId} not found` }); - } - - if (originalDB.dateDeleted) { - return res.status(400).json({ message: 'Cant edit a deleted Description Bullet' }); - } - - const workPackage = originalDB.workPackageDeliverables || originalDB.workPackageExpectedActivities; - if (!workPackage) { - return res.status(400).json({ - message: 'This description bullet is not tied to a workpackage deliverable or expected activity!' - }); - } - - if (workPackage.wbsElement.status !== WBS_Element_Status.ACTIVE) { - return res.status(400).json({ message: 'Cannot check a description bullet on an inactive work package!' }); - } - - const hasPerms = await hasBulletCheckingPermissions(userId, descriptionId); - - if (!hasPerms) { - return res.status(403).json({ message: 'Access Denied' }); } - - let updatedDB; - - if (originalDB.userCheckedId) { - updatedDB = await prisma.description_Bullet.update({ - where: { descriptionId }, - data: { - userCheckedId: null, - dateTimeChecked: null - } - }); - } else { - updatedDB = await prisma.description_Bullet.update({ - where: { descriptionId }, - data: { - userCheckedId: userId, - dateTimeChecked: new Date() - } - }); - } - - return res.status(200).json(updatedDB); -}; +} diff --git a/src/backend/src/prisma-query-args/description-bullets.query-args.ts b/src/backend/src/prisma-query-args/description-bullets.query-args.ts new file mode 100644 index 0000000000..baae61399e --- /dev/null +++ b/src/backend/src/prisma-query-args/description-bullets.query-args.ts @@ -0,0 +1,7 @@ +import { Prisma } from '@prisma/client'; + +const descriptionBulletQueryArgs = Prisma.validator()({ + include: { userChecked: true } +}); + +export default descriptionBulletQueryArgs; diff --git a/src/backend/src/prisma-query-args/work-packages.query-args.ts b/src/backend/src/prisma-query-args/work-packages.query-args.ts index 16fcd79141..0e20975fb2 100644 --- a/src/backend/src/prisma-query-args/work-packages.query-args.ts +++ b/src/backend/src/prisma-query-args/work-packages.query-args.ts @@ -1,5 +1,5 @@ import { Prisma } from '@prisma/client'; -import { descBulletArgs } from '../utils/description-bullets.utils'; +import descriptionBulletQueryArgs from '../prisma-query-args/description-bullets.query-args'; const workPackageQueryArgs = Prisma.validator()({ include: { @@ -15,8 +15,8 @@ const workPackageQueryArgs = Prisma.validator()({ changes: { include: { implementer: true }, orderBy: { dateImplemented: 'asc' } } } }, - expectedActivities: { where: { dateDeleted: null }, ...descBulletArgs }, - deliverables: { where: { dateDeleted: null }, ...descBulletArgs }, + expectedActivities: { where: { dateDeleted: null }, ...descriptionBulletQueryArgs }, + deliverables: { where: { dateDeleted: null }, ...descriptionBulletQueryArgs }, dependencies: { where: { dateDeleted: null } } } }); diff --git a/src/backend/src/routes/description-bullets.routes.ts b/src/backend/src/routes/description-bullets.routes.ts index eb941bd204..ee5117a105 100644 --- a/src/backend/src/routes/description-bullets.routes.ts +++ b/src/backend/src/routes/description-bullets.routes.ts @@ -1,16 +1,15 @@ import express from 'express'; import { body } from 'express-validator'; -import { checkDescriptionBullet } from '../controllers/description-bullets.controllers'; +import DescriptionBulletsController from '../controllers/description-bullets.controllers'; import { validateInputs } from '../utils/utils'; const descriptionBulletsRouter = express.Router(); descriptionBulletsRouter.post( '/check', - body('userId').isInt({ min: 0 }).not().isString(), body('descriptionId').isInt({ min: 0 }).not().isString(), validateInputs, - checkDescriptionBullet + DescriptionBulletsController.checkDescriptionBullet ); export default descriptionBulletsRouter; diff --git a/src/backend/src/services/description-bullets.services.ts b/src/backend/src/services/description-bullets.services.ts new file mode 100644 index 0000000000..b8879c9f97 --- /dev/null +++ b/src/backend/src/services/description-bullets.services.ts @@ -0,0 +1,65 @@ +import { User, WBS_Element_Status } from '@prisma/client'; +import prisma from '../prisma/prisma'; +import { hasBulletCheckingPermissions } from '../utils/description-bullets.utils'; +import { AccessDeniedException, HttpException, NotFoundException } from '../utils/errors.utils'; +import descriptionBulletTransformer from '../transformers/description-bullets.transformer'; +import descriptionBulletQueryArgs from '../prisma-query-args/description-bullets.query-args'; +import { DescriptionBullet } from 'shared'; + +export default class DescriptionBulletsService { + /** + * Checks the description bullet + * @param user user that checks the description bullet + * @param descriptionId description of bullet that is being checked + * @throws if bullet doesn't exist or if the bullet is not linked to anything valid + * @returns a checked description bullet + */ + static async checkDescriptionBullet(user: User, descriptionId: number): Promise { + const originalDB = await prisma.description_Bullet.findUnique({ + where: { descriptionId }, + include: { + workPackageDeliverables: { include: { wbsElement: true } }, + workPackageExpectedActivities: { include: { wbsElement: true } } + } + }); + if (!originalDB) throw new NotFoundException('Description Bullet', descriptionId); + + if (originalDB.dateDeleted) throw new HttpException(400, 'Cant edit a deleted Description Bullet!'); + + const workPackage = originalDB.workPackageDeliverables || originalDB.workPackageExpectedActivities; + + if (!workPackage) + throw new HttpException(400, 'This description bullet is not tied to a workpackage deliverable or expected activity'); + + if (workPackage.wbsElement.status !== WBS_Element_Status.ACTIVE) + throw new HttpException(400, 'Cannot check a description bullet on an inactive work package!'); + + const hasPerms = await hasBulletCheckingPermissions(user.userId, descriptionId); + + if (!hasPerms) throw new AccessDeniedException(); + + let updatedDB; + + if (originalDB.userCheckedId) { + updatedDB = await prisma.description_Bullet.update({ + where: { descriptionId }, + data: { + userCheckedId: null, + dateTimeChecked: null + }, + ...descriptionBulletQueryArgs + }); + } else { + updatedDB = await prisma.description_Bullet.update({ + where: { descriptionId }, + data: { + userCheckedId: user.userId, + dateTimeChecked: new Date() + }, + ...descriptionBulletQueryArgs + }); + } + + return descriptionBulletTransformer(updatedDB); + } +} diff --git a/src/backend/src/transformers/description-bullets.transformer.ts b/src/backend/src/transformers/description-bullets.transformer.ts new file mode 100644 index 0000000000..33ad4391d3 --- /dev/null +++ b/src/backend/src/transformers/description-bullets.transformer.ts @@ -0,0 +1,17 @@ +import { Prisma } from '@prisma/client'; +import { DescriptionBullet } from 'shared'; +import descriptionBulletQueryArgs from '../prisma-query-args/description-bullets.query-args'; + +const descriptionBulletTransformer = ( + descBullet: Prisma.Description_BulletGetPayload +): DescriptionBullet => { + return { + id: descBullet.descriptionId, + detail: descBullet.detail, + dateAdded: descBullet.dateAdded, + dateDeleted: descBullet.dateDeleted ?? undefined, + userChecked: descBullet.userChecked ?? undefined + }; +}; + +export default descriptionBulletTransformer; diff --git a/src/backend/src/transformers/work-packages.transformer.ts b/src/backend/src/transformers/work-packages.transformer.ts index 5e81c06aad..2d66f0039f 100644 --- a/src/backend/src/transformers/work-packages.transformer.ts +++ b/src/backend/src/transformers/work-packages.transformer.ts @@ -1,7 +1,7 @@ import { Prisma } from '@prisma/client'; import { calculateEndDate, calculatePercentExpectedProgress, calculateTimelineStatus, WorkPackage } from 'shared'; import workPackageQueryArgs from '../prisma-query-args/work-packages.query-args'; -import { descBulletTransformer } from '../utils/description-bullets.utils'; +import descriptionBulletTransformer from '../transformers/description-bullets.transformer'; import { userTransformer } from '../utils/users.utils'; import { convertStatus, wbsNumOf } from '../utils/utils'; import { calculateWorkPackageProgress } from '../utils/work-packages.utils'; @@ -18,8 +18,8 @@ const workPackageTransformer = (wpInput: Prisma.Work_PackageGetPayload()({ - include: { userChecked: true } -}); - -export const descBulletTransformer = (descBullet: Prisma.Description_BulletGetPayload) => { - return { - id: descBullet.descriptionId, - detail: descBullet.detail, - dateAdded: descBullet.dateAdded, - dateDeleted: descBullet.dateDeleted ?? undefined, - userChecked: descBullet.userChecked ?? undefined - }; -}; +import { Role } from '@prisma/client'; export const hasBulletCheckingPermissions = async (userId: number, descriptionId: number) => { const user = await prisma.user.findUnique({ where: { userId } });