миграция
This commit is contained in:
@@ -2,6 +2,7 @@ const express = require('express');
|
|||||||
const cors = require('cors');
|
const cors = require('cors');
|
||||||
const dotenv = require('dotenv');
|
const dotenv = require('dotenv');
|
||||||
const connectDB = require('./config/db');
|
const connectDB = require('./config/db');
|
||||||
|
const { runMigrations } = require('./scripts/run-migrations');
|
||||||
|
|
||||||
// Загрузить переменные окружения
|
// Загрузить переменные окружения
|
||||||
dotenv.config();
|
dotenv.config();
|
||||||
@@ -29,11 +30,32 @@ const homeRoutes = require('./routes/home');
|
|||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
// Подключить MongoDB при инициализации
|
// Подключить MongoDB и запустить миграции при инициализации
|
||||||
let dbConnected = false;
|
let dbConnected = false;
|
||||||
connectDB().then(() => {
|
let migrationsCompleted = false;
|
||||||
dbConnected = true;
|
|
||||||
});
|
const initializeApp = async () => {
|
||||||
|
try {
|
||||||
|
await connectDB().then(() => {
|
||||||
|
dbConnected = true;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Запустить миграции после успешного подключения
|
||||||
|
if (dbConnected) {
|
||||||
|
try {
|
||||||
|
await runMigrations();
|
||||||
|
migrationsCompleted = true;
|
||||||
|
} catch (migrationError) {
|
||||||
|
console.error('⚠️ Migrations failed but app will continue:', migrationError.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Error during app initialization:', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Запустить инициализацию
|
||||||
|
initializeApp();
|
||||||
|
|
||||||
// Middleware
|
// Middleware
|
||||||
app.use(cors());
|
app.use(cors());
|
||||||
@@ -68,6 +90,7 @@ app.get('/health', (req, res) => {
|
|||||||
status: 'ok',
|
status: 'ok',
|
||||||
api: 'running',
|
api: 'running',
|
||||||
database: dbConnected ? 'mongodb' : 'mock',
|
database: dbConnected ? 'mongodb' : 'mock',
|
||||||
|
migrations: migrationsCompleted ? 'completed' : 'pending',
|
||||||
timestamp: new Date().toISOString()
|
timestamp: new Date().toISOString()
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -127,8 +127,14 @@ router.get('/', verifyToken, async (req, res) => {
|
|||||||
log('[Search] Industry codes:', industryList, 'Mapped to:', dbIndustries);
|
log('[Search] Industry codes:', industryList, 'Mapped to:', dbIndustries);
|
||||||
|
|
||||||
if (dbIndustries.length > 0) {
|
if (dbIndustries.length > 0) {
|
||||||
filters.push({ industry: { $in: dbIndustries } });
|
// Handle both string and array industry values
|
||||||
log('[Search] Added industry filter:', { industry: { $in: dbIndustries } });
|
filters.push({
|
||||||
|
$or: [
|
||||||
|
{ industry: { $in: dbIndustries } },
|
||||||
|
{ industry: { $elemMatch: { $in: dbIndustries } } }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
log('[Search] Added industry filter:', { $or: [{ industry: { $in: dbIndustries } }, { industry: { $elemMatch: { $in: dbIndustries } } }] });
|
||||||
} else {
|
} else {
|
||||||
log('[Search] No industries mapped! Codes were:', industryList);
|
log('[Search] No industries mapped! Codes were:', industryList);
|
||||||
}
|
}
|
||||||
@@ -213,8 +219,10 @@ router.get('/', verifyToken, async (req, res) => {
|
|||||||
page: pageNum,
|
page: pageNum,
|
||||||
totalPages: Math.ceil(total / limitNum),
|
totalPages: Math.ceil(total / limitNum),
|
||||||
_debug: {
|
_debug: {
|
||||||
|
requestParams: { query, industries, companySize, geography, minRating, hasReviews, hasAcceptedDocs, sortBy, sortOrder },
|
||||||
filter: JSON.stringify(filter),
|
filter: JSON.stringify(filter),
|
||||||
industriesReceived: industries
|
filtersCount: filters.length,
|
||||||
|
appliedFilters: filters.map(f => JSON.stringify(f))
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|||||||
74
server/routers/procurement/scripts/init-database.js
Normal file
74
server/routers/procurement/scripts/init-database.js
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
const mongoose = require('mongoose');
|
||||||
|
const { migrateCompanies } = require('./migrate-companies');
|
||||||
|
require('dotenv').config({ path: '../../.env' });
|
||||||
|
|
||||||
|
const mongoUrl = process.env.MONGODB_URI || 'mongodb://localhost:27017/procurement_db';
|
||||||
|
|
||||||
|
// Migration history model
|
||||||
|
const migrationSchema = new mongoose.Schema({
|
||||||
|
name: { type: String, unique: true, required: true },
|
||||||
|
executedAt: { type: Date, default: Date.now },
|
||||||
|
status: { type: String, enum: ['completed', 'failed'], default: 'completed' },
|
||||||
|
message: String
|
||||||
|
}, { collection: 'migrations' });
|
||||||
|
|
||||||
|
const Migration = mongoose.model('Migration', migrationSchema);
|
||||||
|
|
||||||
|
async function initializeDatabase() {
|
||||||
|
try {
|
||||||
|
console.log('[Init] Connecting to MongoDB...');
|
||||||
|
await mongoose.connect(mongoUrl, {
|
||||||
|
useNewUrlParser: true,
|
||||||
|
useUnifiedTopology: true,
|
||||||
|
serverSelectionTimeoutMS: 5000,
|
||||||
|
connectTimeoutMS: 5000,
|
||||||
|
});
|
||||||
|
console.log('[Init] Connected to MongoDB\n');
|
||||||
|
|
||||||
|
// Check if migrations already ran
|
||||||
|
const migrateCompaniesRan = await Migration.findOne({ name: 'migrate-companies' });
|
||||||
|
|
||||||
|
if (!migrateCompaniesRan) {
|
||||||
|
console.log('[Init] Running migrate-companies migration...');
|
||||||
|
try {
|
||||||
|
await migrateCompanies();
|
||||||
|
|
||||||
|
// Record successful migration
|
||||||
|
await Migration.create({
|
||||||
|
name: 'migrate-companies',
|
||||||
|
status: 'completed',
|
||||||
|
message: 'Company data migration completed successfully'
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log('[Init] ✅ migrate-companies recorded in database\n');
|
||||||
|
} catch (err) {
|
||||||
|
// Record failed migration
|
||||||
|
await Migration.create({
|
||||||
|
name: 'migrate-companies',
|
||||||
|
status: 'failed',
|
||||||
|
message: err.message
|
||||||
|
});
|
||||||
|
console.error('[Init] ❌ migrate-companies failed:', err.message);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('[Init] ℹ️ migrate-companies already executed:', migrateCompaniesRan.executedAt);
|
||||||
|
console.log('[Init] Skipping migration...\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
await mongoose.connection.close();
|
||||||
|
console.log('[Init] Database initialization complete\n');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[Init] ❌ Error during database initialization:', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = initializeDatabase;
|
||||||
|
|
||||||
|
// Run directly if called as script
|
||||||
|
if (require.main === module) {
|
||||||
|
initializeDatabase().catch(err => {
|
||||||
|
console.error('Initialization failed:', err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
124
server/routers/procurement/scripts/migrate-companies.js
Normal file
124
server/routers/procurement/scripts/migrate-companies.js
Normal file
@@ -0,0 +1,124 @@
|
|||||||
|
const mongoose = require('mongoose');
|
||||||
|
const Company = require('../models/Company');
|
||||||
|
require('dotenv').config({ path: '../../.env' });
|
||||||
|
|
||||||
|
const industryMap = {
|
||||||
|
'it': 'IT',
|
||||||
|
'finance': 'Финансы',
|
||||||
|
'manufacturing': 'Производство',
|
||||||
|
'construction': 'Строительство',
|
||||||
|
'retail': 'Розничная торговля',
|
||||||
|
'wholesale': 'Оптовая торговля',
|
||||||
|
'logistics': 'Логистика',
|
||||||
|
'healthcare': 'Здравоохранение',
|
||||||
|
'education': 'Образование',
|
||||||
|
'consulting': 'Консалтинг',
|
||||||
|
'marketing': 'Маркетинг',
|
||||||
|
'realestate': 'Недвижимость',
|
||||||
|
'food': 'Пищевая промышленность',
|
||||||
|
'agriculture': 'Сельское хозяйство',
|
||||||
|
'energy': 'Энергетика',
|
||||||
|
'telecom': 'Телекоммуникации',
|
||||||
|
'media': 'Медиа',
|
||||||
|
'tourism': 'Туризм',
|
||||||
|
'legal': 'Юридические услуги',
|
||||||
|
'other': 'Другое'
|
||||||
|
};
|
||||||
|
|
||||||
|
const validIndustries = Object.values(industryMap);
|
||||||
|
|
||||||
|
const industryAliases = {
|
||||||
|
'Торговля': 'Розничная торговля',
|
||||||
|
'торговля': 'Розничная торговля',
|
||||||
|
'Trade': 'Розничная торговля'
|
||||||
|
};
|
||||||
|
|
||||||
|
async function migrateCompanies() {
|
||||||
|
try {
|
||||||
|
const allCompanies = await Company.find().exec();
|
||||||
|
console.log(`[Migration] Found ${allCompanies.length} companies to process`);
|
||||||
|
|
||||||
|
let fixedCount = 0;
|
||||||
|
let errorCount = 0;
|
||||||
|
|
||||||
|
for (const company of allCompanies) {
|
||||||
|
let needsUpdate = false;
|
||||||
|
let updates = {};
|
||||||
|
|
||||||
|
// Check and fix industry field
|
||||||
|
if (company.industry) {
|
||||||
|
if (Array.isArray(company.industry)) {
|
||||||
|
console.log(`[FIX] ${company.fullName}: industry is array, converting to string`);
|
||||||
|
updates.industry = company.industry[0] || 'Другое';
|
||||||
|
needsUpdate = true;
|
||||||
|
} else if (!validIndustries.includes(company.industry)) {
|
||||||
|
const mapped = industryAliases[company.industry];
|
||||||
|
if (mapped) {
|
||||||
|
console.log(`[FIX] ${company.fullName}: "${company.industry}" → "${mapped}"`);
|
||||||
|
updates.industry = mapped;
|
||||||
|
needsUpdate = true;
|
||||||
|
} else {
|
||||||
|
console.log(`[WARN] ${company.fullName}: unknown industry "${company.industry}"`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check and fix companySize field
|
||||||
|
if (company.companySize && Array.isArray(company.companySize)) {
|
||||||
|
console.log(`[FIX] ${company.fullName}: companySize is array, converting to string`);
|
||||||
|
updates.companySize = company.companySize[0] || '';
|
||||||
|
needsUpdate = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needsUpdate) {
|
||||||
|
try {
|
||||||
|
await Company.updateOne({ _id: company._id }, { $set: updates });
|
||||||
|
fixedCount++;
|
||||||
|
console.log(` ✅ Updated`);
|
||||||
|
} catch (err) {
|
||||||
|
console.error(` ❌ Error: ${err.message}`);
|
||||||
|
errorCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n[Migration] === MIGRATION SUMMARY ===');
|
||||||
|
console.log(`[Migration] Total companies: ${allCompanies.length}`);
|
||||||
|
console.log(`[Migration] Fixed: ${fixedCount}`);
|
||||||
|
console.log(`[Migration] Errors: ${errorCount}`);
|
||||||
|
|
||||||
|
if (fixedCount === 0 && errorCount === 0) {
|
||||||
|
console.log('[Migration] ✅ No migration needed - all data is valid!');
|
||||||
|
} else if (errorCount === 0) {
|
||||||
|
console.log('[Migration] ✅ Migration completed successfully!');
|
||||||
|
} else {
|
||||||
|
console.log('[Migration] ⚠️ Migration completed with errors.');
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[Migration] ❌ Error:', err.message);
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
migrateCompanies: migrateCompanies
|
||||||
|
};
|
||||||
|
|
||||||
|
// Run directly if called as script
|
||||||
|
if (require.main === module) {
|
||||||
|
const mongoUrl = process.env.MONGODB_URI || 'mongodb://admin:password@localhost:27017/procurement_db?authSource=admin';
|
||||||
|
|
||||||
|
mongoose.connect(mongoUrl, {
|
||||||
|
useNewUrlParser: true,
|
||||||
|
useUnifiedTopology: true,
|
||||||
|
serverSelectionTimeoutMS: 5000,
|
||||||
|
connectTimeoutMS: 5000,
|
||||||
|
}).then(async () => {
|
||||||
|
console.log('[Migration] Connected to MongoDB\n');
|
||||||
|
await migrateCompanies();
|
||||||
|
await mongoose.connection.close();
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('[Migration] ❌ Error:', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -86,8 +86,16 @@ async function migrateMessages() {
|
|||||||
console.log('[Migration] Disconnected from MongoDB');
|
console.log('[Migration] Disconnected from MongoDB');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error('[Migration] ❌ Error:', err.message);
|
console.error('[Migration] ❌ Error:', err.message);
|
||||||
process.exit(1);
|
throw err;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
migrateMessages();
|
module.exports = { migrateMessages };
|
||||||
|
|
||||||
|
// Run directly if called as script
|
||||||
|
if (require.main === module) {
|
||||||
|
migrateMessages().catch(err => {
|
||||||
|
console.error('Migration failed:', err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|||||||
@@ -7,32 +7,25 @@ const Company = require('../models/Company');
|
|||||||
|
|
||||||
const recreateTestUser = async () => {
|
const recreateTestUser = async () => {
|
||||||
try {
|
try {
|
||||||
const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/procurement_db';
|
console.log('[Migration] Processing test user creation...');
|
||||||
|
|
||||||
console.log('\n🔄 Подключение к MongoDB...');
|
|
||||||
await mongoose.connect(mongoUri, {
|
|
||||||
useNewUrlParser: true,
|
|
||||||
useUnifiedTopology: true,
|
|
||||||
});
|
|
||||||
console.log('✅ Подключено к MongoDB\n');
|
|
||||||
|
|
||||||
// Удалить старого тестового пользователя
|
// Удалить старого тестового пользователя
|
||||||
console.log('🗑️ Удаление старого тестового пользователя...');
|
console.log('[Migration] Removing old test user...');
|
||||||
const oldUser = await User.findOne({ email: 'admin@test-company.ru' });
|
const oldUser = await User.findOne({ email: 'admin@test-company.ru' });
|
||||||
if (oldUser) {
|
if (oldUser) {
|
||||||
// Удалить связанную компанию
|
// Удалить связанную компанию
|
||||||
if (oldUser.companyId) {
|
if (oldUser.companyId) {
|
||||||
await Company.findByIdAndDelete(oldUser.companyId);
|
await Company.findByIdAndDelete(oldUser.companyId);
|
||||||
console.log(' ✓ Старая компания удалена');
|
console.log('[Migration] ✓ Old company removed');
|
||||||
}
|
}
|
||||||
await User.findByIdAndDelete(oldUser._id);
|
await User.findByIdAndDelete(oldUser._id);
|
||||||
console.log(' ✓ Старый пользователь удален');
|
console.log('[Migration] ✓ Old user removed');
|
||||||
} else {
|
} else {
|
||||||
console.log(' ℹ️ Старый пользователь не найден');
|
console.log('[Migration] ℹ️ Old user not found');
|
||||||
}
|
}
|
||||||
|
|
||||||
// Создать новую компанию с правильной кодировкой UTF-8
|
// Создать новую компанию с правильной кодировкой UTF-8
|
||||||
console.log('\n🏢 Создание тестовой компании...');
|
console.log('[Migration] Creating test company...');
|
||||||
const company = await Company.create({
|
const company = await Company.create({
|
||||||
fullName: 'ООО "Тестовая Компания"',
|
fullName: 'ООО "Тестовая Компания"',
|
||||||
inn: '1234567890',
|
inn: '1234567890',
|
||||||
@@ -47,10 +40,10 @@ const recreateTestUser = async () => {
|
|||||||
reviewsCount: 10,
|
reviewsCount: 10,
|
||||||
dealsCount: 25,
|
dealsCount: 25,
|
||||||
});
|
});
|
||||||
console.log(' ✓ Компания создана:', company.fullName);
|
console.log('[Migration] ✓ Company created:', company.fullName);
|
||||||
|
|
||||||
// Создать нового пользователя с правильной кодировкой UTF-8
|
// Создать нового пользователя с правильной кодировкой UTF-8
|
||||||
console.log('\n👤 Создание тестового пользователя...');
|
console.log('[Migration] Creating test user...');
|
||||||
const user = await User.create({
|
const user = await User.create({
|
||||||
email: 'admin@test-company.ru',
|
email: 'admin@test-company.ru',
|
||||||
password: 'SecurePass123!',
|
password: 'SecurePass123!',
|
||||||
@@ -60,24 +53,10 @@ const recreateTestUser = async () => {
|
|||||||
phone: '+7 (999) 123-45-67',
|
phone: '+7 (999) 123-45-67',
|
||||||
companyId: company._id,
|
companyId: company._id,
|
||||||
});
|
});
|
||||||
console.log(' ✓ Пользователь создан:', user.firstName, user.lastName);
|
console.log('[Migration] ✓ User created:', user.firstName, user.lastName);
|
||||||
|
|
||||||
// Проверка что данные сохранены правильно
|
|
||||||
console.log('\n✅ Проверка данных:');
|
|
||||||
console.log(' Email:', user.email);
|
|
||||||
console.log(' Имя:', user.firstName);
|
|
||||||
console.log(' Фамилия:', user.lastName);
|
|
||||||
console.log(' Компания:', company.fullName);
|
|
||||||
console.log(' Должность:', user.position);
|
|
||||||
|
|
||||||
console.log('\n✅ ГОТОВО! Тестовый пользователь создан с правильной кодировкой UTF-8');
|
|
||||||
console.log('\n📋 Данные для входа:');
|
|
||||||
console.log(' Email: admin@test-company.ru');
|
|
||||||
console.log(' Пароль: SecurePass123!');
|
|
||||||
console.log('');
|
|
||||||
|
|
||||||
// Обновить существующие mock компании
|
// Обновить существующие mock компании
|
||||||
console.log('\n🔄 Обновление существующих mock компаний...');
|
console.log('[Migration] Updating existing companies...');
|
||||||
const updates = [
|
const updates = [
|
||||||
{ inn: '7707083894', updates: { companySize: '51-250', partnerGeography: ['moscow', 'russia_all'] } },
|
{ inn: '7707083894', updates: { companySize: '51-250', partnerGeography: ['moscow', 'russia_all'] } },
|
||||||
{ inn: '7707083895', updates: { companySize: '500+', partnerGeography: ['moscow', 'russia_all'] } },
|
{ inn: '7707083895', updates: { companySize: '500+', partnerGeography: ['moscow', 'russia_all'] } },
|
||||||
@@ -88,18 +67,33 @@ const recreateTestUser = async () => {
|
|||||||
|
|
||||||
for (const item of updates) {
|
for (const item of updates) {
|
||||||
await Company.updateOne({ inn: item.inn }, { $set: item.updates });
|
await Company.updateOne({ inn: item.inn }, { $set: item.updates });
|
||||||
console.log(` ✓ Компания обновлена: INN ${item.inn}`);
|
console.log(`[Migration] ✓ Company updated: INN ${item.inn}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
await mongoose.connection.close();
|
console.log('[Migration] ✅ Test user migration completed!');
|
||||||
process.exit(0);
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('\n❌ Ошибка:', error.message);
|
console.error('[Migration] ❌ Error:', error.message);
|
||||||
console.error(error);
|
throw error;
|
||||||
process.exit(1);
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Запуск
|
module.exports = { recreateTestUser };
|
||||||
recreateTestUser();
|
|
||||||
|
// Run directly if called as script
|
||||||
|
if (require.main === module) {
|
||||||
|
const mongoUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/procurement_db';
|
||||||
|
|
||||||
|
mongoose.connect(mongoUri, {
|
||||||
|
useNewUrlParser: true,
|
||||||
|
useUnifiedTopology: true,
|
||||||
|
}).then(async () => {
|
||||||
|
console.log('[Migration] Connected to MongoDB\n');
|
||||||
|
await recreateTestUser();
|
||||||
|
await mongoose.connection.close();
|
||||||
|
process.exit(0);
|
||||||
|
}).catch(err => {
|
||||||
|
console.error('[Migration] ❌ Error:', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
105
server/routers/procurement/scripts/run-migrations.js
Normal file
105
server/routers/procurement/scripts/run-migrations.js
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
const mongoose = require('mongoose');
|
||||||
|
const { migrateCompanies } = require('./migrate-companies');
|
||||||
|
const { migrateMessages } = require('./migrate-messages');
|
||||||
|
const { recreateTestUser } = require('./recreate-test-user');
|
||||||
|
require('dotenv').config();
|
||||||
|
|
||||||
|
const mongoUrl = process.env.MONGODB_URI || 'mongodb://localhost:27017/procurement_db';
|
||||||
|
|
||||||
|
// Migration history model
|
||||||
|
const migrationSchema = new mongoose.Schema({
|
||||||
|
name: { type: String, unique: true, required: true },
|
||||||
|
executedAt: { type: Date, default: Date.now },
|
||||||
|
status: { type: String, enum: ['completed', 'failed'], default: 'completed' },
|
||||||
|
message: String
|
||||||
|
}, { collection: 'migrations' });
|
||||||
|
|
||||||
|
const Migration = mongoose.model('Migration', migrationSchema);
|
||||||
|
|
||||||
|
const migrations = [
|
||||||
|
{ name: 'migrate-companies', fn: migrateCompanies },
|
||||||
|
{ name: 'migrate-messages', fn: migrateMessages },
|
||||||
|
{ name: 'recreate-test-user', fn: recreateTestUser }
|
||||||
|
];
|
||||||
|
|
||||||
|
async function runMigrations() {
|
||||||
|
let mongooseConnected = false;
|
||||||
|
|
||||||
|
try {
|
||||||
|
console.log('\n' + '='.repeat(60));
|
||||||
|
console.log('🚀 Starting Database Migrations');
|
||||||
|
console.log('='.repeat(60) + '\n');
|
||||||
|
|
||||||
|
console.log('[Migrations] Connecting to MongoDB...');
|
||||||
|
await mongoose.connect(mongoUrl, {
|
||||||
|
useNewUrlParser: true,
|
||||||
|
useUnifiedTopology: true,
|
||||||
|
serverSelectionTimeoutMS: 5000,
|
||||||
|
connectTimeoutMS: 5000,
|
||||||
|
});
|
||||||
|
mongooseConnected = true;
|
||||||
|
console.log('[Migrations] ✅ Connected to MongoDB\n');
|
||||||
|
|
||||||
|
for (const migration of migrations) {
|
||||||
|
console.log(`[${migration.name}] Starting...`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Check if already executed
|
||||||
|
const existing = await Migration.findOne({ name: migration.name });
|
||||||
|
|
||||||
|
if (existing) {
|
||||||
|
console.log(`[${migration.name}] ℹ️ Already executed at: ${existing.executedAt.toISOString()}`);
|
||||||
|
console.log(`[${migration.name}] Status: ${existing.status}`);
|
||||||
|
if (existing.message) console.log(`[${migration.name}] Message: ${existing.message}`);
|
||||||
|
console.log('');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run migration
|
||||||
|
await migration.fn();
|
||||||
|
|
||||||
|
// Record successful migration
|
||||||
|
await Migration.create({
|
||||||
|
name: migration.name,
|
||||||
|
status: 'completed',
|
||||||
|
message: `${migration.name} executed successfully`
|
||||||
|
});
|
||||||
|
|
||||||
|
console.log(`[${migration.name}] ✅ Completed and recorded\n`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`[${migration.name}] ❌ Error: ${error.message}\n`);
|
||||||
|
|
||||||
|
// Record failed migration
|
||||||
|
await Migration.create({
|
||||||
|
name: migration.name,
|
||||||
|
status: 'failed',
|
||||||
|
message: error.message
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('='.repeat(60));
|
||||||
|
console.log('✅ All migrations processed');
|
||||||
|
console.log('='.repeat(60) + '\n');
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error('\n❌ Fatal migration error:', error.message);
|
||||||
|
console.error(error);
|
||||||
|
process.exit(1);
|
||||||
|
} finally {
|
||||||
|
if (mongooseConnected) {
|
||||||
|
await mongoose.connection.close();
|
||||||
|
console.log('[Migrations] Disconnected from MongoDB\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = { runMigrations, Migration };
|
||||||
|
|
||||||
|
// Run directly if called as script
|
||||||
|
if (require.main === module) {
|
||||||
|
runMigrations().catch(err => {
|
||||||
|
console.error('Migration failed:', err);
|
||||||
|
process.exit(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
#!/usr/bin/env node
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Скрипт для тестирования логирования
|
|
||||||
*
|
|
||||||
* Использование:
|
|
||||||
* node stubs/scripts/test-logging.js # Логи скрыты (DEV не установлена)
|
|
||||||
* DEV=true node stubs/scripts/test-logging.js # Логи видны
|
|
||||||
*/
|
|
||||||
|
|
||||||
// Функция логирования из маршрутов
|
|
||||||
const log = (message, data = '') => {
|
|
||||||
if (process.env.DEV === 'true') {
|
|
||||||
if (data) {
|
|
||||||
console.log(message, data);
|
|
||||||
} else {
|
|
||||||
console.log(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('');
|
|
||||||
console.log('='.repeat(60));
|
|
||||||
console.log('TEST: Логирование с переменной окружения DEV');
|
|
||||||
console.log('='.repeat(60));
|
|
||||||
console.log('');
|
|
||||||
|
|
||||||
console.log('Значение DEV:', process.env.DEV || '(не установлена)');
|
|
||||||
console.log('');
|
|
||||||
|
|
||||||
// Тестируем различные логи
|
|
||||||
log('[Auth] Token verified - userId: 68fe2ccda3526c303ca06799 companyId: 68fe2ccda3526c303ca06796');
|
|
||||||
log('[Auth] Generating token for userId:', '68fe2ccda3526c303ca06799');
|
|
||||||
log('[BuyProducts] Found', 0, 'products for company 68fe2ccda3526c303ca06796');
|
|
||||||
log('[Products] GET Fetching products for companyId:', '68fe2ccda3526c303ca06799');
|
|
||||||
log('[Products] Found', 1, 'products');
|
|
||||||
log('[Reviews] Returned', 0, 'reviews for company 68fe2ccda3526c303ca06796');
|
|
||||||
log('[Messages] Fetching threads for companyId:', '68fe2ccda3526c303ca06796');
|
|
||||||
log('[Messages] Found', 4, 'messages for company');
|
|
||||||
log('[Messages] Returned', 3, 'unique threads');
|
|
||||||
log('[Search] Request params:', { query: '', page: 1 });
|
|
||||||
|
|
||||||
console.log('');
|
|
||||||
console.log('='.repeat(60));
|
|
||||||
console.log('РЕЗУЛЬТАТ:');
|
|
||||||
console.log('='.repeat(60));
|
|
||||||
|
|
||||||
if (process.env.DEV === 'true') {
|
|
||||||
console.log('✅ DEV=true - логи ВИДНЫ выше');
|
|
||||||
} else {
|
|
||||||
console.log('❌ DEV не установлена или != "true" - логи СКРЫТЫ');
|
|
||||||
console.log('');
|
|
||||||
console.log('Для включения логов запустите:');
|
|
||||||
console.log(' export DEV=true && npm start (Linux/Mac)');
|
|
||||||
console.log(' $env:DEV = "true"; npm start (PowerShell)');
|
|
||||||
console.log(' set DEV=true && npm start (CMD)');
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('');
|
|
||||||
console.log('='.repeat(60));
|
|
||||||
console.log('');
|
|
||||||
93
server/routers/procurement/scripts/validate-companies.js
Normal file
93
server/routers/procurement/scripts/validate-companies.js
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
const mongoose = require('mongoose');
|
||||||
|
const Company = require('../models/Company');
|
||||||
|
require('dotenv').config({ path: '../../.env' });
|
||||||
|
|
||||||
|
const mongoUrl = process.env.MONGODB_URI || 'mongodb://admin:password@localhost:27017/procurement_db?authSource=admin';
|
||||||
|
|
||||||
|
const industryMap = {
|
||||||
|
'it': 'IT',
|
||||||
|
'finance': 'Финансы',
|
||||||
|
'manufacturing': 'Производство',
|
||||||
|
'construction': 'Строительство',
|
||||||
|
'retail': 'Розничная торговля',
|
||||||
|
'wholesale': 'Оптовая торговля',
|
||||||
|
'logistics': 'Логистика',
|
||||||
|
'healthcare': 'Здравоохранение',
|
||||||
|
'education': 'Образование',
|
||||||
|
'consulting': 'Консалтинг',
|
||||||
|
'marketing': 'Маркетинг',
|
||||||
|
'realestate': 'Недвижимость',
|
||||||
|
'food': 'Пищевая промышленность',
|
||||||
|
'agriculture': 'Сельское хозяйство',
|
||||||
|
'energy': 'Энергетика',
|
||||||
|
'telecom': 'Телекоммуникации',
|
||||||
|
'media': 'Медиа',
|
||||||
|
'tourism': 'Туризм',
|
||||||
|
'legal': 'Юридические услуги',
|
||||||
|
'other': 'Другое'
|
||||||
|
};
|
||||||
|
|
||||||
|
async function validateCompanies() {
|
||||||
|
try {
|
||||||
|
console.log('[Validation] Connecting to MongoDB...');
|
||||||
|
await mongoose.connect(mongoUrl, {
|
||||||
|
useNewUrlParser: true,
|
||||||
|
useUnifiedTopology: true,
|
||||||
|
serverSelectionTimeoutMS: 5000,
|
||||||
|
connectTimeoutMS: 5000,
|
||||||
|
});
|
||||||
|
console.log('[Validation] Connected to MongoDB\n');
|
||||||
|
|
||||||
|
const allCompanies = await Company.find().exec();
|
||||||
|
console.log(`Found ${allCompanies.length} total companies\n`);
|
||||||
|
|
||||||
|
console.log('=== COMPANY DATA VALIDATION REPORT ===\n');
|
||||||
|
|
||||||
|
let issuesFound = 0;
|
||||||
|
let validCompanies = 0;
|
||||||
|
|
||||||
|
for (const company of allCompanies) {
|
||||||
|
console.log(`📋 Company: ${company.fullName}`);
|
||||||
|
console.log(` ID: ${company._id}`);
|
||||||
|
console.log(` Industry: ${company.industry} (type: ${typeof company.industry})`);
|
||||||
|
console.log(` Company Size: ${company.companySize}`);
|
||||||
|
|
||||||
|
let hasIssues = false;
|
||||||
|
|
||||||
|
if (company.industry) {
|
||||||
|
if (Array.isArray(company.industry)) {
|
||||||
|
console.log(` ⚠️ WARNING: industry is array!`);
|
||||||
|
issuesFound++;
|
||||||
|
hasIssues = true;
|
||||||
|
} else if (!Object.values(industryMap).includes(company.industry)) {
|
||||||
|
console.log(` ⚠️ industry value unknown: "${company.industry}"`);
|
||||||
|
issuesFound++;
|
||||||
|
hasIssues = true;
|
||||||
|
} else {
|
||||||
|
console.log(` ✅ industry OK`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!hasIssues) validCompanies++;
|
||||||
|
console.log('');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('\n=== SUMMARY ===');
|
||||||
|
console.log(`Total: ${allCompanies.length}`);
|
||||||
|
console.log(`Valid: ${validCompanies}`);
|
||||||
|
console.log(`Issues: ${issuesFound}`);
|
||||||
|
|
||||||
|
if (issuesFound === 0) {
|
||||||
|
console.log('\n✅ All data OK. No migration needed.');
|
||||||
|
} else {
|
||||||
|
console.log('\n⚠️ Migration recommended.');
|
||||||
|
}
|
||||||
|
|
||||||
|
await mongoose.connection.close();
|
||||||
|
} catch (err) {
|
||||||
|
console.error('❌ Error:', err.message);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
validateCompanies();
|
||||||
Reference in New Issue
Block a user