152 lines
4.6 KiB
JavaScript
152 lines
4.6 KiB
JavaScript
import { Router } from 'express';
|
|
import { authRequired } from '../middleware/authRequired.js';
|
|
import { csrfRequired } from '../middleware/csrfRequired.js';
|
|
import * as scenarioService from '../services/scenario.service.js';
|
|
|
|
const router = Router();
|
|
|
|
/**
|
|
* POST /api/scenario/:scenarioId/start
|
|
* Запуск сценария. body должен быть пустым {}.
|
|
*/
|
|
router.post('/:scenarioId/start', authRequired, csrfRequired, async (req, res, next) => {
|
|
try {
|
|
const { scenarioId } = req.params;
|
|
const input = req.body;
|
|
|
|
// 1) проверить, что пользователь имеет право на этот scenarioId
|
|
await scenarioService.assertUserCanStartScenario({
|
|
userId: req.user.id,
|
|
scenarioId,
|
|
});
|
|
|
|
// 2) создать generation и вызвать n8n
|
|
const generation = await scenarioService.startScenario({
|
|
userId: req.user.id,
|
|
scenarioId,
|
|
input,
|
|
user: req.user,
|
|
});
|
|
|
|
res.status(202).json({
|
|
ok: true,
|
|
generationUuid: generation.generationUuid,
|
|
status: generation.status,
|
|
currentStepId: generation.currentStepId,
|
|
});
|
|
} catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/scenario/:scenarioId/step/:stepId
|
|
* Выполнение шага сценария. body должен соответствовать input_schema из БД.
|
|
*/
|
|
router.post('/:scenarioId/step/:stepId', authRequired, csrfRequired, async (req, res, next) => {
|
|
try {
|
|
const { scenarioId, stepId } = req.params;
|
|
const input = req.body;
|
|
|
|
// 1) проверить, что пользователь может выполнять этот шаг
|
|
await scenarioService.assertUserCanExecuteStep({
|
|
userId: req.user.id,
|
|
scenarioId,
|
|
stepId,
|
|
});
|
|
|
|
// 2) выполнить шаг (с валидацией input_schema)
|
|
const result = await scenarioService.executeStep({
|
|
userId: req.user.id,
|
|
scenarioId,
|
|
stepId,
|
|
input,
|
|
user: req.user,
|
|
});
|
|
|
|
res.status(202).json({
|
|
ok: true,
|
|
generationUuid: result.generationUuid,
|
|
stepState: result.stepState,
|
|
nextStepId: result.nextStepId,
|
|
});
|
|
} catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
|
|
/**
|
|
* POST /api/scenario/:scenarioId/step/:stepId/record
|
|
* Создать запись generation_step и вернуть её ID (для загрузки файлов).
|
|
* Используется когда нужно загрузить файл ДО выполнения шага.
|
|
*/
|
|
router.post('/:scenarioId/step/:stepId/record', authRequired, csrfRequired, async (req, res, next) => {
|
|
try {
|
|
const { scenarioId, stepId } = req.params;
|
|
const input = req.body;
|
|
const userId = req.user.id;
|
|
|
|
// Проверка прав
|
|
await scenarioService.assertUserCanExecuteStep({
|
|
userId,
|
|
scenarioId,
|
|
stepId,
|
|
});
|
|
|
|
// Найти активную generation
|
|
const { pool } = await import('../db.js');
|
|
const genQuery = `
|
|
SELECT generation_uuid, current_step_id, status
|
|
FROM uno_bff.generations
|
|
WHERE user_id = $1 AND scenario_id = $2 AND status IN ('running', 'waiting_for_input')
|
|
ORDER BY created_at DESC
|
|
LIMIT 1
|
|
`;
|
|
const genResult = await pool.query(genQuery, [userId, scenarioId]);
|
|
const generation = genResult.rows[0];
|
|
|
|
if (!generation) {
|
|
return res.status(400).json({
|
|
ok: false,
|
|
error: 'GENERATION_NOT_FOUND',
|
|
message: `No active generation found for scenario '${scenarioId}'`,
|
|
});
|
|
}
|
|
|
|
// Найти шаг сценария для получения step_order
|
|
const step = await scenarioService.getScenarioStep(scenarioId, stepId);
|
|
if (!step) {
|
|
return res.status(404).json({
|
|
ok: false,
|
|
error: 'STEP_NOT_FOUND',
|
|
message: `Step '${stepId}' not found`,
|
|
});
|
|
}
|
|
|
|
// Создать/обновить запись generation_step
|
|
const stepQuery = `
|
|
INSERT INTO uno_bff.generation_steps (generation_uuid, scenario_id, step_id, step_order, status, request_payload)
|
|
VALUES ($1, $2, $3, $4, 'running', $5)
|
|
ON CONFLICT (generation_uuid, step_id) DO UPDATE
|
|
SET status = 'running', request_payload = $5, updated_at = now()
|
|
RETURNING id
|
|
`;
|
|
const stepResult = await pool.query(stepQuery, [
|
|
generation.generation_uuid,
|
|
scenarioId,
|
|
stepId,
|
|
step.step_order,
|
|
JSON.stringify(input),
|
|
]);
|
|
|
|
res.status(201).json({
|
|
ok: true,
|
|
stepRecordId: stepResult.rows[0].id,
|
|
generationUuid: generation.generation_uuid,
|
|
});
|
|
} catch (err) {
|
|
next(err);
|
|
}
|
|
});
|
|
|
|
export default router; |