Files
tg_tinder_bot/src/services/vipService.ts
2025-09-18 08:31:14 +09:00

237 lines
9.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { query } from '../database/connection';
import { BotError } from '../types/index';
export interface VipSearchFilters {
ageMin?: number;
ageMax?: number;
city?: string;
datingGoal?: string;
hobbies?: string[];
lifestyle?: string[];
distance?: number;
hasPhotos?: boolean;
isOnline?: boolean;
}
export interface PremiumInfo {
isPremium: boolean;
expiresAt?: Date;
daysLeft?: number;
}
export class VipService {
// Проверить премиум статус пользователя
async checkPremiumStatus(telegramId: string): Promise<PremiumInfo> {
try {
// Проверяем существование пользователя
const result = await query(`
SELECT id
FROM users
WHERE telegram_id = $1
`, [telegramId]);
if (result.rows.length === 0) {
throw new BotError('User not found', 'USER_NOT_FOUND', 404);
}
// Временно возвращаем false для всех пользователей, так как колонки premium нет
// В будущем, когда колонки будут добавлены, этот код нужно будет заменить обратно
return {
isPremium: false,
expiresAt: undefined,
daysLeft: undefined
};
} catch (error) {
console.error('Error checking premium status:', error);
throw error;
}
}
// Добавить премиум статус
async addPremium(telegramId: string, durationDays: number = 30): Promise<void> {
try {
// Временно заглушка, так как колонок premium и premium_expires_at нет
console.log(`[VIP] Попытка добавить премиум для ${telegramId} на ${durationDays} дней`);
// TODO: Добавить колонки premium и premium_expires_at в таблицу users
} catch (error) {
console.error('Error adding premium:', error);
throw error;
}
}
// Удалить премиум статус
async removePremium(telegramId: string): Promise<void> {
try {
// Временно заглушка, так как колонок premium и premium_expires_at нет
console.log(`[VIP] Попытка удалить премиум для ${telegramId}`);
// TODO: Добавить колонки premium и premium_expires_at в таблицу users
} catch (error) {
console.error('Error removing premium:', error);
throw error;
}
}
// VIP поиск с фильтрами
async vipSearch(telegramId: string, filters: VipSearchFilters): Promise<any[]> {
try {
// Проверяем премиум статус
const premiumInfo = await this.checkPremiumStatus(telegramId);
if (!premiumInfo.isPremium) {
throw new BotError('Premium subscription required', 'PREMIUM_REQUIRED', 403);
}
// Получаем профиль пользователя
const userProfile = await query(`
SELECT p.*, u.telegram_id
FROM profiles p
JOIN users u ON p.user_id = u.id
WHERE u.telegram_id = $1
`, [telegramId]);
if (userProfile.rows.length === 0) {
throw new BotError('Profile not found', 'PROFILE_NOT_FOUND', 404);
}
const currentUser = userProfile.rows[0];
// Строим запрос с фильтрами
let query_text = `
SELECT p.*, u.telegram_id,
CASE WHEN u.updated_at > NOW() - INTERVAL '15 minutes' THEN true ELSE false END as is_online
FROM profiles p
JOIN users u ON p.user_id = u.id
LEFT JOIN swipes s ON (
s.swiper_id = $1 AND s.swiped_id = u.id
)
WHERE u.telegram_id != $2
AND s.id IS NULL
AND p.is_active = true
`;
let params = [currentUser.user_id, telegramId];
let paramIndex = 3;
// Фильтр по противоположному полу
if (currentUser.gender === 'male') {
query_text += ` AND p.gender = 'female'`;
} else if (currentUser.gender === 'female') {
query_text += ` AND p.gender = 'male'`;
} else {
// Если пол не определен или 'other', показываем всех кроме того же пола
query_text += ` AND p.gender != $${paramIndex}`;
params.push(currentUser.gender);
paramIndex++;
}
// Фильтр по возрасту
if (filters.ageMin) {
query_text += ` AND p.age >= $${paramIndex}`;
params.push(filters.ageMin);
paramIndex++;
}
if (filters.ageMax) {
query_text += ` AND p.age <= $${paramIndex}`;
params.push(filters.ageMax);
paramIndex++;
}
// Фильтр по городу
if (filters.city) {
query_text += ` AND LOWER(p.city) LIKE LOWER($${paramIndex})`;
params.push(`%${filters.city}%`);
paramIndex++;
}
// Фильтр по цели знакомства
if (filters.datingGoal) {
query_text += ` AND p.dating_goal = $${paramIndex}`;
params.push(filters.datingGoal);
paramIndex++;
}
// Фильтр по хобби
if (filters.hobbies && filters.hobbies.length > 0) {
const hobbyConditions = filters.hobbies.map((_, index) => {
return `LOWER(p.hobbies) LIKE LOWER($${paramIndex + index})`;
});
query_text += ` AND (${hobbyConditions.join(' OR ')})`;
filters.hobbies.forEach(hobby => {
params.push(`%${hobby}%`);
});
paramIndex += filters.hobbies.length;
}
// Фильтр по образу жизни
if (filters.lifestyle && filters.lifestyle.length > 0) {
const lifestyleConditions = filters.lifestyle.map((field) => {
const condition = `p.lifestyle ? $${paramIndex}`;
params.push(field);
paramIndex++;
return condition;
});
query_text += ` AND (${lifestyleConditions.join(' OR ')})`;
}
// Фильтр по наличию фото
if (filters.hasPhotos) {
query_text += ` AND p.photos IS NOT NULL AND array_length(p.photos, 1) > 0`;
}
// Фильтр по онлайн статусу
if (filters.isOnline) {
query_text += ` AND u.updated_at > NOW() - INTERVAL '15 minutes'`;
}
query_text += ` ORDER BY
CASE WHEN u.updated_at > NOW() - INTERVAL '15 minutes' THEN 0 ELSE 1 END,
u.updated_at DESC,
p.created_at DESC
LIMIT 50`;
const result = await query(query_text, params);
return result.rows;
} catch (error) {
console.error('Error in VIP search:', error);
throw error;
}
}
// Получить информацию о премиум возможностях
getPremiumFeatures(): string {
return `💎 ПРЕМИУМ ПОДПИСКА 💎
🔥 Что дает VIP статус:
🎯 VIP Поиск с фильтрами:
• Поиск по возрасту
• Поиск по городу
• Фильтр по целям знакомства
• Поиск по хобби и интересам
• Фильтр по образу жизни
• Только пользователи с фото
• Только онлайн пользователи
⚡ Дополнительные возможности:
• Неограниченные супер-лайки
• Просмотр кто лайкнул вас
• Возможность отменить свайп
• Приоритет в показе другим
• Расширенная статистика
• Скрытый режим просмотра
💰 Тарифы:
• 1 месяц - 299₽
• 3 месяца - 699₽ (экономия 25%)
• 6 месяцев - 1199₽ (экономия 33%)
• 1 год - 1999₽ (экономия 44%)
📞 Для покупки обратитесь к администратору:
@admin_bot
✨ Попробуйте VIP уже сегодня!`;
}
}