ваше сообщение коммита

This commit is contained in:
2025-03-26 14:32:38 +03:00
parent 46cb5c39b2
commit 75274beb92
9 changed files with 1094 additions and 874 deletions

View File

@@ -2,17 +2,9 @@ const { Telegraf } = require('telegraf');
const logger = require('../utils/logger');
const db = require('../db');
const authService = require('./auth-service');
const verificationService = require('./verification-service');
let botInstance = null;
const verificationCodes = new Map();
// Простая остановка бота
async function stopBot() {
if (botInstance) {
await botInstance.stop();
botInstance = null;
}
}
// Создание и настройка бота
async function getBot() {
@@ -27,95 +19,96 @@ async function getBot() {
// Обработка кодов верификации
botInstance.on('text', async (ctx) => {
const code = ctx.message.text.trim();
const verification = verificationCodes.get(code);
if (!verification) {
ctx.reply('Неверный код подтверждения');
return;
}
try {
logger.info('Starting Telegram auth process for code:', code);
logger.info('Verification data:', verification);
// Сначала проверяем, существует ли пользователь с этим Telegram ID
let userId;
const existingUser = await db.query(
`SELECT u.id
FROM users u
JOIN user_identities ui ON u.id = ui.user_id
WHERE ui.provider = $1
AND ui.provider_id = $2`,
['telegram', ctx.from.id.toString()]
// Получаем код верификации для всех активных кодов с провайдером telegram
const codeResult = await db.query(
`SELECT * FROM verification_codes
WHERE code = $1
AND provider = 'telegram'
AND used = false
AND expires_at > NOW()`,
[code]
);
if (existingUser.rows.length > 0) {
userId = existingUser.rows[0].id;
logger.info('Found existing user with ID:', userId);
} else {
// Создаем нового пользователя
const result = await db.query(
`INSERT INTO users (created_at, updated_at)
VALUES (NOW(), NOW())
RETURNING id`,
[]
);
userId = result.rows[0].id;
logger.info('Created new user with ID:', userId);
if (codeResult.rows.length === 0) {
ctx.reply('Неверный код подтверждения');
return;
}
// Связываем Telegram с пользователем
const verification = codeResult.rows[0];
const providerId = verification.provider_id;
let userId = verification.user_id;
// Отмечаем код как использованный
await db.query(
`INSERT INTO user_identities
(user_id, provider, provider_id, created_at)
VALUES ($1, $2, $3, NOW())
ON CONFLICT (provider, provider_id) DO UPDATE SET user_id = $1`,
[userId, 'telegram', ctx.from.id.toString()]
'UPDATE verification_codes SET used = true WHERE id = $1',
[verification.id]
);
logger.info(`User ${userId} successfully linked Telegram account ${ctx.from.id}`);
logger.info('Starting Telegram auth process for code:', code);
// Обновляем сессию
if (verification?.session) {
logger.info('Creating session with data:', verification.session);
// Обновляем данные сессии напрямую
verification.session.userId = userId;
verification.session.authenticated = true;
verification.session.authType = 'telegram';
verification.session.telegramId = ctx.from.id.toString(); // Добавляем идентификатор Telegram в сессию
// Проверяем роль пользователя
const userRole = await authService.checkUserRole(userId);
verification.session.userRole = userRole;
await new Promise((resolve, reject) => {
verification.session.save(err => {
if (err) reject(err);
else resolve();
});
});
logger.info('Session created successfully');
}
// Проверяем, существует ли уже пользователь с таким Telegram ID
const existingTelegramUser = await db.query(
`SELECT ui.user_id
FROM user_identities ui
WHERE ui.provider = 'telegram' AND ui.provider_id = $1`,
[ctx.from.id.toString()]
);
// Отправляем последнее сообщение пользователя
if (verification.session.guestId) {
logger.info('Fetching last guest message for guestId:', verification.session.guestId);
const messageResult = await db.query(`
SELECT content FROM guest_messages
WHERE guest_id = $1
ORDER BY created_at DESC
LIMIT 1
`, [verification.session.guestId]);
if (existingTelegramUser.rows.length > 0) {
// Если пользователь с таким Telegram ID уже существует,
// используем его ID вместо создания нового связывания
const existingUserId = existingTelegramUser.rows[0].user_id;
const lastMessage = messageResult.rows[0]?.content;
logger.info('Found last message:', lastMessage);
if (lastMessage) {
await ctx.reply(`Ваше последнее сообщение: "${lastMessage}"`);
// Связываем гостевой ID с существующим пользователем, если его еще нет
const guestIdentity = await db.query(
`SELECT * FROM user_identities
WHERE user_id = $1 AND provider = 'guest' AND provider_id = $2`,
[existingUserId, providerId]
);
if (guestIdentity.rows.length === 0 && providerId) {
await db.query(
`INSERT INTO user_identities
(user_id, provider, provider_id, created_at)
VALUES ($1, $2, $3, NOW())
ON CONFLICT (provider, provider_id) DO UPDATE SET user_id = $1`,
[existingUserId, 'guest', providerId]
);
}
userId = existingUserId;
logger.info(`Using existing user ${userId} for Telegram account ${ctx.from.id}`);
} else {
// Связываем Telegram с пользователем
await db.query(
`INSERT INTO user_identities
(user_id, provider, provider_id, created_at)
VALUES ($1, $2, $3, NOW())
ON CONFLICT (provider, provider_id) DO UPDATE SET user_id = $1`,
[userId, 'telegram', ctx.from.id.toString()]
);
logger.info(`User ${userId} successfully linked Telegram account ${ctx.from.id}`);
}
// Обновляем сессию в базе данных
await db.query(
`UPDATE session
SET sess = (sess::jsonb || $1::jsonb)::json
WHERE sess::jsonb @> $2::jsonb`,
[
JSON.stringify({
userId: userId.toString(),
authenticated: true,
authType: "telegram",
telegramId: ctx.from.id.toString()
}),
JSON.stringify({guestId: providerId})
]
);
// Отправляем сообщение об успешной аутентификации
await ctx.reply('Аутентификация успешна! Можете вернуться в приложение.');
@@ -126,31 +119,9 @@ async function getBot() {
logger.warn('Could not delete code message:', error);
}
// Удаляем код верификации
verificationCodes.delete(code);
} catch (error) {
logger.error('Error in Telegram auth:', error);
// Более информативные сообщения об ошибках
let errorMessage = 'Произошла ошибка при сохранении. Попробуйте позже.';
if (error.code === '42P01') {
errorMessage = 'Ошибка сессии. Пожалуйста, обновите страницу и попробуйте снова.';
} else if (error.code === '42703') {
errorMessage = 'Ошибка структуры данных. Обратитесь к администратору.';
}
if (error.code) {
logger.error('Database error code:', error.code);
}
if (error.detail) {
logger.error('Error detail:', error.detail);
}
if (error.stack) {
logger.error('Error stack:', error.stack);
}
await ctx.reply(errorMessage);
await ctx.reply('Произошла ошибка при аутентификации. Попробуйте позже.');
}
});
@@ -161,23 +132,87 @@ async function getBot() {
return botInstance;
}
// Остановка бота
async function stopBot() {
if (botInstance) {
try {
await botInstance.stop();
botInstance = null;
logger.info('Telegram bot stopped successfully');
} catch (error) {
logger.error('Error stopping Telegram bot:', error);
throw error;
}
}
}
// Инициализация процесса аутентификации
async function initTelegramAuth(session) {
const code = Math.random().toString(36).substring(2, 8).toUpperCase();
const botLink = `https://t.me/${process.env.TELEGRAM_BOT_USERNAME}`;
verificationCodes.set(code, {
timestamp: Date.now(),
session: session
});
logger.info(`Generated verification code: ${code} for Telegram auth`);
return { verificationCode: code, botLink };
try {
// Создаем или получаем ID пользователя
let userId;
if (session.authenticated && session.userId) {
// Если пользователь уже аутентифицирован, используем его ID
userId = session.userId;
} else if (session.guestId) {
// Проверяем, есть ли уже пользователь с этим guestId
const existingUser = await db.query(
`SELECT u.id
FROM users u
JOIN user_identities ui ON u.id = ui.user_id
WHERE ui.provider = 'guest' AND ui.provider_id = $1`,
[session.guestId]
);
if (existingUser.rows.length > 0) {
// Используем существующего пользователя
userId = existingUser.rows[0].id;
} else {
// Создаем нового пользователя
const userResult = await db.query(
'INSERT INTO users (created_at) VALUES (NOW()) RETURNING id'
);
userId = userResult.rows[0].id;
// Связываем гостевой ID с пользователем
await db.query(
`INSERT INTO user_identities
(user_id, provider, provider_id, created_at)
VALUES ($1, $2, $3, NOW())`,
[userId, 'guest', session.guestId]
);
}
session.tempUserId = userId;
} else {
// Создаем нового пользователя без гостевого ID
const userResult = await db.query(
'INSERT INTO users (created_at) VALUES (NOW()) RETURNING id'
);
userId = userResult.rows[0].id;
session.tempUserId = userId;
}
// Создаем код через сервис верификации
const code = await verificationService.createVerificationCode(
'telegram',
session.guestId || 'temp',
userId
);
return {
verificationCode: code,
botLink: `https://t.me/${process.env.TELEGRAM_BOT_USERNAME}`
};
} catch (error) {
logger.error('Error initializing Telegram auth:', error);
throw error;
}
}
module.exports = {
getBot,
stopBot,
verificationCodes,
initTelegramAuth
};
};