Тестовый коммит после удаления husky

This commit is contained in:
2025-03-05 01:02:09 +03:00
parent 97ca5e4b64
commit 3157ad0cd9
118 changed files with 8177 additions and 8530 deletions

246
backend/routes/messages.js Normal file
View File

@@ -0,0 +1,246 @@
const express = require('express');
const router = express.Router();
const { pool } = require('../db');
const { requireAuth } = require('../middleware/auth');
const { processMessage, getUserInfo } = require('../services/ai-assistant');
// Получение списка диалогов пользователя
router.get('/conversations', requireAuth, async (req, res) => {
try {
const userId = req.session.userId;
const result = await pool.query(
`SELECT * FROM conversation_view
WHERE user_id = $1
ORDER BY updated_at DESC`,
[userId]
);
res.json(result.rows);
} catch (error) {
console.error('Error fetching conversations:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Получение сообщений диалога
router.get('/conversations/:id/messages', requireAuth, async (req, res) => {
try {
const userId = req.session.userId;
const conversationId = req.params.id;
// Проверка доступа к диалогу
const conversationCheck = await pool.query(
'SELECT id FROM conversations WHERE id = $1 AND user_id = $2',
[conversationId, userId]
);
if (conversationCheck.rows.length === 0) {
return res.status(403).json({ error: 'Access denied' });
}
const result = await pool.query(
`SELECT * FROM message_view
WHERE conversation_id = $1
ORDER BY created_at ASC`,
[conversationId]
);
res.json(result.rows);
} catch (error) {
console.error('Error fetching messages:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Отправка сообщения
router.post('/conversations/:id/messages', requireAuth, async (req, res) => {
try {
const userId = req.session.userId;
const conversationId = req.params.id;
const { content } = req.body;
if (!content || content.trim() === '') {
return res.status(400).json({ error: 'Message content is required' });
}
// Проверка доступа к диалогу
const conversationCheck = await pool.query(
'SELECT id FROM conversations WHERE id = $1 AND user_id = $2',
[conversationId, userId]
);
if (conversationCheck.rows.length === 0) {
return res.status(403).json({ error: 'Access denied' });
}
// Обновление времени последней активности диалога
await pool.query('UPDATE conversations SET updated_at = NOW() WHERE id = $1', [conversationId]);
// Сохранение сообщения пользователя
const userMessageResult = await pool.query(
`INSERT INTO messages
(conversation_id, sender_type, sender_id, content, channel)
VALUES ($1, 'user', $2, $3, 'web')
RETURNING *`,
[conversationId, userId, content]
);
// Получение информации о пользователе для ИИ
const userInfo = await getUserInfo(userId);
// Обработка сообщения ИИ-ассистентом
const aiResponse = await processMessage(userId, content, userInfo.language || 'ru');
// Сохранение ответа ИИ
const aiMessageResult = await pool.query(
`INSERT INTO messages
(conversation_id, sender_type, content, channel)
VALUES ($1, 'ai', $2, 'web')
RETURNING *`,
[conversationId, aiResponse]
);
res.json({
userMessage: userMessageResult.rows[0],
aiMessage: aiMessageResult.rows[0],
});
} catch (error) {
console.error('Error sending message:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Создание нового диалога
router.post('/conversations', requireAuth, async (req, res) => {
try {
const userId = req.session.userId;
const { title } = req.body;
// Создание нового диалога
const result = await pool.query(
`INSERT INTO conversations (user_id, title)
VALUES ($1, $2)
RETURNING *`,
[userId, title || 'Новый диалог']
);
res.json(result.rows[0]);
} catch (error) {
console.error('Error creating conversation:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Обновление заголовка диалога
router.put('/conversations/:id', requireAuth, async (req, res) => {
try {
const userId = req.session.userId;
const conversationId = req.params.id;
const { title } = req.body;
if (!title || title.trim() === '') {
return res.status(400).json({ error: 'Title is required' });
}
// Проверка доступа к диалогу
const conversationCheck = await pool.query(
'SELECT id FROM conversations WHERE id = $1 AND user_id = $2',
[conversationId, userId]
);
if (conversationCheck.rows.length === 0) {
return res.status(403).json({ error: 'Access denied' });
}
// Обновление заголовка
const result = await pool.query(
'UPDATE conversations SET title = $1 WHERE id = $2 RETURNING *',
[title, conversationId]
);
res.json(result.rows[0]);
} catch (error) {
console.error('Error updating conversation:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Удаление диалога
router.delete('/conversations/:id', requireAuth, async (req, res) => {
try {
const userId = req.session.userId;
const conversationId = req.params.id;
// Проверка доступа к диалогу
const conversationCheck = await pool.query(
'SELECT id FROM conversations WHERE id = $1 AND user_id = $2',
[conversationId, userId]
);
if (conversationCheck.rows.length === 0) {
return res.status(403).json({ error: 'Access denied' });
}
// Удаление диалога (каскадно удалит все сообщения)
await pool.query('DELETE FROM conversations WHERE id = $1', [conversationId]);
res.json({ success: true });
} catch (error) {
console.error('Error deleting conversation:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Маршруты для администраторов
// Получение всех диалогов (только для администраторов)
router.get('/admin/conversations', requireAuth, async (req, res) => {
try {
// Проверка прав администратора
if (!req.session.isAdmin) {
return res.status(403).json({ error: 'Admin access required' });
}
const result = await pool.query(
`SELECT * FROM conversation_view
ORDER BY updated_at DESC`
);
res.json(result.rows);
} catch (error) {
console.error('Error fetching all conversations:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
// Получение статистики по каналам (только для администраторов)
router.get('/admin/stats/channels', requireAuth, async (req, res) => {
try {
// Проверка прав администратора
if (!req.session.isAdmin) {
return res.status(403).json({ error: 'Admin access required' });
}
const result = await pool.query(
`SELECT
channel,
COUNT(*) AS message_count,
COUNT(DISTINCT conversation_id) AS conversation_count,
COUNT(DISTINCT sender_id) AS user_count,
MIN(created_at) AS first_message,
MAX(created_at) AS last_message
FROM
messages
GROUP BY
channel`
);
res.json(result.rows);
} catch (error) {
console.error('Error fetching channel stats:', error);
res.status(500).json({ error: 'Internal server error' });
}
});
module.exports = router;