├── .gitignore ├── .env-example ├── middlewares └── error-handler.js ├── routes ├── uploads.js ├── order.js ├── size.js ├── color.js └── product.js ├── package.json ├── app.js ├── db └── connect.js ├── controllers ├── order.js ├── color.js ├── size.js └── product.js └── projet_bdd.sql /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .env 3 | /uploads -------------------------------------------------------------------------------- /.env-example: -------------------------------------------------------------------------------- 1 | PORT=3000 2 | DB_HOST=localhost 3 | DB_USER=root 4 | DB_PASS=ahmed123 5 | DB_NAME=store_db -------------------------------------------------------------------------------- /middlewares/error-handler.js: -------------------------------------------------------------------------------- 1 | const errorHandler = (err, req, res, next) => { 2 | if (err) { 3 | console.log(err); 4 | return res.status(500).json({message: err.message}); 5 | } 6 | } 7 | 8 | module.exports = errorHandler; -------------------------------------------------------------------------------- /routes/uploads.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | 4 | router.get("/:filename", (req, res) => { 5 | const {filename} = req.params; 6 | res.sendFile(`${process.cwd()}/uploads/${filename}`); 7 | }); 8 | 9 | module.exports = router; -------------------------------------------------------------------------------- /routes/order.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const {createOrder, getOrders, deleteOrder} = require('../controllers/order'); 4 | 5 | router.post('/', createOrder); 6 | router.get('/', getOrders); 7 | router.delete('/:id', deleteOrder); 8 | 9 | module.exports = router; -------------------------------------------------------------------------------- /routes/size.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const {createSize, getSizes, updateSize, deleteSize, getAllSizes, getProductSizes} = require('../controllers/size'); 4 | 5 | router.post("/", createSize) 6 | router.get("/", getSizes) 7 | router.get("/product/:productId", getProductSizes) 8 | router.get("/all", getAllSizes) 9 | router.patch("/:id", updateSize) 10 | router.delete("/:id", deleteSize) 11 | 12 | module.exports = router; -------------------------------------------------------------------------------- /routes/color.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const {createColor, getColors, updateColor, deleteColor, getAllColors, getProductColors} = require('../controllers/color'); 4 | 5 | router.post("/", createColor) 6 | router.get("/", getColors) 7 | router.get("/product/:productId", getProductColors) 8 | router.get("/all", getAllColors) 9 | router.patch("/:id", updateColor) 10 | router.delete("/:id", deleteColor) 11 | 12 | module.exports = router; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "projet-bdd", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "app.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1", 8 | "start": "nodemon app.js" 9 | }, 10 | "keywords": [], 11 | "author": "", 12 | "license": "ISC", 13 | "dependencies": { 14 | "cors": "^2.8.5", 15 | "dotenv": "^16.3.1", 16 | "express": "^4.18.2", 17 | "express-async-errors": "^3.1.1", 18 | "multer": "^1.4.5-lts.1", 19 | "mysql": "^2.18.1" 20 | }, 21 | "devDependencies": { 22 | "nodemon": "^3.0.2" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /routes/product.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | const router = express.Router(); 3 | const multer = require('multer'); 4 | const {createProduct, getProducts, getAvailableProducts, updateProduct, deleteProduct, getGeneralInfo} = require('../controllers/product'); 5 | 6 | const storage = multer.diskStorage({ 7 | destination: function (req, file, cb) { 8 | cb(null, 'uploads') 9 | }, 10 | filename: function (req, file, cb) { 11 | const fileExt = file.mimetype.split('/')[1]; 12 | const newFileName = Date.now() + '.' + fileExt; 13 | cb(null, newFileName) 14 | } 15 | }) 16 | 17 | const upload = multer({ storage: storage }) 18 | 19 | router.post("/", upload.single('image'), createProduct) 20 | router.get("/", getProducts) 21 | router.get("/available", getAvailableProducts) 22 | router.get("/overview", getGeneralInfo) 23 | router.patch("/:id", upload.single('image'), updateProduct) 24 | router.delete("/:id", deleteProduct) 25 | 26 | module.exports = router; -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | require('dotenv').config(); 3 | require('express-async-errors'); 4 | const app = express(); 5 | const {connectDB, createTable} = require('./db/connect'); 6 | const cors = require('cors'); 7 | const sizeRouter = require('./routes/size'); 8 | const colorRouter = require('./routes/color'); 9 | const productRouter = require('./routes/product'); 10 | const uploadsRouter = require('./routes/uploads'); 11 | const ordersRouter = require('./routes/order'); 12 | const errorHandler = require('./middlewares/error-handler'); 13 | 14 | app.use(cors()); 15 | app.use(express.json()); 16 | app.use('/api/v1/sizes', sizeRouter); 17 | app.use('/api/v1/colors', colorRouter); 18 | app.use('/api/v1/products', productRouter); 19 | app.use('/api/v1/orders', ordersRouter); 20 | app.use('/uploads', uploadsRouter); 21 | app.use(errorHandler); 22 | 23 | 24 | const start = async () => { 25 | const PORT = process.env.PORT || 3000; 26 | await connectDB(); 27 | await createTable(); 28 | app.listen(PORT, () => { 29 | console.log(`Server is listening on port ${PORT}...`); 30 | }); 31 | } 32 | 33 | start(); -------------------------------------------------------------------------------- /db/connect.js: -------------------------------------------------------------------------------- 1 | const mysql = require('mysql'); 2 | 3 | const db = mysql.createConnection({ 4 | host: process.env.DB_HOST, 5 | user: process.env.DB_USER, 6 | password: process.env.DB_PASS, 7 | database: process.env.DB_NAME 8 | }) 9 | 10 | const connectDB = () => { 11 | db.connect((err) => { 12 | if (err) { 13 | throw err; 14 | } 15 | console.log('MySQL connected...'); 16 | }); 17 | } 18 | 19 | const createTable = () => { 20 | const sqlArr = [ 21 | `CREATE TABLE IF NOT EXISTS colors (id int AUTO_INCREMENT, name VARCHAR(255), value VARCHAR(255), createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id))`, 22 | `CREATE TABLE IF NOT EXISTS sizes (id int AUTO_INCREMENT, name VARCHAR(255), value VARCHAR(255), createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id))`, 23 | `CREATE TABLE IF NOT EXISTS products (id int AUTO_INCREMENT, name VARCHAR(255), price INT, imgUrl VARCHAR(255), createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, quantity INT, PRIMARY KEY (id))`, 24 | `CREATE TABLE IF NOT EXISTS product_sizes (productId INT, sizeId INT, FOREIGN KEY (productId) REFERENCES products(id) ON DELETE CASCADE, FOREIGN KEY (sizeId) REFERENCES sizes(id) ON DELETE CASCADE, PRIMARY KEY (productId, sizeId))`, 25 | `CREATE TABLE IF NOT EXISTS product_colors (productId INT, colorId INT, FOREIGN KEY (productId) REFERENCES products(id)ON DELETE CASCADE, FOREIGN KEY (colorId) REFERENCES colors(id) ON DELETE CASCADE, PRIMARY KEY (productId, colorId))`, 26 | `CREATE TABLE IF NOT EXISTS orders (id int AUTO_INCREMENT, phone VARCHAR(255), address VARCHAR(255), productId INT, sizeId INT, colorId INT, createdAt TIMESTAMP DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), Foreign Key (productId) REFERENCES products(id) ON DELETE CASCADE, Foreign Key (sizeId) REFERENCES sizes(id) ON DELETE CASCADE, Foreign Key (colorId) REFERENCES colors(id) ON DELETE CASCADE)`, 27 | ]; 28 | for (let i = 0; i < sqlArr.length; i++) { 29 | db.query(sqlArr[i], (err, result) => { 30 | if (err) { 31 | throw err; 32 | } 33 | console.log('Table created...'); 34 | }); 35 | } 36 | } 37 | 38 | module.exports = {connectDB, createTable, db}; -------------------------------------------------------------------------------- /controllers/order.js: -------------------------------------------------------------------------------- 1 | const {db} = require('../db/connect'); 2 | 3 | const createOrder = async (req, res) => { 4 | const {phone, address, productId, sizeId, colorId} = req.body; 5 | const sql = `INSERT INTO orders (phone, address, productId, sizeId, colorId) VALUES (?, ?, ?, ?, ?)`; 6 | db.query(sql, [phone, address, productId, sizeId, colorId], (err, result) => { 7 | if (err) { 8 | throw err; 9 | } 10 | const sql = `UPDATE products SET quantity = quantity - 1 WHERE id = ?`; 11 | db.query(sql, [productId], (err, result) => { 12 | if (err) { 13 | throw err; 14 | } 15 | res.status(201).json({message: 'Order created successfully'}); 16 | }); 17 | }); 18 | } 19 | 20 | const getOrders = async (req, res) => { 21 | const {page, pageSize} = req.query; 22 | const sql = `SELECT * FROM orders LIMIT ? OFFSET ?`; 23 | db.query(sql, [parseInt(pageSize), (parseInt(page) - 1) * parseInt(pageSize)], (err, result) => { 24 | if (err) { 25 | throw err; 26 | } 27 | const sql = `SELECT COUNT(*) AS count FROM orders`; 28 | db.query(sql, async (err, count) => { 29 | if (err) { 30 | throw err; 31 | } 32 | const productInfo = await Promise.all(result.map(order => { 33 | const sql = `SELECT products.name, products.price, products.imgUrl, sizes.name AS size, colors.name AS color FROM products INNER JOIN product_sizes ON products.id = product_sizes.productId INNER JOIN sizes ON product_sizes.sizeId = sizes.id INNER JOIN product_colors ON products.id = product_colors.productId INNER JOIN colors ON product_colors.colorId = colors.id WHERE products.id = ? AND sizes.id = ? AND colors.id = ?`; 34 | return new Promise((resolve, reject) => { 35 | db.query(sql, [order.productId, order.sizeId, order.colorId], (err, result) => { 36 | if (err) { 37 | reject(err); 38 | } 39 | resolve({...result[0], ...order}); 40 | }); 41 | } 42 | ); 43 | })); 44 | res.status(200).json({orders: productInfo, count: count[0].count}); 45 | }); 46 | }); 47 | } 48 | 49 | const deleteOrder = async (req, res) => { 50 | const {id} = req.params; 51 | const orderExistsSql = `SELECT * FROM orders WHERE id = ?`; 52 | db.query(orderExistsSql, [id], (err, result) => { 53 | if (err) { 54 | throw err; 55 | } 56 | if (!result.length) { 57 | return res.status(404).json({message: 'Order not found'}); 58 | } else { 59 | const sql = `DELETE FROM orders WHERE id = ?`; 60 | db.query(sql, [id], (err, result) => { 61 | if (err) { 62 | throw err; 63 | } 64 | res.status(200).json({message: 'Order deleted successfully'}); 65 | }); 66 | } 67 | }); 68 | } 69 | 70 | module.exports = {createOrder, getOrders, deleteOrder}; -------------------------------------------------------------------------------- /controllers/color.js: -------------------------------------------------------------------------------- 1 | const {db} = require('../db/connect'); 2 | 3 | const createColor = async (req, res) => { 4 | const {name, value} = req.body; 5 | const sql = `INSERT INTO colors (name, value) VALUES (?, ?)`; 6 | db.query(sql, [name, value], (err, result) => { 7 | if (err) { 8 | throw err; 9 | } 10 | res.status(201).json({message: 'Color created successfully'}); 11 | }); 12 | } 13 | 14 | const getColors = async (req, res) => { 15 | const {page, pageSize} = req.query; 16 | const sql = `SELECT * FROM colors LIMIT ? OFFSET ?`; 17 | db.query(sql, [+pageSize, (page - 1) * pageSize], (err, result) => { 18 | if (err) { 19 | throw err; 20 | } 21 | const sql = `SELECT COUNT(*) AS count FROM colors`; 22 | db.query(sql, (err, count) => { 23 | if (err) { 24 | throw err; 25 | } 26 | res.status(200).json({colors: result, count: count[0].count}); 27 | }); 28 | }); 29 | } 30 | 31 | const getProductColors = async (req, res) => { 32 | const {productId} = req.params; 33 | const sql = `SELECT colors.id, colors.name, colors.value FROM colors INNER JOIN product_colors ON colors.id = product_colors.colorId WHERE product_colors.productId = ?`; 34 | db.query(sql, [productId], (err, result) => { 35 | if (err) { 36 | throw err; 37 | } 38 | res.status(200).json(result); 39 | }); 40 | } 41 | 42 | const getAllColors = async (req, res) => { 43 | const sql = `SELECT * FROM colors`; 44 | db.query(sql, (err, result) => { 45 | if (err) { 46 | throw err; 47 | } 48 | res.status(200).json(result); 49 | }); 50 | } 51 | 52 | const updateColor = async (req, res) => { 53 | const {id} = req.params; 54 | const {name, value} = req.body; 55 | // check if exists 56 | let sql = 'SELECT * FROM colors WHERE id = ?'; 57 | db.query(sql, [id], (err, result) => { 58 | if (err) { 59 | throw err; 60 | } 61 | if (!result.length) { 62 | return res.status(404).json({message: 'Color not found'}); 63 | } else { 64 | sql = `UPDATE colors SET name = ?, value = ? WHERE id = ?`; 65 | db.query(sql, [name, value, id], (err, result) => { 66 | if (err) { 67 | throw err; 68 | } 69 | res.status(200).json({message: 'Color updated successfully'}); 70 | }); 71 | } 72 | }); 73 | 74 | } 75 | 76 | const deleteColor = async (req, res) => { 77 | const {id} = req.params; 78 | // check if exists 79 | let sql = 'SELECT * FROM colors WHERE id = ?'; 80 | const result = db.query(sql, [id], (err, result) => { 81 | if (err) { 82 | throw err; 83 | } 84 | if (!result.length) { 85 | return res.status(404).json({message: 'Color not found'}); 86 | } else { 87 | sql = `DELETE FROM colors WHERE id = ?`; 88 | db.query(sql, [id], (err, result) => { 89 | if (err) { 90 | throw err; 91 | } 92 | res.status(200).json({message: 'Color deleted successfully'}); 93 | }); 94 | } 95 | }); 96 | } 97 | 98 | module.exports = {createColor, getColors, updateColor, deleteColor, getAllColors, getProductColors} -------------------------------------------------------------------------------- /controllers/size.js: -------------------------------------------------------------------------------- 1 | 2 | const e = require('express'); 3 | const {db} = require('../db/connect'); 4 | 5 | const createSize = async (req, res) => { 6 | const {name, value} = req.body; 7 | const sql = `INSERT INTO sizes (name, value) VALUES (?, ?)`; 8 | db.query(sql, [name, value], (err, result) => { 9 | if (err) { 10 | throw err; 11 | } 12 | res.status(201).json({message: 'Size created successfully'}); 13 | }); 14 | } 15 | 16 | const getSizes = async (req, res) => { 17 | const {page, pageSize} = req.query; 18 | const sql = `SELECT * FROM sizes LIMIT ? OFFSET ?`; 19 | db.query(sql, [+pageSize, (page - 1) * pageSize], (err, result) => { 20 | if (err) { 21 | throw err; 22 | } 23 | const sql = `SELECT COUNT(*) AS count FROM sizes`; 24 | db.query(sql, (err, count) => { 25 | if (err) { 26 | throw err; 27 | } 28 | res.status(200).json({sizes: result, count: count[0].count}); 29 | }); 30 | }); 31 | } 32 | 33 | const getAllSizes = async (req, res) => { 34 | const sql = `SELECT * FROM sizes`; 35 | db.query(sql, (err, result) => { 36 | if (err) { 37 | throw err; 38 | } 39 | res.status(200).json(result); 40 | }); 41 | } 42 | 43 | const getProductSizes = async (req, res) => { 44 | const {productId} = req.params; 45 | const sql = `SELECT sizes.id, sizes.name, sizes.value FROM sizes INNER JOIN product_sizes ON sizes.id = product_sizes.sizeId WHERE product_sizes.productId = ?`; 46 | db.query(sql, [productId], (err, result) => { 47 | if (err) { 48 | throw err; 49 | } 50 | res.status(200).json(result); 51 | }); 52 | 53 | } 54 | 55 | const updateSize = async (req, res) => { 56 | const {id} = req.params; 57 | const {name, value} = req.body; 58 | // check if exists 59 | let sql = 'SELECT * FROM sizes WHERE id = ?'; 60 | db.query(sql, [id], (err, result) => { 61 | if (err) { 62 | throw err; 63 | } 64 | if (!result.length) { 65 | return res.status(404).json({message: 'Size not found'}); 66 | } else { 67 | sql = `UPDATE sizes SET name = ?, value = ? WHERE id = ?`; 68 | db.query(sql, [name, value, id], (err, result) => { 69 | if (err) { 70 | throw err; 71 | } 72 | res.status(200).json({message: 'Size updated successfully'}); 73 | }); 74 | } 75 | }); 76 | 77 | } 78 | 79 | const deleteSize = async (req, res) => { 80 | const {id} = req.params; 81 | // check if exists 82 | let sql = 'SELECT * FROM sizes WHERE id = ?'; 83 | const result = db.query(sql, [id], (err, result) => { 84 | if (err) { 85 | throw err; 86 | } 87 | if (!result.length) { 88 | return res.status(404).json({message: 'Size not found'}); 89 | } else { 90 | sql = `DELETE FROM sizes WHERE id = ?`; 91 | db.query(sql, [id], (err, result) => { 92 | if (err) { 93 | throw err; 94 | } 95 | res.status(200).json({message: 'Size deleted successfully'}); 96 | }); 97 | } 98 | }); 99 | } 100 | 101 | module.exports = {createSize, getSizes, updateSize, deleteSize, getAllSizes, getProductSizes}; -------------------------------------------------------------------------------- /projet_bdd.sql: -------------------------------------------------------------------------------- 1 | CREATE DATABASE IF NOT EXISTS `store_db` /*!40100 DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci */ /*!80016 DEFAULT ENCRYPTION='N' */; 2 | USE `store_db`; 3 | -- MySQL dump 10.13 Distrib 8.0.34, for Win64 (x86_64) 4 | -- 5 | -- Host: localhost Database: store_db 6 | -- ------------------------------------------------------ 7 | -- Server version 8.0.35 8 | 9 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 10 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 11 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 12 | /*!50503 SET NAMES utf8 */; 13 | /*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; 14 | /*!40103 SET TIME_ZONE='+00:00' */; 15 | /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; 16 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 17 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 18 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 19 | 20 | -- 21 | -- Table structure for table `colors` 22 | -- 23 | 24 | DROP TABLE IF EXISTS `colors`; 25 | /*!40101 SET @saved_cs_client = @@character_set_client */; 26 | /*!50503 SET character_set_client = utf8mb4 */; 27 | CREATE TABLE `colors` ( 28 | `id` int NOT NULL AUTO_INCREMENT, 29 | `name` varchar(255) DEFAULT NULL, 30 | `value` varchar(255) DEFAULT NULL, 31 | `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP, 32 | PRIMARY KEY (`id`) 33 | ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 34 | /*!40101 SET character_set_client = @saved_cs_client */; 35 | 36 | -- 37 | -- Dumping data for table `colors` 38 | -- 39 | 40 | LOCK TABLES `colors` WRITE; 41 | /*!40000 ALTER TABLE `colors` DISABLE KEYS */; 42 | INSERT INTO `colors` VALUES (1,'Red','#E74C3C','2024-01-28 21:17:48'),(2,'Green','#2ECC71','2024-01-28 21:18:09'),(3,'Black','#000000','2024-01-28 21:18:33'),(4,'Orange','#F1C40F','2024-01-28 21:18:59'),(5,'Gray','#85929E','2024-01-28 21:19:16'); 43 | /*!40000 ALTER TABLE `colors` ENABLE KEYS */; 44 | UNLOCK TABLES; 45 | 46 | -- 47 | -- Table structure for table `orders` 48 | -- 49 | 50 | DROP TABLE IF EXISTS `orders`; 51 | /*!40101 SET @saved_cs_client = @@character_set_client */; 52 | /*!50503 SET character_set_client = utf8mb4 */; 53 | CREATE TABLE `orders` ( 54 | `id` int NOT NULL AUTO_INCREMENT, 55 | `phone` varchar(255) DEFAULT NULL, 56 | `address` varchar(255) DEFAULT NULL, 57 | `productId` int DEFAULT NULL, 58 | `sizeId` int DEFAULT NULL, 59 | `colorId` int DEFAULT NULL, 60 | `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP, 61 | PRIMARY KEY (`id`), 62 | KEY `productId` (`productId`), 63 | KEY `sizeId` (`sizeId`), 64 | KEY `colorId` (`colorId`), 65 | CONSTRAINT `orders_ibfk_1` FOREIGN KEY (`productId`) REFERENCES `products` (`id`) ON DELETE CASCADE, 66 | CONSTRAINT `orders_ibfk_2` FOREIGN KEY (`sizeId`) REFERENCES `sizes` (`id`) ON DELETE CASCADE, 67 | CONSTRAINT `orders_ibfk_3` FOREIGN KEY (`colorId`) REFERENCES `colors` (`id`) ON DELETE CASCADE 68 | ) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 69 | /*!40101 SET character_set_client = @saved_cs_client */; 70 | 71 | -- 72 | -- Dumping data for table `orders` 73 | -- 74 | 75 | LOCK TABLES `orders` WRITE; 76 | /*!40000 ALTER TABLE `orders` DISABLE KEYS */; 77 | INSERT INTO `orders` VALUES (1,'0541236987','RU Amizour 2, Bejaia',1,2,1,'2024-01-28 21:23:46'),(2,'0541236987','RU Amizour 2, Bejaia',1,2,1,'2024-01-28 21:23:50'),(3,'0541236987','RU Amizour 2, Bejaia',1,1,1,'2024-01-28 21:23:58'),(4,'0541236987','RU Amizour 2, Bejaia',1,1,1,'2024-01-28 21:24:00'),(5,'0541236987','RU Amizour 2, Bejaia',2,1,1,'2024-01-28 21:24:05'),(6,'0541236987','RU Amizour 2, Bejaia',2,1,1,'2024-01-28 21:24:06'); 78 | /*!40000 ALTER TABLE `orders` ENABLE KEYS */; 79 | UNLOCK TABLES; 80 | 81 | -- 82 | -- Table structure for table `product_colors` 83 | -- 84 | 85 | DROP TABLE IF EXISTS `product_colors`; 86 | /*!40101 SET @saved_cs_client = @@character_set_client */; 87 | /*!50503 SET character_set_client = utf8mb4 */; 88 | CREATE TABLE `product_colors` ( 89 | `productId` int NOT NULL, 90 | `colorId` int NOT NULL, 91 | PRIMARY KEY (`productId`,`colorId`), 92 | KEY `colorId` (`colorId`), 93 | CONSTRAINT `product_colors_ibfk_1` FOREIGN KEY (`productId`) REFERENCES `products` (`id`) ON DELETE CASCADE, 94 | CONSTRAINT `product_colors_ibfk_2` FOREIGN KEY (`colorId`) REFERENCES `colors` (`id`) ON DELETE CASCADE 95 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 96 | /*!40101 SET character_set_client = @saved_cs_client */; 97 | 98 | -- 99 | -- Dumping data for table `product_colors` 100 | -- 101 | 102 | LOCK TABLES `product_colors` WRITE; 103 | /*!40000 ALTER TABLE `product_colors` DISABLE KEYS */; 104 | INSERT INTO `product_colors` VALUES (1,1),(2,1),(3,1),(4,1),(5,1),(1,2),(2,2),(3,2),(4,2),(5,2); 105 | /*!40000 ALTER TABLE `product_colors` ENABLE KEYS */; 106 | UNLOCK TABLES; 107 | 108 | -- 109 | -- Table structure for table `product_sizes` 110 | -- 111 | 112 | DROP TABLE IF EXISTS `product_sizes`; 113 | /*!40101 SET @saved_cs_client = @@character_set_client */; 114 | /*!50503 SET character_set_client = utf8mb4 */; 115 | CREATE TABLE `product_sizes` ( 116 | `productId` int NOT NULL, 117 | `sizeId` int NOT NULL, 118 | PRIMARY KEY (`productId`,`sizeId`), 119 | KEY `sizeId` (`sizeId`), 120 | CONSTRAINT `product_sizes_ibfk_1` FOREIGN KEY (`productId`) REFERENCES `products` (`id`) ON DELETE CASCADE, 121 | CONSTRAINT `product_sizes_ibfk_2` FOREIGN KEY (`sizeId`) REFERENCES `sizes` (`id`) ON DELETE CASCADE 122 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 123 | /*!40101 SET character_set_client = @saved_cs_client */; 124 | 125 | -- 126 | -- Dumping data for table `product_sizes` 127 | -- 128 | 129 | LOCK TABLES `product_sizes` WRITE; 130 | /*!40000 ALTER TABLE `product_sizes` DISABLE KEYS */; 131 | INSERT INTO `product_sizes` VALUES (1,1),(2,1),(3,1),(4,1),(5,1),(1,2),(2,2),(3,2),(4,2),(5,2),(1,3),(2,3),(3,3),(4,3),(5,3); 132 | /*!40000 ALTER TABLE `product_sizes` ENABLE KEYS */; 133 | UNLOCK TABLES; 134 | 135 | -- 136 | -- Table structure for table `products` 137 | -- 138 | 139 | DROP TABLE IF EXISTS `products`; 140 | /*!40101 SET @saved_cs_client = @@character_set_client */; 141 | /*!50503 SET character_set_client = utf8mb4 */; 142 | CREATE TABLE `products` ( 143 | `id` int NOT NULL AUTO_INCREMENT, 144 | `name` varchar(255) DEFAULT NULL, 145 | `price` int DEFAULT NULL, 146 | `imgUrl` varchar(255) DEFAULT NULL, 147 | `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP, 148 | `quantity` int DEFAULT NULL, 149 | PRIMARY KEY (`id`) 150 | ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 151 | /*!40101 SET character_set_client = @saved_cs_client */; 152 | 153 | -- 154 | -- Dumping data for table `products` 155 | -- 156 | 157 | LOCK TABLES `products` WRITE; 158 | /*!40000 ALTER TABLE `products` DISABLE KEYS */; 159 | INSERT INTO `products` VALUES (1,'T-Shirt',300,'http://localhost:3000/uploads/1706476916631.png','2024-01-28 21:21:56',96),(2,'Pantalon',300,'http://localhost:3000/uploads/1706476929758.png','2024-01-28 21:22:09',98),(3,'Shoes',1000,'http://localhost:3000/uploads/1706476939897.png','2024-01-28 21:22:19',100),(4,'Ensemble',1500,'http://localhost:3000/uploads/1706476955418.png','2024-01-28 21:22:35',100),(5,'Hoodie',1000,'http://localhost:3000/uploads/1706476970213.png','2024-01-28 21:22:50',100); 160 | /*!40000 ALTER TABLE `products` ENABLE KEYS */; 161 | UNLOCK TABLES; 162 | 163 | -- 164 | -- Table structure for table `sizes` 165 | -- 166 | 167 | DROP TABLE IF EXISTS `sizes`; 168 | /*!40101 SET @saved_cs_client = @@character_set_client */; 169 | /*!50503 SET character_set_client = utf8mb4 */; 170 | CREATE TABLE `sizes` ( 171 | `id` int NOT NULL AUTO_INCREMENT, 172 | `name` varchar(255) DEFAULT NULL, 173 | `value` varchar(255) DEFAULT NULL, 174 | `createdAt` timestamp NULL DEFAULT CURRENT_TIMESTAMP, 175 | PRIMARY KEY (`id`) 176 | ) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci; 177 | /*!40101 SET character_set_client = @saved_cs_client */; 178 | 179 | -- 180 | -- Dumping data for table `sizes` 181 | -- 182 | 183 | LOCK TABLES `sizes` WRITE; 184 | /*!40000 ALTER TABLE `sizes` DISABLE KEYS */; 185 | INSERT INTO `sizes` VALUES (1,'Extra Large','XL','2024-01-28 21:19:54'),(2,'Extra Small','XS','2024-01-28 21:20:07'),(3,'Small','S','2024-01-28 21:20:14'),(4,'Medium','M','2024-01-28 21:20:25'),(5,'Large','L','2024-01-28 21:21:07'); 186 | /*!40000 ALTER TABLE `sizes` ENABLE KEYS */; 187 | UNLOCK TABLES; 188 | /*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; 189 | 190 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 191 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 192 | /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; 193 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 194 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 195 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 196 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 197 | 198 | -- Dump completed on 2024-01-28 22:26:18 199 | -------------------------------------------------------------------------------- /controllers/product.js: -------------------------------------------------------------------------------- 1 | const {db} = require("../db/connect"); 2 | 3 | const createProduct = async (req, res) => { 4 | const image = req.file.filename; 5 | const {name, price, quantity, sizeIds, colorIds} = req.body; 6 | if(!name || !price || !quantity || !sizeIds || !colorIds) { 7 | return res.status(400).json({message: 'All fields are required'}); 8 | } 9 | const imgUrl = `http://localhost:${process.env.PORT}/uploads/${image}`; 10 | const sizeIdsArr = JSON.parse(sizeIds); 11 | const colorIdsArr = JSON.parse(colorIds); 12 | // check if sizes exists 13 | const sizeSql = 'SELECT * FROM sizes WHERE id IN (?)'; 14 | db.query(sizeSql, [sizeIdsArr], (err, result) => { 15 | if (err) { 16 | throw err; 17 | } 18 | if (result.length !== sizeIdsArr.length) { 19 | res.status(404).json({message: 'Size not found'}); 20 | } else { 21 | const colorSql = 'SELECT * FROM colors WHERE id IN (?)'; 22 | db.query(colorSql, [colorIdsArr], (err, result) => { 23 | if (err) { 24 | throw err; 25 | } 26 | if (result.length !== colorIdsArr.length) { 27 | res.status(404).json({message: 'Color not found'}); 28 | } else { 29 | const sql = `INSERT INTO products (name, price, imgUrl, quantity) VALUES (?, ?, ?, ?)`; 30 | db.query(sql, [name, +price, imgUrl, +quantity], (err, result) => { 31 | if (err) { 32 | throw err; 33 | } 34 | const productId = result.insertId; 35 | const sizeSql = `INSERT INTO product_sizes (productId, sizeId) VALUES ?`; 36 | const sizeValues = sizeIdsArr.map(sizeId => [productId, sizeId]); 37 | db.query(sizeSql, [sizeValues], (err, result) => { 38 | if (err) { 39 | throw err; 40 | } 41 | const colorSql = `INSERT INTO product_colors (productId, colorId) VALUES ?`; 42 | const colorValues = colorIdsArr.map(colorId => [productId, colorId]); 43 | db.query(colorSql, [colorValues], (err, result) => { 44 | if (err) { 45 | throw err; 46 | } 47 | res.status(201).json({ 48 | message: "Product created successfully" 49 | }); 50 | }); 51 | }); 52 | }); 53 | } 54 | }); 55 | } 56 | }); 57 | } 58 | 59 | const getProducts = async (req, res) => { 60 | const {page, pageSize} = req.query 61 | const sql = `SELECT * FROM products LIMIT ? OFFSET ?`; 62 | db.query(sql, [+pageSize, (page - 1) * pageSize], (err, result) => { 63 | if (err) { 64 | throw err; 65 | } 66 | const sql = `SELECT COUNT(*) AS count FROM products`; 67 | db.query(sql, (err, count) => { 68 | if (err) { 69 | throw err; 70 | } 71 | res.status(200).json({products: result, count: count[0].count}); 72 | }); 73 | }); 74 | } 75 | 76 | const getGeneralInfo = async (req, res) => { 77 | // get orders count 78 | const ordersSql = `SELECT COUNT(*) AS ordersCount FROM orders`; 79 | db.query(ordersSql, (err, ordersCount) => { 80 | if (err) { 81 | throw err; 82 | } 83 | // get products count 84 | const productsSql = `SELECT COUNT(*) AS productsCount FROM products`; 85 | db.query(productsSql, (err, productsCount) => { 86 | if (err) { 87 | throw err; 88 | } 89 | res.status(200).json({ordersCount: ordersCount[0].ordersCount, productsCount: productsCount[0].productsCount}); 90 | }); 91 | }); 92 | } 93 | 94 | const updateProduct = async (req, res) => { 95 | const {id} = req.params; 96 | const {name, price, quantity, sizeIds, colorIds} = req.body; 97 | if(!name || !price || !quantity || !sizeIds || !colorIds) { 98 | return res.status(400).json({message: 'All fields are required'}); 99 | } 100 | const sizeIdsArr = JSON.parse(sizeIds); 101 | const colorIdsArr = JSON.parse(colorIds); 102 | // check if exists 103 | let sql = 'SELECT * FROM products WHERE id = ?'; 104 | db.query(sql, [id], (err, result) => { 105 | if (err) { 106 | throw err; 107 | } 108 | if (!result.length) { 109 | return res.status(404).json({message: 'Product not found'}); 110 | } else { 111 | const colorSql = 'SELECT * FROM colors WHERE id IN (?)'; 112 | db.query(colorSql, [colorIdsArr], (err, result) => { 113 | if (err) { 114 | throw err; 115 | } 116 | if (result.length !== colorIdsArr.length) { 117 | res.status(404).json({message: 'Color not found'}); 118 | } else { 119 | const sizeSql = 'SELECT * FROM sizes WHERE id IN (?)'; 120 | db.query(sizeSql, [sizeIdsArr], (err, result) => { 121 | if (err) { 122 | throw err; 123 | } 124 | if (result.length !== sizeIdsArr.length) { 125 | res.status(404).json({message: 'Size not found'}); 126 | } else { 127 | const sql = 'SELECT * FROM products WHERE id = ?'; 128 | db.query(sql, [id], (err, result) => { 129 | if (err) { 130 | throw err; 131 | } 132 | const image = req.file ? req.file.filename : result[0].imgUrl?.split('/')?.pop(); 133 | const imgUrl = `http://localhost:${process.env.PORT}/uploads/${image}`; 134 | const sql = `UPDATE products SET name = ?, price = ?, imgUrl = ?, quantity = ? WHERE id = ?`; 135 | db.query(sql, [name, +price, imgUrl, +quantity, id], (err, result) => { 136 | if (err) { 137 | throw err; 138 | } 139 | const sizeSql = `DELETE FROM product_sizes WHERE productId = ?`; 140 | db.query(sizeSql, [id], (err, result) => { 141 | if (err) { 142 | throw err; 143 | } 144 | const sizeSql = `INSERT INTO product_sizes (productId, sizeId) VALUES ?`; 145 | const sizeValues = sizeIdsArr.map(sizeId => [id, sizeId]); 146 | db.query(sizeSql, [sizeValues], (err, result) => { 147 | if (err) { 148 | throw err; 149 | } 150 | const colorSql = `DELETE FROM product_colors WHERE productId = ?`; 151 | db.query(colorSql, [id], (err, result) => { 152 | if (err) { 153 | throw err; 154 | } 155 | const colorSql = `INSERT INTO product_colors (productId, colorId) VALUES ?`; 156 | const colorValues = colorIdsArr.map(colorId => [id, colorId]); 157 | db.query(colorSql, [colorValues], (err, result) => { 158 | if (err) { 159 | throw err; 160 | } 161 | res.status(200).json({message: 'Product updated successfully'}); 162 | }); 163 | }); 164 | }); 165 | }); 166 | }); 167 | }); 168 | } 169 | }); 170 | } 171 | }); 172 | } 173 | }); 174 | } 175 | 176 | const deleteProduct = async (req, res) => { 177 | const {id} = req.params; 178 | // check if exists 179 | let sql = 'SELECT * FROM products WHERE id = ?'; 180 | const result = db.query(sql, [id], (err, result) => { 181 | if (err) { 182 | throw err; 183 | } 184 | if (!result.length) { 185 | return res.status(404).json({message: 'Product not found'}); 186 | } else { 187 | sql = `DELETE FROM products WHERE id = ?`; 188 | db.query(sql, [id], (err, result) => { 189 | if (err) { 190 | throw err; 191 | } 192 | res.status(200).json({message: 'Product deleted successfully'}); 193 | }); 194 | } 195 | }); 196 | } 197 | 198 | const getAvailableProducts = async (req, res) => { 199 | const sql = `SELECT * FROM products WHERE quantity > 0`; 200 | db.query(sql, (err, result) => { 201 | if (err) { 202 | throw err; 203 | } 204 | res.status(200).json(result); 205 | }); 206 | } 207 | 208 | module.exports = { 209 | createProduct, 210 | getProducts, 211 | updateProduct, 212 | deleteProduct, 213 | getAvailableProducts, 214 | getGeneralInfo 215 | } --------------------------------------------------------------------------------