forked from UKSOURCE/cms.hailearning.edu.vn
fea/nhat-dat-11042026-merge #1
BIN
.env.example
BIN
.env.example
Binary file not shown.
@@ -445,14 +445,11 @@ exports.apiGetBlogs = async (req, res) => {
|
|||||||
};
|
};
|
||||||
exports.api = async (req, res) => {
|
exports.api = async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const docs = await getAllHomeDocs();
|
// Chỉ dùng doc mới nhất, không merge nhiều docs
|
||||||
let data = docs[0]?.toObject() || {};
|
const doc = await getHomeDoc();
|
||||||
|
let data = doc?.toObject() || {};
|
||||||
const baseUrl = `${req.protocol}://${req.get("host")}`;
|
const baseUrl = `${req.protocol}://${req.get("host")}`;
|
||||||
|
|
||||||
if (docs.length > 1) {
|
|
||||||
data.hero = getPreferredHeroData(docs.map((doc) => doc.toObject()));
|
|
||||||
}
|
|
||||||
|
|
||||||
// === Xử lý Blog Preview động ===
|
// === Xử lý Blog Preview động ===
|
||||||
const blogPreview = data.blogPreview || {};
|
const blogPreview = data.blogPreview || {};
|
||||||
let blogs = [];
|
let blogs = [];
|
||||||
|
|||||||
@@ -349,5 +349,8 @@ const HomeSchema = new Schema(
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Đảm bảo chỉ có 1 document duy nhất (singleton pattern)
|
||||||
|
HomeSchema.index({ createdAt: 1 }, { unique: false });
|
||||||
|
|
||||||
module.exports = mongoose.model("Home", HomeSchema);
|
module.exports = mongoose.model("Home", HomeSchema);
|
||||||
|
|
||||||
|
|||||||
22
scripts/cleanup-home-docs.js
Normal file
22
scripts/cleanup-home-docs.js
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
require('dotenv').config();
|
||||||
|
const mongoose = require('mongoose');
|
||||||
|
const Home = require('../models/home');
|
||||||
|
|
||||||
|
mongoose.connect(process.env.MONGODB_URI).then(async () => {
|
||||||
|
const docs = await Home.find().sort({ updatedAt: -1 }).lean();
|
||||||
|
console.log('Total docs:', docs.length);
|
||||||
|
|
||||||
|
if (docs.length <= 1) {
|
||||||
|
console.log('Nothing to clean up.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const keep = docs[0];
|
||||||
|
const idsToDelete = docs.slice(1).map(d => d._id);
|
||||||
|
await Home.deleteMany({ _id: { $in: idsToDelete } });
|
||||||
|
|
||||||
|
console.log('Kept doc:', keep._id, '| hero.enabled:', keep.hero?.enabled);
|
||||||
|
console.log('Deleted', idsToDelete.length, 'duplicate docs');
|
||||||
|
|
||||||
|
await mongoose.disconnect();
|
||||||
|
});
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- Achievements Tab -->
|
<!-- Achievements Tab -->
|
||||||
<div class="tab-pane fade" id="achievements" role="tabpanel">
|
<div class="tab-pane fade" id="achievements" role="tabpanel">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<!-- Basic Info -->
|
<!-- Basic Info -->
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
window.homeScrapers.achievements = function () {
|
window.homeScrapers.achievements = function () {
|
||||||
const items = [];
|
const items = [];
|
||||||
|
|
||||||
const enabled = document.getElementById("achievementEnabled")?.checked !== false;
|
const enabled = document.getElementById("achievementEnabled")?.checked === true;
|
||||||
|
|
||||||
document.querySelectorAll('.achievement-item').forEach(el => {
|
document.querySelectorAll('.achievement-item').forEach(el => {
|
||||||
items.push({
|
items.push({
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- Blog Preview Tab -->
|
<!-- Blog Preview Tab -->
|
||||||
<div class="tab-pane fade" id="blogpreview" role="tabpanel">
|
<div class="tab-pane fade" id="blogpreview" role="tabpanel">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<!-- Basic Info -->
|
<!-- Basic Info -->
|
||||||
@@ -158,7 +158,7 @@
|
|||||||
window.homeScrapers.blogPreview = () => {
|
window.homeScrapers.blogPreview = () => {
|
||||||
const selectedIds = [];
|
const selectedIds = [];
|
||||||
|
|
||||||
const enabled = document.getElementById("blogpreviewEnabled")?.checked !== false;
|
const enabled = document.getElementById("blogpreviewEnabled")?.checked === true;
|
||||||
|
|
||||||
document.querySelectorAll('.blog-checkbox:checked').forEach(cb => {
|
document.querySelectorAll('.blog-checkbox:checked').forEach(cb => {
|
||||||
selectedIds.push(cb.value);
|
selectedIds.push(cb.value);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- FAQ Tab -->
|
<!-- FAQ Tab -->
|
||||||
<div class="tab-pane fade" id="faq" role="tabpanel">
|
<div class="tab-pane fade" id="faq" role="tabpanel">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<!-- Basic Info -->
|
<!-- Basic Info -->
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
window.homeScrapers.faq = () => {
|
window.homeScrapers.faq = () => {
|
||||||
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
||||||
|
|
||||||
const enabled = document.getElementById('faqEnabled')?.checked !== false;
|
const enabled = document.getElementById('faqEnabled')?.checked === true;
|
||||||
|
|
||||||
const items = [];
|
const items = [];
|
||||||
document.querySelectorAll(".faq-item").forEach((el, idx) => {
|
document.querySelectorAll(".faq-item").forEach((el, idx) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- Hero Tab -->
|
<!-- Hero Tab -->
|
||||||
<div class="tab-pane fade show active" id="hero" role="tabpanel">
|
<div class="tab-pane fade show active" id="hero" role="tabpanel">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
@@ -203,7 +203,7 @@
|
|||||||
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
||||||
|
|
||||||
const backgroundImage = getVal("heroBackgroundImage");
|
const backgroundImage = getVal("heroBackgroundImage");
|
||||||
const enabled = document.getElementById("heroEnabled")?.checked !== false;
|
const enabled = document.getElementById("heroEnabled")?.checked === true;
|
||||||
|
|
||||||
const slides = [];
|
const slides = [];
|
||||||
const slideEls = document.querySelectorAll(".hero-slide-item");
|
const slideEls = document.querySelectorAll(".hero-slide-item");
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- Partners Tab -->
|
<!-- Partners Tab -->
|
||||||
<div class="tab-pane fade" id="partners" role="tabpanel">
|
<div class="tab-pane fade" id="partners" role="tabpanel">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<!-- Visa Consultancy Awards -->
|
<!-- Visa Consultancy Awards -->
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
window.homeScrapers.partners = function () {
|
window.homeScrapers.partners = function () {
|
||||||
const visaItems = [];
|
const visaItems = [];
|
||||||
|
|
||||||
const enabled = document.getElementById('partnersEnabled')?.checked !== false;
|
const enabled = document.getElementById('partnersEnabled')?.checked === true;
|
||||||
|
|
||||||
document.querySelectorAll('.visa-item').forEach(el => {
|
document.querySelectorAll('.visa-item').forEach(el => {
|
||||||
visaItems.push({
|
visaItems.push({
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- Testimonials Tab -->
|
<!-- Testimonials Tab -->
|
||||||
<div class="tab-pane fade" id="testimonials" role="tabpanel">
|
<div class="tab-pane fade" id="testimonials" role="tabpanel">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<!-- Basic Info -->
|
<!-- Basic Info -->
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
window.homeScrapers.testimonials = () => {
|
window.homeScrapers.testimonials = () => {
|
||||||
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
||||||
|
|
||||||
const enabled = document.getElementById("testimonialEnabled")?.checked !== false;
|
const enabled = document.getElementById("testimonialEnabled")?.checked === true;
|
||||||
|
|
||||||
const items = [];
|
const items = [];
|
||||||
document.querySelectorAll(".testimonial-item").forEach((el, idx) => {
|
document.querySelectorAll(".testimonial-item").forEach((el, idx) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- Video Gallery Tab -->
|
<!-- Video Gallery Tab -->
|
||||||
<div class="tab-pane fade" id="videogallery" role="tabpanel">
|
<div class="tab-pane fade" id="videogallery" role="tabpanel">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<div class="col-md-12">
|
<div class="col-md-12">
|
||||||
@@ -64,7 +64,7 @@
|
|||||||
window.homeScrapers.videoGallery = () => {
|
window.homeScrapers.videoGallery = () => {
|
||||||
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
||||||
|
|
||||||
const enabled = document.getElementById("videoGalleryEnabled")?.checked !== false;
|
const enabled = document.getElementById("videoGalleryEnabled")?.checked === true;
|
||||||
return {
|
return {
|
||||||
heading: getVal("videoGalleryHeading"),
|
heading: getVal("videoGalleryHeading"),
|
||||||
videoUrl: getVal("videoGalleryVideoUrl"),
|
videoUrl: getVal("videoGalleryVideoUrl"),
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- Visa Countries Tab -->
|
<!-- Visa Countries Tab -->
|
||||||
<div class="tab-pane fade" id="visacountries" role="tabpanel">
|
<div class="tab-pane fade" id="visacountries" role="tabpanel">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<!-- Basic Info -->
|
<!-- Basic Info -->
|
||||||
@@ -135,7 +135,7 @@
|
|||||||
window.homeScrapers.visaCountries = () => {
|
window.homeScrapers.visaCountries = () => {
|
||||||
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
||||||
|
|
||||||
const enabled = document.getElementById("visaCountriesEnabled")?.checked !== false
|
const enabled = document.getElementById("visaCountriesEnabled")?.checked === true
|
||||||
|
|
||||||
const visaTypesRaw = getVal("visaCountriesVisaTypes_0");
|
const visaTypesRaw = getVal("visaCountriesVisaTypes_0");
|
||||||
const visaTypes = visaTypesRaw ? visaTypesRaw.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
const visaTypes = visaTypesRaw ? visaTypesRaw.split(",").map((s) => s.trim()).filter(Boolean) : [];
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- Visa Solutions Tab -->
|
<!-- Visa Solutions Tab -->
|
||||||
<div class="tab-pane fade" id="visasolutions" role="tabpanel">
|
<div class="tab-pane fade" id="visasolutions" role="tabpanel">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<!-- Basic Info -->
|
<!-- Basic Info -->
|
||||||
@@ -100,7 +100,7 @@
|
|||||||
window.homeScrapers.visaSolutions = () => {
|
window.homeScrapers.visaSolutions = () => {
|
||||||
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
||||||
|
|
||||||
const enabled = document.getElementById("visaSolutionsEnabled")?.checked !== false;
|
const enabled = document.getElementById("visaSolutionsEnabled")?.checked === true;
|
||||||
|
|
||||||
const items = [];
|
const items = [];
|
||||||
document.querySelectorAll(".visa-solution-item").forEach((el, idx) => {
|
document.querySelectorAll(".visa-solution-item").forEach((el, idx) => {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
<!-- Why Choose Us Tab -->
|
<!-- Why Choose Us Tab -->
|
||||||
<div class="tab-pane fade" id="whychooseus" role="tabpanel">
|
<div class="tab-pane fade" id="whychooseus" role="tabpanel">
|
||||||
<div class="row g-4">
|
<div class="row g-4">
|
||||||
<!-- Basic Info -->
|
<!-- Basic Info -->
|
||||||
@@ -206,7 +206,7 @@
|
|||||||
window.homeScrapers = window.homeScrapers || {};
|
window.homeScrapers = window.homeScrapers || {};
|
||||||
window.homeScrapers.whyChooseUs = () => {
|
window.homeScrapers.whyChooseUs = () => {
|
||||||
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
const getVal = (id) => (document.getElementById(id)?.value || "").trim();
|
||||||
const enabled = document.getElementById("whyChooseUsEnabled")?.checked !== false;
|
const enabled = document.getElementById("whyChooseUsEnabled")?.checked === true;
|
||||||
|
|
||||||
// Collect items
|
// Collect items
|
||||||
const items = [];
|
const items = [];
|
||||||
|
|||||||
Reference in New Issue
Block a user