замечания 3

This commit is contained in:
2025-11-02 12:40:42 +03:00
parent 35493a09b5
commit 0d1dcf21c1
29 changed files with 1498 additions and 1827 deletions

View File

@@ -1,74 +0,0 @@
const mongoose = require('mongoose');
const { migrateCompanies } = require('./migrate-companies');
require('dotenv').config({ path: '../../.env' });
const mongoUrl = process.env.MONGODB_URI || 'mongodb://admin:password@localhost:27017/procurement_db?authSource=admin';
// 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);
});
}

View File

@@ -1,124 +0,0 @@
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://localhost:27017/procurement_db';
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);
});
}

View File

@@ -6,17 +6,14 @@ const mongoUrl = process.env.MONGODB_URI || 'mongodb://localhost:27017/procureme
async function migrateMessages() {
try {
// Check if connection exists, if not connect
if (mongoose.connection.readyState === 0) {
console.log('[Migration] Connecting to MongoDB...');
await mongoose.connect(mongoUrl, {
useNewUrlParser: true,
useUnifiedTopology: true,
serverSelectionTimeoutMS: 5000,
connectTimeoutMS: 5000,
});
console.log('[Migration] Connected to MongoDB');
}
console.log('[Migration] Connecting to MongoDB...');
await mongoose.connect(mongoUrl, {
useNewUrlParser: true,
useUnifiedTopology: true,
serverSelectionTimeoutMS: 5000,
connectTimeoutMS: 5000,
});
console.log('[Migration] Connected to MongoDB');
// Найти все сообщения
const allMessages = await Message.find().exec();
@@ -84,18 +81,13 @@ async function migrateMessages() {
console.log('[Migration] ✅ Migration completed!');
console.log('[Migration] Fixed:', fixedCount, 'messages');
console.log('[Migration] Errors:', errorCount);
await mongoose.connection.close();
console.log('[Migration] Disconnected from MongoDB');
} catch (err) {
console.error('[Migration] ❌ Error:', err.message);
throw err;
process.exit(1);
}
}
module.exports = { migrateMessages };
// Run directly if called as script
if (require.main === module) {
migrateMessages().catch(err => {
console.error('Migration failed:', err);
process.exit(1);
});
}
migrateMessages();

View File

@@ -1,32 +1,62 @@
const mongoose = require('mongoose');
const path = require('path');
require('dotenv').config();
// Импорт моделей
const User = require('../models/User');
const Company = require('../models/Company');
const User = require(path.join(__dirname, '..', 'models', 'User'));
const Company = require(path.join(__dirname, '..', 'models', 'Company'));
const primaryUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/procurement_db';
const fallbackUri =
process.env.MONGODB_AUTH_URI || 'mongodb://admin:password@localhost:27017/procurement_db?authSource=admin';
const connectWithFallback = async () => {
try {
console.log('\n📡 Подключение к MongoDB (PRIMARY)...');
await mongoose.connect(primaryUri, { useNewUrlParser: true, useUnifiedTopology: true });
console.log('✅ Подключено к PRIMARY MongoDB');
} catch (primaryError) {
console.error('❌ Ошибка PRIMARY подключения:', primaryError.message);
const requiresFallback =
primaryError.code === 18 || primaryError.code === 13 || String(primaryError.message || '').includes('auth');
if (!requiresFallback) {
throw primaryError;
}
console.log('\n📡 Подключение к MongoDB (FALLBACK)...');
await mongoose.connect(fallbackUri, { useNewUrlParser: true, useUnifiedTopology: true });
console.log('✅ Подключено к FALLBACK MongoDB');
}
};
const recreateTestUser = async () => {
try {
console.log('[Migration] Processing test user creation...');
await connectWithFallback();
const presetCompanyId = new mongoose.Types.ObjectId('68fe2ccda3526c303ca06796');
const presetUserEmail = 'admin@test-company.ru';
// Удалить старого тестового пользователя
console.log('[Migration] Removing old test user...');
const oldUser = await User.findOne({ email: 'admin@test-company.ru' });
console.log('🗑️ Удаление старого тестового пользователя...');
const oldUser = await User.findOne({ email: presetUserEmail });
if (oldUser) {
// Удалить связанную компанию
if (oldUser.companyId) {
await Company.findByIdAndDelete(oldUser.companyId);
console.log('[Migration] ✓ Old company removed');
console.log(' ✓ Старая компания удалена');
}
await User.findByIdAndDelete(oldUser._id);
console.log('[Migration] ✓ Old user removed');
console.log(' ✓ Старый пользователь удален');
} else {
console.log('[Migration] Old user not found');
console.log(' Старый пользователь не найден');
}
// Создать новую компанию с правильной кодировкой UTF-8
console.log('[Migration] Creating test company...');
console.log('\n🏢 Создание тестовой компании...');
const company = await Company.create({
_id: presetCompanyId,
fullName: 'ООО "Тестовая Компания"',
inn: '1234567890',
ogrn: '1234567890123',
@@ -40,12 +70,12 @@ const recreateTestUser = async () => {
reviewsCount: 10,
dealsCount: 25,
});
console.log('[Migration] ✓ Company created:', company.fullName);
console.log(' ✓ Компания создана:', company.fullName);
// Создать нового пользователя с правильной кодировкой UTF-8
console.log('[Migration] Creating test user...');
console.log('\n👤 Создание тестового пользователя...');
const user = await User.create({
email: 'admin@test-company.ru',
email: presetUserEmail,
password: 'SecurePass123!',
firstName: 'Иван',
lastName: 'Иванов',
@@ -53,10 +83,24 @@ const recreateTestUser = async () => {
phone: '+7 (999) 123-45-67',
companyId: company._id,
});
console.log('[Migration] ✓ User created:', user.firstName, user.lastName);
console.log(' ✓ Пользователь создан:', 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 компании
console.log('[Migration] Updating existing companies...');
console.log('\n🔄 Обновление существующих mock компаний...');
const updates = [
{ inn: '7707083894', updates: { companySize: '51-250', partnerGeography: ['moscow', 'russia_all'] } },
{ inn: '7707083895', updates: { companySize: '500+', partnerGeography: ['moscow', 'russia_all'] } },
@@ -67,33 +111,18 @@ const recreateTestUser = async () => {
for (const item of updates) {
await Company.updateOne({ inn: item.inn }, { $set: item.updates });
console.log(`[Migration] ✓ Company updated: INN ${item.inn}`);
console.log(` ✓ Компания обновлена: INN ${item.inn}`);
}
console.log('[Migration] ✅ Test user migration completed!');
await mongoose.connection.close();
process.exit(0);
} catch (error) {
console.error('[Migration] ❌ Error:', error.message);
throw error;
console.error('\n❌ Ошибка:', error.message);
console.error(error);
process.exit(1);
}
};
module.exports = { 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);
});
}
// Запуск
recreateTestUser();

View File

@@ -1,117 +0,0 @@
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://admin:password@localhost:27017/procurement_db?authSource=admin';
// 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(shouldCloseConnection = false) {
let mongooseConnected = false;
try {
console.log('\n' + '='.repeat(60));
console.log('🚀 Starting Database Migrations');
console.log('='.repeat(60) + '\n');
// Only connect if not already connected
if (mongoose.connection.readyState === 0) {
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');
} else {
console.log('[Migrations] ✅ Using existing MongoDB connection\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
try {
await Migration.create({
name: migration.name,
status: 'failed',
message: error.message
});
} catch (recordErr) {
// Ignore if we can't record the failure
}
}
}
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);
if (shouldCloseConnection) {
process.exit(1);
}
} finally {
// Only close connection if we created it and requested to close
if (mongooseConnected && shouldCloseConnection) {
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(true).catch(err => {
console.error('Migration failed:', err);
process.exit(1);
});
}

View File

@@ -0,0 +1,61 @@
#!/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('');

View File

@@ -1,93 +0,0 @@
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();