Reflex/backend/controllers/adminController.js
2025-05-26 12:32:53 +07:00

334 lines
12 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 mongoose = require('mongoose');
const User = require('../models/User');
const Conversation = require('../models/Conversation');
const Message = require('../models/Message');
const ProfileView = require('../models/ProfileView');
/**
* @desc Получить список всех пользователей
* @route GET /api/admin/users
* @access Admin
*/
const getAllUsers = async (req, res) => {
try {
const { search, page = 1, limit = 20, isActive } = req.query;
const skip = (page - 1) * limit;
// Создание фильтра
const filter = {};
// Добавляем поиск по имени или email, если указан
if (search) {
filter.$or = [
{ name: { $regex: search, $options: 'i' } },
{ email: { $regex: search, $options: 'i' } }
];
}
// Фильтр по статусу активности, если указан
if (isActive !== undefined) {
filter.isActive = isActive === 'true';
}
// Исключаем админа из результатов выдачи
filter.isAdmin = { $ne: true };
// Получаем пользователей с пагинацией
const users = await User.find(filter)
.select('-password')
.skip(skip)
.limit(parseInt(limit))
.sort({ createdAt: -1 });
// Получаем общее количество пользователей для пагинации
const total = await User.countDocuments(filter);
res.json({
users,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
total,
pages: Math.ceil(total / limit)
}
});
} catch (error) {
console.error('Ошибка при получении списка пользователей:', error);
res.status(500).json({ message: 'Ошибка сервера при получении списка пользователей' });
}
};
/**
* @desc Получить детальную информацию о пользователе
* @route GET /api/admin/users/:id
* @access Admin
*/
const getUserDetails = async (req, res) => {
try {
const userId = req.params.id;
const user = await User.findById(userId)
.select('-password')
.lean();
if (!user) {
return res.status(404).json({ message: 'Пользователь не найден' });
}
// Получаем статистику для пользователя
const messagesCount = await Message.countDocuments({ sender: userId });
const conversationsCount = await Conversation.countDocuments({
participants: userId
});
const profileViewsCount = await ProfileView.countDocuments({
profileOwner: userId
});
const matchesCount = user.matches ? user.matches.length : 0;
const likesGivenCount = user.liked ? user.liked.length : 0;
// Добавляем статистику к данным пользователя
const userWithStats = {
...user,
stats: {
messagesCount,
conversationsCount,
profileViewsCount,
matchesCount,
likesGivenCount
}
};
res.json(userWithStats);
} catch (error) {
console.error('Ошибка при получении информации о пользователе:', error);
res.status(500).json({ message: 'Ошибка сервера при получении информации о пользователе' });
}
};
/**
* @desc Заблокировать/разблокировать пользователя
* @route PUT /api/admin/users/:id/toggle-active
* @access Admin
*/
const toggleUserActive = async (req, res) => {
try {
const userId = req.params.id;
const user = await User.findById(userId);
if (!user) {
return res.status(404).json({ message: 'Пользователь не найден' });
}
// Проверка, чтобы нельзя было заблокировать админа
if (user.isAdmin) {
return res.status(403).json({ message: 'Невозможно заблокировать администратора' });
}
// Изменяем статус активности на противоположный
user.isActive = !user.isActive;
await user.save();
res.json({
message: user.isActive ? 'Пользователь разблокирован' : 'Пользователь заблокирован',
isActive: user.isActive
});
} catch (error) {
console.error('Ошибка при изменении статуса пользователя:', error);
res.status(500).json({ message: 'Ошибка сервера при изменении статуса пользователя' });
}
};
/**
* @desc Получить статистику приложения
* @route GET /api/admin/statistics
* @access Admin
*/
const getAppStatistics = async (req, res) => {
try {
// Общая статистика пользователей
const totalUsers = await User.countDocuments({ isAdmin: { $ne: true } });
const activeUsers = await User.countDocuments({ isActive: true, isAdmin: { $ne: true } });
const inactiveUsers = await User.countDocuments({ isActive: false, isAdmin: { $ne: true } });
// Статистика по полу
const maleUsers = await User.countDocuments({ gender: 'male' });
const femaleUsers = await User.countDocuments({ gender: 'female' });
const otherGenderUsers = await User.countDocuments({ gender: 'other' });
// Статистика сообщений и диалогов
const totalMessages = await Message.countDocuments();
const totalConversations = await Conversation.countDocuments();
// Статистика просмотров профилей
const totalProfileViews = await ProfileView.countDocuments();
// Средние значения
const messagesPerUser = totalUsers > 0 ? totalMessages / totalUsers : 0;
const conversationsPerUser = totalUsers > 0 ? totalConversations / totalUsers : 0;
// Новые пользователи за последние 30 дней
const thirtyDaysAgo = new Date();
thirtyDaysAgo.setDate(thirtyDaysAgo.getDate() - 30);
const newUsers30Days = await User.countDocuments({
createdAt: { $gte: thirtyDaysAgo },
isAdmin: { $ne: true }
});
res.json({
users: {
total: totalUsers,
active: activeUsers,
inactive: inactiveUsers,
newIn30Days: newUsers30Days,
genderDistribution: {
male: maleUsers,
female: femaleUsers,
other: otherGenderUsers
}
},
activity: {
totalMessages,
totalConversations,
totalProfileViews,
averages: {
messagesPerUser: messagesPerUser.toFixed(2),
conversationsPerUser: conversationsPerUser.toFixed(2)
}
}
});
} catch (error) {
console.error('Ошибка при получении статистики приложения:', error);
res.status(500).json({ message: 'Ошибка сервера при получении статистики приложения' });
}
};
/**
* @desc Получить список всех диалогов
* @route GET /api/admin/conversations
* @access Admin
*/
const getAllConversations = async (req, res) => {
try {
console.log('[ADMIN] Запрос списка диалогов');
const { page = 1, limit = 20, userId } = req.query;
const skip = (page - 1) * limit;
// Создание фильтра
const filter = {};
// Фильтр по пользователю, если указан
if (userId) {
console.log(`[ADMIN] Фильтр по пользователю: ${userId}`);
if (!mongoose.Types.ObjectId.isValid(userId)) {
console.log(`[ADMIN] Недопустимый формат ID пользователя: ${userId}`);
return res.status(400).json({ message: 'Недопустимый формат ID пользователя' });
}
filter.participants = userId;
}
console.log(`[ADMIN] Поиск диалогов с фильтром:`, filter);
// Получаем диалоги с пагинацией и данными участников
const conversations = await Conversation.find(filter)
.populate('participants', 'name email photos')
.populate('lastMessage')
.skip(skip)
.limit(parseInt(limit))
.sort({ updatedAt: -1 });
console.log(`[ADMIN] Найдено диалогов: ${conversations.length}`);
// Получаем общее количество диалогов для пагинации
const total = await Conversation.countDocuments(filter);
// Добавляем дополнительную информацию о диалогах
const conversationsWithInfo = conversations.map(conv => {
const convObj = conv.toObject();
convObj._id = convObj._id.toString(); // Преобразуем ObjectId в строку для безопасности
return convObj;
});
res.json({
conversations: conversationsWithInfo,
pagination: {
page: parseInt(page),
limit: parseInt(limit),
total,
pages: Math.ceil(total / limit)
}
});
} catch (error) {
console.error('[ADMIN] Ошибка при получении списка диалогов:', error);
res.status(500).json({ message: 'Ошибка сервера при получении списка диалогов' });
}
};
/**
* @desc Получить сообщения диалога
* @route GET /api/admin/conversations/:id/messages
* @access Admin
*/
const getConversationMessages = async (req, res) => {
try {
const conversationId = req.params.id;
console.log(`[ADMIN] Запрос сообщений для диалога с ID: ${conversationId}`);
if (!mongoose.Types.ObjectId.isValid(conversationId)) {
console.log(`[ADMIN] Недопустимый формат ID диалога: ${conversationId}`);
return res.status(400).json({ message: 'Недопустимый формат ID диалога' });
}
const { page = 1, limit = 50 } = req.query;
const skip = (page - 1) * limit;
// Проверяем существование диалога с подробным логированием
console.log(`[ADMIN] Поиск диалога с ID: ${conversationId}`);
const conversation = await Conversation.findById(conversationId);
if (!conversation) {
console.log(`[ADMIN] Диалог с ID ${conversationId} не найден в базе данных`);
return res.status(404).json({ message: 'Диалог не найден' });
}
console.log(`[ADMIN] Диалог найден, участники: ${conversation.participants}`);
// Получаем сообщения с пагинацией
const messages = await Message.find({ conversationId })
.populate('sender', 'name email')
.skip(skip)
.limit(parseInt(limit))
.sort({ createdAt: -1 });
console.log(`[ADMIN] Найдено сообщений: ${messages.length}`);
// Получаем общее количество сообщений для пагинации
const total = await Message.countDocuments({ conversationId });
res.json({
messages,
conversation: {
id: conversation._id,
participants: conversation.participants
},
pagination: {
page: parseInt(page),
limit: parseInt(limit),
total,
pages: Math.ceil(total / limit)
}
});
} catch (error) {
console.error('[ADMIN] Ошибка при получении сообщений диалога:', error);
res.status(500).json({ message: 'Ошибка сервера при получении сообщений диалога' });
}
};
module.exports = {
getAllUsers,
getUserDetails,
toggleUserActive,
getAppStatistics,
getAllConversations,
getConversationMessages
};