require("dotenv").config(); const express = require("express"); const mysql = require("mysql2"); const bodyParser = require("body-parser"); const bcrypt = require("bcryptjs"); const session = require("express-session"); const passport = require("passport"); const LocalStrategy = require("passport-local").Strategy; const flash = require("connect-flash"); const app = express(); const port = 3000; const db = mysql.createConnection({ host: process.env.DB_HOST, user: process.env.DB_USER, password: process.env.DB_PASSWORD, database: process.env.DB_NAME, }); db.connect((err) => { if (err) throw err; console.log("Connected to MySQL Database"); }); app.use(bodyParser.urlencoded({ extended: true })); app.use(express.static("public")); app.set("view engine", "ejs"); app.use(session({ secret: "secret", resave: false, saveUninitialized: false })); app.use(passport.initialize()); app.use(passport.session()); app.use(flash()); // ตั้งค่า Passport สำหรับ Auth passport.use( new LocalStrategy((username, password, done) => { db.query( "SELECT * FROM users WHERE username = ?", [username], async (err, results) => { if (err) return done(err); if (results.length === 0) return done(null, false, { message: "ไม่พบผู้ใช้" }); const user = results[0]; const match = await bcrypt.compare(password, user.password); if (!match) return done(null, false, { message: "รหัสผ่านไม่ถูกต้อง" }); return done(null, user); // ตรวจสอบให้แน่ใจว่าได้ข้อมูลผู้ใช้ที่ถูกต้อง } ); }) ); passport.serializeUser((user, done) => done(null, user.id)); passport.deserializeUser((id, done) => { db.query("SELECT * FROM users WHERE id = ?", [id], (err, results) => { if (err) return done(err); done(null, results[0]); // ควรให้ข้อมูลผู้ใช้ถูกดึงมาอย่างถูกต้อง }); }); // Middleware เช็ค Login const isAuthenticated = (req, res, next) => { if (req.isAuthenticated()) { return next(); } res.redirect("/login"); }; const isAdmin = (req, res, next) => { if (!req.isAuthenticated()) { return res.redirect("/login"); // ถ้าไม่ได้ login ให้ไปหน้า login } if (req.user.role !== "admin") { return res.status(403).send("Forbidden: คุณไม่มีสิทธิ์เข้าถึงหน้านี้"); } next(); // ถ้าเป็น admin ให้ไปต่อ }; passport.deserializeUser((id, done) => { db.query( "SELECT id, username, role FROM users WHERE id = ?", [id], (err, results) => { if (err) return done(err); done(null, results[0]); // ต้องแน่ใจว่า role ถูกส่งมาด้วย } ); }); // หน้า Login app.get("/login", (req, res) => { res.render("login"); }); app.post( "/login", passport.authenticate("local", { successRedirect: "/", failureRedirect: "/login", }) ); // Logout app.get("/logout", (req, res) => { req.logout(() => { res.redirect("/login"); }); }); // Register app.get("/register", (req, res) => { res.render("register"); }); app.post("/register", async (req, res) => { const { username, password } = req.body; const hash = await bcrypt.hash(password, 10); // ทุกคนที่สมัครจากหน้าเว็บจะเป็น 'user' เท่านั้น const role = "user"; db.query( "INSERT INTO users (username, password, role) VALUES (?, ?, ?)", [username, hash, role], (err) => { if (err) throw err; res.redirect("/login"); } ); }); // ค้นหาอุปกรณ์ app.get("/", isAuthenticated, (req, res) => { const search = req.query.search || ""; // ตรวจสอบ search ให้แน่ใจว่ามีค่าเสมอ const searchQuery = `%${search}%`; db.query( "SELECT * FROM equipment WHERE name LIKE ?", [searchQuery], (err, equipment) => { if (err) throw err; res.render("index", { equipment, user: req.user, search }); // ส่งค่า search ไปยังหน้า EJS } ); }); // ยืมอุปกรณ์ // ยืมอุปกรณ์ app.post("/borrow", isAuthenticated, (req, res) => { const { equipment_id, quantity } = req.body; // ตรวจสอบจำนวนที่ต้องการยืม db.query( "SELECT quantity FROM equipment WHERE id = ?", [equipment_id], (err, results) => { if (err) throw err; const availableQuantity = results[0].quantity; if (availableQuantity >= quantity) { // ลดจำนวนอุปกรณ์ที่มีในระบบ db.query( "UPDATE equipment SET quantity = quantity - ? WHERE id = ?", [quantity, equipment_id], (err) => { if (err) throw err; // บันทึกข้อมูลการยืม (โดยใช้สถานะ 'pending' รอการยืนยัน) db.query( "INSERT INTO loans (equipment_id, user_id, quantity, status) VALUES (?, ?, ?, 'pending')", [equipment_id, req.user.id, quantity], (err) => { if (err) throw err; res.redirect("/loans"); // เปลี่ยนเส้นทางไปยังหน้า 'รวมการยืม' } ); } ); } else { res.send("จำนวนอุปกรณ์ไม่เพียงพอ"); } } ); }); // คืนอุปกรณ์ app.post("/return", isAuthenticated, (req, res) => { const { equipment_id } = req.body; db.query( "UPDATE equipment SET quantity = quantity + 1, status = 'available' WHERE id = ?", [equipment_id], (err) => { if (err) throw err; db.query( "UPDATE loans SET returned_at = NOW() WHERE equipment_id = ? AND returned_at IS NULL", [equipment_id], (err) => { if (err) throw err; res.redirect("/"); } ); } ); }); app.get( "/manage", isAuthenticated, (req, res, next) => { console.log(req.user); // ตรวจสอบค่าที่ได้จาก session next(); }, isAdmin, (req, res) => { db.query("SELECT * FROM equipment", (err, equipment) => { if (err) throw err; res.render("manage", { equipment, user: req.user }); }); } ); app.post("/add-equipment", isAuthenticated, (req, res) => { const { name, quantity } = req.body; db.query( "INSERT INTO equipment (name, quantity, status) VALUES (?, ?, 'available')", [name, quantity], (err) => { if (err) throw err; res.redirect("/manage"); } ); }); // แสดงฟอร์มแก้ไขอุปกรณ์ app.get("/edit-equipment/:id", isAuthenticated, (req, res) => { const equipmentId = req.params.id; db.query("SELECT * FROM equipment WHERE id = ?", [equipmentId], (err, results) => { if (err) throw err; if (results.length === 0) { return res.status(404).send("ไม่พบอุปกรณ์ที่ต้องการแก้ไข"); } const equipment = results[0]; res.render("edit-equipment", { equipment }); }); }); // ฟังก์ชันการแก้ไขอุปกรณ์ app.post("/edit-equipment", isAuthenticated, (req, res) => { const { id, name, quantity } = req.body; // ตรวจสอบว่าอุปกรณ์มีจำนวนเป็น 0 หรือไม่ let status = quantity > 0 ? "available" : "unavailable"; // อัปเดตชื่อและจำนวนอุปกรณ์ db.query( "UPDATE equipment SET name = ?, quantity = ?, status = ? WHERE id = ?", [name, quantity, status, id], (err) => { if (err) throw err; res.redirect("/manage"); } ); }); app.post("/delete-equipment", isAuthenticated, (req, res) => { const { id } = req.body; db.query("DELETE FROM equipment WHERE id = ?", [id], (err) => { if (err) throw err; res.redirect("/manage"); }); }); // หน้าแสดงรายการการยืม app.get("/loans", (req, res) => { if (req.user && req.user.role === "user") { db.query( `SELECT loans.id, loans.quantity, loans.status, equipment.name AS equipment_name FROM loans JOIN equipment ON loans.equipment_id = equipment.id WHERE loans.user_id = ?`, [req.user.id], (err, loans) => { if (err) { return res.status(500).send("Error retrieving loans"); } // ส่งข้อมูลทั้ง loans และ equipment ไปยัง EJS res.render("loans", { loans: loans, user: req.user }); } ); } else { res.redirect("/"); // ถ้าไม่ได้ล็อกอินหรือไม่ใช่ผู้ใช้ ให้กลับไปหน้าแรก } }); // หน้าแสดงรายการการยืมสำหรับ Admin app.get("/admin-loans", (req, res) => { if (req.isAuthenticated() && req.user.role === "admin") { // Query ดึงข้อมูลการยืม db.query( 'SELECT loans.id, users.username, equipment.name AS equipment_name, loans.quantity, loans.status FROM loans JOIN users ON loans.user_id = users.id JOIN equipment ON loans.equipment_id = equipment.id WHERE loans.status = "pending"', (err, loans) => { if (err) throw err; res.render("admin-loans", { user: req.user, loans: loans }); // ส่งข้อมูล user และ loans } ); } else { res.redirect("/login"); // ถ้าไม่ใช่ผู้ดูแลระบบ ให้ไปที่หน้า login } }); // ยืนยันการยืม (สำหรับ Admin) // อนุมัติหรือปฏิเสธคำขอยืม (สำหรับ Admin) app.post("/approve-loan", isAuthenticated, isAdmin, (req, res) => { const { loan_id, action } = req.body; // กำหนดสถานะใหม่ let newStatus = action === 'approve' ? 'approved' : 'rejected'; // อัปเดตสถานะในฐานข้อมูล db.query( "UPDATE loans SET status = ? WHERE id = ?", [newStatus, loan_id], (err) => { if (err) throw err; res.redirect("/admin-loans"); // หลังจากอนุมัติหรือปฏิเสธเสร็จ, กลับไปที่หน้าการจัดการการยืม } ); }); // Route แสดงหน้าการยืนยันการยืม app.post("/confirm-loan", (req, res) => { if (!req.user) { return res.redirect("/login"); // หากไม่ได้ล็อกอิน ให้กลับไปที่หน้า login } const equipment_id = req.body.equipment_id; const quantity = req.body.quantity; // ดึงข้อมูลอุปกรณ์จากฐานข้อมูล db.query( "SELECT * FROM equipment WHERE id = ?", [equipment_id], (err, result) => { if (err) throw err; const equipment = result[0]; // ส่งข้อมูล user ไปยัง confirm-loan.ejs res.render("confirm-loan", { equipment, quantity, user: req.user }); } ); }); // Route สำหรับยืนยันการยืม app.post('/submit-loan', (req, res) => { const user_id = req.user.id; // สมมติว่าผู้ใช้ล็อกอินแล้ว const equipment_id = req.body.equipment_id; const quantity = req.body.quantity; // ตรวจสอบว่าอุปกรณ์มีจำนวนเพียงพอหรือไม่ db.query('SELECT * FROM equipment WHERE id = ?', [equipment_id], (err, result) => { if (err) throw err; const equipment = result[0]; if (equipment.quantity >= quantity) { // บันทึกข้อมูลการยืมลงในตาราง loans db.query('INSERT INTO loans (user_id, equipment_id, quantity, status) VALUES (?, ?, ?, "pending")', [user_id, equipment_id, quantity], (err) => { if (err) throw err; // ปรับจำนวนอุปกรณ์ในตาราง equipment db.query('UPDATE equipment SET quantity = quantity - ? WHERE id = ?', [quantity, equipment_id], (err) => { if (err) throw err; res.redirect('/loans'); // เปลี่ยนเส้นทางไปยังหน้า "รวมการยืมอุปกรณ์" }); }); } else { res.send('จำนวนอุปกรณ์ไม่เพียงพอ'); } }); }); // การยกเลิกการยืม (Backend) app.post("/cancel-loan", (req, res) => { const loanId = req.body.loan_id; const userId = req.user.id; const query = "DELETE FROM loans WHERE id = ? AND user_id = ?"; db.query(query, [loanId, userId], (err, result) => { if (err) { console.error(err); return res.redirect("/loans"); } // ใช้ flash message หลังจากการลบสำเร็จ req.flash("success", "การยืมอุปกรณ์ถูกยกเลิกแล้ว"); res.redirect("/loans"); }); }); app.get("/return-equipment", (req, res) => { // ดึงข้อมูลจากฐานข้อมูล db.query( "SELECT * FROM loans WHERE user_id = ?", [req.session.user_id], (err, results) => { if (err) { console.error(err); return res.status(500).send("Database query error"); } console.log(results); // ตรวจสอบว่า loans ถูกดึงมาจริงๆ res.render("return-equipment", { loans: results, user: req.session.user, }); } ); }); app.post("/return-equipment", (req, res) => { const loanId = req.body.loan_id; const userId = req.user.id; // Assume user is logged in and user.id is available // ตรวจสอบว่าผู้ใช้คือผู้ที่ยืมอุปกรณ์จริงหรือไม่ db.query( "SELECT * FROM loans WHERE id = ? AND user_id = ?", [loanId, userId], (err, results) => { if (err) { return res.status(500).send("เกิดข้อผิดพลาดในการเข้าถึงฐานข้อมูล"); } if (results.length === 0) { return res.status(404).send("ไม่พบการยืมอุปกรณ์นี้"); } const loan = results[0]; if (loan.status === "returned") { return res.status(400).send("อุปกรณ์นี้ได้ถูกคืนแล้ว"); } // อัพเดตสถานะการคืนอุปกรณ์ db.query( 'UPDATE loans SET status = "returned" WHERE id = ?', [loanId], (err, result) => { if (err) { return res.status(500).send("เกิดข้อผิดพลาดในการคืนอุปกรณ์"); } res.redirect("/return-equipment"); // กลับไปที่หน้า "คืนอุปกรณ์" } ); } ); }); function confirmReturn(button) { const loanId = button.getAttribute("data-loan-id"); console.log("Loan ID:", loanId); // ตรวจสอบค่า loanId const confirmation = confirm("คุณแน่ใจหรือไม่ว่าต้องการคืนอุปกรณ์นี้?"); if (confirmation) { document.getElementById("loan_id").value = loanId; document.getElementById("returnForm").submit(); } } app.listen(port, () => { console.log(`Server running on http://localhost:${port}`); });