forked from UKSOURCE/cms.hailearning.edu.vn
first commit
This commit is contained in:
308
scripts/2025_12_10_120047_terms.js
Normal file
308
scripts/2025_12_10_120047_terms.js
Normal file
@@ -0,0 +1,308 @@
|
||||
require('dotenv').config();
|
||||
const fs = require('fs').promises;
|
||||
const path = require('path');
|
||||
const connectDB = require('../config/database');
|
||||
const Terms = require('../models/terms');
|
||||
const mongoose = require('mongoose');
|
||||
|
||||
/**
|
||||
* Migration: terms
|
||||
* Migrate Terms & Conditions data từ terms-conditions.json
|
||||
* Đã sửa để phù hợp với cấu trúc mới: hero, page, content
|
||||
* Created: 12:00:47 10/12/2025
|
||||
*/
|
||||
async function migrate() {
|
||||
try {
|
||||
// Kết nối database
|
||||
await connectDB();
|
||||
console.log('Starting migration: terms...');
|
||||
|
||||
// Đọc file terms-conditions.json
|
||||
const termsJsonPath = path.join(__dirname, '../data/terms-conditions.json');
|
||||
console.log('Reading JSON file from:', termsJsonPath);
|
||||
|
||||
const termsData = JSON.parse(await fs.readFile(termsJsonPath, 'utf8'));
|
||||
console.log('Terms data loaded successfully');
|
||||
console.log('Data structure keys:', Object.keys(termsData));
|
||||
|
||||
// Kiểm tra cấu trúc và gọi method phù hợp
|
||||
if (termsData.hero && termsData.page && termsData.content) {
|
||||
// Cấu trúc mới - sử dụng migrateFromNewJson
|
||||
console.log('Detected new structure, using migrateFromNewJson...');
|
||||
if (typeof Terms.migrateFromNewJson === 'function') {
|
||||
await Terms.migrateFromNewJson(termsData);
|
||||
console.log('Migration completed using migrateFromNewJson method');
|
||||
} else {
|
||||
console.log('migrateFromNewJson not found, using custom logic...');
|
||||
await migrateTermsData(termsData);
|
||||
}
|
||||
} else if (termsData.hero && termsData.termsHeader && termsData.sections) {
|
||||
// Cấu trúc cũ - sử dụng migrateFromJson
|
||||
console.log('Detected old structure, using migrateFromJson...');
|
||||
if (typeof Terms.migrateFromJson === 'function') {
|
||||
await Terms.migrateFromJson(termsData);
|
||||
console.log('Migration completed using migrateFromJson method');
|
||||
} else {
|
||||
await migrateTermsData(termsData);
|
||||
}
|
||||
} else {
|
||||
// Không xác định được cấu trúc
|
||||
console.error('Unknown data structure. Keys:', Object.keys(termsData));
|
||||
throw new Error('Unknown terms data structure');
|
||||
}
|
||||
|
||||
console.log('Terms migration completed successfully!');
|
||||
|
||||
await mongoose.disconnect();
|
||||
process.exit(0);
|
||||
} catch (error) {
|
||||
console.error('Migration error:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom migration logic cho terms data với cấu trúc mới
|
||||
* Chỉ có 3 phần: hero, page, content
|
||||
*/
|
||||
async function migrateTermsData(termsData) {
|
||||
try {
|
||||
console.log('Starting custom migration logic with new structure...');
|
||||
|
||||
// 1. Xóa dữ liệu cũ (tùy chọn)
|
||||
const existingTerms = await Terms.find({});
|
||||
if (existingTerms.length > 0) {
|
||||
console.log(`Found ${existingTerms.length} existing terms documents`);
|
||||
// Có thể bỏ comment để xóa dữ liệu cũ nếu cần
|
||||
// await Terms.deleteMany({});
|
||||
// console.log('Cleared existing terms data');
|
||||
}
|
||||
|
||||
// 2. Chuyển đổi từ cấu trúc cũ sang cấu trúc mới nếu cần
|
||||
let heroData, pageData, contentData;
|
||||
|
||||
// Kiểm tra xem data có cấu trúc cũ hay mới
|
||||
if (termsData.hero && termsData.page && termsData.content) {
|
||||
// Đây là cấu trúc mới, sử dụng trực tiếp
|
||||
console.log('Using new structure (hero, page, content)');
|
||||
heroData = termsData.hero;
|
||||
pageData = termsData.page;
|
||||
contentData = termsData.content;
|
||||
|
||||
// Debug: kiểm tra content data
|
||||
console.log('contentData keys:', Object.keys(contentData));
|
||||
console.log('contentData.content exists?', !!contentData.content);
|
||||
console.log('contentData.content length:', contentData.content ? contentData.content.length : 0);
|
||||
if (contentData.content && contentData.content.length > 0) {
|
||||
console.log('First content item type:', contentData.content[0].type);
|
||||
}
|
||||
} else if (termsData.hero && termsData.termsHeader && termsData.sections) {
|
||||
// Đây là cấu trúc cũ, cần chuyển đổi sang cấu trúc mới
|
||||
console.log('Converting from old structure to new structure...');
|
||||
heroData = termsData.hero;
|
||||
pageData = convertOldPageToNew(termsData);
|
||||
contentData = convertOldSectionsToNew(termsData);
|
||||
} else {
|
||||
throw new Error('Unknown terms data structure');
|
||||
}
|
||||
|
||||
// 3. Tạo document mới cho terms
|
||||
const termsDocument = new Terms({
|
||||
version: '2.0.0', // Tăng version vì cấu trúc thay đổi
|
||||
language: 'en',
|
||||
|
||||
// Cấu trúc mới chỉ có 3 phần chính
|
||||
hero: {
|
||||
title: heroData.title,
|
||||
backgroundImage: heroData.backgroundImage,
|
||||
sectionClass: heroData.sectionClass || 'uk-section-default uk-section-overlap uk-preserve-color uk-light uk-position-relative',
|
||||
backgroundClasses: heroData.backgroundClasses || 'uk-background-norepeat uk-background-cover uk-background-top-center uk-section uk-section-xlarge',
|
||||
overlayStyle: heroData.overlayStyle || { backgroundColor: 'rgba(0, 0, 0, 0)' },
|
||||
titleClass: heroData.titleClass || 'text-white text-[5vw] uk-text-center',
|
||||
enableScrollspy: heroData.enableScrollspy !== undefined ? heroData.enableScrollspy : true
|
||||
},
|
||||
|
||||
page: {
|
||||
title: pageData.title,
|
||||
divider: pageData.divider !== undefined ? pageData.divider : true,
|
||||
sectionClass: pageData.sectionClass || 'uk-section-default uk-section-overlap uk-section',
|
||||
titleClass: pageData.titleClass || 'text-[2.5vw] text-[#292c3d] uk-text-left@m uk-text-center',
|
||||
dividerClass: pageData.dividerClass || 'uk-divider-small uk-text-left@m uk-text-center'
|
||||
},
|
||||
|
||||
content: {
|
||||
sectionClass: contentData.sectionClass || 'uk-section-muted uk-section-overlap uk-section',
|
||||
textClass: contentData.textClass || 'uk-panel uk-margin text-[1vw]',
|
||||
content: contentData.content || []
|
||||
},
|
||||
|
||||
// Metadata
|
||||
createdAt: new Date(),
|
||||
updatedAt: new Date(),
|
||||
isActive: true,
|
||||
migratedFromOldStructure: !termsData.content // Đánh dấu nếu được chuyển từ cấu trúc cũ
|
||||
});
|
||||
|
||||
// 4. Lưu vào database
|
||||
await termsDocument.save();
|
||||
console.log('Terms document saved successfully with new structure');
|
||||
|
||||
// 5. Log thông tin
|
||||
console.log(`Created terms document with ID: ${termsDocument._id}`);
|
||||
console.log(`Hero title: ${termsDocument.hero.title}`);
|
||||
console.log(`Page title: ${termsDocument.page.title}`);
|
||||
console.log(`Content items count: ${termsDocument.content.content.length}`);
|
||||
|
||||
// 6. Tạo thêm bản German nếu có
|
||||
const germanJsonPath = path.join(__dirname, '../data/terms-conditions.de.json');
|
||||
try {
|
||||
const germanData = JSON.parse(await fs.readFile(germanJsonPath, 'utf8'));
|
||||
|
||||
// Xác định cấu trúc của German data
|
||||
let germanHero, germanPage, germanContent;
|
||||
|
||||
if (germanData.hero && germanData.page && germanData.content) {
|
||||
germanHero = germanData.hero;
|
||||
germanPage = germanData.page;
|
||||
germanContent = germanData.content;
|
||||
} else if (germanData.hero && germanData.termsHeader && germanData.sections) {
|
||||
germanHero = germanData.hero;
|
||||
germanPage = convertOldPageToNew(germanData);
|
||||
germanContent = convertOldSectionsToNew(germanData);
|
||||
}
|
||||
|
||||
const germanTerms = new Terms({
|
||||
...termsDocument.toObject(),
|
||||
_id: new mongoose.Types.ObjectId(), // Tạo ID mới
|
||||
language: 'de',
|
||||
hero: {
|
||||
...termsDocument.hero,
|
||||
title: germanHero.title || termsDocument.hero.title
|
||||
},
|
||||
page: {
|
||||
...termsDocument.page,
|
||||
title: germanPage.title || termsDocument.page.title
|
||||
},
|
||||
content: {
|
||||
...termsDocument.content,
|
||||
content: germanContent.content || termsDocument.content.content
|
||||
},
|
||||
isActive: true
|
||||
});
|
||||
|
||||
await germanTerms.save();
|
||||
console.log('German terms document created successfully');
|
||||
} catch (error) {
|
||||
console.log('German version not found or error:', error.message);
|
||||
console.log('Continuing with English version only...');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error in migrateTermsData:', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Chuyển đổi từ cấu trúc page cũ sang cấu trúc page mới
|
||||
*/
|
||||
function convertOldPageToNew(oldData) {
|
||||
return {
|
||||
title: oldData.termsHeader?.title || 'Terms & Conditions',
|
||||
divider: oldData.termsHeader?.divider !== false,
|
||||
sectionClass: oldData.termsHeader?.sectionClass || 'uk-section-default uk-section-overlap uk-section',
|
||||
titleClass: oldData.termsHeader?.titleClass || 'text-[2.5vw] text-[#292c3d] uk-text-left@m uk-text-center',
|
||||
dividerClass: oldData.termsHeader?.dividerClass || 'uk-divider-small uk-text-left@m uk-text-center'
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Chuyển đổi từ cấu trúc sections cũ sang cấu trúc content mới
|
||||
*/
|
||||
function convertOldSectionsToNew(oldData) {
|
||||
const contentItems = [];
|
||||
|
||||
// Thêm disclaimer đầu tiên nếu có
|
||||
if (oldData.disclaimer?.text) {
|
||||
contentItems.push({
|
||||
type: 'paragraph',
|
||||
text: oldData.disclaimer.text
|
||||
});
|
||||
}
|
||||
|
||||
// Thêm các sections
|
||||
if (oldData.sections && Array.isArray(oldData.sections)) {
|
||||
oldData.sections.forEach(section => {
|
||||
if (section.title && section.content) {
|
||||
const contentItem = {
|
||||
type: 'section',
|
||||
title: section.title,
|
||||
content: section.content
|
||||
};
|
||||
|
||||
// Thêm subsections nếu có
|
||||
if (section.subsections && section.subsections.length > 0) {
|
||||
contentItem.subsections = section.subsections.map(sub => ({
|
||||
type: 'note',
|
||||
text: sub
|
||||
}));
|
||||
}
|
||||
|
||||
// Thêm cancellation table nếu có
|
||||
if (section.fees) {
|
||||
contentItem.subsections = contentItem.subsections || [];
|
||||
contentItem.subsections.push({
|
||||
type: 'cancellation_table',
|
||||
title: 'Standard Cancellation Fees',
|
||||
items: Object.entries(section.fees).map(([key, value]) => `${key}: ${value}`)
|
||||
});
|
||||
}
|
||||
|
||||
contentItems.push(contentItem);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Thêm footer note nếu có
|
||||
if (oldData.footerNote?.text) {
|
||||
contentItems.push({
|
||||
type: 'paragraph',
|
||||
text: oldData.footerNote.text
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
sectionClass: oldData.layout?.termsSectionClass || 'uk-section-muted uk-section-overlap uk-section',
|
||||
textClass: oldData.layout?.textContentClass || 'uk-panel uk-margin text-[1vw]',
|
||||
content: contentItems
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Hàm backup data trước khi migration
|
||||
*/
|
||||
async function backupExistingData() {
|
||||
try {
|
||||
console.log('Creating backup of existing terms data...');
|
||||
const existingTerms = await Terms.find({});
|
||||
|
||||
if (existingTerms.length > 0) {
|
||||
const backupPath = path.join(__dirname, '../backups/terms-backup-' + Date.now() + '.json');
|
||||
|
||||
// Tạo thư mục backup nếu chưa có
|
||||
await fs.mkdir(path.dirname(backupPath), { recursive: true });
|
||||
|
||||
await fs.writeFile(backupPath, JSON.stringify(existingTerms, null, 2));
|
||||
console.log(`Backup created at: ${backupPath}`);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Backup error:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Chạy migration nếu được gọi trực tiếp
|
||||
if (require.main === module) {
|
||||
migrate();
|
||||
}
|
||||
|
||||
module.exports = { migrate, migrateTermsData };
|
||||
Reference in New Issue
Block a user