Skip to content

Commit

Permalink
refactor: codebase improved MVC
Browse files Browse the repository at this point in the history
  • Loading branch information
hossainchisty committed Mar 10, 2024
1 parent 38b646a commit d121ca8
Show file tree
Hide file tree
Showing 16 changed files with 110 additions and 82 deletions.
57 changes: 30 additions & 27 deletions app.js
Original file line number Diff line number Diff line change
@@ -1,52 +1,55 @@
// Basic Lib Imports
const express = require("express"); // Importing the Express framework for building web applications
const helmet = require("helmet"); // Importing Helmet middleware for securing HTTP headers
const bodyParser = require('body-parser'); // Importing Body Parser middleware for parsing request bodies
const cookieParser = require('cookie-parser'); // Importing Cookie Parser middleware for parsing cookies
require("dotenv").config(); // Loading environment variables from .env file
const cors = require('cors'); // Importing CORS middleware for enabling Cross-Origin Resource Sharing
const { errorHandler } = require("./middleware/errorMiddleware"); // Importing custom error handling middleware

// Database connection with mongoose
const connectDB = require("./config/db"); // Importing database connection function using Mongoose
connectDB(); // Establishing the database connection



const app = express(); // Creating an instance of the Express application
app.use('/uploads', express.static(__dirname + '/uploads')); // Serve uploaded files from the 'uploads' folder

app.use(helmet()); // Setting up Helmet middleware for securing HTTP headers
app.use(bodyParser.json()); // Parsing JSON bodies
app.use(cookieParser()); // Parsing cookies
app.use(express.json()); // Parsing JSON bodies
const express = require("express");
const helmet = require("helmet");
const bodyParser = require('body-parser');
const cookieParser = require('cookie-parser');
require("dotenv").config();
const cors = require('cors');
const { errorHandler } = require("./app/middleware/errorMiddleware");
const connectDB = require("./config/db");
connectDB();

const applicationRoutes = require('./app/routes/index');


const app = express();

app.use('/uploads', express.static(__dirname + '/uploads'));
app.use(helmet());
app.use(bodyParser.json());
app.use(cookieParser());
app.use(express.json());
app.use(cors(
{
origin: `${process.env.FRONTEND_URL}`,
credentials: true
}
)); // Enabling CORS for localhost origins
));
app.use(
express.urlencoded({
extended: false,
})
);

// Routing Implement
app.use("/api/v1/users", require("./routes/userRouters")); // Mounting userRouters for handling user-related routes
app.use("/api/v1/posts", require("./routes/postRouters")); // Mounting postRouters for handling task-related routes
app.use('/api/v1/', applicationRoutes);

// Health Check
app.use("/health", (req, res) => {
res.status(200).json({ status: 200, success: true, message: "Health OK✅" });
res.status(200).json({ status: 200, success: true, message: "Health OK🔥" });
});

// Root
app.use("/", (req, res) => {
res.status(200).json({ status: 200, success: true, message: "If you saw this, it's because our servers are working ✅." });
});

// Undefined Route Implement
app.use("*", (req, res) => {
res.status(404).json({ status: 404, message: "Not Found" });
res.status(404).json({ status: 404, success: false, message: "Not Found" });
});

// Custom error handler
app.use(errorHandler);

module.exports = app; // Exporting the Express app for external use
module.exports = app;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
const jwt = require("jsonwebtoken");
const asyncHandler = require("express-async-handler");
const User = require("../models/userModel");
const User = require("../modules/user/user.model");

/**
* @desc Middleware that verifies user authorization
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ const moment = require("moment");
const bcrypt = require("bcryptjs");
const crypto = require("crypto");
const asyncHandler = require("express-async-handler");
const User = require("../models/userModel");
const User = require("../user/user.model");
const {
generateToken,
generateResetToken,
} = require("../helper/generateToken");
} = require("../../../helper/generateToken");
const {
sendVerificationEmail,
sendResetPasswordLink,
} = require("../services/emailService");
} = require("../../../services/emailService");

/**
* @desc Register new user
Expand Down Expand Up @@ -237,7 +237,7 @@ const emailVerify = asyncHandler(async (req, res) => {
* @param {string} email - User's email address
* @returns {object} - Success message or error message
*/
const forgetPassword = async (req, res) => {
const forgetPassword = asyncHandler(async (req, res) => {
const { email } = req.body;

try {
Expand Down Expand Up @@ -280,7 +280,7 @@ const forgetPassword = async (req, res) => {
details: "The provided email address does not exist in our records.",
});
}
};
});

/**
* @desc Reset Password
Expand All @@ -291,7 +291,7 @@ const forgetPassword = async (req, res) => {
* @param {string} newPassword - User's new password
* @returns {object} - Success message or error message
*/
const resetPassword = async (req, res) => {
const resetPassword = asyncHandler(async (req, res) => {
const { newPassword } = req.body;
const { token } = req.query;

Expand Down Expand Up @@ -328,7 +328,7 @@ const resetPassword = async (req, res) => {
message: "An internal server error occurred.",
});
}
};
});

module.exports = {
registerUser,
Expand Down
File renamed without changes.
28 changes: 28 additions & 0 deletions app/modules/auth/auth.route.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
// Basic Lib Imports
const express = require('express');
const router = express.Router();

const {
createAccountLimiter,
forgetPasswordLimiter,
verifyLimiter,
} = require('../../../services/rateLimitService');

const {
registerUser,
emailVerify,
loginUser,
logoutUser,
forgetPassword,
resetPassword,
} = require('./auth.controller');

// Routing Implement
router.post('/register', createAccountLimiter, registerUser);
router.post('/verify', verifyLimiter, emailVerify);
router.post('/login', loginUser);
router.post('/reset-password', resetPassword);
router.post('/logout', logoutUser);
router.post('/forgot-password', forgetPasswordLimiter, forgetPassword);

module.exports = router;
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
// Basic Lib Imports
const Post = require("./post.model");
const handleFileUpload = require("../../../utility/fileManager");
const verifyAuthorization = require("../../../utility/verifyAuthorization");
const asyncHandler = require("express-async-handler");
const Post = require("../models/postModel");
const handleFileUpload = require("../utility/fileManager");
const verifyAuthorization = require("../utility/verifyAuthorization");

/**
* @desc Get posts for a given user request
Expand Down
2 changes: 1 addition & 1 deletion models/postModel.js → app/modules/post/post.model.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ const postSchema = mongoose.Schema(
{ versionKey: false },
);

module.exports = mongoose.model("Post", postSchema);
module.exports = mongoose.model("Post", postSchema);
4 changes: 2 additions & 2 deletions routes/postRouters.js → app/modules/post/post.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const {
deletePost,
searchPost,
getMostRecentPost,
} = require("../controllers/postController");
} = require("./post.controller");

const storage = multer.diskStorage({
destination: (req, file, cb) => {
Expand Down Expand Up @@ -42,4 +42,4 @@ router
router.route("/:id").delete(deletePost).get(getPostByID);

// Exporting the Router
module.exports = router;
module.exports = router;
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Basic Lib Import
const User = require("../models/userModel");
const User = require("./user.model");
const asyncHandler = require("express-async-handler");
const verifyAuthorization = require("../utility/verifyAuthorization");
const verifyAuthorization = require("../../../utility/verifyAuthorization");

/**
* @desc Get user data
Expand Down
File renamed without changes.
8 changes: 4 additions & 4 deletions routes/userRouters.js → app/modules/user/user.route.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ const router = express.Router();
const {
createAccountLimiter,
forgetPasswordLimiter,
} = require("../services/rateLimitService");
} = require("../../../services/rateLimitService");

const ExpressBrute = require("express-brute");

Expand All @@ -20,11 +20,11 @@ const {
forgetPassword,
resetPassword,
emailVerify,
} = require("../controllers/authController");
} = require("../auth/auth.controller");

const { getMe, userList } = require("../controllers/userController");
const { getMe, userList } = require("./user.controller");

const { protect } = require("../middleware/authMiddleware");
const { protect } = require("../../middleware/authMiddleware");

// Routing Implement
router.get("/list", userList);
Expand Down
20 changes: 20 additions & 0 deletions app/routes/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// Basic Lib Imports
const express = require('express');

const router = express.Router();


const authRouters = require('../modules/auth/auth.route');
const userRouters = require('../modules/user/user.route');
const postRouters = require('../modules/post/post.route');


const moduleRoutes = [
{ path: '/auth', route: authRouters },
{ path: '/users', route: userRouters },
{ path: '/posts', route: postRouters },
];

moduleRoutes.forEach((route) => router.use(route.path, route.route));

module.exports = applicationRoutes = router;
1 change: 1 addition & 0 deletions logs/app.log
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@
{"level":"info","message":"Verification email sent:","response":"250 2.0.0 OK 1693502414 l19-20020a17090aec1300b0026b26181ac9sm3158272pjy.14 - gsmtp","timestamp":"2023-08-31T17:20:16.972Z"}
{"level":"info","message":"Verification email sent:","response":"250 2.0.0 OK 1693503310 e4-20020a170902d38400b001adf6b21c77sm1508101pld.107 - gsmtp","timestamp":"2023-08-31T17:35:12.345Z"}
{"level":"info","message":"Verification email sent:","response":"250 2.0.0 OK 1693503929 x4-20020a636304000000b00570668ccd5bsm74965pgb.14 - gsmtp","timestamp":"2023-08-31T17:45:31.227Z"}
{"code":"EAUTH","command":"AUTH PLAIN","level":"error","message":"Error sending verification email: Invalid login: 535-5.7.8 Username and Password not accepted. For more information, go to\n535 5.7.8 https://support.google.com/mail/?p=BadCredentials f12-20020a17090ab94c00b0029bed2dc95esm605209pjw.56 - gsmtp","response":"535-5.7.8 Username and Password not accepted. For more information, go to\n535 5.7.8 https://support.google.com/mail/?p=BadCredentials f12-20020a17090ab94c00b0029bed2dc95esm605209pjw.56 - gsmtp","responseCode":535,"stack":"Error: Invalid login: 535-5.7.8 Username and Password not accepted. For more information, go to\n535 5.7.8 https://support.google.com/mail/?p=BadCredentials f12-20020a17090ab94c00b0029bed2dc95esm605209pjw.56 - gsmtp\n at SMTPConnection._formatError (C:\\Users\\USER OS\\Desktop\\StoryLink-Server\\node_modules\\nodemailer\\lib\\smtp-connection\\index.js:790:19)\n at SMTPConnection._actionAUTHComplete (C:\\Users\\USER OS\\Desktop\\StoryLink-Server\\node_modules\\nodemailer\\lib\\smtp-connection\\index.js:1564:34)\n at SMTPConnection.<anonymous> (C:\\Users\\USER OS\\Desktop\\StoryLink-Server\\node_modules\\nodemailer\\lib\\smtp-connection\\index.js:546:26)\n at SMTPConnection._processResponse (C:\\Users\\USER OS\\Desktop\\StoryLink-Server\\node_modules\\nodemailer\\lib\\smtp-connection\\index.js:969:20)\n at SMTPConnection._onData (C:\\Users\\USER OS\\Desktop\\StoryLink-Server\\node_modules\\nodemailer\\lib\\smtp-connection\\index.js:755:14)\n at SMTPConnection._onSocketData (C:\\Users\\USER OS\\Desktop\\StoryLink-Server\\node_modules\\nodemailer\\lib\\smtp-connection\\index.js:193:44)\n at TLSSocket.emit (node:events:514:28)\n at addChunk (node:internal/streams/readable:324:12)\n at readableAddChunk (node:internal/streams/readable:297:9)\n at Readable.push (node:internal/streams/readable:234:10)","timestamp":"2024-03-10T09:25:55.717Z"}
34 changes: 0 additions & 34 deletions models/notificationModel.js

This file was deleted.

12 changes: 11 additions & 1 deletion services/rateLimitService.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,24 @@ const createAccountLimiter = rateLimit({

const forgetPasswordLimiter = rateLimit({
windowMs: 60 * 60 * 1000, // 1 hour
max: 4, // Limit each IP to 4 create account requests per `window` (here, per hour)
max: 4, // Limit each IP to 4 forget password requests per `window` (here, per hour)
message:
"Too many password rest mail send from this IP, please try again after an hour",
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
});

const verifyLimiter = rateLimit({
windowMs: 60 * 60 * 1000, // 1 hour
max: 3, // Limit each IP to 3 verify email requests per `window` (here, per hour)
message:
"Too many verify request from this IP, please try again after an hour",
standardHeaders: true, // Return rate limit info in the `RateLimit-*` headers
legacyHeaders: false, // Disable the `X-RateLimit-*` headers
});

module.exports = {
verifyLimiter,
createAccountLimiter,
forgetPasswordLimiter,
};

0 comments on commit d121ca8

Please sign in to comment.