310 lines
9.1 KiB
JavaScript
310 lines
9.1 KiB
JavaScript
const express = require('express');
|
|
const router = express.Router();
|
|
|
|
// Get all AI prompts
|
|
router.get('/', async (req, res) => {
|
|
try {
|
|
const pool = req.app.locals.pool;
|
|
if (!pool) {
|
|
throw new Error('Database pool not initialized');
|
|
}
|
|
|
|
const result = await pool.query(`
|
|
SELECT * FROM ai_prompts
|
|
ORDER BY prompt_type ASC, company ASC
|
|
`);
|
|
res.json(result.rows);
|
|
} catch (error) {
|
|
console.error('Error fetching AI prompts:', error);
|
|
res.status(500).json({
|
|
error: 'Failed to fetch AI prompts',
|
|
details: error instanceof Error ? error.message : 'Unknown error'
|
|
});
|
|
}
|
|
});
|
|
|
|
// Get prompt by ID
|
|
router.get('/:id', async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const pool = req.app.locals.pool;
|
|
if (!pool) {
|
|
throw new Error('Database pool not initialized');
|
|
}
|
|
|
|
const result = await pool.query(`
|
|
SELECT * FROM ai_prompts
|
|
WHERE id = $1
|
|
`, [id]);
|
|
|
|
if (result.rows.length === 0) {
|
|
return res.status(404).json({ error: 'AI prompt not found' });
|
|
}
|
|
|
|
res.json(result.rows[0]);
|
|
} catch (error) {
|
|
console.error('Error fetching AI prompt:', error);
|
|
res.status(500).json({
|
|
error: 'Failed to fetch AI prompt',
|
|
details: error instanceof Error ? error.message : 'Unknown error'
|
|
});
|
|
}
|
|
});
|
|
|
|
// Get prompt by type (any prompt_type value - extensible)
|
|
router.get('/by-type', async (req, res) => {
|
|
try {
|
|
const { type, company } = req.query;
|
|
const pool = req.app.locals.pool;
|
|
|
|
if (!pool) {
|
|
throw new Error('Database pool not initialized');
|
|
}
|
|
|
|
// Validate type is provided
|
|
if (!type || typeof type !== 'string' || type.trim().length === 0) {
|
|
return res.status(400).json({
|
|
error: 'Valid type query parameter is required'
|
|
});
|
|
}
|
|
|
|
// For company_specific types, company ID is required
|
|
const isCompanySpecificType = type.endsWith('_company_specific');
|
|
if (isCompanySpecificType && !company) {
|
|
return res.status(400).json({
|
|
error: 'Company ID is required for company_specific prompt types'
|
|
});
|
|
}
|
|
|
|
// For non-company-specific types, company should not be provided
|
|
if (!isCompanySpecificType && company) {
|
|
return res.status(400).json({
|
|
error: 'Company ID should not be provided for non-company-specific prompt types'
|
|
});
|
|
}
|
|
|
|
// Build the query based on whether company is provided
|
|
let query, params;
|
|
if (company) {
|
|
query = 'SELECT * FROM ai_prompts WHERE prompt_type = $1 AND company = $2';
|
|
params = [type.trim(), company];
|
|
} else {
|
|
query = 'SELECT * FROM ai_prompts WHERE prompt_type = $1 AND company IS NULL';
|
|
params = [type.trim()];
|
|
}
|
|
|
|
// Execute the query
|
|
const result = await pool.query(query, params);
|
|
|
|
// Check if any prompt was found
|
|
if (result.rows.length === 0) {
|
|
const errorMessage = company
|
|
? `AI prompt '${type}' not found for company ${company}`
|
|
: `AI prompt '${type}' not found`;
|
|
return res.status(404).json({ error: errorMessage });
|
|
}
|
|
|
|
// Return the first matching prompt
|
|
res.json(result.rows[0]);
|
|
} catch (error) {
|
|
console.error('Error fetching AI prompt by type:', error);
|
|
res.status(500).json({
|
|
error: 'Failed to fetch AI prompt',
|
|
details: error instanceof Error ? error.message : 'Unknown error'
|
|
});
|
|
}
|
|
});
|
|
|
|
// Create new AI prompt
|
|
router.post('/', async (req, res) => {
|
|
try {
|
|
const {
|
|
prompt_text,
|
|
prompt_type,
|
|
company
|
|
} = req.body;
|
|
|
|
// Validate required fields
|
|
if (!prompt_text || !prompt_type) {
|
|
return res.status(400).json({ error: 'Prompt text and type are required' });
|
|
}
|
|
|
|
// Validate prompt_type is a non-empty string (no hardcoded list - extensible)
|
|
if (typeof prompt_type !== 'string' || prompt_type.trim().length === 0) {
|
|
return res.status(400).json({ error: 'Prompt type must be a non-empty string' });
|
|
}
|
|
|
|
// For company-specific types (ending with _company_specific), require company
|
|
const isCompanySpecificType = prompt_type.endsWith('_company_specific');
|
|
if (isCompanySpecificType && !company) {
|
|
return res.status(400).json({ error: 'Company is required for company-specific prompt types' });
|
|
}
|
|
|
|
// For non-company-specific types, company should not be provided
|
|
if (!isCompanySpecificType && company) {
|
|
return res.status(400).json({ error: 'Company should not be provided for non-company-specific prompt types' });
|
|
}
|
|
|
|
const pool = req.app.locals.pool;
|
|
if (!pool) {
|
|
throw new Error('Database pool not initialized');
|
|
}
|
|
|
|
const result = await pool.query(`
|
|
INSERT INTO ai_prompts (
|
|
prompt_text,
|
|
prompt_type,
|
|
company
|
|
) VALUES ($1, $2, $3)
|
|
RETURNING *
|
|
`, [
|
|
prompt_text,
|
|
prompt_type.trim(),
|
|
company || null
|
|
]);
|
|
|
|
res.status(201).json(result.rows[0]);
|
|
} catch (error) {
|
|
console.error('Error creating AI prompt:', error);
|
|
|
|
// Check for unique constraint violations
|
|
if (error instanceof Error && error.message.includes('unique')) {
|
|
if (error.message.includes('idx_singleton_with_company')) {
|
|
return res.status(409).json({
|
|
error: 'A prompt of this type already exists for this company',
|
|
details: error.message
|
|
});
|
|
} else if (error.message.includes('idx_singleton_no_company')) {
|
|
return res.status(409).json({
|
|
error: 'A prompt of this type already exists',
|
|
details: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
res.status(500).json({
|
|
error: 'Failed to create AI prompt',
|
|
details: error instanceof Error ? error.message : 'Unknown error'
|
|
});
|
|
}
|
|
});
|
|
|
|
// Update AI prompt
|
|
router.put('/:id', async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const {
|
|
prompt_text,
|
|
prompt_type,
|
|
company
|
|
} = req.body;
|
|
|
|
// Validate required fields
|
|
if (!prompt_text || !prompt_type) {
|
|
return res.status(400).json({ error: 'Prompt text and type are required' });
|
|
}
|
|
|
|
// Validate prompt_type is a non-empty string (no hardcoded list - extensible)
|
|
if (typeof prompt_type !== 'string' || prompt_type.trim().length === 0) {
|
|
return res.status(400).json({ error: 'Prompt type must be a non-empty string' });
|
|
}
|
|
|
|
// For company-specific types, require company
|
|
const isCompanySpecificType = prompt_type.endsWith('_company_specific');
|
|
if (isCompanySpecificType && !company) {
|
|
return res.status(400).json({ error: 'Company is required for company-specific prompt types' });
|
|
}
|
|
|
|
// For non-company-specific types, company should not be provided
|
|
if (!isCompanySpecificType && company) {
|
|
return res.status(400).json({ error: 'Company should not be provided for non-company-specific prompt types' });
|
|
}
|
|
|
|
const pool = req.app.locals.pool;
|
|
if (!pool) {
|
|
throw new Error('Database pool not initialized');
|
|
}
|
|
|
|
// Check if the prompt exists
|
|
const checkResult = await pool.query('SELECT * FROM ai_prompts WHERE id = $1', [id]);
|
|
if (checkResult.rows.length === 0) {
|
|
return res.status(404).json({ error: 'AI prompt not found' });
|
|
}
|
|
|
|
const result = await pool.query(`
|
|
UPDATE ai_prompts
|
|
SET
|
|
prompt_text = $1,
|
|
prompt_type = $2,
|
|
company = $3,
|
|
updated_at = CURRENT_TIMESTAMP
|
|
WHERE id = $4
|
|
RETURNING *
|
|
`, [
|
|
prompt_text,
|
|
prompt_type.trim(),
|
|
company || null,
|
|
id
|
|
]);
|
|
|
|
res.json(result.rows[0]);
|
|
} catch (error) {
|
|
console.error('Error updating AI prompt:', error);
|
|
|
|
// Check for unique constraint violations
|
|
if (error instanceof Error && error.message.includes('unique')) {
|
|
if (error.message.includes('idx_singleton_with_company')) {
|
|
return res.status(409).json({
|
|
error: 'A prompt of this type already exists for this company',
|
|
details: error.message
|
|
});
|
|
} else if (error.message.includes('idx_singleton_no_company')) {
|
|
return res.status(409).json({
|
|
error: 'A prompt of this type already exists',
|
|
details: error.message
|
|
});
|
|
}
|
|
}
|
|
|
|
res.status(500).json({
|
|
error: 'Failed to update AI prompt',
|
|
details: error instanceof Error ? error.message : 'Unknown error'
|
|
});
|
|
}
|
|
});
|
|
|
|
// Delete AI prompt
|
|
router.delete('/:id', async (req, res) => {
|
|
try {
|
|
const { id } = req.params;
|
|
const pool = req.app.locals.pool;
|
|
if (!pool) {
|
|
throw new Error('Database pool not initialized');
|
|
}
|
|
|
|
const result = await pool.query('DELETE FROM ai_prompts WHERE id = $1 RETURNING *', [id]);
|
|
|
|
if (result.rows.length === 0) {
|
|
return res.status(404).json({ error: 'AI prompt not found' });
|
|
}
|
|
|
|
res.json({ message: 'AI prompt deleted successfully' });
|
|
} catch (error) {
|
|
console.error('Error deleting AI prompt:', error);
|
|
res.status(500).json({
|
|
error: 'Failed to delete AI prompt',
|
|
details: error instanceof Error ? error.message : 'Unknown error'
|
|
});
|
|
}
|
|
});
|
|
|
|
// Error handling middleware
|
|
router.use((err, req, res, next) => {
|
|
console.error('AI prompts route error:', err);
|
|
res.status(500).json({
|
|
error: 'Internal server error',
|
|
details: err.message
|
|
});
|
|
});
|
|
|
|
module.exports = router;
|