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