godcrm/backend/routes/service.js
GOD CRM Release f89e074dd1
Some checks failed
CI / Lint / Typecheck / Test / Build (push) Has been cancelled
CI / PostgreSQL Integration Tests (push) Has been cancelled
GOD CRM — public scrubbed snapshot
Governed substrate for autonomous agents: scoped identity (passports),
audited actions, MCP workspace. Infra IPs and secrets redacted for public release.
2026-08-10 04:01:45 +03:00

141 lines
4.7 KiB
JavaScript

import { logger, apiLogger } from '../utils/logger.js';
import express from 'express';
import { dbRun, dbGet, dbAll } from '../database/init.js';
import { authenticate } from '../middleware/auth.js';
import { encrypt, decrypt } from '../utils/crypto.js';
import { success, error, badRequest, notFound } from '../utils/response.js';
const router = express.Router();
// Get all services
router.get('/', authenticate, async (req, res) => {
try {
const { businessId } = req.query;
let query = `
SELECT s.*, e.name as assigned_name, b.name as business_name
FROM services s
LEFT JOIN employees e ON s.assigned_to = e.id
JOIN businesses b ON s.business_id = b.id
WHERE b.owner_id = ?
`;
const params = [req.user.id];
if (businessId) {
query += ' AND s.business_id = ?';
params.push(businessId);
}
query += ' ORDER BY s.created_at DESC';
const services = await dbAll(query, params);
// Decrypt sensitive data
const decrypted = services.map(s => ({
...s,
login: s.login_encrypted ? decrypt(s.login_encrypted) : null,
password: s.password_encrypted ? decrypt(s.password_encrypted) : null,
api_key: s.api_key_encrypted ? decrypt(s.api_key_encrypted) : null,
notes: s.notes_encrypted ? decrypt(s.notes_encrypted) : null
}));
success(res, decrypted);
} catch (err) {
error(res, err.message);
}
});
// Create service
router.post('/', authenticate, async (req, res) => {
try {
const { businessId, name, description, url, type, status, price, login, password, apiKey, notes, assignedTo } = req.body;
logger.info('📝 Create service request:', { businessId, name, status, hasLogin: !!login, hasPassword: !!password });
if (!businessId || !name) {
return badRequest(res, 'Business ID and name are required');
}
const result = await dbRun(`
INSERT INTO services (
business_id, name, description, url, type, status, price,
login_encrypted, password_encrypted, api_key_encrypted, notes_encrypted, assigned_to
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
`, [
businessId,
name,
description || '',
url || '',
type || 'other',
status || 'active',
price || null,
encrypt(login || ''),
encrypt(password || ''),
encrypt(apiKey || ''),
encrypt(notes || ''),
assignedTo || null
]);
logger.info('✅ Service created:', result.lastInsertRowid);
success(res, { id: result.lastInsertRowid });
} catch (err) {
logger.error('❌ Create service error:', err);
error(res, err.message);
}
});
// Update service (partial update support)
router.put('/:id', authenticate, async (req, res) => {
try {
// Get current service data
const service = await dbGet('SELECT * FROM services WHERE id = ?', [req.params.id]);
if (!service) {
return notFound(res, 'Service not found');
}
// Extract fields from request - allow partial updates
const updates = {};
if (req.body.name !== undefined) updates.name = req.body.name;
if (req.body.description !== undefined) updates.description = req.body.description;
if (req.body.url !== undefined) updates.url = req.body.url;
if (req.body.type !== undefined) updates.type = req.body.type;
if (req.body.status !== undefined) updates.status = req.body.status;
if (req.body.price !== undefined) updates.price = req.body.price;
if (req.body.assignedTo !== undefined) updates.assigned_to = req.body.assignedTo;
// Handle encrypted fields
if (req.body.login !== undefined) updates.login_encrypted = encrypt(req.body.login || '');
if (req.body.password !== undefined) updates.password_encrypted = encrypt(req.body.password || '');
if (req.body.apiKey !== undefined) updates.api_key_encrypted = encrypt(req.body.apiKey || '');
if (req.body.notes !== undefined) updates.notes_encrypted = encrypt(req.body.notes || '');
// Build dynamic UPDATE query
const setClause = Object.keys(updates).map(key => `${key} = ?`).join(', ');
const values = Object.values(updates);
if (setClause.length > 0) {
await dbRun(`
UPDATE services SET ${setClause}, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
`, [...values, req.params.id]);
}
success(res);
} catch (err) {
logger.error('Update service error:', err);
error(res, err.message);
}
});
// Delete service
router.delete('/:id', authenticate, async (req, res) => {
try {
await dbRun('DELETE FROM services WHERE id = ?', [req.params.id]);
success(res);
} catch (err) {
error(res, err.message);
}
});
export default router;