S50 Capstone added

master
Ron Reciproco 1 year ago
parent acfadce5cb
commit 4b003da8da

@ -1,40 +1,53 @@
const jwt = require('jsonwebtoken'); // middlewares/auth.js
require("dotenv").config()
// Function to verify JWT token const jwt = require("jsonwebtoken")
exports.verifyToken = (token) => { require("dotenv").config()
try {
const decoded = jwt.verify(token, process.env.SECRET_SAUCE);
return decoded;
} catch (error) {
console.error(error);
return null; // Return null if verification fails
}
};
// Middleware for verifying JWT token // Middleware for verifying and authenticating JWT token
exports.authenticateToken = (req, res, next) => { exports.authenticateToken = (req, res, next) => {
// Extract the token from the Authorization header // Extract the token from the Authorization header
const token = req.header('Authorization')?.replace('Bearer ', ''); const token = req.header("Authorization")?.replace("Bearer ", "")
if (!token) { if (!token) {
return res.status(401).json({ message: 'Unauthorized. Token not provided.' }); return res
} .status(401)
.json({ message: "Unauthorized. Token not provided." })
}
const decoded = exports.verifyToken(token); console.log("Token:", token) // Log the token to the console
if (!decoded) { try {
return res.status(401).json({ message: 'Unauthorized. Invalid token.' }); const decoded = jwt.verify(token, process.env.SECRET_SAUCE)
} req.user = decoded // Attach the decoded information to the request for future use
// Attach the decoded information to the request for future use // dEBUGGING PURPOSES
req.user = decoded; console.log("userId:", decoded.userId)
console.log("isAdmin:", decoded.isAdmin)
// Proceed to the next middleware or route handler next()
next(); } catch (error) {
}; console.error("Token Verification Error:", error)
return res
.status(401)
.json({ message: "Unauthorized. Invalid or expired token." })
}
}
// Function to generate a JWT token // Function to generate a JWT token
exports.generateToken = (userId, email) => { exports.generateToken = (userId, email, isAdmin) => {
return jwt.sign({ userId, email }, process.env.SECRET_SAUCE, { expiresIn: '1h' }); return jwt.sign({ userId, email, isAdmin }, process.env.SECRET_SAUCE, {
}; expiresIn: "1h",
})
}
// Middleware to verify admin status
exports.verifyAdmin = (req, res, next) => {
if (req.user && req.user.isAdmin) {
next()
} else {
return res
.status(403)
.json({ message: "Action Forbidden. User is not an admin." })
}
}

@ -0,0 +1,30 @@
const User = require("../model/User")
exports.createOrder = async (req, res) => {
try {
const { userId, products, totalAmount } = req.body
const user = await User.findById(userId)
if (!user) {
return res.status(404).json({ message: "User not found" })
}
const newOrder = {
products: products,
totalAmount: totalAmount,
purchaseOn: Date.now(),
}
user.orderedProducts.push(newOrder)
await user.save()
res.status(201).json({
message: "Order created successfully",
order: newOrder,
})
} catch (error) {
console.error(error)
res.status(500).json({ message: "Internal Server Error" })
}
}

@ -1,52 +1,141 @@
// productController.js const Product = require("../model/Product")
const Product = require('../model/Product');
// Controller function for creating a product (accessible only by isAdmin)
exports.createProduct = async (req, res) => { exports.createProduct = async (req, res) => {
try {
const { name, description, price } = req.body
const newProduct = new Product({ name, description, price })
await newProduct.save()
res.status(201).json(newProduct)
} catch (error) {
res.status(500).json({ error: error.message })
}
}
// Controller function for retrieving all products (accessible to both admin and normal user)
exports.getAllProducts = async (req, res) => {
try {
const products = await Product.find()
res.status(200).json(products)
} catch (error) {
console.error(error)
res.status(500).json({ message: "Internal server error" })
}
}
// Controller function for retrieving all active products (accessible to both admin and normal user)
exports.getActiveProducts = async (req, res) => {
try {
const activeProducts = await Product.find({ isActive: true })
res.status(200).json(activeProducts)
} catch (error) {
console.error(error)
res.status(500).json({ message: "Internal server error" })
}
}
// Controller to retrieve a single product by id
exports.getProductById = async (req, res) => {
const productId = req.params.id;
try { try {
// Check if the user is an admin const product = await Product.findById(productId);
if (!req.user.isAdmin) {
return res.status(403).json({ message: 'Permission denied. Only admins can create products.' }); if (!product) {
return res.status(404).json({ message: 'Product not found' });
} }
const { name, description, price, isActive } = req.body; res.status(200).json(product);
} catch (error) {
res.status(500).json({ message: 'Internal server error' });
}
};
// Controller function to update product information
exports.updateProduct = async (req, res) => {
const productId = req.params.id;
const { name, description, price, isActive } = req.body;
try {
// Check if the product exists
const existingProduct = await Product.findById(productId);
if (!existingProduct) {
return res.status(404).json({ message: 'Product not found' });
}
const newProduct = new Product({ // Update product information
name, existingProduct.name = name;
description, existingProduct.description = description;
price, existingProduct.price = price;
isActive, existingProduct.isActive = isActive;
});
await newProduct.save(); // Save the updated product
const updatedProduct = await existingProduct.save();
res.status(201).json({ message: 'Product created successfully' }); res.status(200).json(updatedProduct);
} catch (error) { } catch (error) {
console.error(error); console.error(error);
res.status(500).json({ message: 'Internal server error' }); res.status(500).json({ message: 'Internal Server Error' });
} }
}; };
// Controller function for retrieving all products (accessible to both admin and normal user) exports.activateProduct = async (req, res) => {
exports.getAllProducts = async (req, res) => { const { productId } = req.params;
try { try {
const products = await Product.find(); // Find the product by ID
const product = await Product.findById(productId);
if (!product) {
return res.status(404).json({ message: 'Product not found' });
}
res.status(200).json(products); // Check if the product is already active
if (product.isActive) {
return res.status(400).json({ message: 'Product is already active' });
}
// Activate the product
product.isActive = true;
// Save the updated product
await product.save();
res.json({ message: 'Product activated successfully', product });
} catch (error) { } catch (error) {
console.error(error); console.error(error);
res.status(500).json({ message: 'Internal server error' }); res.status(500).json({ message: 'Internal Server Error' });
} }
}; };
// Controller function for retrieving all active products (accessible to both admin and normal user) exports.archiveProduct = async (req, res) => {
exports.getActiveProducts = async (req, res) => { const { productId } = req.params;
try { try {
const activeProducts = await Product.find({ isActive: true }); // Find the product by ID
const product = await Product.findById(productId);
if (!product) {
return res.status(404).json({ message: 'Product not found' });
}
res.status(200).json(activeProducts); // Check if the product is already active
if (!product.isActive) {
return res.status(400).json({ message: 'Product is already in Archive' });
}
// Activate the product
product.isActive = false;
// Save the updated product
await product.save();
res.json({ message: 'Product successfuly archived', product });
} catch (error) { } catch (error) {
console.error(error); console.error(error);
res.status(500).json({ message: 'Internal server error' }); res.status(500).json({ message: 'Internal Server Error' });
} }
}; };

@ -1,3 +1,4 @@
const jwt = require('jsonwebtoken');
const bcrypt = require("bcrypt") const bcrypt = require("bcrypt")
const faker = require("faker") const faker = require("faker")
const User = require("../model/User") const User = require("../model/User")
@ -5,61 +6,140 @@ const auth = require("../auth")
// Controller function for user registration // Controller function for user registration
exports.registerUser = async (req, res) => { exports.registerUser = async (req, res) => {
try {
const { email, password, firstName, lastName } = req.body
// Check if the email already exists
const existingUser = await User.findOne({ email })
if (existingUser) {
return res
.status(400)
.json({ message: "This Email is already registered." })
}
// If firstName and lastName are not provided, generate default values using faker
const autoGeneratedFirstName = firstName || faker.name.firstName()
const autoGeneratedLastName = lastName || faker.name.lastName()
// Hash the password before saving it
const hashedPassword = await bcrypt.hash(password, 10)
const newUser = new User({
email,
password: hashedPassword,
firstName: autoGeneratedFirstName,
lastName: autoGeneratedLastName,
})
await newUser.save()
res.status(201).json({
message:
"User registered successfully. To update account details, acess user/update",
})
} catch (error) {
console.error(error)
res.status(500).json({ message: "Internal server error" })
}
}
// Controller function for user authentication
exports.authenticateUser = async (req, res) => {
try { try {
const { email, password, firstName, lastName } = req.body; const { email, password } = req.body;
// If firstName and lastName are not provided, generate default values using faker const user = await User.findOne({ email });
const autoGeneratedFirstName = firstName || faker.name.firstName();
const autoGeneratedLastName = lastName || faker.name.lastName();
// Hash the password before saving it if (!user) {
const hashedPassword = await bcrypt.hash(password, 10); return res.status(401).json({ message: 'Invalid credentials' });
}
const newUser = new User({ const passwordMatch = await bcrypt.compare(password, user.password);
email,
password: hashedPassword,
firstName: autoGeneratedFirstName,
lastName: autoGeneratedLastName,
});
await newUser.save(); if (!passwordMatch) {
return res.status(401).json({ message: 'Invalid credentials' });
}
res.status(201).json({ message: 'User registered successfully. To update account details, acess user/update' }); // Generate JWT token using the function from auth.js
const token = auth.generateToken(user._id, user.email, user.isAdmin);
// Decode JWT token to get expiration time
const decodedToken = jwt.decode(token);
if (decodedToken) {
const expiration = new Date(decodedToken.exp * 1000); // Convert seconds to milliseconds
// Log token expiration
console.log(`Login success. Token will expire on: ${expiration}`);
} else {
console.error('Error decoding token');
}
// Return user details and token
res.status(200).json({
userId: user._id,
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
isAdmin: user.isAdmin,
token: token,
});
} catch (error) { } catch (error) {
console.error(error); console.error(error);
res.status(500).json({ message: 'Internal server error' }); res.status(500).json({ message: 'Internal server error' });
} }
}; };
// Controller function for updating user data (including email, firstName, lastName, and password)
exports.updateUserData = async (req, res) => {
// Controller function for user authentication
exports.authenticateUser = async (req, res) => {
try { try {
const { email, password } = req.body const { userId, newEmail, newFirstName, newLastName, newPassword } =
req.body
const userIdFromToken = req.user.userId
if (userIdFromToken !== userId) {
return res.status(403).json({
message:
"Permission denied. You can only update your own data.",
})
}
const user = await User.findOne({ email }) const user = await User.findById(userId)
if (!user) { if (!user) {
return res.status(401).json({ message: "Invalid credentials" }) return res.status(404).json({ message: "User not found" })
} }
const passwordMatch = await bcrypt.compare(password, user.password) // Update email if provided
if (newEmail) {
user.email = newEmail
}
if (!passwordMatch) { // Update firstName if provided
return res.status(401).json({ message: "Invalid credentials" }) if (newFirstName) {
user.firstName = newFirstName
} }
// Generate JWT token using the function from auth.js // Update lastName if provided
const token = auth.generateToken(user._id, user.email) if (newLastName) {
user.lastName = newLastName
}
// Update password if provided
if (newPassword) {
const hashedPassword = await bcrypt.hash(newPassword, 10)
user.password = hashedPassword
}
// Save the updated user data
await user.save()
// Return user details and token // Fetch the updated user details
const updatedUser = await User.findById(userId)
// Return the updated user details in the response
res.status(200).json({ res.status(200).json({
userId: user._id, message: "User data updated successfully",
email: user.email, user: updatedUser,
firstName: user.firstName,
lastName: user.lastName,
isAdmin: user.isAdmin,
token: token,
}) })
} catch (error) { } catch (error) {
console.error(error) console.error(error)
@ -67,58 +147,30 @@ exports.authenticateUser = async (req, res) => {
} }
} }
// Controller function for updating user data (including email, firstName, lastName, and password) exports.getUserDetails = async (req, res) => {
exports.updateUserData = async (req, res) => {
try { try {
const { userId, newEmail, newFirstName, newLastName, newPassword } = req.body; const { userId } = req.params;
// Add authentication logic here using the authorization token const userIdFromToken = req.user.userId;
// For example:
// const userIdFromToken = req.user.userId;
// if (userIdFromToken !== userId) {
// return res.status(403).json({ message: 'Permission denied. You can only update your own data.' });
// }
// Your logic to update user data based on userId if (userIdFromToken !== userId) {
// For example: return res.status(403).json({
message: "Permission denied. You can only retrieve your own data.",
});
}
const user = await User.findById(userId); const user = await User.findById(userId);
if (!user) { if (!user) {
return res.status(404).json({ message: 'User not found' }); return res.status(404).json({ message: "User not found" });
}
// Update email if provided
if (newEmail) {
user.email = newEmail;
}
// Update firstName if provided
if (newFirstName) {
user.firstName = newFirstName;
} }
// Update lastName if provided // Return the user details in the response
if (newLastName) { res.status(200).json({
user.lastName = newLastName; user,
} });
// Update password if provided
if (newPassword) {
const hashedPassword = await bcrypt.hash(newPassword, 10);
user.password = hashedPassword;
}
// Save the updated user data
await user.save();
// Fetch the updated user details
const updatedUser = await User.findById(userId);
// Return the updated user details in the response
res.status(200).json({ message: 'User data updated successfully', user: updatedUser });
} catch (error) { } catch (error) {
console.error(error); console.error(error);
res.status(500).json({ message: 'Internal server error' }); res.status(500).json({ message: "Internal server error" });
} }
}; };

@ -4,6 +4,7 @@ const mongoose = require("mongoose")
const cors = require("cors") const cors = require("cors")
require("dotenv").config() require("dotenv").config()
const userRoute = require("./routes/user") const userRoute = require("./routes/user")
const productRoute = require("./routes/product")
// Server start // Server start
const app = express() const app = express()
@ -29,7 +30,7 @@ mongoose
}) })
// Routes // Routes
app.use("/user", userRoute) app.use("/user", userRoute, productRoute)
// Server up // Server up
app.listen(process.env.PORT || 3000, () => { app.listen(process.env.PORT || 3000, () => {

@ -4,7 +4,7 @@ const productSchema = new mongoose.Schema({
name: { type: String, required: true }, name: { type: String, required: true },
description: { type: String, required: true }, description: { type: String, required: true },
price: { type: Number, required: true }, price: { type: Number, required: true },
isActive: { type: Boolean, default: true }, isActive: { type: Boolean, default: false },
createdOn: { type: Date, default: Date.now }, createdOn: { type: Date, default: Date.now },
}); });

@ -0,0 +1,89 @@
**** Accounts ****
User: ( Password: wapatu )
{
"userId": "65544d9be5c01f6c0ca79200",
"email": "wapatu@example.com",
"firstName": "Estevan",
"lastName": "Cummings",
"isAdmin": false,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NTU0NGQ5YmU1YzAxZjZjMGNhNzkyMDAiLCJlbWFpbCI6IndhcGF0dUBleGFtcGxlLmNvbSIsImlzQWRtaW4iOmZhbHNlLCJpYXQiOjE3MDAwMjM3MjQsImV4cCI6MTcwMDAyNzMyNH0.dpWV9Zx64TH4RLgmV_RlyrMBCa0HwDe9wJRAkwAyjys"
}
Admin: (Password is: admin )
{
"userId": "65535cb526b586a3e2fd56cc",
"email": "admin@email.com",
"isAdmin": true,
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOiI2NTUzNWNiNTI2YjU4NmEzZTJmZDU2Y2MiLCJlbWFpbCI6ImFkbWluQGVtYWlsLmNvbSIsImlzQWRtaW4iOnRydWUsImlhdCI6MTcwMDAyMzgxMSwiZXhwIjoxNzAwMDI3NDExfQ.DrhpNlBJKpfHod7MfTalQ5j2-s8tnR630yh2-_EIYWw"
}
**** Links ****
REGISTER
http://localhost:3000/user/register
--> Use post
{
"email": "admin@email.com",
"password": "admin"
}
LOGIN
http://localhost:3000/user/login
--> Use post
{
"email": "admin@email.com",
"password": "admin"
}
UPDATE PROFILE
http://localhost:3000/user/update
--> Must use Admin token // use put
{
"userId": "6554473388d9942bbf4de065",
"newEmail": "mundo@email.com",
"newFirstname": "Ron",
"newLastName": "Pogi",
"newPassword": "mundo"
}
CREATE PRODUCT [ADMIN]
http://localhost:3000/user/products
--> Must use Admin token // use post
{
"name": "Poring Card",
"description": "Description unknown",
"price": 500
}
GET ALL PRODUCT
http://localhost:3000/user/all
--> Use get
GET ALL ACTIVE PRODUCT
http://localhost:3000/user/active
--> Use get
GET A SINGLE PROUCT
http://localhost:3000/user/products/65538bd4a601aa30730f6d4c
--> Use get
UPDATE A PRODUCT [ADMIN]
http://localhost:3000/user/products/65545a1e6fa9d841e1518d1d
--> Must use Admin token // Use put
{
"name": "Christmas Cookie Card",
"description": "Updated Product Description",
"price": 29.99,
"isActive": false
}
ACTIVATE / ARCHIVE A PRODUCT [ADMIN]
--> Use Put
http://localhost:3000/user/products/6554634e5cac4bcd6f2394ed/activate
http://localhost:3000/user/products/6554634e5cac4bcd6f2394ed/archive
RETRIEVE OWN USER DATA
--> Use Get
http://localhost:3000/user/65535cb526b586a3e2fd56cc

@ -1,18 +1,32 @@
const express = require('express'); const express = require("express")
const router = express.Router(); const router = express.Router()
const productController = require('../controllers/product'); const productController = require("../controllers/product")
const auth = require('./auth'); // Assuming you have an auth.js file with authentication middleware const auth = require("../auth")
// Middleware for authorization token const { authenticateToken, verifyAdmin } = auth
const authenticateToken = auth.authenticateToken;
// S50
// Create a product route (accessible only by isAdmin) // Create a product route (accessible only by isAdmin)
router.post('/create', authenticateToken, productController.createProduct); router.post("/products", authenticateToken, verifyAdmin, productController.createProduct)
// Retrieve all products route (accessible to both admin and normal user) // Retrieve all products route (accessible to both admin and normal user)
router.get('/all', productController.getAllProducts); router.get("/all", productController.getAllProducts)
// Retrieve all active products route (accessible to both admin and normal user) // Retrieve all active products route (accessible to both admin and normal user)
router.get('/active', productController.getActiveProducts); router.get("/active", productController.getActiveProducts)
module.exports = router; // S51
// Retrieve a single product by ID
router.get('/products/:id', productController.getProductById);
// Update product route + admin verification
router.put('/products/:id', authenticateToken, verifyAdmin, productController.updateProduct);
// Archive a product
router.put('/products/:productId/archive', authenticateToken, verifyAdmin, productController.archiveProduct);
// Activate a product
router.put('/products/:productId/activate', authenticateToken, verifyAdmin, productController.activateProduct);
module.exports = router

@ -1,9 +1,10 @@
const express = require("express") const express = require("express")
const router = express.Router() const router = express.Router()
const userController = require("../controllers/user") const userController = require("../controllers/user")
const orderController = require("../controllers/order")
const auth = require("../auth"); const auth = require("../auth");
const { authenticateToken } = auth; const { authenticateToken, } = auth;
// User registration route // User registration route
router.post("/register", userController.registerUser) router.post("/register", userController.registerUser)
@ -14,4 +15,10 @@ router.post("/login", userController.authenticateUser)
// Update user data route // Update user data route
router.put("/update", authenticateToken, userController.updateUserData) router.put("/update", authenticateToken, userController.updateUserData)
// POST /users/order
router.post("/order", orderController.createOrder);
// Retrieve user details
router.get('/:userId', authenticateToken, userController.getUserDetails);
module.exports = router module.exports = router

Loading…
Cancel
Save