alpha-test

This commit is contained in:
2025-09-18 13:46:35 +09:00
parent 85027a7747
commit 5ea3e8c1f3
27 changed files with 5887 additions and 174 deletions

76
scripts/README.md Normal file
View File

@@ -0,0 +1,76 @@
# Исправление проблем с уведомлениями в боте
Этот набор скриптов предназначен для исправления проблем с обработкой уведомлений в боте.
## Описание проблемы
После внедрения системы уведомлений и связанных с ней изменений в базе данных, возникла проблема с обработкой callback запросов. Бот перестал реагировать на все callback запросы, кроме тех, что связаны с уведомлениями.
Проблема вызвана следующими факторами:
1. Отсутствие или неверная структура таблиц в базе данных для хранения уведомлений
2. Отсутствие необходимых полей `state` и `state_data` в таблице `users`
3. Отсутствие правильной регистрации обработчиков уведомлений в файле `bot.ts`
## Решение
Для решения проблемы были созданы следующие скрипты:
### 1. `fix_notification_callbacks.js`
Проверяет и создает необходимые таблицы и столбцы в базе данных:
- Таблицы `notifications`, `scheduled_notifications`, `notification_templates`
- Столбцы `notification_settings`, `state`, `state_data` в таблице `users`
### 2. `update_bot_with_notifications.js`
Обновляет файл `bot.ts`:
- Добавляет импорт класса `NotificationHandlers`
- Добавляет объявление поля `notificationHandlers` в класс `TelegramTinderBot`
- Добавляет создание экземпляра `NotificationHandlers` в конструкторе
- Добавляет регистрацию обработчиков уведомлений в методе `registerHandlers`
### 3. `fix_all_notifications.js`
Запускает оба скрипта последовательно для полного исправления проблемы
## Как использовать
1. Остановите бота, если он запущен:
```bash
# Нажмите Ctrl+C в терминале, где запущен бот
# или найдите процесс и завершите его
```
2. Запустите комплексный скрипт исправления:
```bash
node scripts/fix_all_notifications.js
```
3. После успешного выполнения скрипта перезапустите бота:
```bash
npm run start
```
## Проверка результата
После запуска бота убедитесь, что:
1. Бот отвечает на все callback запросы (включая кнопки, не связанные с уведомлениями)
2. Настройки уведомлений работают корректно (команда /notifications или кнопка в меню настроек)
3. Уведомления о лайках, супер-лайках и новых матчах приходят пользователям
## Если проблемы остались
Если после выполнения всех шагов проблемы остались, выполните следующие проверки:
1. Проверьте логи бота на наличие ошибок
2. Проверьте структуру базы данных:
```sql
\dt -- Список всех таблиц
\d notifications -- Структура таблицы notifications
\d scheduled_notifications -- Структура таблицы scheduled_notifications
\d notification_templates -- Структура таблицы notification_templates
\d users -- Убедитесь, что поля state, state_data и notification_settings существуют
```
3. Проверьте код в файлах:
- `src/bot.ts`: должен содержать импорт, создание и регистрацию `NotificationHandlers`
- `src/handlers/callbackHandlers.ts`: должен правильно обрабатывать все callback-запросы
В случае обнаружения ошибок, исправьте их вручную и перезапустите бота.

View File

@@ -0,0 +1,58 @@
// Скрипт для добавления колонки premium в таблицу users и установки premium для всех пользователей
require('dotenv').config();
const { Pool } = require('pg');
// Создаем пул соединений
const pool = new Pool({
user: process.env.DB_USERNAME,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASSWORD,
port: parseInt(process.env.DB_PORT || '5432')
});
async function setAllUsersToPremium() {
try {
console.log('Проверяем наличие столбца premium в таблице users...');
const result = await pool.query(`
SELECT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'users'
AND column_name = 'premium'
);
`);
if (!result.rows[0].exists) {
console.log('🔄 Добавляем столбец premium...');
await pool.query(`ALTER TABLE users ADD COLUMN premium BOOLEAN DEFAULT false;`);
console.log('✅ Столбец premium успешно добавлен');
} else {
console.log('✅ Столбец premium уже существует');
}
console.log('Устанавливаем премиум-статус для всех пользователей...');
const updateResult = await pool.query(`
UPDATE users
SET premium = true
WHERE true
RETURNING id, telegram_id, premium
`);
console.log(`✅ Успешно установлен премиум-статус для ${updateResult.rows.length} пользователей:`);
updateResult.rows.forEach(row => {
console.log(`ID: ${row.id.substr(0, 8)}... | Telegram ID: ${row.telegram_id} | Premium: ${row.premium}`);
});
console.log('🎉 Все пользователи теперь имеют премиум-статус!');
} catch (error) {
console.error('Ошибка при установке премиум-статуса:', error);
} finally {
await pool.end();
console.log('Соединение с базой данных закрыто');
}
}
setAllUsersToPremium();

View File

@@ -0,0 +1,88 @@
// Скрипт для анализа и отладки проблем с обработчиками коллбэков
require('dotenv').config();
const fs = require('fs');
const path = require('path');
function analyzeCallbackHandlers() {
const filePath = path.join(__dirname, '..', 'src', 'handlers', 'callbackHandlers.ts');
const content = fs.readFileSync(filePath, 'utf-8');
// Проверяем наличие реализаций методов
const methodsToCheck = [
'handleCreateProfile',
'handleGenderSelection',
'handleViewMyProfile',
'handleEditProfile',
'handleManagePhotos',
'handleStartBrowsing',
'handleSettings'
];
const issues = [];
let debugInfo = [];
methodsToCheck.forEach(method => {
debugInfo.push(`Проверяем метод: ${method}`);
// Проверяем наличие полной реализации метода (не только сигнатуры)
const methodSignatureRegex = new RegExp(`async\\s+${method}\\s*\\([^)]*\\)\\s*:\\s*Promise<void>\\s*{`, 'g');
const hasSignature = methodSignatureRegex.test(content);
const methodBodyRegex = new RegExp(`async\\s+${method}\\s*\\([^)]*\\)\\s*:\\s*Promise<void>\\s*{[\\s\\S]+?}`, 'g');
const methodMatch = content.match(methodBodyRegex);
debugInfo.push(` Сигнатура найдена: ${hasSignature}`);
debugInfo.push(` Реализация найдена: ${methodMatch !== null}`);
if (methodMatch) {
const methodContent = methodMatch[0];
debugInfo.push(` Длина метода: ${methodContent.length} символов`);
// Проверяем, содержит ли метод только заглушку
const isStub = methodContent.includes('// Заглушка метода') ||
(!methodContent.includes('await') && methodContent.split('\n').length <= 3);
if (isStub) {
issues.push(`❌ Метод ${method} содержит только заглушку, нет реальной реализации`);
} else {
debugInfo.push(` Метод ${method} имеет полную реализацию`);
}
} else if (hasSignature) {
issues.push(`❌ Метод ${method} имеет только сигнатуру, но нет реализации`);
} else {
issues.push(`❌ Метод ${method} не найден в файле`);
}
});
// Проверяем регистрацию обработчиков для NotificationHandlers
const notificationHandlersRegex = /this\.notificationHandlers\s*=\s*new\s+NotificationHandlers\(bot\);/g;
const hasNotificationHandlers = notificationHandlersRegex.test(content);
debugInfo.push(`NotificationHandlers инициализирован: ${hasNotificationHandlers}`);
// Проверяем обработку коллбэка notifications
const notificationsCallbackRegex = /if\s*\(data\s*===\s*['"]notifications['"].*?\)/g;
const hasNotificationsCallback = notificationsCallbackRegex.test(content);
debugInfo.push(`Обработчик для callback 'notifications' найден: ${hasNotificationsCallback}`);
// Выводим результаты
console.log('\n=== Анализ CallbackHandlers.ts ===\n');
if (issues.length > 0) {
console.log('НАЙДЕНЫ ПРОБЛЕМЫ:');
issues.forEach(issue => console.log(issue));
console.log('\nРЕКОМЕНДАЦИИ:');
console.log('1. Восстановите оригинальные реализации методов вместо заглушек');
console.log('2. Убедитесь, что методы содержат необходимую бизнес-логику');
console.log('3. Проверьте, что все коллбэки правильно обрабатываются');
} else {
console.log('✅ Проблем не обнаружено');
}
console.log('\n=== Отладочная информация ===\n');
debugInfo.forEach(info => console.log(info));
// Проверяем количество методов в файле
const asyncMethodsCount = (content.match(/async\s+handle[A-Za-z]+\s*\(/g) || []).length;
console.log(`\nВсего async методов в файле: ${asyncMethodsCount}`);
}
analyzeCallbackHandlers();

74
scripts/checkUserTable.js Normal file
View File

@@ -0,0 +1,74 @@
const { Pool } = require('pg');
require('dotenv').config();
const pool = new Pool({
user: process.env.DB_USER || 'postgres',
host: process.env.DB_HOST || 'localhost',
database: process.env.DB_NAME || 'telegram_tinder_db',
password: process.env.DB_PASSWORD || 'postgres',
port: parseInt(process.env.DB_PORT || '5432')
});
async function checkUserTableStructure() {
try {
// Получаем информацию о структуре таблицы users
const result = await pool.query(`
SELECT column_name, data_type, is_nullable
FROM information_schema.columns
WHERE table_name = 'users'
ORDER BY ordinal_position;
`);
console.log('=== Структура таблицы users ===');
console.table(result.rows);
// Проверяем наличие столбцов state и state_data
const stateColumn = result.rows.find(row => row.column_name === 'state');
const stateDataColumn = result.rows.find(row => row.column_name === 'state_data');
if (!stateColumn) {
console.log('❌ Столбец state отсутствует в таблице users');
} else {
console.log('✅ Столбец state присутствует в таблице users');
}
if (!stateDataColumn) {
console.log('❌ Столбец state_data отсутствует в таблице users');
} else {
console.log('✅ Столбец state_data присутствует в таблице users');
}
// Добавляем эти столбцы, если их нет
if (!stateColumn || !stateDataColumn) {
console.log('🔄 Добавление отсутствующих столбцов...');
await pool.query(`
ALTER TABLE users
ADD COLUMN IF NOT EXISTS state VARCHAR(255) NULL,
ADD COLUMN IF NOT EXISTS state_data JSONB DEFAULT '{}'::jsonb;
`);
console.log('✅ Столбцы успешно добавлены');
}
// Проверяем наличие других таблиц, связанных с уведомлениями
const tablesResult = await pool.query(`
SELECT tablename
FROM pg_catalog.pg_tables
WHERE schemaname = 'public'
AND tablename IN ('notifications', 'notification_settings', 'scheduled_notifications');
`);
console.log('\n=== Таблицы для уведомлений ===');
console.table(tablesResult.rows);
// Закрываем соединение
await pool.end();
} catch (error) {
console.error('Ошибка при проверке структуры таблицы:', error);
await pool.end();
}
}
checkUserTableStructure();

View File

@@ -0,0 +1,259 @@
const { Pool } = require('pg');
const dotenv = require('dotenv');
const uuid = require('uuid');
dotenv.config();
const pool = new Pool({
connectionString: process.env.DATABASE_URL,
});
async function createNotificationTables() {
const client = await pool.connect();
try {
await client.query('BEGIN');
console.log('Creating UUID extension if not exists...');
await client.query(`
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
`);
// Проверяем существование таблицы notifications
const notificationsExists = await client.query(`
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_name = 'notifications'
) as exists
`);
if (!notificationsExists.rows[0].exists) {
console.log('Creating notifications table...');
await client.query(`
CREATE TABLE notifications (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
type VARCHAR(50) NOT NULL,
data JSONB,
is_read BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW()
)
`);
console.log('Creating index on notifications...');
await client.query(`
CREATE INDEX idx_notifications_user_id ON notifications (user_id);
CREATE INDEX idx_notifications_type ON notifications (type);
CREATE INDEX idx_notifications_created_at ON notifications (created_at);
`);
} else {
console.log('Notifications table already exists.');
}
// Проверяем существование таблицы scheduled_notifications
const scheduledExists = await client.query(`
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_name = 'scheduled_notifications'
) as exists
`);
if (!scheduledExists.rows[0].exists) {
console.log('Creating scheduled_notifications table...');
await client.query(`
CREATE TABLE scheduled_notifications (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
type VARCHAR(50) NOT NULL,
data JSONB,
scheduled_at TIMESTAMP NOT NULL,
processed BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW()
)
`);
console.log('Creating index on scheduled_notifications...');
await client.query(`
CREATE INDEX idx_scheduled_notifications_user_id ON scheduled_notifications (user_id);
CREATE INDEX idx_scheduled_notifications_scheduled_at ON scheduled_notifications (scheduled_at);
CREATE INDEX idx_scheduled_notifications_processed ON scheduled_notifications (processed);
`);
} else {
console.log('Scheduled_notifications table already exists.');
}
// Проверяем существование таблицы notification_templates
const templatesExists = await client.query(`
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_name = 'notification_templates'
) as exists
`);
if (!templatesExists.rows[0].exists) {
console.log('Creating notification_templates table...');
await client.query(`
CREATE TABLE notification_templates (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
type VARCHAR(50) NOT NULL UNIQUE,
title TEXT NOT NULL,
message_template TEXT NOT NULL,
button_template JSONB,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
)
`);
} else {
console.log('Notification_templates table already exists.');
}
// Проверяем наличие колонки notification_settings в таблице users
const settingsColumnExists = await client.query(`
SELECT EXISTS (
SELECT FROM information_schema.columns
WHERE table_name = 'users' AND column_name = 'notification_settings'
) as exists
`);
if (!settingsColumnExists.rows[0].exists) {
console.log('Adding notification_settings column to users table...');
await client.query(`
ALTER TABLE users
ADD COLUMN notification_settings JSONB DEFAULT '{
"newMatches": true,
"newMessages": true,
"newLikes": true,
"reminders": true,
"dailySummary": true,
"timePreference": "evening",
"doNotDisturb": false
}'::jsonb
`);
} else {
console.log('Notification_settings column already exists in users table.');
}
// Заполнение таблицы шаблонов уведомлений базовыми шаблонами
if (!templatesExists.rows[0].exists) {
console.log('Populating notification templates...');
const templates = [
{
type: 'new_like',
title: 'Новый лайк!',
message_template: '❤️ *{{name}}* поставил(а) вам лайк!\n\nВозраст: {{age}}\n{{city}}\n\nОтветьте взаимностью или посмотрите профиль.',
button_template: {
inline_keyboard: [
[{ text: '👀 Посмотреть профиль', callback_data: 'view_profile:{{userId}}' }],
[
{ text: '❤️ Лайк в ответ', callback_data: 'like_back:{{userId}}' },
{ text: '⛔️ Пропустить', callback_data: 'dislike_profile:{{userId}}' }
],
[{ text: '💕 Открыть все лайки', callback_data: 'view_likes' }]
]
}
},
{
type: 'super_like',
title: 'Супер-лайк!',
message_template: '⭐️ *{{name}}* отправил(а) вам супер-лайк!\n\nВозраст: {{age}}\n{{city}}\n\nВы произвели особое впечатление! Ответьте взаимностью или посмотрите профиль.',
button_template: {
inline_keyboard: [
[{ text: '👀 Посмотреть профиль', callback_data: 'view_profile:{{userId}}' }],
[
{ text: '❤️ Лайк в ответ', callback_data: 'like_back:{{userId}}' },
{ text: '⛔️ Пропустить', callback_data: 'dislike_profile:{{userId}}' }
],
[{ text: '💕 Открыть все лайки', callback_data: 'view_likes' }]
]
}
},
{
type: 'new_match',
title: 'Новый матч!',
message_template: '🎊 *Ура! Это взаимно!* 🎊\n\nВы и *{{name}}* понравились друг другу!\nВозраст: {{age}}\n{{city}}\n\nСделайте первый шаг - напишите сообщение!',
button_template: {
inline_keyboard: [
[{ text: '💬 Начать общение', callback_data: 'open_chat:{{matchId}}' }],
[
{ text: '👀 Посмотреть профиль', callback_data: 'view_profile:{{userId}}' },
{ text: '📋 Все матчи', callback_data: 'view_matches' }
]
]
}
},
{
type: 'new_message',
title: 'Новое сообщение!',
message_template: '💌 *Новое сообщение!*\n\nОт: *{{name}}*\n\n"{{message}}"\n\nОтветьте на сообщение прямо сейчас!',
button_template: {
inline_keyboard: [
[{ text: '📩 Ответить', callback_data: 'open_chat:{{matchId}}' }],
[
{ text: '👤 Профиль', callback_data: 'view_profile:{{userId}}' },
{ text: '📋 Все чаты', callback_data: 'view_matches' }
]
]
}
},
{
type: 'match_reminder',
title: 'Напоминание о матче',
message_template: '💕 У вас есть матч с *{{name}}*, но вы еще не начали общение!\n\nНе упустите шанс познакомиться поближе!',
button_template: {
inline_keyboard: [
[{ text: '💬 Начать общение', callback_data: 'open_chat:{{matchId}}' }],
[{ text: '👀 Посмотреть профиль', callback_data: 'view_profile:{{userId}}' }]
]
}
},
{
type: 'inactive_matches',
title: 'Неактивные матчи',
message_template: '⏰ У вас {{count}} неактивных матчей!\n\nПродолжите общение, чтобы не упустить интересные знакомства!',
button_template: {
inline_keyboard: [
[{ text: '📋 Открыть матчи', callback_data: 'view_matches' }],
[{ text: '💕 Смотреть новые анкеты', callback_data: 'start_browsing' }]
]
}
},
{
type: 'like_summary',
title: 'Сводка лайков',
message_template: '💖 У вас {{count}} новых лайков!\n\nПосмотрите, кто проявил к вам интерес сегодня!',
button_template: {
inline_keyboard: [
[{ text: '👀 Посмотреть лайки', callback_data: 'view_likes' }],
[{ text: '💕 Начать знакомиться', callback_data: 'start_browsing' }]
]
}
}
];
for (const template of templates) {
await client.query(`
INSERT INTO notification_templates (id, type, title, message_template, button_template)
VALUES ($1, $2, $3, $4, $5)
`, [
uuid.v4(),
template.type,
template.title,
template.message_template,
JSON.stringify(template.button_template)
]);
}
}
await client.query('COMMIT');
console.log('Successfully created notification tables');
} catch (err) {
await client.query('ROLLBACK');
console.error('Error creating notification tables:', err);
} finally {
client.release();
pool.end();
}
}
createNotificationTables().catch(err => console.error('Failed to create notification tables:', err));

View File

@@ -0,0 +1,142 @@
// Скрипт для восстановления оригинальной функциональности callbackHandlers.ts
const fs = require('fs');
const path = require('path');
// Находим самую последнюю версию файла callbackHandlers.ts в репозитории
const { execSync } = require('child_process');
try {
console.log('Поиск оригинальной версии CallbackHandlers.ts с полной функциональностью...');
// Находим коммиты, содержащие значительные изменения в файле (более 1000 символов)
const commits = execSync('git log --format="%H" -- src/handlers/callbackHandlers.ts')
.toString()
.trim()
.split('\n');
console.log(`Найдено ${commits.length} коммитов с изменениями файла`);
// Пробуем разные коммиты, начиная с последнего, чтобы найти полную реализацию
let foundFullImplementation = false;
let fullImplementationContent = '';
for (const commit of commits) {
console.log(`Проверяем коммит ${commit.substring(0, 8)}...`);
try {
const fileContent = execSync(`git show ${commit}:src/handlers/callbackHandlers.ts`).toString();
// Проверяем, содержит ли файл полные реализации методов
const hasFullImplementations = !fileContent.includes('// Заглушка метода') &&
fileContent.includes('await this.bot.sendMessage');
if (hasFullImplementations) {
console.log(`✅ Найдена полная реализация в коммите ${commit.substring(0, 8)}`);
fullImplementationContent = fileContent;
foundFullImplementation = true;
break;
} else {
console.log(`❌ Коммит ${commit.substring(0, 8)} не содержит полной реализации`);
}
} catch (error) {
console.error(`Ошибка при проверке коммита ${commit}:`, error.message);
}
}
if (!foundFullImplementation) {
console.error('❌ Не удалось найти полную реализацию в истории коммитов');
process.exit(1);
}
// Теперь получаем текущую версию файла с поддержкой уведомлений
console.log('Получаем текущую версию с поддержкой уведомлений...');
const currentFilePath = path.join(__dirname, '..', 'src', 'handlers', 'callbackHandlers.ts');
const currentContent = fs.readFileSync(currentFilePath, 'utf-8');
// Сначала создаем бэкап текущего файла
const backupPath = currentFilePath + '.backup-' + Date.now();
fs.writeFileSync(backupPath, currentContent);
console.log(`✅ Создан бэкап текущей версии: ${path.basename(backupPath)}`);
// Извлекаем код для поддержки уведомлений из текущей версии
console.log('Извлекаем код для поддержки уведомлений...');
// Находим импорт NotificationHandlers
const notificationImportRegex = /import\s+{\s*NotificationHandlers\s*}\s*from\s*['"]\.\/notificationHandlers['"]\s*;/;
const notificationImport = currentContent.match(notificationImportRegex)?.[0] || '';
// Находим объявление поля notificationHandlers
const notificationFieldRegex = /private\s+notificationHandlers\?\s*:\s*NotificationHandlers\s*;/;
const notificationField = currentContent.match(notificationFieldRegex)?.[0] || '';
// Находим инициализацию notificationHandlers в конструкторе
const notificationInitRegex = /\/\/\s*Создаем экземпляр NotificationHandlers[\s\S]*?try\s*{[\s\S]*?this\.notificationHandlers\s*=\s*new\s*NotificationHandlers[\s\S]*?}\s*catch[\s\S]*?}/;
const notificationInit = currentContent.match(notificationInitRegex)?.[0] || '';
// Находим метод handleNotificationSettings
const notificationSettingsMethodRegex = /async\s+handleNotificationSettings[\s\S]*?}\s*}/;
const notificationSettingsMethod = currentContent.match(notificationSettingsMethodRegex)?.[0] || '';
// Находим обработку callback для notifications в handleCallback
const notificationCallbackRegex = /\/\/\s*Настройки уведомлений[\s\S]*?else\s+if\s*\(data\s*===\s*['"]notifications['"][\s\S]*?}\s*}/;
const notificationCallback = currentContent.match(notificationCallbackRegex)?.[0] || '';
// Получаем часть обработки коллбэков для уведомлений
const notificationToggleRegex = /\/\/\s*Обработка переключения настроек уведомлений[\s\S]*?else\s+if[\s\S]*?notif_[\s\S]*?}\s*}/;
const notificationToggle = currentContent.match(notificationToggleRegex)?.[0] || '';
console.log(`✅ Извлечены блоки кода для уведомлений`);
// Интегрируем код уведомлений в оригинальную версию
console.log('Интегрируем код уведомлений в оригинальную версию...');
// 1. Добавляем импорт
let newContent = fullImplementationContent;
if (notificationImport) {
newContent = newContent.replace(/import\s*{[^}]*}\s*from\s*['"]\.\/messageHandlers['"]\s*;/,
match => match + '\n' + notificationImport);
}
// 2. Добавляем объявление поля
if (notificationField) {
newContent = newContent.replace(/private\s+translationController\s*:\s*TranslationController\s*;/,
match => match + '\n ' + notificationField);
}
// 3. Добавляем инициализацию в конструкторе
if (notificationInit) {
newContent = newContent.replace(/this\.translationController\s*=\s*new\s*TranslationController\(\);/,
match => match + '\n ' + notificationInit);
}
// 4. Добавляем обработку коллбэков для уведомлений
if (notificationCallback) {
newContent = newContent.replace(/else\s+{\s*await\s+this\.bot\.answerCallbackQuery\(query\.id[\s\S]*?return;/,
match => notificationCallback + '\n ' + match);
}
// 5. Добавляем обработку переключения настроек уведомлений
if (notificationToggle) {
newContent = newContent.replace(/else\s+{\s*await\s+this\.bot\.answerCallbackQuery\(query\.id[\s\S]*?return;/,
match => notificationToggle + '\n ' + match);
}
// 6. Добавляем метод handleNotificationSettings в конец класса
if (notificationSettingsMethod) {
newContent = newContent.replace(/}(\s*)$/, notificationSettingsMethod + '\n}$1');
}
// Сохраняем обновленный файл
const outputPath = currentFilePath + '.fixed';
fs.writeFileSync(outputPath, newContent);
console.log(`✅ Создана исправленная версия файла: ${path.basename(outputPath)}`);
console.log('\nИнструкция по восстановлению:');
console.log(`1. Проверьте файл ${path.basename(outputPath)}`);
console.log('2. Если все выглядит правильно, выполните команду:');
console.log(` Move-Item -Force "${path.basename(outputPath)}" "${path.basename(currentFilePath)}"`);
console.log('3. Перезапустите бота');
} catch (error) {
console.error('Произошла ошибка:', error);
}

View File

@@ -0,0 +1,170 @@
// Скрипт для исправления проблемы с ботом
require('dotenv').config();
const { Pool } = require('pg');
// Получаем данные подключения из .env
console.log('Параметры подключения к БД:');
console.log('DB_USERNAME:', process.env.DB_USERNAME);
console.log('DB_HOST:', process.env.DB_HOST);
console.log('DB_NAME:', process.env.DB_NAME);
console.log('DB_PASSWORD:', process.env.DB_PASSWORD ? '[указан]' : '[не указан]');
console.log('DB_PORT:', process.env.DB_PORT);
// Создаем пул соединений
const pool = new Pool({
user: process.env.DB_USERNAME,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASSWORD,
port: parseInt(process.env.DB_PORT || '5432')
});
async function fixDatabase() {
try {
console.log('Начинаем исправление базы данных...');
// Проверяем существование таблицы users
const tableResult = await pool.query(`
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = 'users'
);
`);
if (!tableResult.rows[0].exists) {
console.error('Таблица users не найдена!');
return;
}
console.log('✅ Таблица users существует');
// Проверяем и добавляем столбцы state и state_data, если они отсутствуют
console.log('Проверяем наличие столбцов state и state_data...');
const stateColumnResult = await pool.query(`
SELECT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'users'
AND column_name = 'state'
);
`);
const stateDataColumnResult = await pool.query(`
SELECT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'users'
AND column_name = 'state_data'
);
`);
if (!stateColumnResult.rows[0].exists) {
console.log('🔄 Добавляем столбец state...');
await pool.query(`ALTER TABLE users ADD COLUMN state VARCHAR(255) NULL;`);
console.log('✅ Столбец state успешно добавлен');
} else {
console.log('✅ Столбец state уже существует');
}
if (!stateDataColumnResult.rows[0].exists) {
console.log('🔄 Добавляем столбец state_data...');
await pool.query(`ALTER TABLE users ADD COLUMN state_data JSONB DEFAULT '{}'::jsonb;`);
console.log('✅ Столбец state_data успешно добавлен');
} else {
console.log('✅ Столбец state_data уже существует');
}
// Проверка наличия таблиц для уведомлений
console.log('Проверяем наличие таблиц для уведомлений...');
const tablesCheck = await Promise.all([
checkTableExists('notifications'),
checkTableExists('notification_settings'),
checkTableExists('scheduled_notifications')
]);
// Создаем отсутствующие таблицы
if (!tablesCheck[0]) {
console.log('🔄 Создаем таблицу notifications...');
await pool.query(`
CREATE TABLE notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
type VARCHAR(50) NOT NULL,
content JSONB NOT NULL DEFAULT '{}',
is_read BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_notifications_user_id ON notifications(user_id);
CREATE INDEX idx_notifications_type ON notifications(type);
CREATE INDEX idx_notifications_created_at ON notifications(created_at);
`);
console.log('✅ Таблица notifications успешно создана');
}
if (!tablesCheck[1]) {
console.log('🔄 Создаем таблицу notification_settings...');
await pool.query(`
CREATE TABLE notification_settings (
user_id UUID PRIMARY KEY REFERENCES users(id) ON DELETE CASCADE,
new_matches BOOLEAN DEFAULT true,
new_messages BOOLEAN DEFAULT true,
new_likes BOOLEAN DEFAULT true,
reminders BOOLEAN DEFAULT true,
daily_summary BOOLEAN DEFAULT false,
time_preference VARCHAR(20) DEFAULT 'evening',
do_not_disturb BOOLEAN DEFAULT false,
do_not_disturb_start TIME,
do_not_disturb_end TIME,
updated_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
`);
console.log('✅ Таблица notification_settings успешно создана');
}
if (!tablesCheck[2]) {
console.log('🔄 Создаем таблицу scheduled_notifications...');
await pool.query(`
CREATE TABLE scheduled_notifications (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
type VARCHAR(50) NOT NULL,
content JSONB NOT NULL DEFAULT '{}',
scheduled_at TIMESTAMP WITH TIME ZONE NOT NULL,
processed BOOLEAN DEFAULT false,
created_at TIMESTAMP WITH TIME ZONE DEFAULT NOW()
);
CREATE INDEX idx_scheduled_notifications_user_id ON scheduled_notifications(user_id);
CREATE INDEX idx_scheduled_notifications_scheduled_at ON scheduled_notifications(scheduled_at);
CREATE INDEX idx_scheduled_notifications_processed ON scheduled_notifications(processed);
`);
console.log('✅ Таблица scheduled_notifications успешно создана');
}
console.log('✅ Исправление базы данных завершено успешно');
} catch (error) {
console.error('Ошибка при исправлении базы данных:', error);
} finally {
await pool.end();
}
}
async function checkTableExists(tableName) {
const result = await pool.query(`
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_schema = 'public'
AND table_name = $1
);
`, [tableName]);
const exists = result.rows[0].exists;
console.log(`${exists ? '✅' : '❌'} Таблица ${tableName} ${exists ? 'существует' : 'отсутствует'}`);
return exists;
}
fixDatabase();

View File

@@ -0,0 +1,48 @@
/**
* Комплексный скрипт для исправления всех проблем с уведомлениями
* Запускает последовательно оба скрипта исправления
*/
const { exec } = require('child_process');
const path = require('path');
console.log('🔧 Запуск комплексного исправления проблем с уведомлениями...');
// Путь к скриптам
const fixNotificationCallbacksScript = path.join(__dirname, 'fix_notification_callbacks.js');
const updateBotWithNotificationsScript = path.join(__dirname, 'update_bot_with_notifications.js');
// Запуск первого скрипта для исправления таблиц и колонок
console.log('\n📊 Шаг 1/2: Проверка и исправление таблиц базы данных...');
exec(`node ${fixNotificationCallbacksScript}`, (error, stdout, stderr) => {
if (error) {
console.error(`❌ Ошибка при запуске скрипта исправления таблиц: ${error}`);
return;
}
console.log(stdout);
if (stderr) {
console.error(`❌ Ошибки при выполнении скрипта: ${stderr}`);
}
// Запуск второго скрипта для обновления bot.ts
console.log('\n📝 Шаг 2/2: Обновление файла bot.ts для регистрации обработчиков уведомлений...');
exec(`node ${updateBotWithNotificationsScript}`, (error2, stdout2, stderr2) => {
if (error2) {
console.error(`❌ Ошибка при запуске скрипта обновления bot.ts: ${error2}`);
return;
}
console.log(stdout2);
if (stderr2) {
console.error(`❌ Ошибки при выполнении скрипта: ${stderr2}`);
}
console.log('\n✅ Все исправления успешно выполнены!');
console.log('🔄 Пожалуйста, перезапустите бота для применения изменений:');
console.log(' npm run start');
console.log('\n💡 Уведомления должны теперь работать корректно!');
});
});

View File

@@ -0,0 +1,332 @@
/**
* Скрипт для проверки и исправления проблем с обработчиками уведомлений в боте
*/
const { Client } = require('pg');
const fs = require('fs');
// Конфигурация базы данных
const dbConfig = {
host: 'localhost',
port: 5432,
database: 'telegram_tinder',
user: 'postgres',
password: 'postgres'
};
// Подключение к базе данных
const client = new Client(dbConfig);
async function main() {
try {
console.log('Подключение к базе данных...');
await client.connect();
console.log('Успешно подключено к базе данных');
// Шаг 1: Проверка существования необходимых таблиц для уведомлений
console.log('\n=== Проверка таблиц для уведомлений ===');
// Проверяем таблицу notifications
let notificationsTableExists = await checkTableExists('notifications');
if (!notificationsTableExists) {
console.log('Таблица notifications не найдена. Создаем...');
await createNotificationsTable();
console.log('Таблица notifications успешно создана');
} else {
console.log('Таблица notifications уже существует');
}
// Проверяем таблицу scheduled_notifications
let scheduledNotificationsTableExists = await checkTableExists('scheduled_notifications');
if (!scheduledNotificationsTableExists) {
console.log('Таблица scheduled_notifications не найдена. Создаем...');
await createScheduledNotificationsTable();
console.log('Таблица scheduled_notifications успешно создана');
} else {
console.log('Таблица scheduled_notifications уже существует');
}
// Проверяем таблицу notification_templates
let notificationTemplatesTableExists = await checkTableExists('notification_templates');
if (!notificationTemplatesTableExists) {
console.log('Таблица notification_templates не найдена. Создаем...');
await createNotificationTemplatesTable();
console.log('Таблица notification_templates успешно создана');
console.log('Заполняем таблицу базовыми шаблонами...');
await populateDefaultTemplates();
console.log('Шаблоны успешно добавлены');
} else {
console.log('Таблица notification_templates уже существует');
}
// Шаг 2: Проверка существования столбца notification_settings в таблице users
console.log('\n=== Проверка столбца notification_settings в таблице users ===');
const notificationSettingsColumnExists = await checkColumnExists('users', 'notification_settings');
if (!notificationSettingsColumnExists) {
console.log('Столбец notification_settings не найден. Добавляем...');
await addNotificationSettingsColumn();
console.log('Столбец notification_settings успешно добавлен');
} else {
console.log('Столбец notification_settings уже существует');
}
// Шаг 3: Проверка существования столбцов state и state_data в таблице users
console.log('\n=== Проверка столбцов state и state_data в таблице users ===');
const stateColumnExists = await checkColumnExists('users', 'state');
if (!stateColumnExists) {
console.log('Столбец state не найден. Добавляем...');
await addStateColumn();
console.log('Столбец state успешно добавлен');
} else {
console.log('Столбец state уже существует');
}
const stateDataColumnExists = await checkColumnExists('users', 'state_data');
if (!stateDataColumnExists) {
console.log('Столбец state_data не найден. Добавляем...');
await addStateDataColumn();
console.log('Столбец state_data успешно добавлен');
} else {
console.log('Столбец state_data уже существует');
}
console.log('\nВсе таблицы и столбцы успешно проверены и созданы при необходимости.');
console.log('Механизм уведомлений должен работать корректно.');
console.log('\n=== Проверка регистрации обработчиков уведомлений ===');
console.log('Подсказка: убедитесь, что в файле bot.ts создается экземпляр NotificationHandlers и регистрируются его обработчики:');
console.log(`
// Настройка обработчиков уведомлений
const notificationHandlers = new NotificationHandlers(bot);
notificationHandlers.register();
// Запуск обработчика запланированных уведомлений
setInterval(() => {
const notificationService = new NotificationService(bot);
notificationService.processScheduledNotifications();
}, 60000); // Проверяем каждую минуту
`);
} catch (error) {
console.error('Ошибка выполнения скрипта:', error);
} finally {
await client.end();
console.log('\nСоединение с базой данных закрыто.');
}
}
async function checkTableExists(tableName) {
const query = `
SELECT EXISTS (
SELECT FROM information_schema.tables
WHERE table_name = $1
) as exists
`;
const result = await client.query(query, [tableName]);
return result.rows[0].exists;
}
async function checkColumnExists(tableName, columnName) {
const query = `
SELECT EXISTS (
SELECT FROM information_schema.columns
WHERE table_name = $1 AND column_name = $2
) as exists
`;
const result = await client.query(query, [tableName, columnName]);
return result.rows[0].exists;
}
async function createNotificationsTable() {
await client.query(`
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE notifications (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
type VARCHAR(50) NOT NULL,
data JSONB,
is_read BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW()
)
`);
}
async function createScheduledNotificationsTable() {
await client.query(`
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE scheduled_notifications (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
type VARCHAR(50) NOT NULL,
data JSONB,
scheduled_at TIMESTAMP NOT NULL,
processed BOOLEAN DEFAULT FALSE,
created_at TIMESTAMP DEFAULT NOW()
)
`);
}
async function createNotificationTemplatesTable() {
await client.query(`
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
CREATE TABLE notification_templates (
id UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
type VARCHAR(50) NOT NULL UNIQUE,
title TEXT NOT NULL,
message_template TEXT NOT NULL,
button_template JSONB,
created_at TIMESTAMP DEFAULT NOW(),
updated_at TIMESTAMP DEFAULT NOW()
)
`);
}
async function addNotificationSettingsColumn() {
await client.query(`
ALTER TABLE users
ADD COLUMN notification_settings JSONB DEFAULT '{
"newMatches": true,
"newMessages": true,
"newLikes": true,
"reminders": true,
"dailySummary": true,
"timePreference": "evening",
"doNotDisturb": false
}'::jsonb
`);
}
async function addStateColumn() {
await client.query(`
ALTER TABLE users ADD COLUMN state VARCHAR(255) NULL
`);
}
async function addStateDataColumn() {
await client.query(`
ALTER TABLE users ADD COLUMN state_data JSONB DEFAULT '{}'::jsonb
`);
}
async function populateDefaultTemplates() {
const templates = [
{
type: 'new_like',
title: 'Новый лайк!',
message_template: '❤️ *{{name}}* поставил(а) вам лайк!\n\nВозраст: {{age}}\n{{city}}\n\nОтветьте взаимностью или посмотрите профиль.',
button_template: {
inline_keyboard: [
[{ text: '👀 Посмотреть профиль', callback_data: 'view_profile:{{userId}}' }],
[
{ text: '❤️ Лайк в ответ', callback_data: 'like_back:{{userId}}' },
{ text: '⛔️ Пропустить', callback_data: 'dislike_profile:{{userId}}' }
],
[{ text: '💕 Открыть все лайки', callback_data: 'view_likes' }]
]
}
},
{
type: 'super_like',
title: 'Супер-лайк!',
message_template: '⭐️ *{{name}}* отправил(а) вам супер-лайк!\n\nВозраст: {{age}}\n{{city}}\n\nВы произвели особое впечатление! Ответьте взаимностью или посмотрите профиль.',
button_template: {
inline_keyboard: [
[{ text: '👀 Посмотреть профиль', callback_data: 'view_profile:{{userId}}' }],
[
{ text: '❤️ Лайк в ответ', callback_data: 'like_back:{{userId}}' },
{ text: '⛔️ Пропустить', callback_data: 'dislike_profile:{{userId}}' }
],
[{ text: '💕 Открыть все лайки', callback_data: 'view_likes' }]
]
}
},
{
type: 'new_match',
title: 'Новый матч!',
message_template: '🎊 *Ура! Это взаимно!* 🎊\n\nВы и *{{name}}* понравились друг другу!\nВозраст: {{age}}\n{{city}}\n\nСделайте первый шаг - напишите сообщение!',
button_template: {
inline_keyboard: [
[{ text: '💬 Начать общение', callback_data: 'open_chat:{{matchId}}' }],
[
{ text: '👀 Посмотреть профиль', callback_data: 'view_profile:{{userId}}' },
{ text: '📋 Все матчи', callback_data: 'view_matches' }
]
]
}
},
{
type: 'new_message',
title: 'Новое сообщение!',
message_template: '💌 *Новое сообщение!*\n\nОт: *{{name}}*\n\n"{{message}}"\n\nОтветьте на сообщение прямо сейчас!',
button_template: {
inline_keyboard: [
[{ text: '📩 Ответить', callback_data: 'open_chat:{{matchId}}' }],
[
{ text: '👤 Профиль', callback_data: 'view_profile:{{userId}}' },
{ text: '📋 Все чаты', callback_data: 'view_matches' }
]
]
}
},
{
type: 'match_reminder',
title: 'Напоминание о матче',
message_template: '💕 У вас есть матч с *{{name}}*, но вы еще не начали общение!\n\nНе упустите шанс познакомиться поближе!',
button_template: {
inline_keyboard: [
[{ text: '💬 Начать общение', callback_data: 'open_chat:{{matchId}}' }],
[{ text: '👀 Посмотреть профиль', callback_data: 'view_profile:{{userId}}' }]
]
}
},
{
type: 'inactive_matches',
title: 'Неактивные матчи',
message_template: '⏰ У вас {{count}} неактивных матчей!\n\nПродолжите общение, чтобы не упустить интересные знакомства!',
button_template: {
inline_keyboard: [
[{ text: '📋 Открыть матчи', callback_data: 'view_matches' }],
[{ text: '💕 Смотреть новые анкеты', callback_data: 'start_browsing' }]
]
}
},
{
type: 'like_summary',
title: 'Сводка лайков',
message_template: '💖 У вас {{count}} новых лайков!\n\nПосмотрите, кто проявил к вам интерес сегодня!',
button_template: {
inline_keyboard: [
[{ text: '👀 Посмотреть лайки', callback_data: 'view_likes' }],
[{ text: '💕 Начать знакомиться', callback_data: 'start_browsing' }]
]
}
}
];
for (const template of templates) {
await client.query(`
INSERT INTO notification_templates (type, title, message_template, button_template)
VALUES ($1, $2, $3, $4)
ON CONFLICT (type) DO UPDATE
SET title = EXCLUDED.title,
message_template = EXCLUDED.message_template,
button_template = EXCLUDED.button_template,
updated_at = NOW()
`, [
template.type,
template.title,
template.message_template,
JSON.stringify(template.button_template)
]);
}
}
// Запуск скрипта
main();

View File

@@ -0,0 +1,73 @@
// Скрипт для установки премиум-статуса всем пользователям
require('dotenv').config();
const { Pool } = require('pg');
// Проверяем и выводим параметры подключения
console.log('Параметры подключения к БД:');
console.log('DB_USERNAME:', process.env.DB_USERNAME);
console.log('DB_HOST:', process.env.DB_HOST);
console.log('DB_NAME:', process.env.DB_NAME);
console.log('DB_PASSWORD:', process.env.DB_PASSWORD ? '[указан]' : '[не указан]');
console.log('DB_PORT:', process.env.DB_PORT);
// Создаем пул соединений
const pool = new Pool({
user: process.env.DB_USERNAME,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASSWORD,
port: parseInt(process.env.DB_PORT || '5432')
});
async function setAllUsersToPremium() {
try {
console.log('Устанавливаем премиум-статус для всех пользователей...');
// Проверка соединения с БД
console.log('Проверка соединения с БД...');
const testResult = await pool.query('SELECT NOW()');
console.log('✅ Соединение успешно:', testResult.rows[0].now);
// Проверка наличия столбца premium
console.log('Проверяем наличие столбца premium в таблице users...');
const checkResult = await pool.query(`
SELECT EXISTS (
SELECT FROM information_schema.columns
WHERE table_schema = 'public'
AND table_name = 'users'
AND column_name = 'premium'
);
`);
if (!checkResult.rows[0].exists) {
console.log('🔄 Добавляем столбец premium...');
await pool.query(`ALTER TABLE users ADD COLUMN premium BOOLEAN DEFAULT false;`);
console.log('✅ Столбец premium успешно добавлен');
} else {
console.log('✅ Столбец premium уже существует');
}
// Устанавливаем premium=true для всех пользователей
const updateResult = await pool.query(`
UPDATE users
SET premium = true
WHERE true
RETURNING id, telegram_id, premium
`);
console.log(`✅ Успешно установлен премиум-статус для ${updateResult.rows.length} пользователей:`);
updateResult.rows.forEach(row => {
console.log(`ID: ${row.id.substr(0, 8)}... | Telegram ID: ${row.telegram_id} | Premium: ${row.premium}`);
});
console.log('🎉 Все пользователи теперь имеют премиум-статус!');
} catch (error) {
console.error('❌ Ошибка при установке премиум-статуса:', error);
} finally {
await pool.end();
console.log('Соединение с базой данных закрыто');
}
}
setAllUsersToPremium();

85
scripts/testCallbacks.js Normal file
View File

@@ -0,0 +1,85 @@
// Скрипт для проверки работы callback-хэндлеров и уведомлений
require('dotenv').config();
const TelegramBot = require('node-telegram-bot-api');
const { Pool } = require('pg');
// Создаем пул соединений
const pool = new Pool({
user: process.env.DB_USERNAME,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASSWORD,
port: parseInt(process.env.DB_PORT || '5432')
});
// Функция для имитации callback-запроса к боту
async function testCallback() {
try {
console.log('Начинаем тестирование callback-хэндлеров и уведомлений...');
// Используем последнего пользователя из базы данных
const userResult = await pool.query(`
SELECT * FROM users ORDER BY last_active_at DESC NULLS LAST LIMIT 1
`);
if (userResult.rows.length === 0) {
console.error('❌ Пользователи не найдены в базе данных');
return;
}
const user = userResult.rows[0];
console.log(`Выбран тестовый пользователь: ${user.first_name || 'Без имени'} (ID: ${user.telegram_id})`);
// Получаем токен бота из переменных окружения
const token = process.env.TELEGRAM_BOT_TOKEN;
if (!token) {
console.error('❌ Токен бота не найден в переменных окружения');
return;
}
// Создаем экземпляр бота
const bot = new TelegramBot(token);
// Отправляем тестовое уведомление пользователю
console.log(`Отправляем тестовое уведомление пользователю ID: ${user.telegram_id}...`);
try {
const result = await bot.sendMessage(
user.telegram_id,
`🔔 *Тестовое уведомление*\n\nЭто проверка работы уведомлений и callback-хэндлеров.\n\nВаш премиум-статус: ${user.premium ? '✅ Активен' : '❌ Не активен'}`,
{
parse_mode: 'Markdown',
reply_markup: {
inline_keyboard: [
[
{ text: '🔔 Уведомления', callback_data: 'notification_settings' },
{ text: '❤️ Профиль', callback_data: 'view_profile' }
],
[
{ text: '⚙️ Настройки', callback_data: 'settings' }
]
]
}
}
);
console.log('✅ Тестовое сообщение успешно отправлено!');
console.log('Информация о сообщении:', JSON.stringify(result, null, 2));
} catch (error) {
console.error('❌ Ошибка при отправке тестового сообщения:', error.message);
if (error.response && error.response.body) {
console.error('Детали ошибки:', JSON.stringify(error.response.body, null, 2));
}
}
} catch (error) {
console.error('❌ Ошибка при тестировании:', error);
} finally {
await pool.end();
console.log('Соединение с базой данных закрыто');
console.log('Тестирование завершено!');
}
}
// Запускаем тестирование
testCallback();

81
scripts/testVipMethod.js Normal file
View File

@@ -0,0 +1,81 @@
// Скрипт для тестирования метода checkPremiumStatus
require('dotenv').config();
const { Pool } = require('pg');
// Создаем пул соединений
const pool = new Pool({
user: process.env.DB_USERNAME,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASSWORD,
port: parseInt(process.env.DB_PORT || '5432')
});
async function testCheckPremiumMethod() {
try {
console.log('Тестирование метода checkPremiumStatus...');
// Получаем пользователя для тестирования
const userResult = await pool.query(`
SELECT id, telegram_id, first_name, username, premium
FROM users
ORDER BY last_active_at DESC NULLS LAST
LIMIT 1
`);
if (userResult.rows.length === 0) {
console.error('❌ Пользователи не найдены в базе данных');
return;
}
const user = userResult.rows[0];
console.log(`Выбран тестовый пользователь: ${user.first_name || user.username || 'Без имени'} (Telegram ID: ${user.telegram_id})`);
console.log(`Текущий премиум-статус: ${user.premium ? '✅ Активен' : '❌ Не активен'}`);
// Проверка работы метода checkPremiumStatus
console.log('\nЭмулируем вызов метода checkPremiumStatus из vipService:');
const result = await pool.query(`
SELECT id, premium
FROM users
WHERE telegram_id = $1
`, [user.telegram_id]);
if (result.rows.length === 0) {
console.log('❌ Пользователь не найден');
} else {
const isPremium = result.rows[0].premium || false;
console.log(`Результат метода: isPremium = ${isPremium ? '✅ true' : '❌ false'}`);
if (!isPremium) {
console.log('\nПремиум-статус отсутствует. Устанавливаем премиум...');
await pool.query(`
UPDATE users
SET premium = true
WHERE telegram_id = $1
`, [user.telegram_id]);
// Проверяем обновление
const updatedResult = await pool.query(`
SELECT premium
FROM users
WHERE telegram_id = $1
`, [user.telegram_id]);
const updatedPremium = updatedResult.rows[0].premium;
console.log(`Обновленный статус: isPremium = ${updatedPremium ? '✅ true' : '❌ false'}`);
}
}
console.log('\n✅ Тестирование завершено');
console.log('🔧 Теперь проверьте функциональность VIP поиска в боте');
} catch (error) {
console.error('❌ Ошибка при тестировании:', error);
} finally {
await pool.end();
console.log('Соединение с базой данных закрыто');
}
}
// Запускаем тест
testCheckPremiumMethod();

75
scripts/testVipStatus.js Normal file
View File

@@ -0,0 +1,75 @@
// Скрипт для тестирования VIP функционала
require('dotenv').config();
const { Pool } = require('pg');
// Создаем пул соединений
const pool = new Pool({
user: process.env.DB_USERNAME,
host: process.env.DB_HOST,
database: process.env.DB_NAME,
password: process.env.DB_PASSWORD,
port: parseInt(process.env.DB_PORT || '5432')
});
async function testVipStatus() {
try {
console.log('Тестирование функционала VIP статуса...');
// Получаем список пользователей с информацией о premium статусе
const users = await pool.query(`
SELECT id, telegram_id, username, first_name, premium
FROM users
ORDER BY last_active_at DESC
LIMIT 5
`);
console.log('Список пользователей и их премиум статус:');
users.rows.forEach(user => {
console.log(`ID: ${user.id.substr(0, 8)}... | Telegram ID: ${user.telegram_id} | Имя: ${user.first_name || user.username || 'Не указано'} | Premium: ${user.premium ? '✅' : '❌'}`);
});
// Если premium у всех false, устанавливаем premium = true
const nonPremiumUsers = users.rows.filter(user => !user.premium);
if (nonPremiumUsers.length > 0) {
console.log('\nОбнаружены пользователи без премиум статуса. Устанавливаем премиум...');
for (const user of nonPremiumUsers) {
await pool.query(`
UPDATE users
SET premium = true
WHERE id = $1
RETURNING id, telegram_id, premium
`, [user.id]);
console.log(`✅ Установлен премиум для пользователя ${user.first_name || user.username || user.telegram_id}`);
}
} else {
console.log('\nВсе пользователи уже имеют премиум-статус!');
}
// Проверяем результат
const updatedUsers = await pool.query(`
SELECT id, telegram_id, username, first_name, premium
FROM users
ORDER BY last_active_at DESC
LIMIT 5
`);
console.log('\nОбновленный список пользователей и их премиум статус:');
updatedUsers.rows.forEach(user => {
console.log(`ID: ${user.id.substr(0, 8)}... | Telegram ID: ${user.telegram_id} | Имя: ${user.first_name || user.username || 'Не указано'} | Premium: ${user.premium ? '✅' : '❌'}`);
});
console.log('\n✅ Тестирование VIP функционала завершено');
console.log('🔧 Проверьте доступность VIP поиска в боте через меню или команды');
} catch (error) {
console.error('❌ Ошибка при тестировании VIP статуса:', error);
} finally {
await pool.end();
console.log('Соединение с базой данных закрыто');
}
}
// Запускаем тест
testVipStatus();

View File

@@ -0,0 +1,104 @@
/**
* Скрипт для проверки и исправления регистрации NotificationHandlers в bot.ts
*/
const fs = require('fs');
const path = require('path');
const botFilePath = path.join(__dirname, '../src/bot.ts');
// Проверка существования файла bot.ts
if (!fs.existsSync(botFilePath)) {
console.error(`❌ Файл ${botFilePath} не найден`);
process.exit(1);
}
// Чтение содержимого файла bot.ts
let botContent = fs.readFileSync(botFilePath, 'utf8');
// Проверка импорта NotificationHandlers
if (!botContent.includes('import { NotificationHandlers }')) {
console.log('Добавляем импорт NotificationHandlers в bot.ts...');
// Находим последний импорт
const importRegex = /^import.*?;/gms;
const matches = [...botContent.matchAll(importRegex)];
if (matches.length > 0) {
const lastImport = matches[matches.length - 1][0];
const lastImportIndex = botContent.lastIndexOf(lastImport) + lastImport.length;
// Добавляем импорт NotificationHandlers
botContent =
botContent.slice(0, lastImportIndex) +
'\nimport { NotificationHandlers } from \'./handlers/notificationHandlers\';\n' +
botContent.slice(lastImportIndex);
console.log('✅ Импорт NotificationHandlers добавлен');
} else {
console.error('❌ Не удалось найти место для добавления импорта');
}
}
// Проверка объявления NotificationHandlers в классе
if (!botContent.includes('private notificationHandlers')) {
console.log('Добавляем объявление notificationHandlers в класс...');
const classPropertiesRegex = /class TelegramTinderBot {([^}]+?)constructor/s;
const classPropertiesMatch = botContent.match(classPropertiesRegex);
if (classPropertiesMatch) {
const classProperties = classPropertiesMatch[1];
const updatedProperties = classProperties + ' private notificationHandlers: NotificationHandlers;\n ';
botContent = botContent.replace(classPropertiesRegex, `class TelegramTinderBot {${updatedProperties}constructor`);
console.log('✅ Объявление notificationHandlers добавлено');
} else {
console.error('❌ Не удалось найти место для добавления объявления notificationHandlers');
}
}
// Проверка создания экземпляра NotificationHandlers в конструкторе
if (!botContent.includes('this.notificationHandlers = new NotificationHandlers')) {
console.log('Добавляем инициализацию notificationHandlers в конструктор...');
const initializationRegex = /(this\.callbackHandlers = new CallbackHandlers[^;]+;)/;
const initializationMatch = botContent.match(initializationRegex);
if (initializationMatch) {
const callbackHandlersInit = initializationMatch[1];
const updatedInit = callbackHandlersInit + '\n this.notificationHandlers = new NotificationHandlers(this.bot);';
botContent = botContent.replace(initializationRegex, updatedInit);
console.log('✅ Инициализация notificationHandlers добавлена');
} else {
console.error('❌ Не удалось найти место для добавления инициализации notificationHandlers');
}
}
// Проверка регистрации notificationHandlers в методе registerHandlers
if (!botContent.includes('this.notificationHandlers.register()')) {
console.log('Добавляем регистрацию notificationHandlers...');
const registerHandlersRegex = /(private registerHandlers\(\): void {[^}]+?)}/s;
const registerHandlersMatch = botContent.match(registerHandlersRegex);
if (registerHandlersMatch) {
const registerHandlersBody = registerHandlersMatch[1];
const updatedBody = registerHandlersBody + '\n // Обработчики уведомлений\n this.notificationHandlers.register();\n }';
botContent = botContent.replace(registerHandlersRegex, updatedBody);
console.log('✅ Регистрация notificationHandlers добавлена');
} else {
console.error('❌ Не удалось найти место для добавления регистрации notificationHandlers');
}
}
// Запись обновленного содержимого в файл
fs.writeFileSync(botFilePath, botContent, 'utf8');
console.log('✅ Файл bot.ts успешно обновлен');
console.log('🔔 Перезапустите бота для применения изменений');