From 4d02572d0c929d36be337c2178081654387cdaf8 Mon Sep 17 00:00:00 2001 From: Filip Rojek Date: Sun, 12 May 2024 12:05:56 +0200 Subject: [PATCH] Added: API review --- api/src/controllers/reviewController.ts | 52 +++++++++++++++++++++++++ api/src/models/Review.ts | 37 ++++++++++++++++++ api/src/routes/api_v1.ts | 5 ++- api/src/validators/reviewValidator.ts | 45 +++++++++++++++++++++ api/tests/review.test.ts | 49 +++++++++++++++++++++++ 5 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 api/src/controllers/reviewController.ts create mode 100644 api/src/models/Review.ts create mode 100644 api/src/validators/reviewValidator.ts create mode 100644 api/tests/review.test.ts diff --git a/api/src/controllers/reviewController.ts b/api/src/controllers/reviewController.ts new file mode 100644 index 0000000..db0b68d --- /dev/null +++ b/api/src/controllers/reviewController.ts @@ -0,0 +1,52 @@ +import { Request, Response } from 'express'; +import Review from "../models/Review" +import { isValidObjectId, Types } from 'mongoose'; +import {Log} from 'nork' +import Docs from '../services/docsService'; +import { addExam, delExam, IReview } from '../validators/reviewValidator'; + +new Docs('review', 'add', '/api/v1/review/add', 'POST', 'review add api', undefined, addExam, 'status object | review object'); +export async function add_post(req: Request, res: Response) { + try { + const data: IReview = req.body; + const review = new Review(data) + await review.save() + res.status(201).json(Log.info(201, 'review was added', review)) + } catch (err) { + Log.error(500, 'error while adding review', err) + res.status(500).json(Log.error(500, 'something went wrong')) + } +} + +new Docs('review', 'get', '/api/v1/review/get', 'GET', 'review get api', undefined, undefined, 'status object | array of review objects'); +export async function get_get(req: Request, res: Response) { + try { + const review = await Review.find({}, '-__v') + res.status(200).json(Log.info(200, 'reviews fetched', review)) + } catch (err) { + Log.error(500, 'error while geting reviews', err) + res.status(500).json(Log.error(500, 'something went wrong')) + } +} + +new Docs('review', 'del', '/api/v1/review/del', 'POST', 'review del api', undefined, delExam, 'status object'); +export async function del_post(req: Request, res: Response) { + try { + if (!isValidObjectId(req.body._id)) throw Log.error(400, 'this is not valid _id'); + + const review = await Review.deleteOne(new Types.ObjectId(req.body._id)) + + if (review.deletedCount > 0) { + res.status(200).json(Log.info(200, `review ${req.body._id} deleted`)); + return; + } + throw Log.error(400, `review ${req.body._id} does not exist`); + } catch (err: any) { + if (err.code) { + res.status(err.code).json(err); + return; + } + Log.error(500, 'error in del_post', err); + res.status(500).json(Log.error(500, 'something went wrong')); + } +} diff --git a/api/src/models/Review.ts b/api/src/models/Review.ts new file mode 100644 index 0000000..4b1696b --- /dev/null +++ b/api/src/models/Review.ts @@ -0,0 +1,37 @@ +import path from 'path'; +import { Schema, model } from 'mongoose'; +import { IReview } from '../validators/reviewValidator'; + +const schema = new Schema( + { + foam : { + type: Number, + required: true + }, + bitter_sweetness: { + type: Number, + required: true, + }, + taste: { + type: Number, + required: true + }, + packaging: { + type: Number, + required: true + }, + sourness: { + type: Boolean, + required: true + }, + would_again: { + type: Boolean, + required: true + } + }, + { + timestamps: true + } +); + +export default model(path.basename(__filename).split('.')[0], schema); diff --git a/api/src/routes/api_v1.ts b/api/src/routes/api_v1.ts index bedb87f..4e60a18 100644 --- a/api/src/routes/api_v1.ts +++ b/api/src/routes/api_v1.ts @@ -4,6 +4,7 @@ import path from 'path' import * as authController from "../controllers/authController"; import * as beerController from "../controllers/beerController" import * as docsController from "../controllers/docsController" +import * as reviewController from "../controllers/reviewController" import { requireAuth } from "../middlewares/authMiddleware"; import validate from '../middlewares/validateRequest' import valMulter from '../middlewares/validateMulterRequest'; @@ -26,4 +27,6 @@ router.get('/beer/get', [requireAuth], beerController.get_get); router.post('/beer/del', [requireAuth, validate(BVal.del)], beerController.del_post); router.post('/beer/edit', [requireAuth, upload.array('photos', 4), valMulter, validate(BVal.edit)], beerController.edit_post); -export default router; \ No newline at end of file +router.post('/review/add', requireAuth, reviewController.add_post) + +export default router; diff --git a/api/src/validators/reviewValidator.ts b/api/src/validators/reviewValidator.ts new file mode 100644 index 0000000..a458378 --- /dev/null +++ b/api/src/validators/reviewValidator.ts @@ -0,0 +1,45 @@ +import * as yup from 'yup' +import mongoose, { Schema } from 'mongoose' + +interface mongooseAddition { + _id?: Schema.Types.ObjectId; + createdAt?: Schema.Types.Date; + updatedAt?: Schema.Types.Date; +} + +let objectIdSchema = yup.string().test( + 'is-objectId', + 'Invalid ObjectId', + (value: any) => mongoose.Types.ObjectId.isValid(value) +) + +// Add +export const add = yup.object({ + beer_id: objectIdSchema, + foam: yup.number().min(1).max(3).required(), + bitter_sweetness: yup.number().min(1).max(5).required(), + taste: yup.number().min(1).max(5).required(), + packaging: yup.number().min(1).max(5).required(), + sourness: yup.boolean().required(), + would_again: yup.boolean().required() +}) +export interface IReview extends yup.InferType, mongooseAddition {} +export const addExam: IReview = { + beer_id: '6352b303b71cb62222f39895', + foam: 3, + bitter_sweetness: 2, + taste: 5, + packaging: 3, + sourness: false, + would_again: true +} + +// Remove +export const del = yup.object({ + _id: objectIdSchema.required() +}) +export interface IDel extends yup.InferType {} +export const delExam: IDel = { + _id: '6352b303b71cb62222f39895' +}; + diff --git a/api/tests/review.test.ts b/api/tests/review.test.ts new file mode 100644 index 0000000..88b3dee --- /dev/null +++ b/api/tests/review.test.ts @@ -0,0 +1,49 @@ +import supertest from 'supertest'; +import { app } from '../src/app'; +import { login } from './auth.test'; +//import { addExam, delExam, editExam } from '../src/validators/beerValidator'; + +const request = supertest(app); + +describe('POST /api/v1/review/add', () => { + const url = '/api/v1/review/add'; + test('should drop 401 error', async () => { + const res = await request.post(url).send({}); + expect(res.statusCode).toBe(401); + }); + + test('should drop 400 ()', async () => { + const jwt = await login(); + const res = await request.post(url).set('Cookie', jwt).send({}); + + console.log("TEST", await res.body) + + expect(res.statusCode).toBe(400); + }); + +// test('should drop 201', async () => { +// const jwt = await login(); +// const res = await request.post(url).set('Cookie', jwt).send(addExam); +// +// expect(res.statusCode).toBe(201); +// }); +}); + +//describe('GET /api/v1/beer/get', () => { +// const url = '/api/v1/beer/get'; +// +// test('should drop 401', async () => { +// const res = await request.get(url).send(); +// +// expect(res.statusCode).toBe(401); +// }); +// +// test('should drop 200', async () => { +// const jwt = await login(); +// const res = await request.get(url).set('Cookie', jwt).send(); +// +// expect(res.statusCode).toBe(200); +// }); +//}); + +