Files

172 lines
4.8 KiB
JavaScript

const { addBaseUrlToImages } = require("../utils/imageHelper");
const { normalizeIconClass } = require("../utils/iconOptions");
const RequestInfo = require("../models/requestInfo");
const writeAuditLog = require("../audit/writeAuditLog");
const diffObject = require("../audit/diffObject");
const AUDIT_ACTIONS = require("../constants/auditAction");
const SLUG = "request-info";
function emptyPageShape() {
return {
metadata: { title: "", description: "", keywords: "", ogImage: "" },
hero: {
badge: "",
titleMain: "",
titleHighlight: "",
description: "",
valueProps: [],
},
form: {
heading: "",
description: "",
fields: {
firstName: { name: "", label: "", placeholder: "", required: true },
lastName: { name: "", label: "", placeholder: "", required: true },
email: { name: "", label: "", placeholder: "", required: true },
phone: { name: "", label: "", placeholder: "", required: false },
program: { name: "", label: "", placeholder: "", required: true, options: [] },
timeline: { name: "", label: "", options: [] },
},
consentText: "",
submitLabel: "",
footerText: "",
successMessage: "",
errorMessage: "",
},
};
}
function parseJsonField(raw) {
if (raw == null || raw === "") return null;
if (typeof raw === "object") return raw;
try {
return JSON.parse(raw);
} catch {
return null;
}
}
/** Chuẩn hoá icon theo whitelist (valueProps). */
function sanitizeIcons(payload) {
if (!payload) return payload;
if (payload.hero?.valueProps?.length) {
payload.hero.valueProps = payload.hero.valueProps.map((vp) => ({
...vp,
icon: normalizeIconClass(vp.icon),
}));
}
return payload;
}
async function getDocument() {
return RequestInfo.findOne({ slug: SLUG }).lean();
}
/**
* GET /api/request-info — public payload cho frontend LAMS.
* Response: { metadata, hero, form } với ảnh đã gắn full URL.
*/
exports.api = async (req, res) => {
try {
const doc = await getDocument();
if (!doc) {
return res.status(404).json({ error: "Request Info content not found" });
}
const baseUrl =
process.env.BACKEND_URL ?? `${req.protocol}://${req.get("host")}`;
const body = {
metadata: doc.metadata || {},
hero: doc.hero || {},
form: doc.form || {},
};
res.json(addBaseUrlToImages(body, baseUrl));
} catch (err) {
console.error("requestInfo.api:", err);
res.status(500).json({ error: "Error loading Request Info data" });
}
};
/**
* GET /admin/request-info — Admin view.
*/
exports.index = async (req, res) => {
try {
const doc = await getDocument();
const data = doc
? {
metadata: doc.metadata || {},
hero: doc.hero || {},
form: doc.form || {},
}
: emptyPageShape();
const { ICON_OPTIONS } = require("../utils/iconOptions");
const frontendUrl = process.env.FRONTEND_URL || "";
res.render("admin/request-info/index", {
title: "Request Info",
layout: "layouts/main",
data,
iconOptions: ICON_OPTIONS,
frontendUrl,
currentPath: req.path,
user: req.session.user,
});
} catch (error) {
console.error("requestInfo.index:", error);
req.flash("error_msg", "Could not load Request Info page");
res.redirect("/admin/dashboard");
}
};
/**
* POST /admin/request-info/update — Lưu dữ liệu, tạo audit log.
*/
exports.update = async (req, res) => {
try {
const metadata = parseJsonField(req.body.metadata);
const hero = parseJsonField(req.body.hero);
const form = parseJsonField(req.body.form);
if (!metadata || !hero || !form) {
req.flash("error_msg", "Invalid form payload. Please try again.");
return res.redirect("/admin/request-info");
}
const payload = sanitizeIcons({ metadata, hero, form });
let doc = await RequestInfo.findOne({ slug: SLUG });
const beforeData = doc ? JSON.parse(JSON.stringify(doc.toObject())) : {};
if (!doc) {
doc = new RequestInfo({ slug: SLUG, ...payload });
} else {
doc.set(payload);
}
await doc.save();
const afterData = JSON.parse(JSON.stringify(doc.toObject()));
const changes = diffObject(beforeData, afterData);
if (changes.length > 0) {
await writeAuditLog({
model: "RequestInfo",
documentId: doc._id,
action: AUDIT_ACTIONS.UPDATE_REQUEST_INFO,
before: beforeData,
after: afterData,
changes,
req,
});
}
req.flash("success_msg", "Request Info updated successfully");
res.redirect("/admin/request-info");
} catch (err) {
console.error("requestInfo.update:", err);
req.flash("error_msg", err.message || "Error updating Request Info");
res.redirect("/admin/request-info");
}
};