forked from UKSOURCE/cms.hailearning.edu.vn
feat: implement comprehensive audit logging system
This commit is contained in:
@@ -1,377 +1,450 @@
|
||||
const AppointmentSubmission = require("../models/appointmentSubmission");
|
||||
const Appointment = require("../models/appointment");
|
||||
const writeAuditLog = require("../audit/writeAuditLog");
|
||||
const diffObject = require("../audit/diffObject");
|
||||
const AUDIT_ACTIONS = require("../constants/auditAction");
|
||||
|
||||
// ==================== CMS ADMIN FUNCTIONS ====================
|
||||
|
||||
// Render admin page for appointment management
|
||||
exports.index = async (req, res) => {
|
||||
try {
|
||||
let appointment = await Appointment.findOne({ name: "default" });
|
||||
try {
|
||||
let appointment = await Appointment.findOne({ name: "default" });
|
||||
|
||||
// If no data in DB, try to load from JSON file
|
||||
if (!appointment) {
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const jsonPath = path.join(__dirname, "../data/appointment.json");
|
||||
// If no data in DB, try to load from JSON file
|
||||
if (!appointment) {
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const jsonPath = path.join(__dirname, "../data/appointment.json");
|
||||
|
||||
if (fs.existsSync(jsonPath)) {
|
||||
const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8"));
|
||||
appointment = await Appointment.migrateFromJson(jsonData);
|
||||
} else {
|
||||
// Create default appointment
|
||||
appointment = await Appointment.create({
|
||||
name: "default",
|
||||
hero: {
|
||||
title: "Make Appointment",
|
||||
backgroundImage: "",
|
||||
subtitle: "",
|
||||
heading: "",
|
||||
description: "",
|
||||
},
|
||||
visaOptions: [],
|
||||
form: {
|
||||
heading: "Request Appointment",
|
||||
fields: [],
|
||||
submitButton: {
|
||||
text: "Request Appointment",
|
||||
icon: "fa-solid fa-arrow-right",
|
||||
buttonClass: "theme-btn",
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const { startDate, endDate } = req.query;
|
||||
const query = {};
|
||||
|
||||
if (startDate || endDate) {
|
||||
query.createdAt = {};
|
||||
if (startDate) {
|
||||
query.createdAt.$gte = new Date(startDate);
|
||||
}
|
||||
if (endDate) {
|
||||
// Set end date to end of day
|
||||
const end = new Date(endDate);
|
||||
end.setHours(23, 59, 59, 999);
|
||||
query.createdAt.$lte = end;
|
||||
}
|
||||
}
|
||||
|
||||
const submissions = await AppointmentSubmission.find(query).sort({ createdAt: -1 }).limit(50);
|
||||
|
||||
res.render("admin/appointment/index", {
|
||||
layout: "layouts/main",
|
||||
title: "Appointment Management",
|
||||
data: appointment,
|
||||
submissions,
|
||||
startDate,
|
||||
endDate,
|
||||
user: req.session.user,
|
||||
frontendUrl: process.env.FRONTEND_URL || "http://localhost:3000",
|
||||
if (fs.existsSync(jsonPath)) {
|
||||
const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8"));
|
||||
appointment = await Appointment.migrateFromJson(jsonData);
|
||||
} else {
|
||||
// Create default appointment
|
||||
appointment = await Appointment.create({
|
||||
name: "default",
|
||||
hero: {
|
||||
title: "Make Appointment",
|
||||
backgroundImage: "",
|
||||
subtitle: "",
|
||||
heading: "",
|
||||
description: "",
|
||||
},
|
||||
visaOptions: [],
|
||||
form: {
|
||||
heading: "Request Appointment",
|
||||
fields: [],
|
||||
submitButton: {
|
||||
text: "Request Appointment",
|
||||
icon: "fa-solid fa-arrow-right",
|
||||
buttonClass: "theme-btn",
|
||||
},
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error loading appointment admin page:", err);
|
||||
req.flash("error", "Error loading appointment data");
|
||||
res.redirect("/admin/dashboard");
|
||||
}
|
||||
}
|
||||
|
||||
const { startDate, endDate } = req.query;
|
||||
const query = {};
|
||||
|
||||
if (startDate || endDate) {
|
||||
query.createdAt = {};
|
||||
if (startDate) {
|
||||
query.createdAt.$gte = new Date(startDate);
|
||||
}
|
||||
if (endDate) {
|
||||
// Set end date to end of day
|
||||
const end = new Date(endDate);
|
||||
end.setHours(23, 59, 59, 999);
|
||||
query.createdAt.$lte = end;
|
||||
}
|
||||
}
|
||||
|
||||
const submissions = await AppointmentSubmission.find(query)
|
||||
.sort({ createdAt: -1 })
|
||||
.limit(50);
|
||||
|
||||
res.render("admin/appointment/index", {
|
||||
layout: "layouts/main",
|
||||
title: "Appointment Management",
|
||||
data: appointment,
|
||||
submissions,
|
||||
startDate,
|
||||
endDate,
|
||||
user: req.session.user,
|
||||
frontendUrl: process.env.FRONTEND_URL || "http://localhost:3000",
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error loading appointment admin page:", err);
|
||||
req.flash("error", "Error loading appointment data");
|
||||
res.redirect("/admin/dashboard");
|
||||
}
|
||||
};
|
||||
|
||||
// Update appointment data
|
||||
exports.update = async (req, res) => {
|
||||
try {
|
||||
const { hero, visaOptions, form } = req.body;
|
||||
try {
|
||||
const { hero, visaOptions, form } = req.body;
|
||||
|
||||
// Parse JSON strings if needed
|
||||
const heroData = typeof hero === "string" ? JSON.parse(hero) : hero;
|
||||
const visaOptionsData = typeof visaOptions === "string" ? JSON.parse(visaOptions) : visaOptions;
|
||||
const formData = typeof form === "string" ? JSON.parse(form) : form;
|
||||
// Parse JSON strings if needed
|
||||
const heroData = typeof hero === "string" ? JSON.parse(hero) : hero;
|
||||
const visaOptionsData =
|
||||
typeof visaOptions === "string" ? JSON.parse(visaOptions) : visaOptions;
|
||||
const formData = typeof form === "string" ? JSON.parse(form) : form;
|
||||
|
||||
let appointment = await Appointment.findOne({ name: "default" });
|
||||
let appointment = await Appointment.findOne({ name: "default" });
|
||||
|
||||
if (appointment) {
|
||||
appointment.hero = heroData;
|
||||
appointment.visaOptions = visaOptionsData;
|
||||
appointment.form = formData;
|
||||
await appointment.save();
|
||||
} else {
|
||||
appointment = await Appointment.create({
|
||||
name: "default",
|
||||
hero: heroData,
|
||||
visaOptions: visaOptionsData,
|
||||
form: formData,
|
||||
});
|
||||
}
|
||||
// Capture before state for audit logging
|
||||
const beforeState = appointment
|
||||
? JSON.parse(JSON.stringify(appointment.toObject()))
|
||||
: null;
|
||||
|
||||
req.flash("success", "Appointment data updated successfully");
|
||||
res.redirect("/admin/appointment");
|
||||
} catch (err) {
|
||||
console.error("Error updating appointment:", err);
|
||||
req.flash("error", "Error updating appointment data");
|
||||
res.redirect("/admin/appointment");
|
||||
if (appointment) {
|
||||
appointment.hero = heroData;
|
||||
appointment.visaOptions = visaOptionsData;
|
||||
appointment.form = formData;
|
||||
await appointment.save();
|
||||
} else {
|
||||
appointment = await Appointment.create({
|
||||
name: "default",
|
||||
hero: heroData,
|
||||
visaOptions: visaOptionsData,
|
||||
form: formData,
|
||||
});
|
||||
}
|
||||
|
||||
// Capture after state for audit logging
|
||||
const afterState = JSON.parse(JSON.stringify(appointment.toObject()));
|
||||
|
||||
// Generate changes diff
|
||||
const changes = beforeState ? diffObject(beforeState, afterState) : [];
|
||||
|
||||
// Write audit log
|
||||
await writeAuditLog({
|
||||
model: "Appointment",
|
||||
documentId: appointment._id,
|
||||
action: AUDIT_ACTIONS.UPDATE_APPOINTMENT,
|
||||
before: beforeState,
|
||||
after: afterState,
|
||||
changes,
|
||||
req,
|
||||
});
|
||||
|
||||
req.flash("success", "Appointment data updated successfully");
|
||||
res.redirect("/admin/appointment");
|
||||
} catch (err) {
|
||||
console.error("Error updating appointment:", err);
|
||||
req.flash("error", "Error updating appointment data");
|
||||
res.redirect("/admin/appointment");
|
||||
}
|
||||
};
|
||||
|
||||
// API to get appointment data
|
||||
exports.getAppointmentData = async (req, res) => {
|
||||
try {
|
||||
let appointment = await Appointment.findOne({ name: "default" });
|
||||
try {
|
||||
let appointment = await Appointment.findOne({ name: "default" });
|
||||
|
||||
if (!appointment) {
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const jsonPath = path.join(__dirname, "../data/appointment.json");
|
||||
if (!appointment) {
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const jsonPath = path.join(__dirname, "../data/appointment.json");
|
||||
|
||||
if (fs.existsSync(jsonPath)) {
|
||||
const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8"));
|
||||
appointment = await Appointment.migrateFromJson(jsonData);
|
||||
}
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: appointment,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error getting appointment data:", err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error loading appointment data",
|
||||
});
|
||||
if (fs.existsSync(jsonPath)) {
|
||||
const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8"));
|
||||
appointment = await Appointment.migrateFromJson(jsonData);
|
||||
}
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: appointment,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error getting appointment data:", err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error loading appointment data",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Public API to get appointment page data (for frontend)
|
||||
exports.api = async (req, res) => {
|
||||
try {
|
||||
let appointment = await Appointment.findOne({ name: "default" });
|
||||
try {
|
||||
let appointment = await Appointment.findOne({ name: "default" });
|
||||
|
||||
if (!appointment) {
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const jsonPath = path.join(__dirname, "../data/appointment.json");
|
||||
if (!appointment) {
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const jsonPath = path.join(__dirname, "../data/appointment.json");
|
||||
|
||||
if (fs.existsSync(jsonPath)) {
|
||||
const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8"));
|
||||
appointment = await Appointment.migrateFromJson(jsonData);
|
||||
}
|
||||
}
|
||||
|
||||
if (!appointment) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: "Appointment data not found",
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
hero: appointment.hero,
|
||||
visaOptions: appointment.visaOptions,
|
||||
form: appointment.form,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error getting appointment API data:", err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error loading appointment data",
|
||||
});
|
||||
if (fs.existsSync(jsonPath)) {
|
||||
const jsonData = JSON.parse(fs.readFileSync(jsonPath, "utf8"));
|
||||
appointment = await Appointment.migrateFromJson(jsonData);
|
||||
}
|
||||
}
|
||||
|
||||
if (!appointment) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: "Appointment data not found",
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: {
|
||||
hero: appointment.hero,
|
||||
visaOptions: appointment.visaOptions,
|
||||
form: appointment.form,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error getting appointment API data:", err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error loading appointment data",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// ==================== APPOINTMENT SUBMISSIONS API ====================
|
||||
|
||||
// API để submit appointment form (từ frontend)
|
||||
exports.submitAppointment = async (req, res) => {
|
||||
try {
|
||||
const { name, email, phone, address, appointmentDate, message, visaTypes } = req.body;
|
||||
try {
|
||||
const { name, email, phone, address, appointmentDate, message, visaTypes } =
|
||||
req.body;
|
||||
|
||||
// Validation
|
||||
if (!name || !email) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: "Name and email are required",
|
||||
});
|
||||
}
|
||||
|
||||
// Create new submission
|
||||
const submission = new AppointmentSubmission({
|
||||
name: name.trim(),
|
||||
email: email.trim().toLowerCase(),
|
||||
phone: phone?.trim() || "",
|
||||
address: address?.trim() || "",
|
||||
appointmentDate: appointmentDate?.trim() || "",
|
||||
message: message?.trim() || "",
|
||||
visaTypes: Array.isArray(visaTypes) ? visaTypes : [],
|
||||
ipAddress: req.ip || req.connection?.remoteAddress || "",
|
||||
userAgent: req.get("User-Agent") || "",
|
||||
});
|
||||
|
||||
await submission.save();
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message: "Thank you! Your appointment request has been submitted. We will contact you soon.",
|
||||
data: {
|
||||
id: submission._id,
|
||||
name: submission.name,
|
||||
email: submission.email,
|
||||
appointmentDate: submission.appointmentDate,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error submitting appointment:", err);
|
||||
|
||||
// Handle validation errors
|
||||
if (err.name === "ValidationError") {
|
||||
const errors = Object.values(err.errors).map((e) => e.message);
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: errors.join(", "),
|
||||
});
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error submitting appointment. Please try again later.",
|
||||
});
|
||||
// Validation
|
||||
if (!name || !email) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: "Name and email are required",
|
||||
});
|
||||
}
|
||||
|
||||
// Create new submission
|
||||
const submission = new AppointmentSubmission({
|
||||
name: name.trim(),
|
||||
email: email.trim().toLowerCase(),
|
||||
phone: phone?.trim() || "",
|
||||
address: address?.trim() || "",
|
||||
appointmentDate: appointmentDate?.trim() || "",
|
||||
message: message?.trim() || "",
|
||||
visaTypes: Array.isArray(visaTypes) ? visaTypes : [],
|
||||
ipAddress: req.ip || req.connection?.remoteAddress || "",
|
||||
userAgent: req.get("User-Agent") || "",
|
||||
});
|
||||
|
||||
await submission.save();
|
||||
|
||||
res.status(201).json({
|
||||
success: true,
|
||||
message:
|
||||
"Thank you! Your appointment request has been submitted. We will contact you soon.",
|
||||
data: {
|
||||
id: submission._id,
|
||||
name: submission.name,
|
||||
email: submission.email,
|
||||
appointmentDate: submission.appointmentDate,
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error submitting appointment:", err);
|
||||
|
||||
// Handle validation errors
|
||||
if (err.name === "ValidationError") {
|
||||
const errors = Object.values(err.errors).map((e) => e.message);
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: errors.join(", "),
|
||||
});
|
||||
}
|
||||
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error submitting appointment. Please try again later.",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// API để lấy danh sách appointments (cho admin)
|
||||
exports.getAppointments = async (req, res) => {
|
||||
try {
|
||||
const { status, page = 1, limit = 20 } = req.query;
|
||||
try {
|
||||
const { status, page = 1, limit = 20 } = req.query;
|
||||
|
||||
const query = {};
|
||||
if (status && ["pending", "confirmed", "completed", "cancelled"].includes(status)) {
|
||||
query.status = status;
|
||||
}
|
||||
|
||||
const skip = (parseInt(page) - 1) * parseInt(limit);
|
||||
|
||||
const [appointments, total] = await Promise.all([
|
||||
AppointmentSubmission.find(query)
|
||||
.sort({ createdAt: -1 })
|
||||
.skip(skip)
|
||||
.limit(parseInt(limit)),
|
||||
AppointmentSubmission.countDocuments(query),
|
||||
]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: appointments,
|
||||
pagination: {
|
||||
page: parseInt(page),
|
||||
limit: parseInt(limit),
|
||||
total,
|
||||
totalPages: Math.ceil(total / parseInt(limit)),
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error getting appointments:", err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error loading appointments",
|
||||
});
|
||||
const query = {};
|
||||
if (
|
||||
status &&
|
||||
["pending", "confirmed", "completed", "cancelled"].includes(status)
|
||||
) {
|
||||
query.status = status;
|
||||
}
|
||||
|
||||
const skip = (parseInt(page) - 1) * parseInt(limit);
|
||||
|
||||
const [appointments, total] = await Promise.all([
|
||||
AppointmentSubmission.find(query)
|
||||
.sort({ createdAt: -1 })
|
||||
.skip(skip)
|
||||
.limit(parseInt(limit)),
|
||||
AppointmentSubmission.countDocuments(query),
|
||||
]);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: appointments,
|
||||
pagination: {
|
||||
page: parseInt(page),
|
||||
limit: parseInt(limit),
|
||||
total,
|
||||
totalPages: Math.ceil(total / parseInt(limit)),
|
||||
},
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error getting appointments:", err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error loading appointments",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// API để cập nhật status của appointment
|
||||
exports.updateAppointmentStatus = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { status, notes } = req.body;
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { status, notes } = req.body;
|
||||
|
||||
const validStatuses = ["pending", "confirmed", "completed", "cancelled"];
|
||||
if (!validStatuses.includes(status)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: "Invalid status",
|
||||
});
|
||||
}
|
||||
|
||||
const updateData = { status };
|
||||
if (notes !== undefined) updateData.notes = notes;
|
||||
if (status === "confirmed") updateData.confirmedAt = new Date();
|
||||
if (status === "completed") updateData.completedAt = new Date();
|
||||
|
||||
const appointment = await AppointmentSubmission.findByIdAndUpdate(
|
||||
id,
|
||||
updateData,
|
||||
{ new: true }
|
||||
);
|
||||
|
||||
if (!appointment) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: "Appointment not found",
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: appointment,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error updating appointment:", err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error updating appointment",
|
||||
});
|
||||
const validStatuses = ["pending", "confirmed", "completed", "cancelled"];
|
||||
if (!validStatuses.includes(status)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
error: "Invalid status",
|
||||
});
|
||||
}
|
||||
|
||||
// Get the appointment before update for audit logging
|
||||
const beforeAppointment = await AppointmentSubmission.findById(id);
|
||||
if (!beforeAppointment) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: "Appointment not found",
|
||||
});
|
||||
}
|
||||
|
||||
const beforeState = JSON.parse(
|
||||
JSON.stringify(beforeAppointment.toObject()),
|
||||
);
|
||||
|
||||
const updateData = { status };
|
||||
if (notes !== undefined) updateData.notes = notes;
|
||||
if (status === "confirmed") updateData.confirmedAt = new Date();
|
||||
if (status === "completed") updateData.completedAt = new Date();
|
||||
|
||||
const appointment = await AppointmentSubmission.findByIdAndUpdate(
|
||||
id,
|
||||
updateData,
|
||||
{ new: true },
|
||||
);
|
||||
|
||||
// Capture after state for audit logging
|
||||
const afterState = JSON.parse(JSON.stringify(appointment.toObject()));
|
||||
|
||||
// Generate changes diff
|
||||
const changes = diffObject(beforeState, afterState);
|
||||
|
||||
// Write audit log
|
||||
await writeAuditLog({
|
||||
model: "AppointmentSubmission",
|
||||
documentId: appointment._id,
|
||||
action: AUDIT_ACTIONS.UPDATE_APPOINTMENT_STATUS,
|
||||
before: beforeState,
|
||||
after: afterState,
|
||||
changes,
|
||||
req,
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: appointment,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error updating appointment:", err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error updating appointment",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// API để lấy chi tiết một appointment
|
||||
exports.getAppointmentById = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const appointment = await AppointmentSubmission.findById(id);
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const appointment = await AppointmentSubmission.findById(id);
|
||||
|
||||
if (!appointment) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: "Appointment not found",
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: appointment,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error getting appointment:", err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error loading appointment",
|
||||
});
|
||||
if (!appointment) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: "Appointment not found",
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
data: appointment,
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error getting appointment:", err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error loading appointment",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// API để xóa appointment
|
||||
exports.deleteAppointment = async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const appointment = await AppointmentSubmission.findByIdAndDelete(id);
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
if (!appointment) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: "Appointment not found",
|
||||
});
|
||||
}
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: "Appointment deleted successfully",
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error deleting appointment:", err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error deleting appointment",
|
||||
});
|
||||
// Get the appointment before deletion for audit logging
|
||||
const appointment = await AppointmentSubmission.findById(id);
|
||||
if (!appointment) {
|
||||
return res.status(404).json({
|
||||
success: false,
|
||||
error: "Appointment not found",
|
||||
});
|
||||
}
|
||||
|
||||
const beforeState = JSON.parse(JSON.stringify(appointment.toObject()));
|
||||
|
||||
// Delete the appointment
|
||||
await AppointmentSubmission.findByIdAndDelete(id);
|
||||
|
||||
// Write audit log
|
||||
await writeAuditLog({
|
||||
model: "AppointmentSubmission",
|
||||
documentId: appointment._id,
|
||||
action: AUDIT_ACTIONS.DELETE_APPOINTMENT,
|
||||
before: beforeState,
|
||||
after: null,
|
||||
changes: [],
|
||||
req,
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
message: "Appointment deleted successfully",
|
||||
});
|
||||
} catch (err) {
|
||||
console.error("Error deleting appointment:", err);
|
||||
res.status(500).json({
|
||||
success: false,
|
||||
error: "Error deleting appointment",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user