From c59c8dae19ed96a9b2f735765740a6dd760fa727 Mon Sep 17 00:00:00 2001 From: 65160132 <65160132@go.buu.ac.th> Date: Sat, 22 Mar 2025 23:54:06 +0700 Subject: [PATCH] show crate delete --- controllers/indexController.js | 33 ++- controllers/loginController.js | 1 + controllers/productController.js | 40 ++++ index.js | 7 +- public/css/index.css | 6 + views/addProduct.ejs | 31 +++ views/index.ejs | 381 ++----------------------------- views/product.ejs | 31 +++ 8 files changed, 161 insertions(+), 369 deletions(-) create mode 100644 controllers/productController.js create mode 100644 public/css/index.css create mode 100644 views/addProduct.ejs create mode 100644 views/product.ejs diff --git a/controllers/indexController.js b/controllers/indexController.js index 7ccb044..932af7d 100644 --- a/controllers/indexController.js +++ b/controllers/indexController.js @@ -1,3 +1,30 @@ -module.exports = (req, res) => { - res.render('index', { message: req.flash('message') }); -} \ No newline at end of file +const pool = require('../db'); + +exports.getProducts = async (req, res) => { + try { + const [rows] = await pool.query('SELECT * FROM products'); + res.render('index', { products: rows }); + } catch (err) { + res.status(500).send('Database error: ' + err.message); + } + }; + + exports.getProductDetail = async (req, res) => { + const productId = req.params.id; + try { + const [rows] = await pool.query(` + SELECT p.*, u.email AS owner + FROM products p + LEFT JOIN users u ON p.owner = u.email + WHERE p.product_id = ?`, [productId]); + + if (rows.length === 0) { + return res.status(404).send('ไม่พบสินค้านี้'); + } + + res.render('product', { product: rows[0], currentUserEmail: req.session.userIdEmail || '' }); + } catch (err) { + res.status(500).send('Database error: ' + err.message); + } + }; + \ No newline at end of file diff --git a/controllers/loginController.js b/controllers/loginController.js index 0ef09e3..5e69712 100644 --- a/controllers/loginController.js +++ b/controllers/loginController.js @@ -19,6 +19,7 @@ module.exports = { const match = await bcrypt.compare(rpassword, user.password); if (match) { req.session.userId = user.id + req.session.userIdEmail = user.email; res.redirect('/'); } else { req.flash('message', 'Password incorrect'); diff --git a/controllers/productController.js b/controllers/productController.js new file mode 100644 index 0000000..e202f1c --- /dev/null +++ b/controllers/productController.js @@ -0,0 +1,40 @@ +const pool = require('../db'); + +exports.showAddProductForm = (req, res) => { + res.render('addProduct'); +}; + +exports.createProduct = async (req, res) => { + const { product_name, price, image, description } = req.body; + const owner = req.session.userIdEmail; // เราต้องเก็บ email ตอน login ด้วยนะครับ + try { + const sql = 'INSERT INTO products (product_name, price, image, description, owner) VALUES (?, ?, ?, ?, ?)'; + await pool.query(sql, [product_name, price, image, description, owner]); + res.redirect('/'); + } catch (err) { + res.status(500).send('เกิดข้อผิดพลาดในการเพิ่มสินค้า: ' + err.message); + } + }; + + exports.deleteProduct = async (req, res) => { + const productId = req.params.id; + const currentUserEmail = req.session.userIdEmail; + try { + // ตรวจสอบว่าผู้ใช้นี้เป็นเจ้าของหรือไม่ + const [rows] = await pool.query('SELECT * FROM products WHERE product_id = ?', [productId]); + if (rows.length === 0) { + return res.status(404).send('ไม่พบสินค้านี้'); + } + const product = rows[0]; + if (product.owner !== currentUserEmail) { + return res.status(403).send('คุณไม่มีสิทธิ์ลบสินค้านี้'); + } + + // ลบสินค้าได้ + await pool.query('DELETE FROM products WHERE product_id = ?', [productId]); + res.redirect('/'); + } catch (err) { + res.status(500).send('Database error: ' + err.message); + } + }; + \ No newline at end of file diff --git a/index.js b/index.js index 39e707b..2e4a8e8 100644 --- a/index.js +++ b/index.js @@ -25,14 +25,19 @@ const indexController = require('./controllers/indexController'); const loginController = require('./controllers/loginController'); const registerController = require('./controllers/registerController'); const logoutController = require('./controllers/logoutController'); +const productController = require('./controllers/productController'); -app.get('/', indexController); +app.get('/', indexController.getProducts); app.get('/login', loginController.showLoginPage); app.post('/user/login', loginController.loginUser); app.get('/register', registerController.showRegisterPage); app.post('/user/register', registerController.registerUser); app.post('/user/register', registerController.registerUser); app.get('/logout', logoutController); +app.get('/product/:id', indexController.getProductDetail); +app.get('/addProduct', productController.showAddProductForm); +app.post('/addProduct', productController.createProduct); +app.post('/delete_product/:id', productController.deleteProduct); const port = process.env.PORT || 3000; app.listen(port, () => { diff --git a/public/css/index.css b/public/css/index.css new file mode 100644 index 0000000..b453322 --- /dev/null +++ b/public/css/index.css @@ -0,0 +1,6 @@ +img { + width: 150px; + height: auto; + border-radius: 8px; + margin-bottom: 10px; + } \ No newline at end of file diff --git a/views/addProduct.ejs b/views/addProduct.ejs new file mode 100644 index 0000000..c0e76b2 --- /dev/null +++ b/views/addProduct.ejs @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>เพิ่มสินค้าใหม่</title> +</head> +<body> + <h1>เพิ่มสินค้าใหม่</h1> + <form action="/addProduct" method="POST"> + <div> + <label>ชื่อสินค้า:</label> + <input type="text" name="product_name" required> + </div> + <div> + <label>ราคาสินค้า:</label> + <input type="number" name="price" required> + </div> + <div> + <label>URL รูปภาพ:</label> + <input type="text" name="image" required> + </div> + <div> + <label>รายละเอียดสินค้า:</label> + <textarea name="description"></textarea> + </div> + <button type="submit">เพิ่มสินค้า</button> + </form> + <a href="/">กลับหน้าหลัก</a> +</body> +</html> diff --git a/views/index.ejs b/views/index.ejs index 11f2fbe..0d1212e 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -19,6 +19,7 @@ <link rel="stylesheet" type="text/css" href="css/style.css"> <!-- Responsive--> <link rel="stylesheet" href="css/responsive.css"> + <link rel="stylesheet" href="css/index.css"> <!-- fevicon --> <link rel="icon" href="images/fevicon.png" type="image/gif" /> <!-- Scrollbar Custom CSS --> @@ -30,7 +31,7 @@ <link rel="stylesheet" href="css/owl.theme.default.min.css"> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fancybox/2.1.5/jquery.fancybox.min.css" media="screen"> </head> - <body> + <body class="bg-light"> <!--header section start --> <div class="header_section"> <div class="container-fluid"> @@ -51,6 +52,9 @@ <a class="nav-link" href="gallery.html">Gallery</a> </li> <% if (loggedIn) { %> + <li class="nav-item"> + <a class="nav-link" href="/addProduct">create</a> + </li> <li class="nav-item"> <a class="nav-link text-danger" href="/logout">Logout</a> </li> @@ -72,388 +76,35 @@ </div> </div> <!--header section end --> - <!-- banner section start --> - <div class="banner_section layout_padding"> - <div class="container"> - <div id="main_slider" class="carousel slide" data-ride="carousel"> - <div class="carousel-inner"> - <div class="carousel-item active"> - <div class="row"> - <div class="col-sm-12"> - <div class="banner_taital"> - <h1 class="outstanding_text">Outstanding</h1> - <h1 class="coffee_text">Coffee Shop</h1> - <p class="there_text">There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, </p> - <div class="learnmore_bt"><a href="#">Learn More</a></div> - </div> - </div> - </div> - </div> - <div class="carousel-item"> - <div class="row"> - <div class="col-sm-12"> - <div class="banner_taital"> - <h1 class="outstanding_text">Outstanding </h1> - <h1 class="coffee_text">Coffee Shop</h1> - <p class="there_text">There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, </p> - <div class="learnmore_bt"><a href="#">Learn More</a></div> - </div> - </div> - </div> - </div> - <div class="carousel-item"> - <div class="row"> - <div class="col-sm-12"> - <div class="banner_taital"> - <h1 class="outstanding_text">Outstanding </h1> - <h1 class="coffee_text">Coffee Shop</h1> - <p class="there_text">There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, </p> - <div class="learnmore_bt"><a href="#">Learn More</a></div> - </div> - </div> - </div> - </div> - </div> - <a class="carousel-control-prev" href="#main_slider" role="button" data-slide="prev"> - <i class="fa fa-angle-left"></i> - </a> - <a class="carousel-control-next" href="#main_slider" role="button" data-slide="next"> - <i class="fa fa-angle-right"></i> - </a> - </div> - </div> - </div> - <!-- banner section end --> - <!-- about section start --> - <div class="about_section layout_padding"> - <div class="container"> - <div class="row"> - <div class="col-md-6"> - <div class="about_taital_main"> - <div class="about_taital">About Us</div> - <p class="about_text">Full cleaning and housekeeping services for companies and households.</p> - <p class="about_text">Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text.Lorem Ipsum is simply</p> - <div class="read_bt"><a href="#">Read More</a></div> - </div> - </div> - <div class="col-md-6"> - <div class="about_img"><img src="images/about-img.png"></div> - </div> - </div> - </div> - </div> - <!-- about section end --> <!-- gallery section start --> <div class="gallery_section layout_padding"> <div class="container"> <div class="row"> <div class="col-sm-12"> - <h1 class="gallery_taital">Our Gallery</h1> - <p class="gallery_text">Lorem Ipsum is simply dummy text of printing typesetting ststry lorem Ipsum the industry'ndard dummy text ever since of the 1500s, when an unknown printer took a galley of type and scra make a type specimen book. It has</p> + <h1 class="gallery_taital">bookstore</h1> </div> </div> <div class=""> <div class="gallery_section_2"> <div class="row"> - <div class="col-md-4"> - <div class="container_main"> - <img src="images/img-1.png" alt="Avatar" class="image"> - <div class="overlay"> - <div class="text"><a href="#"><i class="fa fa-search" aria-hidden="true"></i></a></div> - </div> - </div> - </div> - <div class="col-md-4"> - <div class="container_main"> - <img src="images/img-2.png" alt="Avatar" class="image"> - <div class="overlay"> - <div class="text"><a href="#"><i class="fa fa-search" aria-hidden="true"></i></a></div> - </div> - </div> - </div> - <div class="col-md-4"> - <div class="container_main"> - <img src="images/img-3.png" alt="Avatar" class="image"> - <div class="overlay"> - <div class="text"><a href="#"><i class="fa fa-search" aria-hidden="true"></i></a></div> - </div> - </div> - </div> - </div> - </div> - <div class="gallery_section_2"> - <div class="row"> - <div class="col-md-4"> - <div class="container_main"> - <img src="images/img-4.png" alt="Avatar" class="image"> - <div class="overlay"> - <div class="text"><a href="#"><i class="fa fa-search" aria-hidden="true"></i></a></div> - </div> - </div> - </div> - <div class="col-md-4"> - <div class="container_main"> - <img src="images/img-5.png" alt="Avatar" class="image"> - <div class="overlay"> - <div class="overlay"> - <div class="text"><a href="#"><i class="fa fa-search" aria-hidden="true"></i></a></div> - </div> - </div> - </div> - </div> - <div class="col-md-4"> - <div class="container_main"> - <img src="images/img-6.png" alt="Avatar" class="image"> - <div class="overlay"> - <div class="overlay"> - <div class="text"><a href="#"><i class="fa fa-search" aria-hidden="true"></i></a></div> - </div> - </div> - </div> - </div> - </div> - </div> - <div class="gallery_section_2"> - <div class="row"> - <div class="col-md-4"> - <div class="container_main"> - <img src="images/img-7.png" alt="Avatar" class="image"> - <div class="overlay"> - <div class="text"><a href="#"><i class="fa fa-search" aria-hidden="true"></i></a></div> - </div> - </div> - </div> - <div class="col-md-4"> - <div class="container_main"> - <img src="images/img-8.png" alt="Avatar" class="image"> - <div class="overlay"> - <div class="text"><a href="#"><i class="fa fa-search" aria-hidden="true"></i></a></div> + <% products.forEach(product => { %> + <div class="col-md-4"> + <div class="container_main"> + <a href="/product/<%= product.product_id %>"> <!-- ให้คลิกได้ที่รูปหรือกล่องทั้งใบ --> + <img src="<%= product.image %>" alt="Avatar" class="image"> + <div class="container"> + <h1><%= product.product_name %></h1> + </div> + </a> </div> </div> - </div> - <div class="col-md-4"> - <div class="container_main"> - <img src="images/img-9.png" alt="Avatar" class="image"> - <div class="overlay"> - <div class="text"><a href="#"><i class="fa fa-search" aria-hidden="true"></i></a></div> - </div> - </div> - </div> + <% }) %> </div> </div> </div> - <div class="seemore_bt"><a href="#">See More</a></div> </div> </div> <!-- gallery section end --> - <!-- services section start --> - <div class="services_section layout_padding"> - <div class="container"> - <div class="row"> - <div class="col-sm-12"> - <h1 class="services_taital">Services</h1> - <p class="services_text">Typesetting industry lorem Ipsum is simply dummy text of the </p> - </div> - </div> - <div class="services_section_2"> - <div class="row"> - <div class="col-lg-4 col-sm-12 col-md-4"> - <div class="box_main active"> - <div class="house_icon"> - <img src="images/icon1.png" class="image_1"> - <img src="images/icon1.png" class="image_2"> - </div> - <h3 class="decorate_text">Original Coffee</h3> - <p class="tation_text">Exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea </p> - <div class="readmore_bt"><a href="#">Read More</a></div> - </div> - </div> - <div class="col-lg-4 col-sm-12 col-md-4"> - <div class="box_main"> - <div class="house_icon"> - <img src="images/icon2.png" class="image_1"> - <img src="images/icon2.png" class="image_2"> - </div> - <h3 class="decorate_text">20 Coffee Flavors</h3> - <p class="tation_text">Exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea </p> - <div class="readmore_bt"><a href="#">Read More</a></div> - </div> - </div> - <div class="col-lg-4 col-sm-12 col-md-4"> - <div class="box_main"> - <div class="house_icon"> - <img src="images/icon3.png" class="image_1"> - <img src="images/icon3.png" class="image_2"> - </div> - <h3 class="decorate_text">Pleasant Abient</h3> - <p class="tation_text">Exerci tation ullamcorper suscipit lobortis nisl ut aliquip ex ea </p> - <div class="readmore_bt"><a href="#">Read More</a></div> - </div> - </div> - </div> - </div> - </div> - </div> - <!-- services section end --> - <!-- testimonial section start --> - <div class="client_section layout_padding"> - <div class="container"> - <div class="row"> - <div class="col-sm-12"> - <h1 class="client_taital">Testimonial</h1> - <p class="client_text">Eeven slightly believable. If you are going to use a passage of Lorem Ipsum, you need to</p> - </div> - </div> - </div> - <div id="carouselExampleIndicators" class="carousel slide" data-ride="carousel"> - <ol class="carousel-indicators"> - <li data-target="#carouselExampleIndicators" data-slide-to="0" class="active"></li> - <li data-target="#carouselExampleIndicators" data-slide-to="1"></li> - <li data-target="#carouselExampleIndicators" data-slide-to="2"></li> - </ol> - <div class="carousel-inner"> - <div class="carousel-item active"> - <div class="client_section_2"> - <div class="container"> - <div class="row"> - <div class="col-md-12"> - <div class="testimonial_section_2"> - <h4 class="client_name_text">Monila <span class="quick_icon"><img src="images/quick-icon.png"></span></h4> - <p class="customer_text">many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All themany variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some embarrassing hidden in the middle of text. All the</p> - </div> - </div> - </div> - </div> - </div> - </div> - <div class="carousel-item"> - <div class="client_section_2"> - <div class="container"> - <div class="row"> - <div class="col-md-12"> - <div class="testimonial_section_2"> - <h4 class="client_name_text">Monila <span class="quick_icon"><img src="images/quick-icon.png"></span></h4> - <p class="customer_text">many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All themany variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some embarrassing hidden in the middle of text. All the</p> - </div> - </div> - </div> - </div> - </div> - </div> - <div class="carousel-item"> - <div class="client_section_2"> - <div class="container"> - <div class="row"> - <div class="col-md-12"> - <div class="testimonial_section_2"> - <h4 class="client_name_text">Monila <span class="quick_icon"><img src="images/quick-icon.png"></span></h4> - <p class="customer_text">many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable. If you are going to use a passage of Lorem Ipsum, you need to be sure there isn't anything embarrassing hidden in the middle of text. All themany variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some embarrassing hidden in the middle of text. All the</p> - </div> - </div> - </div> - </div> - </div> - </div> - </div> - </div> - </div> - <!-- testimonial section end --> - <!-- contact section start --> - <div class="contact_section layout_padding"> - <div class="container"> - <h1 class="contact_text">Contact Us</h1> - </div> - </div> - <div class="contact_section_2 layout_padding"> - <div class="container-fluid"> - <div class="row"> - <div class="col-md-6 padding_0"> - <div class="mail_section"> - <div class="email_text"> - <div class="form-group"> - <input type="text" class="email-bt" placeholder="Name" name="Email"> - </div> - <div class="form-group"> - <input type="text" class="email-bt" placeholder="Email" name="Email"> - </div> - <div class="form-group"> - <input type="text" class="email-bt" placeholder="Phone Numbar" name="Email"> - </div> - <div class="form-group"> - <textarea class="massage-bt" placeholder="Massage" rows="5" id="comment" name="Massage"></textarea> - </div> - <div class="send_btn"> - <div type="text" class="main_bt"><a href="#">SEND</a></div> - </div> - </div> - </div> - </div> - <div class="col-md-6 padding_0"> - <div class="map-responsive"> - <iframe src="https://www.google.com/maps/embed/v1/place?key=AIzaSyA0s1a7phLN0iaD6-UE7m4qP-z21pH0eSc&q=Eiffel+Tower+Paris+France" width="600" height="508" frameborder="0" style="border:0; width: 100%;" allowfullscreen></iframe> - </div> - </div> - </div> - </div> - </div> - <!-- contact section end --> - <!-- footer section start --> - <div class="footer_section layout_padding"> - <div class="container"> - <div class="row"> - <div class="col-lg-3 col-sm-6"> - <h3 class="useful_text">About</h3> - <p class="footer_text">consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation u</p> - </div> - <div class="col-lg-3 col-sm-6"> - <h3 class="useful_text">Menu</h3> - <div class="footer_menu"> - <ul> - <li><a href="index.html">Home</a></li> - <li><a href="about.html">About Us</a></li> - <li><a href="gallery.html">Gallery</a></li> - <li><a href="services.html">Services</a></li> - <li><a href="contact.html">Contact Us</a></li> - </ul> - </div> - </div> - <div class="col-lg-3 col-sm-6"> - <h1 class="useful_text">Useful Link</h1> - <p class="dummy_text">Adipiscing Elit, sed do Eiusmod Tempor incididunt </p> - </div> - <div class="col-lg-3 col-sm-6"> - <h1 class="useful_text">Contact Us</h1> - <div class="location_text"> - <ul> - <li> - <a href="#"> - <i class="fa fa-map-marker" aria-hidden="true"></i><span class="padding_left_10">Address : Loram Ipusm</span> - </a> - </li> - <li> - <a href="#"> - <i class="fa fa-phone" aria-hidden="true"></i><span class="padding_left_10">Call : +01 1234567890</span> - </a> - </li> - <li> - <a href="#"> - <i class="fa fa-envelope" aria-hidden="true"></i><span class="padding_left_10">Email : demo@gmail.com</span> - </a> - </li> - </ul> - </div> - </div> - </div> - </div> - </div> - <!-- footer section end --> - <!-- copyright section start --> - <div class="copyright_section"> - <div class="container"> - <p class="copyright_text">2020 All Rights Reserved. Design by <a href="https://html.design">Free html Templates</a></p> - </div> - </div> - <!-- copyright section end --> <!-- Javascript files--> <script src="js/jquery.min.js"></script> <script src="js/popper.min.js"></script> diff --git a/views/product.ejs b/views/product.ejs new file mode 100644 index 0000000..80b8ca1 --- /dev/null +++ b/views/product.ejs @@ -0,0 +1,31 @@ +<!DOCTYPE html> +<html lang="en"> +<head> + <meta charset="UTF-8"> + <meta name="viewport" content="width=device-width, initial-scale=1.0"> + <title>รายละเอียดสินค้า</title> + <style> + img { + width: 300px; + border-radius: 10px; + margin-bottom: 20px; + } + </style> +</head> +<body> + <h1><%= product.product_name %></h1> +<img src="<%= product.image %>" alt="<%= product.product_name %>" width="300px"> +<p>ราคา: <strong><%= product.price %> บาท</strong></p> +<p>รายละเอียด: <%= product.description || "ไม่มีรายละเอียด" %></p> +<p>สร้างโดย: <%= product.owner %></p> + +<% if (currentUserEmail === product.owner) { %> + <form action="/delete_product/<%= product.product_id %>" method="POST" onsubmit="return confirm('ยืนยันการลบสินค้านี้?');"> + <button type="submit" style="color: red;">ลบสินค้า</button> + </form> +<% } %> + +<a href="/">กลับหน้าหลัก</a> + +</body> +</html> -- GitLab