updateweb
This commit is contained in:
@@ -95,4 +95,515 @@ router.get("/pages", requireAuth, async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Get single product
|
||||
router.get("/products/:id", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await query("SELECT * FROM products WHERE id = $1", [
|
||||
req.params.id,
|
||||
]);
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Product not found" });
|
||||
}
|
||||
res.json({
|
||||
success: true,
|
||||
product: result.rows[0],
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Product error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Create product
|
||||
router.post("/products", requireAuth, async (req, res) => {
|
||||
try {
|
||||
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,
|
||||
]
|
||||
);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
product: result.rows[0],
|
||||
message: "Product created successfully",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Create product error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Update product
|
||||
router.put("/products/:id", requireAuth, async (req, res) => {
|
||||
try {
|
||||
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 res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Product not found" });
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
product: result.rows[0],
|
||||
message: "Product updated successfully",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Update product error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Delete product
|
||||
router.delete("/products/:id", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"DELETE FROM products WHERE id = $1 RETURNING id",
|
||||
[req.params.id]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Product not found" });
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: "Product deleted successfully",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Delete product error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Portfolio Project CRUD
|
||||
router.get("/portfolio/projects/:id", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"SELECT * FROM portfolioprojects WHERE id = $1",
|
||||
[req.params.id]
|
||||
);
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Project not found" });
|
||||
}
|
||||
res.json({ success: true, project: result.rows[0] });
|
||||
} catch (error) {
|
||||
console.error("Portfolio project error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/portfolio/projects", requireAuth, async (req, res) => {
|
||||
try {
|
||||
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]
|
||||
);
|
||||
res.json({
|
||||
success: true,
|
||||
project: result.rows[0],
|
||||
message: "Project created successfully",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Create portfolio project error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.put("/portfolio/projects/:id", requireAuth, async (req, res) => {
|
||||
try {
|
||||
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 res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Project not found" });
|
||||
}
|
||||
res.json({
|
||||
success: true,
|
||||
project: result.rows[0],
|
||||
message: "Project updated successfully",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Update portfolio project error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.delete("/portfolio/projects/:id", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"DELETE FROM portfolioprojects WHERE id = $1 RETURNING id",
|
||||
[req.params.id]
|
||||
);
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Project not found" });
|
||||
}
|
||||
res.json({ success: true, message: "Project deleted successfully" });
|
||||
} catch (error) {
|
||||
console.error("Delete portfolio project error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Blog Post CRUD
|
||||
router.get("/blog/:id", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await query("SELECT * FROM blogposts WHERE id = $1", [
|
||||
req.params.id,
|
||||
]);
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Blog post not found" });
|
||||
}
|
||||
res.json({ success: true, post: result.rows[0] });
|
||||
} catch (error) {
|
||||
console.error("Blog post error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/blog", requireAuth, async (req, res) => {
|
||||
try {
|
||||
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,
|
||||
]
|
||||
);
|
||||
res.json({
|
||||
success: true,
|
||||
post: result.rows[0],
|
||||
message: "Blog post created successfully",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Create blog post error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.put("/blog/:id", requireAuth, async (req, res) => {
|
||||
try {
|
||||
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 res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Blog post not found" });
|
||||
}
|
||||
res.json({
|
||||
success: true,
|
||||
post: result.rows[0],
|
||||
message: "Blog post updated successfully",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Update blog post error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.delete("/blog/:id", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"DELETE FROM blogposts WHERE id = $1 RETURNING id",
|
||||
[req.params.id]
|
||||
);
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Blog post not found" });
|
||||
}
|
||||
res.json({ success: true, message: "Blog post deleted successfully" });
|
||||
} catch (error) {
|
||||
console.error("Delete blog post error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Custom Pages CRUD
|
||||
router.get("/pages/:id", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await query("SELECT * FROM pages WHERE id = $1", [
|
||||
req.params.id,
|
||||
]);
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Page not found" });
|
||||
}
|
||||
res.json({ success: true, page: result.rows[0] });
|
||||
} catch (error) {
|
||||
console.error("Page error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/pages", requireAuth, async (req, res) => {
|
||||
try {
|
||||
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]
|
||||
);
|
||||
res.json({
|
||||
success: true,
|
||||
page: result.rows[0],
|
||||
message: "Page created successfully",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Create page error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.put("/pages/:id", requireAuth, async (req, res) => {
|
||||
try {
|
||||
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 res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Page not found" });
|
||||
}
|
||||
res.json({
|
||||
success: true,
|
||||
page: result.rows[0],
|
||||
message: "Page updated successfully",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Update page error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
router.delete("/pages/:id", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await query("DELETE FROM pages WHERE id = $1 RETURNING id", [
|
||||
req.params.id,
|
||||
]);
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Page not found" });
|
||||
}
|
||||
res.json({ success: true, message: "Page deleted successfully" });
|
||||
} catch (error) {
|
||||
console.error("Delete page error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Homepage Settings
|
||||
router.get("/homepage/settings", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"SELECT settings FROM site_settings WHERE key = 'homepage'"
|
||||
);
|
||||
const settings = result.rows.length > 0 ? result.rows[0].settings : {};
|
||||
res.json({ success: true, settings });
|
||||
} catch (error) {
|
||||
console.error("Homepage settings error:", error);
|
||||
res.json({ success: true, settings: {} });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/homepage/settings", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const settings = req.body;
|
||||
await query(
|
||||
`INSERT INTO site_settings (key, settings, updatedat)
|
||||
VALUES ('homepage', $1, NOW())
|
||||
ON CONFLICT (key) DO UPDATE SET settings = $1, updatedat = NOW()`,
|
||||
[JSON.stringify(settings)]
|
||||
);
|
||||
res.json({
|
||||
success: true,
|
||||
message: "Homepage settings saved successfully",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Save homepage settings error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// General Settings
|
||||
router.get("/settings", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"SELECT settings FROM site_settings WHERE key = 'general'"
|
||||
);
|
||||
const settings = result.rows.length > 0 ? result.rows[0].settings : {};
|
||||
res.json({ success: true, settings });
|
||||
} catch (error) {
|
||||
console.error("Settings error:", error);
|
||||
res.json({ success: true, settings: {} });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/settings", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const settings = req.body;
|
||||
await query(
|
||||
`INSERT INTO site_settings (key, settings, updatedat)
|
||||
VALUES ('general', $1, NOW())
|
||||
ON CONFLICT (key) DO UPDATE SET settings = $1, updatedat = NOW()`,
|
||||
[JSON.stringify(settings)]
|
||||
);
|
||||
res.json({ success: true, message: "Settings saved successfully" });
|
||||
} catch (error) {
|
||||
console.error("Save settings error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Menu Management
|
||||
router.get("/menu", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"SELECT settings FROM site_settings WHERE key = 'menu'"
|
||||
);
|
||||
const items =
|
||||
result.rows.length > 0 ? result.rows[0].settings.items || [] : [];
|
||||
res.json({ success: true, items });
|
||||
} catch (error) {
|
||||
console.error("Menu error:", error);
|
||||
res.json({ success: true, items: [] });
|
||||
}
|
||||
});
|
||||
|
||||
router.post("/menu", requireAuth, async (req, res) => {
|
||||
try {
|
||||
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 })]
|
||||
);
|
||||
res.json({ success: true, message: "Menu saved successfully" });
|
||||
} catch (error) {
|
||||
console.error("Save menu error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
@@ -92,7 +92,7 @@ router.get("/homepage/sections", async (req, res) => {
|
||||
router.get("/portfolio/projects", async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"SELECT id, title, description, imageurl, categoryid, createdat FROM portfolioprojects ORDER BY createdat DESC"
|
||||
"SELECT id, title, description, featuredimage, images, category, categoryid, isactive, createdat FROM portfolioprojects WHERE isactive = true ORDER BY displayorder ASC, createdat DESC"
|
||||
);
|
||||
res.json({
|
||||
success: true,
|
||||
@@ -120,4 +120,101 @@ router.get("/blog/posts", async (req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// Get single blog post by slug
|
||||
router.get("/blog/posts/:slug", async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"SELECT * FROM blogposts WHERE slug = $1 AND ispublished = true",
|
||||
[req.params.slug]
|
||||
);
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Blog post not found" });
|
||||
}
|
||||
res.json({
|
||||
success: true,
|
||||
post: result.rows[0],
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Blog post detail error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Get custom pages
|
||||
router.get("/pages", async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"SELECT id, title, slug, content, metatitle, metadescription, isactive, createdat FROM pages WHERE isactive = true ORDER BY createdat DESC"
|
||||
);
|
||||
res.json({
|
||||
success: true,
|
||||
pages: result.rows,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Pages error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Get single page by slug
|
||||
router.get("/pages/:slug", async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"SELECT * FROM pages WHERE slug = $1 AND isactive = true",
|
||||
[req.params.slug]
|
||||
);
|
||||
if (result.rows.length === 0) {
|
||||
return res
|
||||
.status(404)
|
||||
.json({ success: false, message: "Page not found" });
|
||||
}
|
||||
res.json({
|
||||
success: true,
|
||||
page: result.rows[0],
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Page detail error:", error);
|
||||
res.status(500).json({ success: false, message: "Server error" });
|
||||
}
|
||||
});
|
||||
|
||||
// Get menu items for frontend navigation
|
||||
router.get("/menu", async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"SELECT settings FROM site_settings WHERE key = 'menu'"
|
||||
);
|
||||
const items =
|
||||
result.rows.length > 0 ? result.rows[0].settings.items || [] : [];
|
||||
// Filter only visible items
|
||||
const visibleItems = items.filter((item) => item.visible !== false);
|
||||
res.json({
|
||||
success: true,
|
||||
items: visibleItems,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Menu error:", error);
|
||||
res.json({ success: true, items: [] });
|
||||
}
|
||||
});
|
||||
|
||||
// Get homepage settings for frontend
|
||||
router.get("/homepage/settings", async (req, res) => {
|
||||
try {
|
||||
const result = await query(
|
||||
"SELECT settings FROM site_settings WHERE key = 'homepage'"
|
||||
);
|
||||
const settings = result.rows.length > 0 ? result.rows[0].settings : {};
|
||||
res.json({
|
||||
success: true,
|
||||
settings,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Homepage settings error:", error);
|
||||
res.json({ success: true, settings: {} });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
|
||||
207
backend/routes/upload.js
Normal file
207
backend/routes/upload.js
Normal file
@@ -0,0 +1,207 @@
|
||||
const express = require("express");
|
||||
const router = express.Router();
|
||||
const multer = require("multer");
|
||||
const path = require("path");
|
||||
const fs = require("fs").promises;
|
||||
const { requireAuth } = require("../middleware/auth");
|
||||
const { pool } = require("../config/database");
|
||||
|
||||
// Configure multer for file uploads
|
||||
const storage = multer.diskStorage({
|
||||
destination: async function (req, file, cb) {
|
||||
const uploadDir = path.join(__dirname, "..", "..", "website", "uploads");
|
||||
try {
|
||||
await fs.mkdir(uploadDir, { recursive: true });
|
||||
cb(null, uploadDir);
|
||||
} catch (error) {
|
||||
cb(error);
|
||||
}
|
||||
},
|
||||
filename: function (req, file, cb) {
|
||||
// Generate unique filename
|
||||
const uniqueSuffix = Date.now() + "-" + Math.round(Math.random() * 1e9);
|
||||
const ext = path.extname(file.originalname);
|
||||
const name = path
|
||||
.basename(file.originalname, ext)
|
||||
.replace(/[^a-z0-9]/gi, "-")
|
||||
.toLowerCase();
|
||||
cb(null, name + "-" + uniqueSuffix + ext);
|
||||
},
|
||||
});
|
||||
|
||||
const upload = multer({
|
||||
storage: storage,
|
||||
limits: {
|
||||
fileSize: 5 * 1024 * 1024, // 5MB limit
|
||||
},
|
||||
fileFilter: function (req, file, cb) {
|
||||
// Accept images only
|
||||
if (!file.mimetype.startsWith("image/")) {
|
||||
return cb(new Error("Only image files are allowed!"), false);
|
||||
}
|
||||
cb(null, true);
|
||||
},
|
||||
});
|
||||
|
||||
// Upload multiple files
|
||||
router.post(
|
||||
"/upload",
|
||||
requireAuth,
|
||||
upload.array("files", 10),
|
||||
async (req, res) => {
|
||||
try {
|
||||
const uploadedBy = req.session.user?.id || null;
|
||||
const files = [];
|
||||
|
||||
// Insert each file into database
|
||||
for (const file of req.files) {
|
||||
const result = await pool.query(
|
||||
`INSERT INTO uploads
|
||||
(filename, original_name, file_path, file_size, mime_type, uploaded_by, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, NOW(), NOW())
|
||||
RETURNING id, filename, original_name, file_path, file_size, mime_type, created_at`,
|
||||
[
|
||||
file.filename,
|
||||
file.originalname,
|
||||
`/uploads/${file.filename}`,
|
||||
file.size,
|
||||
file.mimetype,
|
||||
uploadedBy,
|
||||
]
|
||||
);
|
||||
|
||||
files.push({
|
||||
id: result.rows[0].id,
|
||||
filename: result.rows[0].filename,
|
||||
originalName: result.rows[0].original_name,
|
||||
size: result.rows[0].file_size,
|
||||
mimetype: result.rows[0].mime_type,
|
||||
path: result.rows[0].file_path,
|
||||
uploadDate: result.rows[0].created_at,
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: `${files.length} file(s) uploaded successfully`,
|
||||
files: files,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Upload error:", error);
|
||||
|
||||
// If database insert fails, clean up uploaded files
|
||||
if (req.files) {
|
||||
for (const file of req.files) {
|
||||
try {
|
||||
await fs.unlink(file.path);
|
||||
} catch (unlinkError) {
|
||||
console.error("Error cleaning up file:", unlinkError);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
// Get all uploaded files
|
||||
router.get("/uploads", requireAuth, async (req, res) => {
|
||||
try {
|
||||
// Query files from database
|
||||
const result = await pool.query(
|
||||
`SELECT
|
||||
id,
|
||||
filename,
|
||||
original_name,
|
||||
file_path,
|
||||
file_size,
|
||||
mime_type,
|
||||
uploaded_by,
|
||||
created_at,
|
||||
updated_at,
|
||||
used_in_type,
|
||||
used_in_id
|
||||
FROM uploads
|
||||
ORDER BY created_at DESC`
|
||||
);
|
||||
|
||||
const files = result.rows.map((row) => ({
|
||||
id: row.id,
|
||||
filename: row.filename,
|
||||
originalName: row.original_name,
|
||||
size: row.file_size,
|
||||
mimetype: row.mime_type,
|
||||
path: row.file_path,
|
||||
uploadDate: row.created_at,
|
||||
uploadedBy: row.uploaded_by,
|
||||
usedInType: row.used_in_type,
|
||||
usedInId: row.used_in_id,
|
||||
}));
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
files: files,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error listing files:", error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Delete a file
|
||||
router.delete("/uploads/:filename", requireAuth, async (req, res) => {
|
||||
try {
|
||||
const filename = req.params.filename;
|
||||
const uploadDir = path.join(__dirname, "..", "..", "website", "uploads");
|
||||
const filePath = path.join(uploadDir, filename);
|
||||
|
||||
// Security check: ensure file is within uploads directory
|
||||
if (!filePath.startsWith(uploadDir)) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
error: "Invalid file path",
|
||||
});
|
||||
}
|
||||
|
||||
// Start transaction: delete from database first
|
||||
const result = await pool.query(
|
||||
"DELETE FROM uploads WHERE filename = $1 RETURNING id",
|
||||
[filename]
|
||||
);
|
||||
|
||||
if (result.rowCount === 0) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: "File not found in database",
|
||||
});
|
||||
}
|
||||
|
||||
// Then delete physical file
|
||||
try {
|
||||
await fs.unlink(filePath);
|
||||
} catch (fileError) {
|
||||
console.warn("File already deleted from disk:", filename);
|
||||
// Continue anyway since database record is deleted
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: "File deleted successfully",
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error deleting file:", error);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: error.message,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
@@ -13,12 +13,9 @@ router.get("/", async (req, res) => {
|
||||
try {
|
||||
const result = await query(`
|
||||
SELECT
|
||||
u.id, u.username, u.email, u.role_id, u.isactive,
|
||||
u.last_login, u.createdat, u.password_never_expires,
|
||||
u.password_expires_at, u.last_password_change,
|
||||
r.name as role_name, r.description as role_description
|
||||
u.id, u.username, u.email, u.name, u.role, u.isactive,
|
||||
u.last_login, u.createdat, u.passwordneverexpires
|
||||
FROM adminusers u
|
||||
LEFT JOIN roles r ON u.role_id = r.id
|
||||
ORDER BY u.createdat DESC
|
||||
`);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user