updateweb

This commit is contained in:
Local Server
2025-12-14 01:54:40 -06:00
parent dce6460994
commit 61929a5daf
454 changed files with 12193 additions and 42002 deletions

View File

@@ -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;

View File

@@ -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
View 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;

View File

@@ -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
`);