├── .gitignore ├── .vscode └── settings.json ├── README.md ├── controllers └── tools.controller.js ├── index.js ├── middleware ├── errorHandler.js ├── limiter.js └── veiwCount.js ├── package.json ├── public ├── test.html └── wow.jpg ├── routes └── v1 │ └── tools.route.js ├── utils ├── dbConnect.js └── email.js └── views └── home.ejs /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | yarn.lock -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abdify/express-mvc-acc/722ae0597cf7e7a70360ccf59733882889508efc/README.md -------------------------------------------------------------------------------- /controllers/tools.controller.js: -------------------------------------------------------------------------------- 1 | const { ObjectId } = require("mongodb"); 2 | const { getDb } = require("../utils/dbConnect"); 3 | 4 | let tools = [ 5 | { id: 1, name: "Hammer" }, 6 | { id: 2, name: "Hammer2" }, 7 | { id: 3, name: "Hammer3" }, 8 | ]; 9 | 10 | module.exports.getAllTools = async (req, res, next) => { 11 | try { 12 | const { limit, page } = req.query; 13 | const db = getDb(); 14 | 15 | // cursor => toArray(), forEach() 16 | const tool = await db 17 | .collection("tools") 18 | .find({}) 19 | // .project({ _id: 0 }) 20 | // .skip(+page * limit) 21 | // .limit(+limit) 22 | .toArray(); 23 | 24 | res.status(200).json({ success: true, data: tool }); 25 | } catch (error) { 26 | next(error); 27 | } 28 | }; 29 | 30 | module.exports.saveATool = async (req, res, next) => { 31 | try { 32 | const db = getDb(); 33 | const tool = req.body; 34 | 35 | const result = await db.collection("tools").insertOne(tool); 36 | console.log(result); 37 | 38 | if (!result.insertedId) { 39 | return res.status(400).send({ status: false, error: "Something went wrong!" }); 40 | } 41 | 42 | res.send({ success: true, message: `Tool added with id: ${result.insertedId}` }); 43 | } catch (error) { 44 | next(error); 45 | } 46 | }; 47 | 48 | module.exports.getToolDetail = async (req, res, next) => { 49 | try { 50 | const db = getDb(); 51 | const { id } = req.params; 52 | 53 | if(!ObjectId.isValid(id)){ 54 | return res.status(400).json({ success: false, error: "Not a valid tool id."}); 55 | } 56 | 57 | const tool = await db.collection("tools").findOne({_id: ObjectId(id)}); 58 | 59 | if(!tool){ 60 | return res.status(400).json({ success: false, error: "Couldn't find a tool with this id"}); 61 | } 62 | 63 | res.status(200).json({ success: true, data: tool }); 64 | 65 | } catch (error) { 66 | next(error); 67 | } 68 | }; 69 | 70 | module.exports.updateTool = async (req, res, next) => { 71 | try { 72 | const db = getDb(); 73 | const { id } = req.params; 74 | 75 | if (!ObjectId.isValid(id)) { 76 | return res.status(400).json({ success: false, error: "Not a valid tool id." }); 77 | } 78 | 79 | const tool = await db.collection("tools").updateOne({ _id: ObjectId(id) }, { $set: req.body }); 80 | 81 | if (!tool.modifiedCount) { 82 | return res.status(400).json({ success: false, error: "Couldn't update the tool" }); 83 | } 84 | 85 | res.status(200).json({ success: true, message: "Successfully updated the tool" }); 86 | } catch (error) { 87 | next(error); 88 | } 89 | }; 90 | 91 | module.exports.deleteTool = async (req, res, next) => { 92 | try { 93 | const db = getDb(); 94 | const { id } = req.params; 95 | 96 | if (!ObjectId.isValid(id)) { 97 | return res.status(400).json({ success: false, error: "Not a valid tool id." }); 98 | } 99 | 100 | const tool = await db.collection("tools").deleteOne({ _id: ObjectId(id) }); 101 | 102 | if (!tool.deletedCount) { 103 | return res.status(400).json({ success: false, error: "Couldn't delete the tool" }); 104 | } 105 | 106 | res.status(200).json({ success: true, message: "Successfully deleted the tool" }); 107 | } catch (error) { 108 | next(error); 109 | } 110 | }; 111 | 112 | module.exports.test = async(req, res, next) => { 113 | for (let i = 0; i < 100000; i++) { 114 | const db = getDb(); 115 | db.collection("test").insertOne({name: `test ${i}`, age: i }); 116 | } 117 | }; 118 | module.exports.testGet = async(req, res, next) => { 119 | const db = getDb(); 120 | 121 | const result = await db.collection("test").find({ name: "test 99999" }).toArray(); 122 | res.json(result); 123 | }; -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const cors = require("cors"); 3 | require("dotenv").config(); 4 | const app = express(); 5 | const port = process.env.PORT || 5000; 6 | const dbConnect = require("./utils/dbConnect"); 7 | const toolsRoutes = require("./routes/v1/tools.route.js"); 8 | const errorHandler = require("./middleware/errorHandler"); 9 | const { connectToServer } = require("./utils/dbConnect"); 10 | 11 | app.use(cors()); 12 | app.use(express.json()); 13 | app.use(express.static("public")); 14 | app.set("view engine", "ejs"); 15 | 16 | // app.use(viewCount); 17 | 18 | // Apply the rate limiting middleware to all requests 19 | // app.use(limiter); 20 | 21 | connectToServer((err) => { 22 | if (!err) { 23 | app.listen(port, () => { 24 | console.log(`Example app listening on port ${port}`); 25 | }); 26 | } else { 27 | console.log(err); 28 | } 29 | }); 30 | 31 | app.use("/api/v1/tools", toolsRoutes); 32 | 33 | app.get("/", (req, res) => { 34 | // res.send("Hello World"); 35 | // res.sendFile(__dirname + "/public/test.html"); 36 | res.render("home.ejs", { 37 | id: 5, 38 | user: { 39 | name: "test", 40 | }, 41 | }); 42 | }); 43 | 44 | app.all("*", (req, res) => { 45 | res.send("NO route found."); 46 | }); 47 | 48 | app.use(errorHandler); 49 | 50 | process.on("unhandledRejection", (error) => { 51 | console.log(error.name, error.message); 52 | app.close(() => { 53 | process.exit(1); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /middleware/errorHandler.js: -------------------------------------------------------------------------------- 1 | const errorHandler = (err, req, res, next) => { 2 | res.send(err.message); 3 | }; 4 | 5 | module.exports = errorHandler; -------------------------------------------------------------------------------- /middleware/limiter.js: -------------------------------------------------------------------------------- 1 | const { default: rateLimit } = require("express-rate-limit"); 2 | 3 | const limiter = rateLimit({ 4 | windowMs: 15 * 60 * 1000, // 15 minutes 5 | max: 100, // Limit each IP to 100 requests per `window` (here, per 15 minutes) 6 | standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers 7 | legacyHeaders: false, // Disable the `X-RateLimit-*` headers 8 | }); 9 | 10 | module.exports = limiter; -------------------------------------------------------------------------------- /middleware/veiwCount.js: -------------------------------------------------------------------------------- 1 | let count = 0; 2 | 3 | const viewCount = (req, res, next) => { 4 | count++; 5 | console.log(count); 6 | 7 | // res.send("tools found"); 8 | next(); 9 | }; 10 | 11 | module.exports = viewCount; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "phero-final-project-server", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "node index.js", 8 | "start-dev": "nodemon index.js", 9 | "test": "echo \"Error: no test specified\" && exit 1" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "dependencies": { 15 | "cors": "^2.8.5", 16 | "dotenv": "^16.0.1", 17 | "ejs": "^3.1.8", 18 | "express": "^4.18.1", 19 | "express-rate-limit": "^6.5.2", 20 | "jsonwebtoken": "^8.5.1", 21 | "mongodb": "^4.6.0", 22 | "nodemailer": "^6.7.8", 23 | "nodemon": "^2.0.19", 24 | "stripe": "^10.3.0" 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /public/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |

This is home

11 | 12 | -------------------------------------------------------------------------------- /public/wow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Abdify/express-mvc-acc/722ae0597cf7e7a70360ccf59733882889508efc/public/wow.jpg -------------------------------------------------------------------------------- /routes/v1/tools.route.js: -------------------------------------------------------------------------------- 1 | const express = require("express"); 2 | const toolsControllers = require("../../controllers/tools.controller"); 3 | const limiter = require("../../middleware/limiter"); 4 | const viewCount = require("../../middleware/veiwCount"); 5 | 6 | const router = express.Router(); 7 | 8 | // router.get("/", (req, res) => { 9 | // res.send("tools found with id"); 10 | // }); 11 | 12 | // router.post("/", (req, res) => { 13 | // res.send("tool added"); 14 | // }); 15 | 16 | router 17 | .route("/") 18 | /** 19 | * @api {get} /tools All tools 20 | * @apiDescription Get all the tools 21 | * @apiPermission admin 22 | * 23 | * @apiHeader {String} Authorization User's access token 24 | * 25 | * @apiParam {Number{1-}} [page=1] List page 26 | * @apiParam {Number{1-100}} [limit=10] Users per page 27 | * 28 | * @apiSuccess {Object[]} all the tools. 29 | * 30 | * @apiError (Unauthorized 401) Unauthorized Only authenticated users can access the data 31 | * @apiError (Forbidden 403) Forbidden Only admins can access the data 32 | */ 33 | .get(toolsControllers.getAllTools) 34 | 35 | /** 36 | * @api {post} /tools save a tool 37 | * @apiDescription Get all the tools 38 | * @apiPermission admin 39 | * 40 | * @apiHeader {String} Authorization User's access token 41 | * 42 | * @apiParam {Number{1-}} [page=1] List page 43 | * @apiParam {Number{1-100}} [limit=10] Users per page 44 | * 45 | * @apiSuccess {Object[]} all the tools. 46 | * 47 | * @apiError (Unauthorized 401) Unauthorized Only authenticated users can access the data 48 | * @apiError (Forbidden 403) Forbidden Only admins can access the data 49 | */ 50 | .post(toolsControllers.saveATool); 51 | 52 | 53 | router.route("/test").post(toolsControllers.test).get(toolsControllers.testGet); 54 | 55 | router 56 | .route("/:id") 57 | .get(viewCount, limiter, toolsControllers.getToolDetail) 58 | .patch(toolsControllers.updateTool) 59 | .delete(toolsControllers.deleteTool); 60 | 61 | module.exports = router; 62 | -------------------------------------------------------------------------------- /utils/dbConnect.js: -------------------------------------------------------------------------------- 1 | const { MongoClient } = require("mongodb"); 2 | const connectionString = process.env.ATLAS_URI; 3 | const client = new MongoClient(connectionString, { 4 | useNewUrlParser: true, 5 | useUnifiedTopology: true, 6 | }); 7 | 8 | let dbConnection; 9 | 10 | module.exports = { 11 | connectToServer: function (callback) { 12 | client.connect(function (err, db) { 13 | if (err || !db) { 14 | return callback(err); 15 | } 16 | 17 | dbConnection = db.db("tools"); 18 | console.log("Successfully connected to MongoDB."); 19 | 20 | return callback(); 21 | }); 22 | }, 23 | 24 | getDb: function () { 25 | return dbConnection; 26 | }, 27 | }; 28 | -------------------------------------------------------------------------------- /utils/email.js: -------------------------------------------------------------------------------- 1 | const transporter = nodemailer.createTransport({ 2 | service: "gmail", 3 | auth: { 4 | user: "", 5 | pass: process.env.MAIL_PASS, 6 | }, 7 | }); 8 | function sendMail(orders) { 9 | const { address, name, email, product, price, quantity } = orders; 10 | 11 | const mailOptions = { 12 | from: "", 13 | to: email, 14 | subject: `Your order ${product} is successfully booked`, 15 | text: "Your product will be shifted within 7 days", 16 | html: ` 17 |
18 |

Hello, Sir

19 |

Your product will be shifted in this address ${address}

20 |

Quantity: ${quantity}

21 |

Total Price: ${price * quantity} Tk BDT.

22 |

Sincerely

23 |

Total Car Care Ltd.

24 |

Our Address

25 |

Muradpur ,Ctg

26 |

Bangladesh

27 | 28 |
29 | `, 30 | }; 31 | 32 | transporter.sendMail(mailOptions, function (err, data) { 33 | if (err) { 34 | console.log("something is wrong", err); 35 | } else { 36 | // console.log('Email sent', data); 37 | } 38 | }); 39 | } 40 | 41 | 42 | module.exports = sendMail; -------------------------------------------------------------------------------- /views/home.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 |

this is user: <%= id %>

11 | <% if (user) { %> 12 |

this is <%= user.name %>

13 | <% } %> 14 | 15 | --------------------------------------------------------------------------------