diff --git a/package-lock.json b/package-lock.json index a28dd014..3de79c79 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "chai-http": "^4.4.0", "cloudinary": "^2.2.0", "compression": "^1.7.4", + "cookie-parser": "^1.4.6", "cors": "^2.8.5", "coverage": "^0.4.1", "coveralls": "^3.1.1", @@ -64,6 +65,7 @@ "devDependencies": { "@types/bcrypt": "^5.0.2", "@types/compression": "^1.7.5", + "@types/cookie-parser": "^1.4.7", "@types/cors": "^2.8.17", "@types/express": "^4.17.21", "@types/jsonwebtoken": "^9.0.6", @@ -1228,6 +1230,15 @@ "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" }, + "node_modules/@types/cookie-parser": { + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-Fvuyi354Z+uayxzIGCwYTayFKocfV7TuDYZClCdIP9ckhvAu/ixDtCB6qx2TT0FKjPLf1f3P/J1rgf6lPs64mw==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/cookiejar": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@types/cookiejar/-/cookiejar-2.1.5.tgz", @@ -3081,6 +3092,26 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", + "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", + "dependencies": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/cookie-parser/node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", diff --git a/package.json b/package.json index 1ca05a4e..aedd2c7d 100644 --- a/package.json +++ b/package.json @@ -79,6 +79,7 @@ "chai-http": "^4.4.0", "cloudinary": "^2.2.0", "compression": "^1.7.4", + "cookie-parser": "^1.4.6", "cors": "^2.8.5", "coverage": "^0.4.1", "coveralls": "^3.1.1", @@ -122,6 +123,7 @@ "devDependencies": { "@types/bcrypt": "^5.0.2", "@types/compression": "^1.7.5", + "@types/cookie-parser": "^1.4.7", "@types/cors": "^2.8.17", "@types/express": "^4.17.21", "@types/jsonwebtoken": "^9.0.6", diff --git a/src/databases/migrations/20240704115209-create-termsAndCondition.ts b/src/databases/migrations/20240704115209-create-termsAndCondition.ts index b1e38fed..ca75b7a0 100644 --- a/src/databases/migrations/20240704115209-create-termsAndCondition.ts +++ b/src/databases/migrations/20240704115209-create-termsAndCondition.ts @@ -4,20 +4,28 @@ export default { up: async (queryInterface: QueryInterface) => { await queryInterface.createTable("termsAndConditions", { - id: { - type: DataTypes.UUID, - allowNull: false, - primaryKey: true, - defaultValue: DataTypes.UUIDV4 - }, - content: { + id: { + type: DataTypes.UUID, allowNull: false, - type: DataTypes.STRING - }, - type: { + primaryKey: true, + defaultValue: DataTypes.UUIDV4 + }, + content: { + allowNull: true, + type: DataTypes.TEXT + }, + type: { type: DataTypes.STRING, - allowNull: true - }, + allowNull: false + }, + pdfUrl: { + type: DataTypes.STRING, + allowNull: true, + unique: true, + validate: { + isUrl: true + } + }, createdAt: { allowNull: false, type: DataTypes.DATE, diff --git a/src/databases/models/termsAndCodition.ts b/src/databases/models/termsAndCodition.ts index aa6f0007..8ddfc9fa 100644 --- a/src/databases/models/termsAndCodition.ts +++ b/src/databases/models/termsAndCodition.ts @@ -9,11 +9,13 @@ export interface ITermsAndConditions { id: string; content:string; type: string; + pdfUrl: string; } class TermsAndConditions extends Model implements ITermsAndConditions { declare id: string; declare content: string; declare type: string; + declare pdfUrl: string; static associate() { @@ -29,12 +31,20 @@ TermsAndConditions.init( defaultValue: DataTypes.UUIDV4 }, content: { - allowNull: false, - type: DataTypes.STRING, + allowNull: true, + type: DataTypes.TEXT, }, type: { type: DataTypes.STRING, - allowNull: true + allowNull: false + }, + pdfUrl:{ + type: DataTypes.STRING, + allowNull: true, + unique: true, + validate:{ + isUrl: true + } } }, { diff --git a/src/databases/seeders/20240520202759-users.ts b/src/databases/seeders/20240520202759-users.ts index f1f4f072..2a50ecf7 100644 --- a/src/databases/seeders/20240520202759-users.ts +++ b/src/databases/seeders/20240520202759-users.ts @@ -88,7 +88,7 @@ const userFour = { passwordUpdatedAt: new Date(), firstName: "F Seller", lastName: "L Seller", - email: "seller@gmail.com", + email: "aimegetz@gmail.com", password: hashPassword("Password@123"), phone: 25089767099, profilePicture: "https://res.cloudinary.com/djrmfg6k9/image/upload/v1720294521/cce1ffu7uw3j2vg9s2vl.jpg", @@ -109,7 +109,7 @@ const userFive = { passwordUpdatedAt: new Date(), firstName: "dj5090", lastName: "dj2090", - email: "dj@gmail.com", + email: "jadowacu@gmail.com", password: hashPassword("Password@123"), phone: 25089767899, profilePicture: "https://res.cloudinary.com/djrmfg6k9/image/upload/v1720294521/cce1ffu7uw3j2vg9s2vl.jpg", @@ -130,7 +130,7 @@ const userSix = { passwordUpdatedAt: new Date(), firstName: "F Seller3", lastName: "L Seller3", - email: "seller3@gmail.com", + email: "ndahimana154@gmail.com", password: hashPassword("Password@123"), phone: 25089767899, profilePicture: "https://res.cloudinary.com/djrmfg6k9/image/upload/v1720294521/cce1ffu7uw3j2vg9s2vl.jpg", @@ -151,7 +151,7 @@ const userSeven = { passwordUpdatedAt: new Date(), firstName: "F Seller4", lastName: "L Seller4", - email: "seller4@gmail.com", + email: "ijbapte@gmail.com", password: hashPassword("Password@123"), phone: 25089767899, profilePicture: "https://res.cloudinary.com/djrmfg6k9/image/upload/v1720294521/cce1ffu7uw3j2vg9s2vl.jpg", diff --git a/src/databases/seeders/20240601224834-shops.ts b/src/databases/seeders/20240601224834-shops.ts index bfd4b1e6..89c7a759 100644 --- a/src/databases/seeders/20240601224834-shops.ts +++ b/src/databases/seeders/20240601224834-shops.ts @@ -3,58 +3,60 @@ import { shopFiveId, shopFourId, shopOneId, shopSixId, shopThreeId, shopTwoId, u const shopOne = { id: shopOneId, - name: "Paccy Shop 250", + name: "GadgetHub 250", userId: userFourId, - description: "Selling", + description: "Your one-stop shop for the latest gadgets and electronics.", createdAt: new Date(), updatedAt: new Date() } const shopTwo = { id: shopTwoId, - name: "Paccy Shop 509", + name: "UrbanStyle Boutique", userId: userSevenId, - description: "Selling", + description: "Bringing you the trendiest fashion and accessories in town.", createdAt: new Date(), updatedAt: new Date() } const shopThree = { id: shopThreeId, - name: "Shoes Shop 509", + name: "SoleMates", userId: userFourTeenId, - description: "Selling", + description: "Premium footwear for every step of your journey.", createdAt: new Date(), updatedAt: new Date() } + const shopFour = { id: shopFourId, - name: "electronic Shop 509", + name: "TechNest", userId: userSixId, - description: "Selling", + description: "Explore a world of cutting-edge electronics and accessories.", createdAt: new Date(), updatedAt: new Date() } + const shopFive = { id: shopFiveId, - name: "Shop 509", + name: "HomeEssentials", userId: userFiveId, - description: "Selling", + description: "Everything you need to make your house a home.", createdAt: new Date(), updatedAt: new Date() } + const shopSix = { id: shopSixId, - name: "electronics Shop 509", + name: "ElectroMart", userId: userFiveTeenId, - description: "Selling", + description: "Your trusted source for all things electronic.", createdAt: new Date(), updatedAt: new Date() } - export const up = async (queryInterface: QueryInterface) => { - await queryInterface.bulkInsert("shops", [shopOne, shopTwo,shopThree,shopFour, shopFive, shopSix]); + await queryInterface.bulkInsert("shops", [shopOne, shopTwo, shopThree, shopFour, shopFive, shopSix]); }; export const down = async (queryInterface: QueryInterface) => { diff --git a/src/databases/seeders/20240601224835-products.ts b/src/databases/seeders/20240601224835-products.ts index 45193604..eaa05642 100644 --- a/src/databases/seeders/20240601224835-products.ts +++ b/src/databases/seeders/20240601224835-products.ts @@ -51,7 +51,7 @@ const productTwo = { description: "A women's bag is a fashionable and functional accessory designed to carry personal belongings. Available in various styles, sizes, and materials, women's bags cater to diverse needs and preferences. From elegant clutches and chic handbags to spacious totes and practical backpacks, each type serves a unique purpose. High-quality women's bags offer a blend of style, durability, and convenience, making them essential for everyday use, special occasions, and professional settings.", price: 19.99, discount: "13%", - category: "Handbags:", + category: "Handbags", expiryDate: new Date("2050-12-31"), expired: false, bonus: "Bonus 1", diff --git a/src/index.ts b/src/index.ts index 73617e41..8638781a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,5 @@ import express, { Express, Request, Response, NextFunction } from "express"; +import cookieParser from "cookie-parser"; import dotenv from "dotenv"; import morgan from "morgan"; import compression from "compression"; @@ -19,7 +20,7 @@ const app: Express = express(); const PORT = process.env.PORT; const server = createServer(app); -const allowedOrigins = ["http://localhost:5000" , "https://e-commerce-ninja-fn-staging.netlify.app"]; +const allowedOrigins = ["http://localhost:5000" , "https://e-commerce-ninjas.netlify.app"]; export const io = new Server(server, { cors: { @@ -42,7 +43,11 @@ app.use((req: Request, res: Response, next: NextFunction) => { app.use(morgan(process.env.NODE_EN)); app.use(compression()); -app.use(cors()); +app.use(cookieParser()); +app.use(cors({ + origin:allowedOrigins, + credentials:true +})); app.use("/api-docs", SwaggerUi.serve, SwaggerUi.setup(Document)); app.use("/api", router); diff --git a/src/middlewares/authorization.ts b/src/middlewares/authorization.ts index 6cff932a..1fd4c2bf 100644 --- a/src/middlewares/authorization.ts +++ b/src/middlewares/authorization.ts @@ -117,4 +117,4 @@ export const socketAuthMiddleware = async (socket: Socket, next: NextFunction) = err.data = { message: "Internal server error" }; return next(err); } -}; +}; \ No newline at end of file diff --git a/src/middlewares/validation.ts b/src/middlewares/validation.ts index 68df7cd0..e3b9f632 100644 --- a/src/middlewares/validation.ts +++ b/src/middlewares/validation.ts @@ -1049,33 +1049,37 @@ const isSellerRequestExist = async ( const role = req.user.role; let existingRequest = null; let user = null; - if(req.params.userId){ - user = await userRepositories.findUserById(req.params.userId) - } switch (role) { case "admin": const requestCount = await db.SellerProfile.count(); + if (requestCount === 0) { return res.status(httpStatus.NOT_FOUND).json({ status: httpStatus.NOT_FOUND, message: "No seller requests found", }); } - if(req.params.userId){ - existingRequest = await userRepositories.findSellerRequestByUserId(req.params.userId); - if (!existingRequest) { - return res.status(httpStatus.NOT_FOUND).json({ - status: httpStatus.NOT_FOUND, - message: "No seller requests found for the provided user ID", - }); + + if (req.params.userId) { + existingRequest = await userRepositories.findSellerRequestByUserId(req.params.userId); + user = await userRepositories.findUserById(req.params.userId); + + if (!existingRequest) { + return res.status(httpStatus.NOT_FOUND).json({ + status: httpStatus.NOT_FOUND, + message: "No seller requests found for the provided user ID", + }); + } + + req.user = user; } - } break; case "buyer": const userId = req.user.id || req.params.userId; existingRequest = await userRepositories.findSellerRequestByUserId(userId); + if (existingRequest) { return res.status(httpStatus.BAD_REQUEST).json({ status: httpStatus.BAD_REQUEST, @@ -1090,7 +1094,7 @@ const isSellerRequestExist = async ( message: "Invalid role or request", }); } - req.user = user + next(); } catch (error) { return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ @@ -1100,6 +1104,7 @@ const isSellerRequestExist = async ( } }; + const isRequestAcceptedOrRejected = (req: any, res: Response, next: NextFunction) => { try { const { requestStatus } = req.body; diff --git a/src/modules/auth/controller/authControllers.ts b/src/modules/auth/controller/authControllers.ts index 0a384404..41e687b5 100644 --- a/src/modules/auth/controller/authControllers.ts +++ b/src/modules/auth/controller/authControllers.ts @@ -47,7 +47,7 @@ const registerSeller = async (req: Request, res: Response): Promise => { const { firstName, lastName, email, password, phone, businessName, businessDescription, Tin, mobileNumber, mobilePayment, bankPayment, bankAccount, bankName,terms } = req.body; if (req.file) { const result = await uploadImages(req.file); - console.log(result) + req.body.rdbDocument = result.secure_url; } @@ -59,7 +59,6 @@ const registerSeller = async (req: Request, res: Response): Promise => { phone, role: "seller", } - console.log(userInfo) const sellerData = { businessName, diff --git a/src/modules/auth/repository/authRepositories.ts b/src/modules/auth/repository/authRepositories.ts index 9d0d0a60..a8415003 100644 --- a/src/modules/auth/repository/authRepositories.ts +++ b/src/modules/auth/repository/authRepositories.ts @@ -4,7 +4,6 @@ import { Op } from "sequelize"; import db from "../../../databases/models"; const createUser = async (body: any) => { - console.log("body" + JSON.stringify(body)) return await db.Users.create(body); }; diff --git a/src/modules/auth/test/auth.spec.ts b/src/modules/auth/test/auth.spec.ts index 77a4e2c3..b686b777 100644 --- a/src/modules/auth/test/auth.spec.ts +++ b/src/modules/auth/test/auth.spec.ts @@ -882,11 +882,10 @@ describe("updateUser2FA", () => { router() .post("/api/auth/login") .send({ - email: "seller4@gmail.com", + email: "ijbapte@gmail.com", password: "Password@123" }) .end((error, response) => { - console.log(response) token = response.body.data.token; done(error); }); @@ -1029,7 +1028,7 @@ describe("verifyUserCredentials Middleware", () => { router() .post("/api/auth/login") .send({ - email: "seller4@gmail.com", + email: "ijbapte@gmail.com", password: "Password@123" }) .end((error, response) => { diff --git a/src/modules/product/controller/productController.ts b/src/modules/product/controller/productController.ts index 503e55a1..2a581de3 100644 --- a/src/modules/product/controller/productController.ts +++ b/src/modules/product/controller/productController.ts @@ -441,6 +441,31 @@ const sellerGetOrdersHistory = async(req: ExtendRequest, res:Response)=>{ }) } +const getProductsByShopId = async (req: ExtendRequest, res: Response) => { + try { + const products = await productRepositories.getProductsByShopId(req.params.id); + + if (products.length === 0) { + return res.status(httpStatus.OK).json({ + status: httpStatus.OK, + message: "No products found for this shop", + data: { products: [] }, + }); + } + + res.status(httpStatus.OK).json({ + status: httpStatus.OK, + message: "Products fetched successfully", + data: { products }, + }); + } catch (error) { + res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ + status: httpStatus.INTERNAL_SERVER_ERROR, + message: error.message, + }); + } +}; + export { sellerCreateProduct, sellerCreateShop, @@ -460,5 +485,6 @@ export { buyerViewWishListProducts, buyerDeleteWishListProduct, adminGetShops, - sellerGetOrdersHistory + sellerGetOrdersHistory, + getProductsByShopId }; \ No newline at end of file diff --git a/src/modules/product/repositories/productRepositories.ts b/src/modules/product/repositories/productRepositories.ts index 441374ee..3adcf460 100644 --- a/src/modules/product/repositories/productRepositories.ts +++ b/src/modules/product/repositories/productRepositories.ts @@ -250,6 +250,10 @@ const sellerGetOrdersHistory = async (shopId: string) => { return db.Orders.findAll({ where: { shopId } }); }; +const getProductsByShopId = async (shopId: string) => { + return await db.Products.findAll({ where: { shopId } }); +}; + export default { createProduct, updateProduct, @@ -280,7 +284,8 @@ export default { removeWishList, userCreateReview, findSingleProductById, - sellerGetOrdersHistory + sellerGetOrdersHistory, + getProductsByShopId }; diff --git a/src/modules/product/test/product.spec.ts b/src/modules/product/test/product.spec.ts index 3afc9ac3..df8c6612 100644 --- a/src/modules/product/test/product.spec.ts +++ b/src/modules/product/test/product.spec.ts @@ -50,8 +50,9 @@ describe("Product and Shops API Tests", () => { before((done) => { router() .post("/api/auth/login") - .send({ email: "dj@gmail.com", password: "Password@123" }) + .send({ email: "jadowacu@gmail.com", password: "Password@123" }) .end((err, res) => { + console.log(res); token = res.body.data.token; done(err); }); @@ -399,7 +400,7 @@ describe("Seller test cases", () => { before((done) => { router() .post("/api/auth/login") - .send({ email: "seller@gmail.com", password: "Password@123" }) + .send({ email: "aimegetz@gmail.com", password: "Password@123" }) .end((err, res) => { token = res.body.data.token; done(err); @@ -465,7 +466,6 @@ describe("Seller test cases", () => { // // description: "A new Shops description", // // }) // // .end((err, res) => { -// // console.log(res) // // expect(res).to.have.status(httpStatus.INTERNAL_SERVER_ERROR); // // expect(res.body).to.have.property("message"); // // done(err); @@ -601,7 +601,7 @@ describe("Product Controller", () => { before((done) => { router() .post("/api/auth/login") - .send({ email: "seller3@gmail.com", password: "Password@123" }) + .send({ email: "ndahimana154@gmail.com", password: "Password@123" }) .end((err, res) => { token = res.body.data.token; done(err); diff --git a/src/modules/user/controller/userControllers.ts b/src/modules/user/controller/userControllers.ts index 4f602acb..c6e11ea9 100644 --- a/src/modules/user/controller/userControllers.ts +++ b/src/modules/user/controller/userControllers.ts @@ -48,6 +48,21 @@ const adminGetUser = async (req: Request, res: Response) => { } }; +const adminDeleteUser = async (req: Request, res: Response) => { + try { + await userRepositories.deleteUser(req.params.id); + return res.status(httpStatus.OK).json({ + status: httpStatus.OK, + message: "User deleted successfully", + }); + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ + status: httpStatus.INTERNAL_SERVER_ERROR, + message: error.message, + }); + } +} + const updateUserRole = async (req: Request, res: Response) => { try { const user = await authRepositories.updateUserByAttributes( @@ -220,7 +235,6 @@ const submitSellerRequest = async (req: any, res: Response) => { const userId = req.user.id; if(req.file){ const result= await uploadImages(req.file); - console.log(result) req.body.rdbDocument = result.secure_url; } const sellerData : any = { @@ -233,17 +247,17 @@ const submitSellerRequest = async (req: any, res: Response) => { sellerData }); - // await sendEmail( - // process.env.ADMIN_EMAIL, - // "New Seller Request", - // `A new seller request has been submitted by user ID: ${userId}.` - // ); + await sendEmail( + process.env.ADMIN_EMAIL, + "New Seller Request", + `A new seller request has been submitted by user ID: ${userId}.` + ); - // await sendEmail( - // req.user.email, - // "Seller Request Submitted", - // "Your request to become a seller has been submitted successfully. We will notify you once it is reviewed." - // ); + await sendEmail( + req.user.email, + "Seller Request Submitted", + "Your request to become a seller has been submitted successfully. We will notify you once it is reviewed." + ); return res.status(httpStatus.OK).json({ status: httpStatus.OK, @@ -365,6 +379,26 @@ const adminSetTermsAndCondition = async (req: Request, res: Response) =>{ } } +const adminSetTermsAndConditionWithPdf = async (req: Request, res: Response) =>{ + try { + if(req.file){ + const result= await uploadImages(req.file); + req.body.content = result.secure_url; + } + const termsAndCondition = await userRepositories.createTermsAndConditionWithUrl(req.body.content,req.body.type) + return res.status(httpStatus.CREATED).json({ + status: httpStatus.CREATED, + message: "Terms and condition created successfully", + data: { termsAndCondition }, + }); + } catch (error) { + return res.status(httpStatus.INTERNAL_SERVER_ERROR).json({ + status: httpStatus.INTERNAL_SERVER_ERROR, + message: error.message, + }) + } +} + const adminGetTermsAndCondition = async (req: Request, res: Response) =>{ try { const termsAndCondition = await userRepositories.getTermsAndCondition() @@ -411,8 +445,11 @@ const adminGetSingleTermsAndCondition = async (req: Request, res: Response)=>{ } const adminUpdateTermsAndCondition = async(req: Request, res: Response) =>{ try { - const {content,type} = req.body - const updatedTermsAndCondition = await userRepositories.UpdateTermsAndCondition({content,type},req.params.id) + if(req.file){ + const result= await uploadImages(req.file); + req.body.pdfUrl = result.secure_url; + } + const updatedTermsAndCondition = await userRepositories.UpdateTermsAndCondition(req.body,req.params.id) return res.status(httpStatus.OK).json({ status: httpStatus.OK, message: "Terms and condition updated successfully", @@ -502,4 +539,6 @@ export default { adminGetSingleTermsAndCondition, adminDeleteTermsAndCondition, adminUpdateTermsAndCondition, + adminDeleteUser, + adminSetTermsAndConditionWithPdf, }; \ No newline at end of file diff --git a/src/modules/user/repository/userRepositories.ts b/src/modules/user/repository/userRepositories.ts index f8a18bdf..c0dd381a 100644 --- a/src/modules/user/repository/userRepositories.ts +++ b/src/modules/user/repository/userRepositories.ts @@ -175,6 +175,9 @@ const createTermsAndCondition = async (content: string, type: string) => { return await db.TermsAndConditions.create({ content, type }); } +const createTermsAndConditionWithUrl = async(url: string,type:string) => { + return await db.TermsAndConditions.create({ pdfUrl: url, type }); +} const getTermsAndCondition = async () => { return await db.TermsAndConditions.findAll(); }; @@ -228,6 +231,10 @@ const updateSettingValue = async (setting: any, value: string) => { return await setting.save(); }; +const deleteUser = async (id:string) => { + return await db.Users.destroy({ where: { id } }); +} + export default { getAllUsers, updateUserProfile, @@ -257,5 +264,7 @@ export default { updateSellerProfileAndUserStatus, deleteTermsAndCondition, getTermsAndConditionById, - findTermByType + findTermByType, + deleteUser, + createTermsAndConditionWithUrl }; \ No newline at end of file diff --git a/src/modules/user/validation/userValidations.ts b/src/modules/user/validation/userValidations.ts index 05ec2ab6..1e88a943 100644 --- a/src/modules/user/validation/userValidations.ts +++ b/src/modules/user/validation/userValidations.ts @@ -22,66 +22,71 @@ export const statusSchema = Joi.object({ export const roleSchema = Joi.object({ role: Joi.string().valid("admin", "buyer", "seller").required().messages({ - "any.required": "The 'role' parameter is required.", - "string.base": "The 'role' parameter must be a string.", - "any.only": "Only admin, buyer and seller are allowed." + "any.required": "The 'role' parameter is required.", + "string.base": "The 'role' parameter must be a string.", + "any.only": "Only admin, buyer and seller are allowed." }) }); export const termsSchema = Joi.object({ - content : Joi.string().required().messages({ - "string.base" : "the content should be a string", - "string.empty" : "the content should not be empty" + content: Joi.string().optional().messages({ + "string.base": "the content should be a string", + "string.empty": "the content should not be empty" }), - type : Joi.string().valid("seller", "buyer").required().messages({ + type: Joi.string().valid("seller", "buyer").required().messages({ "any.required": "The 'type' parameter is required.", "string.base": "The 'type' parameter must be a string.", "any.only": "Only buyer and seller are allowed.", - "string.empty" : "The 'type' parameter cannot be empty" + "string.empty": "The 'type' parameter cannot be empty" + }), + pdf: Joi.string().uri().optional().messages({ + "string.base": "pdf should be a type of text", + "string.uri": "pdf must be a valid URI" }) + }) export const userSchema = Joi.object({ firstName: Joi.string().messages({ - "string.base": "firstName should be a type of text", - "string.empty": "firstName cannot be an empty field", - "any.required": "firstName is required" + "string.base": "firstName should be a type of text", + "string.empty": "firstName cannot be an empty field", + "any.required": "firstName is required" }), lastName: Joi.string().messages({ - "string.base": "lastName should be a type of text", - "string.empty": "lastName cannot be an empty field", - "any.required": "lastName is required" + "string.base": "lastName should be a type of text", + "string.empty": "lastName cannot be an empty field", + "any.required": "lastName is required" }), phone: Joi.number().messages({ - "number.base": "phone number should be a type of number", - "any.required": "phone number is required" + "number.base": "phone number should be a type of number", + "any.required": "phone number is required" }), profilePicture: Joi.string().uri().optional().messages({ - "string.base": "profilePicture should be a type of text", - "string.uri": "profilePicture must be a valid URI" + "string.base": "profilePicture should be a type of text", + "string.uri": "profilePicture must be a valid URI" }), gender: Joi.string().valid("male", "female", "other").messages({ - "string.base": "gender should be a type of text", - "any.only": "gender must be one of [male, female, other]", - "any.required": "gender is required" + "string.base": "gender should be a type of text", + "any.only": "gender must be one of [male, female, other]", + "any.required": "gender is required" }), birthDate: Joi.date().iso().messages({ - "date.base": "birthDate should be a valid date", - "date.iso": "birthDate must be in ISO format", - "any.required": "birthDate is required" + "date.base": "birthDate should be a valid date", + "date.iso": "birthDate must be in ISO format", + "any.required": "birthDate is required" }), language: Joi.string().messages({ - "string.base": "language should be a type of text", - "string.empty": "language cannot be an empty field", - "any.required": "language is required" + "string.base": "language should be a type of text", + "string.empty": "language cannot be an empty field", + "any.required": "language is required" }), currency: Joi.string().messages({ - "string.base": "currency should be a type of text", - "string.empty": "currency cannot be an empty field", - "any.required": "currency is required" + "string.base": "currency should be a type of text", + "string.empty": "currency cannot be an empty field", + "any.required": "currency is required" }), role: Joi.string().valid("buyer", "seller", "admin").messages({ - "string.base": "role should be a type of text", - "any.only": "role must be one of [buyer, seller, admin]", - "any.required": "role is required" + "string.base": "role should be a type of text", + "any.only": "role must be one of [buyer, seller, admin]", + "any.required": "role is required" }) }); @@ -98,7 +103,7 @@ export const changePasswordSchema = Joi.object({ "string.min": "New password should have a minimum length of 8", "string.pattern.base": "New password must contain both letters and numbers", "any.required": "New password is required" -}), + }), confirmPassword: Joi.string().valid(Joi.ref("newPassword")).required().messages({ "any.only": "Confirm password must match new password", "any.required": "Confirm password is required" diff --git a/src/routes/productRouter.ts b/src/routes/productRouter.ts index 63961b9f..d97cc765 100644 --- a/src/routes/productRouter.ts +++ b/src/routes/productRouter.ts @@ -125,4 +125,9 @@ router.post( productController.buyerReviewProduct ) router.get("/admin-get-shops",userAuthorization(["admin"]),isShopEmpty,productController.adminGetShops); router.get("/seller-get-orderHistory",userAuthorization(["seller"]),isOrderExistByShopId,productController.sellerGetOrdersHistory); + router.get("/get-all-shops",isShopEmpty,productController.adminGetShops); + router.get( + "/get-products-by-shop/:id", + productController.getProductsByShopId + ); export default router; \ No newline at end of file diff --git a/src/routes/userRouter.ts b/src/routes/userRouter.ts index 4437d13a..6a5cee2a 100644 --- a/src/routes/userRouter.ts +++ b/src/routes/userRouter.ts @@ -9,18 +9,24 @@ import upload from "../helpers/multer"; router.get("/admin-get-users", userAuthorization(["admin"]), isUsersExist, userControllers.adminGetUsers); router.get("/admin-get-user/:id", userAuthorization(["admin"]), isUserExist, userControllers.adminGetUser); + router.delete("/admin-delete-user/:id", userAuthorization(["admin"]), isUserExist, userControllers.adminDeleteUser); router.put("/admin-update-user-status/:id", userAuthorization(["admin"]), validation(statusSchema), isUserExist, userControllers.updateUserStatus); router.put("/admin-update-user-role/:id", userAuthorization(["admin"]), validation(roleSchema), isUserExist, userControllers.updateUserRole); router.get("/admin-get-users-request", userAuthorization(["admin"]),isSellerRequestExist,userControllers.adminGetAllSellerRequested); router.get("/admin-get-user-request/:userId", userAuthorization(["admin"]),isSellerRequestExist,userControllers.adminGetRequestDetails); router.put("/admin-accept-or-reject-request/:userId", userAuthorization(["admin"]),isSellerRequestExist,isRequestAcceptedOrRejected,userControllers.adminAcceptOrDenyRequest); router.delete("/admin-delete-user-request/:userId/:id", userAuthorization(["admin"]),isSellerRequestExist,userControllers.adminDeleteSellerRequest); + router.get("/admin-get-users-request", userAuthorization(["admin"]),isSellerRequestExist,userControllers.adminGetAllSellerRequested); + router.get("/admin-get-user-request/:userId", userAuthorization(["admin"]),isSellerRequestExist,userControllers.adminGetRequestDetails); + router.put("/admin-accept-or-reject-request/:userId", userAuthorization(["admin"]),isSellerRequestExist,isRequestAcceptedOrRejected,userControllers.adminAcceptOrDenyRequest); + router.delete("/admin-delete-user-request/:userId/:id", userAuthorization(["admin"]),isSellerRequestExist,userControllers.adminDeleteSellerRequest); router.put("/admin-update-password-expiration", userAuthorization(["admin"]), validation(passwordExpirationTimeSchema), userControllers.updatePasswordExpirationSetting); router.get("/admin-get-password-expiration", userAuthorization(["admin"]), userControllers.getPasswordExpiration); router.post("/admin-set-terms", userAuthorization(["admin"]), validation(termsSchema),isTermsTypeExist,userControllers.adminSetTermsAndCondition); - router.get("/user-get-terms", userAuthorization(["admin", "buyer", "seller"]),userControllers.adminGetTermsAndCondition); + router.post("/admin-set-terms-with-pdf", userAuthorization(["admin"]), upload.single("pdf"),validation(termsSchema),isTermsTypeExist,userControllers.adminSetTermsAndConditionWithPdf); + router.get("/user-get-terms",userControllers.adminGetTermsAndCondition); router.get("/admin-get-terms/:id", userAuthorization(["admin"]),isTermsAndConditionsExist,userControllers.adminGetSingleTermsAndCondition); - router.put("/admin-update-terms/:id", userAuthorization(["admin"]),isTermsAndConditionsExist,userControllers.adminUpdateTermsAndCondition); + router.put("/admin-update-terms/:id", userAuthorization(["admin"]),upload.single("pdf"),isTermsAndConditionsExist,userControllers.adminUpdateTermsAndCondition); router.delete("/admin-delete-terms/:id", userAuthorization(["admin"]),isTermsAndConditionsExist,userControllers.adminDeleteTermsAndCondition);