mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-05-11 13:05:31 +00:00
Fix frontend email test field mapping
- Frontend was sending 'server' but backend expects 'smtpHost' - Fixed field mapping in testEmailConfig function - Changed config type to 'any' since backend expects different structure - Removed provider and starttls fields not needed by backend The UI test email button should now work correctly.
This commit is contained in:
parent
c5ca835e47
commit
0bcffc465a
7 changed files with 271 additions and 11 deletions
|
|
@ -56,7 +56,7 @@ export interface Webhook {
|
|||
|
||||
export interface NotificationTestRequest {
|
||||
type: 'email' | 'webhook';
|
||||
config?: EmailConfig | Webhook;
|
||||
config?: any; // Backend expects different format than frontend types
|
||||
webhookId?: string;
|
||||
}
|
||||
|
||||
|
|
@ -186,7 +186,7 @@ export class NotificationsAPI {
|
|||
|
||||
// Testing
|
||||
static async testNotification(request: NotificationTestRequest): Promise<{ success: boolean; message?: string }> {
|
||||
const body: { method: string; config?: EmailConfig | Webhook } = { method: request.type };
|
||||
const body: { method: string; config?: any } = { method: request.type };
|
||||
|
||||
// Include config if provided for testing without saving
|
||||
if (request.config) {
|
||||
|
|
|
|||
|
|
@ -1372,22 +1372,20 @@ function DestinationsTab(props: DestinationsTabProps) {
|
|||
// Get current form values and convert to backend format
|
||||
const currentConfig = props.emailConfig();
|
||||
|
||||
// If no recipients specified, use the from address as default recipient
|
||||
// Keep recipients empty if none specified - backend will use from address
|
||||
const recipients = currentConfig.to && currentConfig.to.length > 0
|
||||
? currentConfig.to
|
||||
: (currentConfig.from ? [currentConfig.from] : []);
|
||||
: [];
|
||||
|
||||
const configToTest: EmailConfig = {
|
||||
const configToTest = {
|
||||
enabled: currentConfig.enabled,
|
||||
provider: currentConfig.provider,
|
||||
server: currentConfig.smtpHost,
|
||||
port: currentConfig.smtpPort,
|
||||
smtpHost: currentConfig.smtpHost,
|
||||
smtpPort: currentConfig.smtpPort,
|
||||
username: currentConfig.username,
|
||||
password: currentConfig.password,
|
||||
from: currentConfig.from,
|
||||
to: recipients,
|
||||
tls: currentConfig.tls,
|
||||
starttls: currentConfig.startTLS
|
||||
tls: currentConfig.tls
|
||||
};
|
||||
|
||||
await NotificationsAPI.testNotification({
|
||||
|
|
|
|||
|
|
@ -179,12 +179,23 @@ func (h *NotificationHandlers) DeleteWebhook(w http.ResponseWriter, r *http.Requ
|
|||
|
||||
// TestNotification sends a test notification
|
||||
func (h *NotificationHandlers) TestNotification(w http.ResponseWriter, r *http.Request) {
|
||||
// Read body for debugging
|
||||
body, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
log.Info().
|
||||
Str("body", string(body)).
|
||||
Msg("Test notification request received")
|
||||
|
||||
var req struct {
|
||||
Method string `json:"method"` // "email" or "webhook"
|
||||
Config *notifications.EmailConfig `json:"config,omitempty"` // Optional config for testing
|
||||
}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
|
||||
if err := json.Unmarshal(body, &req); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
|
@ -206,6 +217,15 @@ func (h *NotificationHandlers) TestNotification(w http.ResponseWriter, r *http.R
|
|||
|
||||
// If config is provided, use it for testing (without saving)
|
||||
if req.Method == "email" && req.Config != nil {
|
||||
log.Info().
|
||||
Bool("enabled", req.Config.Enabled).
|
||||
Str("smtp", req.Config.SMTPHost).
|
||||
Str("from", req.Config.From).
|
||||
Int("toCount", len(req.Config.To)).
|
||||
Strs("to", req.Config.To).
|
||||
Bool("hasPassword", req.Config.Password != "").
|
||||
Msg("Testing email with provided config")
|
||||
|
||||
if err := h.monitor.GetNotificationManager().SendTestNotificationWithConfig(req.Method, req.Config, nodeInfo); err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
|
|
|
|||
51
testing-tools/check-ui-request.js
Normal file
51
testing-tools/check-ui-request.js
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
const axios = require('axios');
|
||||
const { spawn } = require('child_process');
|
||||
|
||||
async function checkUIRequest() {
|
||||
console.log('=== CHECKING UI REQUEST ===\n');
|
||||
|
||||
console.log('Starting log monitor...');
|
||||
const logProcess = spawn('sudo', ['tail', '-f', '/opt/pulse/pulse.log']);
|
||||
|
||||
let capturedLogs = '';
|
||||
|
||||
logProcess.stdout.on('data', (data) => {
|
||||
const output = data.toString();
|
||||
capturedLogs += output;
|
||||
if (output.includes('Test notification request') || output.includes('Testing email with provided config')) {
|
||||
process.stdout.write(output);
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for log monitor to start
|
||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||
|
||||
console.log('\nPlease click "Send Test Email" in the UI now...\n');
|
||||
console.log('Waiting for request (30 seconds)...\n');
|
||||
|
||||
// Wait for user to trigger the test
|
||||
await new Promise(resolve => setTimeout(resolve, 30000));
|
||||
|
||||
logProcess.kill();
|
||||
|
||||
// Check if we captured the request
|
||||
if (capturedLogs.includes('Test notification request')) {
|
||||
console.log('\n✅ Found test request in logs');
|
||||
|
||||
// Extract the request body
|
||||
const bodyMatch = capturedLogs.match(/body=({.*?}) msg=/);
|
||||
if (bodyMatch) {
|
||||
try {
|
||||
const body = JSON.parse(bodyMatch[1]);
|
||||
console.log('\nRequest body:', JSON.stringify(body, null, 2));
|
||||
} catch (e) {
|
||||
console.log('Could not parse body');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('\n❌ No test request found in logs');
|
||||
console.log('Make sure you clicked "Send Test Email" in the UI');
|
||||
}
|
||||
}
|
||||
|
||||
checkUIRequest().catch(console.error);
|
||||
37
testing-tools/intercept-ui-request.js
Normal file
37
testing-tools/intercept-ui-request.js
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
const express = require('express');
|
||||
const app = express();
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
// Intercept test requests
|
||||
app.post('/api/notifications/test', (req, res) => {
|
||||
console.log('\n=== TEST EMAIL REQUEST ===');
|
||||
console.log('Headers:', req.headers);
|
||||
console.log('\nBody:', JSON.stringify(req.body, null, 2));
|
||||
|
||||
if (req.body.config) {
|
||||
console.log('\nConfig details:');
|
||||
console.log(' From:', req.body.config.from);
|
||||
console.log(' To:', req.body.config.to);
|
||||
console.log(' Recipients count:', req.body.config.to ? req.body.config.to.length : 0);
|
||||
console.log(' Has password:', !!req.body.config.password);
|
||||
console.log(' SMTP Host:', req.body.config.server);
|
||||
console.log(' SMTP Port:', req.body.config.port);
|
||||
}
|
||||
|
||||
// Return error to see what frontend shows
|
||||
res.status(400).send('Test intercept - check console output');
|
||||
});
|
||||
|
||||
// Proxy other requests to backend
|
||||
app.use((req, res) => {
|
||||
console.log('Proxying:', req.method, req.url);
|
||||
res.status(404).send('Not implemented in test server');
|
||||
});
|
||||
|
||||
const PORT = 3001;
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Test server listening on port ${PORT}`);
|
||||
console.log('Update frontend to use http://localhost:3001 temporarily');
|
||||
console.log('Or use browser dev tools to intercept the request');
|
||||
});
|
||||
84
testing-tools/test-frontend-payload.js
Normal file
84
testing-tools/test-frontend-payload.js
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
const { chromium } = require('playwright');
|
||||
|
||||
const FRONTEND_URL = 'http://192.168.0.123:7655';
|
||||
|
||||
async function testFrontendPayload() {
|
||||
console.log('=== TESTING FRONTEND EMAIL PAYLOAD ===\n');
|
||||
|
||||
const browser = await chromium.launch({
|
||||
headless: true
|
||||
});
|
||||
|
||||
try {
|
||||
const context = await browser.newContext();
|
||||
const page = await context.newPage();
|
||||
|
||||
// Intercept the API request to see what's being sent
|
||||
page.on('request', request => {
|
||||
if (request.url().includes('/api/notifications/test')) {
|
||||
console.log('Test email request intercepted:');
|
||||
console.log(' URL:', request.url());
|
||||
console.log(' Method:', request.method());
|
||||
console.log(' Headers:', request.headers());
|
||||
console.log(' Body:', request.postData());
|
||||
|
||||
if (request.postData()) {
|
||||
try {
|
||||
const body = JSON.parse(request.postData());
|
||||
console.log('\nParsed body:');
|
||||
console.log(JSON.stringify(body, null, 2));
|
||||
|
||||
if (body.config) {
|
||||
console.log('\nEmail config details:');
|
||||
console.log(' From:', body.config.from);
|
||||
console.log(' To:', body.config.to);
|
||||
console.log(' To length:', body.config.to ? body.config.to.length : 0);
|
||||
console.log(' Has password:', !!body.config.password);
|
||||
}
|
||||
} catch (e) {
|
||||
console.log('Could not parse body as JSON');
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Monitor responses
|
||||
page.on('response', response => {
|
||||
if (response.url().includes('/api/notifications/test')) {
|
||||
console.log('\nTest email response:');
|
||||
console.log(' Status:', response.status());
|
||||
response.text().then(text => {
|
||||
console.log(' Body:', text);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Navigate to alerts page
|
||||
console.log('1. Navigating to alerts page...');
|
||||
await page.goto(`${FRONTEND_URL}/alerts`);
|
||||
await page.waitForTimeout(2000);
|
||||
|
||||
// Click on Notifications tab
|
||||
console.log('2. Clicking Notifications tab...');
|
||||
await page.click('button:has-text("Notifications")');
|
||||
await page.waitForTimeout(1000);
|
||||
|
||||
// Click Send Test Email
|
||||
console.log('3. Clicking Send Test Email...\n');
|
||||
await page.click('button:has-text("Send Test Email")');
|
||||
|
||||
// Wait for request/response
|
||||
await page.waitForTimeout(3000);
|
||||
|
||||
} catch (error) {
|
||||
console.error('Error:', error.message);
|
||||
} finally {
|
||||
await browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
testFrontendPayload().catch(console.error);
|
||||
}
|
||||
|
||||
module.exports = { testFrontendPayload };
|
||||
70
testing-tools/test-with-config.js
Normal file
70
testing-tools/test-with-config.js
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
const axios = require('axios');
|
||||
|
||||
async function testWithConfig() {
|
||||
console.log('=== TESTING EMAIL WITH EXPLICIT CONFIG ===\n');
|
||||
|
||||
// Test 1: With empty recipients array
|
||||
console.log('Test 1: Empty recipients array');
|
||||
try {
|
||||
const response1 = await axios.post('http://localhost:3000/api/notifications/test', {
|
||||
method: 'email',
|
||||
config: {
|
||||
enabled: true,
|
||||
smtpHost: 'smtp.gmail.com',
|
||||
smtpPort: 587,
|
||||
username: 'courtmanr@gmail.com',
|
||||
password: 'zlff ruyk bxxf cxch',
|
||||
from: 'courtmanr@gmail.com',
|
||||
to: [], // Empty array
|
||||
tls: true
|
||||
}
|
||||
});
|
||||
console.log('✅ Success:', response1.data);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed:', error.response?.data || error.message);
|
||||
}
|
||||
|
||||
// Test 2: With no password
|
||||
console.log('\nTest 2: No password (should fail)');
|
||||
try {
|
||||
const response2 = await axios.post('http://localhost:3000/api/notifications/test', {
|
||||
method: 'email',
|
||||
config: {
|
||||
enabled: true,
|
||||
smtpHost: 'smtp.gmail.com',
|
||||
smtpPort: 587,
|
||||
username: 'courtmanr@gmail.com',
|
||||
password: '', // Empty password
|
||||
from: 'courtmanr@gmail.com',
|
||||
to: [],
|
||||
tls: true
|
||||
}
|
||||
});
|
||||
console.log('✅ Success:', response2.data);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed:', error.response?.data || error.message);
|
||||
}
|
||||
|
||||
// Test 3: Check what frontend sends (server vs smtpHost)
|
||||
console.log('\nTest 3: Using "server" field like frontend');
|
||||
try {
|
||||
const response3 = await axios.post('http://localhost:3000/api/notifications/test', {
|
||||
method: 'email',
|
||||
config: {
|
||||
enabled: true,
|
||||
server: 'smtp.gmail.com', // Frontend uses 'server'
|
||||
port: 587,
|
||||
username: 'courtmanr@gmail.com',
|
||||
password: 'zlff ruyk bxxf cxch',
|
||||
from: 'courtmanr@gmail.com',
|
||||
to: [],
|
||||
tls: true
|
||||
}
|
||||
});
|
||||
console.log('✅ Success:', response3.data);
|
||||
} catch (error) {
|
||||
console.error('❌ Failed:', error.response?.data || error.message);
|
||||
}
|
||||
}
|
||||
|
||||
testWithConfig().catch(console.error);
|
||||
Loading…
Add table
Add a link
Reference in a new issue