diff --git a/src/__test__/buyerController.test.ts b/src/__test__/buyerController.test.ts new file mode 100644 index 00000000..4c3932fc --- /dev/null +++ b/src/__test__/buyerController.test.ts @@ -0,0 +1,75 @@ +import request from 'supertest'; +import app from '../app'; +import { + afterAllHook, + beforeAllHook, + getBuyerToken, + getVendorToken, +} from './testSetup'; +beforeAll(beforeAllHook); +afterAll(afterAllHook); + +describe('Buyer Controller test', () => { + let buyerToken: string; + let vendorToken: string; + let productId: number; + let categoryId: number; + + beforeAll(async () => { + buyerToken = await getBuyerToken(); + vendorToken = await getVendorToken(); + }); + + it('should get a product by id', async () => { + // create a category + const categoryData = { + name: 'Category4', + description: 'category description', + }; + + const categoryResponse = await request(app) + .post('/api/v1/category') + .set('Authorization', `Bearer ${vendorToken}`) + .send(categoryData); + + categoryId = categoryResponse.body.data.id; + + const productData = { + name: 'New Product Two', + image: 'new_product.jpg', + gallery: [], + shortDesc: 'This is a new product', + longDesc: 'Detailed description of the new product', + categoryId: categoryId, + quantity: 10, + regularPrice: 5, + salesPrice: 4, + tags: ['tag1', 'tag2'], + type: 'Simple', + isAvailable: true, + }; + + const response = await request(app) + .post('/api/v1/product') + .set('Authorization', `Bearer ${vendorToken}`) + .send(productData); + + productId = response.body.data.id; + + const getResponse = await request(app) + .get(`/api/v1/buyer/get_product/${productId}`) + .set('Authorization', `Bearer ${buyerToken}`); + + + expect(getResponse.statusCode).toEqual(200); + expect(getResponse.body.msg).toEqual('Product retrieved successfully'); + }); + + it('should return a 404 if product is not found', async () => { + const response = await request(app) + .get('/api/v1/buyer/get_product/5') + .set('Authorization', `Bearer ${buyerToken}`); + expect(response.status).toBe(404); + expect(response.body.msg).toBe('Product not found'); + }); +}); diff --git a/src/__test__/testSetup.ts b/src/__test__/testSetup.ts index 969af324..41bef9c9 100644 --- a/src/__test__/testSetup.ts +++ b/src/__test__/testSetup.ts @@ -77,15 +77,52 @@ export async function getVendorToken() { return verifyResponse.body.token; } +export const getBuyerToken = async () => { + const userRepository = await DbConnection.connection.getRepository(UserModel); + const formData = { + name: 'Buyer', + permissions: ['test-permission1', 'test-permission2'], + }; + await request(app) + .post('/api/v1/roles/create_role') + .send(formData); + + const userData = { + firstName: 'Tester', + lastName: 'Test', + email: 'test4@gmail.com', + password: 'TestPassword123', + userType: 'buyer', + }; + await request(app).post('/api/v1/register').send(userData); + + const updatedUser = await userRepository.findOne({ + where: { email: userData.email }, + }); + if (updatedUser) { + updatedUser.isVerified = true; + await userRepository.save(updatedUser); + } + + const loginResponse = await request(app).post('/api/v1/login').send({ + email: userData.email, + password: userData.password, + }); + + return loginResponse.body.token; +}; + export async function afterAllHook() { await DbConnection.connection.transaction(async (transactionManager) => { const userRepository = transactionManager.getRepository(UserModel); const categoryRepository = transactionManager.getRepository(Category); const productRepository = transactionManager.getRepository(Product); + const roleRepository = transactionManager.getRepository(Role); await userRepository.createQueryBuilder().delete().execute(); await categoryRepository.createQueryBuilder().delete().execute(); await productRepository.createQueryBuilder().delete().execute(); + await roleRepository.createQueryBuilder().delete().execute(); }); await DbConnection.instance.disconnectDb(); } diff --git a/src/controller/buyerController.ts b/src/controller/buyerController.ts new file mode 100644 index 00000000..839970a5 --- /dev/null +++ b/src/controller/buyerController.ts @@ -0,0 +1,25 @@ +import { Request, Response } from 'express'; +import dbConnection from '../database'; +import Product from '../database/models/productEntity'; +import errorHandler from '../middlewares/errorHandler'; + +const productRepository = dbConnection.getRepository(Product); + +export const getOneProduct = errorHandler( + async (req: Request, res: Response) => { + const productId = parseInt(req.params.id); + + const product = await productRepository.findOne({ + where: { id: productId }, + relations: ['category'], + }); + + if (!product) { + return res.status(404).json({ msg: 'Product not found' }); + } + + return res + .status(200) + .json({ msg: 'Product retrieved successfully', product }); + } +); diff --git a/src/database/models/productEntity.ts b/src/database/models/productEntity.ts index 4c2fa97c..e036eea8 100644 --- a/src/database/models/productEntity.ts +++ b/src/database/models/productEntity.ts @@ -50,7 +50,7 @@ export default class Product { @Column({ default: true }) isAvailable: boolean; - @ManyToOne(() => UserModel) + @ManyToOne(() => UserModel, { onDelete: 'CASCADE' }) vendor: UserModel; @CreateDateColumn() diff --git a/src/docs/buyerDocs.ts b/src/docs/buyerDocs.ts new file mode 100644 index 00000000..649d4f75 --- /dev/null +++ b/src/docs/buyerDocs.ts @@ -0,0 +1,22 @@ +/** + * @swagger + * /api/v1/buyer/get_product/{id}: + * get: + * summary: Get a specific product + * tags: [Buyer] + * security: + * - bearerAuth: [] + * parameters: + * - in: path + * name: id + * type: string + * required: true + * description: ID of the product to get + * responses: + * '200': + * description: Successful + * '404': + * description: Product not found + * '500': + * description: Internal Server Error + */ diff --git a/src/routes/buyerRoutes.ts b/src/routes/buyerRoutes.ts new file mode 100644 index 00000000..dd59f24e --- /dev/null +++ b/src/routes/buyerRoutes.ts @@ -0,0 +1,15 @@ +import { Router } from 'express'; +import { checkRole } from '../middlewares/authorize'; +import { getOneProduct } from '../controller/buyerController' +import { IsLoggedIn } from '../middlewares/isLoggedIn'; + +const buyerRouter = Router(); + +buyerRouter.get( + '/get_product/:id', + IsLoggedIn, + checkRole(['Buyer']), + getOneProduct +); + +export default buyerRouter; diff --git a/src/routes/index.ts b/src/routes/index.ts index da75aa8f..6887a8c7 100644 --- a/src/routes/index.ts +++ b/src/routes/index.ts @@ -3,6 +3,7 @@ import userRouter from './userRoutes'; import roleRoutes from './roleRoutes'; import productRoutes from './productRoutes'; import categoryRoutes from './categoryRoutes'; +import buyerRoutes from './buyerRoutes'; const router = Router(); @@ -10,5 +11,6 @@ router.use('/user', userRouter); router.use('/roles', roleRoutes); router.use('/product', productRoutes); router.use('/category', categoryRoutes); +router.use('/buyer', buyerRoutes); export default router;