254 lines
9.5 KiB
TypeScript
254 lines
9.5 KiB
TypeScript
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, premium
|
||
FROM users
|
||
WHERE telegram_id = $1
|
||
`, [telegramId]);
|
||
|
||
if (result.rows.length === 0) {
|
||
throw new BotError('User not found', 'USER_NOT_FOUND', 404);
|
||
}
|
||
|
||
// Получаем актуальное значение премиум статуса из базы данных
|
||
const isPremium = result.rows[0].premium || false;
|
||
|
||
return {
|
||
isPremium: isPremium,
|
||
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 {
|
||
console.log(`[VIP] Добавление премиум для ${telegramId} на ${durationDays} дней`);
|
||
|
||
// Обновляем статус premium в базе данных
|
||
await query(`
|
||
UPDATE users
|
||
SET premium = true
|
||
WHERE telegram_id = $1
|
||
RETURNING id, telegram_id, premium
|
||
`, [telegramId]);
|
||
|
||
console.log(`[VIP] Премиум успешно добавлен для пользователя ${telegramId}`);
|
||
} catch (error) {
|
||
console.error('Error adding premium:', error);
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
// Удалить премиум статус
|
||
async removePremium(telegramId: string): Promise<void> {
|
||
try {
|
||
console.log(`[VIP] Удаление премиум для ${telegramId}`);
|
||
|
||
// Обновляем статус premium в базе данных
|
||
await query(`
|
||
UPDATE users
|
||
SET premium = false
|
||
WHERE telegram_id = $1
|
||
RETURNING id, telegram_id, premium
|
||
`, [telegramId]);
|
||
|
||
console.log(`[VIP] Премиум успешно удален для пользователя ${telegramId}`);
|
||
} 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 уже сегодня!`;
|
||
}
|
||
}
|