diff --git a/backend/src/app.ts b/backend/src/app.ts index 95c5f67..dd8155b 100644 --- a/backend/src/app.ts +++ b/backend/src/app.ts @@ -32,11 +32,7 @@ app.use(Sentry.Handlers.errorHandler()); app.use(async (err: Error, req: Request, res: Response, _: NextFunction) => { if (err instanceof AppError) { - if (err.statusCode === 403) { - logger.warn(err); - } else { - logger.error(err); - } + logger.warn(err); return res.status(err.statusCode).json({ error: err.message }); } diff --git a/backend/src/controllers/QueueController.ts b/backend/src/controllers/QueueController.ts index de489c7..9dbad1b 100644 --- a/backend/src/controllers/QueueController.ts +++ b/backend/src/controllers/QueueController.ts @@ -1,11 +1,12 @@ import { Request, Response } from "express"; -import Queue from "../models/Queue"; - -// import { getIO } from "../libs/socket"; -// import AppError from "../errors/AppError"; +import CreateQueueService from "../services/QueueService/CreateQueueService"; +import DeleteQueueService from "../services/QueueService/DeleteQueueService"; +import ListQueuesService from "../services/QueueService/ListQueuesService"; +import ShowQueueService from "../services/QueueService/ShowQueueService"; +import UpdateQueueService from "../services/QueueService/UpdateQueueService"; export const index = async (req: Request, res: Response): Promise => { - const queues = await Queue.findAll(); + const queues = await ListQueuesService(); return res.status(200).json(queues); }; @@ -13,7 +14,37 @@ export const index = async (req: Request, res: Response): Promise => { export const store = async (req: Request, res: Response): Promise => { const { name, color, greetingMessage } = req.body; - const queue = await Queue.create({ name, color, greetingMessage }); + const queue = await CreateQueueService({ name, color, greetingMessage }); return res.status(200).json(queue); }; + +export const show = async (req: Request, res: Response): Promise => { + const { queueId } = req.params; + + const queue = await ShowQueueService(queueId); + + return res.status(200).json(queue); +}; + +export const update = async ( + req: Request, + res: Response +): Promise => { + const { queueId } = req.params; + + const queue = await UpdateQueueService(queueId, req.body); + + return res.status(201).json(queue); +}; + +export const remove = async ( + req: Request, + res: Response +): Promise => { + const { queueId } = req.params; + + await DeleteQueueService(queueId); + + return res.status(200).send(); +}; diff --git a/backend/src/routes/queueRoutes.ts b/backend/src/routes/queueRoutes.ts index 51e793d..a85f5e3 100644 --- a/backend/src/routes/queueRoutes.ts +++ b/backend/src/routes/queueRoutes.ts @@ -9,4 +9,10 @@ queueRoutes.get("/queue", isAuth, QueueController.index); queueRoutes.post("/queue", isAuth, QueueController.store); +queueRoutes.get("/queue/:queueId", isAuth, QueueController.show); + +queueRoutes.put("/queue/:queueId", isAuth, QueueController.update); + +queueRoutes.delete("/queue/:queueId", isAuth, QueueController.remove); + export default queueRoutes; diff --git a/backend/src/services/QueueService/CreateQueueService.ts b/backend/src/services/QueueService/CreateQueueService.ts new file mode 100644 index 0000000..57881e1 --- /dev/null +++ b/backend/src/services/QueueService/CreateQueueService.ts @@ -0,0 +1,67 @@ +import * as Yup from "yup"; +import AppError from "../../errors/AppError"; +import Queue from "../../models/Queue"; + +interface QueueData { + name: string; + color: string; + greetingMessage?: string; +} + +const CreateQueueService = async (queueData: QueueData): Promise => { + const { color, name } = queueData; + + const queueSchema = Yup.object().shape({ + name: Yup.string() + .min(2, "ERR_QUEUE_INVALID_NAME") + .required("ERR_QUEUE_INVALID_NAME") + .test( + "Check-unique-name", + "ERR_QUEUE_NAME_ALREADY_EXISTS", + async value => { + if (value) { + const queueWithSameName = await Queue.findOne({ + where: { name: value } + }); + + return !queueWithSameName; + } + return false; + } + ), + color: Yup.string() + .required("ERR_QUEUE_INVALID_COLOR") + .test("Check-color", "ERR_QUEUE_INVALID_COLOR", async value => { + if (value) { + const colorTestRegex = /^#[0-9a-f]{3,6}$/i; + return colorTestRegex.test(value); + } + return false; + }) + .test( + "Check-color-exists", + "ERR_QUEUE_COLOR_ALREADY_EXISTS", + async value => { + if (value) { + const queueWithSameColor = await Queue.findOne({ + where: { color: value } + }); + return !queueWithSameColor; + } + return false; + } + ) + }); + + try { + await queueSchema.validate({ color, name }); + } catch (err) { + throw new AppError(err.message); + } + + const queue = await Queue.create(queueData); + + return queue; +}; + +export default CreateQueueService; diff --git a/backend/src/services/QueueService/DeleteQueueService.ts b/backend/src/services/QueueService/DeleteQueueService.ts new file mode 100644 index 0000000..fcf9ef6 --- /dev/null +++ b/backend/src/services/QueueService/DeleteQueueService.ts @@ -0,0 +1,9 @@ +import ShowQueueService from "./ShowQueueService"; + +const DeleteQueueService = async (queueId: number | string): Promise => { + const queue = await ShowQueueService(queueId); + + await queue.destroy(); +}; + +export default DeleteQueueService; diff --git a/backend/src/services/QueueService/ListQueuesService.ts b/backend/src/services/QueueService/ListQueuesService.ts new file mode 100644 index 0000000..9a9a3a1 --- /dev/null +++ b/backend/src/services/QueueService/ListQueuesService.ts @@ -0,0 +1,9 @@ +import Queue from "../../models/Queue"; + +const ListQueuesService = async (): Promise => { + const queues = await Queue.findAll(); + + return queues; +}; + +export default ListQueuesService; diff --git a/backend/src/services/QueueService/ShowQueueService.ts b/backend/src/services/QueueService/ShowQueueService.ts new file mode 100644 index 0000000..16ade45 --- /dev/null +++ b/backend/src/services/QueueService/ShowQueueService.ts @@ -0,0 +1,14 @@ +import AppError from "../../errors/AppError"; +import Queue from "../../models/Queue"; + +const ShowQueueService = async (queueId: number | string): Promise => { + const queue = await Queue.findByPk(queueId); + + if (!queue) { + throw new AppError("ERR_QUEUE_NOT_FOUND"); + } + + return queue; +}; + +export default ShowQueueService; diff --git a/backend/src/services/QueueService/UpdateQueueService.ts b/backend/src/services/QueueService/UpdateQueueService.ts new file mode 100644 index 0000000..8aa2a23 --- /dev/null +++ b/backend/src/services/QueueService/UpdateQueueService.ts @@ -0,0 +1,73 @@ +import { Op } from "sequelize"; +import * as Yup from "yup"; +import AppError from "../../errors/AppError"; +import Queue from "../../models/Queue"; +import ShowQueueService from "./ShowQueueService"; + +interface QueueData { + name?: string; + color?: string; + greetingMessage?: string; +} + +const UpdateQueueService = async ( + queueId: number | string, + queueData: QueueData +): Promise => { + const { color, name } = queueData; + + const queueSchema = Yup.object().shape({ + name: Yup.string() + .min(2, "ERR_QUEUE_INVALID_NAME") + .test( + "Check-unique-name", + "ERR_QUEUE_NAME_ALREADY_EXISTS", + async value => { + if (value) { + const queueWithSameName = await Queue.findOne({ + where: { name: value, id: { [Op.not]: queueId } } + }); + + return !queueWithSameName; + } + return true; + } + ), + color: Yup.string() + .required("ERR_QUEUE_INVALID_COLOR") + .test("Check-color", "ERR_QUEUE_INVALID_COLOR", async value => { + if (value) { + const colorTestRegex = /^#[0-9a-f]{3,6}$/i; + return colorTestRegex.test(value); + } + return true; + }) + .test( + "Check-color-exists", + "ERR_QUEUE_COLOR_ALREADY_EXISTS", + async value => { + if (value) { + const queueWithSameColor = await Queue.findOne({ + where: { color: value, id: { [Op.not]: queueId } } + }); + return !queueWithSameColor; + } + return true; + } + ) + }); + + try { + await queueSchema.validate({ color, name }); + } catch (err) { + throw new AppError(err.message); + } + + const queue = await ShowQueueService(queueId); + + await queue.update(queueData); + + return queue; +}; + +export default UpdateQueueService;