const Report = require('../models/Report'); const User = require('../models/User'); // @desc Подать жалобу на пользователя // @route POST /api/reports // @access Private const createReport = async (req, res, next) => { try { const { reportedUserId, reason, description } = req.body; const reporterId = req.user._id; // Проверяем, что пользователь не подает жалобу на самого себя if (reporterId.equals(reportedUserId)) { const error = new Error('Вы не можете подать жалобу на самого себя'); error.statusCode = 400; return next(error); } // Проверяем, существует ли пользователь, на которого подается жалоба const reportedUser = await User.findById(reportedUserId); if (!reportedUser) { const error = new Error('Пользователь не найден'); error.statusCode = 404; return next(error); } // Проверяем, нет ли уже жалобы от этого пользователя на этого же пользователя const existingReport = await Report.findOne({ reporter: reporterId, reportedUser: reportedUserId }); if (existingReport) { const error = new Error('Вы уже подавали жалобу на этого пользователя'); error.statusCode = 400; return next(error); } // Создаем новую жалобу const newReport = new Report({ reporter: reporterId, reportedUser: reportedUserId, reason, description: description || '' }); await newReport.save(); console.log(`[REPORT_CTRL] Создана жалоба ${newReport._id} от пользователя ${reporterId} на пользователя ${reportedUserId}`); res.status(201).json({ message: 'Жалоба успешно подана. Мы рассмотрим её в ближайшее время.', reportId: newReport._id }); } catch (error) { console.error('[REPORT_CTRL] Ошибка при создании жалобы:', error.message); next(error); } }; // @desc Получить список всех жалоб (для админов) // @route GET /api/admin/reports // @access Admin const getAllReports = async (req, res, next) => { try { const { page = 1, limit = 20, status = 'all' } = req.query; const skip = (page - 1) * limit; // Строим фильтр let filter = {}; if (status !== 'all') { filter.status = status; } // Получаем жалобы с информацией о пользователях const reports = await Report.find(filter) .populate('reporter', 'name email') .populate('reportedUser', 'name email isActive') .populate('reviewedBy', 'name email') .skip(skip) .limit(parseInt(limit)) .sort({ createdAt: -1 }); // Получаем общее количество жалоб const total = await Report.countDocuments(filter); res.json({ reports, pagination: { page: parseInt(page), limit: parseInt(limit), total, pages: Math.ceil(total / limit) } }); } catch (error) { console.error('[REPORT_CTRL] Ошибка при получении списка жалоб:', error.message); next(error); } }; // @desc Получить детали жалобы // @route GET /api/admin/reports/:id // @access Admin const getReportById = async (req, res, next) => { try { const { id } = req.params; const report = await Report.findById(id) .populate('reporter', 'name email photos') .populate('reportedUser', 'name email photos isActive') .populate('reviewedBy', 'name email'); if (!report) { const error = new Error('Жалоба не найдена'); error.statusCode = 404; return next(error); } // Преобразуем adminComment в adminNotes для фронтенда const reportResponse = report.toObject(); if (reportResponse.adminComment) { reportResponse.adminNotes = reportResponse.adminComment; } res.json(reportResponse); } catch (error) { console.error('[REPORT_CTRL] Ошибка при получении деталей жалобы:', error.message); next(error); } }; // @desc Обновить статус жалобы // @route PUT /api/admin/reports/:id // @access Admin const updateReportStatus = async (req, res, next) => { try { const { id } = req.params; const { status, adminNotes } = req.body; const adminId = req.user._id; const report = await Report.findById(id); if (!report) { const error = new Error('Жалоба не найдена'); error.statusCode = 404; return next(error); } // Обновляем жалобу report.status = status; report.reviewedBy = adminId; if (status === 'resolved' || status === 'dismissed') { report.reviewedAt = new Date(); } if (adminNotes) { report.adminComment = adminNotes; // В модели поле называется adminComment } await report.save(); console.log(`[REPORT_CTRL] Жалоба ${id} обновлена администратором ${adminId}, статус: ${status}`); // Возвращаем обновленную жалобу с заполненными связями const updatedReport = await Report.findById(id) .populate('reporter', 'name email') .populate('reportedUser', 'name email isActive') .populate('reviewedBy', 'name email'); // Преобразуем adminComment в adminNotes для фронтенда const reportResponse = updatedReport.toObject(); if (reportResponse.adminComment) { reportResponse.adminNotes = reportResponse.adminComment; } res.json(reportResponse); } catch (error) { console.error('[REPORT_CTRL] Ошибка при обновлении жалобы:', error.message); next(error); } }; // @desc Получить статистику жалоб // @route GET /api/admin/reports/stats // @access Admin const getReportsStats = async (req, res, next) => { try { // Общее количество жалоб const totalReports = await Report.countDocuments(); // Жалобы по статусам const pendingReports = await Report.countDocuments({ status: 'pending' }); const reviewedReports = await Report.countDocuments({ status: 'reviewed' }); const resolvedReports = await Report.countDocuments({ status: 'resolved' }); const dismissedReports = await Report.countDocuments({ status: 'dismissed' }); // Жалобы за последние 30 дней const thirtyDaysAgo = new Date(Date.now() - 30 * 24 * 60 * 60 * 1000); const recentReports = await Report.countDocuments({ createdAt: { $gte: thirtyDaysAgo } }); // Топ причин жалоб const topReasons = await Report.aggregate([ { $group: { _id: '$reason', count: { $sum: 1 } } }, { $sort: { count: -1 } }, { $limit: 5 } ]); const stats = { total: totalReports, byStatus: { pending: pendingReports, reviewed: reviewedReports, resolved: resolvedReports, dismissed: dismissedReports }, recent: recentReports, topReasons }; res.json(stats); } catch (error) { console.error('[REPORT_CTRL] Ошибка при получении статистики жалоб:', error.message); next(error); } }; module.exports = { createReport, getAllReports, getReportById, updateReportStatus, getReportsStats };