first commit

This commit is contained in:
r2xrzh9q2z-lab
2026-02-02 11:07:09 +07:00
commit d1b931d547
286 changed files with 53992 additions and 0 deletions

View 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 };