new file: .claude/settings.local.json
new file: .gitignore new file: backend/.env.example new file: backend/.gitignore new file: backend/ecosystem.config.js new file: backend/nodemon.json new file: backend/package-lock.json new file: backend/package.json new file: backend/src/config/database.ts new file: backend/src/config/dynamicSwagger.ts new file: backend/src/config/environment.ts new file: backend/src/config/swagger.ts new file: backend/src/controllers/apiKeyController.ts new file: backend/src/controllers/authController.ts new file: backend/src/controllers/databaseController.ts new file: backend/src/controllers/databaseManagementController.ts new file: backend/src/controllers/dynamicApiController.ts new file: backend/src/controllers/endpointController.ts new file: backend/src/controllers/folderController.ts new file: backend/src/controllers/logsController.ts new file: backend/src/controllers/userController.ts new file: backend/src/middleware/apiKey.ts new file: backend/src/middleware/auth.ts new file: backend/src/middleware/logging.ts new file: backend/src/migrations/001_initial_schema.sql new file: backend/src/migrations/002_add_logging.sql new file: backend/src/migrations/003_add_scripting.sql new file: backend/src/migrations/004_add_superadmin.sql new file: backend/src/migrations/run.ts new file: backend/src/migrations/seed.ts new file: backend/src/routes/apiKeys.ts new file: backend/src/routes/auth.ts new file: backend/src/routes/databaseManagement.ts new file: backend/src/routes/databases.ts new file: backend/src/routes/dynamic.ts new file: backend/src/routes/endpoints.ts new file: backend/src/routes/folders.ts new file: backend/src/routes/logs.ts new file: backend/src/routes/users.ts new file: backend/src/server.ts new file: backend/src/services/DatabasePoolManager.ts new file: backend/src/services/ScriptExecutor.ts new file: backend/src/services/SqlExecutor.ts new file: backend/src/types/index.ts new file: backend/tsconfig.json new file: frontend/.gitignore new file: frontend/index.html new file: frontend/nginx.conf new file: frontend/package-lock.json new file: frontend/package.json new file: frontend/postcss.config.js new file: frontend/src/App.tsx new file: frontend/src/components/CodeEditor.tsx
This commit is contained in:
185
backend/src/controllers/databaseManagementController.ts
Normal file
185
backend/src/controllers/databaseManagementController.ts
Normal file
@@ -0,0 +1,185 @@
|
||||
import { Response } from 'express';
|
||||
import { AuthRequest } from '../middleware/auth';
|
||||
import { mainPool } from '../config/database';
|
||||
import { databasePoolManager } from '../services/DatabasePoolManager';
|
||||
|
||||
// Только админы могут управлять базами данных
|
||||
export const getDatabases = async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const result = await mainPool.query(
|
||||
'SELECT id, name, type, host, port, database_name, username, ssl, is_active, created_at, updated_at FROM databases ORDER BY name'
|
||||
);
|
||||
|
||||
res.json(result.rows);
|
||||
} catch (error) {
|
||||
console.error('Get databases error:', error);
|
||||
res.status(500).json({ error: 'Ошибка получения списка баз данных' });
|
||||
}
|
||||
};
|
||||
|
||||
export const getDatabase = async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const result = await mainPool.query(
|
||||
'SELECT id, name, type, host, port, database_name, username, ssl, is_active, created_at, updated_at FROM databases WHERE id = $1',
|
||||
[id]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return res.status(404).json({ error: 'База данных не найдена' });
|
||||
}
|
||||
|
||||
res.json(result.rows[0]);
|
||||
} catch (error) {
|
||||
console.error('Get database error:', error);
|
||||
res.status(500).json({ error: 'Ошибка получения базы данных' });
|
||||
}
|
||||
};
|
||||
|
||||
export const createDatabase = async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const { name, type, host, port, database_name, username, password, ssl } = req.body;
|
||||
|
||||
if (!name || !host || !port || !database_name || !username || !password) {
|
||||
return res.status(400).json({ error: 'Не заполнены обязательные поля' });
|
||||
}
|
||||
|
||||
const result = await mainPool.query(
|
||||
`INSERT INTO databases (name, type, host, port, database_name, username, password, ssl, is_active)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, true)
|
||||
RETURNING *`,
|
||||
[name, type || 'postgresql', host, port, database_name, username, password, ssl || false]
|
||||
);
|
||||
|
||||
const newDb = result.rows[0];
|
||||
|
||||
// Добавить пул подключений
|
||||
await databasePoolManager.reloadPool(newDb.id);
|
||||
|
||||
// Не возвращаем пароль
|
||||
delete newDb.password;
|
||||
|
||||
res.status(201).json(newDb);
|
||||
} catch (error: any) {
|
||||
console.error('Create database error:', error);
|
||||
if (error.code === '23505') {
|
||||
return res.status(400).json({ error: 'База данных с таким именем уже существует' });
|
||||
}
|
||||
res.status(500).json({ error: 'Ошибка создания базы данных' });
|
||||
}
|
||||
};
|
||||
|
||||
export const updateDatabase = async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
const { name, type, host, port, database_name, username, password, ssl, is_active } = req.body;
|
||||
|
||||
// Если пароль не передан, не обновляем его
|
||||
let query;
|
||||
let params;
|
||||
|
||||
if (password) {
|
||||
query = `
|
||||
UPDATE databases
|
||||
SET name = COALESCE($1, name),
|
||||
type = COALESCE($2, type),
|
||||
host = COALESCE($3, host),
|
||||
port = COALESCE($4, port),
|
||||
database_name = COALESCE($5, database_name),
|
||||
username = COALESCE($6, username),
|
||||
password = $7,
|
||||
ssl = COALESCE($8, ssl),
|
||||
is_active = COALESCE($9, is_active),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $10
|
||||
RETURNING id, name, type, host, port, database_name, username, ssl, is_active, created_at, updated_at
|
||||
`;
|
||||
params = [name, type, host, port, database_name, username, password, ssl, is_active, id];
|
||||
} else {
|
||||
query = `
|
||||
UPDATE databases
|
||||
SET name = COALESCE($1, name),
|
||||
type = COALESCE($2, type),
|
||||
host = COALESCE($3, host),
|
||||
port = COALESCE($4, port),
|
||||
database_name = COALESCE($5, database_name),
|
||||
username = COALESCE($6, username),
|
||||
ssl = COALESCE($7, ssl),
|
||||
is_active = COALESCE($8, is_active),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $9
|
||||
RETURNING id, name, type, host, port, database_name, username, ssl, is_active, created_at, updated_at
|
||||
`;
|
||||
params = [name, type, host, port, database_name, username, ssl, is_active, id];
|
||||
}
|
||||
|
||||
const result = await mainPool.query(query, params);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return res.status(404).json({ error: 'База данных не найдена' });
|
||||
}
|
||||
|
||||
// Перезагрузить пул
|
||||
await databasePoolManager.reloadPool(id);
|
||||
|
||||
res.json(result.rows[0]);
|
||||
} catch (error: any) {
|
||||
console.error('Update database error:', error);
|
||||
if (error.code === '23505') {
|
||||
return res.status(400).json({ error: 'База данных с таким именем уже существует' });
|
||||
}
|
||||
res.status(500).json({ error: 'Ошибка обновления базы данных' });
|
||||
}
|
||||
};
|
||||
|
||||
export const deleteDatabase = async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
// Проверяем, используется ли база данных в эндпоинтах
|
||||
const endpointCheck = await mainPool.query(
|
||||
'SELECT COUNT(*) FROM endpoints WHERE database_id = $1',
|
||||
[id]
|
||||
);
|
||||
|
||||
if (parseInt(endpointCheck.rows[0].count) > 0) {
|
||||
return res.status(400).json({
|
||||
error: 'Невозможно удалить базу данных, используемую в эндпоинтах'
|
||||
});
|
||||
}
|
||||
|
||||
const result = await mainPool.query(
|
||||
'DELETE FROM databases WHERE id = $1 RETURNING id',
|
||||
[id]
|
||||
);
|
||||
|
||||
if (result.rows.length === 0) {
|
||||
return res.status(404).json({ error: 'База данных не найдена' });
|
||||
}
|
||||
|
||||
// Удалить пул
|
||||
databasePoolManager.removePool(id);
|
||||
|
||||
res.json({ message: 'База данных удалена успешно' });
|
||||
} catch (error) {
|
||||
console.error('Delete database error:', error);
|
||||
res.status(500).json({ error: 'Ошибка удаления базы данных' });
|
||||
}
|
||||
};
|
||||
|
||||
export const testDatabaseConnection = async (req: AuthRequest, res: Response) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const isConnected = await databasePoolManager.testConnection(id);
|
||||
|
||||
res.json({
|
||||
success: isConnected,
|
||||
message: isConnected ? 'Подключение успешно' : 'Ошибка подключения',
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Test connection error:', error);
|
||||
res.status(500).json({ error: 'Ошибка тестирования подключения' });
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user