From 3cb9a4a1ef74e1238dda493bf4158a3b1cd320a1 Mon Sep 17 00:00:00 2001 From: Mohamed Abdelhafiz Date: Tue, 26 Aug 2025 04:14:51 +0300 Subject: [PATCH 1/2] finished getResturantMenuItems task and add some refactors --- app.js | 42 +-- controllers/menu.controller.js | 267 +++++++++++--------- controllers/user.controller.js | 240 +++++++++--------- middlewares/authentication.middleware.js | 82 +++--- models/menuItem.model.js | 74 +++--- models/payment.model.js | 40 +-- package-lock.json | 309 +++++++++++++++++++++++ package.json | 4 +- routes/menuItem.route.js | 45 +++- routes/order.route.js | 2 +- server.js | 4 +- utils/Helper/dataAccess.js | 2 +- utils/initial.js | 265 +++++++++++-------- 13 files changed, 913 insertions(+), 463 deletions(-) diff --git a/app.js b/app.js index a69c447..6f6290b 100644 --- a/app.js +++ b/app.js @@ -1,19 +1,19 @@ -const express = require('express'); -const cookieParser = require('cookie-parser'); +const express = require("express"); +const cookieParser = require("cookie-parser"); const app = express(); -const cors = require('cors'); -const { connectDB } = require('./config/db.Config'); -const userRouter = require('./routes/user.route'); -const restaurantRouter = require('./routes/restaurant.route'); -const orderRouter = require('./routes/order.route'); -const menuRouter = require('./routes/menu.route'); -const menuItemRouter = require('./routes/menuItem.route'); -const initial = require('./utils/initial'); +const cors = require("cors"); +const { connectDB } = require("./config/db.Config"); +const userRouter = require("./routes/user.route"); +const restaurantRouter = require("./routes/restaurant.route"); +const orderRouter = require("./routes/order.route"); +const menuRouter = require("./routes/menu.route"); +const menuItemRouter = require("./routes/menuItem.route"); +const initial = require("./utils/initial"); connectDB(); -// initail data -//initial.all(); +// Seed initial data +// initial.all(); // Middlewares app.use(cors()); @@ -22,15 +22,15 @@ app.use(cookieParser()); app.use(express.urlencoded({ extended: true })); //Routes -app.use('/api/auth', userRouter); -app.use('/api/restaurants', restaurantRouter); -app.use('/api/menus' , menuRouter); -app.use('/api/menuItems' , menuItemRouter); -app.use('/api/restaurants', menuRouter); -app.use('/api/orders' , orderRouter); +app.use("/api/auth", userRouter); +app.use("/api/restaurants", restaurantRouter); +app.use("/api/menus", menuRouter); +app.use("/api/menuItems", menuItemRouter); +app.use("/api/restaurants", menuRouter); +app.use("/api/orders", orderRouter); -app.get('/', (req, res) => { - res.send('Welcome to the Uber Eats Clone API'); +app.get("/", (req, res) => { + res.send("Welcome to the Uber Eats Clone API"); }); -module.exports = app; \ No newline at end of file +module.exports = app; diff --git a/controllers/menu.controller.js b/controllers/menu.controller.js index 27aeb2a..91f4f82 100644 --- a/controllers/menu.controller.js +++ b/controllers/menu.controller.js @@ -1,133 +1,166 @@ -const { get } = require('mongoose'); -const Menu = require('../models/menu.model'); -const MenuItem = require('../models/menuItem.model'); -const Restaurant = require('../models/restaurant.model'); -const dataAccessHelper = require('../utils/Helper/dataAccess'); -const {checkRestaurantAuthorization} = require('../middlewares/authorization.middleware') -const cloud = require('../utils/cloud'); +const { get } = require("mongoose"); +const Menu = require("../models/menu.model"); +const MenuItem = require("../models/menuItem.model"); +const Restaurant = require("../models/restaurant.model"); +const dataAccessHelper = require("../utils/Helper/dataAccess"); +const { + checkRestaurantAuthorization, +} = require("../middlewares/authorization.middleware"); +const cloud = require("../utils/cloud"); exports.getRestaurantMenuItems = async (req, res) => { - try { - if(!req.user) { - return res.status(401).json({ message: 'You Have To login First' }); - } - const menuItems = await dataAccessHelper.getMenuItemsByRestaurantId(req.params.restaurantId); - if (!menuItems) { - return res.status(404).json({ message: 'This Menu has no items' }); - } - res.status(200).json({ - message: 'Menu items found', - menuItems - }); - } catch (error) { - res.status(500).json({ - message: 'Internal server error', - process: "Menu Retrieval" - }); + try { + if (!req.user) { + return res.status(401).json({ message: "You have to login first" }); + } + + const { restaurantId } = req.params; + const restaurant = await Restaurant.findById(restaurantId); + if (!restaurant) { + return res.status(404).json({ message: "Restaurant not found" }); + } + const menu = await Menu.findOne({ restaurantId: restaurantId }); + + if (!menu) { + return res.status(404).json({ message: "Menu not found" }); + } + const menuItems = await dataAccessHelper.getMenuItemsByMenuId(menu._id); + + if (!menuItems || menuItems.length === 0) { + return res.status(404).json({ message: "This menu has no items" }); } -} + + const formattedItems = menuItems.map((item) => ({ + id: item._id, + name: item.name, + description: item.description, + price: { + amount: item.price?.amount, + currency: item.price?.currency, + }, + imageUrl: item.image, + label: item.isAvailable ? "Available" : "Not Available", + })); + + const response = { + restaurantId: restaurant._id, + menuId: menu._id, + menuName: menu.name, + items: formattedItems, + }; + + res.status(200).json(response); + } catch (error) { + res.status(500).json({ + message: "Internal server error", + process: "Menu Retrieval", + }); + } +}; // restaurant make new menu exports.createMenu = async (req, res) => { - try { - if (!req.user) { - return res.status(401).json({ message: 'You Have To login First' }); - } - - const { name, description } = req.body; - - const restaurant = await Restaurant.findById(req.params.restaurantId); - if (!restaurant) { - return res.status(404).json({ message: 'Restaurant not found' }); - } - - const existingMenu = await dataAccessHelper.getMenuByRestaurantId(req.params.restaurantId); - if (existingMenu) { - return res.status(400).json({ message: "This restaurant already have a menu" }); - } - const menu = new Menu({ - restaurantId: req.user._id, - name, - description, - image: req.menuImage || null, // store the Cloudinary link - }); - - await menu.save(); - - return res.status(201).json({ - message: 'Menu created successfully', - menu - }); - - } catch (error) { - console.error("Menu Creation Error:", error); - return res.status(500).json({ - message: 'Internal server error', - process: "Menu Creation" - }); + try { + if (!req.user) { + return res.status(401).json({ message: "You Have To login First" }); + } + + const { name, description } = req.body; + + const restaurant = await Restaurant.findById(req.params.restaurantId); + if (!restaurant) { + return res.status(404).json({ message: "Restaurant not found" }); } + + const existingMenu = await dataAccessHelper.getMenuByRestaurantId( + req.params.restaurantId + ); + if (existingMenu) { + return res + .status(400) + .json({ message: "This restaurant already have a menu" }); + } + const menu = new Menu({ + restaurantId: req.user._id, + name, + description, + image: req.menuImage || null, // store the Cloudinary link + }); + + await menu.save(); + + return res.status(201).json({ + message: "Menu created successfully", + menu, + }); + } catch (error) { + console.error("Menu Creation Error:", error); + return res.status(500).json({ + message: "Internal server error", + process: "Menu Creation", + }); + } }; exports.updateMenu = async (req, res) => { - try { - if (!req.user) { - return res.status(401).json({ message: 'You Have To login First' }); - } - const menu = await getMenuAndAuthorize(req, req.params.menuId); - const { name, description } = req.body; - if (menu.image && req.menuImage) { - await cloud.deleteCloud(menu.image); - } - if (req.menuImage) { - menu.image = req.menuImage; - } - menu.name = name || menu.name; - menu.description = description || menu.description; - await menu.save(); - return res.status(200).json({ - message: 'Menu updated successfully', - menu - }); - } catch (error) { - console.error("Menu Update Error:", error); - return res.status(error.status || 500).json({ - message: error.message || 'Internal server error', - process: "Menu Update" - }); - + try { + if (!req.user) { + return res.status(401).json({ message: "You Have To login First" }); } -} + const menu = await getMenuAndAuthorize(req, req.params.menuId); + const { name, description } = req.body; + if (menu.image && req.menuImage) { + await cloud.deleteCloud(menu.image); + } + if (req.menuImage) { + menu.image = req.menuImage; + } + menu.name = name || menu.name; + menu.description = description || menu.description; + await menu.save(); + return res.status(200).json({ + message: "Menu updated successfully", + menu, + }); + } catch (error) { + console.error("Menu Update Error:", error); + return res.status(error.status || 500).json({ + message: error.message || "Internal server error", + process: "Menu Update", + }); + } +}; exports.deleteMenu = async (req, res) => { - try { - if (!req.user) { - return res.status(401).json({ message: 'You Have To login First' }); - } - const menu = await getMenuAndAuthorize(req, req.params.menuId); - if (menu.image) { - await cloud.deleteCloud(menu.image); - } - await menu.deleteOne(); - return res.status(200).json({ - message: 'Menu deleted successfully', - menu - }); - } catch (error) { - console.error("Menu Deletion Error:", error); - return res.status(error.status || 500).json({ - message: error.message || 'Internal server error', - process: "Menu Deletion" - }); + try { + if (!req.user) { + return res.status(401).json({ message: "You Have To login First" }); } -} + const menu = await getMenuAndAuthorize(req, req.params.menuId); + if (menu.image) { + await cloud.deleteCloud(menu.image); + } + await menu.deleteOne(); + return res.status(200).json({ + message: "Menu deleted successfully", + menu, + }); + } catch (error) { + console.error("Menu Deletion Error:", error); + return res.status(error.status || 500).json({ + message: error.message || "Internal server error", + process: "Menu Deletion", + }); + } +}; async function getMenuAndAuthorize(req, menuId) { - const menu = await dataAccessHelper.getMenuById(menuId); - if (!menu) { - const error = new Error('Menu not found'); - error.status = 404; - throw error; - } - checkRestaurantAuthorization(req, menu); - return menu; -} \ No newline at end of file + const menu = await dataAccessHelper.getMenuById(menuId); + if (!menu) { + const error = new Error("Menu not found"); + error.status = 404; + throw error; + } + checkRestaurantAuthorization(req, menu); + return menu; +} diff --git a/controllers/user.controller.js b/controllers/user.controller.js index ccecb0a..e38ba60 100644 --- a/controllers/user.controller.js +++ b/controllers/user.controller.js @@ -1,132 +1,140 @@ -const User = require('../models/user.model.js'); -const hashPassword = require('../utils/hashPassword.js'); -const jwt = require('../utils/jwt.js'); -const cookie = require('../utils/cookie.js'); +const User = require("../models/user.model.js"); +const hashPassword = require("../utils/hashPassword.js"); +const jwt = require("../utils/jwt.js"); +const cookie = require("../utils/cookie.js"); exports.register = async (req, res) => { - try { - const {username , email , password} = req.body; - let {name} = req.body; + try { + const { username, email, password, role, phone } = req.body; + let { name } = req.body; - // Validate required fields - if(!username || !email || !password){ - return res.status(400).json({ message: 'All fields are required' }); - } - if(!name) { - name = username; // Default name - } - - // Check if the username or email already exists - const existingUser = await User.findOne({ username }); - if (existingUser) { - return res.status(400).json({ message: 'Username already exists' }); - } - const existingEmail = await User.findOne({ email }); - if (existingEmail) { - return res.status(400).json({ message: 'Email already exists' }); - } - - // Hash the password before saving - const hashedPassword = await hashPassword.hash(password); - - // Create a new user - name = name.trim(); - const user = new User({name,username,email,password:hashedPassword}); - await user.save(); - res.status(201).json({ message: 'User registered successfully' }); - } catch (error) { - res.status(500).json({ - message: 'Internal server error', - process: "User Registration" - }); + // Validate required fields + if (!username || !email || !password) { + return res.status(400).json({ message: "All fields are required" }); + } + if (!name) { + name = username; // Default name } -} + // Check if the username or email already exists + const existingUser = await User.findOne({ username }); + if (existingUser) { + return res.status(400).json({ message: "Username already exists" }); + } + const existingEmail = await User.findOne({ email }); + if (existingEmail) { + return res.status(400).json({ message: "Email already exists" }); + } -exports.login = async (req, res) => { - try { - if(req.user) { - return res.status(400).json({ - message: 'User already logged in', - login: true, - user: { - name: req.user.name, - username: req.user.username, - email: req.user.email, - role: req.user.role, - } - }); - } + // Hash the password before saving + const hashedPassword = await hashPassword.hash(password); - const { username, password } = req.body; + // Create a new user + name = name.trim(); + const user = new User({ + name, + username, + email, + password: hashedPassword, + role, + phone, + }); + await user.save(); + res.status(201).json({ message: "User registered successfully" }); + } catch (error) { + res.status(500).json({ + message: "Internal server error", + process: "User Registration", + }); + } +}; - // Validate required fields - if(!username || !password){ - return res.status(400).json({ message: 'All fields are required' }); - } - - // Find the user by username - const user = await User.findOne({ username }); - if (!user) { - user = await User.findOne({ email:username }); - } - if (!user) { - return res.status(400).json({ message: 'Invalid username or password' }); - } - // Compare the provided password with the stored hashed password - const isPasswordValid = await hashPassword.compare(password, user.password); - if (!isPasswordValid) { - return res.status(400).json({ message: 'Invalid username or password' }); - } +exports.login = async (req, res) => { + try { + if (req.user) { + return res.status(400).json({ + message: "User already logged in", + login: true, + user: { + name: req.user.name, + username: req.user.username, + email: req.user.email, + role: req.user.role, + }, + }); + } - // Generate JWT tokens - // Set cookies for access and refresh tokens - cookie.setCookie(res , 'accessToken', jwt.generateAccessToken(user), 60*1000); - user.refreshToken = jwt.generateRefreshToken(user); - user.sessionExpiry = Date.now() + 60*60*24*7*1000; - await user.save(); + const { username, password } = req.body; - // Respond with user details and access token - return res.status(200).json({ - message: 'Login successful', - user: { - name: user.name, - username: user.username, - email: user.email, - role: user.role, - }, - token: jwt.generateAccessToken(user) - }); + // Validate required fields + if (!username || !password) { + return res.status(400).json({ message: "All fields are required" }); + } + // Find the user by username + const user = await User.findOne({ username }); + if (!user) { + user = await User.findOne({ email: username }); + } + if (!user) { + return res.status(400).json({ message: "Invalid username or password" }); } - catch (error) { - res.status(500).json({ - message: 'Internal server error', - process: "User Login" - }); + // Compare the provided password with the stored hashed password + const isPasswordValid = await hashPassword.compare(password, user.password); + if (!isPasswordValid) { + return res.status(400).json({ message: "Invalid username or password" }); } -} + + // Generate JWT tokens + // Set cookies for access and refresh tokens + cookie.setCookie( + res, + "accessToken", + jwt.generateAccessToken(user), + 60 * 1000 * 60 + ); // 1 hour + user.refreshToken = jwt.generateRefreshToken(user); + user.sessionExpiry = Date.now() + 60 * 60 * 24 * 7 * 1000; + await user.save(); + + // Respond with user details and access token + return res.status(200).json({ + message: "Login successful", + user: { + name: user.name, + username: user.username, + email: user.email, + role: user.role, + }, + token: jwt.generateAccessToken(user), + }); + } catch (error) { + res.status(500).json({ + message: "Internal server error", + process: "User Login", + }); + } +}; exports.logout = async (req, res) => { - try { - const currentUser = req.user; - if(!currentUser) { - return res.status(400).json({ - message: 'User not logged in' , - login:false - }); - } - let user = await User.findById(currentUser.id); - user.refreshToken = ''; - user.sessionExpiry = Date.now(); - await user.save(); - cookie.clearCookie(res,'accessToken'); - res.status(200).json({ message: 'Logout successful' }); - } - catch (error) { - res.status(500).json({ - message: 'Internal server error', - process: "User Logout" - }); + try { + const currentUser = req.user; + if (!currentUser) { + return res.status(400).json({ + message: "User not logged in", + login: false, + }); } -} \ No newline at end of file + let user = await User.findById(currentUser.id); + user.refreshToken = ""; + user.sessionExpiry = Date.now(); + await user.save(); + cookie.clearCookie(res, "accessToken"); + res.status(200).json({ message: "Logout successful" }); + } catch (error) { + res.status(500).json({ + message: "Internal server error", + process: "User Logout", + }); + } +}; diff --git a/middlewares/authentication.middleware.js b/middlewares/authentication.middleware.js index 8beb664..8db152f 100644 --- a/middlewares/authentication.middleware.js +++ b/middlewares/authentication.middleware.js @@ -1,47 +1,51 @@ -const jwt = require('../utils/jwt.js'); -const cookie = require('../utils/cookie.js'); -const User = require('../models/user.model.js'); +const jwt = require("../utils/jwt.js"); +const cookie = require("../utils/cookie.js"); +const User = require("../models/user.model.js"); exports.authenticate = async (req, res, next) => { - try { - const accessToken = req.cookies?.accessToken; - if (!accessToken) { - return next(); // Allow unauthenticated users to continue - } - - const decoded = jwt.verifyToken(accessToken, 'access'); - if (!decoded) { - return next(); - } - - const user = await User.findById(decoded.id); - if (!user) { - return next(); - } + try { + const accessToken = req.cookies?.accessToken; + if (!accessToken) { + return next(); // Allow unauthenticated users to continue + } - // Handle expired access token - if (jwt.checkExpiry(accessToken)) { - const refreshToken = user.refreshToken; - if (!refreshToken || refreshToken === '' || jwt.checkExpiry(refreshToken) || user.sessionExpiry < Date.now()) { - user.refreshToken = ''; - await user.save(); - return next(); - } + const decoded = jwt.verifyToken(accessToken, "access"); + if (!decoded) { + return next(); + } - const newAccessToken = jwt.generateAccessToken(user); - if (newAccessToken) { - cookie.setCookie(res, 'accessToken', newAccessToken, 60 * 1000); - await user.save(); - } - } + const user = await User.findById(decoded.id); + if (!user) { + return next(); + } - req.user = user; + // Handle expired access token + if (jwt.checkExpiry(accessToken)) { + const refreshToken = user.refreshToken; + if ( + !refreshToken || + refreshToken === "" || + jwt.checkExpiry(refreshToken) || + user.sessionExpiry < Date.now() + ) { + user.refreshToken = ""; + await user.save(); return next(); + } - } catch (error) { - return res.status(500).json({ - message: 'Internal server error', - process: "User Authentication" - }); + const newAccessToken = jwt.generateAccessToken(user); + if (newAccessToken) { + cookie.setCookie(res, "accessToken", newAccessToken, 60 * 1000 * 60); // 1 hour + await user.save(); + } } -}; \ No newline at end of file + + req.user = user; + return next(); + } catch (error) { + return res.status(500).json({ + message: "Internal server error", + process: "User Authentication", + }); + } +}; diff --git a/models/menuItem.model.js b/models/menuItem.model.js index a992492..99a2845 100644 --- a/models/menuItem.model.js +++ b/models/menuItem.model.js @@ -1,41 +1,51 @@ -const mongoose = require('mongoose'); -const { dropSearchIndex } = require('./user.model'); +const mongoose = require("mongoose"); +const { dropSearchIndex } = require("./user.model"); const menuItemSchema = new mongoose.Schema({ - menuId: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Menu', - required: true - }, - name: { - type: String, - required: true, - trim: true, - minlength: 3, - maxlength: 50 - }, - description: { - type: String, - required: true, - trim: true, - minlength: 10, - maxlength: 500 - }, - price: { + menuId: { + type: mongoose.Schema.Types.ObjectId, + ref: "Menu", + required: true, + }, + name: { + type: String, + required: true, + trim: true, + minlength: 3, + maxlength: 50, + }, + description: { + type: String, + required: true, + trim: true, + minlength: 10, + maxlength: 500, + }, + price: { + type: { + amount: { type: Number, required: true, - min: 0 - }, - image: { + min: 0, + }, + currency: { type: String, - default: 'No Image' - }, - isAvailable: { - type: Boolean, - default: true + enum: ["USD", "EUR", "EGP"], + default: "EGP", + }, }, + required: true, + }, + image: { + type: String, + default: "No Image", + }, + isAvailable: { + type: Boolean, + default: true, + }, }); -const MenuItem = mongoose.model('MenuItem', menuItemSchema); +const MenuItem = mongoose.model("MenuItem", menuItemSchema); -module.exports = MenuItem; \ No newline at end of file +module.exports = MenuItem; diff --git a/models/payment.model.js b/models/payment.model.js index c8d5536..692348d 100644 --- a/models/payment.model.js +++ b/models/payment.model.js @@ -1,30 +1,32 @@ -const mongoose = require('mongoose'); +const mongoose = require("mongoose"); -const paymentSchema = new mongoose.Schema({ +const paymentSchema = new mongoose.Schema( + { orderId: { - type: mongoose.Schema.Types.ObjectId, - ref: 'Order', - required: true + type: mongoose.Schema.Types.ObjectId, + ref: "Order", + required: true, }, paymentMethod: { - type: String, - required: true, - enum: ['online', 'cash', 'card', 'bank transfer'], - default: 'online' + type: String, + required: true, + enum: ["online", "cash", "card", "bank transfer"], + default: "online", }, amount: { - type: Number, - required: true, - min: 0 + type: Number, + required: true, + min: 0, }, status: { - type: String, - enum: ['pending', 'completed', 'failed'], - default: 'pending' + type: String, + enum: ["pending", "completed", "failed"], + default: "pending", }, -}, -{ timestamps: true }); + }, + { timestamps: true } +); -const Payment = mongoose.model('Payment', paymentSchema); +const Payment = mongoose.model("Payment", paymentSchema); -module.exports = Payment; \ No newline at end of file +module.exports = Payment; diff --git a/package-lock.json b/package-lock.json index 825a9d4..db4db16 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,7 @@ "morgan": "^1.10.1", "multer": "^2.0.2", "nodemailer": "^7.0.5", + "nodemon": "^3.1.10", "socket.io": "^4.8.1", "streamifier": "^0.1.1", "winston": "^3.17.0" @@ -113,6 +114,19 @@ "node": ">= 0.6" } }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/append-field": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/append-field/-/append-field-1.0.0.tgz", @@ -125,6 +139,12 @@ "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", "license": "MIT" }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", @@ -166,6 +186,18 @@ "node": ">= 18" } }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/body-parser": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", @@ -186,6 +218,28 @@ "node": ">=18" } }, + "node_modules/brace-expansion": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/bson": { "version": "6.10.4", "resolved": "https://registry.npmjs.org/bson/-/bson-6.10.4.tgz", @@ -256,6 +310,30 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/cloudinary": { "version": "2.7.0", "resolved": "https://registry.npmjs.org/cloudinary/-/cloudinary-2.7.0.tgz", @@ -314,6 +392,12 @@ "text-hex": "1.0.x" } }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, "node_modules/concat-stream": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", @@ -677,6 +761,18 @@ "integrity": "sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==", "license": "MIT" }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/finalhandler": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.0.tgz", @@ -718,6 +814,20 @@ "node": ">= 0.8" } }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", @@ -764,6 +874,18 @@ "node": ">= 0.4" } }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -776,6 +898,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -837,6 +968,12 @@ "node": ">=0.10.0" } }, + "node_modules/ignore-by-default": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz", + "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==", + "license": "ISC" + }, "node_modules/inherits": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", @@ -858,6 +995,48 @@ "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", "license": "MIT" }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -1056,6 +1235,18 @@ "node": ">= 0.6" } }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/minimist": { "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", @@ -1324,6 +1515,43 @@ "node": ">=6.0.0" } }, + "node_modules/nodemon": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.10.tgz", + "integrity": "sha512-WDjw3pJ0/0jMFmyNDp3gvY2YizjLmmOUQo6DEBY+JgdvW/yQ9mEeSw6H5ythl5Ny2ytb7f9C2nIbjSxMNzbJXw==", + "license": "MIT", + "dependencies": { + "chokidar": "^3.5.2", + "debug": "^4", + "ignore-by-default": "^1.0.1", + "minimatch": "^3.1.2", + "pstree.remy": "^1.1.8", + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -1402,6 +1630,18 @@ "node": ">=16" } }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -1415,6 +1655,12 @@ "node": ">= 0.10" } }, + "node_modules/pstree.remy": { + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz", + "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==", + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -1488,6 +1734,18 @@ "node": ">= 6" } }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -1681,6 +1939,18 @@ "is-arrayish": "^0.3.1" } }, + "node_modules/simple-update-notifier": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz", + "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==", + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/socket.io": { "version": "4.8.1", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", @@ -1869,12 +2139,36 @@ "safe-buffer": "~5.2.0" } }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/text-hex": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz", "integrity": "sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==", "license": "MIT" }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -1884,6 +2178,15 @@ "node": ">=0.6" } }, + "node_modules/touch": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz", + "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==", + "license": "ISC", + "bin": { + "nodetouch": "bin/nodetouch.js" + } + }, "node_modules/tr46": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.1.tgz", @@ -1925,6 +2228,12 @@ "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", "license": "MIT" }, + "node_modules/undefsafe": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", + "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==", + "license": "MIT" + }, "node_modules/undici-types": { "version": "7.10.0", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz", diff --git a/package.json b/package.json index a352e0f..db235f5 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,8 @@ "main": "server.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", - "start": "node server.js" + "start": "node server.js", + "dev": "nodemon server.js" }, "keywords": [], "author": "", @@ -24,6 +25,7 @@ "morgan": "^1.10.1", "multer": "^2.0.2", "nodemailer": "^7.0.5", + "nodemon": "^3.1.10", "socket.io": "^4.8.1", "streamifier": "^0.1.1", "winston": "^3.17.0" diff --git a/routes/menuItem.route.js b/routes/menuItem.route.js index d418ec9..d180317 100644 --- a/routes/menuItem.route.js +++ b/routes/menuItem.route.js @@ -1,13 +1,38 @@ -const express = require('express'); +const express = require("express"); const router = express.Router(); -const menuItemController = require('../controllers/menuItem.controller'); -const {authenticate} = require('../middlewares/authentication.middleware'); -const {roleCheck} = require('../middlewares/authorization.middleware'); +const menuItemController = require("../controllers/menuItem.controller"); +const { authenticate } = require("../middlewares/authentication.middleware"); +const { roleCheck } = require("../middlewares/authorization.middleware"); -router.post('/create' , authenticate , roleCheck(['restaurant','admin']) , menuItemController.createItem); -router.get('/getAll' , authenticate , roleCheck(['restaurant','admin']) , menuItemController.getAllItems); -router.get('/:id' , authenticate , roleCheck(['restaurant','admin']) , menuItemController.getItemById); -router.put('/:id' , authenticate , roleCheck(['restaurant','admin']) , menuItemController.updateItem); -router.delete('/:id' , authenticate , roleCheck(['restaurant','admin']) , menuItemController.deleteItem); +router.post( + "/create", + authenticate, + roleCheck(["restaurant", "admin"]), + menuItemController.createItem +); +router.get( + "/getAll", + authenticate, + roleCheck(["restaurant", "admin"]), + menuItemController.getAllItems +); +router.get( + "/:id", + authenticate, + roleCheck(["restaurant", "admin"]), + menuItemController.getItemById +); +router.put( + "/:id", + authenticate, + roleCheck(["restaurant", "admin"]), + menuItemController.updateItem +); +router.delete( + "/:id", + authenticate, + roleCheck(["restaurant", "admin"]), + menuItemController.deleteItem +); -module.exports = router; \ No newline at end of file +module.exports = router; diff --git a/routes/order.route.js b/routes/order.route.js index 8ddedca..38ac56e 100644 --- a/routes/order.route.js +++ b/routes/order.route.js @@ -7,6 +7,6 @@ const {roleCheck} = require('../middlewares/authorization.middleware'); router.post('/' , authenticate , roleCheck(['customer','admin']) , orderController.placeOrder); router.post('/:id' , authenticate , roleCheck(['customer','admin']) , orderController.addOrderItem); router.get('/' , authenticate , roleCheck(['customer','restaurant','admin']) , orderController.getOrders); -router.get('/:id' , authenticate , roleCheck(['customer','restaurant','admin']) , orderController.getOrderById); +// router.get('/:id' , authenticate , roleCheck(['customer','restaurant','admin']) , orderController.getOrderById); module.exports = router; diff --git a/server.js b/server.js index 4cd7f10..a7af238 100644 --- a/server.js +++ b/server.js @@ -5,6 +5,4 @@ dotenv.config(); app.listen(process.env.PORT || 3000, () => { console.log(`Server is running on port ${process.env.PORT || 3000}`); -}); - -//test \ No newline at end of file +}); \ No newline at end of file diff --git a/utils/Helper/dataAccess.js b/utils/Helper/dataAccess.js index 553d4cc..40bee37 100644 --- a/utils/Helper/dataAccess.js +++ b/utils/Helper/dataAccess.js @@ -172,7 +172,7 @@ exports.getOrderById = async (id) => { exports.getOrdersByUserId = async (id) => { try { let orders; - const role = await exports.getUserById(id).role; + const role = (await exports.getUserById(id)).role; if (!role) { console.log('User Not Found / Try to Login first'); return null; diff --git a/utils/initial.js b/utils/initial.js index 5ec8488..2a1d47e 100644 --- a/utils/initial.js +++ b/utils/initial.js @@ -1,124 +1,183 @@ -const User = require('../models/user.model'); -const Restaurant = require('../models/restaurant.model'); -const Menu = require('../models/menu.model'); -const MenuItem = require('../models/menuItem.model'); -const Order = require('../models/order.model'); -const OrderItem = require('../models/orderItem.model'); -const hashPassword = require('./hashPassword'); +const User = require("../models/user.model"); +const Restaurant = require("../models/restaurant.model"); +const Menu = require("../models/menu.model"); +const MenuItem = require("../models/menuItem.model"); +const Order = require("../models/order.model"); +const OrderItem = require("../models/orderItem.model"); +const hashPassword = require("./hashPassword"); -exports.ClearDB = async() => { - await User.deleteMany({}); - await Restaurant.deleteMany({}); - await Menu.deleteMany({}); - await MenuItem.deleteMany({}); - await Order.deleteMany({}); - await OrderItem.deleteMany({}); -} - -exports.Customer = async() => { - const password = await hashPassword.hash("123456"); - const user = new User({ - name: "Customer", - username: "customer", - email: "customer@customer.com", - password: password, - phone: "123456789", - role: "customer", - }); - await user.save(); - return user; -} +exports.ClearDB = async () => { + await User.deleteMany({}); + await Restaurant.deleteMany({}); + await Menu.deleteMany({}); + await MenuItem.deleteMany({}); + await Order.deleteMany({}); + await OrderItem.deleteMany({}); +}; -exports.Restaurant = async() => { - const password = await hashPassword.hash("123456"); - const user = new User({ - name: "Restaurant", - username: "restaurant", - email: "restaurant@restaurant.com", - password: password, - phone: "123456789", - role: "restaurant", - }); - await user.save(); +// Customer +exports.Customer = async () => { + const password = await hashPassword.hash("123456"); + const user = new User({ + name: "Customer", + username: "customer", + email: "customer@customer.com", + password: password, + phone: "+201234567890", + role: "customer", + }); + await user.save(); + return user; +}; - const restaurant = new Restaurant({ - userId: user._id, - name: "Dagag bondok", - description: "Delicious bondok", - address: "123 Main St", - phone: user.phone, - status: "open", - }); - await restaurant.save(); - return restaurant; -} +// Admin +exports.Admin = async () => { + const password = await hashPassword.hash("123456"); + const user = new User({ + name: "Admin", + username: "admin", + email: "admin@admin.com", + password: password, + phone: "+201111111111", + role: "admin", + }); + await user.save(); + return user; +}; -exports.Admin = async() => { - const password = await hashPassword.hash("123456"); - const user = new User({ - name: "Admin", - username: "admin", - email: "admin@admin.com", - password: password, - phone: "123456789", - role: "admin", - }); - await user.save(); - return user; -} +// مطعم 1 +exports.Restaurant1 = async () => { + const password = await hashPassword.hash("123456"); + const user = new User({ + name: "Restaurant One", + username: "restaurant1", + email: "res1@restaurant.com", + password: password, + phone: "+201000000001", + role: "restaurant", + }); + await user.save(); -exports.Menu = async(restaurant) => { - const menu = new Menu({ - restaurantId: restaurant._id, - name: "Salta3 Burger", - description: "Delicious burgers", - }); - await menu.save(); - return menu; -} + const restaurant = new Restaurant({ + userId: user._id, + name: "El Tahrir Shawarma", + description: "Best shawarma in town", + address: "12 Tahrir St, Cairo", + phone: user.phone, + status: "open", + }); + await restaurant.save(); + return restaurant; +}; -exports.MenuItem = async(menu) => { - const menuItem = new MenuItem({ - menuId: menu._id, - name: "Salta3 Burger", - description: "Delicious burgers", - price: 10, - }); - await menuItem.save(); - return menuItem; -} +// مطعم 2 +exports.Restaurant2 = async () => { + const password = await hashPassword.hash("123456"); + const user = new User({ + name: "Restaurant Two", + username: "restaurant2", + email: "res2@restaurant.com", + password: password, + phone: "+201000000002", + role: "restaurant", + }); + await user.save(); -exports.Order = async (customer, restaurant, admin, menuItem) => { - const order = new Order({ - customerId: customer._id, - restaurantId: restaurant._id, - adminId: admin._id, - totalPrice: 20, - status: "completed", + const restaurant = new Restaurant({ + userId: user._id, + name: "Italiano Pizza", + description: "Authentic Italian Pizza", + address: "22 October St, Giza", + phone: user.phone, + status: "open", }); - await order.save(); + await restaurant.save(); + return restaurant; +}; - const orderItem = new OrderItem({ - orderId: order._id, - itemId: menuItem._id, - quantity: 2, - price: 10, +// Menu لكل مطعم +exports.Menu = async (restaurant, name) => { + const menu = new Menu({ + restaurantId: restaurant._id, + name, + description: `${restaurant.name} main menu`, }); - await orderItem.save(); + await menu.save(); + return menu; +}; - return { order, orderItem }; +// MenuItems لكل Menu +exports.MenuItems = async (menu, items) => { + const savedItems = []; + for (const item of items) { + const menuItem = new MenuItem({ + menuId: menu._id, + name: item.name, + description: item.description, + price: { + amount: item.price, + currency: "EGP", + }, + isAvailable: true, + }); + await menuItem.save(); + savedItems.push(menuItem); + } + return savedItems; }; +// Seeding كامل exports.all = async () => { try { await exports.ClearDB(); + const customer = await exports.Customer(); - const restaurant = await exports.Restaurant(); const admin = await exports.Admin(); - const menu = await exports.Menu(restaurant); - const menuItem = await exports.MenuItem(menu); - const order = await exports.Order(customer, restaurant, admin, menuItem); - console.log("✅ Initial data seeded:", { customer, restaurant, admin, menu, menuItem, order }); + + // مطعم 1 + Menu + Items + const restaurant1 = await exports.Restaurant1(); + const menu1 = await exports.Menu(restaurant1, "Shawarma Menu"); + const menuItems1 = await exports.MenuItems(menu1, [ + { + name: "Chicken Shawarma", + description: "Juicy chicken wrap", + price: 70, + }, + { name: "Beef Shawarma", description: "Tender beef wrap", price: 80 }, + { name: "Shawarma Combo", description: "Mix chicken + beef", price: 120 }, + ]); + + // مطعم 2 + Menu + Items + const restaurant2 = await exports.Restaurant2(); + const menu2 = await exports.Menu(restaurant2, "Pizza Menu"); + const menuItems2 = await exports.MenuItems(menu2, [ + { + name: "Margherita Pizza", + description: "Cheese & tomato classic", + price: 90, + }, + { + name: "Pepperoni Pizza", + description: "Spicy pepperoni slices", + price: 110, + }, + { + name: "BBQ Chicken Pizza", + description: "Grilled chicken & BBQ sauce", + price: 130, + }, + ]); + + console.log("✅ Seeded:", { + customer, + admin, + restaurant1, + menu1, + menuItems1, + restaurant2, + menu2, + menuItems2, + }); } catch (err) { console.error("❌ Error seeding initial data:", err); } From a4071565c2f9c8378e5619ac942ed04292950d49 Mon Sep 17 00:00:00 2001 From: Mohamed Abdelhafiz Date: Wed, 27 Aug 2025 03:21:30 +0300 Subject: [PATCH 2/2] create filter util function --- utils/filter.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 utils/filter.js diff --git a/utils/filter.js b/utils/filter.js new file mode 100644 index 0000000..483bc0e --- /dev/null +++ b/utils/filter.js @@ -0,0 +1,15 @@ +const filter = async (model, filter, options = {}) => { + try { + const { projection = {}, limit = 0, skip = 0, sort = {} } = options; + const results = await model + .find(filter, projection) + .limit(limit) + .skip(skip) + .sort(sort); + return results; + } catch (error) { + throw new Error(`Error filtering data: ${error.message}`); + } +}; + +module.exports = filter;