diff --git a/.env.example b/.env.example index 244b072..5e17a15 100644 --- a/.env.example +++ b/.env.example @@ -27,6 +27,7 @@ PINDO_API_URL = ******************************** PINDO_SENDER = ******************************** JWT_SECRET = ******************************** TWO_FA_MINS = ******************************** + HOST = ******************* AUTH_EMAIL = ********************* AUTH_PASSWORD = ****************** diff --git a/src/controllers/productController.ts b/src/controllers/productController.ts index e2edd45..ead88a1 100644 --- a/src/controllers/productController.ts +++ b/src/controllers/productController.ts @@ -1,5 +1,13 @@ import { Request, Response } from 'express'; -import { createProductService, updateProductService, removeProductImageService } from '../services'; +import { createProductService, updateProductService, removeProductImageService, readProductService, readProductsService, deleteProductService } from '../services'; + +export const readProduct = async (req: Request, res: Response) => { + await readProductService(req, res); +}; + +export const readProducts = async (req: Request, res: Response) => { + await readProductsService(req, res); +}; export const createProduct = async (req: Request, res: Response) => { await createProductService(req, res); @@ -12,3 +20,7 @@ export const updateProduct = async (req: Request, res: Response) => { export const removeProductImage = async (req: Request, res: Response) => { await removeProductImageService(req, res); }; + +export const deleteProduct = async (req: Request, res: Response) => { + await deleteProductService(req, res); +}; diff --git a/src/middlewares/verifyToken.ts b/src/middlewares/verifyToken.ts index 8ff50f3..3fe4f1a 100644 --- a/src/middlewares/verifyToken.ts +++ b/src/middlewares/verifyToken.ts @@ -43,7 +43,7 @@ export const authMiddleware = async (req: AuthRequest, res: Response, next: Next next(); } }); - } catch (ex) { + } catch (error) { return res.status(401).json({ error: 'Invalid token' }); } } diff --git a/src/routes/ProductRoutes.ts b/src/routes/ProductRoutes.ts index 74f664a..1e62c08 100644 --- a/src/routes/ProductRoutes.ts +++ b/src/routes/ProductRoutes.ts @@ -3,12 +3,22 @@ import { Router } from 'express'; import upload from '../middlewares/multer'; import { authMiddleware } from '../middlewares/verifyToken'; import { hasRole } from '../middlewares'; -import { createProduct, updateProduct, removeProductImage } from '../controllers/productController'; +import { + createProduct, + updateProduct, + removeProductImage, + readProducts, + readProduct, + deleteProduct, +} from '../controllers/productController'; const router = Router(); +router.get('/', authMiddleware, hasRole('VENDOR'), readProducts); +router.get('/:id', authMiddleware, hasRole('VENDOR'), readProduct); router.post('/', authMiddleware, hasRole('VENDOR'), upload.array('images', 10), createProduct); router.put('/:id', authMiddleware, hasRole('VENDOR'), upload.array('images', 10), updateProduct); router.delete('/images/:id', authMiddleware, hasRole('VENDOR'), removeProductImage); +router.delete('/:id', authMiddleware, hasRole('VENDOR'), deleteProduct); export default router; diff --git a/src/services/index.ts b/src/services/index.ts index aa9f99d..97a40a9 100644 --- a/src/services/index.ts +++ b/src/services/index.ts @@ -8,6 +8,10 @@ export * from './userServices/userValidateOTP'; export * from './userServices/userLoginService'; export * from './userServices/userResendOTP'; export * from './userServices/logoutServices'; + +// Vendor product services export * from './productServices/createProduct'; export * from './productServices/updateProduct'; export * from './productServices/removeProductImage'; +export * from './productServices/readProduct'; +export * from './productServices/deleteProduct'; diff --git a/src/services/productServices/deleteProduct.ts b/src/services/productServices/deleteProduct.ts new file mode 100644 index 0000000..43ec3d1 --- /dev/null +++ b/src/services/productServices/deleteProduct.ts @@ -0,0 +1,32 @@ +import { Request, Response } from 'express'; +import { Product } from '../../entities/Product'; +import { getRepository } from 'typeorm'; +import { responseError, responseSuccess } from '../../utils/response.utils'; + + +export const deleteProductService = async (req: Request, res: Response) => { + try { + const { id } = req.params; + + const productRepository = getRepository(Product); + + const product = await productRepository.findOne({ + where: { + id: id, + vendor: { + id: req.user?.id + } + } + }); + + if (product) { + await productRepository.remove(product); + return responseSuccess(res, 200, 'Product successfully deleted'); + } + + return responseError(res, 404, 'Product not found'); + + } catch (error) { + responseError(res, 400, (error as Error).message); + } +}; diff --git a/src/services/productServices/readProduct.ts b/src/services/productServices/readProduct.ts new file mode 100644 index 0000000..0b3d7a1 --- /dev/null +++ b/src/services/productServices/readProduct.ts @@ -0,0 +1,58 @@ +import { Request, Response } from 'express'; +import { Product } from '../../entities/Product'; +import { getRepository } from 'typeorm'; +import { responseError, responseSuccess } from '../../utils/response.utils'; + + +export const readProductsService = async (req: Request, res: Response) => { + try { + + // Define pagination parameters + const page = req.query.page ? Number(req.query.page) : 1; + const limit = req.query.limit ? Number(req.query.limit) : 10; + const skip = (page - 1) * limit; + + // Retrieve products + const productRepository = getRepository(Product); + const products = await productRepository.find({ + where: { + vendor: { + id: req.user?.id + } + }, + skip, + take: limit + }); + + if (!products) { + return responseError(res, 404, 'No Products available'); + } + return responseSuccess(res, 200, 'Products retrieved', { products }); + } catch (error) { + responseError(res, 400, (error as Error).message); + } +}; + +export const readProductService = async (req: Request, res: Response) => { + try { + const { id } = req.params; + + const productRepository = getRepository(Product); + const product = await productRepository.findOne({ + where: { + id: id, + vendor: { + id: req.user?.id + } + } + }); + + if (!product) { + return responseError(res, 404, 'Product not found'); + } + + return responseSuccess(res, 200, 'Product retrieved', { product }); + } catch (error) { + responseError(res, 400, (error as Error).message); + } +}; diff --git a/src/services/productServices/removeProductImage.ts b/src/services/productServices/removeProductImage.ts index e6a04dd..a3b33c9 100644 --- a/src/services/productServices/removeProductImage.ts +++ b/src/services/productServices/removeProductImage.ts @@ -33,6 +33,10 @@ export const removeProductImageService = async (req: Request, res: Response) => return res.status(403).json({ status: 'error', error: 'You are not authorized to perform this action' }); } + if (product.images.length === 2) { + return res.status(400).json({ status: 'error', error: 'Product must have at least two image' }); + } + const index = product.images.indexOf(image); if (index === -1) { diff --git a/src/services/productServices/updateProduct.ts b/src/services/productServices/updateProduct.ts index ed76cb2..6780099 100644 --- a/src/services/productServices/updateProduct.ts +++ b/src/services/productServices/updateProduct.ts @@ -47,6 +47,9 @@ export const updateProductService = async (req: Request, res: Response) => { } if (req.files) { + if (product.images.length + req.files.length > 10) { + return res.status(400).json({ status: 'error', error: 'Product cannot have more than 10 images' }); + } const imageUrls: string[] = []; for (const image of req.files) { const link = await cloudinary.uploader.upload(image.path); diff --git a/src/utils/response.utils.ts b/src/utils/response.utils.ts index 3be109b..3fd1ce5 100644 --- a/src/utils/response.utils.ts +++ b/src/utils/response.utils.ts @@ -17,7 +17,7 @@ export const responseSuccess = ( jsend.success({ code: statusCode, message, - data, + ...data, }) ); };