import { Response } from 'express'; import { AuthRequest } from '../middleware/auth'; import { mainPool } from '../config/database'; import { v4 as uuidv4 } from 'uuid'; export const getEndpoints = async (req: AuthRequest, res: Response) => { try { const { search, folder_id } = req.query; let query = ` SELECT e.*, f.name as folder_name FROM endpoints e LEFT JOIN folders f ON e.folder_id = f.id WHERE 1=1 `; const params: any[] = []; if (folder_id) { query += ` AND e.folder_id = $${params.length + 1}`; params.push(folder_id); } if (search) { const searchIndex = params.length + 1; query += ` AND ( e.name ILIKE $${searchIndex} OR e.description ILIKE $${searchIndex} OR e.sql_query ILIKE $${searchIndex} OR e.path ILIKE $${searchIndex} )`; params.push(`%${search}%`); } query += ` ORDER BY e.created_at DESC`; const result = await mainPool.query(query, params); res.json(result.rows); } catch (error) { console.error('Get endpoints error:', error); res.status(500).json({ error: 'Internal server error' }); } }; export const getEndpoint = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; const result = await mainPool.query( `SELECT e.*, f.name as folder_name FROM endpoints e LEFT JOIN folders f ON e.folder_id = f.id WHERE e.id = $1`, [id] ); if (result.rows.length === 0) { return res.status(404).json({ error: 'Endpoint not found' }); } res.json(result.rows[0]); } catch (error) { console.error('Get endpoint error:', error); res.status(500).json({ error: 'Internal server error' }); } }; export const createEndpoint = async (req: AuthRequest, res: Response) => { try { const { name, description, method, path, database_id, sql_query, parameters, folder_id, is_public, enable_logging, execution_type, script_language, script_code, script_queries, } = req.body; if (!name || !method || !path) { return res.status(400).json({ error: 'Missing required fields' }); } const execType = execution_type || 'sql'; // Валидация для типа SQL if (execType === 'sql') { if (!database_id || !sql_query) { return res.status(400).json({ error: 'Database ID and SQL query are required for SQL execution type' }); } } // Валидация для типа Script if (execType === 'script') { if (!script_language || !script_code || !script_queries) { return res.status(400).json({ error: 'Script language, code, and queries are required for script execution type' }); } } const result = await mainPool.query( `INSERT INTO endpoints ( name, description, method, path, database_id, sql_query, parameters, folder_id, user_id, is_public, enable_logging, execution_type, script_language, script_code, script_queries ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15) RETURNING *`, [ name, description || '', method, path, database_id || null, sql_query || '', JSON.stringify(parameters || []), folder_id || null, req.user!.id, is_public || false, enable_logging || false, execType, script_language || null, script_code || null, JSON.stringify(script_queries || []), ] ); res.status(201).json(result.rows[0]); } catch (error: any) { console.error('Create endpoint error:', error); if (error.code === '23505') { return res.status(400).json({ error: 'Endpoint path already exists' }); } res.status(500).json({ error: 'Internal server error' }); } }; export const updateEndpoint = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; const { name, description, method, path, database_id, sql_query, parameters, folder_id, is_public, enable_logging, execution_type, script_language, script_code, script_queries, } = req.body; const result = await mainPool.query( `UPDATE endpoints SET name = $1, description = $2, method = $3, path = $4, database_id = $5, sql_query = $6, parameters = $7, folder_id = $8, is_public = $9, enable_logging = $10, execution_type = $11, script_language = $12, script_code = $13, script_queries = $14, updated_at = CURRENT_TIMESTAMP WHERE id = $15 RETURNING *`, [ name, description, method, path, database_id || null, sql_query, parameters ? JSON.stringify(parameters) : null, folder_id || null, is_public, enable_logging, execution_type, script_language || null, script_code || null, script_queries ? JSON.stringify(script_queries) : null, id, ] ); if (result.rows.length === 0) { return res.status(404).json({ error: 'Endpoint not found' }); } res.json(result.rows[0]); } catch (error: any) { console.error('Update endpoint error:', error); if (error.code === '23505') { return res.status(400).json({ error: 'Endpoint path already exists' }); } res.status(500).json({ error: 'Internal server error' }); } }; export const deleteEndpoint = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; const result = await mainPool.query( 'DELETE FROM endpoints WHERE id = $1 RETURNING id', [id] ); if (result.rows.length === 0) { return res.status(404).json({ error: 'Endpoint not found' }); } res.json({ message: 'Endpoint deleted successfully' }); } catch (error) { console.error('Delete endpoint error:', error); res.status(500).json({ error: 'Internal server error' }); } }; export const testEndpoint = async (req: AuthRequest, res: Response) => { try { const { database_id, sql_query, parameters, endpoint_parameters, execution_type, script_language, script_code, script_queries } = req.body; const execType = execution_type || 'sql'; if (execType === 'sql') { if (!database_id) { return res.status(400).json({ error: 'Missing database_id for SQL execution' }); } if (!sql_query) { return res.status(400).json({ error: 'Missing sql_query' }); } // Преобразуем именованные параметры ($paramName) в позиционные ($1, $2, $3...) let processedQuery = sql_query; if (endpoint_parameters && Array.isArray(endpoint_parameters)) { endpoint_parameters.forEach((param: any, index: number) => { const paramName = param.name; const position = index + 1; // Заменяем все вхождения $paramName на $position const regex = new RegExp(`\\$${paramName}\\b`, 'g'); processedQuery = processedQuery.replace(regex, `$${position}`); }); } const { sqlExecutor } = require('../services/SqlExecutor'); const result = await sqlExecutor.executeQuery(database_id, processedQuery, parameters || []); res.json({ success: true, data: result.rows, rowCount: result.rowCount, executionTime: result.executionTime, }); } else if (execType === 'script') { if (!script_language || !script_code) { return res.status(400).json({ error: 'Missing script_language or script_code' }); } // Собираем параметры из тестовых значений const requestParams: Record = {}; if (endpoint_parameters && Array.isArray(endpoint_parameters) && parameters && Array.isArray(parameters)) { endpoint_parameters.forEach((param: any, index: number) => { requestParams[param.name] = parameters[index]; }); } const { scriptExecutor } = require('../services/scriptExecutor'); const scriptResult = await scriptExecutor.execute(script_language, script_code, { databaseId: database_id, scriptQueries: script_queries || [], requestParams, endpointParameters: endpoint_parameters || [], }); res.json({ success: true, data: scriptResult.data || scriptResult, rowCount: scriptResult.rowCount || (Array.isArray(scriptResult.data) ? scriptResult.data.length : 0), executionTime: scriptResult.executionTime || 0, }); } else { return res.status(400).json({ error: 'Invalid execution_type' }); } } catch (error: any) { res.status(400).json({ success: false, error: error.message, }); } };