From c4664edd7eb042fbe8791dc11856f93d039c0a81 Mon Sep 17 00:00:00 2001 From: innoavvlasov Date: Tue, 4 Nov 2025 19:46:39 +0300 Subject: [PATCH] fix mongo --- server/routers/procurement/config/db.js | 99 ------------------- server/routers/procurement/index.js | 13 +-- server/routers/procurement/routes/auth.js | 27 ++--- server/routers/procurement/routes/buy.js | 7 +- .../routers/procurement/routes/buyProducts.js | 26 +++-- server/routers/procurement/routes/requests.js | 32 +++--- .../procurement/scripts/recreate-test-user.js | 9 +- 7 files changed, 60 insertions(+), 153 deletions(-) delete mode 100644 server/routers/procurement/config/db.js diff --git a/server/routers/procurement/config/db.js b/server/routers/procurement/config/db.js deleted file mode 100644 index 7452f7e..0000000 --- a/server/routers/procurement/config/db.js +++ /dev/null @@ -1,99 +0,0 @@ -const mongoose = require('mongoose'); - -// Get MongoDB URL from environment variables -// MONGO_ADDR is a centralized env variable from server/utils/const.ts -const primaryUri = process.env.MONGO_ADDR || 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'; - -/** - * Check if error is related to authentication - */ -const isAuthError = (error) => { - if (!error) { - return false; - } - - const authCodes = new Set([18, 13]); - if (error.code && authCodes.has(error.code)) { - return true; - } - - const message = String(error.message || '').toLowerCase(); - return message.includes('auth') || message.includes('authentication'); -}; - -/** - * Try to connect to MongoDB with specific URI - */ -const connectWithUri = async (uri, label) => { - console.log(`\nπŸ“‘ ΠŸΠΎΠΏΡ‹Ρ‚ΠΊΠ° ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ΠΊ MongoDB (${label})...`); - if (process.env.DEV === 'true') { - console.log(` URI: ${uri}`); - } - - const connection = await mongoose.connect(uri, { - useNewUrlParser: true, - useUnifiedTopology: true, - serverSelectionTimeoutMS: 5000, - connectTimeoutMS: 5000, - }); - - try { - if (connection?.connection?.db) { - await connection.connection.db.admin().command({ ping: 1 }); - } - } catch (pingError) { - if (isAuthError(pingError)) { - await mongoose.connection.close().catch(() => {}); - throw pingError; - } - console.error('⚠️ MongoDB ping error:', pingError.message); - } - - console.log('βœ… MongoDB ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½Π° ΡƒΡΠΏΠ΅ΡˆΠ½ΠΎ!'); - console.log(` Π₯ост: ${connection?.connection?.host || 'Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½'}`); - console.log(` Π‘Π”: ${connection?.connection?.name || 'Π½Π΅ ΡƒΠΊΠ°Π·Π°Π½Π°'}\n`); - if (process.env.DEV === 'true') { - console.log(` ΠŸΠΎΠ»ΡŒΠ·ΠΎΠ²Π°Ρ‚Π΅Π»ΡŒ: ${connection?.connection?.user || 'anonymous'}`); - } - - return connection; -}; - -/** - * Connect to MongoDB with fallback strategy - */ -const connectDB = async () => { - const attempts = []; - - if (fallbackUri) { - attempts.push({ uri: fallbackUri, label: 'AUTH' }); - } - - attempts.push({ uri: primaryUri, label: 'PRIMARY' }); - - let lastError = null; - - for (const attempt of attempts) { - try { - console.log(`[MongoDB] Trying ${attempt.label} connection...`); - return await connectWithUri(attempt.uri, attempt.label); - } catch (error) { - lastError = error; - console.error(`\n❌ Ошибка ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ ΠΊ MongoDB (${attempt.label}):`); - console.error(` ${error.message}\n`); - - if (!isAuthError(error)) { - break; - } - } - } - - if (lastError) { - console.warn('⚠️ ΠŸΡ€ΠΈΠ»ΠΎΠΆΠ΅Π½ΠΈΠ΅ ΠΏΡ€ΠΎΠ΄ΠΎΠ»ΠΆΠΈΡ‚ Ρ€Π°Π±ΠΎΡ‚Ρƒ с mock Π΄Π°Π½Π½Ρ‹ΠΌΠΈ\n'); - } - - return null; -}; - -module.exports = connectDB; diff --git a/server/routers/procurement/index.js b/server/routers/procurement/index.js index b20542e..518ff7a 100644 --- a/server/routers/procurement/index.js +++ b/server/routers/procurement/index.js @@ -2,7 +2,7 @@ const express = require('express'); const cors = require('cors'); const dotenv = require('dotenv'); const fs = require('fs'); -const path = require('path'); +const mongoose = require('mongoose'); // Π—Π°Π³Ρ€ΡƒΠ·ΠΈΡ‚ΡŒ ΠΏΠ΅Ρ€Π΅ΠΌΠ΅Π½Π½Ρ‹Π΅ окруТСния dotenv.config(); @@ -28,15 +28,10 @@ const buyProductsRoutes = require('./routes/buyProducts'); const requestsRoutes = require('./routes/requests'); const homeRoutes = require('./routes/home'); -const connectDB = require('./config/db'); - const app = express(); -// ΠŸΠΎΠ΄ΠΊΠ»ΡŽΡ‡ΠΈΡ‚ΡŒ MongoDB ΠΏΡ€ΠΈ ΠΈΠ½ΠΈΡ†ΠΈΠ°Π»ΠΈΠ·Π°Ρ†ΠΈΠΈ -let dbConnected = false; -connectDB().then(() => { - dbConnected = true; -}); +// ΠŸΡ€ΠΎΠ²Π΅Ρ€ΠΈΡ‚ΡŒ ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ ΠΊ MongoDB (ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ происходит Π² server/utils/mongoose.ts) +const dbConnected = mongoose.connection.readyState === 1; // Middleware app.use(cors()); @@ -66,7 +61,7 @@ const delay = (ms = 300) => (req, res, next) => setTimeout(next, ms); app.use(delay()); // Π‘Ρ‚Π°Ρ‚ΠΈΠΊΠ° для Π·Π°Π³Ρ€ΡƒΠΆΠ΅Π½Π½Ρ‹Ρ… Ρ„Π°ΠΉΠ»ΠΎΠ² -const uploadsRoot = path.join(__dirname, '..', '..', 'remote-assets', 'uploads'); +const uploadsRoot = 'server/remote-assets/uploads'; if (!fs.existsSync(uploadsRoot)) { fs.mkdirSync(uploadsRoot, { recursive: true }); } diff --git a/server/routers/procurement/routes/auth.js b/server/routers/procurement/routes/auth.js index aa2943c..9b5437c 100644 --- a/server/routers/procurement/routes/auth.js +++ b/server/routers/procurement/routes/auth.js @@ -9,7 +9,6 @@ const Message = require('../models/Message'); const Review = require('../models/Review'); const mongoose = require('mongoose'); const { Types } = mongoose; -const connectDB = require('../config/db'); const PRESET_COMPANY_ID = new Types.ObjectId('68fe2ccda3526c303ca06796'); const PRESET_USER_EMAIL = 'admin@test-company.ru'; @@ -140,17 +139,15 @@ const waitForDatabaseConnection = async () => { } try { - const connection = await connectDB(); - if (!connection) { - break; + // ОТидаСм ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΡ (ΠΏΠΎΠ΄ΠΊΠ»ΡŽΡ‡Π΅Π½ΠΈΠ΅ происходит автоматичСски Ρ‡Π΅Ρ€Π΅Π· server/utils/mongoose.ts) + await new Promise(resolve => setTimeout(resolve, 500)); + + if (mongoose.connection.readyState === 1) { + const authed = await verifyAuth(); + if (authed) { + return; + } } - - const authed = await verifyAuth(); - if (authed) { - return; - } - - await mongoose.connection.close().catch(() => {}); } catch (error) { if (!isAuthFailure(error)) { throw error; @@ -221,12 +218,8 @@ const initializeTestUser = async () => { } catch (error) { console.error('Error initializing test data:', error.message); if (error?.code === 13 || /auth/i.test(error?.message || '')) { - try { - await connectDB(); - } catch (connectError) { - if (process.env.DEV === 'true') { - console.error('Failed to re-connect after auth error:', connectError.message); - } + if (process.env.DEV === 'true') { + console.error('Auth error detected. Connection managed by server/utils/mongoose.ts'); } } } diff --git a/server/routers/procurement/routes/buy.js b/server/routers/procurement/routes/buy.js index d23ea01..da95f94 100644 --- a/server/routers/procurement/routes/buy.js +++ b/server/routers/procurement/routes/buy.js @@ -1,11 +1,10 @@ const express = require('express') const fs = require('fs') -const path = require('path') const router = express.Router() const BuyDocument = require('../models/BuyDocument') // Create remote-assets/docs directory if it doesn't exist -const docsDir = path.join(__dirname, '../../remote-assets/docs') +const docsDir = 'server/remote-assets/docs' if (!fs.existsSync(docsDir)) { fs.mkdirSync(docsDir, { recursive: true }) } @@ -57,7 +56,7 @@ router.post('/docs', async (req, res) => { // Save file to disk const binaryData = Buffer.from(fileData, 'base64') - const filePath = path.join(docsDir, `${id}.${type}`) + const filePath = `${docsDir}/${id}.${type}` fs.writeFileSync(filePath, binaryData) console.log(`[BUY API] File saved to ${filePath}, size: ${binaryData.length} bytes`) @@ -187,7 +186,7 @@ router.get('/docs/:id/file', async (req, res) => { return res.status(404).json({ error: 'Document not found' }) } - const filePath = path.join(docsDir, `${id}.${doc.type}`) + const filePath = `${docsDir}/${id}.${doc.type}` if (!fs.existsSync(filePath)) { console.log('[BUY API] File not found on disk:', filePath) return res.status(404).json({ error: 'File not found on disk' }) diff --git a/server/routers/procurement/routes/buyProducts.js b/server/routers/procurement/routes/buyProducts.js index 9ee74fe..f480130 100644 --- a/server/routers/procurement/routes/buyProducts.js +++ b/server/routers/procurement/routes/buyProducts.js @@ -2,10 +2,9 @@ const express = require('express'); const router = express.Router(); const { verifyToken } = require('../middleware/auth'); const BuyProduct = require('../models/BuyProduct'); -const path = require('path'); const fs = require('fs'); const multer = require('multer'); -const UPLOADS_ROOT = path.join(__dirname, '..', '..', 'remote-assets', 'uploads', 'buy-products'); +const UPLOADS_ROOT = 'server/remote-assets/uploads/buy-products'; const ensureDirectory = (dirPath) => { if (!fs.existsSync(dirPath)) { fs.mkdirSync(dirPath, { recursive: true }); @@ -24,17 +23,28 @@ const ALLOWED_MIME_TYPES = new Set([ 'text/csv', ]); +const getExtension = (filename) => { + const lastDot = filename.lastIndexOf('.'); + return lastDot > 0 ? filename.slice(lastDot) : ''; +}; + +const getBasename = (filename) => { + const lastDot = filename.lastIndexOf('.'); + const name = lastDot > 0 ? filename.slice(0, lastDot) : filename; + const lastSlash = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')); + return lastSlash >= 0 ? name.slice(lastSlash + 1) : name; +}; + const storage = multer.diskStorage({ destination: (req, file, cb) => { const productId = req.params.id || 'common'; - const productDir = path.join(UPLOADS_ROOT, productId); + const productDir = `${UPLOADS_ROOT}/${productId}`; ensureDirectory(productDir); cb(null, productDir); }, filename: (req, file, cb) => { - const originalExtension = path.extname(file.originalname) || ''; - const baseName = path - .basename(file.originalname, originalExtension) + const originalExtension = getExtension(file.originalname); + const baseName = getBasename(file.originalname) .replace(/[^a-zA-Z0-9-_]+/g, '_') .toLowerCase(); cb(null, `${Date.now()}_${baseName}${originalExtension}`); @@ -243,7 +253,7 @@ router.post('/:id/files', verifyToken, handleSingleFileUpload, async (req, res) return res.status(400).json({ error: 'File is required' }); } - const relativePath = path.join('buy-products', id, req.file.filename).replace(/\\/g, '/'); + const relativePath = `buy-products/${id}/${req.file.filename}`; const file = { id: `file-${Date.now()}`, name: req.file.originalname, @@ -293,7 +303,7 @@ router.delete('/:id/files/:fileId', verifyToken, async (req, res) => { await product.save(); const storedPath = fileToRemove.storagePath || fileToRemove.url.replace(/^\/uploads\//, ''); - const absolutePath = path.join(__dirname, '..', '..', 'remote-assets', 'uploads', storedPath); + const absolutePath = `server/remote-assets/uploads/${storedPath}`; fs.promises.unlink(absolutePath).catch((unlinkError) => { if (unlinkError && unlinkError.code !== 'ENOENT') { diff --git a/server/routers/procurement/routes/requests.js b/server/routers/procurement/routes/requests.js index 7e62b15..31d0f48 100644 --- a/server/routers/procurement/routes/requests.js +++ b/server/routers/procurement/routes/requests.js @@ -3,7 +3,6 @@ const router = express.Router(); const { verifyToken } = require('../middleware/auth'); const Request = require('../models/Request'); const BuyProduct = require('../models/BuyProduct'); -const path = require('path'); const fs = require('fs'); const multer = require('multer'); @@ -18,7 +17,7 @@ const log = (message, data = '') => { } }; -const REQUESTS_UPLOAD_ROOT = path.join(__dirname, '..', '..', 'remote-assets', 'uploads', 'requests'); +const REQUESTS_UPLOAD_ROOT = 'server/remote-assets/uploads/requests'; const ensureDirectory = (dirPath) => { if (!fs.existsSync(dirPath)) { @@ -38,17 +37,28 @@ const ALLOWED_REQUEST_MIME_TYPES = new Set([ 'text/csv', ]); +const getExtension = (filename) => { + const lastDot = filename.lastIndexOf('.'); + return lastDot > 0 ? filename.slice(lastDot) : ''; +}; + +const getBasename = (filename) => { + const lastDot = filename.lastIndexOf('.'); + const name = lastDot > 0 ? filename.slice(0, lastDot) : filename; + const lastSlash = Math.max(name.lastIndexOf('/'), name.lastIndexOf('\\')); + return lastSlash >= 0 ? name.slice(lastSlash + 1) : name; +}; + const storage = multer.diskStorage({ destination: (req, file, cb) => { const subfolder = req.requestUploadSubfolder || ''; - const destinationDir = path.join(REQUESTS_UPLOAD_ROOT, subfolder); + const destinationDir = subfolder ? `${REQUESTS_UPLOAD_ROOT}/${subfolder}` : REQUESTS_UPLOAD_ROOT; ensureDirectory(destinationDir); cb(null, destinationDir); }, filename: (req, file, cb) => { - const extension = path.extname(file.originalname) || ''; - const baseName = path - .basename(file.originalname, extension) + const extension = getExtension(file.originalname); + const baseName = getBasename(file.originalname) .replace(/[^a-zA-Z0-9-_]+/g, '_') .toLowerCase(); cb(null, `${Date.now()}_${baseName}${extension}`); @@ -97,7 +107,7 @@ const cleanupUploadedFiles = async (req) => { const subfolder = req.requestUploadSubfolder || ''; const removalTasks = req.files.map((file) => { - const filePath = path.join(REQUESTS_UPLOAD_ROOT, subfolder, file.filename); + const filePath = subfolder ? `${REQUESTS_UPLOAD_ROOT}/${subfolder}/${file.filename}` : `${REQUESTS_UPLOAD_ROOT}/${file.filename}`; return fs.promises.unlink(filePath).catch((error) => { if (error.code !== 'ENOENT') { console.error('[Requests] Failed to cleanup uploaded file:', error.message); @@ -115,7 +125,7 @@ const mapFilesToMetadata = (req) => { const subfolder = req.requestUploadSubfolder || ''; return req.files.map((file) => { - const relativePath = path.join('requests', subfolder, file.filename).replace(/\\/g, '/'); + const relativePath = subfolder ? `requests/${subfolder}/${file.filename}` : `requests/${file.filename}`; return { id: `file-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`, name: file.originalname, @@ -159,7 +169,7 @@ const removeStoredFiles = async (files = []) => { const tasks = files .filter((file) => file && file.storagePath) .map((file) => { - const absolutePath = path.join(__dirname, '..', '..', 'remote-assets', 'uploads', file.storagePath); + const absolutePath = `server/remote-assets/uploads/${file.storagePath}`; return fs.promises.unlink(absolutePath).catch((error) => { if (error.code !== 'ENOENT') { console.error('[Requests] Failed to remove stored file:', error.message); @@ -218,7 +228,7 @@ router.get('/received', verifyToken, async (req, res) => { router.post( '/', verifyToken, - handleFilesUpload('files', (req) => path.join('sent', (req.companyId || 'unknown').toString()), 10), + handleFilesUpload('files', (req) => `sent/${(req.companyId || 'unknown').toString()}`, 10), async (req, res) => { try { const senderCompanyId = req.companyId; @@ -317,7 +327,7 @@ router.post( router.put( '/:id', verifyToken, - handleFilesUpload('responseFiles', (req) => path.join('responses', req.params.id || 'unknown'), 5), + handleFilesUpload('responseFiles', (req) => `responses/${req.params.id || 'unknown'}`, 5), async (req, res) => { try { const { id } = req.params; diff --git a/server/routers/procurement/scripts/recreate-test-user.js b/server/routers/procurement/scripts/recreate-test-user.js index 57a287f..80db85d 100644 --- a/server/routers/procurement/scripts/recreate-test-user.js +++ b/server/routers/procurement/scripts/recreate-test-user.js @@ -1,11 +1,10 @@ const mongoose = require('mongoose'); -const path = require('path'); require('dotenv').config(); -// Π˜ΠΌΠΏΠΎΡ€Ρ‚ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ -const User = require(path.join(__dirname, '..', 'models', 'User')); -const Company = require(path.join(__dirname, '..', 'models', 'Company')); -const Request = require(path.join(__dirname, '..', 'models', 'Request')); +// Π˜ΠΌΠΏΠΎΡ€Ρ‚ ΠΌΠΎΠ΄Π΅Π»Π΅ΠΉ - прямыС ΠΏΡƒΡ‚ΠΈ Π±Π΅Π· path.join ΠΈ __dirname +const User = require('../models/User'); +const Company = require('../models/Company'); +const Request = require('../models/Request'); const primaryUri = process.env.MONGODB_URI || 'mongodb://localhost:27017/procurement_db'; const fallbackUri =