diff --git a/backend/controllers/adminController.js b/backend/controllers/adminController.js index f4b2e13..214c683 100644 --- a/backend/controllers/adminController.js +++ b/backend/controllers/adminController.js @@ -188,6 +188,26 @@ const toggleUserActive = async (req, res) => { else if (!wasActive && user.isActive) { console.log(`[AdminController] Разблокировка пользователя ${userId}`); + // Формируем объект с информацией о разблокировке для отправки через сокет + const unblockInfo = { + message: 'Ваш аккаунт был разблокирован администратором.', + timestamp: new Date().toISOString(), + userId: user._id.toString(), + unblockType: 'admin_action', // Указываем тип разблокировки + userName: user.name, + unblockData: { + canRestoreSession: true, // Флаг возможности восстановления сессии + } + }; + + // Отправляем событие разблокировки всем клиентам (анонимно) + // Это необходимо, чтобы клиент, который залогинен с другого устройства, + // также получил уведомление о разблокировке + io.emit('global_user_unblocked', { + userId: user._id.toString(), + timestamp: new Date().toISOString() + }); + // Ищем пользователя среди активных пользователей (на случай, если он онлайн с другим аккаунтом) const userSockets = activeUsers.filter(u => u.userId === userId); @@ -197,10 +217,7 @@ const toggleUserActive = async (req, res) => { const socket = io.sockets.sockets.get(userSocket.socketId); if (socket) { console.log(`[AdminController] Отправка уведомления о разблокировке на сокет: ${userSocket.socketId}`); - socket.emit("account_unblocked", { - message: 'Ваш аккаунт был разблокирован администратором.', - timestamp: new Date().toISOString() - }); + socket.emit("account_unblocked", unblockInfo); } else { console.log(`[AdminController] Не найден объект сокета для ID: ${userSocket.socketId}`); } diff --git a/src/auth.js b/src/auth.js index 3c853ae..3808f6e 100644 --- a/src/auth.js +++ b/src/auth.js @@ -143,12 +143,27 @@ function handleAccountBlocked(data) { // Сохраняем информацию о блокировке в localStorage для отображения на странице логина localStorage.setItem('accountBlockedInfo', JSON.stringify(blockInfo)); + // Сохраняем данные текущей сессии для последующего восстановления при разблокировке + if (user.value && token.value) { + // Сохраняем только необходимые данные для восстановления сессии + const sessionBackup = { + userId: user.value._id, + email: user.value.email, + name: user.value.name, + token: token.value, + timestamp: new Date().toISOString() + }; + // Сохраняем резервную копию данных сессии + localStorage.setItem('blockedSessionBackup', JSON.stringify(sessionBackup)); + console.log('[Auth] Данные сессии сохранены для последующего восстановления'); + } + // Немедленно очищаем все данные пользователя console.log('[Auth] Очистка данных пользователя из-за блокировки'); user.value = null; token.value = null; - // Очистка localStorage - удаляем все ключи, которые могут содержать пользовательские данные + // Очистка localStorage - удаляем токен, но сохраняем резервную копию сессии localStorage.removeItem('userToken'); localStorage.removeItem('userSettings'); localStorage.removeItem('userPreferences'); @@ -190,25 +205,90 @@ function handleAccountBlocked(data) { } // Функция обработки события разблокировки аккаунта -function handleAccountUnblocked(data) { - console.log('Получено уведомление о разблокировке аккаунта:', data); +async function handleAccountUnblocked(data) { + console.log('[Auth] Получено уведомление о разблокировке аккаунта:', data); // Удаляем информацию о блокировке, если она была сохранена localStorage.removeItem('accountBlockedInfo'); - // Показываем уведомление пользователю, если он сейчас в приложении - // Можно использовать какую-то систему уведомлений в приложении - // или просто логировать это событие - - // Если пользователь не залогинен, но его аккаунт был разблокирован, - // можно показать соответствующее сообщение при следующем входе - localStorage.setItem('accountUnblockedInfo', JSON.stringify({ + // Сохраняем информацию о разблокировке для отображения при следующем входе + const unblockedInfo = { unblocked: true, message: data?.message || 'Ваш аккаунт был разблокирован.', timestamp: new Date().toISOString() - })); + }; + localStorage.setItem('accountUnblockedInfo', JSON.stringify(unblockedInfo)); - console.log('Аккаунт пользователя разблокирован.'); + // Проверяем, есть ли сохраненная сессия для восстановления + try { + const sessionBackupStr = localStorage.getItem('blockedSessionBackup'); + if (sessionBackupStr) { + const sessionBackup = JSON.parse(sessionBackupStr); + console.log('[Auth] Найдены данные для восстановления сессии:', sessionBackup); + + // Проверяем, что данные актуальны (не старше 30 дней) + const backupTime = new Date(sessionBackup.timestamp); + const now = new Date(); + const thirtyDaysInMs = 30 * 24 * 60 * 60 * 1000; + + if (now - backupTime < thirtyDaysInMs && sessionBackup.userId && sessionBackup.token) { + // Восстанавливаем сессию + console.log('[Auth] Восстановление сессии пользователя после разблокировки'); + + // Устанавливаем токен в localStorage + localStorage.setItem('userToken', sessionBackup.token); + token.value = sessionBackup.token; + + // Пробуем загрузить актуальные данные пользователя + try { + console.log('[Auth] Загрузка актуальных данных пользователя'); + await fetchUser(); + + if (user.value) { + console.log('[Auth] Сессия успешно восстановлена, перенаправление в приложение'); + + // Показываем уведомление о восстановлении сессии + const notificationEvent = new CustomEvent('show-toast', { + detail: { + message: 'Ваш аккаунт был разблокирован и сессия восстановлена.', + type: 'success', + duration: 5000 + } + }); + window.dispatchEvent(notificationEvent); + + // Удаляем сохраненные данные сессии + localStorage.removeItem('blockedSessionBackup'); + + // Перенаправление на главную страницу или на последнюю просмотренную страницу + window.location.href = sessionBackup.lastPath || '/'; + return true; + } + } catch (fetchError) { + console.error('[Auth] Ошибка при загрузке данных пользователя:', fetchError); + } + } else { + console.log('[Auth] Сохраненная сессия устарела или неполная, будет выполнен обычный вход'); + // Удаляем устаревшие данные сессии + localStorage.removeItem('blockedSessionBackup'); + } + } else { + console.log('[Auth] Сохраненная сессия не найдена, показываем только уведомление о разблокировке'); + } + } catch (error) { + console.error('[Auth] Ошибка при восстановлении сессии после разблокировки:', error); + } + + // Если мы дошли до этой точки, значит автоматическое восстановление не удалось + // или мы не нашли сохраненной сессии. Просто показываем уведомление. + console.log('[Auth] Аккаунт пользователя разблокирован без автоматического входа'); + + // Если пользователь уже на странице логина, добавляем параметр unblocked=true + if (window.location.pathname === '/login') { + router.replace({ path: '/login', query: { unblocked: 'true' } }); + } + + return false; } // Экспортируем то, что понадобится в компонентах diff --git a/src/services/socketService.js b/src/services/socketService.js index 6f57dff..b44126e 100644 --- a/src/services/socketService.js +++ b/src/services/socketService.js @@ -87,12 +87,61 @@ export const connectSocket = () => { // Обработчик разблокировки аккаунта socket.on('account_unblocked', (data) => { console.log('[SocketService] Получено уведомление о разблокировке аккаунта:', data); + + // Сбрасываем флаг блокировки wasAccountBlocked = false; if (typeof handleAccountUnblocked === 'function') { - handleAccountUnblocked(data); + try { + console.log('[SocketService] Вызов обработчика разблокировки аккаунта'); + handleAccountUnblocked(data); + } catch (error) { + console.error('[SocketService] Ошибка при обработке разблокировки аккаунта:', error); + } } else { console.log('[SocketService] Аккаунт разблокирован, но обработчик не определен'); + // Показываем уведомление с помощью стандартного API + if ('Notification' in window && Notification.permission === 'granted') { + new Notification('Аккаунт разблокирован', { + body: data.message || 'Ваш аккаунт был разблокирован администратором.' + }); + } + } + }); + + // Новый обработчик для глобальных уведомлений о разблокировке + socket.on('global_user_unblocked', (data) => { + console.log('[SocketService] Получено глобальное уведомление о разблокировке пользователя:', data); + + // Проверяем, относится ли это к нашему пользователю + if (user.value && user.value._id === data.userId) { + console.log('[SocketService] Это уведомление относится к текущему пользователю, сбрасываем флаг блокировки'); + wasAccountBlocked = false; + + // Проверяем наличие сохраненных данных о блокировке + const blockedInfoStr = localStorage.getItem('accountBlockedInfo'); + if (blockedInfoStr) { + console.log('[SocketService] Найдена информация о блокировке, вызываем обработчик разблокировки'); + + if (typeof handleAccountUnblocked === 'function') { + try { + // Создаем объект с данными разблокировки + const unblockData = { + message: 'Ваш аккаунт был разблокирован администратором.', + timestamp: data.timestamp, + userId: data.userId, + unblockType: 'global_notification', + unblockData: { + canRestoreSession: true + } + }; + + handleAccountUnblocked(unblockData); + } catch (error) { + console.error('[SocketService] Ошибка при обработке глобальной разблокировки:', error); + } + } + } } });