diff --git a/final_project/index.js b/final_project/index.js index b890c1d380..1d2cbae67e 100644 --- a/final_project/index.js +++ b/final_project/index.js @@ -12,6 +12,28 @@ app.use("/customer",session({secret:"fingerprint_customer",resave: true, saveUni app.use("/customer/auth/*", function auth(req,res,next){ //Write the authenication mechanism here +// セッションが存在するかチェック +if (!req.session || !req.session.authorization) { + return res.status(401).json({ message: "Unauthorized. Please login first" }); + } + + try { + // JWTトークンを検証 + const token = req.session.authorization.accessToken; + + // トークンを検証('access'はJWTの署名に使用した秘密鍵) + jwt.verify(token, 'access', (err, decoded) => { + if (err) { + // トークンが無効または期限切れの場合 + return res.status(401).json({ message: "Invalid token. Please login again" }); + } + + // トークンが有効な場合、次のミドルウェアに進む + next(); + }); + } catch (err) { + return res.status(500).json({ message: "Internal server error during authentication" }); + } }); const PORT =5000; diff --git a/final_project/router/auth_users.js b/final_project/router/auth_users.js index 8cb6ef6e40..92e01a0175 100644 --- a/final_project/router/auth_users.js +++ b/final_project/router/auth_users.js @@ -5,24 +5,135 @@ const regd_users = express.Router(); let users = []; -const isValid = (username)=>{ //returns boolean -//write code to check is the username is valid +const isValid = (username) => { //returns boolean + // ユーザー名が有効かチェック(ここでは単純に存在チェック) + return username !== undefined && username.trim() !== ''; } -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) => { //returns boolean +// 指定されたユーザー名とパスワードが一致するユーザーを検索 + const user = users.find(user => user.username === username && user.password === password); + return user !== undefined; } //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 = req.body.username; + const password = req.body.password; + + // ユーザー名またはパスワードが欠けている場合 + if (!username || !password) { + return res.status(400).json({ message: "Username and password are required" }); + } + + // ユーザー認証 + if (authenticatedUser(username, password)) { + // JWT アクセストークンを生成 + let accessToken = jwt.sign({ + data: password + }, 'access', { expiresIn: 60 * 60 }); // 1時間有効 + + // アクセストークンとユーザー名をセッションに保存 + req.session.authorization = { + accessToken, + username + }; + + return res.status(200).json({ + message: "User successfully logged in", + token: accessToken + }); + } else { + return res.status(401).json({ message: "Invalid Login. Check username and password" }); + } }); + + + +// Add a book review // 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"}); + // セッションから認証情報を確認 + if (!req.session || !req.session.authorization) { + return res.status(401).json({ message: "Unauthorized. Please login first" }); + } + + // ユーザー名をセッションから取得 + const username = req.session.authorization.username; + + // ISBNをパラメータから取得 + const isbn = req.params.isbn; + + // レビュー内容をリクエストクエリから取得 + const review = req.query.review; + + // 必須パラメータのチェック + if (!review) { + return res.status(400).json({ message: "Review content is required" }); + } + + // 指定したISBNの本が存在するかチェック + if (!books[isbn]) { + return res.status(404).json({ message: "Book not found with the given ISBN" }); + } + + // レビューを追加または更新 + // ユーザー名をキーとして、そのユーザーのレビューを保存 + books[isbn].reviews[username] = review; + + // 成功レスポンスを返す + return res.status(200).json({ + message: "Review added/updated successfully", + book: books[isbn].title, + user: username, + review: review + }); +}); + +regd_users.delete("/auth/review/:isbn", (req, res) => { + // セッションから認証情報を確認 + if (!req.session || !req.session.authorization) { + return res.status(401).json({ message: "Unauthorized. Please login first" }); + } + + // ユーザー名をセッションから取得 + const username = req.session.authorization.username; + + // ISBNをパラメータから取得 + const isbn = req.params.isbn; + + // 指定したISBNの本が存在するかチェック + if (!books[isbn]) { + return res.status(404).json({ message: "Book not found with the given ISBN" }); + } + + // 本のレビューオブジェクトを取得 + const reviews = books[isbn].reviews; + + // レビューオブジェクトが存在するかチェック + if (!reviews) { + return res.status(404).json({ message: "No reviews exist for this book" }); + } + + // 現在のユーザーのレビューが存在するかチェック + if (!reviews.hasOwnProperty(username)) { + return res.status(403).json({ + message: "You don't have a review for this book or you're not authorized to delete other users' reviews" + }); + } + + // ユーザーのレビューを削除 + delete reviews[username]; + + // 成功レスポンスを返す + return res.status(200).json({ + message: "Review deleted successfully", + book: books[isbn].title, + isbn: isbn, + review: books[isbn].reviews + }); }); module.exports.authenticated = regd_users; diff --git a/final_project/router/general.js b/final_project/router/general.js index 9eb0ac1a91..807e4748cc 100644 --- a/final_project/router/general.js +++ b/final_project/router/general.js @@ -7,37 +7,187 @@ 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"}); + // リクエストボディからユーザー名とパスワードを取得 + 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(400).json({ message: "Invalid username" }); + } + + // ユーザー名が既に存在するかチェック + const userExists = users.some(user => user.username === username); + if (userExists) { + return res.status(409).json({ message: "Username already exists" }); + } + + // 新しいユーザーを追加 + users.push({ username, password }); + + // 成功レスポンスを返す + return res.status(201).json({ message: "User registered successfully" }); + //return res.status(300).json({message: "Yet to be implemented"}); }); // 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('/', function (req, res) { + // create promise for getting books + const getBooksPromise = new Promise((resolve, reject) => { + + setTimeout(() => { + if (books && Object.keys(books).length > 0) { + resolve(books); + } else { + reject("Books data not available"); + } + }, 100); + }); + + // Process results using promises + getBooksPromise + .then((booksData) => { + res.status(200).json(booksData); + }) + .catch((error) => { + res.status(500).json({ message: error }); + }); }); // 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"}); - }); +public_users.get('/isbn/:isbn', function (req, res) { + const isbn = req.params.isbn; + + // create promise for getting books with ISBN + const getBookByISBNPromise = new Promise((resolve, reject) => { + // Simulate Async + setTimeout(() => { + if (books[isbn]) { + resolve(books[isbn]); + } else { + reject("Book not found with the given ISBN"); + } + }, 100); + }); + + // Process results using promises + getBookByISBNPromise + .then((book) => { + res.status(200).json(book); + }) + .catch((error) => { + res.status(404).json({ message: error }); + }); +}); -// 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 Promise +public_users.get('/author/:author', function (req, res) { + const requestedAuthor = req.params.author; + + // create promise for getting books with author + const getBooksByAuthorPromise = new Promise((resolve, reject) => { + // Simulate Async + setTimeout(() => { + const bookIds = Object.keys(books); + const authorBooks = []; + + // Check each book and add matching authors to the results array + bookIds.forEach(id => { + if (books[id] && books[id].author && + books[id].author.toLowerCase() === requestedAuthor.toLowerCase()) { + authorBooks.push({ + isbn: id, + title: books[id].title, + author: books[id].author, + reviews: books[id].reviews + }); + } + }); + + if (authorBooks.length > 0) { + resolve(authorBooks); + } else { + reject("No books found for this author"); + } + }, 100); + }); + + // Process results using promises + getBooksByAuthorPromise + .then((books) => { + res.status(200).json(books); + }) + .catch((error) => { + res.status(404).json({ message: error }); + }); }); -// 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 Promise +public_users.get('/title/:title', function (req, res) { + const requestedTitle = req.params.title.toLowerCase(); + + // Create a promise to search for books by title + const getBooksByTitlePromise = new Promise((resolve, reject) => { + // Simulate Async + setTimeout(() => { + const bookIds = Object.keys(books); + const matchingBooks = []; + + // Check each book and add the ones whose title contains the search term to the results array + bookIds.forEach(id => { + if (books[id] && books[id].title && + books[id].title.toLowerCase().includes(requestedTitle)) { + matchingBooks.push({ + isbn: id, + title: books[id].title, + author: books[id].author, + reviews: books[id].reviews + }); + } + }); + + if (matchingBooks.length > 0) { + resolve(matchingBooks); + } else { + reject("No books found with this title"); + } + }, 100); + }); + + // Process results using promises + getBooksByTitlePromise + .then((books) => { + res.status(200).json(books); + }) + .catch((error) => { + res.status(404).json({ message: error }); + }); }); // 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"}); -}); +public_users.get('/review/:isbn', function (req, res) { + // リクエストパラメータからISBNを取得 + const isbn = req.params.isbn; + + // 指定されたISBNの本が存在するかチェック + if (books[isbn]) { + // 本が存在する場合、そのレビューを返す + const reviews = books[isbn].reviews; + + // レビューがあるかチェック + if (Object.keys(reviews).length > 0) { + res.status(200).json(reviews); + } else { + res.status(404).json({ message: "No reviews found for this book" }); + } + } else { + // 本が存在しない場合はエラーを返す + res.status(404).json({ message: "Book not found with the given ISBN" }); + } + }); module.exports.general = public_users;