Files
multy-stub/server/routers/procurement/routes/messages.js

264 lines
9.1 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
const express = require('express');
const router = express.Router();
const { verifyToken } = require('../middleware/auth');
const Message = require('../models/Message');
const mongoose = require('../../../utils/mongoose');
const { ObjectId } = mongoose.Types;
// Функция для логирования с проверкой DEV переменной
const log = (message, data = '') => {
if (process.env.DEV === 'true') {
if (data) {
console.log(message, data);
} else {
console.log(message);
}
}
};
// GET /messages/threads - получить все потоки для компании
router.get('/threads', verifyToken, async (req, res) => {
try {
const companyId = req.companyId;
log('[Messages] Fetching threads for companyId:', companyId, 'type:', typeof companyId);
// Преобразовать в ObjectId если это строка
let companyObjectId = companyId;
let companyIdString = companyId.toString ? companyId.toString() : companyId;
try {
if (typeof companyId === 'string' && ObjectId.isValid(companyId)) {
companyObjectId = new ObjectId(companyId);
}
} catch (e) {
log('[Messages] Could not convert to ObjectId:', e.message);
}
log('[Messages] Using companyObjectId:', companyObjectId, 'companyIdString:', companyIdString);
// Получить все сообщения где текущая компания отправитель или получатель
// Поддерживаем оба формата - ObjectId и строки
const allMessages = await Message.find({
$or: [
{ senderCompanyId: companyObjectId },
{ senderCompanyId: companyIdString },
{ recipientCompanyId: companyObjectId },
{ recipientCompanyId: companyIdString },
// Также ищем по threadId который может содержать ID компании
{ threadId: { $regex: companyIdString } }
]
})
.sort({ timestamp: -1 })
.limit(500);
log('[Messages] Found', allMessages.length, 'messages for company');
if (allMessages.length === 0) {
log('[Messages] No messages found');
res.json([]);
return;
}
// Группируем по потокам и берем последнее сообщение каждого потока
const threadsMap = new Map();
allMessages.forEach(msg => {
const threadId = msg.threadId;
if (!threadsMap.has(threadId)) {
threadsMap.set(threadId, {
threadId,
lastMessage: msg.text,
lastMessageAt: msg.timestamp,
senderCompanyId: msg.senderCompanyId,
recipientCompanyId: msg.recipientCompanyId
});
}
});
const threads = Array.from(threadsMap.values()).sort((a, b) =>
new Date(b.lastMessageAt) - new Date(a.lastMessageAt)
);
log('[Messages] Returned', threads.length, 'unique threads');
res.json(threads);
} catch (error) {
console.error('[Messages] Error fetching threads:', error.message, error.stack);
res.status(500).json({ error: error.message });
}
});
// GET /messages/:threadId - получить сообщения потока
router.get('/:threadId', verifyToken, async (req, res) => {
try {
const { threadId } = req.params;
const companyId = req.companyId;
// Получить все сообщения потока
const threadMessages = await Message.find({ threadId })
.sort({ timestamp: 1 })
.exec();
// Отметить сообщения как прочитанные для текущей компании
await Message.updateMany(
{ threadId, recipientCompanyId: companyId, read: false },
{ read: true }
);
log('[Messages] Returned', threadMessages.length, 'messages for thread', threadId);
res.json(threadMessages);
} catch (error) {
console.error('[Messages] Error fetching messages:', error.message);
res.status(500).json({ error: error.message });
}
});
// POST /messages/:threadId - добавить сообщение в поток
router.post('/:threadId', verifyToken, async (req, res) => {
try {
const { threadId } = req.params;
const { text, senderCompanyId } = req.body;
if (!text || !threadId) {
return res.status(400).json({ error: 'Text and threadId required' });
}
// Определить получателя на основе threadId
// threadId формат: "thread-id1-id2"
const threadParts = threadId.replace('thread-', '').split('-');
let recipientCompanyId = null;
const currentSender = senderCompanyId || req.companyId;
const currentSenderString = currentSender.toString ? currentSender.toString() : currentSender;
if (threadParts.length >= 2) {
const companyId1 = threadParts[0];
const companyId2 = threadParts[1];
// Получатель - это другая сторона
recipientCompanyId = currentSenderString === companyId1 ? companyId2 : companyId1;
}
log('[Messages] POST /messages/:threadId');
log('[Messages] threadId:', threadId);
log('[Messages] Sender:', currentSender);
log('[Messages] SenderString:', currentSenderString);
log('[Messages] Recipient:', recipientCompanyId);
// Найти recipientCompanyId по ObjectId если нужно
let recipientObjectId = recipientCompanyId;
try {
if (typeof recipientCompanyId === 'string' && ObjectId.isValid(recipientCompanyId)) {
recipientObjectId = new ObjectId(recipientCompanyId);
}
} catch (e) {
log('[Messages] Could not convert recipientId to ObjectId');
}
const message = new Message({
threadId,
senderCompanyId: currentSender,
recipientCompanyId: recipientObjectId,
text: text.trim(),
read: false,
timestamp: new Date()
});
const savedMessage = await message.save();
log('[Messages] New message created:', savedMessage._id);
log('[Messages] Message data:', {
threadId: savedMessage.threadId,
senderCompanyId: savedMessage.senderCompanyId,
recipientCompanyId: savedMessage.recipientCompanyId
});
res.status(201).json(savedMessage);
} catch (error) {
console.error('[Messages] Error creating message:', error.message, error.stack);
res.status(500).json({ error: error.message });
}
});
// MIGRATION ENDPOINT - Fix recipientCompanyId for all messages
router.post('/admin/migrate-fix-recipients', async (req, res) => {
try {
const allMessages = await Message.find().exec();
log('[Messages] Migrating', allMessages.length, 'messages...');
let fixedCount = 0;
let errorCount = 0;
for (const message of allMessages) {
try {
const threadId = message.threadId;
if (!threadId) continue;
// Parse threadId формат "thread-id1-id2" или "id1-id2"
const ids = threadId.replace('thread-', '').split('-');
if (ids.length < 2) {
errorCount++;
continue;
}
const companyId1 = ids[0];
const companyId2 = ids[1];
// Compare with senderCompanyId
const senderIdString = message.senderCompanyId.toString ? message.senderCompanyId.toString() : message.senderCompanyId;
const expectedRecipient = senderIdString === companyId1 ? companyId2 : companyId1;
// If recipientCompanyId is not set or wrong - fix it
if (!message.recipientCompanyId || message.recipientCompanyId.toString() !== expectedRecipient) {
let recipientObjectId = expectedRecipient;
try {
if (typeof expectedRecipient === 'string' && ObjectId.isValid(expectedRecipient)) {
recipientObjectId = new ObjectId(expectedRecipient);
}
} catch (e) {
// continue
}
await Message.updateOne(
{ _id: message._id },
{ recipientCompanyId: recipientObjectId }
);
fixedCount++;
}
} catch (err) {
console.error('[Messages] Migration error:', err.message);
errorCount++;
}
}
log('[Messages] Migration completed! Fixed:', fixedCount, 'Errors:', errorCount);
res.json({ success: true, fixed: fixedCount, errors: errorCount, total: allMessages.length });
} catch (error) {
console.error('[Messages] Migration error:', error.message);
res.status(500).json({ error: error.message });
}
});
// DEBUG ENDPOINT
router.get('/debug/all-messages', async (req, res) => {
try {
const allMessages = await Message.find().limit(10).exec();
log('[Debug] Total messages in DB:', allMessages.length);
const info = allMessages.map(m => ({
_id: m._id,
threadId: m.threadId,
senderCompanyId: m.senderCompanyId?.toString ? m.senderCompanyId.toString() : m.senderCompanyId,
recipientCompanyId: m.recipientCompanyId?.toString ? m.recipientCompanyId.toString() : m.recipientCompanyId,
text: m.text.substring(0, 30)
}));
res.json({ totalCount: allMessages.length, messages: info });
} catch (error) {
res.status(500).json({ error: error.message });
}
});
module.exports = router;