diff --git a/src/auth.js b/src/auth.js index 06fa21f..e43af02 100644 --- a/src/auth.js +++ b/src/auth.js @@ -98,31 +98,6 @@ async function login(credentials) { if (response?.data) { setUserData(response.data, response.data.token); - - // Очищаем данные о предыдущей блокировке при успешном входе - const wasBlocked = localStorage.getItem('accountBlockedInfo'); - const sessionBackup = localStorage.getItem('blockedSessionBackup'); - - if (wasBlocked || sessionBackup) { - console.log('[Auth] Обнаружена предыдущая блокировка, пользователь теперь может войти - значит разблокирован'); - - // Очищаем данные о блокировке - localStorage.removeItem('accountBlockedInfo'); - localStorage.removeItem('blockedSessionBackup'); - - // Показываем уведомление о разблокировке - setTimeout(() => { - const notificationEvent = new CustomEvent('show-toast', { - detail: { - message: 'Ваш аккаунт был разблокирован. Добро пожаловать обратно!', - type: 'success', - duration: 5000 - } - }); - window.dispatchEvent(notificationEvent); - }, 1000); - } - router.push('/'); // Перенаправляем на главную после успешного входа return response.data; } @@ -132,30 +107,10 @@ async function login(credentials) { // Обработка специального случая блокировки аккаунта if (error.response?.status === 403 && error.response?.data?.blocked) { const errorData = error.response.data; - console.log('[Auth] Аккаунт заблокирован, сохраняем данные для восстановления сессии'); + console.log('[Auth] Аккаунт заблокирован:', errorData.message); - // Сохраняем данные о блокировке - const blockedInfo = { - blocked: true, - message: errorData.message || 'Ваш аккаунт заблокирован администратором.', - timestamp: new Date().toISOString() - }; - localStorage.setItem('accountBlockedInfo', JSON.stringify(blockedInfo)); - - // Сохраняем данные для восстановления сессии, если есть токен восстановления - if (errorData.restorationToken && errorData.userId && errorData.userName) { - const sessionBackup = { - userId: errorData.userId, - userName: errorData.userName, - token: errorData.restorationToken, - timestamp: new Date().toISOString(), - lastPath: '/', // По умолчанию главная страница - credentials: credentials // Сохраняем credentials для повторного входа - }; - - localStorage.setItem('blockedSessionBackup', JSON.stringify(sessionBackup)); - console.log('[Auth] Сохранены данные для восстановления сессии заблокированного пользователя'); - } + // Просто перенаправляем на страницу входа с параметром блокировки + router.replace({ path: '/login', query: { blocked: 'true' } }); } throw error; @@ -198,33 +153,6 @@ async function handleAccountBlocked(data) { console.log('[Auth] Получено уведомление о блокировке аккаунта:', data); try { - // Сохраняем данные о блокировке - const blockedInfo = { - blocked: true, - message: data?.message || 'Ваш аккаунт был заблокирован администратором.', - reason: data?.reason || 'Нарушение правил сервиса', - timestamp: data?.timestamp || new Date().toISOString() - }; - - localStorage.setItem('accountBlockedInfo', JSON.stringify(blockedInfo)); - - // Сохраняем текущие данные сессии для последующего восстановления - if (user.value && token.value) { - const sessionBackup = { - userId: user.value._id, - userName: user.value.name, - token: token.value, - timestamp: new Date().toISOString(), - lastPath: window.location.pathname - }; - - // Сохраняем резервную копию данных сессии - localStorage.setItem('blockedSessionBackup', JSON.stringify(sessionBackup)); - console.log('[Auth] Сохранена резервная копия данных сессии для пользователя:', user.value.name); - } else { - console.log('[Auth] Невозможно сохранить сессию - пользователь не авторизован'); - } - // Показываем уведомление о блокировке const notificationEvent = new CustomEvent('show-toast', { detail: { @@ -260,87 +188,23 @@ async function handleAccountBlocked(data) { async function handleAccountUnblocked(data) { console.log('[Auth] Получено уведомление о разблокировке аккаунта:', data); - // Удаляем информацию о блокировке, если она была сохранена - localStorage.removeItem('accountBlockedInfo'); - - // Сохраняем информацию о разблокировке для отображения при следующем входе - const unblockedInfo = { - unblocked: true, - message: data?.message || 'Ваш аккаунт был разблокирован.', - timestamp: new Date().toISOString() - }; - localStorage.setItem('accountUnblockedInfo', JSON.stringify(unblockedInfo)); - - // Проверяем, есть ли сохраненная сессия для восстановления - 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] Сохраненная сессия не найдена, показываем только уведомление о разблокировке'); + // Показываем уведомление о разблокировке + const notificationEvent = new CustomEvent('show-toast', { + detail: { + message: data?.message || 'Ваш аккаунт был разблокирован администратором.', + type: 'success', + duration: 5000 } - } catch (error) { - console.error('[Auth] Ошибка при восстановлении сессии после разблокировки:', error); - } - - // Если мы дошли до этой точки, значит автоматическое восстановление не удалось - // или мы не нашли сохраненной сессии. Просто показываем уведомление. - console.log('[Auth] Аккаунт пользователя разблокирован без автоматического входа'); + }); + window.dispatchEvent(notificationEvent); // Если пользователь уже на странице логина, добавляем параметр unblocked=true if (window.location.pathname === '/login') { router.replace({ path: '/login', query: { unblocked: 'true' } }); + } else { + // Перенаправляем на страницу входа с параметром разблокировки + router.replace({ path: '/login', query: { unblocked: 'true' } }); } - - return false; } // Экспортируем то, что понадобится в компонентах diff --git a/src/services/api.js b/src/services/api.js index 3eebc99..a678dc4 100644 --- a/src/services/api.js +++ b/src/services/api.js @@ -1,76 +1,22 @@ import axios from 'axios'; import { useAuth } from '../auth'; // Импортируем функцию авторизации -import { isAccountBlocked } from './socketService'; // Импортируем проверку блокировки из socketService // Создаем экземпляр Axios с базовым URL нашего API -// Настраиваем базовый URL в зависимости от окружения - -// Храним токены отмены запросов для возможности отмены при блокировке -const cancelTokenSources = new Map(); - -// Проверка блокировки аккаунта из localStorage -const checkAccountBlockStatus = () => { - try { - const blockedInfo = localStorage.getItem('accountBlockedInfo'); - if (blockedInfo) { - const blockedData = JSON.parse(blockedInfo); - if (blockedData?.blocked === true) { - console.warn('[API] Обнаружен заблокированный аккаунт, запросы невозможны'); - return true; - } - } - - // Проверяем также флаг из socketService - if (isAccountBlocked && isAccountBlocked()) { - console.warn('[API] Аккаунт заблокирован согласно socketService, запросы невозможны'); - return true; - } - - return false; - } catch (e) { - console.error('[API] Ошибка при проверке статуса блокировки:', e); - return false; - } -}; - -// Определяем базовый URL в зависимости от среды выполнения -const getBaseUrl = () => { - // Всегда используем относительный путь /api. - // В режиме разработки Vite dev server будет проксировать эти запросы согласно настройке server.proxy в vite.config.js. - // В продакшене предполагается, что веб-сервер (например, Nginx) настроен аналогично для обработки /api. - // return '/api'; - return import.meta.env.VITE_API_BASE_URL; // Используем переменную окружения Vite -}; - const apiClient = axios.create({ - baseURL: getBaseUrl(), + baseURL: import.meta.env.VITE_API_BASE_URL || '/api', + timeout: 10000, headers: { 'Content-Type': 'application/json', }, }); -// (Опционально, но очень полезно) Перехватчик для добавления JWT токена к запросам +// Храним токены отмены запросов для возможности отмены при блокировке +const cancelTokenSources = new Map(); + +// Интерсептор запросов - добавляет токен авторизации к каждому запросу apiClient.interceptors.request.use( (config) => { - // Проверяем, заблокирован ли аккаунт, ПЕРЕД выполнением запроса - if (checkAccountBlockStatus()) { - // Если аккаунт заблокирован, отменяем запрос - const source = axios.CancelToken.source(); - config.cancelToken = source.token; - source.cancel('Запрос отменен из-за блокировки аккаунта'); - console.error('[API] Запрос отменен из-за блокировки аккаунта:', config.url); - - // Перенаправляем на страницу логина, если пользователь пытается выполнять запросы - setTimeout(() => { - if (window.location.pathname !== '/login') { - window.location.href = '/login?blocked=true'; - } - }, 0); - - return Promise.reject(new Error('Аккаунт заблокирован')); - } - - const token = localStorage.getItem('userToken'); // Предполагаем, что токен хранится в localStorage + const token = localStorage.getItem('userToken'); if (token) { console.log('[API] Добавление токена к запросу:', config.url); config.headers['Authorization'] = `Bearer ${token}`; @@ -94,7 +40,7 @@ apiClient.interceptors.request.use( } ); -// (Опционально) Перехватчик ответов для обработки глобальных ошибок, например, 401 +// Интерсептор ответов для обработки глобальных ошибок apiClient.interceptors.response.use( (response) => { // Удаляем источник токена отмены после успешного ответа @@ -134,7 +80,6 @@ apiClient.interceptors.response.use( console.error('[API] Неавторизованный запрос (401):', error.config.url); // Обходим замыкание, чтобы избежать проблем с импортом - // При использовании такого подхода, logout будет вызван после текущего цикла выполнения JS setTimeout(() => { const { logout } = useAuth(); logout(); @@ -165,10 +110,9 @@ const setAuthToken = (token) => { // Экспортируем функции для конкретных эндпоинтов export default { - // Добавляем новые утилитарные методы + // Утилитарные методы cancelActiveRequests, setAuthToken, - checkAccountBlockStatus, register(userData) { return apiClient.post('/auth/register', userData); @@ -176,7 +120,7 @@ export default { login(credentials) { return apiClient.post('/auth/login', credentials); }, - getMe() { // Для получения данных пользователя + getMe() { return apiClient.get('/auth/me'); }, updateUserProfile(profileData) { @@ -195,11 +139,10 @@ export default { uploadUserProfilePhoto(formData) { return apiClient.post('/users/profile/photo', formData, { headers: { - 'Content-Type': 'multipart/form-data', // Важно для FormData + 'Content-Type': 'multipart/form-data', }, }); }, - // Новые методы для управления фотографиями setMainPhoto(photoId) { return apiClient.put(`/users/profile/photo/${photoId}/set-main`); }, @@ -207,14 +150,12 @@ export default { return apiClient.delete(`/users/profile/photo/${photoId}`); }, getUserConversations() { - return apiClient.get('/conversations'); // GET /api/conversations + return apiClient.get('/conversations'); }, getMessagesForConversation(conversationId) { - return apiClient.get(`/conversations/${conversationId}/messages`); // GET /api/conversations/:id/messages - }, - deleteMessage(conversationId, messageId) { - return apiClient.delete(`/conversations/${conversationId}/messages/${messageId}`); + return apiClient.get(`/conversations/${conversationId}/messages`); }, + deleteMessage(conversationId, message editMessage(conversationId, messageId, newText) { return apiClient.put(`/conversations/${conversationId}/messages/${messageId}`, { text: newText }); }, diff --git a/src/services/socketService.js b/src/services/socketService.js index a914546..2024a5f 100644 --- a/src/services/socketService.js +++ b/src/services/socketService.js @@ -77,29 +77,11 @@ export const connectSocket = () => { // Сбрасываем флаг блокировки wasAccountBlocked = false; - // Сохраняем информацию о разблокировке для последующего восстановления сессии - const unblockData = { - unblocked: true, - message: data?.message || 'Ваш аккаунт был разблокирован администратором.', - timestamp: data?.timestamp || new Date().toISOString(), - userId: data?.userId || user.value?._id, - unblockType: data?.unblockType || 'server_notification', - canRestoreSession: data?.unblockData?.canRestoreSession || true - }; - - // Сохраняем данные разблокировки в localStorage - try { - localStorage.setItem('accountUnblockedInfo', JSON.stringify(unblockData)); - console.log('[SocketService] Информация о разблокировке сохранена в localStorage'); - } catch (storageError) { - console.error('[SocketService] Ошибка при сохранении информации о разблокировке:', storageError); - } - // Вызываем обработчик разблокировки if (typeof handleAccountUnblocked === 'function') { try { console.log('[SocketService] Вызов обработчика разблокировки аккаунта'); - handleAccountUnblocked(unblockData); + handleAccountUnblocked(data); } catch (error) { console.error('[SocketService] Ошибка при обработке разблокировки аккаунта:', error); @@ -130,28 +112,23 @@ export const connectSocket = () => { 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); - } + // Вызываем обработчик разблокировки + 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); } } } diff --git a/src/views/LoginView.vue b/src/views/LoginView.vue index f861b6b..5fabfad 100644 --- a/src/views/LoginView.vue +++ b/src/views/LoginView.vue @@ -135,32 +135,11 @@ const enableScroll = () => { onMounted(async () => { preventScroll(); // Блокируем прокрутку при монтировании компонента - // Проверяем, есть ли информация о блокировке в localStorage - const storedBlockInfo = localStorage.getItem('accountBlockedInfo'); - if (storedBlockInfo) { - try { - const parsedInfo = JSON.parse(storedBlockInfo); - blockedInfo.value = parsedInfo; - - // Удаляем дублирующее сообщение об ошибке, так как эта информация уже - // отображается в блоке blocked-account-message выше кнопки "Войти" - } catch (e) { - console.error('Ошибка при парсинге информации о блокировке:', e); - } - } - - // Проверяем наличие информации о разблокировке только для отображения уведомления - const unblockedInfoStr = localStorage.getItem('accountUnblockedInfo'); - if (unblockedInfoStr) { - try { - const unblockedInfo = JSON.parse(unblockedInfoStr); - // Отображаем уведомление о разблокировке - errorMessage.value = unblockedInfo.message || 'Ваш аккаунт был разблокирован. Пожалуйста, войдите в систему.'; - // Удаляем информацию о разблокировке, чтобы сообщение не появлялось повторно - localStorage.removeItem('accountUnblockedInfo'); - } catch (e) { - console.error('[LoginView] Ошибка при парсинге информации о разблокировке:', e); - } + // Проверяем query параметры для отображения сообщений + if (route.query.blocked === 'true') { + errorMessage.value = 'Ваш аккаунт заблокирован администратором.'; + } else if (route.query.unblocked === 'true') { + errorMessage.value = 'Ваш аккаунт был разблокирован. Пожалуйста, войдите в систему.'; } });