Repository: hiteshchoudhary/pro-backend-developer
Branch: main
Commit: d876ccc661b5
Files: 91
Total size: 175.0 KB
Directory structure:
gitextract_2i27geyc/
├── formsandimages/
│ ├── index.js
│ ├── package.json
│ └── views/
│ ├── getform.ejs
│ └── postform.ejs
├── lcoauthsystem/
│ ├── app.js
│ ├── config/
│ │ └── database.js
│ ├── index.js
│ ├── middleware/
│ │ └── auth.js
│ ├── model/
│ │ └── user.js
│ └── package.json
├── lcopassportgoogle/
│ ├── index.js
│ ├── model/
│ │ └── user.js
│ ├── package.json
│ ├── passport/
│ │ └── passport.js
│ ├── routes/
│ │ └── auth.js
│ └── views/
│ ├── home.ejs
│ └── login.ejs
├── mydocslco/
│ ├── index.js
│ ├── nodemon.json
│ ├── package.json
│ └── swagger.yaml
├── razorpay/
│ ├── index.js
│ ├── package.json
│ └── public/
│ └── index.html
├── readme.md
├── socialapp/
│ ├── .gitignore
│ ├── index.js
│ ├── nodemon.json
│ ├── package.json
│ └── swagger.yaml
└── tshirtstore/
├── .gitignore
├── README.md
├── app.js
├── config/
│ └── db.js
├── controllers/
│ ├── homeController.js
│ ├── orderController.js
│ ├── paymentController.js
│ ├── productController.js
│ └── userController.js
├── index.js
├── lcotshirtstore/
│ ├── .gitignore
│ ├── app.js
│ ├── config/
│ │ └── db.js
│ ├── controllers/
│ │ ├── homeController.js
│ │ ├── orderController.js
│ │ ├── paymentController.js
│ │ ├── productController.js
│ │ └── userController.js
│ ├── index.js
│ ├── middlewares/
│ │ ├── bigPromise.js
│ │ └── user.js
│ ├── models/
│ │ ├── order.js
│ │ ├── product.js
│ │ └── user.js
│ ├── nodemon.json
│ ├── package.json
│ ├── routes/
│ │ ├── home.js
│ │ ├── order.js
│ │ ├── payment.js
│ │ ├── product.js
│ │ └── user.js
│ ├── swagger.yaml
│ ├── utils/
│ │ ├── cookieToken.js
│ │ ├── customError.js
│ │ ├── demotest.js
│ │ ├── emailHelper.js
│ │ ├── testOrder.json
│ │ └── whereClause.js
│ └── views/
│ └── signuptest.ejs
├── middlewares/
│ ├── bigPromise.js
│ ├── productionError.js
│ └── user.js
├── models/
│ ├── order.js
│ ├── product.js
│ └── user.js
├── nodemon.json
├── package.json
├── routes/
│ ├── home.js
│ ├── order.js
│ ├── payment.js
│ ├── product.js
│ └── user.js
├── swagger.yaml
├── utils/
│ ├── cookieToken.js
│ ├── customError.js
│ ├── demotest.js
│ ├── emailHelper.js
│ ├── testOrder.json
│ └── whereClause.js
└── views/
├── home.ejs
└── signuptest.ejs
================================================
FILE CONTENTS
================================================
================================================
FILE: formsandimages/index.js
================================================
const express = require("express");
const fileUpload = require("express-fileupload");
const cloudinary = require("cloudinary").v2;
const app = express();
cloudinary.config({
// cloud_name: processs.env.CLOUD_NAME
cloud_name: "dk92l1yoc",
api_key: "769888332458168",
api_secret: "7Kh-q81hHRdyDNiBxISrouGEFCo",
});
app.set("view engine", "ejs");
//middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(
fileUpload({
useTempFiles: true,
tempFileDir: "/tmp/",
})
);
app.get("/myget", (req, res) => {
console.log(req.body);
res.send(req.body);
});
app.post("/mypost", async (req, res) => {
console.log(req.body);
console.log(req.files);
let result;
let imageArray = [];
// case - multiple images
if (req.files) {
for (let index = 0; index < req.files.samplefile.length; index++) {
let result = await cloudinary.uploader.upload(
req.files.samplefile[index].tempFilePath,
{
folder: "users",
}
);
imageArray.push({
public_id: result.public_id,
secure_url: result.secure_url,
});
}
}
// ### use case for single image
// let file = req.files.samplefile;
// result = await cloudinary.uploader.upload(file.tempFilePath, {
// folder: "users",
// });
console.log(result);
details = {
firstname: req.body.firstname,
lastname: req.body.lastname,
result,
imageArray,
};
console.log(details);
res.send(details);
});
// just to render the forms
app.get("/mygetform", (req, res) => {
res.render("getform");
});
app.get("/mypostform", (req, res) => {
res.render("postform");
});
app.listen(4000, () => console.log(`Server is runnning at port 4000`));
================================================
FILE: formsandimages/package.json
================================================
{
"name": "formsandimages",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "nodemon index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"cloudinary": "^1.27.1",
"ejs": "^3.1.6",
"express": "^4.17.1",
"express-fileupload": "^1.2.1"
},
"devDependencies": {
"nodemon": "^2.0.13"
}
}
================================================
FILE: formsandimages/views/getform.ejs
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>GET form</title>
</head>
<body class="bg-dark text-white">
<div class="container mt-4 col-4 col-offset-6">
<h1 class="display-3">GET form</h1>
<form method="GET" action="/myget">
<div class="mb-3">
<label for="firstname" class="form-label">firstname</label>
<input type="text" name="firstname" class="form-control" id="firstname" aria-describedby="emailHelp">
<div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
</div>
<div class="mb-3">
<label for="lastname" class="form-label">lastname</label>
<input type="text" name="lastname" class="form-control" id="lastname">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>
================================================
FILE: formsandimages/views/postform.ejs
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>GET form</title>
</head>
<body class="bg-dark text-white">
<div class="container mt-4 col-4 col-offset-6">
<h1 class="display-3">POST form</h1>
<form method="POST" action="/mypost" enctype="multipart/form-data">
<div class="mb-3">
<label for="firstname" class="form-label">firstname</label>
<input type="text" name="firstname" class="form-control" id="firstname" aria-describedby="emailHelp">
<div id="emailHelp" class="form-text">We'll never share your email with anyone else.</div>
</div>
<div class="mb-3">
<label for="lastname" class="form-label">lastname</label>
<input type="text" name="lastname" class="form-control" id="lastname">
</div>
<div class="mb-3">
<label for="samplefile" class="form-label">samplefile</label>
<input type="file" name="samplefile" multiple class="form-control" id="lastname">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>
================================================
FILE: lcoauthsystem/app.js
================================================
require("dotenv").config();
require("./config/database").connect();
const express = require("express");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
var cookieParser = require("cookie-parser");
const User = require("./model/user");
const auth = require("./middleware/auth");
const app = express();
app.use(express.json());
app.use(cookieParser());
app.get("/", (req, res) => {
res.send("<h1>Hello from auth system - LCO</h1>");
});
app.post("/register", async (req, res) => {
try {
const { firstname, lastname, email, password } = req.body;
if (!(email && password && firstname && lastname)) {
res.status(400).send("All fields are required");
}
const existingUser = await User.findOne({ email }); // PROMISE
if (existingUser) {
res.status(401).send("User already exists");
}
const myEncPassword = await bcrypt.hash(password, 10);
const user = await User.create({
firstname,
lastname,
email: email.toLowerCase(),
password: myEncPassword,
});
//token
const token = jwt.sign(
{ user_id: user._id, email },
process.env.SECRET_KEY,
{
expiresIn: "2h",
}
);
user.token = token;
//update or not in DB
// handle password situation
user.password = undefined;
// send token or send just success yes and redirect - choice
res.status(201).json(user);
} catch (error) {
console.log(error);
}
});
app.post("/login", async (req, res) => {
try {
const { email, password } = req.body;
if (!(email && password)) {
res.status(400).send("Field is missing");
}
const user = await User.findOne({ email });
// if(!user){
// res.status(400).send("You are not registered in our app")
// }
if (user && (await bcrypt.compare(password, user.password))) {
const token = jwt.sign(
{ user_id: user._id, email },
process.env.SECRET_KEY,
{
expiresIn: "2h",
}
);
user.token = token;
user.password = undefined;
// res.status(200).json(user);
// if you want to use cookies
const options = {
expires: new Date(Date.now() + 3 * 24 * 60 * 60 * 1000),
httpOnly: true,
};
res.status(200).cookie("token", token, options).json({
success: true,
token,
user,
});
}
res.sendStatus(400).send("email or password is incorrect");
} catch (error) {
console.log(error);
}
});
app.get("/dashboard", auth, (req, res) => {
res.send("Welcome to secret information");
});
module.exports = app;
================================================
FILE: lcoauthsystem/config/database.js
================================================
const mongoose = require("mongoose");
const { MONGODB_URL } = process.env;
exports.connect = () => {
mongoose
.connect(MONGODB_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(console.log(`DB CONNECTED SUCCESSFULLY`))
.catch((error) => {
console.log(`DB CONNECTION FAILED`);
console.log(error);
process.exit(1);
});
};
================================================
FILE: lcoauthsystem/index.js
================================================
const app = require("./app");
const { PORT } = process.env;
app.listen(PORT, () => console.log(`Server is running at port ${PORT}...`));
================================================
FILE: lcoauthsystem/middleware/auth.js
================================================
const jwt = require("jsonwebtoken");
//model is optional
const auth = (req, res, next) => {
console.log(req.cookies);
const token =
req.cookies.token ||
req.body.token ||
req.header("Authorization").replace("Bearer ", "");
if (!token) {
return res.status(403).send("token is missing");
}
try {
const decode = jwt.verify(token, process.env.SECRET_KEY);
console.log(decode);
req.user = decode;
// bring in info from DB
} catch (error) {
return res.status(401).send("Invalid Token");
}
return next();
};
module.exports = auth;
================================================
FILE: lcoauthsystem/model/user.js
================================================
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
firstname: {
type: String,
default: null,
},
lastname: {
type: String,
default: null,
},
email: {
type: String,
unique: true,
},
password: {
type: String,
},
token: {
type: String,
},
});
module.exports = mongoose.model("user", userSchema);
================================================
FILE: lcoauthsystem/package.json
================================================
{
"name": "lcoauthsystem",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.5",
"dotenv": "^10.0.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^6.0.11"
},
"devDependencies": {
"nodemon": "^2.0.13"
}
}
================================================
FILE: lcopassportgoogle/index.js
================================================
const express = require("express");
const mongoose = require("mongoose");
const auth = require("./routes/auth");
const passportConfig = require("./passport/passport");
const passport = require("passport");
const cookieSession = require("cookie-session");
const app = express();
//connect to the DB
mongoose.connect("mongodb://127.0.0.1:27017/passport", () =>
console.log("DB CONNECTED")
);
app.use(
cookieSession({
maxAge: 3 * 24 * 60 * 60 * 1000,
keys: ["thisislcotokenkey"], // dotenv
})
);
app.use(passport.initialize());
app.use(passport.session());
const isLoggedIn = (req, res, next) => {
if (!req.user) {
res.redirect("/auth/login");
}
next();
};
app.set("view engine", "ejs");
app.use("/auth", auth);
app.get("/", isLoggedIn, (req, res) => {
res.render("home");
});
app.listen(4000, () => console.log(`Server is running at port 4000...`));
================================================
FILE: lcopassportgoogle/model/user.js
================================================
const mongoose = require("mongoose");
const userSchema = new mongoose.Schema({
name: String,
googleId: String,
email: String,
});
module.exports = mongoose.model("User", userSchema);
================================================
FILE: lcopassportgoogle/package.json
================================================
{
"name": "lcopassportgoogle",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"cookie-session": "^1.4.0",
"ejs": "^3.1.6",
"express": "^4.17.1",
"mongoose": "^6.0.12",
"passport": "^0.5.0",
"passport-google-oauth20": "^2.0.0"
},
"devDependencies": {
"nodemon": "^2.0.14"
}
}
================================================
FILE: lcopassportgoogle/passport/passport.js
================================================
const passport = require("passport");
const User = require("../model/user");
var GoogleStrategy = require("passport-google-oauth20").Strategy;
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
passport.use(
new GoogleStrategy(
{
clientID: "learncodeonline",
clientSecret: "aSecretGoesHere",
callbackURL: "http://localhost:4000/auth/google/callback",
},
(accessToken, refreshToken, profile, next) => {
console.log("MY PROFILE", profile._json.email);
User.findOne({ email: profile._json.email }).then((user) => {
if (user) {
console.log("User already exits in DB", user);
next(null, user);
// cookietoken()
} else {
User.create({
name: profile.displayName,
googleId: profile.id,
email: profile._json.email,
})
.then((user) => {
console.log("New User", user);
next(null, user);
// cookietoken()
})
.catch((err) => console.log(err));
}
});
// next();
}
)
);
================================================
FILE: lcopassportgoogle/routes/auth.js
================================================
const router = require("express").Router();
const passport = require("passport");
router.get("/login", (req, res) => {
res.render("login");
});
router.get("/logout", (req, res) => {
req.logout();
res.redirect("/auth/login");
});
router.get(
"/google",
passport.authenticate("google", {
scope: ["profile", "email"],
}),
(req, res) => {
res.send("login with google");
}
);
router.get("/google/callback", passport.authenticate("google"), (req, res) => {
res.send(req.user);
});
module.exports = router;
================================================
FILE: lcopassportgoogle/views/home.ejs
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<title>LCO</title>
</head>
<body class="bg-dark text-white">
<div class="container">
<h1>LCO Social login</h1>
</div>
<div class="container">
<a href="/auth/logout" class="btn btn-outline-success">Logout</a>
<a href="/auth/login" class="btn btn-outline-success">Login</a>
<a href="/" class="btn btn-outline-success">Home</a>
</div>
<div class="container">
<h1 class="display-1">You are at HOME page</h1>
</div>
</body>
</html>
================================================
FILE: lcopassportgoogle/views/login.ejs
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<title>LCO</title>
</head>
<body class="bg-dark text-white">
<div class="container">
<h1>LCO Social login</h1>
</div>
<div class="container">
<a href="/auth/logout" class="btn btn-outline-success">Logout</a>
<a href="/auth/login" class="btn btn-outline-success">Login</a>
<a href="/" class="btn btn-outline-success">Home</a>
</div>
<div class="container mt-4">
<a href="/auth/google" class="btn btn-danger">google</a>
</div>
</body>
</html>
================================================
FILE: mydocslco/index.js
================================================
const express = require("express");
const app = express();
const swaggerUi = require("swagger-ui-express");
const YAML = require("yamljs");
const swaggerDocument = YAML.load("./swagger.yaml");
const fileUpload = require("express-fileupload");
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));
app.use(express.json());
app.use(fileUpload());
let courses = [
{
id: "11",
name: "Learn Reactjs",
price: 299,
},
{
id: "22",
name: "Learn Angular",
price: 399,
},
{
id: "33",
name: "Learn Django",
price: 499,
},
];
app.get("/", (req, res) => {
res.send("hello from lco");
});
app.get("/api/v1/lco", (req, res) => {
res.send("hello from lco docs");
});
app.get("/api/v1/lcoobject", (req, res) => {
res.send({ id: "55", name: "Learn Backend", price: 999 });
});
app.get("/api/v1/courses", (req, res) => {
res.send(courses);
});
app.get("/api/v1/mycourse/:courseId", (req, res) => {
const myCourse = courses.find((course) => course.id === req.params.courseId);
res.send(myCourse);
});
app.post("/api/v1/addCourse", (req, res) => {
console.log(req.body);
courses.push(req.body);
res.send(true);
});
app.get("/api/v1/coursequery", (req, res) => {
let location = req.query.location;
let device = req.query.device;
res.send({ location, device });
});
app.post("/api/v1/courseupload", (req, res) => {
console.log(req.headers);
const file = req.files.file;
console.log(file);
let path = __dirname + "/images/" + Date.now() + ".jpg";
file.mv(path, (err) => {
res.send(true);
});
});
app.listen(4000, () => console.log(`Server is running at port 4000...`));
================================================
FILE: mydocslco/nodemon.json
================================================
{
"ext": ".js, .jsx, .yaml"
}
================================================
FILE: mydocslco/package.json
================================================
{
"name": "mydocslco",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "nodemon index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1",
"express-fileupload": "^1.2.1",
"nodemon": "^2.0.13",
"swagger-ui-express": "^4.1.6",
"yamljs": "^0.3.0"
}
}
================================================
FILE: mydocslco/swagger.yaml
================================================
openapi: "3.0.0"
info:
title: learn express and swagger - LearnCodeOnline
description: LCO - a course segment about writing docs
version: 1.1.0
contact:
email: hitesh@google.com
url: "https://lco.dev"
# servers:
# - url: "https://localhost:4000/api/v1"
# description: for local host - secure
# - url: "http://localhost:4000/api/v1"
# description: for local host - regular
servers:
- url: "{protocol}://localhost:4000/api/{version}"
description: for local host
variables:
version:
enum:
- v1
- v2
default: v1
protocol:
enum:
- http
- https
default: http
components:
securitySchemes:
cookieAuth:
type: apiKey
in: cookie
name: token
BearerAuth:
type: http
scheme: bearer
paths:
/lco:
get:
tags:
- String
summary: returns a greet message from LCO
responses:
200:
description: All good success
content:
application/json:
schema:
type: string
example: "mystring"
400:
description: Bad request
500:
description: internal server error
/lcoobject:
get:
tags:
- Object
summary: returns a unique course
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
id:
type: string
name:
type: string
price:
type: number
400:
description: Bad request
500:
description: internal server error
/courses:
get:
tags:
- Array
summary: returns all courses
responses:
200:
description: All good success
content:
application/json:
schema:
type: array
items:
type: object
properties:
id:
type: string
name:
type: string
price:
type: number
400:
description: Bad request
500:
description: internal server error
/mycourse/{courseId}:
get:
tags:
- String
summary: returns course based on request id
parameters:
- name: courseId
in: path
required: true
default: 22
schema:
type: string
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
id:
type: string
name:
type: string
price:
type: number
400:
description: Bad request
500:
description: internal server error
/addCourse:
post:
tags:
- String
summary: adds a new course to existing courses
consumes:
- application/json
produces:
- application/json
requestBody:
required: true
content:
application/json:
schema:
type: object
properties:
id:
type: string
name:
type: string
price:
type: number
responses:
200:
description: All good success
content:
application/json:
schema:
type: boolean
400:
description: Bad request
500:
description: internal server error
/coursequery:
get:
tags:
- String
summary: trying to learn about query
parameters:
- name: location
in: query
required: true
schema:
type: string
enum: [delhi, london, jaipur]
- name: device
in: query
required: true
schema:
type: string
enum: [web, mobile]
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
location:
type: string
device:
type: string
400:
description: Bad request
500:
description: internal server error
/courseupload:
post:
tags:
- String
summary: uploading course image
parameters:
- in: header
name: auth
requestBody:
content:
multipart/form-data:
schema:
type: object
properties:
file:
type: string
format: binary
responses:
200:
description: All good success
400:
description: Bad request
500:
description: internal server error
================================================
FILE: razorpay/index.js
================================================
const express = require("express");
const Razorpay = require("razorpay");
const app = express();
app.use(express.static("./public"));
app.use(express.json());
// app.get("/", (req, res) => {
// res.send("hi");
// });
app.post("/order", async (req, res) => {
const amount = req.body.amount;
var instance = new Razorpay({
key_id: "rzp_test_DfhbmLCnKJDWxO",
key_secret: "YFZxjAWfyFyJidZXbXLu2UN0",
// this needs to go in .env
});
var options = {
amount: amount * 100, // amount in the smallest currency unit
currency: "INR",
receipt: "order_rcptid_11",
};
// instance.orders.create(options, function (err, order) {
// console.log(order);
// });
const myOrder = await instance.orders.create(options);
res.status(200).json({
success: true,
amount,
order: myOrder,
});
});
app.listen(4000, () => console.log(`Server is running at port 4000`));
================================================
FILE: razorpay/package.json
================================================
{
"name": "razorpay",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^4.17.1",
"razorpay": "^2.0.7"
}
}
================================================
FILE: razorpay/public/index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<style>
body {
background-color: rgb(25, 25, 25);
color: aliceblue;
}
</style>
</head>
<body>
<h1>Testing public folder</h1>
<button id="rzp-button1">Pay</button>
<script src="https://checkout.razorpay.com/v1/checkout.js"></script>
<script>
const rpbutton = document.getElementById('rzp-button1')
rpbutton.addEventListener('click', async(event) => {
const response = await fetch('/order', {
method: "POST",
headers: {
'Content-Type': "application/json"
},
body: JSON.stringify({amount: 500})
})
const convertReponse = await response.json()
const {order} = convertReponse;
var options = {
key: "rzp_test_DfhbmLCnKJDWxO", // Enter the Key ID generated from the Dashboard
amount: 50000, // Amount is in currency subunits. Default currency is INR. Hence, 50000 refers to 50000 paise
currency: "INR",
order_id: order.id, //This is a sample Order ID. Pass the `id` obtained in the response of Step 1
handler: function (response){
alert(response.razorpay_payment_id);
alert(response.razorpay_order_id);
alert(response.razorpay_signature)
},
};
var rzp1 = new Razorpay(options);
rzp1.open()
})
</script>
</body>
</html>
================================================
FILE: readme.md
================================================
# welcome to pro backend developer course code files
## If you like this course, please drop a thanks node at my social profiles.
[CoderCommunity](https://web.codercommunity.io)
[Website](https://hiteshchoudahry.com)
[Instagram](https://instagram.com/hiteshchoudharyofficial)
of course there are bugs in these code files. As you teach you focus more on concept and less on production level execution. If you find any bug, consider that as your challenge to fix them.
================================================
FILE: socialapp/.gitignore
================================================
node_modules/
================================================
FILE: socialapp/index.js
================================================
const express = require("express");
const format = require("date-format");
const app = express();
// swagger docs related
const swaggerUi = require("swagger-ui-express");
const YAML = require("yamljs");
const swaggerDocument = YAML.load("./swagger.yaml");
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));
const PORT = process.env.PORT || 4000;
app.get("/", (req, res) => {
res.status(200).send("<h1>Hello from LCO</h1>");
});
app.get("/api/v1/instagram", (req, res) => {
const instaSocial = {
username: "hiteshchoudharyOfficial",
folowers: 66,
follows: 70,
date: format.asString("dd[MM] - hh:mm:ss", new Date()),
};
res.status(200).json(instaSocial);
});
app.get("/api/v1/facebook", (req, res) => {
const instaSocial = {
username: "hiteshchoudharyPage",
folowers: 88,
follows: 10,
date: format.asString("dd[MM] - hh:mm:ss", new Date()),
};
res.status(200).json(instaSocial);
});
app.get("/api/v1/linkedin", (req, res) => {
const instaSocial = {
username: "hiteshchoudhary",
folowers: 800,
follows: 80,
date: new Date(),
};
res.status(200).json(instaSocial);
});
app.get("/api/v1/:token", (req, res) => {
console.log(req.params.token);
res.status(200).json({ param: req.params.token });
});
app.listen(PORT, () => {
console.log(`Server is running at ${PORT}`);
});
================================================
FILE: socialapp/nodemon.json
================================================
{
"ext": ".js, .json, .yaml, .jsx"
}
================================================
FILE: socialapp/package.json
================================================
{
"name": "socialapp",
"version": "1.0.0",
"description": "a basic social media app",
"main": "index.js",
"scripts": {
"start": "nodemon index.js"
},
"keywords": [
"express",
"api"
],
"author": "Hitesh Choudhary",
"license": "ISC",
"dependencies": {
"date-format": "^3.0.0",
"express": "^4.17.1",
"swagger-ui-express": "^4.1.6",
"yamljs": "^0.3.0"
},
"devDependencies": {
"nodemon": "^2.0.13"
}
}
================================================
FILE: socialapp/swagger.yaml
================================================
openapi: 3.0.0
info:
title: Social App
description: Our fist Social app at LCO - Hitesh
version: 1.0.1
servers:
- url: http://localhost:4000/api/v1
description: localhost version of our app
- url: https://localhost:4000/api/v1
description: this is just a dummy api url, it doesn't work
components:
securitySchemes:
BasicAuth:
type: http
scheme: basic
BearerAuth:
type: http
scheme: bearer
paths:
/instagram:
get:
summary: returns username, followers and follows
responses:
'200': # status code
description: returns an object
content:
application/json:
schema:
type: object
properties:
username:
type: string
followers:
type: string
follows:
type: string
post:
summary: returns username, followers and follows
responses:
'200': # status code
description: returns an object
content:
application/json:
schema:
type: object
properties:
username:
type: string
followers:
type: string
follows:
type: string
/{token}:
get:
summary: returns whatever is there in parameters
parameters:
- name: token
default: 5
in: path
schema:
type: string
responses:
'200': # status code
description: returns an object
content:
application/json:
schema:
type: object
properties:
params:
type: string
================================================
FILE: tshirtstore/.gitignore
================================================
.env
node_modules/
================================================
FILE: tshirtstore/README.md
================================================
# Tshirt store for pro backend developer course
Please add env variables for the project
---
### PORT=4000
### DB_URL=
### JWT_SECRET=
### JWT_EXPIRY=
### COOKIE_TIME=
### CLOUDINARY_NAME=
### CLOUDINARY_API_KEY=
### CLOUDINARY_API_SECRET=
### SMTP_HOST=
### SMTP_PORT=
### SMTP_USER=
### SMTP_PASS=
### STRIPE_API_KEY=
### STRIPE_SECRET=
### RAZORPAY_API_KEY=
### RAZORPAY_SECRET=
---
[LearnCodeOnline](https://courses.learncodeonline.in/learn)
updat the variables before deploying
================================================
FILE: tshirtstore/app.js
================================================
const express = require("express");
require("dotenv").config();
const app = express();
const morgan = require("morgan");
const cookieParser = require("cookie-parser");
const fileUpload = require("express-fileupload");
//for swagger documentation
const swaggerUi = require("swagger-ui-express");
const YAML = require("yamljs");
const swaggerDocument = YAML.load("./swagger.yaml");
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));
//custom error middleware for easy front end
const productionError = require("./middlewares/productionError");
//regular middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
//cookies and file middleware
app.use(cookieParser());
app.use(
fileUpload({
useTempFiles: true,
tempFileDir: "/tmp/",
})
);
//temp check
app.set("view engine", "ejs");
//morgan middleware
app.use(morgan("tiny"));
//import all routes here
const home = require("./routes/home");
const user = require("./routes/user");
const product = require("./routes/product");
const payment = require("./routes/payment");
const order = require("./routes/order");
//router middleware
app.use("/api/v1", home);
app.use("/api/v1", user);
app.use("/api/v1", product);
app.use("/api/v1", payment);
app.use("/api/v1", order);
app.get("/signuptest", (req, res) => {
res.render("signuptest");
});
app.get("/", (req, res) => {
res.render("home");
});
//to handle production error
app.use(productionError);
// export app js
module.exports = app;
================================================
FILE: tshirtstore/config/db.js
================================================
const mongoose = require("mongoose");
const connectWithDb = () => {
mongoose
.connect(process.env.DB_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(console.log(`DB GOT CONNECTED`))
.catch((error) => {
console.log(`DB CONNECTION ISSUES`);
console.log(error);
process.exit(1);
});
};
module.exports = connectWithDb;
================================================
FILE: tshirtstore/controllers/homeController.js
================================================
const BigPromise = require("../middlewares/bigPromise");
exports.home = BigPromise(async (req, res) => {
// const db = await something()
res.status(200).json({
success: true,
greeting: "Hello from API",
});
});
exports.homeDummy = async (req, res) => {
try {
// const db = await something()
res.status(200).json({
success: true,
greeting: "this is another dummy route",
});
} catch (error) {
console.log(error);
}
};
================================================
FILE: tshirtstore/controllers/orderController.js
================================================
const Order = require("../models/order");
const Product = require("../models/product");
const BigPromise = require("../middlewares/bigPromise");
const CustomError = require("../utils/customError");
exports.createOrder = BigPromise(async (req, res, next) => {
const {
shippingInfo,
orderItems,
paymentInfo,
taxAmount,
shippingAmount,
totalAmount,
} = req.body;
const order = await Order.create({
shippingInfo,
orderItems,
paymentInfo,
taxAmount,
shippingAmount,
totalAmount,
user: req.user._id,
});
res.status(200).json({
success: true,
order,
});
});
exports.getOneOrder = BigPromise(async (req, res, next) => {
const order = await Order.findById(req.params.id).populate(
"user",
"name email"
);
if (!order) {
return next(new CustomError("please check order id", 401));
}
res.status(200).json({
success: true,
order,
});
});
exports.getLoggedInOrders = BigPromise(async (req, res, next) => {
const order = await Order.find({ user: req.user._id });
if (!order) {
return next(new CustomError("please check order id", 401));
}
res.status(200).json({
success: true,
order,
});
});
exports.admingetAllOrders = BigPromise(async (req, res, next) => {
const orders = await Order.find();
res.status(200).json({
success: true,
orders,
});
});
exports.adminUpdateOrder = BigPromise(async (req, res, next) => {
const order = await Order.findById(req.params.id);
if (order.orderStatus === "Delivered") {
return next(new CustomError("Order is already marked for delivered", 401));
}
order.orderStatus = req.body.orderStatus;
order.orderItems.forEach(async (prod) => {
await updateProductStock(prod.product, prod.quantity);
});
await order.save();
res.status(200).json({
success: true,
order,
});
});
exports.adminDeleteOrder = BigPromise(async (req, res, next) => {
const order = await Order.findById(req.params.id);
await order.remove();
res.status(200).json({
success: true,
});
});
async function updateProductStock(productId, quantity) {
const product = await Product.findById(productId);
product.stock = product.stock - quantity;
await product.save({ validateBeforeSave: false });
}
================================================
FILE: tshirtstore/controllers/paymentController.js
================================================
const BigPromise = require("../middlewares/bigPromise");
const stripe = require("stripe")(process.env.STRIPE_SECRET);
const Razorpay = require("razorpay");
exports.sendStripeKey = BigPromise(async (req, res, next) => {
res.status(200).json({
stripekey: process.env.STRIPE_API_KEY,
});
});
exports.captureStripePayment = BigPromise(async (req, res, next) => {
const paymentIntent = await stripe.paymentIntents.create({
amount: req.body.amount,
currency: "inr",
//optional
metadata: { integration_check: "accept_a_payment" },
});
res.status(200).json({
success: true,
amount: req.body.amount,
client_secret: paymentIntent.client_secret,
//you can optionally send id as well
});
});
exports.sendRazorpayKey = BigPromise(async (req, res, next) => {
res.status(200).json({
razorpaykey: process.env.RAZORPAY_API_KEY,
});
});
exports.captureRazorpayPayment = BigPromise(async (req, res, next) => {
var instance = new Razorpay({
key_id: process.env.RAZORPAY_API_KEY,
key_secret: process.env.RAZORPAY_SECRET,
});
var options = {
amount: req.body.amount, // amount in the smallest currency unit
currency: "INR",
};
console.log(req.body.amount);
const myOrder = await instance.orders.create(options);
res.status(200).json({
success: true,
amount: req.body.amount,
order: myOrder,
});
});
================================================
FILE: tshirtstore/controllers/productController.js
================================================
const Product = require("../models/product");
const BigPromise = require("../middlewares/bigPromise");
const CustomError = require("../utils/customError");
const cloudinary = require("cloudinary");
const WhereClause = require("../utils/whereClause");
exports.addProduct = BigPromise(async (req, res, next) => {
// images
let imageArray = [];
if (!req.files) {
return next(new CustomError("images are required", 401));
}
console.log("RESULT", req.files.photos[0]);
if (req.files) {
for (let index = 0; index < req.files.photos.length; index++) {
console.log("UPLOAD START...");
let result = await cloudinary.v2.uploader.upload(
req.files.photos[index].tempFilePath,
{
folder: "products",
}
);
// another way to upload and check error
// let result
// cloudinary.v2.uploader.upload(req.files.photos[index].tempFilePath, {
// folder: "products"
// }, function(error, result){console.log(result, error)})
console.log("RESULT", result);
imageArray.push({
id: result.public_id,
secure_url: result.secure_url,
});
}
}
req.body.photos = imageArray;
req.body.user = req.user.id;
const product = await Product.create(req.body);
res.status(200).json({
success: true,
product,
});
});
exports.getAllProduct = BigPromise(async (req, res, next) => {
const resultPerPage = 3;
const totalcountProduct = await Product.countDocuments();
const productsObj = new WhereClause(Product.find(), req.query)
.search()
.filter();
let products = await productsObj.base;
const filteredProductNumber = products.length;
//products.limit().skip()
productsObj.pager(resultPerPage);
products = await productsObj.base.clone();
res.status(200).json({
success: true,
products,
filteredProductNumber,
totalcountProduct,
resultPerPage,
});
});
exports.getOneProduct = BigPromise(async (req, res, next) => {
const product = await Product.findById(req.params.id);
if (!product) {
return next(new CustomError("No product found with this id", 401));
}
res.status(200).json({
success: true,
product,
});
});
exports.addReview = BigPromise(async (req, res, next) => {
const { rating, comment, productId } = req.body;
const review = {
user: req.user._id,
name: req.user.name,
rating: Number(rating),
comment,
};
const product = await Product.findById(productId);
const AlreadyReview = product.reviews.find(
(rev) => rev.user.toString() === req.user._id.toString()
);
if (AlreadyReview) {
product.reviews.forEach((review) => {
if (review.user.toString() === req.user._id.toString()) {
review.comment = comment;
review.rating = rating;
}
});
} else {
product.reviews.push(review);
product.numberOfReviews = product.reviews.length;
}
// adjust ratings
product.ratings =
product.reviews.reduce((acc, item) => item.rating + acc, 0) /
product.reviews.length;
//save
await product.save({ validateBeforeSave: false });
res.status(200).json({
success: true,
});
});
exports.deleteReview = BigPromise(async (req, res, next) => {
const { productId } = req.query;
const product = await Product.findById(productId);
const reviews = product.reviews.filter(
(rev) => rev.user.toString() === req.user._id.toString()
);
const numberOfReviews = reviews.length;
// adjust ratings
product.ratings =
product.reviews.reduce((acc, item) => item.rating + acc, 0) /
product.reviews.length;
//update the product
await Product.findByIdAndUpdate(
productId,
{
reviews,
ratings,
numberOfReviews,
},
{
new: true,
runValidators: true,
useFindAndModify: false,
}
);
res.status(200).json({
success: true,
});
});
exports.getOnlyReviewsForOneProduct = BigPromise(async (req, res, next) => {
const product = await Product.findById(req.query.id);
res.status(200).json({
success: true,
reviews: product.reviews,
});
});
// admin only controllers
exports.adminGetAllProduct = BigPromise(async (req, res, next) => {
const products = await Product.find();
res.status(200).json({
success: true,
products,
});
});
exports.adminUpdateOneProduct = BigPromise(async (req, res, next) => {
let product = await Product.findById(req.params.id);
if (!product) {
return next(new CustomError("No product found with this id", 401));
}
let imagesArray = [];
if (req.files) {
//destroy the existing image
for (let index = 0; index < product.photos.length; index++) {
const res = await cloudinary.v2.uploader.destroy(
product.photos[index].id
);
}
for (let index = 0; index < req.files.photos.length; index++) {
let result = await cloudinary.v2.uploader.upload(
req.files.photos[index].tempFilePath,
{
folder: "products", //folder name -> .env
}
);
imagesArray.push({
id: result.public_id,
secure_url: result.secure_url,
});
}
}
req.body.photos = imagesArray;
product = await Product.findByIdAndUpdate(req.params.id, req.body, {
new: true,
runValidators: true,
useFindAndModify: false,
});
res.status(200).json({
success: true,
product,
});
});
exports.adminDeleteOneProduct = BigPromise(async (req, res, next) => {
const product = await Product.findById(req.params.id);
if (!product) {
return next(new CustomError("No product found with this id", 401));
}
//destroy the existing image
for (let index = 0; index < product.photos.length; index++) {
const res = await cloudinary.v2.uploader.destroy(product.photos[index].id);
}
await product.remove();
res.status(200).json({
success: true,
message: "Product was deleted !",
});
});
================================================
FILE: tshirtstore/controllers/userController.js
================================================
const User = require("../models/user");
const BigPromise = require("../middlewares/bigPromise");
const CustomError = require("../utils/customError");
const cookieToken = require("../utils/cookieToken");
const cloudinary = require("cloudinary");
const mailHelper = require("../utils/emailHelper");
const crypto = require("crypto");
exports.signup = BigPromise(async (req, res, next) => {
//let result;
console.log(req.body);
if (!req.files) {
return next(new CustomError("photo is required for signup", 400));
}
const { name, email, password } = req.body;
if (!email || !name || !password) {
return next(new CustomError("Name, email and password are required", 400));
}
let file = req.files.photo;
const result = await cloudinary.v2.uploader.upload(file.tempFilePath, {
folder: "users",
width: 150,
crop: "scale",
});
const user = await User.create({
name,
email,
password,
photo: {
id: result.public_id,
secure_url: result.secure_url,
},
});
cookieToken(user, res);
});
exports.login = BigPromise(async (req, res, next) => {
const { email, password } = req.body;
// check for presence of email and password
if (!email || !password) {
return next(new CustomError("please provide email and password", 400));
}
// get user from DB
const user = await User.findOne({ email }).select("+password");
// if user not found in DB
if (!user) {
return next(
new CustomError("Email or password does not match or exist", 400)
);
}
// match the password
const isPasswordCorrect = await user.isValidatedPassword(password);
//if password do not match
if (!isPasswordCorrect) {
return next(
new CustomError("Email or password does not match or exist", 400)
);
}
// if all goes good and we send the token
cookieToken(user, res);
});
exports.logout = BigPromise(async (req, res, next) => {
//clear the cookie
res.cookie("token", null, {
expires: new Date(Date.now()),
httpOnly: true,
});
//send JSON response for success
res.status(200).json({
succes: true,
message: "Logout success",
});
});
exports.forgotPassword = BigPromise(async (req, res, next) => {
// collect email
const { email } = req.body;
console.log(email);
// find user in database
const user = await User.findOne({ email });
// if user not found in database
if (!user) {
return next(new CustomError("Email not found as registered", 400));
}
//get token from user model methods
const forgotToken = user.getForgotPasswordToken();
// save user fields in DB
await user.save({ validateBeforeSave: false });
// create a URL
// const myUrl = `${req.protocol}://${req.get(
// "host"
// )}/api/v1/password/reset/${forgotToken}`;
//URL for deployment as front end might be running at different URL
const myUrl = `${process.env.FRONT_END}/password/reset/${forgotToken}`;
// craft a message
const message = `Copy paste this link in your URL and hit enter \n\n ${myUrl}`;
// attempt to send email
try {
await mailHelper({
email: user.email,
subject: "LCO TStore - Password reset email",
message,
});
// json reponse if email is success
res.status(200).json({
succes: true,
message: "Email sent successfully",
});
} catch (error) {
// reset user fields if things goes wrong
user.forgotPasswordToken = undefined;
user.forgotPasswordExpiry = undefined;
await user.save({ validateBeforeSave: false });
// send error response
return next(new CustomError(error.message, 500));
}
});
exports.passwordReset = BigPromise(async (req, res, next) => {
//get token from params
const token = req.params.token;
// hash the token as db also stores the hashed version
const encryToken = crypto.createHash("sha256").update(token).digest("hex");
// find user based on hased on token and time in future
const user = await User.findOne({
encryToken,
forgotPasswordExpiry: { $gt: Date.now() },
});
if (!user) {
return next(new CustomError("Token is invalid or expired", 400));
}
// check if password and conf password matched
if (req.body.password !== req.body.confirmPassword) {
return next(
new CustomError("password and confirm password do not match", 400)
);
}
// update password field in DB
user.password = req.body.password;
// reset token fields
user.forgotPasswordToken = undefined;
user.forgotPasswordExpiry = undefined;
// save the user
await user.save();
// send a JSON response OR send token
cookieToken(user, res);
});
exports.getLoggedInUserDetails = BigPromise(async (req, res, next) => {
//req.user will be added by middleware
// find user by id
const user = await User.findById(req.user.id);
//send response and user data
res.status(200).json({
success: true,
user,
});
});
exports.changePassword = BigPromise(async (req, res, next) => {
// get user from middleware
const userId = req.user.id;
// get user from database
const user = await User.findById(userId).select("+password");
//check if old password is correct
const isCorrectOldPassword = await user.isValidatedPassword(
req.body.oldPassword
);
if (!isCorrectOldPassword) {
return next(new CustomError("old password is incorrect", 400));
}
// allow to set new password
user.password = req.body.password;
// save user and send fresh token
await user.save();
cookieToken(user, res);
});
exports.updateUserDetails = BigPromise(async (req, res, next) => {
// add a check for email and name in body
// collect data from body
const newData = {
name: req.body.name,
email: req.body.email,
};
// if photo comes to us
if (req.files) {
const user = await User.findById(req.user.id);
const imageId = user.photo.id;
// delete photo on cloudinary
const resp = await cloudinary.v2.uploader.destroy(imageId);
// upload the new photo
const result = await cloudinary.v2.uploader.upload(
req.files.photo.tempFilePath,
{
folder: "users",
width: 150,
crop: "scale",
}
);
// add photo data in newData object
newData.photo = {
id: result.public_id,
secure_url: result.secure_url,
};
}
// update the data in user
const user = await User.findByIdAndUpdate(req.user.id, newData, {
new: true,
runValidators: true,
useFindAndModify: false,
});
res.status(200).json({
success: true,
});
});
exports.adminAllUser = BigPromise(async (req, res, next) => {
// select all users
const users = await User.find();
// send all users
res.status(200).json({
success: true,
users,
});
});
exports.admingetOneUser = BigPromise(async (req, res, next) => {
// get id from url and get user from database
const user = await User.findById(req.params.id);
if (!user) {
next(new CustomError("No user found", 400));
}
// send user
res.status(200).json({
success: true,
user,
});
});
exports.adminUpdateOneUserDetails = BigPromise(async (req, res, next) => {
// add a check for email and name in body
// get data from request body
const newData = {
name: req.body.name,
email: req.body.email,
role: req.body.role,
};
// update the user in database
const user = await User.findByIdAndUpdate(req.params.id, newData, {
new: true,
runValidators: true,
useFindAndModify: false,
});
res.status(200).json({
success: true,
});
});
exports.adminDeleteOneUser = BigPromise(async (req, res, next) => {
// get user from url
const user = await User.findById(req.params.id);
if (!user) {
return next(new CustomError("No Such user found", 401));
}
// get image id from user in database
const imageId = user.photo.id;
// delete image from cloudinary
await cloudinary.v2.uploader.destroy(imageId);
// remove user from databse
await user.remove();
res.status(200).json({
success: true,
});
});
exports.managerAllUser = BigPromise(async (req, res, next) => {
// select the user with role of user
const users = await User.find({ role: "user" });
res.status(200).json({
success: true,
users,
});
});
================================================
FILE: tshirtstore/index.js
================================================
const app = require("./app");
const connectWithDb = require("./config/db");
require("dotenv").config();
const cloudinary = require("cloudinary");
// connect with databases
connectWithDb();
//cloudinary config goes here
cloudinary.config({
cloud_name: process.env.CLOUDINARY_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});
app.listen(process.env.PORT, () => {
console.log(`Server is running at port: ${process.env.PORT}`);
});
================================================
FILE: tshirtstore/lcotshirtstore/.gitignore
================================================
.env
node_modules/
================================================
FILE: tshirtstore/lcotshirtstore/app.js
================================================
const express = require("express");
require("dotenv").config();
const app = express();
const morgan = require("morgan");
const cookieParser = require("cookie-parser");
const fileUpload = require("express-fileupload");
//for swagger documentation
const swaggerUi = require("swagger-ui-express");
const YAML = require("yamljs");
const swaggerDocument = YAML.load("./swagger.yaml");
app.use("/api-docs", swaggerUi.serve, swaggerUi.setup(swaggerDocument));
//regular middleware
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
//cookies and file middleware
app.use(cookieParser());
app.use(
fileUpload({
useTempFiles: true,
tempFileDir: "/tmp/",
})
);
//temp check
app.set("view engine", "ejs");
//morgan middleware
app.use(morgan("tiny"));
//import all routes here
const home = require("./routes/home");
const user = require("./routes/user");
const product = require("./routes/product");
const payment = require("./routes/payment");
const order = require("./routes/order");
//router middleware
app.use("/api/v1", home);
app.use("/api/v1", user);
app.use("/api/v1", product);
app.use("/api/v1", payment);
app.use("/api/v1", order);
app.get("/signuptest", (req, res) => {
res.render("signuptest");
});
// export app js
module.exports = app;
================================================
FILE: tshirtstore/lcotshirtstore/config/db.js
================================================
const mongoose = require("mongoose");
const connectWithDb = () => {
mongoose
.connect(process.env.DB_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
})
.then(console.log(`DB GOT CONNECTED`))
.catch((error) => {
console.log(`DB CONNECTION ISSUES`);
console.log(error);
process.exit(1);
});
};
module.exports = connectWithDb;
================================================
FILE: tshirtstore/lcotshirtstore/controllers/homeController.js
================================================
const BigPromise = require("../middlewares/bigPromise");
exports.home = BigPromise(async (req, res) => {
// const db = await something()
res.status(200).json({
success: true,
greeting: "Hello from API",
});
});
exports.homeDummy = async (req, res) => {
try {
// const db = await something()
res.status(200).json({
success: true,
greeting: "this is another dummy route",
});
} catch (error) {
console.log(error);
}
};
================================================
FILE: tshirtstore/lcotshirtstore/controllers/orderController.js
================================================
const Order = require("../models/order");
const Product = require("../models/product");
const BigPromise = require("../middlewares/bigPromise");
const CustomError = require("../utils/customError");
exports.createOrder = BigPromise(async (req, res, next) => {
const {
shippingInfo,
orderItems,
paymentInfo,
taxAmount,
shippingAmount,
totalAmount,
} = req.body;
const order = await Order.create({
shippingInfo,
orderItems,
paymentInfo,
taxAmount,
shippingAmount,
totalAmount,
user: req.user._id,
});
res.status(200).json({
success: true,
order,
});
});
exports.getOneOrder = BigPromise(async (req, res, next) => {
const order = await Order.findById(req.params.id).populate(
"user",
"name email"
);
if (!order) {
return next(new CustomError("please check order id", 401));
}
res.status(200).json({
success: true,
order,
});
});
exports.getLoggedInOrders = BigPromise(async (req, res, next) => {
const order = await Order.find({ user: req.user._id });
if (!order) {
return next(new CustomError("please check order id", 401));
}
res.status(200).json({
success: true,
order,
});
});
exports.admingetAllOrders = BigPromise(async (req, res, next) => {
const orders = await Order.find();
res.status(200).json({
success: true,
orders,
});
});
exports.adminUpdateOrder = BigPromise(async (req, res, next) => {
const order = await Order.findById(req.params.id);
if (order.orderStatus === "Delivered") {
return next(new CustomError("Order is already marked for delivered", 401));
}
order.orderStatus = req.body.orderStatus;
order.orderItems.forEach(async (prod) => {
await updateProductStock(prod.product, prod.quantity);
});
await order.save();
res.status(200).json({
success: true,
orders,
});
});
exports.adminDeleteOrder = BigPromise(async (req, res, next) => {
const order = await Order.findById(req.params.id);
await order.remove();
res.status(200).json({
success: true,
});
});
async function updateProductStock(productId, quantity) {
const product = await Product.findById(productId);
product.stock = product.stock - quantity;
await product.save({ validateBeforeSave: false });
}
================================================
FILE: tshirtstore/lcotshirtstore/controllers/paymentController.js
================================================
const BigPromise = require("../middlewares/bigPromise");
const stripe = require("stripe")(process.env.STRIPE_SECRET);
exports.sendStripeKey = BigPromise(async (req, res, next) => {
res.status(200).json({
stripekey: process.env.STRIPE_API_KEY,
});
});
exports.captureStripePayment = BigPromise(async (req, res, next) => {
const paymentIntent = await stripe.paymentIntents.create({
amount: req.body.amount,
currency: "inr",
//optional
metadata: { integration_check: "accept_a_payment" },
});
res.status(200).json({
success: true,
amount: req.body.amount,
client_secret: paymentIntent.client_secret,
//you can optionally send id as well
});
});
exports.sendRazorpayKey = BigPromise(async (req, res, next) => {
res.status(200).json({
stripekey: process.env.RAZORPAY_API_KEY,
});
});
exports.captureRazorpayPayment = BigPromise(async (req, res, next) => {
var instance = new Razorpay({
key_id: process.env.RAZORPAY_API_KEY,
key_secret: process.env.RAZORPAY_SECRET,
});
var options = {
amount: req.body.amount, // amount in the smallest currency unit
currency: "INR",
};
const myOrder = await instance.orders.create(options);
res.staus(200).json({
success: true,
amount: req.body.amount,
order: myOrder,
});
});
================================================
FILE: tshirtstore/lcotshirtstore/controllers/productController.js
================================================
const Product = require("../models/product");
const BigPromise = require("../middlewares/bigPromise");
const CustomError = require("../utils/customError");
const cloudinary = require("cloudinary");
const WhereClause = require("../utils/whereClause");
exports.addProduct = BigPromise(async (req, res, next) => {
// images
let imageArray = [];
if (!req.files) {
return next(new CustomError("images are required", 401));
}
if (req.files) {
for (let index = 0; index < req.files.photos.length; index++) {
let result = await cloudinary.v2.uploader.upload(
req.files.photos[index].tempFilePath,
{
folder: "products",
}
);
imageArray.push({
id: result.public_id,
secure_url: result.secure_url,
});
}
}
req.body.photos = imageArray;
req.body.user = req.user.id;
const product = await Product.create(req.body);
res.status(200).json({
success: true,
product,
});
});
exports.getAllProduct = BigPromise(async (req, res, next) => {
const resultPerPage = 6;
const totalcountProduct = await Product.countDocuments();
const productsObj = new WhereClause(Product.find(), req.query)
.search()
.filter();
let products = await productsObj.base;
const filteredProductNumber = products.length;
//products.limit().skip()
productsObj.pager(resultPerPage);
products = await productsObj.base.clone();
res.status(200).json({
success: true,
products,
filteredProductNumber,
totalcountProduct,
});
});
exports.getOneProduct = BigPromise(async (req, res, next) => {
const product = await Product.findById(req.params.id);
if (!product) {
return next(new CustomError("No product found with this id", 401));
}
res.status(200).json({
success: true,
product,
});
});
exports.addReview = BigPromise(async (req, res, next) => {
const { rating, comment, productId } = req.body;
const review = {
user: req.user._id,
name: req.user.name,
rating: Number(rating),
comment,
};
const product = await Product.findById(productId);
const AlreadyReview = product.reviews.find(
(rev) => rev.user.toString() === req.user._id.toString()
);
if (AlreadyReview) {
product.reviews.forEach((review) => {
if (review.user.toString() === req.user._id.toString()) {
review.comment = comment;
review.rating = rating;
}
});
} else {
product.reviews.push(review);
product.numberOfReviews = product.reviews.length;
}
// adjust ratings
product.ratings =
product.reviews.reduce((acc, item) => item.rating + acc, 0) /
product.reviews.length;
//save
await product.save({ validateBeforeSave: false });
res.status(200).json({
success: true,
});
});
exports.deleteReview = BigPromise(async (req, res, next) => {
const { productId } = req.query;
const product = await Product.findById(productId);
const reviews = product.reviews.filter(
(rev) => rev.user.toString() === req.user._id.toString()
);
const numberOfReviews = reviews.length;
// adjust ratings
product.ratings =
product.reviews.reduce((acc, item) => item.rating + acc, 0) /
product.reviews.length;
//update the product
await Product.findByIdAndUpdate(
productId,
{
reviews,
ratings,
numberOfReviews,
},
{
new: true,
runValidators: true,
useFindAndModify: false,
}
);
res.status(200).json({
success: true,
});
});
exports.getOnlyReviewsForOneProduct = BigPromise(async (req, res, next) => {
const product = await Product.findById(req.query.id);
res.status(200).json({
success: true,
reviews: product.reviews,
});
});
// admin only controllers
exports.adminGetAllProduct = BigPromise(async (req, res, next) => {
const products = await Product.find();
res.status(200).json({
success: true,
products,
});
});
exports.adminUpdateOneProduct = BigPromise(async (req, res, next) => {
let product = await Product.findById(req.params.id);
if (!product) {
return next(new CustomError("No product found with this id", 401));
}
let imagesArray = [];
if (req.files) {
//destroy the existing image
for (let index = 0; index < product.photos.length; index++) {
const res = await cloudinary.v2.uploader.destroy(
product.photos[index].id
);
}
for (let index = 0; index < req.files.photos.length; index++) {
let result = await cloudinary.v2.uploader.upload(
req.files.photos[index].tempFilePath,
{
folder: "products", //folder name -> .env
}
);
imagesArray.push({
id: result.public_id,
secure_url: result.secure_url,
});
}
}
req.body.photos = imagesArray;
product = await Product.findByIdAndUpdate(req.params.id, req.body, {
new: true,
runValidators: true,
useFindAndModify: false,
});
res.status(200).json({
success: true,
product,
});
});
exports.adminDeleteOneProduct = BigPromise(async (req, res, next) => {
const product = await Product.findById(req.params.id);
if (!product) {
return next(new CustomError("No product found with this id", 401));
}
//destroy the existing image
for (let index = 0; index < product.photos.length; index++) {
const res = await cloudinary.v2.uploader.destroy(product.photos[index].id);
}
await product.remove();
res.status(200).json({
success: true,
message: "Product was deleted !",
});
});
================================================
FILE: tshirtstore/lcotshirtstore/controllers/userController.js
================================================
const User = require("../models/user");
const BigPromise = require("../middlewares/bigPromise");
const CustomError = require("../utils/customError");
const cookieToken = require("../utils/cookieToken");
const cloudinary = require("cloudinary");
const mailHelper = require("../utils/emailHelper");
const crypto = require("crypto");
exports.signup = BigPromise(async (req, res, next) => {
//let result;
if (!req.files) {
return next(new CustomError("photo is required for signup", 400));
}
const { name, email, password } = req.body;
if (!email || !name || !password) {
return next(new CustomError("Name, email and password are required", 400));
}
let file = req.files.photo;
const result = await cloudinary.v2.uploader.upload(file.tempFilePath, {
folder: "users",
width: 150,
crop: "scale",
});
const user = await User.create({
name,
email,
password,
photo: {
id: result.public_id,
secure_url: result.secure_url,
},
});
cookieToken(user, res);
});
exports.login = BigPromise(async (req, res, next) => {
const { email, password } = req.body;
// check for presence of email and password
if (!email || !password) {
return next(new CustomError("please provide email and password", 400));
}
// get user from DB
const user = await User.findOne({ email }).select("+password");
// if user not found in DB
if (!user) {
return next(
new CustomError("Email or password does not match or exist", 400)
);
}
// match the password
const isPasswordCorrect = await user.isValidatedPassword(password);
//if password do not match
if (!isPasswordCorrect) {
return next(
new CustomError("Email or password does not match or exist", 400)
);
}
// if all goes good and we send the token
cookieToken(user, res);
});
exports.logout = BigPromise(async (req, res, next) => {
//clear the cookie
res.cookie("token", null, {
expires: new Date(Date.now()),
httpOnly: true,
});
//send JSON response for success
res.status(200).json({
succes: true,
message: "Logout success",
});
});
exports.forgotPassword = BigPromise(async (req, res, next) => {
// collect email
const { email } = req.body;
// find user in database
const user = await User.findOne({ email });
// if user not found in database
if (!user) {
return next(new CustomError("Email not found as registered", 400));
}
//get token from user model methods
const forgotToken = user.getForgotPasswordToken();
// save user fields in DB
await user.save({ validateBeforeSave: false });
// create a URL
const myUrl = `${req.protocol}://${req.get(
"host"
)}/api/v1/password/reset/${forgotToken}`;
// craft a message
const message = `Copy paste this link in your URL and hit enter \n\n ${myUrl}`;
// attempt to send email
try {
await mailHelper({
email: user.email,
subject: "LCO TStore - Password reset email",
message,
});
// json reponse if email is success
res.status(200).json({
succes: true,
message: "Email sent successfully",
});
} catch (error) {
// reset user fields if things goes wrong
user.forgotPasswordToken = undefined;
user.forgotPasswordExpiry = undefined;
await user.save({ validateBeforeSave: false });
// send error response
return next(new CustomError(error.message, 500));
}
});
exports.passwordReset = BigPromise(async (req, res, next) => {
//get token from params
const token = req.params.token;
// hash the token as db also stores the hashed version
const encryToken = crypto.createHash("sha256").update(token).digest("hex");
// find user based on hased on token and time in future
const user = await User.findOne({
encryToken,
forgotPasswordExpiry: { $gt: Date.now() },
});
if (!user) {
return next(new CustomError("Token is invalid or expired", 400));
}
// check if password and conf password matched
if (req.body.password !== req.body.confirmPassword) {
return next(
new CustomError("password and confirm password do not match", 400)
);
}
// update password field in DB
user.password = req.body.password;
// reset token fields
user.forgotPasswordToken = undefined;
user.forgotPasswordExpiry = undefined;
// save the user
await user.save();
// send a JSON response OR send token
cookieToken(user, res);
});
exports.getLoggedInUserDetails = BigPromise(async (req, res, next) => {
//req.user will be added by middleware
// find user by id
const user = await User.findById(req.user.id);
//send response and user data
res.status(200).json({
success: true,
user,
});
});
exports.changePassword = BigPromise(async (req, res, next) => {
// get user from middleware
const userId = req.user.id;
// get user from database
const user = await User.findById(userId).select("+password");
//check if old password is correct
const isCorrectOldPassword = await user.isValidatedPassword(
req.body.oldPassword
);
if (!isCorrectOldPassword) {
return next(new CustomError("old password is incorrect", 400));
}
// allow to set new password
user.password = req.body.password;
// save user and send fresh token
await user.save();
cookieToken(user, res);
});
exports.updateUserDetails = BigPromise(async (req, res, next) => {
// add a check for email and name in body
// collect data from body
const newData = {
name: req.body.name,
email: req.body.email,
};
// if photo comes to us
if (req.files) {
const user = await User.findById(req.user.id);
const imageId = user.photo.id;
// delete photo on cloudinary
const resp = await cloudinary.v2.uploader.destroy(imageId);
// upload the new photo
const result = await cloudinary.v2.uploader.upload(
req.files.photo.tempFilePath,
{
folder: "users",
width: 150,
crop: "scale",
}
);
// add photo data in newData object
newData.photo = {
id: result.public_id,
secure_url: result.secure_url,
};
}
// update the data in user
const user = await User.findByIdAndUpdate(req.user.id, newData, {
new: true,
runValidators: true,
useFindAndModify: false,
});
res.status(200).json({
success: true,
});
});
exports.adminAllUser = BigPromise(async (req, res, next) => {
// select all users
const users = await User.find();
// send all users
res.status(200).json({
success: true,
users,
});
});
exports.admingetOneUser = BigPromise(async (req, res, next) => {
// get id from url and get user from database
const user = await User.findById(req.params.id);
if (!user) {
next(new CustomError("No user found", 400));
}
// send user
res.status(200).json({
success: true,
user,
});
});
exports.adminUpdateOneUserDetails = BigPromise(async (req, res, next) => {
// add a check for email and name in body
// get data from request body
const newData = {
name: req.body.name,
email: req.body.email,
role: req.body.role,
};
// update the user in database
const user = await User.findByIdAndUpdate(req.params.id, newData, {
new: true,
runValidators: true,
useFindAndModify: false,
});
res.status(200).json({
success: true,
});
});
exports.adminDeleteOneUser = BigPromise(async (req, res, next) => {
// get user from url
const user = await User.findById(req.params.id);
if (!user) {
return next(new CustomError("No Such user found", 401));
}
// get image id from user in database
const imageId = user.photo.id;
// delete image from cloudinary
await cloudinary.v2.uploader.destroy(imageId);
// remove user from databse
await user.remove();
res.status(200).json({
success: true,
});
});
exports.managerAllUser = BigPromise(async (req, res, next) => {
// select the user with role of user
const users = await User.find({ role: "user" });
res.status(200).json({
success: true,
users,
});
});
================================================
FILE: tshirtstore/lcotshirtstore/index.js
================================================
const app = require("./app");
const connectWithDb = require("./config/db");
require("dotenv").config();
const cloudinary = require("cloudinary");
// connect with databases
connectWithDb();
//cloudinary config goes here
cloudinary.config({
cloud_name: process.env.CLOUDINARY_NAME,
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET,
});
app.listen(process.env.PORT, () => {
console.log(`Server is running at port: ${process.env.PORT}`);
});
================================================
FILE: tshirtstore/lcotshirtstore/middlewares/bigPromise.js
================================================
// try catch and async - await || use promise
module.exports = (func) => (req, res, next) =>
Promise.resolve(func(req, res, next)).catch(next);
================================================
FILE: tshirtstore/lcotshirtstore/middlewares/user.js
================================================
const User = require("../models/user");
const BigPromise = require("../middlewares/bigPromise");
const CustomError = require("../utils/customError");
const jwt = require("jsonwebtoken");
exports.isLoggedIn = BigPromise(async (req, res, next) => {
const token =
req.cookies.token || req.header("Authorization").replace("Bearer ", "");
if (!token) {
return next(new CustomError("Login first to access this page", 401));
}
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = await User.findById(decoded.id);
next();
});
exports.customRole = (...roles) => {
return (req, res, next) => {
if (!roles.includes(req.user.role)) {
return next(new CustomError("You are not allowed for this resouce", 403));
}
next();
};
};
================================================
FILE: tshirtstore/lcotshirtstore/models/order.js
================================================
const mongoose = require("mongoose");
// shippingInfo{}
// user,
// paymentInfo{}
// taxAmount
// ShippingAmount
// totalAmount
// orderStatus
// deliveredAt
// createdAt
// -------------
// orderItems: [ {} ]
// - name
// - quantity
// - image[0]
// - price
// - product
const orderSchema = new mongoose.Schema({
shippingInfo: {
address: {
type: String,
required: true,
},
city: {
type: String,
required: true,
},
phoneNo: {
type: String,
required: true,
},
postalCode: {
type: String,
required: true,
},
state: {
type: String,
required: true,
},
country: {
type: String,
required: true,
},
},
user: {
type: mongoose.Schema.ObjectId, //mongoose.Schema.Types.ObjectId
ref: "User",
required: true,
},
orderItems: [
{
name: {
type: String,
required: true,
},
quantity: {
type: Number,
required: true,
},
image: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
product: {
type: mongoose.Schema.ObjectId, //mongoose.Schema.Types.ObjectId
ref: "Product",
required: true,
},
},
],
paymentInfo: {
id: {
type: String,
},
},
taxAmount: {
type: Number,
required: true,
},
shippingAmount: {
type: Number,
required: true,
},
totalAmount: {
type: Number,
required: true,
},
orderStatus: {
type: String,
required: true,
default: "processing",
},
deliveredAt: {
type: Date,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Order", orderSchema);
// ref link
// https://stackoverflow.com/questions/28997636/should-i-use-schema-types-objectid-or-schema-objectid-when-defining-a-mongoose-s
================================================
FILE: tshirtstore/lcotshirtstore/models/product.js
================================================
const mongoose = require("mongoose");
const productSchema = new mongoose.Schema({
name: {
type: String,
required: [true, "please provide product name"],
trim: true,
maxlength: [120, "Product name should not be more than 120 characters"],
},
price: {
type: Number,
required: [true, "please provide product price"],
maxlength: [6, "Product price should not be more than 6 digits"],
},
description: {
type: String,
required: [true, "please provide product description"],
},
photos: [
{
id: {
type: String,
required: true,
},
secure_url: {
type: String,
required: true,
},
},
],
category: {
type: String,
required: [
true,
"please select category from- short-sleeves, long-sleeves, sweat-shirts, hoodies",
],
enum: {
values: ["shortsleeves", "longsleeves", "sweatshirt", "hoodies"],
message:
"please select category ONLY from - short-sleeves, long-sleeves, sweat-shirts and hoodies ",
},
},
//this field was updated in order videos later
stock: {
type: Number,
required: [true, "please add a number in stock"],
},
brand: {
type: String,
required: [true, "please add a brand for clothing"],
},
ratings: {
type: Number,
default: 0,
},
numberOfReviews: {
type: Number,
default: 0,
},
reviews: [
{
user: {
type: mongoose.Schema.ObjectId,
ref: "User",
required: true,
},
name: {
type: String,
required: true,
},
rating: {
type: Number,
required: true,
},
comment: {
type: String,
required: true,
},
},
],
user: {
type: mongoose.Schema.ObjectId,
ref: "User",
required: true,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Product", productSchema);
================================================
FILE: tshirtstore/lcotshirtstore/models/user.js
================================================
const mongoose = require("mongoose");
const validator = require("validator");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const crypto = require("crypto");
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, "Please provide a name"],
maxlength: [40, "Name should be under 40 characters"],
},
email: {
type: String,
required: [true, "Please provide an email"],
validate: [validator.isEmail, "Please enter email in correct format"],
unique: true,
},
password: {
type: String,
required: [true, "Please provide a password"],
minlength: [6, "password should be atleast 6 char"],
select: false,
},
role: {
type: String,
default: "user",
},
photo: {
id: {
type: String,
required: true,
},
secure_url: {
type: String,
required: true,
},
},
forgotPasswordToken: String,
forgotPasswordExpiry: Date,
createdAt: {
type: Date,
default: Date.now,
},
});
//encrypt password before save - HOOKS
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
return next();
}
this.password = await bcrypt.hash(this.password, 10);
});
// validate the password with passed on user password
userSchema.methods.isValidatedPassword = async function (usersendPassword) {
return await bcrypt.compare(usersendPassword, this.password);
};
//create and return jwt token
userSchema.methods.getJwtToken = function () {
return jwt.sign({ id: this._id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRY,
});
};
//generate forgot password token (string)
userSchema.methods.getForgotPasswordToken = function () {
// generate a long and randomg string
const forgotToken = crypto.randomBytes(20).toString("hex");
// getting a hash - make sure to get a hash on backend
this.forgotPasswordToken = crypto
.createHash("sha256")
.update(forgotToken)
.digest("hex");
//time of token
this.forgotPasswordExpiry = Date.now() + 20 * 60 * 1000;
return forgotToken;
};
module.exports = mongoose.model("User", userSchema);
================================================
FILE: tshirtstore/lcotshirtstore/nodemon.json
================================================
{
"ext": ".js, .jsx, .yaml"
}
================================================
FILE: tshirtstore/lcotshirtstore/package.json
================================================
{
"name": "tshirtstore",
"version": "1.0.0",
"description": "a backend api for tshirt store",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
},
"keywords": [
"api",
"backend"
],
"author": "hitesh choudhary",
"license": "ISC",
"dependencies": {
"bcryptjs": "^2.4.3",
"cloudinary": "^1.27.1",
"cookie-parser": "^1.4.5",
"dotenv": "^10.0.0",
"ejs": "^3.1.6",
"express": "^4.17.1",
"express-fileupload": "^1.2.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^6.0.12",
"morgan": "^1.10.0",
"nodemailer": "^6.7.0",
"razorpay": "^2.0.7",
"stripe": "^8.184.0",
"swagger-ui-express": "^4.1.6",
"validator": "^13.6.0",
"yamljs": "^0.3.0"
},
"devDependencies": {
"nodemon": "^2.0.14"
}
}
================================================
FILE: tshirtstore/lcotshirtstore/routes/home.js
================================================
const express = require("express");
const router = express.Router();
const { home, homeDummy } = require("../controllers/homeController");
router.route("/").get(home);
router.route("/dummy").get(homeDummy);
module.exports = router;
================================================
FILE: tshirtstore/lcotshirtstore/routes/order.js
================================================
const express = require("express");
const {
createOrder,
getOneOrder,
getLoggedInOrders,
admingetAllOrders,
adminUpdateOrder,
adminDeleteOrder,
} = require("../controllers/orderController");
const router = express.Router();
const { isLoggedIn, customRole } = require("../middlewares/user");
router.route("/order/create").post(isLoggedIn, createOrder);
router.route("/order/:id").get(isLoggedIn, getOneOrder);
router.route("/myorder").get(isLoggedIn, getLoggedInOrders);
//admin routes
router
.route("/admin/orders")
.get(isLoggedIn, customRole("admin"), admingetAllOrders);
router
.route("/admin/order/:id")
.put(isLoggedIn, customRole("admin"), adminUpdateOrder)
.delete(isLoggedIn, customRole("admin"), adminDeleteOrder);
module.exports = router;
================================================
FILE: tshirtstore/lcotshirtstore/routes/payment.js
================================================
const express = require("express");
const router = express.Router();
const {
sendRazorpayKey,
sendStripeKey,
captureStripePayment,
captureRazorpayPayment,
} = require("../controllers/paymentController");
const { isLoggedIn } = require("../middlewares/user");
router.route("/stripekey").get(isLoggedIn, sendStripeKey);
router.route("/razorpaykey").get(isLoggedIn, sendRazorpayKey);
router.route("/capturestripe").post(isLoggedIn, captureStripePayment);
router.route("/capturerazorpay").post(isLoggedIn, captureRazorpayPayment);
module.exports = router;
================================================
FILE: tshirtstore/lcotshirtstore/routes/product.js
================================================
const express = require("express");
const {
addProduct,
getAllProduct,
adminGetAllProduct,
getOneProduct,
adminUpdateOneProduct,
adminDeleteOneProduct,
addReview,
deleteReview,
getOnlyReviewsForOneProduct,
} = require("../controllers/productController");
const router = express.Router();
const { isLoggedIn, customRole } = require("../middlewares/user");
//user routes
router.route("/products").get(getAllProduct);
router.route("/product/:id").get(getOneProduct);
router.route("/review").put(isLoggedIn, addReview);
router.route("/review").delete(isLoggedIn, deleteReview);
router.route("/reviews").get(isLoggedIn, getOnlyReviewsForOneProduct);
//admin routes
router
.route("/admin/product/add")
.post(isLoggedIn, customRole("admin"), addProduct);
router
.route("/admin/products")
.get(isLoggedIn, customRole("admin"), adminGetAllProduct);
router
.route("/admin/product/:id")
.put(isLoggedIn, customRole("admin"), adminUpdateOneProduct)
.delete(isLoggedIn, customRole("admin"), adminDeleteOneProduct);
module.exports = router;
================================================
FILE: tshirtstore/lcotshirtstore/routes/user.js
================================================
const express = require("express");
const router = express.Router();
const {
signup,
login,
logout,
forgotPassword,
passwordReset,
getLoggedInUserDetails,
changePassword,
updateUserDetails,
adminAllUser,
managerAllUser,
admingetOneUser,
adminUpdateOneUserDetails,
adminDeleteOneUser,
} = require("../controllers/userController");
const { isLoggedIn, customRole } = require("../middlewares/user");
router.route("/signup").post(signup);
router.route("/login").post(login);
router.route("/logout").get(logout);
router.route("/forgotPassword").post(forgotPassword);
router.route("/password/reset/:token").post(passwordReset);
router.route("/userdashboard").get(isLoggedIn, getLoggedInUserDetails);
router.route("/password/update").post(isLoggedIn, changePassword);
router.route("/userdashboard/update").post(isLoggedIn, updateUserDetails);
//admin only routes
router.route("/admin/users").get(isLoggedIn, customRole("admin"), adminAllUser);
router
.route("/admin/user/:id")
.get(isLoggedIn, customRole("admin"), admingetOneUser)
.put(isLoggedIn, customRole("admin"), adminUpdateOneUserDetails)
.delete(isLoggedIn, customRole("admin"), adminDeleteOneUser);
// manager only route
router
.route("/manager/users")
.get(isLoggedIn, customRole("manager"), managerAllUser);
module.exports = router;
================================================
FILE: tshirtstore/lcotshirtstore/swagger.yaml
================================================
openapi: "3.0.0"
info:
title: Tshirt store API
description: LCO - a course to create API for ecomm store
version: 1.1.0
contact:
email: hitesh@lco.dev
url: "https://lco.dev"
# servers:
# - url: "https://localhost:4000/api/v1"
# description: for local host - secure
# - url: "http://localhost:4000/api/v1"
# description: for local host - regular
servers:
- url: "{protocol}://localhost:4000/api/{version}"
description: for local host
variables:
version:
enum:
- v1
- v2
default: v1
protocol:
enum:
- http
- https
default: http
components:
securitySchemes:
cookieAuth:
type: apiKey
in: cookie
name: token
BearerAuth:
type: http
scheme: bearer
paths:
/dummy:
get:
tags:
- Home
summary: returns a greet message from LCO
responses:
200:
description: All good success
content:
application/json:
schema:
type: string
example: "mystring"
400:
description: Bad request
500:
description: internal server error
/signup:
post:
tags:
- User
summary: signup a new user. required files are - name, email, password and photo
requestBody:
content:
multipart/form-data:
schema:
type: object
required:
- name
- email
- password
- photo
properties:
name:
type: string
required: true
email:
type: string
password:
type: string
photo:
in: formData
description: The uploaded file data
type: file
format: binary
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
token:
type: string
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/login:
post:
tags:
- User
summary: login a new user. required files are - email and password. Also add httpOnly cookie
requestBody:
content:
application/json:
schema:
type: object
required:
- email
- password
properties:
email:
type: string
password:
type: string
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
token:
type: string
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/logout:
get:
tags:
- User
summary: get request to logout the user. Also removes httpOnly cookies
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
message:
type: string
400:
description: Bad request
500:
description: internal server error
/forgotPassword:
post:
tags:
- User
summary: sends an email with link to forgot password. Contains the token for user validation
requestBody:
content:
application/json:
schema:
type: object
required:
- email
properties:
email:
type: string
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
message:
type: string
400:
description: Bad request
500:
description: internal server error
/password/reset/{token}:
post:
tags:
- User
summary: Allows user to reset password, validated based on token. send password and confirm password fields
parameters:
- name: token
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
required:
- password
- confirmPassword
properties:
password:
type: string
confirmPassword:
type: string
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
token:
type: string
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/userdashboard:
get:
tags:
- User
summary: Gets all details about logged in user. Send token in cookies as named token or send Bearer Auth
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/password/update:
post:
tags:
- User
summary: User can update the password if he is logged in. Send oldPassword and password
requestBody:
content:
application/json:
schema:
type: object
required:
- oldPassword
- password
properties:
oldPassword:
type: string
password:
type: string
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
token:
type: string
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/userdashboard/update:
post:
tags:
- User
summary: User can update the name, emails and photo. Photo is optional
requestBody:
content:
multipart/form-data:
schema:
type: object
required:
- name
- email
properties:
name:
type: string
email:
type: string
photo:
in: formData
description: The uploaded file data
type: file
format: binary
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
400:
description: Bad request
500:
description: internal server error
/admin/users:
get:
tags:
- Admin
summary: If user is admin, response will get array of all users
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: array
items:
type: object
properties:
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/admin/user/{id}:
get:
tags:
- Admin
summary: If user is admin, response will get details of 1 user
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
put:
tags:
- Admin
summary: If user is admin, response will get details of 1 user
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: name
in: formData
required: true
schema:
type: string
- name: email
in: formData
required: true
schema:
type: string
- name: role
in: formData
required: true
schema:
type: string
enum: [user, admin, manager]
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
400:
description: Bad request
500:
description: internal server error
delete:
tags:
- Admin
summary: If user is admin, delete the user with given id
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
400:
description: Bad request
500:
description: internal server error
/manager/users:
get:
tags:
- Manager
summary: If manager, response will get array of all users whose role is user
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: array
items:
type: object
properties:
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
================================================
FILE: tshirtstore/lcotshirtstore/utils/cookieToken.js
================================================
const cookieToken = (user, res) => {
const token = user.getJwtToken();
const options = {
expires: new Date(
Date.now() + process.env.COOKIE_TIME * 24 * 60 * 60 * 1000
),
httpOnly: true,
};
user.password = undefined;
res.status(200).cookie("token", token, options).json({
success: true,
token,
user,
});
};
module.exports = cookieToken;
================================================
FILE: tshirtstore/lcotshirtstore/utils/customError.js
================================================
class CustomError extends Error {
constructor(message, code) {
super(message);
this.code = code;
}
}
module.exports = CustomError;
================================================
FILE: tshirtstore/lcotshirtstore/utils/demotest.js
================================================
// User.find({ qty: { $lte: 20 } })
// /api/v1/product?search=coder&page=2&category=shortsleeves&rating[gte]=4
// &price[lte]=999&price[gte]=199
// rating: { $gte: '4' }
// URL - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace
// const p = 'gte gte lte mygte';
// const regex = /\b(gte|lte)\b/g;
// console.log(p.replace(regex, m => `$${m}`));
================================================
FILE: tshirtstore/lcotshirtstore/utils/emailHelper.js
================================================
const nodemailer = require("nodemailer");
const mailHelper = async (option) => {
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
auth: {
user: process.env.SMTP_USER, // generated ethereal user
pass: process.env.SMTP_PASS, // generated ethereal password
},
});
const message = {
from: "hitesh@lco.dev", // sender address
to: option.email, // list of receivers
subject: option.subject, // Subject line
text: option.message, // plain text body
};
// send mail with defined transport object
await transporter.sendMail(message);
};
module.exports = mailHelper;
================================================
FILE: tshirtstore/lcotshirtstore/utils/testOrder.json
================================================
{
"shippingInfo": {
"address": "1 Jaipur",
"city": "Jaipur",
"phoneNo": "9898989898",
"postalCode": "302020",
"state": "Rajasthan",
"country": "India"
},
"orderItems": [
{
"name": "Pro Coder tshirts",
"quantity": 1,
"image": "https://res.cloudinary.com/dk92l1yoc/image/upload/v1635757229/products/b4laryk4dbp6vdrvq3wv.png",
"price": 999,
"product": "617facb5333fd4c0fdfdee65"
}
],
"paymentInfo": {
"id": "testString"
},
"taxAmount": 40,
"shippingAmount": 10,
"totalAmount": 100
}
================================================
FILE: tshirtstore/lcotshirtstore/utils/whereClause.js
================================================
// base - Product.find()
// base - Product.find(email: {"hitesh@lco.dev"})
//bigQ - //search=coder&page=2&category=shortsleeves&rating[gte]=4
// &price[lte]=999&price[gte]=199&limit=5
class WhereClause {
constructor(base, bigQ) {
this.base = base;
this.bigQ = bigQ;
}
search() {
const searchword = this.bigQ.search
? {
name: {
$regex: this.bigQ.search,
$options: "i",
},
}
: {};
this.base = this.base.find({ ...searchword });
return this;
}
filter() {
const copyQ = { ...this.bigQ };
delete copyQ["search"];
delete copyQ["limit"];
delete copyQ["page"];
//convert bigQ into a string => copyQ
let stringOfCopyQ = JSON.stringify(copyQ);
stringOfCopyQ = stringOfCopyQ.replace(
/\b(gte|lte|gt|lt)\b/g,
(m) => `$${m}`
);
const jsonOfCopyQ = JSON.parse(stringOfCopyQ);
this.base = this.base.find(jsonOfCopyQ);
return this;
}
pager(resultperPage) {
let currentPage = 1;
if (this.bigQ.page) {
currentPage = this.bigQ.page;
}
const skipVal = resultperPage * (currentPage - 1);
this.base = this.base.limit(resultperPage).skip(skipVal);
return this;
}
}
module.exports = WhereClause;
================================================
FILE: tshirtstore/lcotshirtstore/views/signuptest.ejs
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>GET form</title>
</head>
<body class="bg-dark text-white">
<div class="container mt-4 col-4 col-offset-6">
<h1 class="display-3">POST form</h1>
<form method="POST" action="/api/v1/signup" enctype="multipart/form-data">
<div class="mb-3">
<label for="name" class="form-label">firstname</label>
<input type="text" name="name" class="form-control" id="name" aria-describedby="emailHelp">
</div>
<div class="mb-3">
<label for="email" class="form-label">email</label>
<input type="text" name="email" class="form-control" id="email" aria-describedby="emailHelp">
</div>
<div class="mb-3">
<label for="password" class="form-label">email</label>
<input type="password" name="password" class="form-control" id="password" aria-describedby="emailHelp">
</div>
<div class="mb-3">
<label for="photo" class="form-label">samplefile</label>
<input type="file" name="photo" multiple class="form-control" id="lastname">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>
================================================
FILE: tshirtstore/middlewares/bigPromise.js
================================================
// try catch and async - await || use promise
module.exports = (func) => (req, res, next) =>
Promise.resolve(func(req, res, next)).catch(next);
================================================
FILE: tshirtstore/middlewares/productionError.js
================================================
const CustomError = require("../utils/customError");
module.exports = (err, req, res, next) => {
let error = { ...err };
error.message = err.message;
res.status(error.statusCode || 500).json({
success: false,
message: error.message || "Internal Server Error",
});
};
================================================
FILE: tshirtstore/middlewares/user.js
================================================
const User = require("../models/user");
const BigPromise = require("../middlewares/bigPromise");
const CustomError = require("../utils/customError");
const jwt = require("jsonwebtoken");
exports.isLoggedIn = BigPromise(async (req, res, next) => {
// const token = req.cookies.token || req.header("Authorization").replace("Bearer ", "");
// check token first in cookies
let token = req.cookies.token;
// if token not found in cookies, check if header contains Auth field
if (!token && req.header("Authorization")) {
token = req.header("Authorization").replace("Bearer ", "");
}
if (!token) {
return next(new CustomError("Login first to access this page", 401));
}
const decoded = jwt.verify(token, process.env.JWT_SECRET);
req.user = await User.findById(decoded.id);
next();
});
exports.customRole = (...roles) => {
return (req, res, next) => {
if (!roles.includes(req.user.role)) {
return next(new CustomError("You are not allowed for this resouce", 403));
}
console.log(req.user.role);
next();
};
};
================================================
FILE: tshirtstore/models/order.js
================================================
const mongoose = require("mongoose");
// shippingInfo{}
// user,
// paymentInfo{}
// taxAmount
// ShippingAmount
// totalAmount
// orderStatus
// deliveredAt
// createdAt
// -------------
// orderItems: [ {} ]
// - name
// - quantity
// - image[0]
// - price
// - product
const orderSchema = new mongoose.Schema({
shippingInfo: {
address: {
type: String,
required: true,
},
city: {
type: String,
required: true,
},
phoneNo: {
type: String,
required: true,
},
postalCode: {
type: String,
required: true,
},
state: {
type: String,
// required: true,
},
country: {
type: String,
required: true,
},
},
user: {
type: mongoose.Schema.ObjectId, //mongoose.Schema.Types.ObjectId
ref: "User",
required: true,
},
orderItems: [
{
name: {
type: String,
required: true,
},
quantity: {
type: Number,
required: true,
},
image: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
product: {
type: mongoose.Schema.ObjectId, //mongoose.Schema.Types.ObjectId
ref: "Product",
required: true,
},
},
],
paymentInfo: {
id: {
type: String,
},
},
taxAmount: {
type: Number,
required: true,
},
shippingAmount: {
type: Number,
required: true,
},
totalAmount: {
type: Number,
required: true,
},
orderStatus: {
type: String,
required: true,
default: "processing",
},
deliveredAt: {
type: Date,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Order", orderSchema);
// ref link
// https://stackoverflow.com/questions/28997636/should-i-use-schema-types-objectid-or-schema-objectid-when-defining-a-mongoose-s
================================================
FILE: tshirtstore/models/product.js
================================================
const mongoose = require("mongoose");
const productSchema = new mongoose.Schema({
name: {
type: String,
required: [true, "please provide product name"],
trim: true,
maxlength: [120, "Product name should not be more than 120 characters"],
},
price: {
type: Number,
required: [true, "please provide product price"],
maxlength: [6, "Product price should not be more than 6 digits"],
},
description: {
type: String,
required: [true, "please provide product description"],
},
photos: [
{
id: {
type: String,
required: true,
},
secure_url: {
type: String,
required: true,
},
},
],
category: {
type: String,
required: [
true,
"please select category from- short-sleeves, long-sleeves, sweat-shirts, hoodies",
],
enum: {
values: ["shortsleeves", "longsleeves", "sweatshirt", "hoodies"],
message:
"please select category ONLY from - short-sleeves, long-sleeves, sweat-shirts and hoodies ",
},
},
//this field was updated in order videos later
stock: {
type: Number,
required: [true, "please add a number in stock"],
},
brand: {
type: String,
required: [true, "please add a brand for clothing"],
},
ratings: {
type: Number,
default: 0,
},
numberOfReviews: {
type: Number,
default: 0,
},
reviews: [
{
user: {
type: mongoose.Schema.ObjectId,
ref: "User",
required: true,
},
name: {
type: String,
required: true,
},
rating: {
type: Number,
required: true,
},
comment: {
type: String,
required: true,
},
},
],
user: {
type: mongoose.Schema.ObjectId,
ref: "User",
required: true,
},
createdAt: {
type: Date,
default: Date.now,
},
});
module.exports = mongoose.model("Product", productSchema);
================================================
FILE: tshirtstore/models/user.js
================================================
const mongoose = require("mongoose");
const validator = require("validator");
const bcrypt = require("bcryptjs");
const jwt = require("jsonwebtoken");
const crypto = require("crypto");
const userSchema = new mongoose.Schema({
name: {
type: String,
required: [true, "Please provide a name"],
maxlength: [40, "Name should be under 40 characters"],
},
email: {
type: String,
required: [true, "Please provide an email"],
validate: [validator.isEmail, "Please enter email in correct format"],
unique: true,
},
password: {
type: String,
required: [true, "Please provide a password"],
minlength: [6, "password should be atleast 6 char"],
select: false,
},
role: {
type: String,
default: "user",
},
photo: {
id: {
type: String,
required: true,
},
secure_url: {
type: String,
required: true,
},
},
forgotPasswordToken: String,
forgotPasswordExpiry: Date,
createdAt: {
type: Date,
default: Date.now,
},
});
//encrypt password before save - HOOKS
userSchema.pre("save", async function (next) {
if (!this.isModified("password")) {
return next();
}
this.password = await bcrypt.hash(this.password, 10);
});
// validate the password with passed on user password
userSchema.methods.isValidatedPassword = async function (usersendPassword) {
return await bcrypt.compare(usersendPassword, this.password);
};
//create and return jwt token
userSchema.methods.getJwtToken = function () {
return jwt.sign({ id: this._id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRY,
});
};
//generate forgot password token (string)
userSchema.methods.getForgotPasswordToken = function () {
// generate a long and randomg string
const forgotToken = crypto.randomBytes(20).toString("hex");
// getting a hash - make sure to get a hash on backend
this.forgotPasswordToken = crypto
.createHash("sha256")
.update(forgotToken)
.digest("hex");
//time of token
this.forgotPasswordExpiry = Date.now() + 20 * 60 * 1000;
return forgotToken;
};
module.exports = mongoose.model("User", userSchema);
================================================
FILE: tshirtstore/nodemon.json
================================================
{
"ext": ".js, .jsx, .yaml"
}
================================================
FILE: tshirtstore/package.json
================================================
{
"name": "tshirtstore",
"version": "1.0.0",
"description": "a backend api for tshirt store",
"main": "index.js",
"scripts": {
"start": "node index.js",
"dev": "nodemon index.js"
},
"keywords": [
"api",
"backend"
],
"author": "hitesh choudhary",
"license": "ISC",
"dependencies": {
"bcryptjs": "^2.4.3",
"cloudinary": "^1.27.1",
"cookie-parser": "^1.4.5",
"dotenv": "^10.0.0",
"ejs": "^3.1.6",
"express": "^4.17.1",
"express-fileupload": "^1.2.1",
"jsonwebtoken": "^8.5.1",
"mongoose": "^6.0.12",
"morgan": "^1.10.0",
"nodemailer": "^6.7.0",
"razorpay": "^2.0.7",
"stripe": "^8.184.0",
"swagger-ui-express": "^4.1.6",
"validator": "^13.6.0",
"yamljs": "^0.3.0"
},
"devDependencies": {
"nodemon": "^2.0.14"
}
}
================================================
FILE: tshirtstore/routes/home.js
================================================
const express = require("express");
const router = express.Router();
const { home, homeDummy } = require("../controllers/homeController");
router.route("/").get(home);
router.route("/dummy").get(homeDummy);
module.exports = router;
================================================
FILE: tshirtstore/routes/order.js
================================================
const express = require("express");
const {
createOrder,
getOneOrder,
getLoggedInOrders,
admingetAllOrders,
adminUpdateOrder,
adminDeleteOrder,
} = require("../controllers/orderController");
const router = express.Router();
const { isLoggedIn, customRole } = require("../middlewares/user");
router.route("/order/create").post(isLoggedIn, createOrder);
router.route("/order/:id").get(isLoggedIn, getOneOrder);
router.route("/myorder").get(isLoggedIn, getLoggedInOrders);
//admin routes
router
.route("/admin/orders")
.get(isLoggedIn, customRole("admin"), admingetAllOrders);
router
.route("/admin/order/:id")
.put(isLoggedIn, customRole("admin"), adminUpdateOrder)
.delete(isLoggedIn, customRole("admin"), adminDeleteOrder);
module.exports = router;
================================================
FILE: tshirtstore/routes/payment.js
================================================
const express = require("express");
const router = express.Router();
const {
sendRazorpayKey,
sendStripeKey,
captureStripePayment,
captureRazorpayPayment,
} = require("../controllers/paymentController");
const { isLoggedIn } = require("../middlewares/user");
router.route("/stripekey").get(isLoggedIn, sendStripeKey);
router.route("/razorpaykey").get(isLoggedIn, sendRazorpayKey);
router.route("/capturestripe").post(isLoggedIn, captureStripePayment);
router.route("/capturerazorpay").post(isLoggedIn, captureRazorpayPayment);
module.exports = router;
================================================
FILE: tshirtstore/routes/product.js
================================================
const express = require("express");
const {
addProduct,
getAllProduct,
adminGetAllProduct,
getOneProduct,
adminUpdateOneProduct,
adminDeleteOneProduct,
addReview,
deleteReview,
getOnlyReviewsForOneProduct,
} = require("../controllers/productController");
const router = express.Router();
const { isLoggedIn, customRole } = require("../middlewares/user");
//user routes
router.route("/products").get(getAllProduct);
router.route("/product/:id").get(getOneProduct);
router.route("/review").put(isLoggedIn, addReview);
router.route("/review").delete(isLoggedIn, deleteReview);
router.route("/reviews").get(isLoggedIn, getOnlyReviewsForOneProduct);
//admin routes
router
.route("/admin/product/add")
.post(isLoggedIn, customRole("admin"), addProduct);
router
.route("/admin/products")
.get(isLoggedIn, customRole("admin"), adminGetAllProduct);
router
.route("/admin/product/:id")
.put(isLoggedIn, customRole("admin"), adminUpdateOneProduct)
.delete(isLoggedIn, customRole("admin"), adminDeleteOneProduct);
module.exports = router;
================================================
FILE: tshirtstore/routes/user.js
================================================
const express = require("express");
const router = express.Router();
const {
signup,
login,
logout,
forgotPassword,
passwordReset,
getLoggedInUserDetails,
changePassword,
updateUserDetails,
adminAllUser,
managerAllUser,
admingetOneUser,
adminUpdateOneUserDetails,
adminDeleteOneUser,
} = require("../controllers/userController");
const { isLoggedIn, customRole } = require("../middlewares/user");
router.route("/signup").post(signup);
router.route("/login").post(login);
router.route("/logout").get(logout);
router.route("/forgotPassword").post(forgotPassword);
router.route("/password/reset/:token").put(passwordReset);
router.route("/userdashboard").get(isLoggedIn, getLoggedInUserDetails);
router.route("/password/update").put(isLoggedIn, changePassword);
router.route("/userdashboard/update").put(isLoggedIn, updateUserDetails);
//admin only routes
router.route("/admin/users").get(isLoggedIn, customRole("admin"), adminAllUser);
router
.route("/admin/user/:id")
.get(isLoggedIn, customRole("admin"), admingetOneUser)
.put(isLoggedIn, customRole("admin"), adminUpdateOneUserDetails)
.delete(isLoggedIn, customRole("admin"), adminDeleteOneUser);
// manager only route
router
.route("/manager/users")
.get(isLoggedIn, customRole("manager"), managerAllUser);
module.exports = router;
================================================
FILE: tshirtstore/swagger.yaml
================================================
openapi: "3.0.0"
info:
title: Tshirt store API
description: LCO - a course to create API for ecomm store
version: 1.1.0
contact:
email: hitesh@lco.dev
url: "https://lco.dev"
# servers:
# - url: "https://localhost:4000/api/v1"
# description: for local host - secure
# - url: "http://localhost:4000/api/v1"
# description: for local host - regular
servers:
- url: "{protocol}://{url}/api/{version}"
description: for local host
variables:
version:
enum:
- v1
- v2
default: v1
url:
enum:
- localhost:4000
- lcotshirtstore.herokuapp.com
default: lcotshirtstore.herokuapp.com
protocol:
enum:
- http
- https
default: https
components:
securitySchemes:
cookieAuth:
type: apiKey
in: cookie
name: token
BearerAuth:
type: http
scheme: bearer
paths:
/dummy:
get:
tags:
- Home
summary: returns a greet message from LCO
responses:
200:
description: All good success
content:
application/json:
schema:
type: string
example: "mystring"
400:
description: Bad request
500:
description: internal server error
/signup:
post:
tags:
- User
summary: signup a new user. required files are - name, email, password and photo
requestBody:
content:
multipart/form-data:
schema:
type: object
required:
- name
- email
- password
- photo
properties:
name:
type: string
required: true
email:
type: string
password:
type: string
photo:
in: formData
description: The uploaded file data
type: file
format: binary
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
token:
type: string
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/login:
post:
tags:
- User
summary: login a new user. required files are - email and password. Also adds httpOnly cookie in browser. It sends token in response too.
requestBody:
content:
application/json:
schema:
type: object
required:
- email
- password
properties:
email:
type: string
password:
type: string
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
token:
type: string
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/logout:
get:
tags:
- User
summary: get request to logout the user. Also removes httpOnly cookies
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
message:
type: string
400:
description: Bad request
500:
description: internal server error
/forgotPassword:
post:
tags:
- User
summary: sends an email with link to forgot password. Contains the token for user validation. Public hosted version will not send email to your account. Use your own SMTP details to access this feature on local project
requestBody:
content:
application/json:
schema:
type: object
required:
- email
properties:
email:
type: string
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
message:
type: string
400:
description: Bad request
500:
description: internal server error
/password/reset/{token}:
post:
tags:
- User
summary: Allows user to reset password, validated based on token. send password and confirm password fields
parameters:
- name: token
in: path
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
required:
- password
- confirmPassword
properties:
password:
type: string
confirmPassword:
type: string
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
token:
type: string
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/userdashboard:
get:
tags:
- User
summary: Gets all details about logged in user. Send token in cookies as named token or send Bearer Auth
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/password/update:
post:
tags:
- User
summary: User can update the password if he is logged in. Send oldPassword and password
requestBody:
content:
application/json:
schema:
type: object
required:
- oldPassword
- password
properties:
oldPassword:
type: string
password:
type: string
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
token:
type: string
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/userdashboard/update:
post:
tags:
- User
summary: User can update the name, emails and photo. Photo is optional
requestBody:
content:
multipart/form-data:
schema:
type: object
required:
- name
- email
properties:
name:
type: string
email:
type: string
photo:
in: formData
description: The uploaded file data
type: file
format: binary
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
400:
description: Bad request
500:
description: internal server error
/admin/users:
get:
tags:
- Admin
summary: If user is admin, response will get array of all users
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: array
items:
type: object
properties:
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/admin/user/{id}:
get:
tags:
- Admin
summary: If user is admin, response will get details of 1 user
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
put:
tags:
- Admin
summary: If user is admin, he can update mentioned fields in user
parameters:
- name: id
in: path
required: true
schema:
type: string
- name: name
in: formData
required: true
schema:
type: string
- name: email
in: formData
required: true
schema:
type: string
- name: role
in: formData
required: true
schema:
type: string
enum: [user, admin, manager]
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
400:
description: Bad request
500:
description: internal server error
delete:
tags:
- Admin
summary: If user is admin, delete the user with given id
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
400:
description: Bad request
500:
description: internal server error
/manager/users:
get:
tags:
- Manager
summary: If manager, response will get array of all users whose role is user
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: array
items:
type: object
properties:
user:
type: object
properties:
name:
type: string
email:
type: string
role:
type: string
photo:
type: object
properties:
id:
type: string
secure_url:
type: string
_id:
type: string
createdAt:
type: string
400:
description: Bad request
500:
description: internal server error
/products:
get:
tags:
- Product
summary: A simple get request will give you all available products
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
filteredProductNumber:
type: number
totalcountProduct:
type: number
products:
type: array
items:
type: object
properties:
_id:
type: string
name:
type: string
price:
type: number
description:
type: string
category:
type: string
brand:
type: string
ratings:
type: number
numberOfReviews:
type: number
user:
type: string
photos:
type: array
items:
type: object
properties:
id:
type: string
secure_url:
type: string
reviews:
type: array
items:
type: object
properties:
id:
type: string
comment:
type: string
user:
type: string
name:
type: string
rating:
type: number
400:
description: Bad request
500:
description: internal server error
/product/{id}:
get:
tags:
- Product
summary: Get a single product
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
product:
type: object
properties:
_id:
type: string
name:
type: string
price:
type: number
description:
type: string
category:
type: string
brand:
type: string
ratings:
type: number
numberOfReviews:
type: number
user:
type: string
photos:
type: array
items:
type: object
properties:
id:
type: string
secure_url:
type: string
reviews:
type: array
items:
type: object
properties:
id:
type: string
comment:
type: string
user:
type: string
name:
type: string
rating:
type: number
400:
description: Bad request
500:
description: internal server error
/admin/products:
get:
tags:
- Admin
summary: If user is admin, he get all products
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
products:
type: array
items:
type: object
properties:
_id:
type: string
name:
type: string
price:
type: number
description:
type: string
category:
type: string
brand:
type: string
ratings:
type: number
numberOfReviews:
type: number
user:
type: string
photos:
type: array
items:
type: object
properties:
id:
type: string
secure_url:
type: string
reviews:
type: array
items:
type: object
properties:
id:
type: string
comment:
type: string
user:
type: string
name:
type: string
rating:
type: number
400:
description: Bad request
500:
description: internal server error
/admin/product/add:
post:
tags:
- Admin
summary: If admin, Add a product
requestBody:
content:
multipart/form-data:
schema:
type: object
required:
- name
- price
- description
- category
- stock
- brand
- photos
properties:
name:
type: string
required: true
price:
type: number
required: true
description:
type: string
required: true
category:
type: string
required: true
enum: [shortsleeves, longsleeves, sweatshirt, hoodies]
stock:
type: number
required: true
brand:
type: string
required: true
photos:
in: formData
description: The uploaded photos
type: array
items:
type: file
format: binary
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
product:
type: object
properties:
_id:
type: string
name:
type: string
price:
type: number
description:
type: string
category:
type: string
brand:
type: string
ratings:
type: number
numberOfReviews:
type: number
user:
type: string
photos:
type: array
items:
type: object
properties:
id:
type: string
secure_url:
type: string
reviews:
type: array
items:
type: object
properties:
id:
type: string
comment:
type: string
user:
type: string
name:
type: string
rating:
type: number
400:
description: Bad request
500:
description: internal server error
/admin/product/{id}:
put:
tags:
- Admin
summary: If admin, update the product. photos are optional to pass. Rest all body is set to be updated to what you pass here.
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
content:
multipart/form-data:
schema:
type: object
required:
- name
- price
- description
- category
- stock
- brand
properties:
name:
type: string
required: true
price:
type: number
required: true
description:
type: number
required: true
category:
type: string
required: true
enum: [shortsleeves, longsleeves, sweatshirt, hoodies]
stock:
type: number
required: true
brand:
type: string
required: true
photos:
in: formData
description: The uploaded photos
type: file
format: binary
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
product:
type: object
properties:
_id:
type: string
name:
type: string
price:
type: number
description:
type: string
category:
type: string
brand:
type: string
ratings:
type: number
numberOfReviews:
type: number
user:
type: string
photos:
type: array
items:
type: object
properties:
id:
type: string
secure_url:
type: string
reviews:
type: array
items:
type: object
properties:
id:
type: string
comment:
type: string
user:
type: string
name:
type: string
rating:
type: number
400:
description: Bad request
500:
description: internal server error
delete:
tags:
- Admin
summary: If admin, pass the id of product and product will be removed
parameters:
- name: id
in: path
required: true
schema:
type: string
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
message:
type: string
400:
description: Bad request
500:
description: internal server error
/reviews:
get:
tags:
- Product
summary: A simple get request will give you all reviews for given products
parameters:
- name: id
in: query
description: id of the product
required: true
schema:
type: string
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
reviews:
type: array
items:
type: object
properties:
user:
type: string
name:
type: string
rating:
type: number
comment:
type: string
_id:
type: string
400:
description: Bad request
500:
description: internal server error
/review:
put:
tags:
- Product
summary: A logged in user can post a review on any product. If review is already posted, it will just update the existing review
parameters:
requestBody:
content:
application/json:
schema:
type: object
required:
- rating
- comment
- productId
properties:
rating:
type: number
required: true
comment:
type: string
required: true
productId:
type: string
required: true
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
reviews:
type: array
items:
type: object
properties:
user:
type: string
name:
type: string
rating:
type: number
comment:
type: string
_id:
type: string
400:
description: Bad request
500:
description: internal server error
delete:
tags:
- Product
summary: Delete the review of logged in user on given product id.
parameters:
- name: productId
in: query
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
type: object
required:
- rating
- comment
- productId
properties:
rating:
type: number
required: true
comment:
type: string
required: true
productId:
type: string
required: true
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
reviews:
type: array
items:
type: object
properties:
user:
type: string
name:
type: string
rating:
type: number
comment:
type: string
_id:
type: string
400:
description: Bad request
500:
description: internal server error
/order/create:
post:
tags:
- Order
summary: create a new order with given details
parameters:
requestBody:
content:
application/json:
schema:
type: object
required:
- shippingInfo
- paymentInfo
- taxAmount
- shippingAmount
- totalAmount
- orderItems
properties:
shippingInfo:
type: object
properties:
address:
type: string
city:
type: string
phoneNo:
type: string
postalCode:
type: string
state:
type: string
country:
type: string
paymentInfo:
type: object
properties:
id:
type: string
taxAmount:
type: number
shippingAmount:
type: number
totalAmount:
type: number
orderItems:
type: array
items:
type: object
properties:
name:
type: string
quantity:
type: string
image:
type: string
price:
type: number
product:
type: string
description: id of product
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
order:
type: object
properties:
_id:
type: string
user:
type: string
orderStatus:
type: string
createdAt:
type: string
shippingInfo:
type: object
properties:
address:
type: string
city:
type: string
phoneNo:
type: string
postalCode:
type: string
state:
type: string
country:
type: string
paymentInfo:
type: object
properties:
id:
type: string
taxAmount:
type: number
shippingAmount:
type: number
totalAmount:
type: number
orderItems:
type: array
items:
type: object
properties:
name:
type: string
quantity:
type: string
image:
type: string
price:
type: number
product:
type: string
description: id of product
400:
description: Bad request
500:
description: internal server error
/order/{id}:
get:
tags:
- Order
summary: get details about a order with order id
parameters:
- name: id
in: path
required: true
description: id of the order
schema:
type: string
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
order:
type: object
properties:
_id:
type: string
user:
type: object
properties:
name:
type: string
email:
type: string
id:
type: string
orderStatus:
type: string
createdAt:
type: string
shippingInfo:
type: object
properties:
address:
type: string
city:
type: string
phoneNo:
type: string
postalCode:
type: string
state:
type: string
country:
type: string
paymentInfo:
type: object
properties:
id:
type: string
taxAmount:
type: number
shippingAmount:
type: number
totalAmount:
type: number
orderItems:
type: array
items:
type: object
properties:
name:
type: string
quantity:
type: string
image:
type: string
price:
type: number
product:
type: string
description: id of product
400:
description: Bad request
500:
description: internal server error
/myorder:
get:
tags:
- Order
summary: get order of logged in user
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
order:
type: object
properties:
_id:
type: string
user:
type: object
properties:
name:
type: string
email:
type: string
id:
type: string
orderStatus:
type: string
createdAt:
type: string
shippingInfo:
type: object
properties:
address:
type: string
city:
type: string
phoneNo:
type: string
postalCode:
type: string
state:
type: string
country:
type: string
paymentInfo:
type: object
properties:
id:
type: string
taxAmount:
type: number
shippingAmount:
type: number
totalAmount:
type: number
orderItems:
type: array
items:
type: object
properties:
name:
type: string
quantity:
type: string
image:
type: string
price:
type: number
product:
type: string
description: id of product
400:
description: Bad request
500:
description: internal server error
/admin/orders:
get:
tags:
- Admin
summary: if admin, get list of all orders
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
orders:
type: array
items:
properties:
_id:
type: string
user:
type: string
orderStatus:
type: string
createdAt:
type: string
shippingInfo:
type: object
properties:
address:
type: string
city:
type: string
phoneNo:
type: string
postalCode:
type: string
state:
type: string
country:
type: string
paymentInfo:
type: object
properties:
id:
type: string
taxAmount:
type: number
shippingAmount:
type: number
totalAmount:
type: number
orderItems:
type: array
items:
type: object
properties:
name:
type: string
quantity:
type: string
image:
type: string
price:
type: number
product:
type: string
description: id of product
400:
description: Bad request
500:
description: internal server error
/admin/order/{id}:
put:
tags:
- Admin
summary: if admin, update the status of the order
parameters:
- name: id
in: path
required: true
description: id of the order
schema:
type: string
requestBody:
content:
multipart/form-data:
schema:
type: object
required:
- orderStatus
properties:
orderStatus:
type: string
enum: [Processing, Delivered]
required: true
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
order:
type: object
properties:
_id:
type: string
user:
type: string
orderStatus:
type: string
createdAt:
type: string
shippingInfo:
type: object
properties:
address:
type: string
city:
type: string
phoneNo:
type: string
postalCode:
type: string
state:
type: string
country:
type: string
paymentInfo:
type: object
properties:
id:
type: string
taxAmount:
type: number
shippingAmount:
type: number
totalAmount:
type: number
orderItems:
type: array
items:
type: object
properties:
name:
type: string
quantity:
type: string
image:
type: string
price:
type: number
product:
type: string
description: id of product
400:
description: Bad request
500:
description: internal server error
delete:
tags:
- Admin
summary: if admin, delete an order with given id
parameters:
- name: id
in: path
required: true
description: id of the order
schema:
type: string
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
400:
description: Bad request
500:
description: internal server error
/stripekey:
get:
tags:
- Payment
summary: gets you the public stripe key
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
stripekey:
type: string
400:
description: Bad request
500:
description: internal server error
/razorpaykey:
get:
tags:
- Payment
summary: gets you the public razorpay key
requestBody:
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
razorpaykey:
type: string
400:
description: Bad request
500:
description: internal server error
/capturestripe:
post:
tags:
- Payment
summary: send amount in number. Send amount after multiplying by 100. Also request from swagger UI are not proper as to capture payment we need to send dummy card details
requestBody:
content:
multipart/form-data:
schema:
type: object
required:
- amount
properties:
amount:
type: number
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
amount:
type: number
client_secret:
type: string
400:
description: Bad request
500:
description: internal server error
/capturerazorpay:
post:
tags:
- Payment
summary: send amount in number. Send amount after multiplying by 100. Check orders tab, not payments. Also request from swagger UI are not proper as to capture payment we need to send dummy card details.
requestBody:
content:
multipart/form-data:
schema:
type: object
required:
- amount
properties:
amount:
type: number
responses:
200:
description: All good success
content:
application/json:
schema:
type: object
properties:
success:
type: boolean
amount:
type: number
order:
type: object
properties:
id:
type: string
amount:
type: number
currency:
type: string
400:
description: Bad request
500:
description: internal server error
================================================
FILE: tshirtstore/utils/cookieToken.js
================================================
const cookieToken = (user, res) => {
const token = user.getJwtToken();
const options = {
expires: new Date(
Date.now() + process.env.COOKIE_TIME * 24 * 60 * 60 * 1000
),
httpOnly: true,
};
user.password = undefined;
res.status(200).cookie("token", token, options).json({
success: true,
token,
user,
});
};
module.exports = cookieToken;
================================================
FILE: tshirtstore/utils/customError.js
================================================
class CustomError extends Error {
constructor(message, statusCode) {
super(message);
this.statusCode = statusCode;
Error.captureStackTrace(this, this.constructor)
}
}
module.exports = CustomError;
================================================
FILE: tshirtstore/utils/demotest.js
================================================
// User.find({ qty: { $lte: 20 } })
// /api/v1/product?search=coder&page=2&category=shortsleeves&rating[gte]=4
// &price[lte]=999&price[gte]=199
// rating: { $gte: '4' }
// URL - https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace
// const p = 'gte gte lte mygte';
// const regex = /\b(gte|lte)\b/g;
// console.log(p.replace(regex, m => `$${m}`));
================================================
FILE: tshirtstore/utils/emailHelper.js
================================================
const nodemailer = require("nodemailer");
const mailHelper = async (option) => {
const transporter = nodemailer.createTransport({
host: process.env.SMTP_HOST,
port: process.env.SMTP_PORT,
auth: {
user: process.env.SMTP_USER, // generated ethereal user
pass: process.env.SMTP_PASS, // generated ethereal password
},
});
const message = {
from: "hitesh@lco.dev", // sender address
to: option.email, // list of receivers
subject: option.subject, // Subject line
text: option.message, // plain text body
};
// send mail with defined transport object
await transporter.sendMail(message);
};
module.exports = mailHelper;
================================================
FILE: tshirtstore/utils/testOrder.json
================================================
{
"shippingInfo": {
"address": "1 Jaipur",
"city": "Jaipur",
"phoneNo": "9898989898",
"postalCode": "302020",
"state": "Rajasthan",
"country": "India"
},
"orderItems": [
{
"name": "Pro Coder tshirts",
"quantity": 1,
"image": "https://res.cloudinary.com/dk92l1yoc/image/upload/v1635757229/products/b4laryk4dbp6vdrvq3wv.png",
"price": 999,
"product": "617facb5333fd4c0fdfdee65"
}
],
"paymentInfo": {
"id": "testString"
},
"taxAmount": 40,
"shippingAmount": 10,
"totalAmount": 100
}
================================================
FILE: tshirtstore/utils/whereClause.js
================================================
// base - Product.find()
// base - Product.find(email: {"hitesh@lco.dev"})
//bigQ - //search=coder&page=2&category=shortsleeves&rating[gte]=4
// &price[lte]=999&price[gte]=199&limit=5
class WhereClause {
constructor(base, bigQ) {
this.base = base;
this.bigQ = bigQ;
}
search() {
const searchword = this.bigQ.search
? {
name: {
$regex: this.bigQ.search,
$options: "i",
},
}
: {};
this.base = this.base.find({ ...searchword });
return this;
}
filter() {
const copyQ = { ...this.bigQ };
delete copyQ["search"];
delete copyQ["limit"];
delete copyQ["page"];
//convert bigQ into a string => copyQ
let stringOfCopyQ = JSON.stringify(copyQ);
stringOfCopyQ = stringOfCopyQ.replace(
/\b(gte|lte|gt|lt)\b/g,
(m) => `$${m}`
);
const jsonOfCopyQ = JSON.parse(stringOfCopyQ);
this.base = this.base.find(jsonOfCopyQ);
return this;
}
pager(resultperPage) {
let currentPage = 1;
if (this.bigQ.page) {
currentPage = this.bigQ.page;
}
const skipVal = resultperPage * (currentPage - 1);
this.base = this.base.limit(resultperPage).skip(skipVal);
return this;
}
}
module.exports = WhereClause;
================================================
FILE: tshirtstore/views/home.ejs
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" >
<title>LCO Tshirt store</title>
</head>
<body class="bg-dark ">
<div class="container mt-5">
<div class="row">
<div class="col-sm-6 mt-2">
<div class="card">
<div class="card-body">
<h5 class="card-title">Read API docs here</h5>
<p class="card-text">All API docs are available here. You have access to everything except admin credentials. If you are a team member of LCO, get it from me (Hitesh)</p>
<a href="/api-docs" class="btn btn-primary">Store DOCS</a>
</div>
</div>
</div>
<div class="col-sm-6 mt-2">
<div class="card">
<div class="card-body">
<h5 class="card-title">LCO course</h5>
<p class="card-text">You can visit our courses at LearnCodeonline. There is something amazing for everyone there.</p>
<a href="https://courses.learncodeonline.in/learn" target="_blank" class="btn btn-primary">Visit LCO</a>
</div>
</div>
</div>
</div>
</div>
</body>
</html>
================================================
FILE: tshirtstore/views/signuptest.ejs
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- CSS only -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<title>GET form</title>
</head>
<body class="bg-dark text-white">
<div class="container mt-4 col-4 col-offset-6">
<h1 class="display-3">POST form</h1>
<form method="POST" action="/api/v1/signup" enctype="multipart/form-data">
<div class="mb-3">
<label for="name" class="form-label">firstname</label>
<input type="text" name="name" class="form-control" id="name" aria-describedby="emailHelp">
</div>
<div class="mb-3">
<label for="email" class="form-label">email</label>
<input type="text" name="email" class="form-control" id="email" aria-describedby="emailHelp">
</div>
<div class="mb-3">
<label for="password" class="form-label">email</label>
<input type="password" name="password" class="form-control" id="password" aria-describedby="emailHelp">
</div>
<div class="mb-3">
<label for="photo" class="form-label">samplefile</label>
<input type="file" name="photo" multiple class="form-control" id="lastname">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</body>
</html>
gitextract_2i27geyc/
├── formsandimages/
│ ├── index.js
│ ├── package.json
│ └── views/
│ ├── getform.ejs
│ └── postform.ejs
├── lcoauthsystem/
│ ├── app.js
│ ├── config/
│ │ └── database.js
│ ├── index.js
│ ├── middleware/
│ │ └── auth.js
│ ├── model/
│ │ └── user.js
│ └── package.json
├── lcopassportgoogle/
│ ├── index.js
│ ├── model/
│ │ └── user.js
│ ├── package.json
│ ├── passport/
│ │ └── passport.js
│ ├── routes/
│ │ └── auth.js
│ └── views/
│ ├── home.ejs
│ └── login.ejs
├── mydocslco/
│ ├── index.js
│ ├── nodemon.json
│ ├── package.json
│ └── swagger.yaml
├── razorpay/
│ ├── index.js
│ ├── package.json
│ └── public/
│ └── index.html
├── readme.md
├── socialapp/
│ ├── .gitignore
│ ├── index.js
│ ├── nodemon.json
│ ├── package.json
│ └── swagger.yaml
└── tshirtstore/
├── .gitignore
├── README.md
├── app.js
├── config/
│ └── db.js
├── controllers/
│ ├── homeController.js
│ ├── orderController.js
│ ├── paymentController.js
│ ├── productController.js
│ └── userController.js
├── index.js
├── lcotshirtstore/
│ ├── .gitignore
│ ├── app.js
│ ├── config/
│ │ └── db.js
│ ├── controllers/
│ │ ├── homeController.js
│ │ ├── orderController.js
│ │ ├── paymentController.js
│ │ ├── productController.js
│ │ └── userController.js
│ ├── index.js
│ ├── middlewares/
│ │ ├── bigPromise.js
│ │ └── user.js
│ ├── models/
│ │ ├── order.js
│ │ ├── product.js
│ │ └── user.js
│ ├── nodemon.json
│ ├── package.json
│ ├── routes/
│ │ ├── home.js
│ │ ├── order.js
│ │ ├── payment.js
│ │ ├── product.js
│ │ └── user.js
│ ├── swagger.yaml
│ ├── utils/
│ │ ├── cookieToken.js
│ │ ├── customError.js
│ │ ├── demotest.js
│ │ ├── emailHelper.js
│ │ ├── testOrder.json
│ │ └── whereClause.js
│ └── views/
│ └── signuptest.ejs
├── middlewares/
│ ├── bigPromise.js
│ ├── productionError.js
│ └── user.js
├── models/
│ ├── order.js
│ ├── product.js
│ └── user.js
├── nodemon.json
├── package.json
├── routes/
│ ├── home.js
│ ├── order.js
│ ├── payment.js
│ ├── product.js
│ └── user.js
├── swagger.yaml
├── utils/
│ ├── cookieToken.js
│ ├── customError.js
│ ├── demotest.js
│ ├── emailHelper.js
│ ├── testOrder.json
│ └── whereClause.js
└── views/
├── home.ejs
└── signuptest.ejs
SYMBOL INDEX (21 symbols across 10 files)
FILE: mydocslco/index.js
constant YAML (line 6) | const YAML = require("yamljs");
FILE: socialapp/index.js
constant YAML (line 7) | const YAML = require("yamljs");
constant PORT (line 12) | const PORT = process.env.PORT || 4000;
FILE: tshirtstore/app.js
constant YAML (line 10) | const YAML = require("yamljs");
FILE: tshirtstore/controllers/orderController.js
function updateProductStock (line 102) | async function updateProductStock(productId, quantity) {
FILE: tshirtstore/lcotshirtstore/app.js
constant YAML (line 10) | const YAML = require("yamljs");
FILE: tshirtstore/lcotshirtstore/controllers/orderController.js
function updateProductStock (line 102) | async function updateProductStock(productId, quantity) {
FILE: tshirtstore/lcotshirtstore/utils/customError.js
class CustomError (line 1) | class CustomError extends Error {
method constructor (line 2) | constructor(message, code) {
FILE: tshirtstore/lcotshirtstore/utils/whereClause.js
class WhereClause (line 7) | class WhereClause {
method constructor (line 8) | constructor(base, bigQ) {
method search (line 13) | search() {
method filter (line 27) | filter() {
method pager (line 48) | pager(resultperPage) {
FILE: tshirtstore/utils/customError.js
class CustomError (line 1) | class CustomError extends Error {
method constructor (line 2) | constructor(message, statusCode) {
FILE: tshirtstore/utils/whereClause.js
class WhereClause (line 7) | class WhereClause {
method constructor (line 8) | constructor(base, bigQ) {
method search (line 13) | search() {
method filter (line 27) | filter() {
method pager (line 48) | pager(resultperPage) {
Condensed preview — 91 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (194K chars).
[
{
"path": "formsandimages/index.js",
"chars": 1747,
"preview": "const express = require(\"express\");\nconst fileUpload = require(\"express-fileupload\");\nconst cloudinary = require(\"cloudi"
},
{
"path": "formsandimages/package.json",
"chars": 391,
"preview": "{\n \"name\": \"formsandimages\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"start"
},
{
"path": "formsandimages/views/getform.ejs",
"chars": 1326,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=ed"
},
{
"path": "formsandimages/views/postform.ejs",
"chars": 1581,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=ed"
},
{
"path": "lcoauthsystem/app.js",
"chars": 2639,
"preview": "require(\"dotenv\").config();\nrequire(\"./config/database\").connect();\nconst express = require(\"express\");\nconst bcrypt = r"
},
{
"path": "lcoauthsystem/config/database.js",
"chars": 389,
"preview": "const mongoose = require(\"mongoose\");\n\nconst { MONGODB_URL } = process.env;\n\nexports.connect = () => {\n mongoose\n .c"
},
{
"path": "lcoauthsystem/index.js",
"chars": 138,
"preview": "const app = require(\"./app\");\nconst { PORT } = process.env;\n\napp.listen(PORT, () => console.log(`Server is running at po"
},
{
"path": "lcoauthsystem/middleware/auth.js",
"chars": 581,
"preview": "const jwt = require(\"jsonwebtoken\");\n\n//model is optional\n\nconst auth = (req, res, next) => {\n console.log(req.cookies)"
},
{
"path": "lcoauthsystem/model/user.js",
"chars": 374,
"preview": "const mongoose = require(\"mongoose\");\n\nconst userSchema = new mongoose.Schema({\n firstname: {\n type: String,\n def"
},
{
"path": "lcoauthsystem/package.json",
"chars": 471,
"preview": "{\n \"name\": \"lcoauthsystem\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"start\""
},
{
"path": "lcopassportgoogle/index.js",
"chars": 881,
"preview": "const express = require(\"express\");\nconst mongoose = require(\"mongoose\");\nconst auth = require(\"./routes/auth\");\nconst p"
},
{
"path": "lcopassportgoogle/model/user.js",
"chars": 191,
"preview": "const mongoose = require(\"mongoose\");\n\nconst userSchema = new mongoose.Schema({\n name: String,\n googleId: String,\n em"
},
{
"path": "lcopassportgoogle/package.json",
"chars": 483,
"preview": "{\n \"name\": \"lcopassportgoogle\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"st"
},
{
"path": "lcopassportgoogle/passport/passport.js",
"chars": 1256,
"preview": "const passport = require(\"passport\");\nconst User = require(\"../model/user\");\n\nvar GoogleStrategy = require(\"passport-goo"
},
{
"path": "lcopassportgoogle/routes/auth.js",
"chars": 531,
"preview": "const router = require(\"express\").Router();\nconst passport = require(\"passport\");\n\nrouter.get(\"/login\", (req, res) => {\n"
},
{
"path": "lcopassportgoogle/views/home.ejs",
"chars": 909,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=ed"
},
{
"path": "lcopassportgoogle/views/login.ejs",
"chars": 932,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=ed"
},
{
"path": "mydocslco/index.js",
"chars": 1667,
"preview": "const express = require(\"express\");\n\nconst app = express();\n\nconst swaggerUi = require(\"swagger-ui-express\");\nconst YAML"
},
{
"path": "mydocslco/nodemon.json",
"chars": 32,
"preview": "{\n \"ext\": \".js, .jsx, .yaml\"\n}\n"
},
{
"path": "mydocslco/package.json",
"chars": 369,
"preview": "{\n \"name\": \"mydocslco\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"start\": \"n"
},
{
"path": "mydocslco/swagger.yaml",
"chars": 5414,
"preview": "openapi: \"3.0.0\"\ninfo:\n title: learn express and swagger - LearnCodeOnline\n description: LCO - a course segment about "
},
{
"path": "razorpay/index.js",
"chars": 913,
"preview": "const express = require(\"express\");\nconst Razorpay = require(\"razorpay\");\nconst app = express();\napp.use(express.static("
},
{
"path": "razorpay/package.json",
"chars": 269,
"preview": "{\n \"name\": \"razorpay\",\n \"version\": \"1.0.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"start\": \"no"
},
{
"path": "razorpay/public/index.html",
"chars": 1533,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=ed"
},
{
"path": "readme.md",
"chars": 471,
"preview": "# welcome to pro backend developer course code files\n\n## If you like this course, please drop a thanks node at my social"
},
{
"path": "socialapp/.gitignore",
"chars": 13,
"preview": "node_modules/"
},
{
"path": "socialapp/index.js",
"chars": 1374,
"preview": "const express = require(\"express\");\nconst format = require(\"date-format\");\nconst app = express();\n\n// swagger docs relat"
},
{
"path": "socialapp/nodemon.json",
"chars": 39,
"preview": "{\n \"ext\": \".js, .json, .yaml, .jsx\"\n}\n"
},
{
"path": "socialapp/package.json",
"chars": 457,
"preview": "{\n \"name\": \"socialapp\",\n \"version\": \"1.0.0\",\n \"description\": \"a basic social media app\",\n \"main\": \"index.js\",\n \"scr"
},
{
"path": "socialapp/swagger.yaml",
"chars": 1882,
"preview": "openapi: 3.0.0\ninfo:\n title: Social App\n description: Our fist Social app at LCO - Hitesh\n version: 1.0.1\n\nservers:\n "
},
{
"path": "tshirtstore/.gitignore",
"chars": 18,
"preview": ".env\nnode_modules/"
},
{
"path": "tshirtstore/README.md",
"chars": 503,
"preview": "# Tshirt store for pro backend developer course\n\nPlease add env variables for the project\n\n---\n\n### PORT=4000\n\n### DB_UR"
},
{
"path": "tshirtstore/app.js",
"chars": 1508,
"preview": "const express = require(\"express\");\nrequire(\"dotenv\").config();\nconst app = express();\nconst morgan = require(\"morgan\");"
},
{
"path": "tshirtstore/config/db.js",
"chars": 386,
"preview": "const mongoose = require(\"mongoose\");\n\nconst connectWithDb = () => {\n mongoose\n .connect(process.env.DB_URL, {\n "
},
{
"path": "tshirtstore/controllers/homeController.js",
"chars": 468,
"preview": "const BigPromise = require(\"../middlewares/bigPromise\");\n\nexports.home = BigPromise(async (req, res) => {\n // const db "
},
{
"path": "tshirtstore/controllers/orderController.js",
"chars": 2290,
"preview": "const Order = require(\"../models/order\");\nconst Product = require(\"../models/product\");\n\nconst BigPromise = require(\"../"
},
{
"path": "tshirtstore/controllers/paymentController.js",
"chars": 1385,
"preview": "const BigPromise = require(\"../middlewares/bigPromise\");\nconst stripe = require(\"stripe\")(process.env.STRIPE_SECRET);\nco"
},
{
"path": "tshirtstore/controllers/productController.js",
"chars": 5937,
"preview": "const Product = require(\"../models/product\");\nconst BigPromise = require(\"../middlewares/bigPromise\");\nconst CustomError"
},
{
"path": "tshirtstore/controllers/userController.js",
"chars": 8284,
"preview": "const User = require(\"../models/user\");\nconst BigPromise = require(\"../middlewares/bigPromise\");\nconst CustomError = req"
},
{
"path": "tshirtstore/index.js",
"chars": 487,
"preview": "const app = require(\"./app\");\nconst connectWithDb = require(\"./config/db\");\nrequire(\"dotenv\").config();\nconst cloudinary"
},
{
"path": "tshirtstore/lcotshirtstore/.gitignore",
"chars": 18,
"preview": ".env\nnode_modules/"
},
{
"path": "tshirtstore/lcotshirtstore/app.js",
"chars": 1284,
"preview": "const express = require(\"express\");\nrequire(\"dotenv\").config();\nconst app = express();\nconst morgan = require(\"morgan\");"
},
{
"path": "tshirtstore/lcotshirtstore/config/db.js",
"chars": 386,
"preview": "const mongoose = require(\"mongoose\");\n\nconst connectWithDb = () => {\n mongoose\n .connect(process.env.DB_URL, {\n "
},
{
"path": "tshirtstore/lcotshirtstore/controllers/homeController.js",
"chars": 468,
"preview": "const BigPromise = require(\"../middlewares/bigPromise\");\n\nexports.home = BigPromise(async (req, res) => {\n // const db "
},
{
"path": "tshirtstore/lcotshirtstore/controllers/orderController.js",
"chars": 2291,
"preview": "const Order = require(\"../models/order\");\nconst Product = require(\"../models/product\");\n\nconst BigPromise = require(\"../"
},
{
"path": "tshirtstore/lcotshirtstore/controllers/paymentController.js",
"chars": 1312,
"preview": "const BigPromise = require(\"../middlewares/bigPromise\");\nconst stripe = require(\"stripe\")(process.env.STRIPE_SECRET);\n\ne"
},
{
"path": "tshirtstore/lcotshirtstore/controllers/productController.js",
"chars": 5555,
"preview": "const Product = require(\"../models/product\");\nconst BigPromise = require(\"../middlewares/bigPromise\");\nconst CustomError"
},
{
"path": "tshirtstore/lcotshirtstore/controllers/userController.js",
"chars": 8085,
"preview": "const User = require(\"../models/user\");\nconst BigPromise = require(\"../middlewares/bigPromise\");\nconst CustomError = req"
},
{
"path": "tshirtstore/lcotshirtstore/index.js",
"chars": 487,
"preview": "const app = require(\"./app\");\nconst connectWithDb = require(\"./config/db\");\nrequire(\"dotenv\").config();\nconst cloudinary"
},
{
"path": "tshirtstore/lcotshirtstore/middlewares/bigPromise.js",
"chars": 147,
"preview": "// try catch and async - await || use promise\n\nmodule.exports = (func) => (req, res, next) =>\n Promise.resolve(func(req"
},
{
"path": "tshirtstore/lcotshirtstore/middlewares/user.js",
"chars": 778,
"preview": "const User = require(\"../models/user\");\nconst BigPromise = require(\"../middlewares/bigPromise\");\nconst CustomError = req"
},
{
"path": "tshirtstore/lcotshirtstore/models/order.js",
"chars": 1931,
"preview": "const mongoose = require(\"mongoose\");\n\n// shippingInfo{}\n// user,\n// paymentInfo{}\n// taxAmount\n// ShippingAmount\n// tot"
},
{
"path": "tshirtstore/lcotshirtstore/models/product.js",
"chars": 1962,
"preview": "const mongoose = require(\"mongoose\");\n\nconst productSchema = new mongoose.Schema({\n name: {\n type: String,\n requi"
},
{
"path": "tshirtstore/lcotshirtstore/models/user.js",
"chars": 2147,
"preview": "const mongoose = require(\"mongoose\");\nconst validator = require(\"validator\");\nconst bcrypt = require(\"bcryptjs\");\nconst "
},
{
"path": "tshirtstore/lcotshirtstore/nodemon.json",
"chars": 32,
"preview": "{\n \"ext\": \".js, .jsx, .yaml\"\n}\n"
},
{
"path": "tshirtstore/lcotshirtstore/package.json",
"chars": 822,
"preview": "{\n \"name\": \"tshirtstore\",\n \"version\": \"1.0.0\",\n \"description\": \"a backend api for tshirt store\",\n \"main\": \"index.js\""
},
{
"path": "tshirtstore/lcotshirtstore/routes/home.js",
"chars": 235,
"preview": "const express = require(\"express\");\nconst router = express.Router();\n\nconst { home, homeDummy } = require(\"../controller"
},
{
"path": "tshirtstore/lcotshirtstore/routes/order.js",
"chars": 774,
"preview": "const express = require(\"express\");\nconst {\n createOrder,\n getOneOrder,\n getLoggedInOrders,\n admingetAllOrders,\n ad"
},
{
"path": "tshirtstore/lcotshirtstore/routes/payment.js",
"chars": 563,
"preview": "const express = require(\"express\");\nconst router = express.Router();\nconst {\n sendRazorpayKey,\n sendStripeKey,\n captu"
},
{
"path": "tshirtstore/lcotshirtstore/routes/product.js",
"chars": 1064,
"preview": "const express = require(\"express\");\nconst {\n addProduct,\n getAllProduct,\n adminGetAllProduct,\n getOneProduct,\n admi"
},
{
"path": "tshirtstore/lcotshirtstore/routes/user.js",
"chars": 1330,
"preview": "const express = require(\"express\");\nconst router = express.Router();\n\nconst {\n signup,\n login,\n logout,\n forgotPassw"
},
{
"path": "tshirtstore/lcotshirtstore/swagger.yaml",
"chars": 17006,
"preview": "openapi: \"3.0.0\"\ninfo:\n title: Tshirt store API\n description: LCO - a course to create API for ecomm store\n version: "
},
{
"path": "tshirtstore/lcotshirtstore/utils/cookieToken.js",
"chars": 381,
"preview": "const cookieToken = (user, res) => {\n const token = user.getJwtToken();\n\n const options = {\n expires: new Date(\n "
},
{
"path": "tshirtstore/lcotshirtstore/utils/customError.js",
"chars": 144,
"preview": "class CustomError extends Error {\n constructor(message, code) {\n super(message);\n this.code = code;\n }\n}\n\nmodule"
},
{
"path": "tshirtstore/lcotshirtstore/utils/demotest.js",
"chars": 396,
"preview": "// User.find({ qty: { $lte: 20 } })\n// /api/v1/product?search=coder&page=2&category=shortsleeves&rating[gte]=4\n// &price"
},
{
"path": "tshirtstore/lcotshirtstore/utils/emailHelper.js",
"chars": 675,
"preview": "const nodemailer = require(\"nodemailer\");\n\nconst mailHelper = async (option) => {\n const transporter = nodemailer.creat"
},
{
"path": "tshirtstore/lcotshirtstore/utils/testOrder.json",
"chars": 564,
"preview": "{\n \"shippingInfo\": {\n \"address\": \"1 Jaipur\",\n \"city\": \"Jaipur\",\n \"phoneNo\": \"9898989898\",\n \"postalCode\": \"3"
},
{
"path": "tshirtstore/lcotshirtstore/utils/whereClause.js",
"chars": 1272,
"preview": "// base - Product.find()\n// base - Product.find(email: {\"hitesh@lco.dev\"})\n\n//bigQ - //search=coder&page=2&category=shor"
},
{
"path": "tshirtstore/lcotshirtstore/views/signuptest.ejs",
"chars": 1725,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=ed"
},
{
"path": "tshirtstore/middlewares/bigPromise.js",
"chars": 147,
"preview": "// try catch and async - await || use promise\n\nmodule.exports = (func) => (req, res, next) =>\n Promise.resolve(func(req"
},
{
"path": "tshirtstore/middlewares/productionError.js",
"chars": 285,
"preview": "const CustomError = require(\"../utils/customError\");\n\nmodule.exports = (err, req, res, next) => {\n let error = { ...err"
},
{
"path": "tshirtstore/middlewares/user.js",
"chars": 1065,
"preview": "const User = require(\"../models/user\");\nconst BigPromise = require(\"../middlewares/bigPromise\");\nconst CustomError = req"
},
{
"path": "tshirtstore/models/order.js",
"chars": 1934,
"preview": "const mongoose = require(\"mongoose\");\n\n// shippingInfo{}\n// user,\n// paymentInfo{}\n// taxAmount\n// ShippingAmount\n// tot"
},
{
"path": "tshirtstore/models/product.js",
"chars": 1962,
"preview": "const mongoose = require(\"mongoose\");\n\nconst productSchema = new mongoose.Schema({\n name: {\n type: String,\n requi"
},
{
"path": "tshirtstore/models/user.js",
"chars": 2147,
"preview": "const mongoose = require(\"mongoose\");\nconst validator = require(\"validator\");\nconst bcrypt = require(\"bcryptjs\");\nconst "
},
{
"path": "tshirtstore/nodemon.json",
"chars": 32,
"preview": "{\n \"ext\": \".js, .jsx, .yaml\"\n}\n"
},
{
"path": "tshirtstore/package.json",
"chars": 822,
"preview": "{\n \"name\": \"tshirtstore\",\n \"version\": \"1.0.0\",\n \"description\": \"a backend api for tshirt store\",\n \"main\": \"index.js\""
},
{
"path": "tshirtstore/routes/home.js",
"chars": 235,
"preview": "const express = require(\"express\");\nconst router = express.Router();\n\nconst { home, homeDummy } = require(\"../controller"
},
{
"path": "tshirtstore/routes/order.js",
"chars": 774,
"preview": "const express = require(\"express\");\nconst {\n createOrder,\n getOneOrder,\n getLoggedInOrders,\n admingetAllOrders,\n ad"
},
{
"path": "tshirtstore/routes/payment.js",
"chars": 563,
"preview": "const express = require(\"express\");\nconst router = express.Router();\nconst {\n sendRazorpayKey,\n sendStripeKey,\n captu"
},
{
"path": "tshirtstore/routes/product.js",
"chars": 1064,
"preview": "const express = require(\"express\");\nconst {\n addProduct,\n getAllProduct,\n adminGetAllProduct,\n getOneProduct,\n admi"
},
{
"path": "tshirtstore/routes/user.js",
"chars": 1327,
"preview": "const express = require(\"express\");\nconst router = express.Router();\n\nconst {\n signup,\n login,\n logout,\n forgotPassw"
},
{
"path": "tshirtstore/swagger.yaml",
"chars": 55769,
"preview": "openapi: \"3.0.0\"\ninfo:\n title: Tshirt store API\n description: LCO - a course to create API for ecomm store\n version: "
},
{
"path": "tshirtstore/utils/cookieToken.js",
"chars": 381,
"preview": "const cookieToken = (user, res) => {\n const token = user.getJwtToken();\n\n const options = {\n expires: new Date(\n "
},
{
"path": "tshirtstore/utils/customError.js",
"chars": 214,
"preview": "class CustomError extends Error {\n constructor(message, statusCode) {\n super(message);\n this.statusCode = statusC"
},
{
"path": "tshirtstore/utils/demotest.js",
"chars": 396,
"preview": "// User.find({ qty: { $lte: 20 } })\n// /api/v1/product?search=coder&page=2&category=shortsleeves&rating[gte]=4\n// &price"
},
{
"path": "tshirtstore/utils/emailHelper.js",
"chars": 675,
"preview": "const nodemailer = require(\"nodemailer\");\n\nconst mailHelper = async (option) => {\n const transporter = nodemailer.creat"
},
{
"path": "tshirtstore/utils/testOrder.json",
"chars": 564,
"preview": "{\n \"shippingInfo\": {\n \"address\": \"1 Jaipur\",\n \"city\": \"Jaipur\",\n \"phoneNo\": \"9898989898\",\n \"postalCode\": \"3"
},
{
"path": "tshirtstore/utils/whereClause.js",
"chars": 1272,
"preview": "// base - Product.find()\n// base - Product.find(email: {\"hitesh@lco.dev\"})\n\n//bigQ - //search=coder&page=2&category=shor"
},
{
"path": "tshirtstore/views/home.ejs",
"chars": 1477,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=ed"
},
{
"path": "tshirtstore/views/signuptest.ejs",
"chars": 1725,
"preview": "<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n <meta charset=\"UTF-8\">\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=ed"
}
]
About this extraction
This page contains the full source code of the hiteshchoudhary/pro-backend-developer GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 91 files (175.0 KB), approximately 41.0k tokens, and a symbol index with 21 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.