diff --git a/final_project/index.js b/final_project/index.js index b890c1d380..61fcba41ac 100644 --- a/final_project/index.js +++ b/final_project/index.js @@ -2,6 +2,7 @@ const express = require('express'); const jwt = require('jsonwebtoken'); const session = require('express-session') const customer_routes = require('./router/auth_users.js').authenticated; +const public_routes = require('./router/general.js').public_users; const genl_routes = require('./router/general.js').general; const app = express(); @@ -11,12 +12,23 @@ 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 + const token = req.session.authorization?.accessToken; + if(!token){ + return res.status(403).json({message: "Access token missing. Please log in."}) + } + jwt.verify(token, "access",(err, user) => { + if(err){ + return res.status(403).json({message: "Invalid or expired token"}) + } + req.user = user; + next(); + }) }); const PORT =5000; app.use("/customer", customer_routes); -app.use("/", genl_routes); +app.use("/", public_routes); +app.use("/general", genl_routes); app.listen(PORT,()=>console.log("Server is running")); diff --git a/final_project/router/auth_users.js b/final_project/router/auth_users.js index 8cb6ef6e40..a93f4d0385 100644 --- a/final_project/router/auth_users.js +++ b/final_project/router/auth_users.js @@ -5,24 +5,74 @@ const regd_users = express.Router(); let users = []; -const isValid = (username)=>{ //returns boolean -//write code to check is the username is valid -} +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. -} +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"}); +regd_users.post("/login", (req, res) => { + const { username, password } = req.body; + + if (!username || !password) { + return res.status(400).json({ message: "Username and password are required" }); + } + + if (!authenticatedUser(username, password)) { + return res.status(401).json({ message: "Invalid credentials" }); + } + + const accessToken = jwt.sign({ username }, 'access', { expiresIn: '1h' }); + + req.session.authorization = { accessToken, username }; + + return res.status(200).json({ + message: "Login successful", + token: accessToken + }); }); // Add 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.review; + const username = req.session.authorization?.username; + if (!username) { + return res.status(403).json({ message: "User not authenticated" }); + } + if (!books[isbn]) { + return res.status(404).json({ message: "Book not found" }); + } + if (!review) { + return res.status(400).json({ message: "Review content is required" }); + } + books[isbn].reviews = books[isbn].reviews || {}; + books[isbn].reviews[username] = review; + return res.status(200).json({ message: "Review added/updated successfully" }); +}); + +regd_users.delete("/auth/review/:isbn", (req, res) => { + const isbn = req.params.isbn; + const username = req.session.authorization?.username; + + if (!username) { + return res.status(403).json({ message: "User not authenticated" }); + } + + const book = books[isbn]; + if (!book) { + return res.status(404).json({ message: "Book not found" }); + } + + if (!book.reviews || !book.reviews[username]) { + return res.status(404).json({ message: "No review found for this user" }); + } + + delete book.reviews[username]; + return res.status(200).json({ message: "Review deleted successfully" }); }); module.exports.authenticated = regd_users; diff --git a/final_project/router/general.js b/final_project/router/general.js index 9eb0ac1a91..58ff731537 100644 --- a/final_project/router/general.js +++ b/final_project/router/general.js @@ -3,41 +3,160 @@ let books = require("./booksdb.js"); let isValid = require("./auth_users.js").isValid; let users = require("./auth_users.js").users; const public_users = express.Router(); - +let general = express.Router(); public_users.post("/register", (req,res) => { - //Write your code here - return res.status(300).json({message: "Yet to be implemented"}); + const { username, password } = req.body; + if(!username || !password){ + return res.status(400).json({message : "Username and password are required"}) + } + if(isValid(username)){ + return res.status(409).json({message: "User already exists"}); + } + users.push({username, password}); + return res.status(200).json({message: "User sucessfully registered"}); }); // 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"}); + return res.status(200).json(books); }); // 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"}); + const isbn = req.params.isbn; + const book = books[isbn]; + if(!book){ + return res.status(404).json({ message : "Book not found"}); + } + return res.status(200).json(book); }); - + // 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"}); + const author = req.params.author.toLocaleLowerCase(); + const filteredBooks = Object.entries(books) + .filter(([_, book]) => book.author.toLocaleLowerCase() === author) + .map(([isbn, book]) => ({isbn, ...book})); + if(filteredBooks.length === 0){ + return res.status(404).json({message: "No books found by this author"}) + } + return res.status(200).json(filteredBooks); }); // 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"}); + const title = req.params.title.toLocaleLowerCase(); + const filteredBooks = Object.entries(books) + .filter(([_, book]) => book.title.toLocaleLowerCase() === title) + .map(([isbn, book]) => ({isbn, ...book})); + if(filteredBooks.length === 0){ + return res.json({message: "No books found with this title"}) + } + return res.status(200).json(filteredBooks); }); // 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"}); + const isbn = req.params.isbn; + const book = books[isbn]; + if(!book){ + return res.status(404).json({ message: "Book not found"}) + } + return res.status(200).json(book.reviews); }); -module.exports.general = public_users; + + // Task 10: Get all books using an async callback function + function getBooks() { + return new Promise((resolve, reject) => { + if (books) { + resolve(books); + } else { + reject("Books not available"); + } + }); + } + + general.get("/", async (req, res) => { + try { + const data = await getBooks(); + res.send(JSON.stringify(data, null, 4)); + } catch (err) { + res.status(500).send({ message: err }); + } + }); + + // Task 11: Get book by ISBN using Promise + function getBookByISBN(isbn) { + return new Promise((resolve, reject) => { + const book = books[isbn]; + if (book) { + resolve(book); + } else { + reject("Book not found for ISBN: " + isbn); + } + }); + } + + general.get('/isbn/:isbn', (req, res) => { + const isbn = req.params.isbn; + getBookByISBN(isbn) + .then((book) => { + res.send(JSON.stringify(book, null, 4)); // Pretty print JSON + }) + .catch((error) => { + res.status(404).send({ message: error }); + }); + }); + + // Task 12: Get books by author using Promise + function getBooksByAuthor(author) { + return new Promise((resolve, reject) => { + const matchingBooks = Object.values(books).filter( + (book) => book.author.toLowerCase() === author.toLowerCase() + ); + if (matchingBooks.length > 0) { + resolve(matchingBooks); + } else { + reject("No books found by author: " + author); + } + }); + } + + general.get("/author/:author", async (req, res) => { + try { + const author = req.params.author; + const data = await getBooksByAuthor(author); + res.send(JSON.stringify(data, null, 4)); + } catch (err) { + res.status(404).send({ message: err }); + } + }); + + // Task 13: Get books by title using Promise + function getBooksByTitle(title) { + return new Promise((resolve, reject) => { + const matchingBooks = Object.values(books).filter( + (book) => book.title.toLowerCase() === title.toLowerCase() + ); + if (matchingBooks.length > 0) { + resolve(matchingBooks); + } else { + reject("No books found with title: " + title); + } + }); + } + + general.get("/title/:title", async (req, res) => { + try { + const title = req.params.title; + const data = await getBooksByTitle(title); + res.send(JSON.stringify(data, null, 4)); + } catch (err) { + res.status(404).send({ message: err }); + } + }); + + module.exports.general = general; + module.exports.public_users = public_users;