diff --git a/server/lib/notifications/agents/discord.ts b/server/lib/notifications/agents/discord.ts
index 209ac6eb..1b79f7e3 100644
--- a/server/lib/notifications/agents/discord.ts
+++ b/server/lib/notifications/agents/discord.ts
@@ -272,7 +272,7 @@ class DiscordAgent
type: Notification[type],
subject: payload.subject,
errorMessage: e.message,
- response: e.response.data,
+ response: e.response?.data,
});
return false;
diff --git a/server/lib/notifications/agents/pushbullet.ts b/server/lib/notifications/agents/pushbullet.ts
index c43e9971..ab4b811e 100644
--- a/server/lib/notifications/agents/pushbullet.ts
+++ b/server/lib/notifications/agents/pushbullet.ts
@@ -170,7 +170,7 @@ class PushbulletAgent
type: Notification[type],
subject: payload.subject,
errorMessage: e.message,
- response: e.response.data,
+ response: e.response?.data,
});
return false;
diff --git a/server/lib/notifications/agents/pushover.ts b/server/lib/notifications/agents/pushover.ts
index f9bff21c..858da0c6 100644
--- a/server/lib/notifications/agents/pushover.ts
+++ b/server/lib/notifications/agents/pushover.ts
@@ -196,7 +196,7 @@ class PushoverAgent
type: Notification[type],
subject: payload.subject,
errorMessage: e.message,
- response: e.response.data,
+ response: e.response?.data,
});
return false;
diff --git a/server/lib/notifications/agents/slack.ts b/server/lib/notifications/agents/slack.ts
index f9fe46c9..7004fe4b 100644
--- a/server/lib/notifications/agents/slack.ts
+++ b/server/lib/notifications/agents/slack.ts
@@ -254,7 +254,7 @@ class SlackAgent
type: Notification[type],
subject: payload.subject,
errorMessage: e.message,
- response: e.response.data,
+ response: e.response?.data,
});
return false;
diff --git a/server/lib/notifications/agents/telegram.ts b/server/lib/notifications/agents/telegram.ts
index a97bbb6f..1a22ddce 100644
--- a/server/lib/notifications/agents/telegram.ts
+++ b/server/lib/notifications/agents/telegram.ts
@@ -244,7 +244,7 @@ class TelegramAgent
type: Notification[type],
subject: payload.subject,
errorMessage: e.message,
- response: e.response.data,
+ response: e.response?.data,
});
return false;
diff --git a/server/lib/notifications/agents/webhook.ts b/server/lib/notifications/agents/webhook.ts
index 7630cf44..7d8cbd86 100644
--- a/server/lib/notifications/agents/webhook.ts
+++ b/server/lib/notifications/agents/webhook.ts
@@ -154,7 +154,7 @@ class WebhookAgent
type: Notification[type],
subject: payload.subject,
errorMessage: e.message,
- response: e.response.data,
+ response: e.response?.data,
});
return false;
diff --git a/server/routes/settings/notifications.ts b/server/routes/settings/notifications.ts
index 8c60c960..bb21c7b6 100644
--- a/server/routes/settings/notifications.ts
+++ b/server/routes/settings/notifications.ts
@@ -28,23 +28,30 @@ notificationRoutes.post('/discord', (req, res) => {
res.status(200).json(settings.notifications.agents.discord);
});
-notificationRoutes.post('/discord/test', (req, res, next) => {
+notificationRoutes.post('/discord/test', async (req, res, next) => {
if (!req.user) {
return next({
status: 500,
- message: 'User information missing from request',
+ message: 'User information is missing from the request.',
});
}
const discordAgent = new DiscordAgent(req.body);
- discordAgent.send(Notification.TEST_NOTIFICATION, {
- notifyUser: req.user,
- subject: 'Test Notification',
- message:
- 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
- });
-
- return res.status(204).send();
+ if (
+ await discordAgent.send(Notification.TEST_NOTIFICATION, {
+ notifyUser: req.user,
+ subject: 'Test Notification',
+ message:
+ 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
+ })
+ ) {
+ return res.status(204).send();
+ } else {
+ return next({
+ status: 500,
+ message: 'Failed to send Discord notification.',
+ });
+ }
});
notificationRoutes.get('/slack', (_req, res) => {
@@ -62,23 +69,30 @@ notificationRoutes.post('/slack', (req, res) => {
res.status(200).json(settings.notifications.agents.slack);
});
-notificationRoutes.post('/slack/test', (req, res, next) => {
+notificationRoutes.post('/slack/test', async (req, res, next) => {
if (!req.user) {
return next({
status: 500,
- message: 'User information missing from request',
+ message: 'User information is missing from the request.',
});
}
const slackAgent = new SlackAgent(req.body);
- slackAgent.send(Notification.TEST_NOTIFICATION, {
- notifyUser: req.user,
- subject: 'Test Notification',
- message:
- 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
- });
-
- return res.status(204).send();
+ if (
+ await slackAgent.send(Notification.TEST_NOTIFICATION, {
+ notifyUser: req.user,
+ subject: 'Test Notification',
+ message:
+ 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
+ })
+ ) {
+ return res.status(204).send();
+ } else {
+ return next({
+ status: 500,
+ message: 'Failed to send Slack notification.',
+ });
+ }
});
notificationRoutes.get('/telegram', (_req, res) => {
@@ -96,23 +110,30 @@ notificationRoutes.post('/telegram', (req, res) => {
res.status(200).json(settings.notifications.agents.telegram);
});
-notificationRoutes.post('/telegram/test', (req, res, next) => {
+notificationRoutes.post('/telegram/test', async (req, res, next) => {
if (!req.user) {
return next({
status: 500,
- message: 'User information missing from request',
+ message: 'User information is missing from the request.',
});
}
const telegramAgent = new TelegramAgent(req.body);
- telegramAgent.send(Notification.TEST_NOTIFICATION, {
- notifyUser: req.user,
- subject: 'Test Notification',
- message:
- 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
- });
-
- return res.status(204).send();
+ if (
+ await telegramAgent.send(Notification.TEST_NOTIFICATION, {
+ notifyUser: req.user,
+ subject: 'Test Notification',
+ message:
+ 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
+ })
+ ) {
+ return res.status(204).send();
+ } else {
+ return next({
+ status: 500,
+ message: 'Failed to send Telegram notification.',
+ });
+ }
});
notificationRoutes.get('/pushbullet', (_req, res) => {
@@ -130,23 +151,30 @@ notificationRoutes.post('/pushbullet', (req, res) => {
res.status(200).json(settings.notifications.agents.pushbullet);
});
-notificationRoutes.post('/pushbullet/test', (req, res, next) => {
+notificationRoutes.post('/pushbullet/test', async (req, res, next) => {
if (!req.user) {
return next({
status: 500,
- message: 'User information missing from request',
+ message: 'User information is missing from the request.',
});
}
const pushbulletAgent = new PushbulletAgent(req.body);
- pushbulletAgent.send(Notification.TEST_NOTIFICATION, {
- notifyUser: req.user,
- subject: 'Test Notification',
- message:
- 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
- });
-
- return res.status(204).send();
+ if (
+ await pushbulletAgent.send(Notification.TEST_NOTIFICATION, {
+ notifyUser: req.user,
+ subject: 'Test Notification',
+ message:
+ 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
+ })
+ ) {
+ return res.status(204).send();
+ } else {
+ return next({
+ status: 500,
+ message: 'Failed to send Pushbullet notification.',
+ });
+ }
});
notificationRoutes.get('/pushover', (_req, res) => {
@@ -164,23 +192,30 @@ notificationRoutes.post('/pushover', (req, res) => {
res.status(200).json(settings.notifications.agents.pushover);
});
-notificationRoutes.post('/pushover/test', (req, res, next) => {
+notificationRoutes.post('/pushover/test', async (req, res, next) => {
if (!req.user) {
return next({
status: 500,
- message: 'User information missing from request',
+ message: 'User information is missing from the request.',
});
}
const pushoverAgent = new PushoverAgent(req.body);
- pushoverAgent.send(Notification.TEST_NOTIFICATION, {
- notifyUser: req.user,
- subject: 'Test Notification',
- message:
- 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
- });
-
- return res.status(204).send();
+ if (
+ await pushoverAgent.send(Notification.TEST_NOTIFICATION, {
+ notifyUser: req.user,
+ subject: 'Test Notification',
+ message:
+ 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
+ })
+ ) {
+ return res.status(204).send();
+ } else {
+ return next({
+ status: 500,
+ message: 'Failed to send Pushover notification.',
+ });
+ }
});
notificationRoutes.get('/email', (_req, res) => {
@@ -198,23 +233,30 @@ notificationRoutes.post('/email', (req, res) => {
res.status(200).json(settings.notifications.agents.email);
});
-notificationRoutes.post('/email/test', (req, res, next) => {
+notificationRoutes.post('/email/test', async (req, res, next) => {
if (!req.user) {
return next({
status: 500,
- message: 'User information missing from request',
+ message: 'User information is missing from the request.',
});
}
const emailAgent = new EmailAgent(req.body);
- emailAgent.send(Notification.TEST_NOTIFICATION, {
- notifyUser: req.user,
- subject: 'Test Notification',
- message:
- 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
- });
-
- return res.status(204).send();
+ if (
+ await emailAgent.send(Notification.TEST_NOTIFICATION, {
+ notifyUser: req.user,
+ subject: 'Test Notification',
+ message:
+ 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
+ })
+ ) {
+ return res.status(204).send();
+ } else {
+ return next({
+ status: 500,
+ message: 'Failed to send email notification.',
+ });
+ }
});
notificationRoutes.get('/webpush', (_req, res) => {
@@ -232,7 +274,7 @@ notificationRoutes.post('/webpush', (req, res) => {
res.status(200).json(settings.notifications.agents.webpush);
});
-notificationRoutes.post('/webpush/test', (req, res, next) => {
+notificationRoutes.post('/webpush/test', async (req, res, next) => {
if (!req.user) {
return next({
status: 500,
@@ -241,14 +283,21 @@ notificationRoutes.post('/webpush/test', (req, res, next) => {
}
const webpushAgent = new WebPushAgent(req.body);
- webpushAgent.send(Notification.TEST_NOTIFICATION, {
- notifyUser: req.user,
- subject: 'Test Notification',
- message:
- 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
- });
-
- return res.status(204).send();
+ if (
+ await webpushAgent.send(Notification.TEST_NOTIFICATION, {
+ notifyUser: req.user,
+ subject: 'Test Notification',
+ message:
+ 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
+ })
+ ) {
+ return res.status(204).send();
+ } else {
+ return next({
+ status: 500,
+ message: 'Failed to send web push notification.',
+ });
+ }
});
notificationRoutes.get('/webhook', (_req, res) => {
@@ -296,11 +345,11 @@ notificationRoutes.post('/webhook', (req, res, next) => {
}
});
-notificationRoutes.post('/webhook/test', (req, res, next) => {
+notificationRoutes.post('/webhook/test', async (req, res, next) => {
if (!req.user) {
return next({
status: 500,
- message: 'User information missing from request',
+ message: 'User information is missing from the request.',
});
}
@@ -320,14 +369,21 @@ notificationRoutes.post('/webhook/test', (req, res, next) => {
};
const webhookAgent = new WebhookAgent(testBody);
- webhookAgent.send(Notification.TEST_NOTIFICATION, {
- notifyUser: req.user,
- subject: 'Test Notification',
- message:
- 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
- });
-
- return res.status(204).send();
+ if (
+ await webhookAgent.send(Notification.TEST_NOTIFICATION, {
+ notifyUser: req.user,
+ subject: 'Test Notification',
+ message:
+ 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
+ })
+ ) {
+ return res.status(204).send();
+ } else {
+ return next({
+ status: 500,
+ message: 'Failed to send webhook notification.',
+ });
+ }
} catch (e) {
next({ status: 500, message: e.message });
}
@@ -348,7 +404,7 @@ notificationRoutes.post('/lunasea', (req, res) => {
res.status(200).json(settings.notifications.agents.lunasea);
});
-notificationRoutes.post('/lunasea/test', (req, res, next) => {
+notificationRoutes.post('/lunasea/test', async (req, res, next) => {
if (!req.user) {
return next({
status: 500,
@@ -357,14 +413,21 @@ notificationRoutes.post('/lunasea/test', (req, res, next) => {
}
const lunaseaAgent = new LunaSeaAgent(req.body);
- lunaseaAgent.send(Notification.TEST_NOTIFICATION, {
- notifyUser: req.user,
- subject: 'Test Notification',
- message:
- 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
- });
-
- return res.status(204).send();
+ if (
+ await lunaseaAgent.send(Notification.TEST_NOTIFICATION, {
+ notifyUser: req.user,
+ subject: 'Test Notification',
+ message:
+ 'This is a test notification! Check check, 1, 2, 3. Are we coming in clear?',
+ })
+ ) {
+ return res.status(204).send();
+ } else {
+ return next({
+ status: 500,
+ message: 'Failed to send web push notification.',
+ });
+ }
});
export default notificationRoutes;
diff --git a/src/components/Settings/Notifications/NotificationsDiscord.tsx b/src/components/Settings/Notifications/NotificationsDiscord.tsx
index b70baf28..f195e9e6 100644
--- a/src/components/Settings/Notifications/NotificationsDiscord.tsx
+++ b/src/components/Settings/Notifications/NotificationsDiscord.tsx
@@ -1,6 +1,6 @@
import axios from 'axios';
import { Field, Form, Formik } from 'formik';
-import React from 'react';
+import React, { useState } from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { useToasts } from 'react-toast-notifications';
import useSWR from 'swr';
@@ -18,13 +18,16 @@ const messages = defineMessages({
webhookUrlPlaceholder: 'Server Settings → Integrations → Webhooks',
discordsettingssaved: 'Discord notification settings saved successfully!',
discordsettingsfailed: 'Discord notification settings failed to save.',
- discordtestsent: 'Discord test notification sent!',
+ toastDiscordTestSending: 'Sending Discord test notification…',
+ toastDiscordTestSuccess: 'Discord test notification sent!',
+ toastDiscordTestFailed: 'Discord test notification failed to send.',
validationUrl: 'You must provide a valid URL',
});
const NotificationsDiscord: React.FC = () => {
const intl = useIntl();
- const { addToast } = useToasts();
+ const { addToast, removeToast } = useToasts();
+ const [isTesting, setIsTesting] = useState(false);
const { data, error, revalidate } = useSWR(
'/api/v1/settings/notifications/discord'
);
@@ -86,20 +89,47 @@ const NotificationsDiscord: React.FC = () => {
>
{({ errors, touched, isSubmitting, values, isValid, setFieldValue }) => {
const testSettings = async () => {
- await axios.post('/api/v1/settings/notifications/discord/test', {
- enabled: true,
- types: values.types,
- options: {
- botUsername: values.botUsername,
- botAvatarUrl: values.botAvatarUrl,
- webhookUrl: values.webhookUrl,
- },
- });
+ setIsTesting(true);
+ let toastId: string | undefined;
+ try {
+ addToast(
+ intl.formatMessage(messages.toastDiscordTestSending),
+ {
+ autoDismiss: false,
+ appearance: 'info',
+ },
+ (id) => {
+ toastId = id;
+ }
+ );
+ await axios.post('/api/v1/settings/notifications/discord/test', {
+ enabled: true,
+ types: values.types,
+ options: {
+ botUsername: values.botUsername,
+ botAvatarUrl: values.botAvatarUrl,
+ webhookUrl: values.webhookUrl,
+ },
+ });
- addToast(intl.formatMessage(messages.discordtestsent), {
- appearance: 'info',
- autoDismiss: true,
- });
+ if (toastId) {
+ removeToast(toastId);
+ }
+ addToast(intl.formatMessage(messages.toastDiscordTestSuccess), {
+ autoDismiss: true,
+ appearance: 'success',
+ });
+ } catch (e) {
+ if (toastId) {
+ removeToast(toastId);
+ }
+ addToast(intl.formatMessage(messages.toastDiscordTestFailed), {
+ autoDismiss: true,
+ appearance: 'error',
+ });
+ } finally {
+ setIsTesting(false);
+ }
};
return (
@@ -178,21 +208,22 @@ const NotificationsDiscord: React.FC = () => {