const express = require("express"); const { query } = require("../config/database"); const { requireAuth } = require("../middleware/auth"); const logger = require("../config/logger"); const { asyncHandler } = require("../middleware/errorHandler"); const { sendSuccess, sendError, sendNotFound } = require("../utils/responseHelpers"); const { getById, deleteById, countRecords } = require("../utils/queryHelpers"); const { HTTP_STATUS } = require("../config/constants"); const router = express.Router(); // Dashboard stats API router.get("/dashboard/stats", requireAuth, asyncHandler(async (req, res) => { const [productsCount, projectsCount, blogCount, pagesCount] = await Promise.all([ countRecords("products"), countRecords("portfolioprojects"), countRecords("blogposts"), countRecords("pages"), ]); sendSuccess(res, { stats: { products: productsCount, projects: projectsCount, blog: blogCount, pages: pagesCount, }, user: { name: req.session.name, email: req.session.email, role: req.session.role, }, }); })); // Generic CRUD factory function const createCRUDRoutes = (config) => { const { table, resourceName, listFields = "*", requiresAuth = true } = config; const auth = requiresAuth ? requireAuth : (req, res, next) => next(); // List all router.get(`/${resourceName}`, auth, asyncHandler(async (req, res) => { const result = await query( `SELECT ${listFields} FROM ${table} ORDER BY createdat DESC` ); sendSuccess(res, { [resourceName]: result.rows }); })); // Get by ID router.get(`/${resourceName}/:id`, auth, asyncHandler(async (req, res) => { const item = await getById(table, req.params.id); if (!item) { return sendNotFound(res, resourceName); } const responseKey = resourceName.slice(0, -1); // Remove 's' for singular sendSuccess(res, { [responseKey]: item }); })); // Delete router.delete(`/${resourceName}/:id`, auth, asyncHandler(async (req, res) => { const deleted = await deleteById(table, req.params.id); if (!deleted) { return sendNotFound(res, resourceName); } sendSuccess(res, { message: `${resourceName} deleted successfully` }); })); }; // Products CRUD router.get("/products", requireAuth, asyncHandler(async (req, res) => { const result = await query( "SELECT id, name, price, stockquantity, isactive, createdat FROM products ORDER BY createdat DESC" ); sendSuccess(res, { products: result.rows }); })); router.get("/products/:id", requireAuth, asyncHandler(async (req, res) => { const product = await getById("products", req.params.id); if (!product) { return sendNotFound(res, "Product"); } sendSuccess(res, { product }); })); router.post("/products", requireAuth, asyncHandler(async (req, res) => { const { name, description, price, stockquantity, category, isactive, isbestseller } = req.body; const result = await query( `INSERT INTO products (name, description, price, stockquantity, category, isactive, isbestseller, createdat) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW()) RETURNING *`, [name, description, price, stockquantity || 0, category, isactive !== false, isbestseller || false] ); sendSuccess(res, { product: result.rows[0], message: "Product created successfully", }, HTTP_STATUS.CREATED); })); router.put("/products/:id", requireAuth, asyncHandler(async (req, res) => { const { name, description, price, stockquantity, category, isactive, isbestseller } = req.body; const result = await query( `UPDATE products SET name = $1, description = $2, price = $3, stockquantity = $4, category = $5, isactive = $6, isbestseller = $7, updatedat = NOW() WHERE id = $8 RETURNING *`, [name, description, price, stockquantity || 0, category, isactive !== false, isbestseller || false, req.params.id] ); if (result.rows.length === 0) { return sendNotFound(res, "Product"); } sendSuccess(res, { product: result.rows[0], message: "Product updated successfully", }); })); router.delete("/products/:id", requireAuth, asyncHandler(async (req, res) => { const deleted = await deleteById("products", req.params.id); if (!deleted) { return sendNotFound(res, "Product"); } sendSuccess(res, { message: "Product deleted successfully" }); })); // Portfolio Projects CRUD router.get("/portfolio/projects", requireAuth, asyncHandler(async (req, res) => { const result = await query( "SELECT id, title, description, imageurl, categoryid, createdat FROM portfolioprojects ORDER BY createdat DESC" ); sendSuccess(res, { projects: result.rows }); })); router.get("/portfolio/projects/:id", requireAuth, asyncHandler(async (req, res) => { const project = await getById("portfolioprojects", req.params.id); if (!project) { return sendNotFound(res, "Project"); } sendSuccess(res, { project }); })); router.post("/portfolio/projects", requireAuth, asyncHandler(async (req, res) => { const { title, description, category, isactive } = req.body; const result = await query( `INSERT INTO portfolioprojects (title, description, category, isactive, createdat) VALUES ($1, $2, $3, $4, NOW()) RETURNING *`, [title, description, category, isactive !== false] ); sendSuccess(res, { project: result.rows[0], message: "Project created successfully", }, HTTP_STATUS.CREATED); })); router.put("/portfolio/projects/:id", requireAuth, asyncHandler(async (req, res) => { const { title, description, category, isactive } = req.body; const result = await query( `UPDATE portfolioprojects SET title = $1, description = $2, category = $3, isactive = $4, updatedat = NOW() WHERE id = $5 RETURNING *`, [title, description, category, isactive !== false, req.params.id] ); if (result.rows.length === 0) { return sendNotFound(res, "Project"); } sendSuccess(res, { project: result.rows[0], message: "Project updated successfully", }); })); router.delete("/portfolio/projects/:id", requireAuth, asyncHandler(async (req, res) => { const deleted = await deleteById("portfolioprojects", req.params.id); if (!deleted) { return sendNotFound(res, "Project"); } sendSuccess(res, { message: "Project deleted successfully" }); })); // Blog Posts CRUD router.get("/blog", requireAuth, asyncHandler(async (req, res) => { const result = await query( "SELECT id, title, slug, excerpt, ispublished, createdat FROM blogposts ORDER BY createdat DESC" ); sendSuccess(res, { posts: result.rows }); })); router.get("/blog/:id", requireAuth, asyncHandler(async (req, res) => { const post = await getById("blogposts", req.params.id); if (!post) { return sendNotFound(res, "Blog post"); } sendSuccess(res, { post }); })); router.post("/blog", requireAuth, asyncHandler(async (req, res) => { const { title, slug, excerpt, content, metatitle, metadescription, ispublished } = req.body; const result = await query( `INSERT INTO blogposts (title, slug, excerpt, content, metatitle, metadescription, ispublished, createdat) VALUES ($1, $2, $3, $4, $5, $6, $7, NOW()) RETURNING *`, [title, slug, excerpt, content, metatitle, metadescription, ispublished || false] ); sendSuccess(res, { post: result.rows[0], message: "Blog post created successfully", }, HTTP_STATUS.CREATED); })); router.put("/blog/:id", requireAuth, asyncHandler(async (req, res) => { const { title, slug, excerpt, content, metatitle, metadescription, ispublished } = req.body; const result = await query( `UPDATE blogposts SET title = $1, slug = $2, excerpt = $3, content = $4, metatitle = $5, metadescription = $6, ispublished = $7, updatedat = NOW() WHERE id = $8 RETURNING *`, [title, slug, excerpt, content, metatitle, metadescription, ispublished || false, req.params.id] ); if (result.rows.length === 0) { return sendNotFound(res, "Blog post"); } sendSuccess(res, { post: result.rows[0], message: "Blog post updated successfully", }); })); router.delete("/blog/:id", requireAuth, asyncHandler(async (req, res) => { const deleted = await deleteById("blogposts", req.params.id); if (!deleted) { return sendNotFound(res, "Blog post"); } sendSuccess(res, { message: "Blog post deleted successfully" }); })); // Custom Pages CRUD router.get("/pages", requireAuth, asyncHandler(async (req, res) => { const result = await query( "SELECT id, title, slug, ispublished, createdat FROM pages ORDER BY createdat DESC" ); sendSuccess(res, { pages: result.rows }); })); router.get("/pages/:id", requireAuth, asyncHandler(async (req, res) => { const page = await getById("pages", req.params.id); if (!page) { return sendNotFound(res, "Page"); } sendSuccess(res, { page }); })); router.post("/pages", requireAuth, asyncHandler(async (req, res) => { const { title, slug, content, metatitle, metadescription, ispublished } = req.body; const result = await query( `INSERT INTO pages (title, slug, content, metatitle, metadescription, ispublished, createdat) VALUES ($1, $2, $3, $4, $5, $6, NOW()) RETURNING *`, [title, slug, content, metatitle, metadescription, ispublished !== false] ); sendSuccess(res, { page: result.rows[0], message: "Page created successfully", }, HTTP_STATUS.CREATED); })); router.put("/pages/:id", requireAuth, asyncHandler(async (req, res) => { const { title, slug, content, metatitle, metadescription, ispublished } = req.body; const result = await query( `UPDATE pages SET title = $1, slug = $2, content = $3, metatitle = $4, metadescription = $5, ispublished = $6, updatedat = NOW() WHERE id = $7 RETURNING *`, [title, slug, content, metatitle, metadescription, ispublished !== false, req.params.id] ); if (result.rows.length === 0) { return sendNotFound(res, "Page"); } sendSuccess(res, { page: result.rows[0], message: "Page updated successfully", }); })); router.delete("/pages/:id", requireAuth, asyncHandler(async (req, res) => { const deleted = await deleteById("pages", req.params.id); if (!deleted) { return sendNotFound(res, "Page"); } sendSuccess(res, { message: "Page deleted successfully" }); })); // Settings Management const settingsHandler = (key) => ({ get: asyncHandler(async (req, res) => { const result = await query( "SELECT settings FROM site_settings WHERE key = $1", [key] ); const settings = result.rows.length > 0 ? result.rows[0].settings : {}; sendSuccess(res, { settings }); }), post: asyncHandler(async (req, res) => { const settings = req.body; await query( `INSERT INTO site_settings (key, settings, updatedat) VALUES ($1, $2, NOW()) ON CONFLICT (key) DO UPDATE SET settings = $2, updatedat = NOW()`, [key, JSON.stringify(settings)] ); sendSuccess(res, { message: `${key} settings saved successfully` }); }), }); // Homepage Settings const homepageSettings = settingsHandler("homepage"); router.get("/homepage/settings", requireAuth, homepageSettings.get); router.post("/homepage/settings", requireAuth, homepageSettings.post); // General Settings const generalSettings = settingsHandler("general"); router.get("/settings", requireAuth, generalSettings.get); router.post("/settings", requireAuth, generalSettings.post); // Menu Management router.get("/menu", requireAuth, asyncHandler(async (req, res) => { const result = await query( "SELECT settings FROM site_settings WHERE key = 'menu'" ); const items = result.rows.length > 0 ? result.rows[0].settings.items || [] : []; sendSuccess(res, { items }); })); router.post("/menu", requireAuth, asyncHandler(async (req, res) => { const { items } = req.body; await query( `INSERT INTO site_settings (key, settings, updatedat) VALUES ('menu', $1, NOW()) ON CONFLICT (key) DO UPDATE SET settings = $1, updatedat = NOW()`, [JSON.stringify({ items })] ); sendSuccess(res, { message: "Menu saved successfully" }); })); module.exports = router;