diff --git a/final_project/index.js b/final_project/index.js index b890c1d380..679ebaaa18 100644 --- a/final_project/index.js +++ b/final_project/index.js @@ -10,9 +10,26 @@ app.use(express.json()); app.use("/customer",session({secret:"fingerprint_customer",resave: true, saveUninitialized: true})) -app.use("/customer/auth/*", function auth(req,res,next){ -//Write the authenication mechanism here +app.use("/customer/auth/*", function auth(req, res, next) { + // 1. Check if session exists and has an access token + if (!req.session || !req.session.accessToken) { + return res.status(401).json({ message: "Unauthorized: No session token" }); + } + + const token = req.session.accessToken; + + // 2. Verify JWT token + jwt.verify(token, "fingerprint_customer", (err, decoded) => { + if (err) { + return res.status(403).json({ message: "Forbidden: Invalid token" }); + } + + // 3. Save decoded info in req.user to use in downstream routes + req.user = decoded; + next(); // pass control to the next middleware or route handler + }); }); + const PORT =5000; diff --git a/final_project/router/auth_users.js b/final_project/router/auth_users.js index 8cb6ef6e40..822ed4a081 100644 --- a/final_project/router/auth_users.js +++ b/final_project/router/auth_users.js @@ -3,28 +3,107 @@ const jwt = require('jsonwebtoken'); let books = require("./booksdb.js"); const regd_users = express.Router(); -let users = []; +let users = []; // Stores registered users -const isValid = (username)=>{ //returns boolean -//write code to check is the username is valid +// Check if the username is valid (exists in records) +const isValid = (username) => { + return users.some(user => user.username === username); } -const authenticatedUser = (username,password)=>{ //returns boolean -//write code to check if username and password match the one we have in records. +// Check if username and password match +const authenticatedUser = (username, password) => { + return users.some(user => user.username === username && user.password === password); } -//only registered users can login -regd_users.post("/login", (req,res) => { - //Write your code here - return res.status(300).json({message: "Yet to be implemented"}); +// Only registered users can login +regd_users.post("/login", (req, res) => { + const { username, password } = req.body; + + // Validate input + if (!username || !password) { + return res.status(400).json({ message: "Username and password are required" }); + } + + // Check if user exists and password matches + if (authenticatedUser(username, password)) { + // Generate JWT token + const token = jwt.sign({ username }, "fingerprint_customer", { expiresIn: "1h" }); + + // Save token in session + req.session = req.session || {}; // Ensure session object exists + req.session.accessToken = token; + + return res.status(200).json({ message: "User successfully logged in", token }); + } else { + return res.status(401).json({ message: "Invalid username or password" }); + } }); // Add a book review +// Add or update a book review regd_users.put("/auth/review/:isbn", (req, res) => { - //Write your code here - return res.status(300).json({message: "Yet to be implemented"}); + const isbn = req.params.isbn; + const { review } = req.body; + + // Check if user is logged in + if (!req.session || !req.session.accessToken) { + return res.status(401).json({ message: "Unauthorized: Please login first" }); + } + + // Verify JWT token + jwt.verify(req.session.accessToken, "fingerprint_customer", (err, decoded) => { + if (err) { + return res.status(403).json({ message: "Forbidden: Invalid token" }); + } + + const username = decoded.username; + + // Check if the book exists + if (!books[isbn]) { + return res.status(404).json({ message: `Book with ISBN ${isbn} not found` }); + } + + // Add or update the review + books[isbn].reviews = books[isbn].reviews || {}; + books[isbn].reviews[username] = review; + + return res.status(200).json({ message: `Review added/updated for book ${isbn}`, reviews: books[isbn].reviews }); + }); }); +// Delete a book review +regd_users.delete("/auth/review/:isbn", (req, res) => { + const isbn = req.params.isbn; + + // Check if user is logged in + if (!req.session || !req.session.accessToken) { + return res.status(401).json({ message: "Unauthorized: Please login first" }); + } + + // Verify JWT token + jwt.verify(req.session.accessToken, "fingerprint_customer", (err, decoded) => { + if (err) { + return res.status(403).json({ message: "Forbidden: Invalid token" }); + } + + const username = decoded.username; + + // Check if the book exists + if (!books[isbn]) { + return res.status(404).json({ message: `Book with ISBN ${isbn} not found` }); + } + + // Check if the user has a review to delete + if (books[isbn].reviews && books[isbn].reviews[username]) { + delete books[isbn].reviews[username]; // Delete the user's review + return res.status(200).json({ message: `Review deleted for book ${isbn}`, reviews: books[isbn].reviews }); + } else { + return res.status(404).json({ message: "No review found by this user for the specified book" }); + } + }); +}); + + module.exports.authenticated = regd_users; module.exports.isValid = isValid; module.exports.users = users; diff --git a/final_project/router/general.js b/final_project/router/general.js index 9eb0ac1a91..6a8114acd5 100644 --- a/final_project/router/general.js +++ b/final_project/router/general.js @@ -1,43 +1,149 @@ const express = require('express'); +const axios = require('axios'); let books = require("./booksdb.js"); let isValid = require("./auth_users.js").isValid; let users = require("./auth_users.js").users; const public_users = express.Router(); -public_users.post("/register", (req,res) => { - //Write your code here - return res.status(300).json({message: "Yet to be implemented"}); +// Register a new user +public_users.post("/register", (req, res) => { + const { username, password } = req.body; // Get username and password from request body + + // Check if both username and password are provided + if (!username || !password) { + return res.status(400).json({ message: "Username and password are required" }); + } + + // Check if username already exists + const userExists = users.some(user => user.username === username); + if (userExists) { + return res.status(409).json({ message: "Username already exists" }); + } + + // Add the new user to the users array + users.push({ username, password }); + return res.status(201).json({ message: "User registered successfully" }); }); + // Get the book list available in the shop -public_users.get('/',function (req, res) { - //Write your code here - return res.status(300).json({message: "Yet to be implemented"}); +public_users.get('/', async function (req, res) { + try { + // Simulate an API call with Axios using a local endpoint + // Here, we use a Promise that resolves immediately for demo + const response = await new Promise((resolve, reject) => { + resolve({ data: books }); + }); + + const bookList = JSON.stringify(response.data, null, 4); + return res.status(200).send(bookList); + } catch (error) { + return res.status(500).json({ message: "Error fetching books", error: error.message }); + } +}); + +// Get book details based on ISBN using async-await +public_users.get('/isbn/:isbn', async function (req, res) { + const isbn = req.params.isbn; // Retrieve ISBN from request parameters + + try { + // Simulate an async API call using a Promise + const response = await new Promise((resolve, reject) => { + if (books[isbn]) { + resolve({ data: books[isbn] }); + } else { + reject(new Error(`Book with ISBN ${isbn} not found`)); + } + }); + + const bookDetails = JSON.stringify(response.data, null, 4); + return res.status(200).send(bookDetails); + + } catch (error) { + return res.status(404).json({ message: error.message }); + } }); -// Get book details based on ISBN -public_users.get('/isbn/:isbn',function (req, res) { - //Write your code here - return res.status(300).json({message: "Yet to be implemented"}); - }); -// Get book details based on author -public_users.get('/author/:author',function (req, res) { - //Write your code here - return res.status(300).json({message: "Yet to be implemented"}); +// Get book details based on author using async-await +public_users.get('/author/:author', async function (req, res) { + const authorName = req.params.author; // Retrieve author from request parameters + + try { + // Simulate an async API call using a Promise + const response = await new Promise((resolve, reject) => { + const bookKeys = Object.keys(books); + let authorBooks = {}; + + bookKeys.forEach((isbn) => { + if (books[isbn].author.toLowerCase() === authorName.toLowerCase()) { + authorBooks[isbn] = books[isbn]; + } + }); + + if (Object.keys(authorBooks).length > 0) { + resolve({ data: authorBooks }); + } else { + reject(new Error(`No books found by author '${authorName}'`)); + } + }); + + const result = JSON.stringify(response.data, null, 4); + return res.status(200).send(result); + + } catch (error) { + return res.status(404).json({ message: error.message }); + } }); -// Get all books based on title -public_users.get('/title/:title',function (req, res) { - //Write your code here - return res.status(300).json({message: "Yet to be implemented"}); + + +// Get all books based on title using async-await +public_users.get('/title/:title', async function (req, res) { + const titleName = req.params.title; // Retrieve title from request parameters + + try { + // Simulate an async API call using a Promise + const response = await new Promise((resolve, reject) => { + const bookKeys = Object.keys(books); + let titleBooks = {}; + + bookKeys.forEach((isbn) => { + if (books[isbn].title.toLowerCase() === titleName.toLowerCase()) { + titleBooks[isbn] = books[isbn]; + } + }); + + if (Object.keys(titleBooks).length > 0) { + resolve({ data: titleBooks }); + } else { + reject(new Error(`No books found with title '${titleName}'`)); + } + }); + + const result = JSON.stringify(response.data, null, 4); + return res.status(200).send(result); + + } catch (error) { + return res.status(404).json({ message: error.message }); + } }); -// Get book review -public_users.get('/review/:isbn',function (req, res) { - //Write your code here - return res.status(300).json({message: "Yet to be implemented"}); + +// Get book review +public_users.get('/review/:isbn', function (req, res) { + const isbn = req.params.isbn; // Retrieve ISBN from request parameters + + // Check if the book exists + if (books[isbn]) { + const reviews = books[isbn].reviews; // Get the reviews object + const result = JSON.stringify(reviews, null, 4); // Format JSON neatly + return res.status(200).send(result); + } else { + return res.status(404).json({ message: `Book with ISBN ${isbn} not found` }); + } }); + module.exports.general = public_users;