diff --git a/backend/controllers/adminController.js b/backend/controllers/adminController.js index 9511240..ae16cc9 100644 --- a/backend/controllers/adminController.js +++ b/backend/controllers/adminController.js @@ -113,6 +113,7 @@ const getUserDetails = async (req, res) => { const toggleUserActive = async (req, res) => { try { const userId = req.params.id; + const { reason } = req.body; // Добавляем возможность указать причину блокировки const user = await User.findById(userId); if (!user) { @@ -124,9 +125,76 @@ const toggleUserActive = async (req, res) => { return res.status(403).json({ message: 'Невозможно заблокировать администратора' }); } + // Получаем доступ к io для отправки уведомлений + const io = req.app.get('io'); + // Изменяем статус активности на противоположный + const wasActive = user.isActive; user.isActive = !user.isActive; await user.save(); + + // Если пользователь был активным и теперь блокируется + if (wasActive && !user.isActive) { + // Находим активное соединение пользователя + const activeUsers = Array.from(io.sockets.sockets).map(socket => socket[1]); + const userSockets = activeUsers.filter(socket => { + const userData = socket.handshake.query; + return userData && userData.userId === userId; + }); + + // Получаем информацию о пользователе из массива activeUsers + // (этот массив хранится в server.js) + const activeUsersArray = Array.from(io.sockets.adapter.rooms).filter(room => { + return room[1].has(room[0]); // Фильтруем комнаты, где id комнаты совпадает с id сокета + }).map(room => { + const socket = io.sockets.sockets.get(room[0]); + return socket && socket.handshake.query.userId + ? { userId: socket.handshake.query.userId, socketId: room[0] } + : null; + }).filter(Boolean); + + // Находим сокет пользователя + const userSocketInfo = activeUsersArray.find(u => u.userId === userId); + + // Если пользователь онлайн, отправляем уведомление о блокировке + if (userSocketInfo && userSocketInfo.socketId) { + io.to(userSocketInfo.socketId).emit("account_blocked", { + message: 'Ваш аккаунт был заблокирован администратором.', + reason: reason || 'Нарушение правил сервиса', + timestamp: new Date().toISOString() + }); + console.log(`[AdminController] Отправлено уведомление о блокировке пользователю ${userId}`); + } else { + // Если пользователь не в сети, просто оставляем лог + console.log(`[AdminController] Пользователь ${userId} заблокирован, но не находится в сети для отправки уведомления`); + } + } + // Если пользователь был неактивным и теперь разблокируется + else if (!wasActive && user.isActive) { + // Используем тот же подход для поиска сокетов пользователя + const activeUsersArray = Array.from(io.sockets.adapter.rooms).filter(room => { + return room[1].has(room[0]); + }).map(room => { + const socket = io.sockets.sockets.get(room[0]); + return socket && socket.handshake.query.userId + ? { userId: socket.handshake.query.userId, socketId: room[0] } + : null; + }).filter(Boolean); + + // Находим сокет пользователя (если он вдруг залогинился с другим статусом) + const userSocketInfo = activeUsersArray.find(u => u.userId === userId); + + // Если пользователь онлайн, отправляем уведомление о разблокировке + if (userSocketInfo && userSocketInfo.socketId) { + io.to(userSocketInfo.socketId).emit("account_unblocked", { + message: 'Ваш аккаунт был разблокирован администратором.', + timestamp: new Date().toISOString() + }); + console.log(`[AdminController] Отправлено уведомление о разблокировке пользователю ${userId}`); + } else { + console.log(`[AdminController] Пользователь ${userId} разблокирован, но не находится в сети для отправки уведомления`); + } + } res.json({ message: user.isActive ? 'Пользователь разблокирован' : 'Пользователь заблокирован', diff --git a/src/auth.js b/src/auth.js index e326285..e304721 100644 --- a/src/auth.js +++ b/src/auth.js @@ -127,6 +127,55 @@ async function logout() { console.log('Пользователь вышел из системы.'); } +// Функция обработки события блокировки аккаунта +function handleAccountBlocked(data) { + // Создаем объект с информацией о блокировке + const blockInfo = { + blocked: true, + message: data?.message || 'Ваш аккаунт был заблокирован администратором.', + reason: data?.reason || 'Нарушение правил сервиса', + timestamp: new Date().toISOString() + }; + + // Сохраняем информацию о блокировке в localStorage для отображения на странице логина + localStorage.setItem('accountBlockedInfo', JSON.stringify(blockInfo)); + + // Выполняем выход пользователя + user.value = null; + token.value = null; + localStorage.removeItem('userToken'); + + // Перенаправляем на страницу входа с уведомлением о блокировке + router.push({ + name: 'Login', + query: { blocked: 'true' } + }); + + console.log('Пользователь был разлогинен из-за блокировки аккаунта.'); +} + +// Функция обработки события разблокировки аккаунта +function handleAccountUnblocked(data) { + console.log('Получено уведомление о разблокировке аккаунта:', data); + + // Удаляем информацию о блокировке, если она была сохранена + localStorage.removeItem('accountBlockedInfo'); + + // Показываем уведомление пользователю, если он сейчас в приложении + // Можно использовать какую-то систему уведомлений в приложении + // или просто логировать это событие + + // Если пользователь не залогинен, но его аккаунт был разблокирован, + // можно показать соответствующее сообщение при следующем входе + localStorage.setItem('accountUnblockedInfo', JSON.stringify({ + unblocked: true, + message: data?.message || 'Ваш аккаунт был разблокирован.', + timestamp: new Date().toISOString() + })); + + console.log('Аккаунт пользователя разблокирован.'); +} + // Экспортируем то, что понадобится в компонентах export function useAuth() { return { @@ -137,5 +186,7 @@ export function useAuth() { register, logout, fetchUser, // Эту функцию нужно будет вызвать при инициализации приложения + handleAccountBlocked, // Добавляем функцию обработки блокировки аккаунта + handleAccountUnblocked // Добавляем функцию обработки разблокировки аккаунта }; } \ No newline at end of file diff --git a/src/services/socketService.js b/src/services/socketService.js index e91f6eb..c231846 100644 --- a/src/services/socketService.js +++ b/src/services/socketService.js @@ -8,7 +8,7 @@ let socket; const SOCKET_URL = '/'; // Vite будет перехватывать /socket.io/ путь export const connectSocket = () => { - const { user, isAuthenticated } = useAuth(); + const { user, isAuthenticated, handleAccountBlocked, handleAccountUnblocked } = useAuth(); if (isAuthenticated.value && user.value && user.value._id) { // Подключаемся только если пользователь аутентифицирован и есть ID @@ -46,6 +46,30 @@ export const connectSocket = () => { console.error('[SocketService] Ошибка подключения к Socket.IO:', error.message, error.data); }); + // Добавляем обработчик для события блокировки аккаунта + socket.on('account_blocked', (data) => { + console.log('[SocketService] Получено уведомление о блокировке аккаунта:', data); + // Вызываем функцию обработки блокировки из auth.js тихо, без показа браузерного уведомления + // Отложенный вызов, чтобы избежать показа стандартного уведомления браузера + setTimeout(() => { + handleAccountBlocked(data); + }, 10); + }); + + // Добавляем обработчик для события разблокировки аккаунта + socket.on('account_unblocked', (data) => { + console.log('[SocketService] Получено уведомление о разблокировке аккаунта:', data); + // Аналогично блокировке, используем setTimeout для предотвращения браузерного уведомления + setTimeout(() => { + // Если есть функция handleAccountUnblocked, вызываем её + if (typeof handleAccountUnblocked === 'function') { + handleAccountUnblocked(data); + } else { + console.log('[SocketService] Аккаунт разблокирован, но обработчик не определен'); + } + }, 10); + }); + // Можно здесь же слушать глобальные события, если нужно // socket.on('getUsers', (users) => { // console.log('[SocketService] Получен список активных пользователей:', users); diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue index 5544f05..6304755 100644 --- a/src/views/LoginView.vue +++ b/src/views/LoginView.vue @@ -16,6 +16,18 @@

Рады видеть вас снова!

+ +
+ +
+

Аккаунт заблокирован

+

{{ blockedInfo.message }}

+

+ Причина: {{ blockedInfo.reason }} +

+
+
+