From 510108f9bbec9651a5d91e11ea411e688b5043fe Mon Sep 17 00:00:00 2001 From: ionred Date: Wed, 9 Jul 2025 09:03:06 -0500 Subject: [PATCH] fix: remove LunaSea (#1759) * refactor(lunasea-removal): remove LunaSea fixes #1756 * chore(localization): undo localization changes in favor of weblate --- cypress/config/settings.cypress.json | 7 - jellyseerr-api.yml | 62 ---- server/index.ts | 2 - server/lib/notifications/agents/lunasea.ts | 133 --------- server/lib/settings/index.ts | 15 - .../migrations/0006_remove_lunasea.ts | 14 + server/routes/settings/notifications.ts | 35 --- src/assets/extlogos/lunasea.svg | 1 - .../NotificationsLunaSea/index.tsx | 272 ------------------ .../Settings/SettingsNotifications.tsx | 12 - src/i18n/locale/en.json | 12 - src/pages/settings/notifications/lunasea.tsx | 19 -- 12 files changed, 14 insertions(+), 570 deletions(-) delete mode 100644 server/lib/notifications/agents/lunasea.ts create mode 100644 server/lib/settings/migrations/0006_remove_lunasea.ts delete mode 100644 src/assets/extlogos/lunasea.svg delete mode 100644 src/components/Settings/Notifications/NotificationsLunaSea/index.tsx delete mode 100644 src/pages/settings/notifications/lunasea.tsx diff --git a/cypress/config/settings.cypress.json b/cypress/config/settings.cypress.json index 8ff53fce4..d10a107fd 100644 --- a/cypress/config/settings.cypress.json +++ b/cypress/config/settings.cypress.json @@ -83,13 +83,6 @@ "enableMentions": true } }, - "lunasea": { - "enabled": false, - "types": 0, - "options": { - "webhookUrl": "" - } - }, "slack": { "enabled": false, "types": 0, diff --git a/jellyseerr-api.yml b/jellyseerr-api.yml index 65bb54951..ac5aaa261 100644 --- a/jellyseerr-api.yml +++ b/jellyseerr-api.yml @@ -1425,22 +1425,6 @@ components: type: boolean token: type: string - LunaSeaSettings: - type: object - properties: - enabled: - type: boolean - example: false - types: - type: number - example: 2 - options: - type: object - properties: - webhookUrl: - type: string - profileName: - type: string NotificationEmailSettings: type: object properties: @@ -3099,52 +3083,6 @@ paths: responses: '204': description: Test notification attempted - /settings/notifications/lunasea: - get: - summary: Get LunaSea notification settings - description: Returns current LunaSea notification settings in a JSON object. - tags: - - settings - responses: - '200': - description: Returned LunaSea settings - content: - application/json: - schema: - $ref: '#/components/schemas/LunaSeaSettings' - post: - summary: Update LunaSea notification settings - description: Updates LunaSea notification settings with the provided values. - tags: - - settings - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/LunaSeaSettings' - responses: - '200': - description: 'Values were sucessfully updated' - content: - application/json: - schema: - $ref: '#/components/schemas/LunaSeaSettings' - /settings/notifications/lunasea/test: - post: - summary: Test LunaSea settings - description: Sends a test notification to the LunaSea agent. - tags: - - settings - requestBody: - required: true - content: - application/json: - schema: - $ref: '#/components/schemas/LunaSeaSettings' - responses: - '204': - description: Test notification attempted /settings/notifications/pushbullet: get: summary: Get Pushbullet notification settings diff --git a/server/index.ts b/server/index.ts index f8819f520..e4d46b8a1 100644 --- a/server/index.ts +++ b/server/index.ts @@ -9,7 +9,6 @@ import notificationManager from '@server/lib/notifications'; import DiscordAgent from '@server/lib/notifications/agents/discord'; import EmailAgent from '@server/lib/notifications/agents/email'; import GotifyAgent from '@server/lib/notifications/agents/gotify'; -import LunaSeaAgent from '@server/lib/notifications/agents/lunasea'; import NtfyAgent from '@server/lib/notifications/agents/ntfy'; import PushbulletAgent from '@server/lib/notifications/agents/pushbullet'; import PushoverAgent from '@server/lib/notifications/agents/pushover'; @@ -113,7 +112,6 @@ app new EmailAgent(), new GotifyAgent(), new NtfyAgent(), - new LunaSeaAgent(), new PushbulletAgent(), new PushoverAgent(), new SlackAgent(), diff --git a/server/lib/notifications/agents/lunasea.ts b/server/lib/notifications/agents/lunasea.ts deleted file mode 100644 index acfa7df9d..000000000 --- a/server/lib/notifications/agents/lunasea.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { IssueStatus, IssueType } from '@server/constants/issue'; -import { MediaStatus } from '@server/constants/media'; -import type { NotificationAgentLunaSea } from '@server/lib/settings'; -import { getSettings } from '@server/lib/settings'; -import logger from '@server/logger'; -import axios from 'axios'; -import { hasNotificationType, Notification } from '..'; -import type { NotificationAgent, NotificationPayload } from './agent'; -import { BaseAgent } from './agent'; - -class LunaSeaAgent - extends BaseAgent - implements NotificationAgent -{ - protected getSettings(): NotificationAgentLunaSea { - if (this.settings) { - return this.settings; - } - - const settings = getSettings(); - - return settings.notifications.agents.lunasea; - } - - private buildPayload(type: Notification, payload: NotificationPayload) { - return { - notification_type: Notification[type], - event: payload.event, - subject: payload.subject, - message: payload.message, - image: payload.image ?? null, - email: payload.notifyUser?.email, - username: payload.notifyUser?.displayName, - avatar: payload.notifyUser?.avatar, - media: payload.media - ? { - media_type: payload.media.mediaType, - tmdbId: payload.media.tmdbId, - tvdbId: payload.media.tvdbId, - status: MediaStatus[payload.media.status], - status4k: MediaStatus[payload.media.status4k], - } - : null, - extra: payload.extra ?? [], - request: payload.request - ? { - request_id: payload.request.id, - requestedBy_email: payload.request.requestedBy.email, - requestedBy_username: payload.request.requestedBy.displayName, - requestedBy_avatar: payload.request.requestedBy.avatar, - } - : null, - issue: payload.issue - ? { - issue_id: payload.issue.id, - issue_type: IssueType[payload.issue.issueType], - issue_status: IssueStatus[payload.issue.status], - createdBy_email: payload.issue.createdBy.email, - createdBy_username: payload.issue.createdBy.displayName, - createdBy_avatar: payload.issue.createdBy.avatar, - } - : null, - comment: payload.comment - ? { - comment_message: payload.comment.message, - commentedBy_email: payload.comment.user.email, - commentedBy_username: payload.comment.user.displayName, - commentedBy_avatar: payload.comment.user.avatar, - } - : null, - }; - } - - public shouldSend(): boolean { - const settings = this.getSettings(); - - if (settings.enabled && settings.options.webhookUrl) { - return true; - } - - return false; - } - - public async send( - type: Notification, - payload: NotificationPayload - ): Promise { - const settings = this.getSettings(); - - if ( - !payload.notifySystem || - !hasNotificationType(type, settings.types ?? 0) - ) { - return true; - } - - logger.debug('Sending LunaSea notification', { - label: 'Notifications', - type: Notification[type], - subject: payload.subject, - }); - - try { - await axios.post( - settings.options.webhookUrl, - this.buildPayload(type, payload), - settings.options.profileName - ? { - headers: { - Authorization: `Basic ${Buffer.from( - `${settings.options.profileName}:` - ).toString('base64')}`, - }, - } - : undefined - ); - - return true; - } catch (e) { - logger.error('Error sending LunaSea notification', { - label: 'Notifications', - type: Notification[type], - subject: payload.subject, - errorMessage: e.message, - response: e?.response?.data, - }); - - return false; - } - } -} - -export default LunaSeaAgent; diff --git a/server/lib/settings/index.ts b/server/lib/settings/index.ts index e2274f97b..115f224f8 100644 --- a/server/lib/settings/index.ts +++ b/server/lib/settings/index.ts @@ -216,13 +216,6 @@ export interface NotificationAgentEmail extends NotificationAgentConfig { }; } -export interface NotificationAgentLunaSea extends NotificationAgentConfig { - options: { - webhookUrl: string; - profileName?: string; - }; -} - export interface NotificationAgentTelegram extends NotificationAgentConfig { options: { botUsername?: string; @@ -294,7 +287,6 @@ interface NotificationAgents { email: NotificationAgentEmail; gotify: NotificationAgentGotify; ntfy: NotificationAgentNtfy; - lunasea: NotificationAgentLunaSea; pushbullet: NotificationAgentPushbullet; pushover: NotificationAgentPushover; slack: NotificationAgentSlack; @@ -430,13 +422,6 @@ class Settings { enableMentions: true, }, }, - lunasea: { - enabled: false, - types: 0, - options: { - webhookUrl: '', - }, - }, slack: { enabled: false, types: 0, diff --git a/server/lib/settings/migrations/0006_remove_lunasea.ts b/server/lib/settings/migrations/0006_remove_lunasea.ts new file mode 100644 index 000000000..e5279afa9 --- /dev/null +++ b/server/lib/settings/migrations/0006_remove_lunasea.ts @@ -0,0 +1,14 @@ +import type { AllSettings } from '@server/lib/settings'; + +const removeLunaSeaSetting = (settings: any): AllSettings => { + if ( + settings.notifications && + settings.notifications.agents && + settings.notifications.agents.lunasea + ) { + delete settings.notifications.agents.lunasea; + } + return settings; +}; + +export default removeLunaSeaSetting; diff --git a/server/routes/settings/notifications.ts b/server/routes/settings/notifications.ts index 7d817c36d..cee96b7d7 100644 --- a/server/routes/settings/notifications.ts +++ b/server/routes/settings/notifications.ts @@ -4,7 +4,6 @@ import type { NotificationAgent } from '@server/lib/notifications/agents/agent'; import DiscordAgent from '@server/lib/notifications/agents/discord'; import EmailAgent from '@server/lib/notifications/agents/email'; import GotifyAgent from '@server/lib/notifications/agents/gotify'; -import LunaSeaAgent from '@server/lib/notifications/agents/lunasea'; import NtfyAgent from '@server/lib/notifications/agents/ntfy'; import PushbulletAgent from '@server/lib/notifications/agents/pushbullet'; import PushoverAgent from '@server/lib/notifications/agents/pushover'; @@ -346,40 +345,6 @@ notificationRoutes.post('/webhook/test', async (req, res, next) => { } }); -notificationRoutes.get('/lunasea', (_req, res) => { - const settings = getSettings(); - - res.status(200).json(settings.notifications.agents.lunasea); -}); - -notificationRoutes.post('/lunasea', async (req, res) => { - const settings = getSettings(); - - settings.notifications.agents.lunasea = req.body; - await settings.save(); - - res.status(200).json(settings.notifications.agents.lunasea); -}); - -notificationRoutes.post('/lunasea/test', async (req, res, next) => { - if (!req.user) { - return next({ - status: 500, - message: 'User information is missing from the request.', - }); - } - - const lunaseaAgent = new LunaSeaAgent(req.body); - if (await sendTestNotification(lunaseaAgent, req.user)) { - return res.status(204).send(); - } else { - return next({ - status: 500, - message: 'Failed to send web push notification.', - }); - } -}); - notificationRoutes.get('/gotify', (_req, res) => { const settings = getSettings(); diff --git a/src/assets/extlogos/lunasea.svg b/src/assets/extlogos/lunasea.svg deleted file mode 100644 index 359ca8161..000000000 --- a/src/assets/extlogos/lunasea.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/components/Settings/Notifications/NotificationsLunaSea/index.tsx b/src/components/Settings/Notifications/NotificationsLunaSea/index.tsx deleted file mode 100644 index 455aa4531..000000000 --- a/src/components/Settings/Notifications/NotificationsLunaSea/index.tsx +++ /dev/null @@ -1,272 +0,0 @@ -import Button from '@app/components/Common/Button'; -import LoadingSpinner from '@app/components/Common/LoadingSpinner'; -import NotificationTypeSelector from '@app/components/NotificationTypeSelector'; -import globalMessages from '@app/i18n/globalMessages'; -import defineMessages from '@app/utils/defineMessages'; -import { ArrowDownOnSquareIcon, BeakerIcon } from '@heroicons/react/24/outline'; -import axios from 'axios'; -import { Field, Form, Formik } from 'formik'; -import { useState } from 'react'; -import { useIntl } from 'react-intl'; -import { useToasts } from 'react-toast-notifications'; -import useSWR from 'swr'; -import * as Yup from 'yup'; - -const messages = defineMessages( - 'components.Settings.Notifications.NotificationsLunaSea', - { - agentenabled: 'Enable Agent', - webhookUrl: 'Webhook URL', - webhookUrlTip: - 'Your user- or device-based notification webhook URL', - validationWebhookUrl: 'You must provide a valid URL', - profileName: 'Profile Name', - profileNameTip: - 'Only required if not using the default profile', - settingsSaved: 'LunaSea notification settings saved successfully!', - settingsFailed: 'LunaSea notification settings failed to save.', - toastLunaSeaTestSending: 'Sending LunaSea test notification…', - toastLunaSeaTestSuccess: 'LunaSea test notification sent!', - toastLunaSeaTestFailed: 'LunaSea test notification failed to send.', - validationTypes: 'You must select at least one notification type', - } -); - -const NotificationsLunaSea = () => { - const intl = useIntl(); - const { addToast, removeToast } = useToasts(); - const [isTesting, setIsTesting] = useState(false); - const { - data, - error, - mutate: revalidate, - } = useSWR('/api/v1/settings/notifications/lunasea'); - - const NotificationsLunaSeaSchema = Yup.object().shape({ - webhookUrl: Yup.string() - .when('enabled', { - is: true, - then: Yup.string() - .nullable() - .required(intl.formatMessage(messages.validationWebhookUrl)), - otherwise: Yup.string().nullable(), - }) - .url(intl.formatMessage(messages.validationWebhookUrl)), - }); - - if (!data && !error) { - return ; - } - - return ( - { - try { - await axios.post('/api/v1/settings/notifications/lunasea', { - enabled: values.enabled, - types: values.types, - options: { - webhookUrl: values.webhookUrl, - profileName: values.profileName, - }, - }); - addToast(intl.formatMessage(messages.settingsSaved), { - appearance: 'success', - autoDismiss: true, - }); - } catch (e) { - addToast(intl.formatMessage(messages.settingsFailed), { - appearance: 'error', - autoDismiss: true, - }); - } finally { - revalidate(); - } - }} - > - {({ - errors, - touched, - isSubmitting, - values, - isValid, - setFieldValue, - setFieldTouched, - }) => { - const testSettings = async () => { - setIsTesting(true); - let toastId: string | undefined; - try { - addToast( - intl.formatMessage(messages.toastLunaSeaTestSending), - { - autoDismiss: false, - appearance: 'info', - }, - (id) => { - toastId = id; - } - ); - await axios.post('/api/v1/settings/notifications/lunasea/test', { - enabled: true, - types: values.types, - options: { - webhookUrl: values.webhookUrl, - profileName: values.profileName, - }, - }); - - if (toastId) { - removeToast(toastId); - } - addToast(intl.formatMessage(messages.toastLunaSeaTestSuccess), { - autoDismiss: true, - appearance: 'success', - }); - } catch (e) { - if (toastId) { - removeToast(toastId); - } - addToast(intl.formatMessage(messages.toastLunaSeaTestFailed), { - autoDismiss: true, - appearance: 'error', - }); - } finally { - setIsTesting(false); - } - }; - - return ( -
-
- -
- -
-
-
- -
-
- -
- {errors.webhookUrl && - touched.webhookUrl && - typeof errors.webhookUrl === 'string' && ( -
{errors.webhookUrl}
- )} -
-
-
- -
-
- -
-
-
- { - setFieldValue('types', newTypes); - setFieldTouched('types'); - - if (newTypes) { - setFieldValue('enabled', true); - } - }} - error={ - values.enabled && !values.types && touched.types - ? intl.formatMessage(messages.validationTypes) - : undefined - } - /> -
-
- - - - - - -
-
- - ); - }} -
- ); -}; - -export default NotificationsLunaSea; diff --git a/src/components/Settings/SettingsNotifications.tsx b/src/components/Settings/SettingsNotifications.tsx index bcd5e5f65..564e4c734 100644 --- a/src/components/Settings/SettingsNotifications.tsx +++ b/src/components/Settings/SettingsNotifications.tsx @@ -1,6 +1,5 @@ import DiscordLogo from '@app/assets/extlogos/discord.svg'; import GotifyLogo from '@app/assets/extlogos/gotify.svg'; -import LunaSeaLogo from '@app/assets/extlogos/lunasea.svg'; import NtfyLogo from '@app/assets/extlogos/ntfy.svg'; import PushbulletLogo from '@app/assets/extlogos/pushbullet.svg'; import PushoverLogo from '@app/assets/extlogos/pushover.svg'; @@ -87,17 +86,6 @@ const SettingsNotifications = ({ children }: SettingsNotificationsProps) => { route: '/settings/notifications/ntfy', regex: /^\/settings\/notifications\/ntfy/, }, - { - text: 'LunaSea', - content: ( - - - LunaSea - - ), - route: '/settings/notifications/lunasea', - regex: /^\/settings\/notifications\/lunasea/, - }, { text: 'Pushbullet', content: ( diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index cfa14b06f..0ff5eb7d2 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -620,18 +620,6 @@ "components.Settings.Notifications.NotificationsGotify.validationTypes": "You must select at least one notification type", "components.Settings.Notifications.NotificationsGotify.validationUrlRequired": "You must provide a valid URL", "components.Settings.Notifications.NotificationsGotify.validationUrlTrailingSlash": "URL must not end in a trailing slash", - "components.Settings.Notifications.NotificationsLunaSea.agentenabled": "Enable Agent", - "components.Settings.Notifications.NotificationsLunaSea.profileName": "Profile Name", - "components.Settings.Notifications.NotificationsLunaSea.profileNameTip": "Only required if not using the default profile", - "components.Settings.Notifications.NotificationsLunaSea.settingsFailed": "LunaSea notification settings failed to save.", - "components.Settings.Notifications.NotificationsLunaSea.settingsSaved": "LunaSea notification settings saved successfully!", - "components.Settings.Notifications.NotificationsLunaSea.toastLunaSeaTestFailed": "LunaSea test notification failed to send.", - "components.Settings.Notifications.NotificationsLunaSea.toastLunaSeaTestSending": "Sending LunaSea test notification…", - "components.Settings.Notifications.NotificationsLunaSea.toastLunaSeaTestSuccess": "LunaSea test notification sent!", - "components.Settings.Notifications.NotificationsLunaSea.validationTypes": "You must select at least one notification type", - "components.Settings.Notifications.NotificationsLunaSea.validationWebhookUrl": "You must provide a valid URL", - "components.Settings.Notifications.NotificationsLunaSea.webhookUrl": "Webhook URL", - "components.Settings.Notifications.NotificationsLunaSea.webhookUrlTip": "Your user- or device-based notification webhook URL", "components.Settings.Notifications.NotificationsNtfy.agentenabled": "Enable Agent", "components.Settings.Notifications.NotificationsNtfy.ntfysettingsfailed": "Ntfy notification settings failed to save.", "components.Settings.Notifications.NotificationsNtfy.ntfysettingssaved": "Ntfy notification settings saved successfully!", diff --git a/src/pages/settings/notifications/lunasea.tsx b/src/pages/settings/notifications/lunasea.tsx deleted file mode 100644 index a9662fdd9..000000000 --- a/src/pages/settings/notifications/lunasea.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import NotificationsLunaSea from '@app/components/Settings/Notifications/NotificationsLunaSea'; -import SettingsLayout from '@app/components/Settings/SettingsLayout'; -import SettingsNotifications from '@app/components/Settings/SettingsNotifications'; -import useRouteGuard from '@app/hooks/useRouteGuard'; -import { Permission } from '@app/hooks/useUser'; -import type { NextPage } from 'next'; - -const NotificationsPage: NextPage = () => { - useRouteGuard(Permission.ADMIN); - return ( - - - - - - ); -}; - -export default NotificationsPage;