Files
Umbrix Dev 33b20b979f 🔒 Аудит: безопасность, TypeScript, UI, BottomNav
Безопасность:
- 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)
2026-02-08 18:59:02 +03:00

112 lines
3.2 KiB
TypeScript

// API endpoint для получения статистики реферальной программы
// GET /api/referral/stats?username=xxx - возвращает статистику пользователя
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 GET(request: NextRequest) {
try {
const { searchParams } = new URL(request.url);
const username = searchParams.get('username');
if (!username) {
return NextResponse.json(
{ success: false, error: 'Username is required' },
{ status: 400 }
);
}
// Return mock data if DB not configured (dev mode)
if (!isDbConfigured) {
logger.info('⚠️ Referral stats skipped: DB not configured');
return NextResponse.json({
success: true,
hasReferrals: false,
dev_mode: true,
stats: {
referral_count: 0,
bonus_days_earned: 0,
total_referrals_used: 0,
},
});
}
// Connect to database
const connection = await mysql.createConnection(dbConfig);
try {
// Get user's referral stats
const [statsRows] = await connection.query(
'SELECT * FROM referrals WHERE username = ?',
[username]
);
if ((statsRows as any[]).length === 0) {
return NextResponse.json({
success: true,
hasReferrals: false,
stats: {
referral_count: 0,
bonus_days_earned: 0,
total_referrals_used: 0,
},
});
}
const stats = (statsRows as any[])[0];
// Get list of referred users
const [referredRows] = await connection.query(
`SELECT u.username, u.created_at, u.status
FROM referrals r
JOIN users u ON r.username = u.username
WHERE r.referrer_username = ?
ORDER BY r.created_at DESC`,
[username]
);
return NextResponse.json({
success: true,
hasReferrals: true,
stats: {
referral_count: stats.referral_count || 0,
bonus_days_earned: stats.bonus_days_earned || 0,
total_referrals_used: stats.total_referrals_used || 0,
created_at: stats.created_at,
updated_at: stats.updated_at,
},
referred_users: (referredRows as any[]).map((user: any) => ({
username: user.username,
created_at: user.created_at,
status: user.status,
})),
});
} finally {
await connection.end();
}
} catch (error) {
logger.error('Referral stats error:', error);
return NextResponse.json(
{
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
},
{ status: 500 }
);
}
}