Repository: MazenShoaip/e-commerce Branch: main Commit: 8a3642f41cfe Files: 47 Total size: 29.0 KB Directory structure: gitextract_byn377yl/ ├── .gitignore ├── jsconfig.json ├── package.json ├── server.js └── src/ ├── app.js ├── controllers/ │ ├── authController.js │ ├── cartController.js │ ├── notFound.js │ ├── orderController.js │ └── productController.js ├── database/ │ └── database.js ├── db/ │ └── db.js ├── middlewares/ │ └── verifyToken.js ├── repositories/ │ ├── databaseRepository.js │ └── userRepository.js ├── routes/ │ ├── authRouter.js │ ├── cartRoute.js │ ├── orderRoute.js │ ├── productRoute.js │ └── router.js ├── schemas/ │ ├── cartSchema.js │ ├── idSchema.js │ ├── productSchema.js │ ├── productUpdateSchema.js │ ├── userLoginSchema.js │ ├── userSignupSchema.js │ └── verifyEmailSchema.js ├── services/ │ ├── auth/ │ │ ├── loginService.js │ │ ├── refreshTokenService.js │ │ ├── refreshVerifyEmailService.js │ │ ├── signupService.js │ │ └── verifyEmailService.js │ ├── cart/ │ │ ├── getCartService.js │ │ └── setCartService.js │ ├── emailService.js │ ├── order/ │ │ ├── addOrderService.js │ │ └── getOrderService.js │ └── product/ │ ├── addProductService.js │ ├── deleteProductService.js │ ├── getProductsService.js │ └── updateProductService.js └── utils/ ├── appError.js ├── errorsHandle.js ├── generateOTP.js ├── generateToken.js ├── rateLimit.js └── storeRefreshToken.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .gitignore ================================================ # dependencies node_modules/ # environment variables .env toDO.txt ================================================ FILE: jsconfig.json ================================================ { "compilerOptions": { "module": "NodeNext", "moduleResolution": "NodeNext", "paths": { "#repositories/*": ["./src/repositories/*"], "#controllers/*": ["./src/controllers/*"], "#db/*": ["./src/db/*"], "#middlewares/*": ["./src/middlewares/*"], "#routes/*": ["./src/routes/*"], "#schemas/*": ["./src/schemas/*"], "#services/*": ["./src/services/*"], "#utils/*": ["./src/utils/*"], "#src/*": ["./src/*"] } } } ================================================ FILE: package.json ================================================ { "name": "e-commerce", "version": "1.0.0", "description": "", "homepage": "https://github.com/MazenShoaip/e-commerce#readme", "bugs": { "url": "https://github.com/MazenShoaip/e-commerce/issues" }, "repository": { "type": "git", "url": "git+https://github.com/MazenShoaip/e-commerce.git" }, "license": "ISC", "author": "", "type": "module", "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "dependencies": { "bcrypt": "^6.0.0", "cookie-parser": "^1.4.7", "dotenv": "^17.4.2", "express": "^5.2.1", "express-rate-limit": "^8.5.2", "jsonwebtoken": "^9.0.3", "nodemailer": "^8.0.7", "pg": "^8.20.0", "pg-format": "^1.0.4", "smtp-server": "^3.18.4", "zod": "^4.4.1" }, "imports": { "#repositories/*": "./src/repositories/*", "#controllers/*": "./src/controllers/*", "#db/*": "./src/db/*", "#middlewares/*": "./src/middlewares/*", "#routes/*": "./src/routes/*", "#schemas/*": "./src/schemas/*", "#services/*": "./src/services/*", "#utils/*": "./src/utils/*", "#src/*": "./src/*" } } ================================================ FILE: server.js ================================================ // process.on("uncaughtException", (err) => { // console.error("UNCAUGHT EXCEPTION 💥:", err); // process.exit(1); // }); import app from "#src/app.js"; import AppError from "#utils/appError.js"; async function startServer() { try { app.listen(5000); console.log("Server is Ready"); } catch (err) { console.log("Server is not Ready"); throw new AppError("Server Error", 500); // process.exit(1); } } await startServer(); // process.on("unhandledRejection", (err) => { // console.error("UNHANDLED REJECTION 💥:", err); // process.exit(1); // }); ================================================ FILE: src/app.js ================================================ import express from "express"; import cookieParser from "cookie-parser"; import errorsHandle from "#utils/errorsHandle.js"; import notFound from "#controllers/notFound.js"; import router from "#routes/router.js"; const app = express(); app.use(express.json()); app.use(cookieParser()); app.use('/', router) app.use(notFound); app.use(errorsHandle); export default app; ================================================ FILE: src/controllers/authController.js ================================================ import signupService from "#services/auth/signupService.js"; import loginService from "#services/auth/loginService.js"; import refreshTokenService from "#services/auth/refreshTokenService.js"; import refreshVerifyEmailService from "#services/auth/refreshVerifyEmailService.js"; import verifyEmailService from "#services/auth/verifyEmailService.js"; export async function loginController(req, res, next) { let result = await loginService(req.body, res); res.status(200).json({ success: true, ...result }); } export async function signupController(req, res, next) { let result = await signupService(req.body); res.status(201).json({ success: true, ...result }); } export async function verifyEmailController(req, res, next) { let result = await verifyEmailService(req.body); res.status(201).json({ success: true, ...result }); } export async function refreshVerifyEmailController(req, res, next) { let result = await refreshVerifyEmailService(req.body); res.status(201).json({ success: true, ...result }); } export async function refreshTokenController(req, res, next) { let result = await refreshTokenService(req.cookies.refreshToken, res); res.status(200).json({ success: true, ...result }); } ================================================ FILE: src/controllers/cartController.js ================================================ import setCartService from "#services/cart/setCartService.js"; import getCartService from "#services/cart/getCartService.js"; export async function setCartController(req, res, next) { let result = await setCartService(req.body, req.user); res.status(201).json({ success: true, ...result }); } export async function getCartController(req, res, next) { let result = await getCartService(req.user); res.status(200).json({ success: true, result }); } ================================================ FILE: src/controllers/notFound.js ================================================ import AppError from "#utils/appError.js"; export default function notFound(req, res, next) { next(new AppError("Route was not found", 404)); } ================================================ FILE: src/controllers/orderController.js ================================================ import addOrderService from "#services/order/addOrderService.js"; import getOrderService from "#services/order/getOrderService.js"; export async function addOrderController(req, res, next) { let result = await addOrderService(req.body, req.user); res.status(201).json({ success: true, ...result }); } export async function getOrderController(req, res, next) { let result = await getOrderService(req.user); res.status(200).json({ success: true, result }); } ================================================ FILE: src/controllers/productController.js ================================================ import addProductService from "#services/product/addProductService.js"; import updateProductService from "#services/product/updateProductService.js"; import getProductsService from "#services/product/getProductsService.js"; import removeProductService from "#services/product/deleteProductService.js"; import AppError from "#utils/appError.js"; export async function addProductController(req, res, next) { if (req.user.role !== "admin") throw new AppError("Access Denied", 401); let result = await addProductService(req.body); res.status(201).json({ success: true, ...result }); } export async function removeProductController(req, res, next) { if (req.user.role !== "admin") throw new AppError("Access Denied", 401); let result = await removeProductService(req.body); if (result.result === 0) throw new AppError("Item was not found", 400); res.status(200).json({ success: true, ...result }); } export async function updateProductController(req, res, next) { if (req.user.role !== "admin") throw new AppError("Access Denied", 401); let result = await updateProductService(req.body); if (result.matchedCount === 0) throw new AppError("Item was not found", 400); res.status(200).json({ success: true, result }); } export async function getProductsController(req, res, next) { let result = await getProductsService(); res.status(200).json({ success: true, result }); } ================================================ FILE: src/database/database.js ================================================ import { configDotenv } from "dotenv"; import { Pool } from "pg"; configDotenv(); const pool = new Pool({ connectionString: process.env.DATABASE_URL, }); export default pool; ================================================ FILE: src/db/db.js ================================================ import { MongoClient } from "mongodb"; import { configDotenv } from "dotenv"; import AppError from "#utils/appError.js"; configDotenv(); let db; export default async function connectDB() { const client = new MongoClient(process.env.MONGO_URI); await client.connect(); // await client.db("ecommerce").dropDatabase(); db = client.db("ecommerce"); await db .collection("pendingUsers") .createIndex({ createdAt: 1 }, { expireAfterSeconds: 300 }); await db .collection("refreshTokens") .createIndex( { createdAt: 1 }, { expireAfterSeconds: 7 * 24 * 60 * 60 }, ); console.log("MongoDB connected"); return db; } export function getDB() { if (!db) // db = await connectDB() throw new AppError("Database Error", 500); return db } ================================================ FILE: src/middlewares/verifyToken.js ================================================ import { configDotenv } from "dotenv"; import jwt from "jsonwebtoken"; import AppError from "#utils/appError.js"; configDotenv(); export default function verifyToken(req, res, next) { let token = String(req.headers.authorization).split(" ")[1]; let user; try { user = jwt.verify(token, process.env.ACCESS_JWT_KEY); } catch (err) { throw new AppError("Access Denied", 401); } if (user.type !== "access") throw AppError("Access Denied", 401); req.user = user; next(); } ================================================ FILE: src/repositories/databaseRepository.js ================================================ import pool from "#src/database/database.js"; import AppError from "#utils/appError.js"; import format from "pg-format"; export async function addItem(data, relation) { let keys = Object.keys(data); let values = Object.values(data); let query = format( "INSERT INTO %I (%I) VALUES (%L) RETURNING id", relation, keys, values, ); let result = await pool.query(query); return result; } export async function addItems(data, relation, chunkSize = 1000) { let keys = Object.keys(data[0]); let results = []; for (let i = 0; i < data.length; i += chunkSize) { let chunk = data.slice(i, i + chunkSize); let values = chunk.map((obj) => keys.map((k) => obj[k])); let query = format( "INSERT INTO %I (%I) VALUES %L RETURNING id", relation, keys, values, ); let result = await pool.query(query); results.push(result.rows); } return results; } export async function findItem(data, relation, limit = "ALL", common = true) { let keys = Object.keys(data); let values = Object.values(data); if (keys.length === 0) return (await pool.query(format("SELECT * FROM %I", relation))).rows; if (limit !== "ALL" && isNaN(limit)) throw new AppError("Limit must be a number", 500); let conditions = keys .map((k, i) => { return format("%I = %L", k, values[i]); }) .join(` ${common ? "AND" : "OR"} `); let query = format( "SELECT * FROM %I WHERE (%s) LIMIT %s", relation, conditions, limit, ); let result = await pool.query(query); return result; } export async function updateItem(data, filters, relation, common = true) { const dataKeys = Object.keys(data); const dataValues = Object.values(data); const setClause = dataKeys .map((k, i) => format("%I = %L", k, dataValues[i])) .join(", "); const filterKeys = Object.keys(filters); const filterValues = Object.values(filters); if (filterKeys.length === 0) { throw new AppError( "You must provide at least one filter to update a row safely.", 500, ); } const whereClause = filterKeys .map((k, i) => format("%I = %L", k, filterValues[i])) .join(` ${common ? "AND" : "OR"} `); let query = format( "UPDATE %I SET %s WHERE %s", relation, setClause, whereClause, ); let result = await pool.query(query); return result; } export async function deleteItem(filters, relation, common = true) { const filterKeys = Object.keys(filters); const filterValues = Object.values(filters); if (filterKeys.length === 0) { throw new AppError( "You must provide at least one filter to delete a row safely.", 500, ); } const whereClause = filterKeys .map((k, i) => format("%I = %L", k, filterValues[i])) .join(` ${common ? "AND" : "OR"} `); let query = format("DELETE FROM %I WHERE %s", relation, whereClause); let result = await pool.query(query); return result; } export async function setCart(data) { let items = data.items; let user_id = data.user_id; for (let i of items) { if (!i.quantity) { await deleteItem({ product_id: i.product_id, user_id }, "carts"); continue; } let item = ( await findItem({ product_id: i.product_id, user_id }, "carts") ).rows[0]; if (!item) { await addItem({ user_id, ...i }, "carts"); continue; } await updateItem( { quantity: i.quantity }, { id: item.id, user_id }, "carts", ); } } export async function setOrder(data) { let items = data.items; let user_id = data.user_id; let address = data.address; let verified_items = []; let stocks = []; let balance = 0; let order_id = (await addItem({ user_id, address, balance }, "orders")) .rows[0]; for (let i of items) { let itemDB = (await findItem({ id: i.product_id }, "products")).rows[0]; if (itemDB.stock < i.quantity) { await deleteItem({ id: order_id.id }, "orders"); throw new AppError("Not enough stock of " + itemDB.product, 400); } balance += i.quantity * itemDB.price; verified_items.push({ product_id: i.product_id, order_id: order_id.id, quantity: i.quantity, }); stocks.push({ product_id: i.product_id, stock: itemDB.stock - i.quantity, }); } for (let i of stocks) { await updateItem({ stock: i.stock }, { id: i.product_id }, "products"); } addItems(verified_items, "orders_items"); await updateItem({ balance }, { id: order_id.id }, "orders"); await deleteItem({ user_id }, "carts"); } ================================================ FILE: src/repositories/userRepository.js ================================================ import pool from "#src/database/database.js"; async function getUsers() { return pool.query("SELECT * FROM users limit 1"); } async function getUser(info) { return pool.query("SELECT * FROM users "); } console.log((await getUsers()).rows) ================================================ FILE: src/routes/authRouter.js ================================================ import express from "express"; import * as authController from "#controllers/authController.js"; import setLimit from "#utils/rateLimit.js"; const authRoute = express.Router(); authRoute.post("/login", setLimit(10, 1), authController.loginController); authRoute.post("/signup",setLimit(10, 10), authController.signupController); authRoute.post("/otp/email",setLimit(5, 1), authController.verifyEmailController); authRoute.post( "/otp/refresh/email", authController.refreshVerifyEmailController, ); authRoute.post("/token/refresh",setLimit(3, 1), authController.refreshTokenController); export default authRoute; ================================================ FILE: src/routes/cartRoute.js ================================================ import express from "express"; import * as cartController from "#controllers/cartController.js"; import verifyToken from "#middlewares/verifyToken.js"; const cartRoute = express.Router(); cartRoute.post("/add", verifyToken, cartController.setCartController); // cartRoute.delete("/delete", verifyToken, cartController.removeCartController); // cartRoute.patch("/update", verifyToken, cartController.updateCartController); cartRoute.get("/", verifyToken, cartController.getCartController); export default cartRoute; ================================================ FILE: src/routes/orderRoute.js ================================================ import express from "express"; import * as orderController from "#controllers/orderController.js"; import verifyToken from "#middlewares/verifyToken.js"; const orderRoute = express.Router(); orderRoute.post("/add", verifyToken, orderController.addOrderController); orderRoute.get("/", verifyToken, orderController.getOrderController); export default orderRoute; ================================================ FILE: src/routes/productRoute.js ================================================ import express from "express"; import * as productController from "#controllers/productController.js"; import verifyToken from "#middlewares/verifyToken.js"; const productRoute = express.Router(); productRoute.post("/add", verifyToken, productController.addProductController); productRoute.delete( "/delete", verifyToken, productController.removeProductController, ); productRoute.patch( "/update", verifyToken, productController.updateProductController, ); productRoute.get("/products", productController.getProductsController); export default productRoute; ================================================ FILE: src/routes/router.js ================================================ import express from 'express' import authRoute from '#routes/authRouter.js' import productRoute from "#routes/productRoute.js"; import cartRoute from '#routes/cartRoute.js'; import setLimit from "#utils/rateLimit.js"; import orderRoute from './orderRoute.js'; let router = express.Router() router.use(setLimit(100, 1)) router.use('/auth', authRoute) router.use('/product', productRoute) router.use('/cart', cartRoute) router.use('/order', orderRoute) export default router ================================================ FILE: src/schemas/cartSchema.js ================================================ import { z } from "zod"; let cartElement = z.object({ product_id: z.number().int().min(0), quantity: z.number().int().min(0), }); let cartSchema = z.object({ cart: z.array(cartElement).min(1), }); export default cartSchema; ================================================ FILE: src/schemas/idSchema.js ================================================ import { z } from "zod"; let idSchema = z.object({ id: z.string().min(1), }); export default idSchema; ================================================ FILE: src/schemas/productSchema.js ================================================ import { z } from "zod"; let productSchema = z.object({ product: z.string().min(3), stock: z.int().min(0), price: z.number().min(0) }); export default productSchema; ================================================ FILE: src/schemas/productUpdateSchema.js ================================================ import { z } from "zod"; let productUpdateSchema = z.object({ id: z.string().min(1), product: z.string().min(3).optional(), stock: z.int().min(0).optional(), price: z.number().min(0).optional() }); export default productUpdateSchema; ================================================ FILE: src/schemas/userLoginSchema.js ================================================ import { z } from "zod"; let userLoginSchema = z.object({ username: z.string().min(3).optional(), email: z.email("invalid email").optional(), password: z.string().min(8), }); export default userLoginSchema; ================================================ FILE: src/schemas/userSignupSchema.js ================================================ import { z } from "zod"; let userSignupSchema = z.object({ username: z.string().min(3), password: z.string().min(8), email: z.email("invalid email"), }); export default userSignupSchema; ================================================ FILE: src/schemas/verifyEmailSchema.js ================================================ import { z } from "zod"; let verifyEmailSchema = z.object({ id: z.string().min(1), otp: z.string().length(7), }); export default verifyEmailSchema; ================================================ FILE: src/services/auth/loginService.js ================================================ import userLoginSchema from "#schemas/userLoginSchema.js"; import AppError from "#utils/appError.js"; import bcrypt from "bcrypt"; import generateToken from "#utils/generateToken.js"; import storeRefreshToken from "#utils/storeRefreshToken.js"; import { findItem } from "#repositories/databaseRepository.js"; export default async function loginService(body, res) { let verify = userLoginSchema.safeParse(body); if (!verify.success) throw new AppError("Invalid " + verify.error.issues[0].path[0], 400); let data = verify.data; if (!data.username && !data.email) throw new AppError("Invalid Data", 400); let id = data.email || data.username; let user = (await findItem({ username: id, email: id }, "users", 'ALL', false)) .rows[0]; if (!user) throw new AppError("User is not found", 404); let passwordMatch = await bcrypt.compare(data.password, user.password); if (!passwordMatch) throw new AppError("Invalid email or password", 401); let accessToken = await generateToken( { sub: user.id, role: user.role }, "access", "1d", ); let refreshToken = await generateToken( { sub: user.id, role: user.role }, "refresh", "1d", ); storeRefreshToken(refreshToken, res); return { accessToken }; } ================================================ FILE: src/services/auth/refreshTokenService.js ================================================ import { configDotenv } from "dotenv"; import { deleteItem } from "#repositories/databaseRepository.js"; import AppError from "#utils/appError.js"; import generateToken from "#utils/generateToken.js"; import storeRefreshToken from "#utils/storeRefreshToken.js"; import jwt from "jsonwebtoken"; configDotenv(); export default async function refreshTokenService(token, res) { let user; try { user = jwt.verify(token, process.env.REFRESH_JWT_KEY); } catch (err) { throw new AppError("Access Denied", 401); } if (user.type !== "refresh") throw new AppError("Access Denied", 401); let tokenUser = (await deleteItem({ jti: user.jti }, "tokens")).rowCount; if (!tokenUser) throw new AppError("Access Denied", 401); let accessToken = await generateToken( { sub: user.sub, role: user.role }, "access", "15m", ); let refreshToken = await generateToken( { sub: user.sub, role: user.role }, "refresh", "1d", ); storeRefreshToken(refreshToken, res); return { success: true, accessToken }; } ================================================ FILE: src/services/auth/refreshVerifyEmailService.js ================================================ import idSchema from "#schemas/idSchema.js"; import AppError from "#utils/appError.js"; import bcrypt from "bcrypt"; import generateOTP from "#utils/generateOTP.js"; import sendEmail from "#services/emailService.js"; import { findItem, updateItem } from "#repositories/databaseRepository.js"; export default async function refreshVerifyEmailService(body) { let verify = idSchema.safeParse(body); if (!verify.success) throw new AppError("Invalid " + verify.error.issues[0].path[0], 400); let data = verify.data; let user = (await findItem({ id: data.id }, "pending_users")).rows[0]; if (!user) throw new AppError("ID was not found", 400); let otp = generateOTP(); let hashedOTP = await bcrypt.hash(String(otp), 10); await updateItem( { otp: hashedOTP, created_at: new Date().toISOString() }, { id: data.id }, "pending_users", ); await sendEmail({ to: user.email, subject: "otp code", text: `Your otp is ${otp}`, }); return { success: true, message: "OTP refresh message is sent" }; } ================================================ FILE: src/services/auth/signupService.js ================================================ import userSignupSchema from "#schemas/userSignupSchema.js"; import AppError from "#utils/appError.js"; import bcrypt from "bcrypt"; import sendEmail from "#services/emailService.js"; import generateOTP from "#utils/generateOTP.js"; import { addItem, findItem } from "#repositories/databaseRepository.js"; export default async function signupService(body) { let verify = userSignupSchema.safeParse(body); if (!verify.success) throw new AppError("Invalid " + verify.error.issues[0].path[0], 400); let data = verify.data; let foundUsers = ( await findItem( { username: data.username, email: data.email }, "users", 1, false, ) ).rows[0]; if (foundUsers) { let err = foundUsers.username == data.username ? "Username" : "Email"; throw new AppError(err, "is already used", 409); } let password = await bcrypt.hash(data.password, 10); let otpCode = generateOTP(); let otp = await bcrypt.hash(String(otpCode), 10); let signupData = { ...data, password, otp, role: "user" }; let result = await addItem(signupData, "pending_users"); await sendEmail({ to: signupData.email, subject: "otp code", text: `Your otp is ${otpCode}`, }); return { success: true, id: result.rows[0].id, message: "Message is sent" }; } ================================================ FILE: src/services/auth/verifyEmailService.js ================================================ import { addItem, findItem } from "#repositories/databaseRepository.js"; import verifyEmailSchema from "#schemas/verifyEmailSchema.js"; import AppError from "#utils/appError.js"; import bcrypt from "bcrypt"; export default async function verifyEmailService(body) { let verify = verifyEmailSchema.safeParse(body); if (!verify.success) throw new AppError("Invalid " + verify.error.issues[0].path[0], 400); let data = verify.data; let user = (await findItem({ id: data.id }, "pending_users")).rows[0]; if (!user) throw new AppError("ID was not found", 404); if (300000 < Date.now() - new Date(user.created_at + "Z").getTime()) throw new AppError("Expired OTP", 401); let match = await bcrypt.compare(data.otp, user.otp); if (!match) throw new AppError("Invalid OTP", 401); let foundUsers = ( await findItem( { username: user.username, email: user.email }, "users", 1, false, ) ).rows[0]; if (foundUsers) { let err = foundUsers.username == data.username ? "Username" : "Email"; throw new AppError(err + " is already used", 409); } delete user.otp; delete user.created_at; await addItem(user, "users"); return { success: true, message: "Email verified" }; } ================================================ FILE: src/services/cart/getCartService.js ================================================ import { findItem } from "#repositories/databaseRepository.js"; export default async function getCartService(user) { console.log(user) let result = await findItem({ user_id: user.sub }, "carts"); return { cart: result.cart, }; } ================================================ FILE: src/services/cart/setCartService.js ================================================ import { updateItem, findItem, setCart, } from "#repositories/databaseRepository.js"; import AppError from "#utils/appError.js"; import cartSchema from "#schemas/cartSchema.js"; export default async function setCartService(items, user) { let verify = cartSchema.safeParse(items); if (!verify.success) throw new AppError("Invalid " + verify.error.issues[0].path[0], 400); let data = { items: verify.data.cart, user_id: user.sub }; // let badCart = []; // for (let i = 0; i < data.length; i++) { // let item = await findItem({ _id: data[i] }, "products"); // if (!item) badCart.push(item); // } // if (badCart.length > 0) // throw new AppError(`${badCart} Does not Exist`, 400); let result = await setCart(data); return { id: result, message: "Product is added", }; } ================================================ FILE: src/services/emailService.js ================================================ import nodemailer from "nodemailer"; import { configDotenv } from "dotenv"; configDotenv(); const transporter = nodemailer.createTransport({ host: process.env.EMAIL_HOST, port: 587, auth: { user: process.env.EMAIL_USER, pass: process.env.EMAIL_PASSWORD, }, }); export default async function sendEmail(mail) { const info = await transporter.sendMail({ from: process.env.EMAIL_USER, to: mail.to, subject: mail.subject, text: mail.text, }); // console.log("Message sent:", info.messageId); console.log("Preview URL:", nodemailer.getTestMessageUrl(info)); return {success:true, message: "Message is sent"}; } // sendEmail({ to: "test1@user.com", subject: "test subject", text: "text ENV" }); ================================================ FILE: src/services/order/addOrderService.js ================================================ import { findItem, setOrder } from "#repositories/databaseRepository.js"; import AppError from "#utils/appError.js"; export default async function setOrderService(items, user) { let order = (await findItem({ user_id: user.sub }, "carts")).rows; let data = { items: order, user_id: user.sub, address: user.role, }; let result = await setOrder(data); return { id: result, message: "Order is added", }; } ================================================ FILE: src/services/order/getOrderService.js ================================================ import { findItem } from "#repositories/databaseRepository.js"; export default async function getCartService(user) { let result = await findItem({ user_id: user.sub }, "orders"); return { orders: result.rows, }; } ================================================ FILE: src/services/product/addProductService.js ================================================ import { addItem } from "#repositories/databaseRepository.js"; import AppError from "#utils/appError.js"; import productSchema from "#schemas/productSchema.js"; export default async function addProductService(body) { let verify = productSchema.safeParse(body); if (!verify.success) throw new AppError("Invalid " + verify.error.issues[0].path[0], 400); let data = verify.data; let result = (await addItem(data, 'products')).rows[0].id; return { id: result, message: "Product is added", }; } ================================================ FILE: src/services/product/deleteProductService.js ================================================ import { deleteItem } from "#repositories/databaseRepository.js"; import AppError from "#utils/appError.js"; import idSchema from "#schemas/idSchema.js"; export default async function removeProductService(body) { let verify = idSchema.safeParse(body); if (!verify.success) throw new AppError("Invalid " + verify.error.issues[0].path[0], 400); let data = { id: verify.data.id }; let result = await deleteItem(data, "products"); return { deletedCount: result.rowCount, }; } ================================================ FILE: src/services/product/getProductsService.js ================================================ import { findItem } from "#repositories/databaseRepository.js"; export default async function getProductsService() { let result = await findItem({}, "products"); return { items: result, }; } ================================================ FILE: src/services/product/updateProductService.js ================================================ import { updateItem } from "#repositories/databaseRepository.js"; import AppError from "#utils/appError.js"; import productUpdateSchema from "#schemas/productUpdateSchema.js"; export default async function updateProductService(body) { let verify = productUpdateSchema.safeParse(body); if (!verify.success) throw new AppError("Invalid " + verify.error.issues[0].path[0], 400); let data = verify.data; let id = data.id; delete data.id; let result = await updateItem(data, { id }, "products"); return { matchedCount: result.rowCount, }; } ================================================ FILE: src/utils/appError.js ================================================ export default class AppError extends Error { constructor(message, status) { super(message); this.status = status; this.isOperational = true; } } ================================================ FILE: src/utils/errorsHandle.js ================================================ export default function errorsHandle(err, req, res, next) { console.log("This error handler"); res.status(err.status || 500).json({ success: false, message: err.message || "Internal Server Error", }); } ================================================ FILE: src/utils/generateOTP.js ================================================ import crypto from "crypto" export default function generateOTP() { return crypto.randomInt(1000000, 9999999) } ================================================ FILE: src/utils/generateToken.js ================================================ import jwt from "jsonwebtoken"; import crypto from "crypto"; import { configDotenv } from "dotenv"; import { addItem } from "#repositories/databaseRepository.js"; configDotenv(); export default async function generateToken(user, type, expire) { let jti = crypto.randomUUID(); let token = jwt.sign( { ...user, jti, type, createdAt: new Date() }, process.env[type.toUpperCase() + "_JWT_KEY"], { expiresIn: expire, }, ); if (type == "refresh") await addItem({ jti: jti }, "tokens"); return token; } // console.log(await generateToken({ user: "demo" },'access', "7d")); ================================================ FILE: src/utils/rateLimit.js ================================================ import rateLimit from "express-rate-limit"; export default function setLimit(limit, time) { return rateLimit({ windowMs: time * 60 * 1000, limit, message: {error: "Too many requests"}, standardHeaders: true, legacyHeaders: true, }); } ================================================ FILE: src/utils/storeRefreshToken.js ================================================ export default function storeRefreshToken(token, res) { res.cookie("refreshToken", token, { httpOnly: true, secure: false, sameSite: "strict", path: "/auth/token/refresh", }); }