import { Router } from "express"; import { desc, eq, and, gte, or, ilike, sql } from "drizzle-orm"; import { db } from "../db"; import { errorLogs, users } from "@shared/schema"; import { authenticateToken, type AuthenticatedRequest } from "../middleware/auth.middleware"; const router = Router(); // Только администратор приложения function requireAppAdmin(req: AuthenticatedRequest, res: any, next: any) { if (req.user?.appRole !== 'admin') { return res.status(403).json({ success: false, error: 'Доступно только администратору' }); } next(); } // GET /api/error-logs?limit=50&offset=0&status=500&search=batch&days=7 router.get('/api/error-logs', authenticateToken, requireAppAdmin, async (req: AuthenticatedRequest, res) => { try { const organizationId = req.organizationId!; const limit = Math.min(parseInt(req.query.limit as string) || 50, 200); const offset = parseInt(req.query.offset as string) || 0; const status = req.query.status ? parseInt(req.query.status as string) : undefined; const search = (req.query.search as string || '').trim(); const days = req.query.days ? parseInt(req.query.days as string) : undefined; const conditions = [eq(errorLogs.organizationId, organizationId)]; if (status && !isNaN(status)) { if (status === 400) conditions.push(and(gte(errorLogs.statusCode, 400), sql`${errorLogs.statusCode} < 500`)!); else conditions.push(gte(errorLogs.statusCode, status)); } if (search) { conditions.push(or(ilike(errorLogs.path, `%${search}%`), ilike(errorLogs.message, `%${search}%`))!); } if (days && !isNaN(days) && days > 0) { conditions.push(gte(errorLogs.createdAt, new Date(Date.now() - days * 24 * 60 * 60 * 1000))); } const where = and(...conditions); const [rows, [{ count }]] = await Promise.all([ db.select({ id: errorLogs.id, method: errorLogs.method, path: errorLogs.path, statusCode: errorLogs.statusCode, message: errorLogs.message, createdAt: errorLogs.createdAt, userId: errorLogs.userId, userFirstName: users.firstName, userLastName: users.lastName, userEmail: users.email, }) .from(errorLogs) .leftJoin(users, eq(errorLogs.userId, users.id)) .where(where) .orderBy(desc(errorLogs.createdAt)) .limit(limit) .offset(offset), db.select({ count: sql`count(*)::int` }).from(errorLogs).where(where), ]); res.json({ success: true, logs: rows, total: count, limit, offset }); } catch (error) { console.error('Get error logs error:', error); res.status(500).json({ success: false, error: 'Ошибка при получении журнала ошибок' }); } }); // DELETE /api/error-logs — очистить журнал организации router.delete('/api/error-logs', authenticateToken, requireAppAdmin, async (req: AuthenticatedRequest, res) => { try { await db.delete(errorLogs).where(eq(errorLogs.organizationId, req.organizationId!)); res.json({ success: true }); } catch (error) { console.error('Clear error logs error:', error); res.status(500).json({ success: false, error: 'Ошибка при очистке журнала ошибок' }); } }); export default router;