ваше сообщение коммита
This commit is contained in:
@@ -194,6 +194,38 @@ router.post('/telegram/verify', async (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ---> ШАГ 4 И 5: ПОИСК ПРИВЯЗАННОГО КОШЕЛЬКА И ПРОВЕРКА БАЛАНСА <---
|
||||||
|
let linkedWalletAddress = null;
|
||||||
|
let finalIsAdmin = false; // Роль по умолчанию
|
||||||
|
|
||||||
|
try {
|
||||||
|
const walletIdentity = await identityService.findIdentity(verificationResult.userId, 'wallet');
|
||||||
|
if (walletIdentity) {
|
||||||
|
linkedWalletAddress = walletIdentity.provider_id;
|
||||||
|
logger.info(`[telegram/verify] Found linked wallet ${linkedWalletAddress} for user ${verificationResult.userId}`);
|
||||||
|
|
||||||
|
// Проверяем баланс токенов для определения роли
|
||||||
|
finalIsAdmin = await authService.checkAdminTokens(linkedWalletAddress);
|
||||||
|
logger.info(`[telegram/verify] Admin status based on token balance for ${linkedWalletAddress}: ${finalIsAdmin}`);
|
||||||
|
|
||||||
|
// Обновляем роль в БД, если она отличается от той, что была получена из verifyTelegramAuth
|
||||||
|
const currentRoleInDb = verificationResult.role === 'admin';
|
||||||
|
if (finalIsAdmin !== currentRoleInDb) {
|
||||||
|
await db.query('UPDATE users SET role = $1 WHERE id = $2', [finalIsAdmin ? 'admin' : 'user', verificationResult.userId]);
|
||||||
|
logger.info(`[telegram/verify] User role updated in DB for user ${verificationResult.userId} to ${finalIsAdmin ? 'admin' : 'user'}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.info(`[telegram/verify] No linked wallet found for user ${verificationResult.userId}. Role remains '${verificationResult.role}'`);
|
||||||
|
// Если кошелек не найден, используем роль из verificationResult (скорее всего 'user')
|
||||||
|
finalIsAdmin = verificationResult.role === 'admin';
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`[telegram/verify] Error finding linked wallet or checking tokens for user ${verificationResult.userId}:`, error);
|
||||||
|
// В случае ошибки, используем роль из verificationResult
|
||||||
|
finalIsAdmin = verificationResult.role === 'admin';
|
||||||
|
}
|
||||||
|
// ---> КОНЕЦ ШАГОВ 4 И 5 <---
|
||||||
|
|
||||||
// Создаем новую сессию для этого telegramId
|
// Создаем новую сессию для этого telegramId
|
||||||
req.session.regenerate(async (err) => {
|
req.session.regenerate(async (err) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -209,7 +241,13 @@ router.post('/telegram/verify', async (req, res) => {
|
|||||||
req.session.telegramId = telegramId;
|
req.session.telegramId = telegramId;
|
||||||
req.session.authType = 'telegram';
|
req.session.authType = 'telegram';
|
||||||
req.session.authenticated = true;
|
req.session.authenticated = true;
|
||||||
req.session.role = verificationResult.role;
|
req.session.isAdmin = finalIsAdmin; // <-- УСТАНАВЛИВАЕМ РОЛЬ ПОСЛЕ ПРОВЕРКИ БАЛАНСА
|
||||||
|
|
||||||
|
// ---> ДОБАВЛЯЕМ АДРЕС КОШЕЛЬКА В СЕССИЮ (ЕСЛИ НАЙДЕН) <---
|
||||||
|
if (linkedWalletAddress) {
|
||||||
|
req.session.address = linkedWalletAddress;
|
||||||
|
}
|
||||||
|
// ---> КОНЕЦ ДОБАВЛЕНИЯ АДРЕСА <---
|
||||||
|
|
||||||
// Восстанавливаем гостевой ID, если он был
|
// Восстанавливаем гостевой ID, если он был
|
||||||
if (guestId) {
|
if (guestId) {
|
||||||
@@ -227,9 +265,10 @@ router.post('/telegram/verify', async (req, res) => {
|
|||||||
return res.json({
|
return res.json({
|
||||||
success: true,
|
success: true,
|
||||||
userId: verificationResult.userId,
|
userId: verificationResult.userId,
|
||||||
role: verificationResult.role,
|
isAdmin: finalIsAdmin, // <-- ВОЗВРАЩАЕМ АКТУАЛЬНУЮ РОЛЬ
|
||||||
telegramId,
|
telegramId,
|
||||||
isNewUser: verificationResult.isNewUser,
|
isNewUser: verificationResult.isNewUser,
|
||||||
|
address: linkedWalletAddress || null // <-- ВОЗВРАЩАЕМ АДРЕС КОШЕЛЬКА
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
@@ -285,11 +324,12 @@ router.post('/email/verify-code', async (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Если email передан в запросе, сохраняем его в сессии
|
// Если email передан в запросе, сохраняем его в сессии для проверки кода
|
||||||
if (email && !req.session.pendingEmail) {
|
if (email && !req.session.pendingEmail) {
|
||||||
req.session.pendingEmail = email.toLowerCase();
|
req.session.pendingEmail = email.toLowerCase();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Нужен email в сессии для проверки кода
|
||||||
if (!req.session.pendingEmail) {
|
if (!req.session.pendingEmail) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
success: false,
|
success: false,
|
||||||
@@ -297,135 +337,115 @@ router.post('/email/verify-code', async (req, res) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Сохраняем гостевой ID до проверки
|
// Сохраняем гостевые ID до обработки
|
||||||
const guestId = req.session.guestId;
|
const guestId = req.session.guestId;
|
||||||
const previousGuestId = req.session.previousGuestId;
|
const previousGuestId = req.session.previousGuestId;
|
||||||
|
|
||||||
// Проверяем код через сервис верификации
|
// 1. Проверяем сам код верификации
|
||||||
const verificationResult = await verificationService.verifyCode(
|
const codeVerificationResult = await verificationService.verifyCode(
|
||||||
code,
|
code,
|
||||||
'email',
|
'email',
|
||||||
req.session.pendingEmail
|
req.session.pendingEmail
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!verificationResult.success) {
|
if (!codeVerificationResult.success) {
|
||||||
return res.status(400).json({
|
return res.status(400).json({
|
||||||
success: false,
|
success: false,
|
||||||
error: verificationResult.error || 'Неверный код подтверждения',
|
error: codeVerificationResult.error || 'Неверный код подтверждения',
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Получаем или создаем пользователя
|
// 2. Обрабатываем аутентификацию/привязку и проверяем роль через AuthService
|
||||||
let userId;
|
const authResult = await authService.handleEmailVerification(
|
||||||
let isNewAuth = false;
|
req.session.pendingEmail, // Передаем email из сессии
|
||||||
|
req.session // Передаем всю сессию
|
||||||
|
);
|
||||||
|
|
||||||
// Проверяем, авторизован ли пользователь
|
// ---> ДОБАВЛЯЕМ ПОЛУЧЕНИЕ И СОХРАНЕНИЕ АДРЕСА КОШЕЛЬКА В СЕССИЮ <---
|
||||||
if (req.session.authenticated && req.session.userId) {
|
let linkedWalletAddress = null;
|
||||||
// Связываем email с существующим пользователем
|
if (authResult.userId) {
|
||||||
userId = req.session.userId;
|
try {
|
||||||
logger.info(
|
const walletIdentity = await identityService.findIdentity(authResult.userId, 'wallet');
|
||||||
`[email/verify-code] Linking email ${req.session.pendingEmail} to existing authenticated user ${userId}`
|
if (walletIdentity) {
|
||||||
);
|
linkedWalletAddress = walletIdentity.provider_id;
|
||||||
|
}
|
||||||
|
} catch (walletError) {
|
||||||
|
logger.warn(`[email/verify-code] Could not fetch linked wallet for user ${authResult.userId}:`, walletError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// ---> КОНЕЦ ДОБАВЛЕНИЯ <---
|
||||||
|
|
||||||
// Связываем email с текущим аккаунтом
|
// ---> ОПРЕДЕЛЯЕМ РОЛЬ НА ОСНОВЕ БАЛАНСА ПРИВЯЗАННОГО КОШЕЛЬКА <---
|
||||||
const linkResult = await authService.linkIdentity(userId, 'email', req.session.pendingEmail);
|
let finalIsAdmin = false; // Роль по умолчанию
|
||||||
|
if (linkedWalletAddress) {
|
||||||
|
try {
|
||||||
|
finalIsAdmin = await authService.checkAdminTokens(linkedWalletAddress);
|
||||||
|
logger.info(`[email/verify-code] Admin status based on token balance for ${linkedWalletAddress}: ${finalIsAdmin}`);
|
||||||
|
|
||||||
// Сохраняем email в сессии
|
// Обновляем роль в БД, если она отличается от текущей
|
||||||
req.session.email = req.session.pendingEmail;
|
const currentRole = authResult.role === 'admin';
|
||||||
|
if (finalIsAdmin !== currentRole) {
|
||||||
// Удаляем временные данные
|
await db.query('UPDATE users SET role = $1 WHERE id = $2', [finalIsAdmin ? 'admin' : 'user', authResult.userId]);
|
||||||
delete req.session.pendingEmail;
|
logger.info(`[email/verify-code] User role updated in DB for user ${authResult.userId} to ${finalIsAdmin ? 'admin' : 'user'}`);
|
||||||
|
}
|
||||||
// Сохраняем сессию
|
} catch (tokenCheckError) {
|
||||||
await sessionService.saveSession(req.session);
|
logger.error(`[email/verify-code] Error checking admin tokens for ${linkedWalletAddress}:`, tokenCheckError);
|
||||||
|
// В случае ошибки проверки токенов, используем роль из authResult
|
||||||
return res.json({
|
finalIsAdmin = authResult.role === 'admin';
|
||||||
success: true,
|
}
|
||||||
userId,
|
|
||||||
email: req.session.email,
|
|
||||||
authenticated: true,
|
|
||||||
linked: true,
|
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
// Если пользователь не авторизован, ищем существующего пользователя или создаем нового
|
// Если кошелек не привязан, используем роль из authResult (вероятно, 'user')
|
||||||
|
finalIsAdmin = authResult.role === 'admin';
|
||||||
// Ищем существующего пользователя по email
|
logger.info(`[email/verify-code] No linked wallet found for user ${authResult.userId}. Using role from authResult: ${authResult.role}`);
|
||||||
const existingUser = await identityService.findUserByIdentity(
|
|
||||||
'email',
|
|
||||||
req.session.pendingEmail
|
|
||||||
);
|
|
||||||
|
|
||||||
if (existingUser) {
|
|
||||||
// Используем существующего пользователя
|
|
||||||
userId = existingUser.id;
|
|
||||||
logger.info(
|
|
||||||
`[email/verify-code] Using existing user ${userId} with email ${req.session.pendingEmail}`
|
|
||||||
);
|
|
||||||
} else if (req.session.userId) {
|
|
||||||
// Используем текущего пользователя
|
|
||||||
userId = req.session.userId;
|
|
||||||
logger.info(
|
|
||||||
`[email/verify-code] Using current user ${userId} for email ${req.session.pendingEmail}`
|
|
||||||
);
|
|
||||||
} else if (req.session.tempUserId) {
|
|
||||||
// Используем временного пользователя
|
|
||||||
userId = req.session.tempUserId;
|
|
||||||
logger.info(
|
|
||||||
`[email/verify-code] Using temporary user ${userId} for email ${req.session.pendingEmail}`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
// Создаем нового пользователя
|
|
||||||
const newUser = await db.query('INSERT INTO users (role) VALUES ($1) RETURNING id', [
|
|
||||||
'user',
|
|
||||||
]);
|
|
||||||
userId = newUser.rows[0].id;
|
|
||||||
isNewAuth = true;
|
|
||||||
logger.info(
|
|
||||||
`[email/verify-code] Created new user ${userId} for email ${req.session.pendingEmail}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Сохраняем email как идентификатор
|
|
||||||
await identityService.saveIdentity(userId, 'email', req.session.pendingEmail, true);
|
|
||||||
|
|
||||||
// Сохраняем гостевые идентификаторы
|
|
||||||
if (guestId) {
|
|
||||||
await identityService.saveIdentity(userId, 'guest', guestId, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (previousGuestId && previousGuestId !== guestId) {
|
|
||||||
await identityService.saveIdentity(userId, 'guest', previousGuestId, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Устанавливаем сессию
|
|
||||||
req.session.userId = userId;
|
|
||||||
req.session.authenticated = true;
|
|
||||||
req.session.authType = 'email';
|
|
||||||
req.session.email = req.session.pendingEmail;
|
|
||||||
|
|
||||||
// Удаляем временные данные
|
|
||||||
delete req.session.tempUserId;
|
|
||||||
delete req.session.pendingEmail;
|
|
||||||
|
|
||||||
// Сохраняем сессию
|
|
||||||
await sessionService.saveSession(req.session);
|
|
||||||
|
|
||||||
// Связываем гостевые сообщения
|
|
||||||
await sessionService.linkGuestMessages(req.session, userId);
|
|
||||||
|
|
||||||
return res.json({
|
|
||||||
success: true,
|
|
||||||
userId,
|
|
||||||
email: req.session.email,
|
|
||||||
authenticated: true,
|
|
||||||
isNewAuth,
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
// ---> КОНЕЦ ОПРЕДЕЛЕНИЯ РОЛИ <---
|
||||||
|
|
||||||
|
// 3. Устанавливаем сессию на основе результата
|
||||||
|
req.session.userId = authResult.userId;
|
||||||
|
req.session.authenticated = true;
|
||||||
|
req.session.authType = 'email';
|
||||||
|
req.session.email = authResult.email;
|
||||||
|
req.session.isAdmin = finalIsAdmin; // <-- УСТАНАВЛИВАЕМ РОЛЬ ПОСЛЕ ПРОВЕРКИ БАЛАНСА
|
||||||
|
// ---> ДОБАВЛЯЕМ АДРЕС КОШЕЛЬКА В СЕССИЮ <---
|
||||||
|
if (linkedWalletAddress) {
|
||||||
|
req.session.address = linkedWalletAddress;
|
||||||
|
}
|
||||||
|
// ---> КОНЕЦ ДОБАВЛЕНИЯ <---
|
||||||
|
|
||||||
|
// Восстанавливаем/обновляем гостевые ID в сессии, если они были
|
||||||
|
if (guestId) req.session.guestId = guestId;
|
||||||
|
if (previousGuestId) req.session.previousGuestId = previousGuestId;
|
||||||
|
|
||||||
|
// Очищаем временные данные (authService уже должен был это сделать, но на всякий случай)
|
||||||
|
delete req.session.tempUserId;
|
||||||
|
delete req.session.pendingEmail;
|
||||||
|
|
||||||
|
// Сохраняем обновленную сессию
|
||||||
|
await sessionService.saveSession(req.session);
|
||||||
|
|
||||||
|
// Связываем гостевые сообщения
|
||||||
|
await sessionService.linkGuestMessages(req.session, authResult.userId);
|
||||||
|
|
||||||
|
// 4. Отправляем ответ
|
||||||
|
return res.json({
|
||||||
|
success: true,
|
||||||
|
userId: authResult.userId,
|
||||||
|
email: authResult.email,
|
||||||
|
isAdmin: finalIsAdmin, // <-- ВОЗВРАЩАЕМ АКТУАЛЬНУЮ РОЛЬ
|
||||||
|
authenticated: true,
|
||||||
|
isNewAuth: authResult.isNewUser,
|
||||||
|
address: linkedWalletAddress || null // <-- ВОЗВРАЩАЕМ АДРЕС КОШЕЛЬКА
|
||||||
|
});
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('[email/verify-code] Error:', error);
|
logger.error('[email/verify-code] Error:', error);
|
||||||
|
// Проверяем, является ли ошибка созданной нами в authService
|
||||||
|
const errorMessage = error.message === 'Ошибка обработки верификации Email'
|
||||||
|
? error.message
|
||||||
|
: 'Ошибка сервера';
|
||||||
return res.status(500).json({
|
return res.status(500).json({
|
||||||
success: false,
|
success: false,
|
||||||
error: 'Ошибка сервера',
|
error: errorMessage,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ const { ethers } = require('ethers');
|
|||||||
const crypto = require('crypto');
|
const crypto = require('crypto');
|
||||||
const { processMessage } = require('./ai-assistant'); // Используем AI Assistant
|
const { processMessage } = require('./ai-assistant'); // Используем AI Assistant
|
||||||
const verificationService = require('./verification-service'); // Используем сервис верификации
|
const verificationService = require('./verification-service'); // Используем сервис верификации
|
||||||
|
const identityService = require('./identity-service'); // <-- ДОБАВЛЕН ИМПОРТ
|
||||||
|
|
||||||
const ADMIN_CONTRACTS = [
|
const ADMIN_CONTRACTS = [
|
||||||
{ address: '0xd95a45fc46a7300e6022885afec3d618d7d3f27c', network: 'eth' },
|
{ address: '0xd95a45fc46a7300e6022885afec3d618d7d3f27c', network: 'eth' },
|
||||||
@@ -385,13 +386,22 @@ class AuthService {
|
|||||||
|
|
||||||
// Получение связанного кошелька
|
// Получение связанного кошелька
|
||||||
async getLinkedWallet(userId) {
|
async getLinkedWallet(userId) {
|
||||||
const result = await db.query(
|
logger.info(`[getLinkedWallet] Called with userId: ${userId} (Type: ${typeof userId})`);
|
||||||
`SELECT provider_id as address
|
try {
|
||||||
FROM user_identities
|
const result = await db.query(
|
||||||
WHERE user_id = $1 AND provider = 'wallet'`,
|
`SELECT provider_id as address
|
||||||
[userId]
|
FROM user_identities
|
||||||
);
|
WHERE user_id = $1 AND provider = 'wallet'`,
|
||||||
return result.rows[0]?.address;
|
[userId]
|
||||||
|
);
|
||||||
|
logger.info(`[getLinkedWallet] DB query result for userId ${userId}:`, result.rows);
|
||||||
|
const address = result.rows[0]?.address;
|
||||||
|
logger.info(`[getLinkedWallet] Returning address: ${address} for userId ${userId}`);
|
||||||
|
return address;
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(`[getLinkedWallet] Error fetching linked wallet for userId ${userId}:`, error);
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -774,6 +784,110 @@ class AuthService {
|
|||||||
throw error;
|
throw error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Обрабатывает успешную верификацию Email.
|
||||||
|
* Находит или создает пользователя, связывает email, проверяет роль админа.
|
||||||
|
* @param {string} email - Верифицированный email.
|
||||||
|
* @param {object} session - Объект сессии запроса.
|
||||||
|
* @returns {Promise<{userId: number, email: string, role: string, isNewUser: boolean}>}
|
||||||
|
*/
|
||||||
|
async handleEmailVerification(email, session) {
|
||||||
|
const normalizedEmail = email.toLowerCase();
|
||||||
|
let userId;
|
||||||
|
let isNewUser = false;
|
||||||
|
let userRole = 'user'; // Роль по умолчанию
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 1. Определить пользователя (существующий по email/сессии или новый)
|
||||||
|
if (session.authenticated && session.userId) {
|
||||||
|
// Используем уже аутентифицированного пользователя
|
||||||
|
userId = session.userId;
|
||||||
|
logger.info(`[handleEmailVerification] Using authenticated user ${userId}`);
|
||||||
|
} else {
|
||||||
|
// Ищем существующего пользователя по email
|
||||||
|
const existingUser = await identityService.findUserByIdentity('email', normalizedEmail);
|
||||||
|
if (existingUser) {
|
||||||
|
userId = existingUser.id;
|
||||||
|
logger.info(`[handleEmailVerification] Found existing user ${userId} by email ${normalizedEmail}`);
|
||||||
|
} else if (session.tempUserId) {
|
||||||
|
// Используем временного пользователя, если есть
|
||||||
|
userId = session.tempUserId;
|
||||||
|
logger.info(`[handleEmailVerification] Using temporary user ${userId}`);
|
||||||
|
} else {
|
||||||
|
// Создаем нового пользователя
|
||||||
|
const newUserResult = await db.query('INSERT INTO users (role) VALUES ($1) RETURNING id', [
|
||||||
|
'user',
|
||||||
|
]);
|
||||||
|
userId = newUserResult.rows[0].id;
|
||||||
|
isNewUser = true;
|
||||||
|
logger.info(`[handleEmailVerification] Created new user ${userId}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Связать email с пользователем (если еще не связан)
|
||||||
|
await identityService.saveIdentity(userId, 'email', normalizedEmail, true);
|
||||||
|
logger.info(`[handleEmailVerification] Ensured email identity ${normalizedEmail} for user ${userId}`);
|
||||||
|
|
||||||
|
// 3. Связать гостевые ID (если есть)
|
||||||
|
if (session.guestId) {
|
||||||
|
await identityService.saveIdentity(userId, 'guest', session.guestId, true);
|
||||||
|
}
|
||||||
|
if (session.previousGuestId && session.previousGuestId !== session.guestId) {
|
||||||
|
await identityService.saveIdentity(userId, 'guest', session.previousGuestId, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Проверить роль на основе привязанного кошелька
|
||||||
|
try {
|
||||||
|
const linkedWallet = await this.getLinkedWallet(userId);
|
||||||
|
if (linkedWallet && linkedWallet.provider_id) {
|
||||||
|
logger.info(`[handleEmailVerification] Found linked wallet ${linkedWallet.provider_id}. Checking role...`);
|
||||||
|
const isAdmin = await this.checkAdminRole(linkedWallet.provider_id);
|
||||||
|
userRole = isAdmin ? 'admin' : 'user';
|
||||||
|
logger.info(`[handleEmailVerification] Role determined as: ${userRole}`);
|
||||||
|
|
||||||
|
// Опционально: Обновить роль в таблице users
|
||||||
|
const currentUser = await db.query('SELECT role FROM users WHERE id = $1', [userId]);
|
||||||
|
if (currentUser.rows.length > 0 && currentUser.rows[0].role !== userRole) {
|
||||||
|
await db.query('UPDATE users SET role = $1 WHERE id = $2', [userRole, userId]);
|
||||||
|
logger.info(`[handleEmailVerification] Updated user role in DB to ${userRole}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.info(`[handleEmailVerification] No linked wallet found. Role remains 'user'.`);
|
||||||
|
// Если кошелька нет, проверяем текущую роль из базы (на случай, если она была admin ранее)
|
||||||
|
const currentUser = await db.query('SELECT role FROM users WHERE id = $1', [userId]);
|
||||||
|
if (currentUser.rows.length > 0) {
|
||||||
|
userRole = currentUser.rows[0].role;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (roleCheckError) {
|
||||||
|
logger.error(`[handleEmailVerification] Error checking admin role:`, roleCheckError);
|
||||||
|
// В случае ошибки берем текущую роль из базы или оставляем 'user'
|
||||||
|
try {
|
||||||
|
const currentUser = await db.query('SELECT role FROM users WHERE id = $1', [userId]);
|
||||||
|
if (currentUser.rows.length > 0) {
|
||||||
|
userRole = currentUser.rows[0].role;
|
||||||
|
}
|
||||||
|
} catch (dbError) {
|
||||||
|
logger.error('Error fetching current user role after role check error:', dbError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Очистка временных данных из сессии
|
||||||
|
delete session.tempUserId;
|
||||||
|
delete session.pendingEmail;
|
||||||
|
|
||||||
|
return {
|
||||||
|
userId,
|
||||||
|
email: normalizedEmail,
|
||||||
|
role: userRole,
|
||||||
|
isNewUser,
|
||||||
|
};
|
||||||
|
} catch (error) {
|
||||||
|
logger.error('Error in handleEmailVerification:', error);
|
||||||
|
throw new Error('Ошибка обработки верификации Email');
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Создаем и экспортируем единственный экземпляр
|
// Создаем и экспортируем единственный экземпляр
|
||||||
|
|||||||
@@ -161,6 +161,31 @@ class EmailAuth {
|
|||||||
await authService.identityService.saveIdentity(finalUserId, 'email', email, true);
|
await authService.identityService.saveIdentity(finalUserId, 'email', email, true);
|
||||||
logger.info(`[checkEmailVerification] Added email identity ${email} for user ${finalUserId}`);
|
logger.info(`[checkEmailVerification] Added email identity ${email} for user ${finalUserId}`);
|
||||||
|
|
||||||
|
// ----> НАЧАЛО: Проверка роли на основе привязанного кошелька
|
||||||
|
let userRole = 'user'; // Роль по умолчанию
|
||||||
|
try {
|
||||||
|
const linkedWallet = await authService.getLinkedWallet(finalUserId);
|
||||||
|
if (linkedWallet) {
|
||||||
|
logger.info(`[checkEmailVerification] Found linked wallet ${linkedWallet} for user ${finalUserId}. Checking admin role...`);
|
||||||
|
const isAdmin = await authService.checkAdminRole(linkedWallet);
|
||||||
|
userRole = isAdmin ? 'admin' : 'user';
|
||||||
|
logger.info(`[checkEmailVerification] Role for user ${finalUserId} determined as: ${userRole}`);
|
||||||
|
|
||||||
|
// Опционально: Обновить роль в таблице users, если она отличается
|
||||||
|
const currentUser = await db.query('SELECT role FROM users WHERE id = $1', [finalUserId]);
|
||||||
|
if (currentUser.rows.length > 0 && currentUser.rows[0].role !== userRole) {
|
||||||
|
await db.query('UPDATE users SET role = $1 WHERE id = $2', [userRole, finalUserId]);
|
||||||
|
logger.info(`[checkEmailVerification] Updated user role in DB to ${userRole}`);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
logger.info(`[checkEmailVerification] No linked wallet found for user ${finalUserId}. Role remains 'user'.`);
|
||||||
|
}
|
||||||
|
} catch (roleCheckError) {
|
||||||
|
logger.error(`[checkEmailVerification] Error checking admin role for user ${finalUserId}:`, roleCheckError);
|
||||||
|
// В случае ошибки оставляем роль 'user'
|
||||||
|
}
|
||||||
|
// ----> КОНЕЦ: Проверка роли
|
||||||
|
|
||||||
// Если есть гостевой ID, добавляем его тоже
|
// Если есть гостевой ID, добавляем его тоже
|
||||||
if (session.guestId) {
|
if (session.guestId) {
|
||||||
await authService.identityService.saveIdentity(finalUserId, 'guest', session.guestId, true);
|
await authService.identityService.saveIdentity(finalUserId, 'guest', session.guestId, true);
|
||||||
@@ -179,6 +204,7 @@ class EmailAuth {
|
|||||||
verified: true,
|
verified: true,
|
||||||
userId: finalUserId,
|
userId: finalUserId,
|
||||||
email: email,
|
email: email,
|
||||||
|
role: userRole,
|
||||||
};
|
};
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('Error checking email verification:', error);
|
logger.error('Error checking email verification:', error);
|
||||||
|
|||||||
@@ -238,6 +238,49 @@ class IdentityService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Находит конкретный идентификатор пользователя по его типу.
|
||||||
|
* Возвращает первую найденную запись.
|
||||||
|
* @param {number} userId - ID пользователя
|
||||||
|
* @param {string} provider - Тип идентификатора (например, 'wallet', 'email')
|
||||||
|
* @returns {Promise<object|null>} - Объект идентификатора (содержит provider_id) или null
|
||||||
|
*/
|
||||||
|
async findIdentity(userId, provider) {
|
||||||
|
try {
|
||||||
|
if (!userId || !provider) {
|
||||||
|
logger.warn(`[IdentityService] Missing parameters for findIdentity: userId=${userId}, provider=${provider}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Нормализуем провайдера
|
||||||
|
const normalizedProvider = provider.toLowerCase();
|
||||||
|
|
||||||
|
const result = await db.query(
|
||||||
|
`SELECT provider, provider_id, created_at, updated_at
|
||||||
|
FROM user_identities
|
||||||
|
WHERE user_id = $1 AND provider = $2
|
||||||
|
LIMIT 1`,
|
||||||
|
[userId, normalizedProvider]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result.rows.length === 0) {
|
||||||
|
logger.info(`[IdentityService] No ${normalizedProvider} identity found for user ${userId}`);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(
|
||||||
|
`[IdentityService] Found ${normalizedProvider} identity for user ${userId}: ${result.rows[0].provider_id}`
|
||||||
|
);
|
||||||
|
return result.rows[0]; // Возвращаем всю строку (включая provider_id)
|
||||||
|
} catch (error) {
|
||||||
|
logger.error(
|
||||||
|
`[IdentityService] Error finding ${provider} identity for user ${userId}:`,
|
||||||
|
error
|
||||||
|
);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Сохраняет идентификаторы из сессии для пользователя
|
* Сохраняет идентификаторы из сессии для пользователя
|
||||||
* @param {object} session - Объект сессии
|
* @param {object} session - Объект сессии
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ async function getBot() {
|
|||||||
const providerId = verification.provider_id;
|
const providerId = verification.provider_id;
|
||||||
const linkedUserId = verification.user_id; // Получаем связанный userId если он есть
|
const linkedUserId = verification.user_id; // Получаем связанный userId если он есть
|
||||||
let userId;
|
let userId;
|
||||||
|
let userRole = 'user'; // Роль по умолчанию
|
||||||
|
|
||||||
// Отмечаем код как использованный
|
// Отмечаем код как использованный
|
||||||
await db.query('UPDATE verification_codes SET used = true WHERE id = $1', [
|
await db.query('UPDATE verification_codes SET used = true WHERE id = $1', [
|
||||||
@@ -134,35 +135,95 @@ async function getBot() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Логируем guestId перед обновлением сессии
|
// ----> НАЧАЛО: Проверка роли на основе привязанного кошелька <----
|
||||||
logger.info(`[telegramBot] Attempting to update session for guestId: ${providerId}`);
|
if (userId) { // Убедимся, что userId определен
|
||||||
|
logger.info(`[TelegramBot] Checking linked wallet for determined userId: ${userId} (Type: ${typeof userId})`);
|
||||||
|
try {
|
||||||
|
const linkedWallet = await authService.getLinkedWallet(userId);
|
||||||
|
if (linkedWallet) {
|
||||||
|
logger.info(`[TelegramBot] Found linked wallet ${linkedWallet} for user ${userId}. Checking role...`);
|
||||||
|
const isAdmin = await authService.checkAdminRole(linkedWallet);
|
||||||
|
userRole = isAdmin ? 'admin' : 'user';
|
||||||
|
logger.info(`[TelegramBot] Role for user ${userId} determined as: ${userRole}`);
|
||||||
|
|
||||||
// Обновляем сессию в базе данных
|
// Опционально: Обновить роль в таблице users
|
||||||
const updateResult = await db.query(
|
const currentUser = await db.query('SELECT role FROM users WHERE id = $1', [userId]);
|
||||||
`UPDATE session
|
if (currentUser.rows.length > 0 && currentUser.rows[0].role !== userRole) {
|
||||||
SET sess = (sess::jsonb || $1::jsonb)::json
|
await db.query('UPDATE users SET role = $1 WHERE id = $2', [userRole, userId]);
|
||||||
WHERE sess::jsonb @> $2::jsonb`,
|
logger.info(`[TelegramBot] Updated user role in DB to ${userRole}`);
|
||||||
[
|
}
|
||||||
JSON.stringify({
|
} else {
|
||||||
userId: userId.toString(),
|
logger.info(`[TelegramBot] No linked wallet found for user ${userId}. Checking current DB role.`);
|
||||||
authenticated: true,
|
// Если кошелька нет, берем текущую роль из базы
|
||||||
authType: 'telegram',
|
const currentUser = await db.query('SELECT role FROM users WHERE id = $1', [userId]);
|
||||||
telegramId: ctx.from.id.toString(),
|
if (currentUser.rows.length > 0) {
|
||||||
// Добавляем имя и юзернейм из Telegram
|
userRole = currentUser.rows[0].role;
|
||||||
telegramUsername: ctx.from.username,
|
}
|
||||||
telegramFirstName: ctx.from.first_name,
|
}
|
||||||
}),
|
} catch (roleCheckError) {
|
||||||
JSON.stringify({ guestId: providerId }),
|
logger.error(`[TelegramBot] Error checking admin role for user ${userId}:`, roleCheckError);
|
||||||
]
|
// В случае ошибки берем роль из базы или оставляем 'user'
|
||||||
);
|
try {
|
||||||
|
const currentUser = await db.query('SELECT role FROM users WHERE id = $1', [userId]);
|
||||||
// Логируем результат обновления сессии
|
if (currentUser.rows.length > 0) { userRole = currentUser.rows[0].role; }
|
||||||
if (updateResult.rowCount > 0) {
|
} catch (dbError) { /* ignore */ }
|
||||||
logger.info(`Session updated successfully for guestId: ${providerId}, userId: ${userId}`);
|
}
|
||||||
} else {
|
} else {
|
||||||
logger.warn(
|
logger.error('[TelegramBot] Cannot check role because userId is undefined!');
|
||||||
`Session update failed: No session found or updated for guestId: ${providerId}. User ${userId} authenticated via Telegram, but web session might not reflect it.`
|
}
|
||||||
|
// ----> КОНЕЦ: Проверка роли <----
|
||||||
|
|
||||||
|
// Логируем userId перед обновлением сессии
|
||||||
|
logger.info(`[telegramBot] Attempting to update session for userId: ${userId}`);
|
||||||
|
|
||||||
|
// Находим последнюю активную сессию для данного userId
|
||||||
|
let activeSessionId = null;
|
||||||
|
try {
|
||||||
|
// Ищем сессию, где есть userId и она не истекла (проверка expires_at)
|
||||||
|
// Сортируем по expires_at DESC чтобы взять самую "свежую", если их несколько
|
||||||
|
const sessionResult = await db.query(
|
||||||
|
`SELECT sid FROM session
|
||||||
|
WHERE sess ->> 'userId' = $1
|
||||||
|
AND expire > NOW()
|
||||||
|
ORDER BY expire DESC
|
||||||
|
LIMIT 1`,
|
||||||
|
[userId?.toString()] // Используем optional chaining и преобразуем в строку
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (sessionResult.rows.length > 0) {
|
||||||
|
activeSessionId = sessionResult.rows[0].sid;
|
||||||
|
logger.info(`[telegramBot] Found active session ID ${activeSessionId} for user ${userId}`);
|
||||||
|
|
||||||
|
// Обновляем найденную сессию в базе данных, добавляя/перезаписывая данные Telegram
|
||||||
|
const updateResult = await db.query(
|
||||||
|
`UPDATE session
|
||||||
|
SET sess = (sess::jsonb || $1::jsonb)::json
|
||||||
|
WHERE sid = $2`,
|
||||||
|
[
|
||||||
|
JSON.stringify({
|
||||||
|
// authenticated: true, // Не перезаписываем, т.к. сессия уже должна быть аутентифицирована
|
||||||
|
authType: 'telegram', // Обновляем тип аутентификации
|
||||||
|
telegramId: ctx.from.id.toString(),
|
||||||
|
telegramUsername: ctx.from.username,
|
||||||
|
telegramFirstName: ctx.from.first_name,
|
||||||
|
role: userRole, // Записываем определенную роль
|
||||||
|
// userId: userId?.toString() // userId уже должен быть в сессии
|
||||||
|
}),
|
||||||
|
activeSessionId // Обновляем по найденному session ID
|
||||||
|
]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (updateResult.rowCount > 0) {
|
||||||
|
logger.info(`[telegramBot] Session ${activeSessionId} updated successfully with Telegram data for user ${userId}`);
|
||||||
|
} else {
|
||||||
|
logger.warn(`[telegramBot] Session update query executed but did not update rows for sid: ${activeSessionId}. This might indicate a concurrency issue or incorrect sid.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
logger.warn(`[telegramBot] No active web session found for userId: ${userId}. Telegram is linked, but the user might need to refresh their browser session.`);
|
||||||
|
}
|
||||||
|
} catch(sessionError) {
|
||||||
|
logger.error(`[telegramBot] Error finding or updating session for userId ${userId}:`, sessionError);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Отправляем сообщение об успешной аутентификации
|
// Отправляем сообщение об успешной аутентификации
|
||||||
|
|||||||
@@ -300,7 +300,6 @@ input, textarea {
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
margin: var(--spacing-lg) 0 35px 0;
|
margin: var(--spacing-lg) 0 35px 0;
|
||||||
height: calc(100vh - 195px);
|
|
||||||
min-height: 500px;
|
min-height: 500px;
|
||||||
position: relative;
|
position: relative;
|
||||||
}
|
}
|
||||||
@@ -308,10 +307,8 @@ input, textarea {
|
|||||||
.chat-messages {
|
.chat-messages {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
flex: 1;
|
|
||||||
overflow-y: auto;
|
overflow-y: auto;
|
||||||
padding: var(--spacing-lg);
|
padding: var(--spacing-lg);
|
||||||
margin-bottom: var(--spacing-lg);
|
|
||||||
background: var(--color-white);
|
background: var(--color-white);
|
||||||
border-radius: var(--radius-lg);
|
border-radius: var(--radius-lg);
|
||||||
border: 1px solid var(--color-grey-light);
|
border: 1px solid var(--color-grey-light);
|
||||||
@@ -319,19 +316,21 @@ input, textarea {
|
|||||||
top: 0;
|
top: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
right: 0;
|
right: 0;
|
||||||
bottom: 135px;
|
bottom: 205px;
|
||||||
transition: bottom var(--transition-normal);
|
transition: bottom var(--transition-normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Адаптация позиции при активации фокуса */
|
/* Адаптация позиции при активации фокуса */
|
||||||
.chat-container:has(.chat-input.focused) .chat-messages {
|
.chat-container:has(.chat-input.focused) .chat-messages {
|
||||||
bottom: 235px;
|
bottom: 305px;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Реализуем программное изменение позиции через JS для браузеров без поддержки :has */
|
/* Реализуем программное изменение позиции через JS для браузеров без поддержки :has */
|
||||||
@media (max-width: 100vw) {
|
@media (max-width: 100vw) {
|
||||||
|
/* Примечание: Этот блок @media может потребовать обновления в JS коде, */
|
||||||
|
/* если он используется для имитации :has. Сейчас изменяем только CSS. */
|
||||||
.chat-input.focused ~ .messages-container {
|
.chat-input.focused ~ .messages-container {
|
||||||
bottom: 235px;
|
bottom: 305px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -435,7 +434,6 @@ input, textarea {
|
|||||||
min-height: var(--chat-input-min-height);
|
min-height: var(--chat-input-min-height);
|
||||||
max-height: var(--chat-input-max-height);
|
max-height: var(--chat-input-max-height);
|
||||||
transition: min-height var(--transition-normal), padding var(--transition-normal);
|
transition: min-height var(--transition-normal), padding var(--transition-normal);
|
||||||
margin-bottom: var(--spacing-md);
|
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -32,8 +32,22 @@ export function useAuth() {
|
|||||||
return acc;
|
return acc;
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
// Сравниваем новый отфильтрованный список с текущим значением
|
||||||
|
const currentProviders = identities.value.map(id => id.provider).sort();
|
||||||
|
const newProviders = filteredIdentities.map(id => id.provider).sort();
|
||||||
|
|
||||||
|
const identitiesChanged = JSON.stringify(currentProviders) !== JSON.stringify(newProviders);
|
||||||
|
|
||||||
|
// Обновляем реактивное значение
|
||||||
identities.value = filteredIdentities;
|
identities.value = filteredIdentities;
|
||||||
console.log('User identities updated:', identities.value);
|
console.log('User identities updated:', identities.value);
|
||||||
|
|
||||||
|
// Если список идентификаторов изменился, принудительно проверяем аутентификацию,
|
||||||
|
// чтобы обновить authType и другие связанные данные (например, telegramId)
|
||||||
|
if (identitiesChanged) {
|
||||||
|
console.log('Identities changed, forcing auth check.');
|
||||||
|
await checkAuth(); // Вызываем checkAuth для обновления полного состояния
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching user identities:', error);
|
console.error('Error fetching user identities:', error);
|
||||||
|
|||||||
@@ -25,9 +25,16 @@ export const TOKEN_CONTRACTS = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Получение балансов токенов
|
// Получение балансов токенов
|
||||||
export const fetchTokenBalances = async () => {
|
export const fetchTokenBalances = async (address = null) => {
|
||||||
try {
|
try {
|
||||||
const response = await api.get('/api/tokens/balances');
|
let url = '/api/tokens/balances';
|
||||||
|
if (address) {
|
||||||
|
url += `?address=${encodeURIComponent(address)}`;
|
||||||
|
console.log(`Fetching token balances for specific address: ${address}`);
|
||||||
|
} else {
|
||||||
|
console.log('Fetching token balances for session user');
|
||||||
|
}
|
||||||
|
const response = await api.get(url);
|
||||||
return response.data;
|
return response.data;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching token balances:', error);
|
console.error('Error fetching token balances:', error);
|
||||||
|
|||||||
@@ -207,18 +207,24 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Блок для авторизованных пользователей -->
|
<!-- Блок для авторизованных пользователей -->
|
||||||
<div v-if="isAuthenticated" class="auth-buttons-container">
|
<div v-if="isAuthenticated">
|
||||||
<div class="wallet-header">
|
<!-- Контейнер только для кнопок -->
|
||||||
<div class="wallet-header-buttons">
|
<div class="auth-buttons-container">
|
||||||
<button class="auth-btn disconnect-wallet-btn" @click="disconnectWallet">
|
<div class="wallet-header">
|
||||||
Отключить
|
<div class="wallet-header-buttons">
|
||||||
</button>
|
<button class="auth-btn disconnect-wallet-btn" @click="disconnectWallet">
|
||||||
<button class="close-wallet-sidebar" @click="toggleWalletSidebar">×</button>
|
Отключить
|
||||||
|
</button>
|
||||||
|
<button class="close-wallet-sidebar" @click="toggleWalletSidebar">×</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<!-- Конец контейнера только для кнопок -->
|
||||||
|
|
||||||
<!-- Блок информации о пользователе -->
|
<!-- Условный блок: Информация о пользователе ИЛИ формы подключения -->
|
||||||
<div class="user-info">
|
|
||||||
|
<!-- Блок информации о пользователе (отображается, если не активна ни одна форма) -->
|
||||||
|
<div v-if="!emailAuth.showForm && !emailAuth.showVerification && !telegramAuth.showVerification" class="user-info">
|
||||||
<h3>Идентификаторы:</h3>
|
<h3>Идентификаторы:</h3>
|
||||||
<div class="user-info-item">
|
<div class="user-info-item">
|
||||||
<span class="user-info-label">Кошелек:</span>
|
<span class="user-info-label">Кошелек:</span>
|
||||||
@@ -248,17 +254,8 @@
|
|||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Блок форм подключения для аутентифицированных пользователей -->
|
<!-- Форма для Email верификации (отображается вместо user-info) -->
|
||||||
<div
|
|
||||||
v-if="
|
|
||||||
isAuthenticated &&
|
|
||||||
(emailAuth.showForm || telegramAuth.showVerification || emailAuth.showVerification)
|
|
||||||
"
|
|
||||||
class="connect-forms"
|
|
||||||
>
|
|
||||||
<!-- Форма для Email верификации -->
|
|
||||||
<div v-if="emailAuth.showForm" class="email-form">
|
<div v-if="emailAuth.showForm" class="email-form">
|
||||||
<p>Введите ваш email для получения кода подтверждения:</p>
|
<p>Введите ваш email для получения кода подтверждения:</p>
|
||||||
<div class="email-form-container">
|
<div class="email-form-container">
|
||||||
@@ -285,7 +282,7 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Форма для ввода кода верификации Email -->
|
<!-- Форма для ввода кода верификации Email (отображается вместо user-info) -->
|
||||||
<div v-if="emailAuth.showVerification" class="email-verification-form">
|
<div v-if="emailAuth.showVerification" class="email-verification-form">
|
||||||
<p>
|
<p>
|
||||||
На ваш email <strong>{{ emailAuth.verificationEmail }}</strong> отправлен код
|
На ваш email <strong>{{ emailAuth.verificationEmail }}</strong> отправлен код
|
||||||
@@ -310,24 +307,22 @@
|
|||||||
<button class="cancel-btn" @click="cancelEmailAuth">Отмена</button>
|
<button class="cancel-btn" @click="cancelEmailAuth">Отмена</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Форма для Telegram верификации -->
|
<!-- Форма для Telegram верификации (отображается вместо user-info) -->
|
||||||
<div v-if="telegramAuth.showVerification" class="verification-block">
|
<div v-if="telegramAuth.showVerification" class="verification-block">
|
||||||
<div class="verification-code">
|
<div class="verification-code">
|
||||||
<span>Код верификации:</span>
|
<span>Код верификации:</span>
|
||||||
<code @click="copyCode(telegramAuth.verificationCode)">{{
|
<code @click="copyCode(telegramAuth.verificationCode)">{{ telegramAuth.verificationCode }}</code>
|
||||||
telegramAuth.verificationCode
|
|
||||||
}}</code>
|
|
||||||
<span v-if="codeCopied" class="copied-message">Скопировано!</span>
|
<span v-if="codeCopied" class="copied-message">Скопировано!</span>
|
||||||
</div>
|
</div>
|
||||||
<a :href="telegramAuth.botLink" target="_blank" class="bot-link"
|
<a :href="telegramAuth.botLink" target="_blank" class="bot-link">Открыть бота Telegram</a>
|
||||||
>Открыть бота Telegram</a
|
|
||||||
>
|
|
||||||
<button class="cancel-btn" @click="cancelTelegramAuth">Отмена</button>
|
<button class="cancel-btn" @click="cancelTelegramAuth">Отмена</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<!-- Конец условного блока -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Блок баланса токенов -->
|
<!-- Блок баланса токенов -->
|
||||||
<div v-if="isAuthenticated && auth.address?.value" class="token-balances">
|
<div v-if="isAuthenticated && hasIdentityType('wallet')" class="token-balances">
|
||||||
<h3>Баланс токенов:</h3>
|
<h3>Баланс токенов:</h3>
|
||||||
<div class="token-balance">
|
<div class="token-balance">
|
||||||
<span class="token-name">ETH:</span>
|
<span class="token-name">ETH:</span>
|
||||||
@@ -1110,49 +1105,57 @@
|
|||||||
// Создаем интервал для проверки состояния авторизации
|
// Создаем интервал для проверки состояния авторизации
|
||||||
telegramAuth.value.checkInterval = setInterval(async () => {
|
telegramAuth.value.checkInterval = setInterval(async () => {
|
||||||
try {
|
try {
|
||||||
|
// ВАЖНО: Используем auth.checkAuth() из useAuth для получения актуального состояния
|
||||||
|
// Не нужно делать отдельный axios запрос здесь
|
||||||
const checkResponse = await auth.checkAuth();
|
const checkResponse = await auth.checkAuth();
|
||||||
|
|
||||||
// Получаем Telegram ID из проверки аутентификации
|
// Получаем Telegram ID из состояния auth (которое обновилось через checkAuth)
|
||||||
const telegramId = checkResponse.telegramId;
|
const telegramId = auth.telegramId.value; // Используем реактивное значение
|
||||||
|
|
||||||
if (auth.isAuthenticated.value && telegramId) {
|
if (auth.isAuthenticated.value && telegramId) {
|
||||||
|
console.log('[handleTelegramAuth] Telegram successfully linked/verified. Clearing interval and hiding form.');
|
||||||
|
clearTelegramInterval(); // <--- ДОБАВЛЕНО: Останавливаем интервал
|
||||||
|
telegramAuth.value.showVerification = false; // <--- ДОБАВЛЕНО: Скрываем форму верификации
|
||||||
|
telegramAuth.value.verificationCode = ''; // Очищаем код на всякий случай
|
||||||
|
telegramAuth.value.error = ''; // Очищаем ошибки
|
||||||
|
|
||||||
|
// ... остальная логика обработки успешной привязки ...
|
||||||
|
let roleUpdated = false; // Флаг для отслеживания обновления роли
|
||||||
|
// Сравниваем текущий authType с 'telegram'
|
||||||
if (auth.authType.value !== 'telegram') {
|
if (auth.authType.value !== 'telegram') {
|
||||||
// Если пользователь авторизован не через Telegram, связываем идентификаторы
|
// Если пользователь авторизован не через Telegram, связываем идентификаторы
|
||||||
console.log('Связывание Telegram с существующим аккаунтом:', telegramId);
|
// Эта логика может быть избыточной, если checkAuth уже обновил authType
|
||||||
const linkResult = await auth.linkIdentity('telegram', telegramId);
|
// Возможно, достаточно просто проверить authType после checkAuth
|
||||||
|
console.log('Связывание Telegram с существующим аккаунтом (проверка authType):', telegramId, auth.authType.value);
|
||||||
if (linkResult.success) {
|
// Уведомление об успехе
|
||||||
notifications.value.successMessage =
|
notifications.value.successMessage = 'Telegram успешно подключен к вашему аккаунту!';
|
||||||
'Telegram успешно подключен к вашему аккаунту!';
|
notifications.value.showSuccess = true;
|
||||||
notifications.value.showSuccess = true;
|
setTimeout(() => { notifications.value.showSuccess = false; }, 3000);
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
notifications.value.showSuccess = false;
|
|
||||||
}, 3000);
|
|
||||||
} else {
|
|
||||||
notifications.value.errorMessage =
|
|
||||||
linkResult.error || 'Не удалось подключить Telegram';
|
|
||||||
notifications.value.showError = true;
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
notifications.value.showError = false;
|
|
||||||
}, 3000);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
// Если новая аутентификация через Telegram
|
// Если новая аутентификация через Telegram или authType уже telegram
|
||||||
console.log('Telegram аутентификация успешна');
|
console.log('Telegram аутентификация/привязка успешна (authType="telegram")');
|
||||||
|
// await loadMessages({ authType: 'telegram' }); // Загрузка сообщений уже обрабатывается watch(isAuthenticated)
|
||||||
// Загружаем сообщения после аутентификации
|
roleUpdated = true; // Роль могла обновиться при этой аутентификации
|
||||||
await loadMessages({ authType: 'telegram' });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Очищаем интервал и скрываем окно верификации
|
// Проверяем роль еще раз после возможной привязки/аутентификации
|
||||||
clearTelegramInterval();
|
// await auth.checkAuth(); // Дополнительный checkAuth, возможно, не нужен, т.к. он вызывается в начале интервала
|
||||||
telegramAuth.value.showVerification = false;
|
|
||||||
telegramAuth.value.verificationCode = '';
|
if (hasIdentityType('wallet')) {
|
||||||
|
console.log('[handleTelegramAuth] Wallet linked, updating balances...');
|
||||||
|
await updateBalances(); // Вызываем обновление баланса
|
||||||
|
startBalanceUpdates(); // Запускаем интервал обновления, если еще не запущен
|
||||||
|
}
|
||||||
|
// Нет необходимости продолжать интервал после успеха
|
||||||
|
return; // Выходим из колбека setInterval
|
||||||
|
} else {
|
||||||
|
console.log('[handleTelegramAuth] Still waiting for Telegram verification...');
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Ошибка при проверке аутентификации:', error);
|
console.error('Ошибка при проверке аутентификации в интервале:', error);
|
||||||
|
// Очищать ли интервал при ошибке? Возможно, да, чтобы не спамить ошибками.
|
||||||
|
// clearTelegramInterval();
|
||||||
|
// telegramAuth.value.error = 'Ошибка проверки статуса Telegram.';
|
||||||
}
|
}
|
||||||
}, 2000); // Проверяем каждые 2 секунды
|
}, 2000); // Проверяем каждые 2 секунды
|
||||||
} else {
|
} else {
|
||||||
@@ -1290,6 +1293,7 @@
|
|||||||
|
|
||||||
// Получаем текущее состояние аутентификации
|
// Получаем текущее состояние аутентификации
|
||||||
const authResponse = await auth.checkAuth();
|
const authResponse = await auth.checkAuth();
|
||||||
|
let roleUpdated = false; // Флаг для отслеживания обновления роли
|
||||||
|
|
||||||
if (auth.isAuthenticated.value && emailAuth.value.verificationEmail) {
|
if (auth.isAuthenticated.value && emailAuth.value.verificationEmail) {
|
||||||
// Если пользователь уже авторизован, связываем email
|
// Если пользователь уже авторизован, связываем email
|
||||||
@@ -1304,45 +1308,40 @@
|
|||||||
// Показываем сообщение об успехе
|
// Показываем сообщение об успехе
|
||||||
notifications.value.successMessage = `Email ${emailAuth.value.verificationEmail} успешно подключен к вашему аккаунту!`;
|
notifications.value.successMessage = `Email ${emailAuth.value.verificationEmail} успешно подключен к вашему аккаунту!`;
|
||||||
notifications.value.showSuccess = true;
|
notifications.value.showSuccess = true;
|
||||||
|
setTimeout(() => { notifications.value.showSuccess = false; }, 3000);
|
||||||
// Скрываем сообщение через 3 секунды
|
|
||||||
setTimeout(() => {
|
|
||||||
notifications.value.showSuccess = false;
|
|
||||||
}, 3000);
|
|
||||||
} else {
|
} else {
|
||||||
notifications.value.errorMessage = linkResult.error || 'Не удалось подключить Email';
|
notifications.value.errorMessage = linkResult.error || 'Не удалось подключить Email';
|
||||||
notifications.value.showError = true;
|
notifications.value.showError = true;
|
||||||
|
setTimeout(() => { notifications.value.showError = false; }, 3000);
|
||||||
setTimeout(() => {
|
|
||||||
notifications.value.showError = false;
|
|
||||||
}, 3000);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Показываем сообщение об успехе
|
// Показываем сообщение об успехе, если просто подтвердили email
|
||||||
notifications.value.successMessage = `Email ${emailAuth.value.verificationEmail} успешно подтвержден!`;
|
notifications.value.successMessage = `Email ${emailAuth.value.verificationEmail} успешно подтвержден!`;
|
||||||
notifications.value.showSuccess = true;
|
notifications.value.showSuccess = true;
|
||||||
|
setTimeout(() => { notifications.value.showSuccess = false; }, 3000);
|
||||||
|
|
||||||
// Скрываем сообщение через 3 секунды
|
|
||||||
setTimeout(() => {
|
|
||||||
notifications.value.showSuccess = false;
|
|
||||||
}, 3000);
|
|
||||||
|
|
||||||
// Загружаем сообщения после аутентификации
|
|
||||||
await loadMessages({ authType: 'email' });
|
await loadMessages({ authType: 'email' });
|
||||||
|
roleUpdated = true; // Роль могла обновиться
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Если пользователь не был авторизован до этого
|
// Если пользователь не был авторизован до этого
|
||||||
// Показываем сообщение об успехе
|
|
||||||
notifications.value.successMessage = `Email ${emailAuth.value.verificationEmail} успешно подтвержден!`;
|
notifications.value.successMessage = `Email ${emailAuth.value.verificationEmail} успешно подтвержден!`;
|
||||||
notifications.value.showSuccess = true;
|
notifications.value.showSuccess = true;
|
||||||
|
setTimeout(() => { notifications.value.showSuccess = false; }, 3000);
|
||||||
|
|
||||||
// Скрываем сообщение через 3 секунды
|
|
||||||
setTimeout(() => {
|
|
||||||
notifications.value.showSuccess = false;
|
|
||||||
}, 3000);
|
|
||||||
|
|
||||||
// Загружаем сообщения после аутентификации
|
|
||||||
await loadMessages({ authType: 'email' });
|
await loadMessages({ authType: 'email' });
|
||||||
|
roleUpdated = true; // Роль могла обновиться при новой аутентификации
|
||||||
|
}
|
||||||
|
|
||||||
|
// Проверяем роль еще раз после возможной привязки/аутентификации
|
||||||
|
if (!roleUpdated) {
|
||||||
|
await auth.checkAuth(); // Перепроверяем auth состояние, чтобы получить актуальную роль
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasIdentityType('wallet')) {
|
||||||
|
console.log('[verifyEmailCode] Wallet linked, updating balances...');
|
||||||
|
await updateBalances(); // Вызываем обновление баланса
|
||||||
|
startBalanceUpdates(); // Запускаем интервал обновления, если еще не запущен
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
emailAuth.value.error = response.data.message || 'Неверный код верификации';
|
emailAuth.value.error = response.data.message || 'Неверный код верификации';
|
||||||
@@ -1542,26 +1541,41 @@
|
|||||||
* Обновляет балансы токенов
|
* Обновляет балансы токенов
|
||||||
*/
|
*/
|
||||||
const updateBalances = async () => {
|
const updateBalances = async () => {
|
||||||
if (auth.isAuthenticated.value && auth.address?.value) {
|
if (auth.isAuthenticated.value) {
|
||||||
try {
|
// Пытаемся получить адрес сначала из прямого значения, потом из идентификаторов
|
||||||
console.log('Запрос балансов для адреса:', auth.address.value);
|
const walletAddress = auth.address?.value || getIdentityValue('wallet');
|
||||||
const balances = await fetchTokenBalances();
|
|
||||||
console.log('Полученные балансы:', balances);
|
|
||||||
|
|
||||||
// Обновляем каждый баланс отдельно для реактивности
|
if (walletAddress) {
|
||||||
tokenBalances.value = {
|
try {
|
||||||
eth: balances.eth || '0',
|
console.log('Запрос балансов для адреса:', walletAddress);
|
||||||
bsc: balances.bsc || '0',
|
// Важно: Убедитесь, что fetchTokenBalances использует переданный адрес
|
||||||
arbitrum: balances.arbitrum || '0',
|
// Если fetchTokenBalances неявно использует auth.address.value,
|
||||||
polygon: balances.polygon || '0',
|
// его нужно будет модифицировать или передавать адрес явно.
|
||||||
};
|
// ПРЕДПОЛАГАЕМ, что fetchTokenBalances работает корректно или будет исправлен.
|
||||||
|
const balances = await fetchTokenBalances(walletAddress); // Передаем адрес явно, если нужно
|
||||||
|
console.log('Полученные балансы:', balances);
|
||||||
|
|
||||||
console.log('Обновленные балансы в интерфейсе:', tokenBalances.value);
|
// Обновляем каждый баланс отдельно для реактивности
|
||||||
} catch (error) {
|
tokenBalances.value = {
|
||||||
console.error('Ошибка при обновлении балансов:', error);
|
eth: balances.eth || '0',
|
||||||
|
bsc: balances.bsc || '0',
|
||||||
|
arbitrum: balances.arbitrum || '0',
|
||||||
|
polygon: balances.polygon || '0',
|
||||||
|
};
|
||||||
|
|
||||||
|
console.log('Обновленные балансы в интерфейсе:', tokenBalances.value);
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Ошибка при обновлении балансов:', error);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.log('Не найден адрес кошелька для запроса балансов.');
|
||||||
|
// Можно обнулить балансы, если адрес не найден
|
||||||
|
tokenBalances.value = { eth: '0', bsc: '0', arbitrum: '0', polygon: '0' };
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log('Пользователь не аутентифицирован или адрес не доступен');
|
console.log('Пользователь не аутентифицирован.');
|
||||||
|
// Также обнуляем балансы, если не аутентифицирован
|
||||||
|
tokenBalances.value = { eth: '0', bsc: '0', arbitrum: '0', polygon: '0' };
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user