From b81e66defa214e0cbb5c9f7b13b0726c898af8c1 Mon Sep 17 00:00:00 2001 From: boys-cyber Date: Wed, 24 Jun 2026 19:18:25 +0100 Subject: [PATCH] fix(#3): uncomment notification test endpoints POST /api/notifications/test and POST /api/notifications/test-all were wrapped in block comments, causing documented API routes to return 404. Uncommented both handlers and applied blockDebugInProduction middleware to match the existing pattern used by all other test/debug routes, ensuring the endpoints are unavailable in production environments. --- backend/src/api/routes.ts | 376 +++++++++++++++++++------------------- 1 file changed, 188 insertions(+), 188 deletions(-) diff --git a/backend/src/api/routes.ts b/backend/src/api/routes.ts index 4e07431..032f4ee 100644 --- a/backend/src/api/routes.ts +++ b/backend/src/api/routes.ts @@ -805,196 +805,196 @@ router.delete('/notifications/unsubscribe', async (req, res) => { // ================================ // Test notification delivery -// router.post('/notifications/test', async (req, res) => { -// try { -// const { userId, eventType } = req.body - -// if (!userId) { -// return res.status(400).json({ -// success: false, -// error: 'userId is required' -// }) -// } - -// if (!eventType || !['rebalance', 'circuitBreaker', 'priceMovement', 'riskChange'].includes(eventType)) { -// return res.status(400).json({ -// success: false, -// error: 'eventType must be one of: rebalance, circuitBreaker, priceMovement, riskChange' -// }) -// } - -// // Check if user has preferences -// const preferences = notificationService.getPreferences(userId) -// if (!preferences) { -// return res.status(404).json({ -// success: false, -// error: 'No notification preferences found for this user. Please subscribe first.' -// }) -// } - -// // Create test notification payload based on event type -// let payload: any = { -// userId, -// eventType, -// timestamp: new Date().toISOString() -// } - -// switch (eventType) { -// case 'rebalance': -// payload.title = 'Test: Portfolio Rebalanced' -// payload.message = 'This is a test notification for a rebalance event. Your portfolio has been rebalanced with 3 trades executed.' -// payload.data = { -// portfolioId: 'test-portfolio-123', -// trades: 3, -// gasUsed: '0.0234 XLM', -// trigger: 'manual' -// } -// break - -// case 'circuitBreaker': -// payload.title = 'Test: Circuit Breaker Triggered' -// payload.message = 'This is a test notification for a circuit breaker event. Circuit breaker activated for BTC due to 22.5% price movement.' -// payload.data = { -// asset: 'BTC', -// priceChange: '22.5', -// cooldownMinutes: 5 -// } -// break - -// case 'priceMovement': -// payload.title = 'Test: Large Price Movement Detected' -// payload.message = 'This is a test notification for a price movement event. ETH price increased by 12.34% to $2,150.00' -// payload.data = { -// asset: 'ETH', -// priceChange: '12.34', -// currentPrice: 2150.00, -// direction: 'increased' -// } -// break - -// case 'riskChange': -// payload.title = 'Test: Portfolio Risk Level Changed' -// payload.message = 'This is a test notification for a risk level change. Your portfolio risk level has increased from medium to high.' -// payload.data = { -// portfolioId: 'test-portfolio-123', -// oldLevel: 'medium', -// newLevel: 'high', -// severity: 'increased' -// } -// break -// } - -// // Send the notification -// await notificationService.notify(payload) - -// logger.info('Test notification sent', { userId, eventType }) - -// res.json({ -// success: true, -// message: 'Test notification sent successfully', -// sentTo: { -// email: preferences.emailEnabled ? preferences.emailAddress : null, -// webhook: preferences.webhookEnabled ? preferences.webhookUrl : null -// }, -// eventType, -// timestamp: new Date().toISOString() -// }) -// } catch (error) { -// logger.error('Failed to send test notification', { error: getErrorObject(error) }) -// res.status(500).json({ -// success: false, -// error: getErrorMessage(error) -// }) -// } -// }) +router.post('/notifications/test', blockDebugInProduction, async (req, res) => { + try { + const { userId, eventType } = req.body + + if (!userId) { + return res.status(400).json({ + success: false, + error: 'userId is required' + }) + } + + if (!eventType || !['rebalance', 'circuitBreaker', 'priceMovement', 'riskChange'].includes(eventType)) { + return res.status(400).json({ + success: false, + error: 'eventType must be one of: rebalance, circuitBreaker, priceMovement, riskChange' + }) + } + + // Check if user has preferences + const preferences = notificationService.getPreferences(userId) + if (!preferences) { + return res.status(404).json({ + success: false, + error: 'No notification preferences found for this user. Please subscribe first.' + }) + } + + // Create test notification payload based on event type + let payload: any = { + userId, + eventType, + timestamp: new Date().toISOString() + } + + switch (eventType) { + case 'rebalance': + payload.title = 'Test: Portfolio Rebalanced' + payload.message = 'This is a test notification for a rebalance event. Your portfolio has been rebalanced with 3 trades executed.' + payload.data = { + portfolioId: 'test-portfolio-123', + trades: 3, + gasUsed: '0.0234 XLM', + trigger: 'manual' + } + break + + case 'circuitBreaker': + payload.title = 'Test: Circuit Breaker Triggered' + payload.message = 'This is a test notification for a circuit breaker event. Circuit breaker activated for BTC due to 22.5% price movement.' + payload.data = { + asset: 'BTC', + priceChange: '22.5', + cooldownMinutes: 5 + } + break + + case 'priceMovement': + payload.title = 'Test: Large Price Movement Detected' + payload.message = 'This is a test notification for a price movement event. ETH price increased by 12.34% to $2,150.00' + payload.data = { + asset: 'ETH', + priceChange: '12.34', + currentPrice: 2150.00, + direction: 'increased' + } + break + + case 'riskChange': + payload.title = 'Test: Portfolio Risk Level Changed' + payload.message = 'This is a test notification for a risk level change. Your portfolio risk level has increased from medium to high.' + payload.data = { + portfolioId: 'test-portfolio-123', + oldLevel: 'medium', + newLevel: 'high', + severity: 'increased' + } + break + } + + // Send the notification + await notificationService.notify(payload) + + logger.info('Test notification sent', { userId, eventType }) + + res.json({ + success: true, + message: 'Test notification sent successfully', + sentTo: { + email: preferences.emailEnabled ? preferences.emailAddress : null, + webhook: preferences.webhookEnabled ? preferences.webhookUrl : null + }, + eventType, + timestamp: new Date().toISOString() + }) + } catch (error) { + logger.error('Failed to send test notification', { error: getErrorObject(error) }) + res.status(500).json({ + success: false, + error: getErrorMessage(error) + }) + } +}) // Test all notification types at once -// router.post('/notifications/test-all', async (req, res) => { -// try { -// const { userId } = req.body - -// if (!userId) { -// return res.status(400).json({ -// success: false, -// error: 'userId is required' -// }) -// } - -// const preferences = notificationService.getPreferences(userId) -// if (!preferences) { -// return res.status(404).json({ -// success: false, -// error: 'No notification preferences found for this user. Please subscribe first.' -// }) -// } - -// const eventTypes = ['rebalance', 'circuitBreaker', 'priceMovement', 'riskChange'] -// const results = [] - -// for (const eventType of eventTypes) { -// try { -// // Create test payload -// let payload: any = { -// userId, -// eventType, -// timestamp: new Date().toISOString() -// } - -// switch (eventType) { -// case 'rebalance': -// payload.title = 'Test: Portfolio Rebalanced' -// payload.message = 'Test rebalance notification - 3 trades executed' -// payload.data = { portfolioId: 'test-123', trades: 3, gasUsed: '0.0234 XLM' } -// break -// case 'circuitBreaker': -// payload.title = 'Test: Circuit Breaker Triggered' -// payload.message = 'Test circuit breaker notification - BTC moved 22.5%' -// payload.data = { asset: 'BTC', priceChange: '22.5' } -// break -// case 'priceMovement': -// payload.title = 'Test: Large Price Movement' -// payload.message = 'Test price movement notification - ETH up 12.34%' -// payload.data = { asset: 'ETH', priceChange: '12.34', direction: 'increased' } -// break -// case 'riskChange': -// payload.title = 'Test: Risk Level Changed' -// payload.message = 'Test risk change notification - Risk increased to high' -// payload.data = { oldLevel: 'medium', newLevel: 'high' } -// break -// } - -// await notificationService.notify(payload) -// results.push({ eventType, status: 'sent' }) -// } catch (error) { -// results.push({ -// eventType, -// status: 'failed', -// error: error instanceof Error ? error.message : String(error) -// }) -// } - -// // Small delay between notifications -// await new Promise(resolve => setTimeout(resolve, 500)) -// } - -// res.json({ -// success: true, -// message: 'Test notifications sent', -// results, -// sentTo: { -// email: preferences.emailEnabled ? preferences.emailAddress : null, -// webhook: preferences.webhookEnabled ? preferences.webhookUrl : null -// }, -// timestamp: new Date().toISOString() -// }) -// } catch (error) { -// logger.error('Failed to send test notifications', { error: getErrorObject(error) }) -// res.status(500).json({ -// success: false, -// error: getErrorMessage(error) -// }) -// } -// }) +router.post('/notifications/test-all', blockDebugInProduction, async (req, res) => { + try { + const { userId } = req.body + + if (!userId) { + return res.status(400).json({ + success: false, + error: 'userId is required' + }) + } + + const preferences = notificationService.getPreferences(userId) + if (!preferences) { + return res.status(404).json({ + success: false, + error: 'No notification preferences found for this user. Please subscribe first.' + }) + } + + const eventTypes = ['rebalance', 'circuitBreaker', 'priceMovement', 'riskChange'] + const results = [] + + for (const eventType of eventTypes) { + try { + // Create test payload + let payload: any = { + userId, + eventType, + timestamp: new Date().toISOString() + } + + switch (eventType) { + case 'rebalance': + payload.title = 'Test: Portfolio Rebalanced' + payload.message = 'Test rebalance notification - 3 trades executed' + payload.data = { portfolioId: 'test-123', trades: 3, gasUsed: '0.0234 XLM' } + break + case 'circuitBreaker': + payload.title = 'Test: Circuit Breaker Triggered' + payload.message = 'Test circuit breaker notification - BTC moved 22.5%' + payload.data = { asset: 'BTC', priceChange: '22.5' } + break + case 'priceMovement': + payload.title = 'Test: Large Price Movement' + payload.message = 'Test price movement notification - ETH up 12.34%' + payload.data = { asset: 'ETH', priceChange: '12.34', direction: 'increased' } + break + case 'riskChange': + payload.title = 'Test: Risk Level Changed' + payload.message = 'Test risk change notification - Risk increased to high' + payload.data = { oldLevel: 'medium', newLevel: 'high' } + break + } + + await notificationService.notify(payload) + results.push({ eventType, status: 'sent' }) + } catch (error) { + results.push({ + eventType, + status: 'failed', + error: error instanceof Error ? error.message : String(error) + }) + } + + // Small delay between notifications + await new Promise(resolve => setTimeout(resolve, 500)) + } + + res.json({ + success: true, + message: 'Test notifications sent', + results, + sentTo: { + email: preferences.emailEnabled ? preferences.emailAddress : null, + webhook: preferences.webhookEnabled ? preferences.webhookUrl : null + }, + timestamp: new Date().toISOString() + }) + } catch (error) { + logger.error('Failed to send test notifications', { error: getErrorObject(error) }) + res.status(500).json({ + success: false, + error: getErrorMessage(error) + }) + } +}) // ================================ // DEBUG ROUTES