Full Code of MazenShoaip/e-commerce for AI

main 8a3642f41cfe cached
47 files
29.0 KB
8.3k tokens
48 symbols
3 requests
Download .txt
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",
    });
}
Download .txt
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
Download .txt
SYMBOL INDEX (48 symbols across 30 files)

FILE: server.js
  function startServer (line 8) | async function startServer() {

FILE: src/controllers/authController.js
  function loginController (line 7) | async function loginController(req, res, next) {
  function signupController (line 12) | async function signupController(req, res, next) {
  function verifyEmailController (line 17) | async function verifyEmailController(req, res, next) {
  function refreshVerifyEmailController (line 22) | async function refreshVerifyEmailController(req, res, next) {
  function refreshTokenController (line 27) | async function refreshTokenController(req, res, next) {

FILE: src/controllers/cartController.js
  function setCartController (line 4) | async function setCartController(req, res, next) {
  function getCartController (line 9) | async function getCartController(req, res, next) {

FILE: src/controllers/notFound.js
  function notFound (line 3) | function notFound(req, res, next) {

FILE: src/controllers/orderController.js
  function addOrderController (line 4) | async function addOrderController(req, res, next) {
  function getOrderController (line 9) | async function getOrderController(req, res, next) {

FILE: src/controllers/productController.js
  function addProductController (line 7) | async function addProductController(req, res, next) {
  function removeProductController (line 12) | async function removeProductController(req, res, next) {
  function updateProductController (line 18) | async function updateProductController(req, res, next) {
  function getProductsController (line 25) | async function getProductsController(req, res, next) {

FILE: src/db/db.js
  function connectDB (line 6) | async function connectDB() {
  function getDB (line 24) | function getDB()

FILE: src/middlewares/verifyToken.js
  function verifyToken (line 5) | function verifyToken(req, res, next) {

FILE: src/repositories/databaseRepository.js
  function addItem (line 5) | async function addItem(data, relation) {
  function addItems (line 17) | async function addItems(data, relation, chunkSize = 1000) {
  function findItem (line 36) | async function findItem(data, relation, limit = "ALL", common = true) {
  function updateItem (line 58) | async function updateItem(data, filters, relation, common = true) {
  function deleteItem (line 87) | async function deleteItem(filters, relation, common = true) {
  function setCart (line 106) | async function setCart(data) {
  function setOrder (line 128) | async function setOrder(data) {

FILE: src/repositories/userRepository.js
  function getUsers (line 3) | async function getUsers() {
  function getUser (line 7) | async function getUser(info) {

FILE: src/services/auth/loginService.js
  function loginService (line 7) | async function loginService(body, res) {

FILE: src/services/auth/refreshTokenService.js
  function refreshTokenService (line 9) | async function refreshTokenService(token, res) {

FILE: src/services/auth/refreshVerifyEmailService.js
  function refreshVerifyEmailService (line 7) | async function refreshVerifyEmailService(body) {

FILE: src/services/auth/signupService.js
  function signupService (line 8) | async function signupService(body) {

FILE: src/services/auth/verifyEmailService.js
  function verifyEmailService (line 5) | async function verifyEmailService(body) {

FILE: src/services/cart/getCartService.js
  function getCartService (line 3) | async function getCartService(user) {

FILE: src/services/cart/setCartService.js
  function setCartService (line 9) | async function setCartService(items, user) {

FILE: src/services/emailService.js
  function sendEmail (line 13) | async function sendEmail(mail) {

FILE: src/services/order/addOrderService.js
  function setOrderService (line 4) | async function setOrderService(items, user) {

FILE: src/services/order/getOrderService.js
  function getCartService (line 3) | async function getCartService(user) {

FILE: src/services/product/addProductService.js
  function addProductService (line 5) | async function addProductService(body) {

FILE: src/services/product/deleteProductService.js
  function removeProductService (line 5) | async function removeProductService(body) {

FILE: src/services/product/getProductsService.js
  function getProductsService (line 3) | async function getProductsService() {

FILE: src/services/product/updateProductService.js
  function updateProductService (line 5) | async function updateProductService(body) {

FILE: src/utils/appError.js
  class AppError (line 1) | class AppError extends Error {
    method constructor (line 2) | constructor(message, status) {

FILE: src/utils/errorsHandle.js
  function errorsHandle (line 1) | function errorsHandle(err, req, res, next) {

FILE: src/utils/generateOTP.js
  function generateOTP (line 3) | function generateOTP()

FILE: src/utils/generateToken.js
  function generateToken (line 8) | async function generateToken(user, type, expire) {

FILE: src/utils/rateLimit.js
  function setLimit (line 3) | function setLimit(limit, time) {

FILE: src/utils/storeRefreshToken.js
  function storeRefreshToken (line 1) | function storeRefreshToken(token, res) {
Condensed preview — 47 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (34K chars).
[
  {
    "path": ".gitignore",
    "chars": 68,
    "preview": "# dependencies\nnode_modules/\n\n# environment variables\n.env\ntoDO.txt\n"
  },
  {
    "path": "jsconfig.json",
    "chars": 556,
    "preview": "{\n    \"compilerOptions\": {\n        \"module\": \"NodeNext\",\n        \"moduleResolution\": \"NodeNext\",\n        \"paths\": {\n    "
  },
  {
    "path": "package.json",
    "chars": 1283,
    "preview": "{\n    \"name\": \"e-commerce\",\n    \"version\": \"1.0.0\",\n    \"description\": \"\",\n    \"homepage\": \"https://github.com/MazenShoa"
  },
  {
    "path": "server.js",
    "chars": 614,
    "preview": "// process.on(\"uncaughtException\", (err) => {\n//     console.error(\"UNCAUGHT EXCEPTION 💥:\", err);\n//     process.exit(1)"
  },
  {
    "path": "src/app.js",
    "chars": 371,
    "preview": "import express from \"express\";\nimport cookieParser from \"cookie-parser\";\nimport errorsHandle from \"#utils/errorsHandle.j"
  },
  {
    "path": "src/controllers/authController.js",
    "chars": 1239,
    "preview": "import signupService from \"#services/auth/signupService.js\";\nimport loginService from \"#services/auth/loginService.js\";\n"
  },
  {
    "path": "src/controllers/cartController.js",
    "chars": 465,
    "preview": "import setCartService from \"#services/cart/setCartService.js\";\nimport getCartService from \"#services/cart/getCartService"
  },
  {
    "path": "src/controllers/notFound.js",
    "chars": 149,
    "preview": "import AppError from \"#utils/appError.js\";\n\nexport default function notFound(req, res, next) {\n    next(new AppError(\"Ro"
  },
  {
    "path": "src/controllers/orderController.js",
    "chars": 475,
    "preview": "import addOrderService from \"#services/order/addOrderService.js\";\nimport getOrderService from \"#services/order/getOrderS"
  },
  {
    "path": "src/controllers/productController.js",
    "chars": 1427,
    "preview": "import addProductService from \"#services/product/addProductService.js\";\nimport updateProductService from \"#services/prod"
  },
  {
    "path": "src/database/database.js",
    "chars": 179,
    "preview": "import { configDotenv } from \"dotenv\";\nimport { Pool } from \"pg\";\nconfigDotenv();\nconst pool = new Pool({\n    connection"
  },
  {
    "path": "src/db/db.js",
    "chars": 841,
    "preview": "import { MongoClient } from \"mongodb\";\nimport { configDotenv } from \"dotenv\";\nimport AppError from \"#utils/appError.js\";"
  },
  {
    "path": "src/middlewares/verifyToken.js",
    "chars": 516,
    "preview": "import { configDotenv } from \"dotenv\";\nimport jwt from \"jsonwebtoken\";\nimport AppError from \"#utils/appError.js\";\nconfig"
  },
  {
    "path": "src/repositories/databaseRepository.js",
    "chars": 5018,
    "preview": "import pool from \"#src/database/database.js\";\nimport AppError from \"#utils/appError.js\";\nimport format from \"pg-format\";"
  },
  {
    "path": "src/repositories/userRepository.js",
    "chars": 248,
    "preview": "import pool from \"#src/database/database.js\";\n\nasync function getUsers() {\n    return pool.query(\"SELECT * FROM users li"
  },
  {
    "path": "src/routes/authRouter.js",
    "chars": 622,
    "preview": "import express from \"express\";\nimport * as authController from \"#controllers/authController.js\";\nimport setLimit from \"#"
  },
  {
    "path": "src/routes/cartRoute.js",
    "chars": 517,
    "preview": "import express from \"express\";\nimport * as cartController from \"#controllers/cartController.js\";\nimport verifyToken from"
  },
  {
    "path": "src/routes/orderRoute.js",
    "chars": 364,
    "preview": "import express from \"express\";\nimport * as orderController from \"#controllers/orderController.js\";\nimport verifyToken fr"
  },
  {
    "path": "src/routes/productRoute.js",
    "chars": 585,
    "preview": "import express from \"express\";\nimport * as productController from \"#controllers/productController.js\";\nimport verifyToke"
  },
  {
    "path": "src/routes/router.js",
    "chars": 476,
    "preview": "import express from 'express'\nimport authRoute from '#routes/authRouter.js'\nimport productRoute from \"#routes/productRou"
  },
  {
    "path": "src/schemas/cartSchema.js",
    "chars": 236,
    "preview": "import { z } from \"zod\";\nlet cartElement = z.object({\n    product_id: z.number().int().min(0),\n    quantity: z.number()."
  },
  {
    "path": "src/schemas/idSchema.js",
    "chars": 108,
    "preview": "import { z } from \"zod\";\nlet idSchema = z.object({\n    id: z.string().min(1),\n});\n\nexport default idSchema;\n"
  },
  {
    "path": "src/schemas/productSchema.js",
    "chars": 180,
    "preview": "import { z } from \"zod\";\nlet productSchema = z.object({\n    product: z.string().min(3),\n    stock: z.int().min(0),\n    p"
  },
  {
    "path": "src/schemas/productUpdateSchema.js",
    "chars": 252,
    "preview": "import { z } from \"zod\";\nlet productUpdateSchema = z.object({\n    id: z.string().min(1),\n    product: z.string().min(3)."
  },
  {
    "path": "src/schemas/userLoginSchema.js",
    "chars": 220,
    "preview": "import { z } from \"zod\";\nlet userLoginSchema = z.object({\n    username: z.string().min(3).optional(),\n    email: z.email"
  },
  {
    "path": "src/schemas/userSignupSchema.js",
    "chars": 201,
    "preview": "import {  z } from \"zod\";\nlet userSignupSchema = z.object({\n    username: z.string().min(3),\n    password: z.string().mi"
  },
  {
    "path": "src/schemas/verifyEmailSchema.js",
    "chars": 157,
    "preview": "import { z } from \"zod\";\nlet verifyEmailSchema = z.object({\n    id: z.string().min(1),\n    otp: z.string().length(7),\n})"
  },
  {
    "path": "src/services/auth/loginService.js",
    "chars": 1313,
    "preview": "import userLoginSchema from \"#schemas/userLoginSchema.js\";\nimport AppError from \"#utils/appError.js\";\nimport bcrypt from"
  },
  {
    "path": "src/services/auth/refreshTokenService.js",
    "chars": 1096,
    "preview": "import { configDotenv } from \"dotenv\";\nimport { deleteItem } from \"#repositories/databaseRepository.js\";\nimport AppError"
  },
  {
    "path": "src/services/auth/refreshVerifyEmailService.js",
    "chars": 1087,
    "preview": "import idSchema from \"#schemas/idSchema.js\";\nimport AppError from \"#utils/appError.js\";\nimport bcrypt from \"bcrypt\";\nimp"
  },
  {
    "path": "src/services/auth/signupService.js",
    "chars": 1373,
    "preview": "import userSignupSchema from \"#schemas/userSignupSchema.js\";\nimport AppError from \"#utils/appError.js\";\nimport bcrypt fr"
  },
  {
    "path": "src/services/auth/verifyEmailService.js",
    "chars": 1314,
    "preview": "import { addItem, findItem } from \"#repositories/databaseRepository.js\";\nimport verifyEmailSchema from \"#schemas/verifyE"
  },
  {
    "path": "src/services/cart/getCartService.js",
    "chars": 254,
    "preview": "import { findItem } from \"#repositories/databaseRepository.js\";\n\nexport default async function getCartService(user) {\n  "
  },
  {
    "path": "src/services/cart/setCartService.js",
    "chars": 867,
    "preview": "import {\n    updateItem,\n    findItem,\n    setCart,\n} from \"#repositories/databaseRepository.js\";\nimport AppError from \""
  },
  {
    "path": "src/services/emailService.js",
    "chars": 774,
    "preview": "import nodemailer from \"nodemailer\";\nimport { configDotenv } from \"dotenv\";\nconfigDotenv();\nconst transporter = nodemail"
  },
  {
    "path": "src/services/order/addOrderService.js",
    "chars": 467,
    "preview": "import { findItem, setOrder } from \"#repositories/databaseRepository.js\";\nimport AppError from \"#utils/appError.js\";\n\nex"
  },
  {
    "path": "src/services/order/getOrderService.js",
    "chars": 235,
    "preview": "import { findItem } from \"#repositories/databaseRepository.js\";\n\nexport default async function getCartService(user) {\n  "
  },
  {
    "path": "src/services/product/addProductService.js",
    "chars": 539,
    "preview": "import { addItem } from \"#repositories/databaseRepository.js\";\nimport AppError from \"#utils/appError.js\";\nimport product"
  },
  {
    "path": "src/services/product/deleteProductService.js",
    "chars": 513,
    "preview": "import { deleteItem } from \"#repositories/databaseRepository.js\";\nimport AppError from \"#utils/appError.js\";\nimport idSc"
  },
  {
    "path": "src/services/product/getProductsService.js",
    "chars": 212,
    "preview": "import { findItem } from \"#repositories/databaseRepository.js\";\n\nexport default async function getProductsService() {\n  "
  },
  {
    "path": "src/services/product/updateProductService.js",
    "chars": 585,
    "preview": "import { updateItem } from \"#repositories/databaseRepository.js\";\nimport AppError from \"#utils/appError.js\";\nimport prod"
  },
  {
    "path": "src/utils/appError.js",
    "chars": 178,
    "preview": "export default class AppError extends Error {\n    constructor(message, status) {\n        super(message);\n        this.st"
  },
  {
    "path": "src/utils/errorsHandle.js",
    "chars": 231,
    "preview": "export default function errorsHandle(err, req, res, next) {\n    console.log(\"This error handler\");\n    res.status(err.st"
  },
  {
    "path": "src/utils/generateOTP.js",
    "chars": 118,
    "preview": "import crypto from \"crypto\"\n\nexport default function generateOTP()\n{\n    return crypto.randomInt(1000000, 9999999)\n}\n\n"
  },
  {
    "path": "src/utils/generateToken.js",
    "chars": 634,
    "preview": "import jwt from \"jsonwebtoken\";\nimport crypto from \"crypto\";\nimport { configDotenv } from \"dotenv\";\nimport { addItem } f"
  },
  {
    "path": "src/utils/rateLimit.js",
    "chars": 284,
    "preview": "import rateLimit from \"express-rate-limit\";\n\nexport default function setLimit(limit, time) {\n    return rateLimit({\n    "
  },
  {
    "path": "src/utils/storeRefreshToken.js",
    "chars": 218,
    "preview": "export default function storeRefreshToken(token, res) {\n    res.cookie(\"refreshToken\", token, {\n        httpOnly: true,\n"
  }
]

About this extraction

This page contains the full source code of the MazenShoaip/e-commerce GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 47 files (29.0 KB), approximately 8.3k tokens, and a symbol index with 48 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!