SaaS/backend/src/controllers/templateController.ts
Aimpress Team bda23a773f 🚀 Initial commit: Aimpress AutomationHub
 Features:
- Modern SaaS automation platform
- Next.js 15 + TypeScript frontend
- Node.js + Express backend
- PostgreSQL database with full schema
- Docker Compose setup
- Admin panel with analytics
- Template marketplace (6 templates)
- Integrations hub (10+ services)
- Authentication & role-based access
- Responsive n8n-style design

🎯 Ready for demo and deployment

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-09-28 21:58:33 +01:00

198 lines
No EOL
6.3 KiB
TypeScript

import { Request, Response } from 'express';
import { pool } from '../db/connection';
import { AuthRequest } from '../middleware/auth';
import { n8nService } from '../services/n8nService';
export const getTemplates = async (req: AuthRequest, res: Response) => {
try {
const { category, search } = req.query;
const userRole = req.user?.role || 'free';
// Build query for local templates
let queryText = `
SELECT id, name, description, category, trigger_type, tags, is_featured, install_count, created_at
FROM templates WHERE 1=1
`;
const params: any[] = [];
let paramCount = 0;
if (category) {
paramCount++;
queryText += ` AND category = $${paramCount}`;
params.push(category);
}
if (search) {
paramCount++;
queryText += ` AND (name ILIKE $${paramCount} OR description ILIKE $${paramCount})`;
params.push(`%${search}%`);
}
queryText += ' ORDER BY is_featured DESC, install_count DESC, created_at DESC';
// Get local templates
const localResult = await pool.query(queryText, params);
let templates = localResult.rows.map(template => ({
...template,
source: 'local'
}));
// For admin users, also fetch templates from n8n
if (userRole === 'admin') {
try {
const n8nWorkflows = await n8nService.getWorkflows();
const n8nTemplates = n8nWorkflows.map(workflow => ({
id: `n8n_${workflow.id}`,
name: workflow.name,
description: `N8n workflow: ${workflow.name}`,
category: 'n8n',
trigger_type: 'n8n_workflow',
tags: ['n8n', 'automation'],
is_featured: false,
install_count: 0,
created_at: workflow.createdAt,
source: 'n8n',
n8n_workflow_id: workflow.id,
n8n_data: workflow
}));
// Filter n8n templates if search is provided
if (search) {
const searchTerm = search.toString().toLowerCase();
const filteredN8nTemplates = n8nTemplates.filter(template =>
template.name.toLowerCase().includes(searchTerm) ||
template.description.toLowerCase().includes(searchTerm)
);
templates = [...templates, ...filteredN8nTemplates];
} else {
templates = [...templates, ...n8nTemplates];
}
} catch (n8nError) {
console.error('Error fetching n8n workflows:', n8nError);
// Continue with local templates only
}
}
res.json({
success: true,
templates: templates
});
} catch (error) {
console.error('Get templates error:', error);
res.status(500).json({
success: false,
message: 'Internal server error'
});
}
};
export const installTemplate = async (req: AuthRequest, res: Response) => {
try {
const { id } = req.params;
const { workflow_name } = req.body;
// Check if it's an n8n template
if (id.startsWith('n8n_')) {
const n8nWorkflowId = id.replace('n8n_', '');
try {
// Get the n8n workflow
const n8nWorkflow = await n8nService.getWorkflow(n8nWorkflowId);
// Create workflow in our database that references the n8n workflow
const workflowResult = await pool.query(
`INSERT INTO workflows (user_id, name, description, trigger_type, n8n_workflow_id, status, is_active)
VALUES ($1, $2, $3, $4, $5, $6, $7)
RETURNING id`,
[
req.user?.id,
workflow_name || n8nWorkflow.name,
`N8n workflow: ${n8nWorkflow.name}`,
'n8n_workflow',
n8nWorkflowId,
'connected',
n8nWorkflow.active
]
);
const workflowId = workflowResult.rows[0].id;
res.status(201).json({
success: true,
message: 'N8n workflow connected successfully',
workflow_id: workflowId,
n8n_workflow_id: n8nWorkflowId
});
} catch (n8nError) {
console.error('Error connecting n8n workflow:', n8nError);
return res.status(500).json({
success: false,
message: 'Failed to connect n8n workflow'
});
}
} else {
// Handle local template installation
const template = await pool.query('SELECT * FROM templates WHERE id = $1', [id]);
if (template.rows.length === 0) {
return res.status(404).json({
success: false,
message: 'Template not found'
});
}
const templateData = template.rows[0];
const workflowName = workflow_name || templateData.name;
// Check user's workflow limit
const userQuery = await pool.query('SELECT workflow_limit FROM users WHERE id = $1', [req.user?.id]);
const userWorkflowLimit = userQuery.rows[0]?.workflow_limit || 3;
const currentWorkflowsQuery = await pool.query(
'SELECT COUNT(*) as count FROM workflows WHERE user_id = $1',
[req.user?.id]
);
const currentWorkflowCount = parseInt(currentWorkflowsQuery.rows[0].count);
if (userWorkflowLimit !== -1 && currentWorkflowCount >= userWorkflowLimit) {
return res.status(403).json({
success: false,
message: 'Workflow limit reached. Please upgrade your plan to create more workflows.'
});
}
const workflowResult = await pool.query(
`INSERT INTO workflows (user_id, name, description, trigger_type, trigger_config, actions_config)
VALUES ($1, $2, $3, $4, $5, $6)
RETURNING id`,
[req.user?.id, workflowName, templateData.description, templateData.trigger_type,
templateData.trigger_config, templateData.actions_config]
);
const workflowId = workflowResult.rows[0].id;
await pool.query(
'INSERT INTO user_templates (user_id, template_id, workflow_id) VALUES ($1, $2, $3)',
[req.user?.id, id, workflowId]
);
await pool.query(
'UPDATE templates SET install_count = install_count + 1 WHERE id = $1',
[id]
);
res.status(201).json({
success: true,
message: 'Template installed successfully',
workflow_id: workflowId
});
}
} catch (error) {
console.error('Install template error:', error);
res.status(500).json({
success: false,
message: 'Internal server error'
});
}
};