forked from UKSOURCE/cms.hailearning.edu.vn
Add CMS support for floating contact widget with Facebook/Zalo quick actions. Includes mongoose schema, admin UI tab, image upload with sharp resize presets, deferred form submission with draft persistence, and upload middleware error handling.
644 lines
18 KiB
JavaScript
644 lines
18 KiB
JavaScript
const express = require("express");
|
|
const router = express.Router();
|
|
const { ensureAuthenticated } = require("../middleware/auth");
|
|
const dashboardController = require("../controllers/dashboardController");
|
|
const uploadController = require("../controllers/uploadController");
|
|
const homeController = require("../controllers/homeController");
|
|
const headerController = require("../controllers/headerController");
|
|
const footerController = require("../controllers/footerController");
|
|
const aboutUsController = require("../controllers/aboutUsController");
|
|
const formController = require("../controllers/formController");
|
|
const contactController = require("../controllers/contactController");
|
|
const pageController = require("../controllers/pageController");
|
|
const settingController = require("../controllers/settingController");
|
|
const faqController = require("../controllers/faqController"); // Thêm import này
|
|
const termsController = require("../controllers/termsController");
|
|
const travelController = require("../controllers/travelController");
|
|
const visaController = require("../controllers/visaController");
|
|
const { upload, uploadVideo, convertToWebp } = require("../middleware/upload");
|
|
const safetyController = require("../controllers/safetyController");
|
|
const insuranceController = require("../controllers/insuranceController");
|
|
const auditLogController = require("../controllers/auditLogController");
|
|
|
|
const activityController = require("../controllers/activityController");
|
|
const bookingSubmissionController = require("../controllers/bookingSubmissionController");
|
|
const serviceController = require("../controllers/serviceController");
|
|
const headerMenuController = require("../controllers/headerMenuController");
|
|
|
|
// Blog controllers
|
|
const blogController = require("../controllers/blogController");
|
|
const blogCategoryController = require("../controllers/blogCategoryController");
|
|
const blogTagController = require("../controllers/blogTagController");
|
|
const socialLinkController = require("../controllers/socialLinkController");
|
|
const testimonialController = require("../controllers/testimonialController");
|
|
const videoGalleryController = require("../controllers/videoGalleryController");
|
|
|
|
// Dashboard
|
|
router.get("/dashboard", ensureAuthenticated, dashboardController.getDashboard);
|
|
|
|
const runUploadMiddleware = (middleware) => (req, res, next) => {
|
|
middleware(req, res, (error) => {
|
|
if (!error) {
|
|
return next();
|
|
}
|
|
|
|
console.error("Upload middleware error:", error);
|
|
|
|
const status =
|
|
error.code === "LIMIT_FILE_SIZE"
|
|
? 413
|
|
: error.statusCode || error.status || 400;
|
|
|
|
return res.status(status).json({
|
|
success: false,
|
|
error: error.message || "Upload failed",
|
|
});
|
|
});
|
|
};
|
|
|
|
// Home
|
|
router.get("/home", ensureAuthenticated, homeController.index);
|
|
router.post("/home/update", ensureAuthenticated, homeController.update);
|
|
router.post(
|
|
"/home/floating-contact/update",
|
|
ensureAuthenticated,
|
|
homeController.updateFloatingContact,
|
|
);
|
|
router.get("/home/api/blogs", ensureAuthenticated, homeController.apiGetBlogs);
|
|
|
|
// Middleware chuẩn hóa code
|
|
router.param("code", (req, res, next, code) => {
|
|
req.params.code = code.toUpperCase();
|
|
next();
|
|
});
|
|
|
|
// About Us
|
|
router.get("/about-us", ensureAuthenticated, aboutUsController.index);
|
|
router.post("/about-us/update", ensureAuthenticated, aboutUsController.update);
|
|
|
|
// Booking admin CRUD removed
|
|
|
|
// Form Management
|
|
router.get("/form", ensureAuthenticated, formController.index);
|
|
router.post(
|
|
"/form/update",
|
|
ensureAuthenticated,
|
|
formController.updateDefaultForm,
|
|
);
|
|
|
|
// Upload routes
|
|
router.get("/upload", ensureAuthenticated, (req, res) => {
|
|
res.render("admin/upload/index", {
|
|
layout: "layouts/admin",
|
|
title: "Quản lý Upload Ảnh",
|
|
user: req.session.user,
|
|
});
|
|
});
|
|
router.post(
|
|
"/upload/image",
|
|
ensureAuthenticated,
|
|
runUploadMiddleware(upload.single("image")),
|
|
uploadController.uploadImage,
|
|
);
|
|
router.post(
|
|
"/upload/video",
|
|
ensureAuthenticated,
|
|
runUploadMiddleware(uploadVideo.single("video")),
|
|
uploadController.uploadVideo,
|
|
);
|
|
router.post(
|
|
"/upload/update-path",
|
|
ensureAuthenticated,
|
|
uploadController.updateImagePath,
|
|
);
|
|
router.post(
|
|
"/upload/delete",
|
|
ensureAuthenticated,
|
|
uploadController.deleteImage,
|
|
);
|
|
|
|
// Header routes
|
|
router.get("/header", ensureAuthenticated, headerController.index);
|
|
router.post("/header/update", ensureAuthenticated, headerController.update);
|
|
router.get("/header/data", ensureAuthenticated, headerController.api); // Normalized from getHeaderData
|
|
router.patch(
|
|
"/header/:id/status",
|
|
ensureAuthenticated,
|
|
headerController.updateStatus,
|
|
);
|
|
router.delete("/header/:id", ensureAuthenticated, headerController.destroy);
|
|
|
|
// Header Menu INTEGRATED routes
|
|
router.post(
|
|
"/header/menu/create",
|
|
ensureAuthenticated,
|
|
headerMenuController.store,
|
|
);
|
|
router.post(
|
|
"/header/menu/update/:id",
|
|
ensureAuthenticated,
|
|
headerMenuController.update,
|
|
);
|
|
router.post(
|
|
"/header/menu/delete",
|
|
ensureAuthenticated,
|
|
headerMenuController.destroy,
|
|
);
|
|
router.post(
|
|
"/header/menu/reorder",
|
|
ensureAuthenticated,
|
|
headerMenuController.reorder,
|
|
);
|
|
|
|
// Social Links routes
|
|
router.get("/social-links", ensureAuthenticated, socialLinkController.index);
|
|
router.post("/social-links", ensureAuthenticated, socialLinkController.store);
|
|
router.put(
|
|
"/social-links/:platform",
|
|
ensureAuthenticated,
|
|
socialLinkController.update,
|
|
);
|
|
router.delete(
|
|
"/social-links/:platform",
|
|
ensureAuthenticated,
|
|
socialLinkController.destroy,
|
|
);
|
|
router.post(
|
|
"/social-links/reorder",
|
|
ensureAuthenticated,
|
|
socialLinkController.reorder,
|
|
);
|
|
|
|
// Footer routes
|
|
router.get("/footer", ensureAuthenticated, footerController.index);
|
|
router.post("/footer/update", ensureAuthenticated, footerController.update);
|
|
router.get("/footer/data", ensureAuthenticated, footerController.getFooterData);
|
|
|
|
// Contact routes
|
|
router.get("/contact", ensureAuthenticated, contactController.index);
|
|
router.post("/contact/update", ensureAuthenticated, contactController.update);
|
|
router.get(
|
|
"/contact/data",
|
|
ensureAuthenticated,
|
|
contactController.getContactData,
|
|
);
|
|
|
|
// Contact submissions management
|
|
router.get(
|
|
"/contact/submissions",
|
|
ensureAuthenticated,
|
|
contactController.getSubmissions,
|
|
);
|
|
router.put(
|
|
"/contact/submissions/:id",
|
|
ensureAuthenticated,
|
|
contactController.updateSubmissionStatus,
|
|
);
|
|
|
|
// Appointment management
|
|
const appointmentController = require("../controllers/appointmentController");
|
|
router.get(
|
|
"/appointments",
|
|
ensureAuthenticated,
|
|
appointmentController.getAppointments,
|
|
);
|
|
router.get(
|
|
"/appointments/:id",
|
|
ensureAuthenticated,
|
|
appointmentController.getAppointmentById,
|
|
);
|
|
router.put(
|
|
"/appointments/:id",
|
|
ensureAuthenticated,
|
|
appointmentController.updateAppointmentStatus,
|
|
);
|
|
router.delete(
|
|
"/appointments/:id",
|
|
ensureAuthenticated,
|
|
appointmentController.deleteAppointment,
|
|
);
|
|
|
|
// Appointment CMS page management
|
|
router.get("/appointment", ensureAuthenticated, appointmentController.index);
|
|
router.post(
|
|
"/appointment/update",
|
|
ensureAuthenticated,
|
|
appointmentController.update,
|
|
);
|
|
router.get(
|
|
"/appointment/data",
|
|
ensureAuthenticated,
|
|
appointmentController.getAppointmentData,
|
|
);
|
|
|
|
// Pricing CMS page management
|
|
const pricingController = require("../controllers/pricingController");
|
|
router.get("/pricing", ensureAuthenticated, pricingController.index);
|
|
router.post("/pricing/update", ensureAuthenticated, pricingController.update);
|
|
router.get(
|
|
"/pricing/data",
|
|
ensureAuthenticated,
|
|
pricingController.getPricingData,
|
|
);
|
|
|
|
// Activity CRUD routes
|
|
router.get("/activity", ensureAuthenticated, activityController.index);
|
|
router.get(
|
|
"/activity/create",
|
|
ensureAuthenticated,
|
|
activityController.createForm,
|
|
);
|
|
router.post("/activity/create", ensureAuthenticated, activityController.create);
|
|
// Update filters (place before any parameterized /activity/:id routes to avoid route collision)
|
|
router.post(
|
|
"/activity/filters/update",
|
|
ensureAuthenticated,
|
|
activityController.updateFilters,
|
|
);
|
|
// Update hero (global hero section for activities)
|
|
router.post(
|
|
"/activity/hero/update",
|
|
ensureAuthenticated,
|
|
activityController.updateHero,
|
|
);
|
|
router.get(
|
|
"/activity/:id/edit",
|
|
ensureAuthenticated,
|
|
activityController.editForm,
|
|
);
|
|
router.post(
|
|
"/activity/:id/update",
|
|
ensureAuthenticated,
|
|
activityController.update,
|
|
);
|
|
router.post(
|
|
"/activity/:id/delete",
|
|
ensureAuthenticated,
|
|
activityController.delete,
|
|
);
|
|
router.post(
|
|
"/activity/:id/toggle-status",
|
|
ensureAuthenticated,
|
|
activityController.toggleStatus,
|
|
);
|
|
// Update display order
|
|
router.post(
|
|
"/activity/update-order",
|
|
ensureAuthenticated,
|
|
activityController.updateOrder,
|
|
);
|
|
|
|
// Booking submissions routes
|
|
router.get(
|
|
"/activity/:id/bookings/count",
|
|
ensureAuthenticated,
|
|
activityController.getBookingCount,
|
|
);
|
|
router.get(
|
|
"/activity/:id/bookings",
|
|
ensureAuthenticated,
|
|
activityController.getBookingSubmissions,
|
|
);
|
|
router.get(
|
|
"/activity/:id/bookings/export",
|
|
ensureAuthenticated,
|
|
activityController.exportBookingData,
|
|
);
|
|
// Export all bookings (across all activities)
|
|
router.get(
|
|
"/bookings/export-all",
|
|
ensureAuthenticated,
|
|
activityController.exportAllBookingsData,
|
|
);
|
|
// Update booking submission
|
|
router.put(
|
|
"/bookings/:bookingId",
|
|
ensureAuthenticated,
|
|
bookingSubmissionController.updateBookingSubmission,
|
|
);
|
|
// Delete booking submission
|
|
router.delete(
|
|
"/bookings/:bookingId",
|
|
ensureAuthenticated,
|
|
bookingSubmissionController.deleteBookingSubmission,
|
|
);
|
|
|
|
// Update filters
|
|
|
|
// Preview activity
|
|
router.get(
|
|
"/activity/:id/preview",
|
|
ensureAuthenticated,
|
|
activityController.preview,
|
|
);
|
|
|
|
// FAQ routes
|
|
router.get("/home/faq", ensureAuthenticated, faqController.index);
|
|
router.post("/home/faq/update", ensureAuthenticated, faqController.update);
|
|
router.get("/home/faq/data", ensureAuthenticated, faqController.getFAQData);
|
|
router.get("/home/faq/api", faqController.api);
|
|
|
|
// Deprecated FAQ API routes removed
|
|
|
|
// API routes cho quản lý FAQ items (AJAX calls)
|
|
router.post("/faq/api/add-faq", ensureAuthenticated, faqController.addFAQ);
|
|
router.put(
|
|
"/faq/api/update-faq-item/:sectionId/:faqId",
|
|
ensureAuthenticated,
|
|
faqController.updateFAQItem,
|
|
);
|
|
router.delete(
|
|
"/faq/api/delete-faq-item/:sectionId/:faqId",
|
|
ensureAuthenticated,
|
|
faqController.deleteFAQItem,
|
|
);
|
|
router.get("/terms-conditions", ensureAuthenticated, termsController.index);
|
|
router.post("/terms/update", ensureAuthenticated, termsController.update);
|
|
router.get("/terms/data", ensureAuthenticated, termsController.getTermsData);
|
|
router.get("/terms/api", termsController.api);
|
|
router.get("/terms/seed", ensureAuthenticated, termsController.seed);
|
|
|
|
// Travel routes
|
|
router.get("/travel", ensureAuthenticated, travelController.index);
|
|
router.post("/travel/update", ensureAuthenticated, travelController.update);
|
|
router.post("/travel/preview", ensureAuthenticated, travelController.preview);
|
|
router.get("/travel/data", ensureAuthenticated, travelController.getTravelData);
|
|
router.get("/travel/api", travelController.api);
|
|
router.get("/travel/seed", ensureAuthenticated, travelController.seed);
|
|
|
|
// Deprecated FAQ API routes removed
|
|
|
|
// API routes cho quản lý FAQ sections (AJAX calls)
|
|
router.post(
|
|
"/faq/api/add-section",
|
|
ensureAuthenticated,
|
|
faqController.addFAQSection,
|
|
);
|
|
router.put(
|
|
"/faq/api/update-section/:sectionId",
|
|
ensureAuthenticated,
|
|
faqController.updateFAQSection,
|
|
);
|
|
router.delete(
|
|
"/faq/api/delete-section/:sectionId",
|
|
ensureAuthenticated,
|
|
faqController.deleteFAQSection,
|
|
);
|
|
router.post(
|
|
"/faq/api/reorder-sections",
|
|
ensureAuthenticated,
|
|
faqController.reorderFAQSection,
|
|
);
|
|
|
|
// API routes cho sidebar navigation (AJAX calls)
|
|
router.put(
|
|
"/faq/api/update-sidebar",
|
|
ensureAuthenticated,
|
|
faqController.updateSidebarNav,
|
|
);
|
|
|
|
// Safety routes
|
|
router.get("/safety", ensureAuthenticated, safetyController.index);
|
|
router.post("/safety/update", ensureAuthenticated, safetyController.update);
|
|
|
|
//Insurance routes
|
|
router.get("/insurance", ensureAuthenticated, insuranceController.index);
|
|
router.post(
|
|
"/insurance/update",
|
|
ensureAuthenticated,
|
|
insuranceController.update,
|
|
);
|
|
|
|
// Service routes
|
|
router.get("/service", ensureAuthenticated, serviceController.index);
|
|
router.post("/service/update", ensureAuthenticated, serviceController.update);
|
|
router.post(
|
|
"/service/generate-slug",
|
|
ensureAuthenticated,
|
|
serviceController.generateSlug,
|
|
);
|
|
router.get("/service/:slug/edit", ensureAuthenticated, serviceController.edit);
|
|
router.post(
|
|
"/service/:slug/edit",
|
|
ensureAuthenticated,
|
|
serviceController.updateService,
|
|
);
|
|
router.get(
|
|
"/service/:slug/details",
|
|
ensureAuthenticated,
|
|
serviceController.details,
|
|
);
|
|
router.post(
|
|
"/service/:slug/details/update",
|
|
ensureAuthenticated,
|
|
serviceController.updateDetails,
|
|
);
|
|
|
|
// Test Image Paths route
|
|
router.get("/test-images", ensureAuthenticated, (req, res) => {
|
|
const fs = require("fs");
|
|
const path = require("path");
|
|
const campLocationData = require("../data/camp-location.json");
|
|
|
|
// Collect all image paths
|
|
const imagePaths = [];
|
|
|
|
// Camps images
|
|
if (campLocationData.camps) {
|
|
campLocationData.camps.forEach((camp) => {
|
|
if (camp.image) {
|
|
imagePaths.push({
|
|
type: "Camp",
|
|
name: camp.title,
|
|
path: camp.image,
|
|
exists: fs.existsSync(path.join(__dirname, "../public", camp.image)),
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
// Locations images
|
|
if (campLocationData.locations) {
|
|
campLocationData.locations.forEach((location) => {
|
|
if (location.imageSrc) {
|
|
imagePaths.push({
|
|
type: "Location",
|
|
name: location.title,
|
|
path: location.imageSrc,
|
|
exists: fs.existsSync(
|
|
path.join(__dirname, "../public", location.imageSrc),
|
|
),
|
|
});
|
|
}
|
|
|
|
// Program images
|
|
if (location.programOptions) {
|
|
location.programOptions.forEach((program) => {
|
|
if (program.imageSrc) {
|
|
imagePaths.push({
|
|
type: "Program",
|
|
name: program.title,
|
|
path: program.imageSrc,
|
|
exists: fs.existsSync(
|
|
path.join(__dirname, "../public", program.imageSrc),
|
|
),
|
|
});
|
|
}
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
res.render("admin/test-images", {
|
|
layout: "layouts/admin",
|
|
title: "Test Image Paths",
|
|
images: imagePaths,
|
|
user: req.session.user,
|
|
});
|
|
});
|
|
|
|
// Display visa management page
|
|
router.get("/visa", ensureAuthenticated, visaController.index);
|
|
|
|
// Get country data for editing
|
|
router.get("/visa/edit/:id", ensureAuthenticated, visaController.getCountry);
|
|
|
|
// Update hero title
|
|
router.post("/visa/update", ensureAuthenticated, visaController.updateCountry);
|
|
|
|
// Add new country
|
|
router.post("/visa/add", ensureAuthenticated, visaController.addCountry);
|
|
|
|
// Update single country
|
|
router.put(
|
|
"/visa/update/:id",
|
|
ensureAuthenticated,
|
|
visaController.updateCountry,
|
|
);
|
|
|
|
// Delete country
|
|
router.delete(
|
|
"/visa/delete/:id",
|
|
ensureAuthenticated,
|
|
visaController.deleteCountry,
|
|
);
|
|
// Blog routes
|
|
// Blog Management Routes
|
|
router.get("/blog", ensureAuthenticated, blogController.index);
|
|
router.get("/blog/create", ensureAuthenticated, blogController.create);
|
|
router.post("/blog/create", ensureAuthenticated, blogController.store);
|
|
router.get("/blog/:id/edit", ensureAuthenticated, blogController.edit);
|
|
router.post("/blog/:id/edit", ensureAuthenticated, blogController.update);
|
|
router.post("/blog/:id/delete", ensureAuthenticated, blogController.destroy);
|
|
|
|
// Comment management routes
|
|
router.post(
|
|
"/blog/:blogId/comments/:commentId/approve",
|
|
ensureAuthenticated,
|
|
blogController.approveComment,
|
|
);
|
|
router.post(
|
|
"/blog/:blogId/comments/:commentId/reject",
|
|
ensureAuthenticated,
|
|
blogController.rejectComment,
|
|
);
|
|
router.post(
|
|
"/blog/:blogId/comments/:commentId/delete",
|
|
ensureAuthenticated,
|
|
blogController.deleteComment,
|
|
);
|
|
|
|
// Blog Categories Management
|
|
router.get(
|
|
"/blog/categories",
|
|
ensureAuthenticated,
|
|
blogCategoryController.index,
|
|
);
|
|
router.get(
|
|
"/blog/categories/create",
|
|
ensureAuthenticated,
|
|
blogCategoryController.create,
|
|
);
|
|
router.post(
|
|
"/blog/categories/create",
|
|
ensureAuthenticated,
|
|
blogCategoryController.store,
|
|
);
|
|
router.get(
|
|
"/blog/categories/:id/edit",
|
|
ensureAuthenticated,
|
|
blogCategoryController.edit,
|
|
);
|
|
router.post(
|
|
"/blog/categories/:id/edit",
|
|
ensureAuthenticated,
|
|
blogCategoryController.update,
|
|
);
|
|
router.post(
|
|
"/blog/categories/:id/delete",
|
|
ensureAuthenticated,
|
|
blogCategoryController.destroy,
|
|
);
|
|
router.post(
|
|
"/blog/categories/quick-create",
|
|
ensureAuthenticated,
|
|
blogCategoryController.quickCreate,
|
|
);
|
|
|
|
// Blog Tags Management
|
|
router.get("/blog/tags", ensureAuthenticated, blogTagController.index);
|
|
router.get("/blog/tags/create", ensureAuthenticated, blogTagController.create);
|
|
router.post("/blog/tags/create", ensureAuthenticated, blogTagController.store);
|
|
router.get("/blog/tags/:id/edit", ensureAuthenticated, blogTagController.edit);
|
|
router.post(
|
|
"/blog/tags/:id/edit",
|
|
ensureAuthenticated,
|
|
blogTagController.update,
|
|
);
|
|
router.post(
|
|
"/blog/tags/:id/delete",
|
|
ensureAuthenticated,
|
|
blogTagController.destroy,
|
|
);
|
|
router.post(
|
|
"/blog/tags/quick-create",
|
|
ensureAuthenticated,
|
|
blogTagController.quickCreate,
|
|
);
|
|
|
|
// Testimonials management
|
|
router.get(
|
|
"/home/testimonials",
|
|
ensureAuthenticated,
|
|
testimonialController.index,
|
|
);
|
|
router.post(
|
|
"/home/testimonials/update",
|
|
ensureAuthenticated,
|
|
testimonialController.update,
|
|
);
|
|
|
|
// Video Gallery management
|
|
router.get(
|
|
"/home/video-gallery",
|
|
ensureAuthenticated,
|
|
videoGalleryController.index,
|
|
);
|
|
router.post(
|
|
"/home/video-gallery/update",
|
|
ensureAuthenticated,
|
|
videoGalleryController.update,
|
|
);
|
|
|
|
// Audit Log routes
|
|
router.get("/audit-logs", ensureAuthenticated, auditLogController.index);
|
|
router.get("/audit-logs/:id", ensureAuthenticated, auditLogController.show);
|
|
router.get("/audit-logs-api", ensureAuthenticated, auditLogController.api);
|
|
router.post(
|
|
"/audit-logs/cleanup",
|
|
ensureAuthenticated,
|
|
auditLogController.cleanup,
|
|
);
|
|
|
|
module.exports = router;
|