From b3c3be5590131fcee75aa46100f0c08c0e1d8d76 Mon Sep 17 00:00:00 2001 From: Theis Gaedigk Date: Tue, 26 May 2026 13:57:37 +0200 Subject: [PATCH] Add product and storage management routes and database functions --- .../routes/app/database/products.database.js | 57 ++++++++++++++++- .../routes/app/database/storage.database.js | 37 +++++++++++ backend/routes/app/database/users.database.js | 10 +-- backend/routes/app/products.route.js | 64 +++++++++++++++++++ backend/routes/app/storage.route.js | 54 ++++++++++++++++ backend/routes/app/users.route.js | 14 ++-- backend/server.js | 3 + frontend/vite.config.ts | 12 ++-- 8 files changed, 233 insertions(+), 18 deletions(-) create mode 100644 backend/routes/app/database/storage.database.js create mode 100644 backend/routes/app/storage.route.js diff --git a/backend/routes/app/database/products.database.js b/backend/routes/app/database/products.database.js index df4ea4d..6e40686 100644 --- a/backend/routes/app/database/products.database.js +++ b/backend/routes/app/database/products.database.js @@ -9,4 +9,59 @@ const pool = mysql password: process.env.DB_PASSWORD, database: process.env.DB_NAME, }) - .promise(); \ No newline at end of file + .promise(); + +export const newProduct = async ( + name, + description, + price, + amount, + storage_location, + expiry_date, + bottling_date, +) => { + const [result] = await pool.query( + "INSERT INTO products (name, description, price, amount, storage_location, expiry_date, bottling_date) VALUES (?, ?, ?, ?, UUID_TO_BIN(?), ?, ?)", + [ + name, + description, + price, + amount, + storage_location, + expiry_date, + bottling_date, + ], + ); + + if (result.affectedRows > 0) { + return { code: "sp001" }; // success + } else { + return { code: "ep001" }; // error + } +}; + +export const allProducts = async () => { + const [result] = await pool.query(` + SELECT + BIN_TO_UUID(p.uuid) AS uuid, + p.name, + p.description, + p.price, + p.amount, + BIN_TO_UUID(s.uuid) AS storage_location_uuid, + s.name AS storage_location_name, + p.expiry_date, + p.bottling_date, + p.picture, + p.created_at, + p.updated_at + FROM products p + JOIN storage_locations s ON p.storage_location = s.uuid + `); + + if (result.length > 0) { + return { code: "sp002", data: result }; + } else { + return { code: "ep002" }; + } +}; diff --git a/backend/routes/app/database/storage.database.js b/backend/routes/app/database/storage.database.js new file mode 100644 index 0000000..40362c0 --- /dev/null +++ b/backend/routes/app/database/storage.database.js @@ -0,0 +1,37 @@ +import mysql from "mysql2"; +import dotenv from "dotenv"; +dotenv.config(); + +const pool = mysql + .createPool({ + host: process.env.DB_HOST, + user: process.env.DB_USER, + password: process.env.DB_PASSWORD, + database: process.env.DB_NAME, + }) + .promise(); + +export const allStorages = async () => { + const [result] = await pool.query( + "SELECT BIN_TO_UUID(uuid) AS uuid, name, description, created_at, updated_at FROM storage_locations;", + ); + + if (result.length > 0) { + return { code: "ss001", data: result }; + } else { + return { code: "es001" }; + } +}; + +export const newStorage = async (name, description) => { + const [result] = await pool.query( + "INSERT INTO storage_locations (name, description) VALUES (?, ?)", + [name, description], + ); + + if (result.affectedRows > 0) { + return { code: "ss002" }; + } else { + return { code: "es002" }; + } +}; diff --git a/backend/routes/app/database/users.database.js b/backend/routes/app/database/users.database.js index b7b0ca8..ddc1668 100644 --- a/backend/routes/app/database/users.database.js +++ b/backend/routes/app/database/users.database.js @@ -18,14 +18,14 @@ export const findUser = async (username, password) => { ); if (result.length <= 0) { - return { code: "e001" }; // username or password is wrong + return { code: "eu001" }; // username or password is wrong } if (!result[0].is_active) { - return { code: "e002" }; // user is deactivated + return { code: "eu002" }; // user is deactivated } - return { code: "s001", data: result[0] }; // user found + return { code: "su001", data: result[0] }; // user found }; export const loginUser = async (username) => { @@ -35,8 +35,8 @@ export const loginUser = async (username) => { ); if (result.affectedRows > 0) { - return { code: "s002" }; + return { code: "su002" }; } else { - return { code: "e003" }; + return { code: "eu003" }; } }; diff --git a/backend/routes/app/products.route.js b/backend/routes/app/products.route.js index d24a755..3e5c695 100644 --- a/backend/routes/app/products.route.js +++ b/backend/routes/app/products.route.js @@ -1,6 +1,70 @@ import express from "express"; import dotenv from "dotenv"; +import { authenticate } from "../../services/tokenService.js"; +import { allProducts, newProduct } from "./database/products.database.js"; dotenv.config(); const router = express.Router(); +router.post("/new-product", authenticate, async (req, res) => { + const { + name, + description, + price, + amount, + storage_location, + expiry_date, + bottling_date, + } = req.body; + + const result = await newProduct( + name, + description, + price, + amount, + storage_location, + expiry_date, + bottling_date, + ); + + if (result.code === "ep001") { + res.status(406).json({ + success: false, + code: "ep001", + data: null, + message: "Error while creating product", + }); + } + + if (result.code === "sp001") { + res.status(201).json({ + success: true, + code: "sp001", + data: null, + message: "", + }); + } +}); + +router.get("/all-products", authenticate, async (req, res) => { + const result = await allProducts(); + + if (result.code === "ep002") { + res.status(406).json({ + success: false, + code: "ep002", + data: null, + message: "Error while fetching products", + }); + } + + if (result.code === "sp002") { + res.status(200).json({ + success: true, + code: "sp002", + data: result.data, + message: "", + }); + } +}); + export default router; diff --git a/backend/routes/app/storage.route.js b/backend/routes/app/storage.route.js new file mode 100644 index 0000000..a0af03c --- /dev/null +++ b/backend/routes/app/storage.route.js @@ -0,0 +1,54 @@ +import express from "express"; +import dotenv from "dotenv"; +import { authenticate } from "../../services/tokenService.js"; +import { allStorages, newStorage } from "./database/storage.database.js"; +dotenv.config(); +const router = express.Router(); + +router.get("/all-storages", authenticate, async (req, res) => { + const result = await allStorages(); + + if (result.code === "es001") { + res.status(500).json({ + success: false, + code: "es001", + data: null, + message: "unexpected server error", + }); + } + + if (result.code === "ss001") { + res.status(200).json({ + success: true, + code: "ss001", + data: result.data, + message: "", + }); + } +}); + +router.post("/new-storage", authenticate, async (req, res) => { + const { name, description } = req.body; + + const result = await newStorage(name, description); + + if (result.code === "es002") { + res.status(500).json({ + success: false, + code: "es002", + data: null, + message: "unexpected server error", + }); + } + + if (result.code === "ss002") { + res.status(201).json({ + success: true, + code: "ss002", + data: null, + message: "", + }); + } +}); + +export default router; diff --git a/backend/routes/app/users.route.js b/backend/routes/app/users.route.js index 5a9473d..b0968d1 100644 --- a/backend/routes/app/users.route.js +++ b/backend/routes/app/users.route.js @@ -11,32 +11,32 @@ router.post("/login", async (req, res) => { const result = await findUser(username, password); - if (result.code === "e001") { + if (result.code === "eu001") { res.status(404).json({ success: false, - code: "e001", + code: "eu001", data: null, message: "username oder password is wrong", }); } - if (result.code === "e002") { + if (result.code === "eu002") { res.status(403).json({ success: false, - code: "e002", + code: "eu002", data: null, message: "user is deactivated", }); } - if (result.code === "s001") { + if (result.code === "su001") { const token = await generateToken(result.data); const login = await loginUser(result.data.username); if (login.code === "e003") { res.status(500).json({ success: false, - code: "e003", + code: "eu003", data: null, message: "Unexpected server error. Please contact system admin.", }); @@ -44,7 +44,7 @@ router.post("/login", async (req, res) => { res.status(202).json({ success: true, - code: "s001", + code: "su001", data: { token, }, diff --git a/backend/server.js b/backend/server.js index 616a80a..44d4ec8 100644 --- a/backend/server.js +++ b/backend/server.js @@ -18,6 +18,9 @@ app.use("/users", userRouter); import productRouter from "./routes/app/products.route.js"; app.use("/products", productRouter); +import storageRouter from "./routes/app/storage.route.js"; +app.use("/storage", storageRouter); + app.listen(PORT, () => { console.log(`Server is running on http://localhost:${PORT}`); }); diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index d1203cd..111db15 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,11 +1,13 @@ -import { defineConfig } from 'vite' -import react, { reactCompilerPreset } from '@vitejs/plugin-react' -import babel from '@rolldown/plugin-babel' +import { defineConfig } from "vite"; +import react, { reactCompilerPreset } from "@vitejs/plugin-react"; +import babel from "@rolldown/plugin-babel"; +import tailwindcss from "@tailwindcss/vite"; // https://vite.dev/config/ export default defineConfig({ plugins: [ react(), - babel({ presets: [reactCompilerPreset()] }) + tailwindcss(), + babel({ presets: [reactCompilerPreset()] }), ], -}) +});