forked from UKSOURCE/cms.hailearning.edu.vn
feat: enhance about us and footer CMS admin panels
- Improve aboutUs controller with better field handling - Update footer controller with expanded content management - Refine about admin view templates - Update appointment and footer admin views - Add about contract repair migration script - Update about.json seed data
This commit is contained in:
@@ -4,6 +4,77 @@ const writeAuditLog = require("../audit/writeAuditLog");
|
||||
const diffObject = require("../audit/diffObject");
|
||||
const AUDIT_ACTIONS = require("../constants/auditAction");
|
||||
|
||||
const isPlainObject = (value) =>
|
||||
value && typeof value === "object" && !Array.isArray(value);
|
||||
|
||||
const normalizeFooterImagePath = (value) => {
|
||||
if (!value || typeof value !== "string") return "";
|
||||
|
||||
const trimmed = value.trim();
|
||||
if (!trimmed) return "";
|
||||
|
||||
if (trimmed.startsWith("/uploads/footer/")) {
|
||||
return trimmed;
|
||||
}
|
||||
|
||||
if (trimmed.startsWith("uploads/footer/")) {
|
||||
return `/${trimmed}`;
|
||||
}
|
||||
|
||||
if (/^https?:\/\//i.test(trimmed)) {
|
||||
try {
|
||||
const parsed = new URL(trimmed);
|
||||
if (parsed.pathname.startsWith("/uploads/footer/")) {
|
||||
return parsed.pathname;
|
||||
}
|
||||
} catch (error) {
|
||||
console.warn("Failed to parse footer image URL:", trimmed, error.message);
|
||||
}
|
||||
}
|
||||
|
||||
return trimmed;
|
||||
};
|
||||
|
||||
const sanitizeFooterData = (data = {}) => {
|
||||
const sanitized = JSON.parse(JSON.stringify(data || {}));
|
||||
|
||||
if (!sanitized.top) {
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
if (typeof sanitized.top.bgImage === "string") {
|
||||
sanitized.top.bgImage = normalizeFooterImagePath(sanitized.top.bgImage);
|
||||
}
|
||||
|
||||
if (sanitized.top.logo && typeof sanitized.top.logo.src === "string") {
|
||||
sanitized.top.logo.src = normalizeFooterImagePath(sanitized.top.logo.src);
|
||||
}
|
||||
|
||||
return sanitized;
|
||||
};
|
||||
|
||||
const mergeFooterData = (currentValue, incomingValue) => {
|
||||
if (incomingValue === undefined) {
|
||||
return currentValue;
|
||||
}
|
||||
|
||||
if (Array.isArray(incomingValue)) {
|
||||
return incomingValue;
|
||||
}
|
||||
|
||||
if (isPlainObject(currentValue) && isPlainObject(incomingValue)) {
|
||||
const merged = { ...currentValue };
|
||||
|
||||
Object.keys(incomingValue).forEach((key) => {
|
||||
merged[key] = mergeFooterData(currentValue[key], incomingValue[key]);
|
||||
});
|
||||
|
||||
return merged;
|
||||
}
|
||||
|
||||
return incomingValue;
|
||||
};
|
||||
|
||||
// GET /api/footer - Public API cho website và CMS load dữ liệu
|
||||
exports.getFooter = async (req, res) => {
|
||||
try {
|
||||
@@ -42,6 +113,8 @@ exports.updateFooter = async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
updateData = sanitizeFooterData(updateData);
|
||||
|
||||
// Lấy footer hiện tại hoặc tạo mới (giống Header logic)
|
||||
let footer = await Footer.findOne();
|
||||
|
||||
@@ -52,8 +125,9 @@ exports.updateFooter = async (req, res) => {
|
||||
console.log("✓ Footer created:", footer._id);
|
||||
} else {
|
||||
console.log("✓ Found existing footer:", footer._id);
|
||||
// Merge với dữ liệu cũ thay vì overwrite (giống Header)
|
||||
Object.assign(footer, updateData);
|
||||
const mergedData = mergeFooterData(footer.toObject(), updateData);
|
||||
// Use set() so nested footer fields persist correctly in MongoDB
|
||||
footer.set(mergedData);
|
||||
await footer.save();
|
||||
console.log("✓ Footer updated successfully");
|
||||
}
|
||||
@@ -80,11 +154,10 @@ exports.updateFooter = async (req, res) => {
|
||||
exports.index = async (req, res) => {
|
||||
try {
|
||||
const data = await Footer.getSingle();
|
||||
const processedData = addBaseUrlToImages(data.toObject());
|
||||
|
||||
res.render("admin/footer/index", {
|
||||
title: "Footer Management",
|
||||
data: processedData,
|
||||
data: data.toObject(),
|
||||
});
|
||||
} catch (error) {
|
||||
console.error("Error in footer index:", error);
|
||||
@@ -114,6 +187,8 @@ exports.update = async (req, res) => {
|
||||
}
|
||||
}
|
||||
|
||||
updateData = sanitizeFooterData(updateData);
|
||||
|
||||
// Lấy footer hiện tại hoặc tạo mới (giống Header)
|
||||
let footer = await Footer.findOne();
|
||||
|
||||
@@ -130,8 +205,9 @@ exports.update = async (req, res) => {
|
||||
req.flash("success_msg", "Footer created successfully");
|
||||
} else {
|
||||
console.log("✓ Found existing footer:", footer._id);
|
||||
// Merge với dữ liệu cũ (giống Header)
|
||||
Object.assign(footer, updateData);
|
||||
const mergedData = mergeFooterData(footer.toObject(), updateData);
|
||||
// Use set() so nested footer fields persist correctly in MongoDB
|
||||
footer.set(mergedData);
|
||||
await footer.save();
|
||||
|
||||
// ✅ Capture AFTER state
|
||||
@@ -166,4 +242,14 @@ exports.update = async (req, res) => {
|
||||
|
||||
// Legacy API endpoints (giữ lại cho tương thích)
|
||||
exports.api = exports.getFooter;
|
||||
exports.getFooterData = exports.getFooter;
|
||||
exports.getFooterData = async (req, res) => {
|
||||
try {
|
||||
const footer = await Footer.getSingle();
|
||||
res.json(footer.toObject());
|
||||
} catch (error) {
|
||||
console.error("Error getting footer data for admin:", error);
|
||||
res.status(500).json({
|
||||
error: "Failed to get footer data",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user