Безопасность: - proxy: белый список путей (только /sub/*), POST заблокирован - console.log заменён на logger (утечки URL/данных) - OnboardingFlow: убраны --tg-theme-* (не существуют в проекте) TypeScript (0 ошибок): - tsconfig target es5→es2017 (regex /u flag fix) - layout.tsx: viewport перенесён в metadata (Next.js 13.5) - telegram-webhook: fix text possibly undefined - hooks/useTelegramWebApp: fix Object possibly undefined - types/telegram: убрана дублирующая Window декларация UI: - BottomNav: новый компонент (Назад/Главная/Помощь) - safe-area-bottom CSS класс добавлен в globals.css - dashboard: spacer h-20, toast поднят над BottomNav - OnboardingFlow: цены 149/249/350₽ (были 200/350/500₽) Очистка: - page_NEW.tsx удалён локально (не был в git)
152 lines
4.6 KiB
TypeScript
152 lines
4.6 KiB
TypeScript
// API endpoint для отслеживания реферальной регистрации
|
||
// POST /api/referral/track - записывает нового пользователя с реферером
|
||
|
||
import { NextRequest, NextResponse } from 'next/server';
|
||
import mysql from 'mysql2/promise';
|
||
import { logger } from '@/lib/logger';
|
||
|
||
// Database connection config from ENV
|
||
const dbConfig = {
|
||
host: process.env.DB_HOST || '',
|
||
user: process.env.DB_USER || '',
|
||
password: process.env.DB_PASSWORD || '',
|
||
database: process.env.DB_NAME || '',
|
||
connectTimeout: 20000, // 20 seconds
|
||
acquireTimeout: 20000,
|
||
};
|
||
|
||
// Check if DB is configured
|
||
const isDbConfigured = dbConfig.host && dbConfig.user && dbConfig.database;
|
||
|
||
export async function POST(request: NextRequest) {
|
||
try {
|
||
const body = await request.json();
|
||
const { username, referrer_username } = body;
|
||
|
||
if (!username) {
|
||
return NextResponse.json(
|
||
{ success: false, error: 'Username is required' },
|
||
{ status: 400 }
|
||
);
|
||
}
|
||
|
||
// Return mock success if DB not configured (dev mode)
|
||
if (!isDbConfigured) {
|
||
logger.info('⚠️ Referral tracking skipped: DB not configured');
|
||
return NextResponse.json({
|
||
success: true,
|
||
message: 'Referral tracking disabled (dev mode)',
|
||
dev_mode: true,
|
||
});
|
||
}
|
||
|
||
// Connect to database
|
||
const connection = await mysql.createConnection(dbConfig);
|
||
|
||
try {
|
||
// Check if user already exists in referrals table
|
||
const [existingRows] = await connection.query(
|
||
'SELECT id FROM referrals WHERE username = ?',
|
||
[username]
|
||
);
|
||
|
||
if ((existingRows as any[]).length > 0) {
|
||
return NextResponse.json({
|
||
success: false,
|
||
error: 'User already tracked',
|
||
});
|
||
}
|
||
|
||
// Insert new referral record
|
||
await connection.query(
|
||
'INSERT INTO referrals (username, referrer_username) VALUES (?, ?)',
|
||
[username, referrer_username || null]
|
||
);
|
||
|
||
// If referrer exists, increment their referral_count
|
||
if (referrer_username) {
|
||
// Check if referrer exists in users table
|
||
const [referrerRows] = await connection.query(
|
||
'SELECT username FROM users WHERE username = ?',
|
||
[referrer_username]
|
||
);
|
||
|
||
if ((referrerRows as any[]).length > 0) {
|
||
// Update or insert referrer's stats
|
||
await connection.query(
|
||
`INSERT INTO referrals (username, referral_count)
|
||
VALUES (?, 1)
|
||
ON DUPLICATE KEY UPDATE
|
||
referral_count = referral_count + 1,
|
||
updated_at = CURRENT_TIMESTAMP`,
|
||
[referrer_username]
|
||
);
|
||
|
||
// Calculate bonus days
|
||
const [statsRows] = await connection.query(
|
||
'SELECT referral_count FROM referrals WHERE username = ?',
|
||
[referrer_username]
|
||
);
|
||
|
||
const referralCount = (statsRows as any[])[0]?.referral_count || 0;
|
||
let bonusDays = 0;
|
||
|
||
// +7 days for each referral
|
||
bonusDays = referralCount * 7;
|
||
|
||
// +30 days milestone bonus for every 5 referrals
|
||
if (referralCount >= 5) {
|
||
const milestones = Math.floor(referralCount / 5);
|
||
bonusDays += milestones * 30;
|
||
}
|
||
|
||
// Update bonus_days_earned
|
||
await connection.query(
|
||
'UPDATE referrals SET bonus_days_earned = ? WHERE username = ?',
|
||
[bonusDays, referrer_username]
|
||
);
|
||
|
||
// Add bonus days to referrer's expire date in users table
|
||
await connection.query(
|
||
`UPDATE users
|
||
SET expire = CASE
|
||
WHEN expire IS NULL OR expire < UNIX_TIMESTAMP()
|
||
THEN UNIX_TIMESTAMP() + (? * 86400)
|
||
ELSE expire + (7 * 86400)
|
||
END
|
||
WHERE username = ?`,
|
||
[bonusDays, referrer_username]
|
||
);
|
||
|
||
return NextResponse.json({
|
||
success: true,
|
||
message: 'Referral tracked successfully',
|
||
referrer_bonus: {
|
||
username: referrer_username,
|
||
new_referral_count: referralCount,
|
||
bonus_days_added: 7,
|
||
total_bonus_days: bonusDays,
|
||
},
|
||
});
|
||
}
|
||
}
|
||
|
||
return NextResponse.json({
|
||
success: true,
|
||
message: 'User tracked without referrer',
|
||
});
|
||
} finally {
|
||
await connection.end();
|
||
}
|
||
} catch (error) {
|
||
logger.error('Referral track error:', error);
|
||
return NextResponse.json(
|
||
{
|
||
success: false,
|
||
error: error instanceof Error ? error.message : 'Unknown error',
|
||
},
|
||
{ status: 500 }
|
||
);
|
||
}
|
||
}
|