import { Response } from 'express'; import { query } from '../utils/db'; import { AuthRequest } from '../middleware/auth'; import n8nService from '../services/n8nService'; export const getWorkflows = async (req: AuthRequest, res: Response) => { try { // Get workflows from n8n const n8nWorkflows = await n8nService.getWorkflows(); // Get local workflow metadata const localResult = await query( `SELECT id, name, n8n_workflow_id, description, status, trigger_type, is_active, created_at, updated_at FROM workflows WHERE user_id = $1 ORDER BY created_at DESC`, [req.user?.id] ); // Merge n8n data with local metadata const workflows = localResult.rows.map(localWorkflow => { const n8nWorkflow = n8nWorkflows.find(w => w.id === localWorkflow.n8n_workflow_id); return { ...localWorkflow, n8n_data: n8nWorkflow, active: n8nWorkflow?.active || false, status: n8nWorkflow?.active ? 'active' : 'inactive' }; }); res.json({ success: true, workflows, total_n8n_workflows: n8nWorkflows.length }); } catch (error) { console.error('Get workflows error:', error); res.status(500).json({ success: false, message: 'Failed to fetch workflows' }); } }; export const getWorkflow = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; // Get local workflow const localResult = await query( `SELECT * FROM workflows WHERE id = $1 AND user_id = $2`, [id, req.user?.id] ); if (localResult.rows.length === 0) { return res.status(404).json({ success: false, message: 'Workflow not found' }); } const localWorkflow = localResult.rows[0]; // Get n8n workflow if exists let n8nWorkflow = null; if (localWorkflow.n8n_workflow_id) { try { n8nWorkflow = await n8nService.getWorkflow(localWorkflow.n8n_workflow_id); } catch (error) { console.error('Failed to fetch n8n workflow:', error); } } res.json({ success: true, workflow: { ...localWorkflow, n8n_data: n8nWorkflow } }); } catch (error) { console.error('Get workflow error:', error); res.status(500).json({ success: false, message: 'Internal server error' }); } }; export const createWorkflow = async (req: AuthRequest, res: Response) => { try { const { name, description, trigger_type, trigger_config, actions_config, n8n_workflow_data } = req.body; if (!name) { return res.status(400).json({ success: false, message: 'Name is required' }); } let n8nWorkflowId = null; // Create workflow in n8n if workflow data provided if (n8n_workflow_data) { try { const n8nWorkflow = await n8nService.createWorkflow({ name, active: false, nodes: n8n_workflow_data.nodes || [], connections: n8n_workflow_data.connections || {}, settings: n8n_workflow_data.settings, staticData: n8n_workflow_data.staticData }); n8nWorkflowId = n8nWorkflow.id; } catch (error) { console.error('Failed to create n8n workflow:', error); return res.status(500).json({ success: false, message: 'Failed to create workflow in n8n' }); } } // Save to local database const result = await query( `INSERT INTO workflows (user_id, name, description, trigger_type, trigger_config, actions_config, n8n_workflow_id) VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING id, name, description, status, trigger_type, is_active, created_at`, [req.user?.id, name, description, trigger_type, trigger_config, actions_config, n8nWorkflowId] ); res.status(201).json({ success: true, workflow: { ...result.rows[0], n8n_workflow_id: n8nWorkflowId } }); } catch (error) { console.error('Create workflow error:', error); res.status(500).json({ success: false, message: 'Internal server error' }); } }; export const updateWorkflow = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; const { name, description, trigger_type, trigger_config, actions_config, n8n_workflow_data } = req.body; // Get existing workflow const existingResult = await query( `SELECT * FROM workflows WHERE id = $1 AND user_id = $2`, [id, req.user?.id] ); if (existingResult.rows.length === 0) { return res.status(404).json({ success: false, message: 'Workflow not found' }); } const existingWorkflow = existingResult.rows[0]; // Update n8n workflow if exists if (existingWorkflow.n8n_workflow_id && n8n_workflow_data) { try { await n8nService.updateWorkflow(existingWorkflow.n8n_workflow_id, { name, nodes: n8n_workflow_data.nodes, connections: n8n_workflow_data.connections, settings: n8n_workflow_data.settings, staticData: n8n_workflow_data.staticData }); } catch (error) { console.error('Failed to update n8n workflow:', error); return res.status(500).json({ success: false, message: 'Failed to update workflow in n8n' }); } } // Update local database const result = await query( `UPDATE workflows SET name = $1, description = $2, trigger_type = $3, trigger_config = $4, actions_config = $5, updated_at = CURRENT_TIMESTAMP WHERE id = $6 AND user_id = $7 RETURNING id, name, description, status, trigger_type, is_active, created_at, updated_at`, [name, description, trigger_type, trigger_config, actions_config, id, req.user?.id] ); res.json({ success: true, workflow: result.rows[0] }); } catch (error) { console.error('Update workflow error:', error); res.status(500).json({ success: false, message: 'Internal server error' }); } }; export const activateWorkflow = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; // Get workflow const workflowResult = await query( `SELECT * FROM workflows WHERE id = $1 AND user_id = $2`, [id, req.user?.id] ); if (workflowResult.rows.length === 0) { return res.status(404).json({ success: false, message: 'Workflow not found' }); } const workflow = workflowResult.rows[0]; // Activate in n8n if (workflow.n8n_workflow_id) { try { await n8nService.activateWorkflow(workflow.n8n_workflow_id); } catch (error) { console.error('Failed to activate n8n workflow:', error); return res.status(500).json({ success: false, message: 'Failed to activate workflow in n8n' }); } } // Update local status await query( `UPDATE workflows SET is_active = true, status = 'active', updated_at = CURRENT_TIMESTAMP WHERE id = $1 AND user_id = $2`, [id, req.user?.id] ); res.json({ success: true, message: 'Workflow activated successfully' }); } catch (error) { console.error('Activate workflow error:', error); res.status(500).json({ success: false, message: 'Internal server error' }); } }; export const deactivateWorkflow = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; // Get workflow const workflowResult = await query( `SELECT * FROM workflows WHERE id = $1 AND user_id = $2`, [id, req.user?.id] ); if (workflowResult.rows.length === 0) { return res.status(404).json({ success: false, message: 'Workflow not found' }); } const workflow = workflowResult.rows[0]; // Deactivate in n8n if (workflow.n8n_workflow_id) { try { await n8nService.deactivateWorkflow(workflow.n8n_workflow_id); } catch (error) { console.error('Failed to deactivate n8n workflow:', error); return res.status(500).json({ success: false, message: 'Failed to deactivate workflow in n8n' }); } } // Update local status await query( `UPDATE workflows SET is_active = false, status = 'inactive', updated_at = CURRENT_TIMESTAMP WHERE id = $1 AND user_id = $2`, [id, req.user?.id] ); res.json({ success: true, message: 'Workflow deactivated successfully' }); } catch (error) { console.error('Deactivate workflow error:', error); res.status(500).json({ success: false, message: 'Internal server error' }); } }; export const executeWorkflow = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; const { inputData } = req.body; // Get workflow const workflowResult = await query( `SELECT * FROM workflows WHERE id = $1 AND user_id = $2`, [id, req.user?.id] ); if (workflowResult.rows.length === 0) { return res.status(404).json({ success: false, message: 'Workflow not found' }); } const workflow = workflowResult.rows[0]; if (!workflow.n8n_workflow_id) { return res.status(400).json({ success: false, message: 'Workflow is not connected to n8n' }); } // Execute in n8n try { const execution = await n8nService.executeWorkflow(workflow.n8n_workflow_id, inputData); // Log execution in database await query( `INSERT INTO workflow_executions (workflow_id, user_id, n8n_execution_id, status, trigger_data, started_at) VALUES ($1, $2, $3, $4, $5, $6)`, [id, req.user?.id, execution.id, execution.finished ? 'completed' : 'running', inputData, new Date()] ); res.json({ success: true, execution }); } catch (error) { console.error('Failed to execute workflow:', error); res.status(500).json({ success: false, message: 'Failed to execute workflow' }); } } catch (error) { console.error('Execute workflow error:', error); res.status(500).json({ success: false, message: 'Internal server error' }); } }; export const deleteWorkflow = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; // Get workflow const workflowResult = await query( `SELECT * FROM workflows WHERE id = $1 AND user_id = $2`, [id, req.user?.id] ); if (workflowResult.rows.length === 0) { return res.status(404).json({ success: false, message: 'Workflow not found' }); } const workflow = workflowResult.rows[0]; // Delete from n8n first if (workflow.n8n_workflow_id) { try { await n8nService.deleteWorkflow(workflow.n8n_workflow_id); } catch (error) { console.error('Failed to delete n8n workflow:', error); // Continue with local deletion even if n8n deletion fails } } // Delete from local database await query( 'DELETE FROM workflows WHERE id = $1 AND user_id = $2', [id, req.user?.id] ); res.json({ success: true, message: 'Workflow deleted successfully' }); } catch (error) { console.error('Delete workflow error:', error); res.status(500).json({ success: false, message: 'Internal server error' }); } }; export const getWorkflowExecutions = async (req: AuthRequest, res: Response) => { try { const { id } = req.params; const limit = parseInt(req.query.limit as string) || 20; // Get workflow const workflowResult = await query( `SELECT * FROM workflows WHERE id = $1 AND user_id = $2`, [id, req.user?.id] ); if (workflowResult.rows.length === 0) { return res.status(404).json({ success: false, message: 'Workflow not found' }); } const workflow = workflowResult.rows[0]; if (!workflow.n8n_workflow_id) { return res.status(400).json({ success: false, message: 'Workflow is not connected to n8n' }); } // Get executions from n8n const executions = await n8nService.getExecutions(workflow.n8n_workflow_id, limit); res.json({ success: true, executions }); } catch (error) { console.error('Get workflow executions error:', error); res.status(500).json({ success: false, message: 'Internal server error' }); } };