S50 Capstone added

master
Ron Reciproco 1 year ago
parent acfadce5cb
commit 4b003da8da

@ -1,40 +1,53 @@
const jwt = require('jsonwebtoken');
require("dotenv").config()
// middlewares/auth.js
// Function to verify JWT token
exports.verifyToken = (token) => {
try {
const decoded = jwt.verify(token, process.env.SECRET_SAUCE);
return decoded;
} catch (error) {
console.error(error);
return null; // Return null if verification fails
}
};
const jwt = require("jsonwebtoken")
require("dotenv").config()
// Middleware for verifying JWT token
exports.authenticateToken = (req, res, next) => {
// Extract the token from the Authorization header
const token = req.header('Authorization')?.replace('Bearer ', '');
// Middleware for verifying and authenticating JWT token
exports.authenticateToken = (req, res, next) => {
// Extract the token from the Authorization header
const token = req.header("Authorization")?.replace("Bearer ", "")
if (!token) {
return res.status(401).json({ message: 'Unauthorized. Token not provided.' });
}
if (!token) {
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) {
return res.status(401).json({ message: 'Unauthorized. Invalid token.' });
}
try {
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
req.user = decoded;
// dEBUGGING PURPOSES
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
exports.generateToken = (userId, email) => {
return jwt.sign({ userId, email }, process.env.SECRET_SAUCE, { expiresIn: '1h' });
};
exports.generateToken = (userId, email, isAdmin) => {
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) => {
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 {
// Check if the user is an admin
if (!req.user.isAdmin) {
return res.status(403).json({ message: 'Permission denied. Only admins can create products.' });
const product = await Product.findById(productId);
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({
name,
description,
price,
isActive,
});
// Update product information
existingProduct.name = name;
existingProduct.description = description;
existingProduct.price = price;
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) {
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.getAllProducts = async (req, res) => {
exports.activateProduct = async (req, res) => {
const { productId } = req.params;
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) {
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.getActiveProducts = async (req, res) => {
exports.archiveProduct = async (req, res) => {
const { productId } = req.params;
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) {
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 faker = require("faker")
const User = require("../model/User")
@ -5,61 +6,140 @@ const auth = require("../auth")
// Controller function for user registration
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 {
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 autoGeneratedFirstName = firstName || faker.name.firstName();
const autoGeneratedLastName = lastName || faker.name.lastName();
const user = await User.findOne({ email });
// Hash the password before saving it
const hashedPassword = await bcrypt.hash(password, 10);
if (!user) {
return res.status(401).json({ message: 'Invalid credentials' });
}
const newUser = new User({
email,
password: hashedPassword,
firstName: autoGeneratedFirstName,
lastName: autoGeneratedLastName,
});
const passwordMatch = await bcrypt.compare(password, user.password);
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) {
console.error(error);
res.status(500).json({ message: 'Internal server error' });
}
};
// Controller function for user authentication
exports.authenticateUser = async (req, res) => {
// Controller function for updating user data (including email, firstName, lastName, and password)
exports.updateUserData = async (req, res) => {
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) {
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) {
return res.status(401).json({ message: "Invalid credentials" })
// Update firstName if provided
if (newFirstName) {
user.firstName = newFirstName
}
// Generate JWT token using the function from auth.js
const token = auth.generateToken(user._id, user.email)
// Update lastName if provided
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({
userId: user._id,
email: user.email,
firstName: user.firstName,
lastName: user.lastName,
isAdmin: user.isAdmin,
token: token,
message: "User data updated successfully",
user: updatedUser,
})
} catch (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.updateUserData = async (req, res) => {
exports.getUserDetails = async (req, res) => {
try {
const { userId, newEmail, newFirstName, newLastName, newPassword } = req.body;
const { userId } = req.params;
// Add authentication logic here using the authorization token
// 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.' });
// }
const userIdFromToken = req.user.userId;
// Your logic to update user data based on userId
// For example:
if (userIdFromToken !== userId) {
return res.status(403).json({
message: "Permission denied. You can only retrieve your own data.",
});
}
const user = await User.findById(userId);
if (!user) {
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;
return res.status(404).json({ message: "User not found" });
}
// Update lastName if provided
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();
// 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 });
// Return the user details in the response
res.status(200).json({
user,
});
} catch (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")
require("dotenv").config()
const userRoute = require("./routes/user")
const productRoute = require("./routes/product")
// Server start
const app = express()
@ -29,7 +30,7 @@ mongoose
})
// Routes
app.use("/user", userRoute)
app.use("/user", userRoute, productRoute)
// Server up
app.listen(process.env.PORT || 3000, () => {

@ -4,7 +4,7 @@ const productSchema = new mongoose.Schema({
name: { type: String, required: true },
description: { type: String, required: true },
price: { type: Number, required: true },
isActive: { type: Boolean, default: true },
isActive: { type: Boolean, default: false },
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 router = express.Router();
const productController = require('../controllers/product');
const auth = require('./auth'); // Assuming you have an auth.js file with authentication middleware
const express = require("express")
const router = express.Router()
const productController = require("../controllers/product")
const auth = require("../auth")
// Middleware for authorization token
const authenticateToken = auth.authenticateToken;
const { authenticateToken, verifyAdmin } = auth
// S50
// 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)
router.get('/all', productController.getAllProducts);
router.get("/all", productController.getAllProducts)
// 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 router = express.Router()
const userController = require("../controllers/user")
const orderController = require("../controllers/order")
const auth = require("../auth");
const { authenticateToken } = auth;
const { authenticateToken, } = auth;
// User registration route
router.post("/register", userController.registerUser)
@ -14,4 +15,10 @@ router.post("/login", userController.authenticateUser)
// Update user data route
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

Loading…
Cancel
Save