diff --git a/server/api/externalapi.ts b/server/api/externalapi.ts index 6ca4c1fd..2a1d9495 100644 --- a/server/api/externalapi.ts +++ b/server/api/externalapi.ts @@ -1,6 +1,5 @@ import axios, { AxiosInstance, AxiosRequestConfig } from 'axios'; import NodeCache from 'node-cache'; -import logger from '../logger'; // 5 minute default TTL (in seconds) const DEFAULT_TTL = 300; @@ -66,9 +65,6 @@ class ExternalAPI { if (cachedItem) { const keyTtl = this.cache?.getTtl(cacheKey) ?? 0; - logger.debug(`Loaded item from cache: ${cacheKey}`, { - keyTtl, - }); // If the item has passed our rolling check, fetch again in background if ( diff --git a/src/components/Settings/RadarrModal/index.tsx b/src/components/Settings/RadarrModal/index.tsx index 992d9f3e..2ba6b61a 100644 --- a/src/components/Settings/RadarrModal/index.tsx +++ b/src/components/Settings/RadarrModal/index.tsx @@ -50,6 +50,8 @@ const messages = defineMessages({ loadingrootfolders: 'Loading root folders…', testFirstRootFolders: 'Test connection to load root folders', preventSearch: 'Disable Auto-Search', + validationApplicationUrl: 'You must provide a valid URL', + validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash', }); interface TestResponse { @@ -105,6 +107,18 @@ const RadarrModal: React.FC = ({ minimumAvailability: Yup.string().required( intl.formatMessage(messages.validationMinimumAvailabilityRequired) ), + externalUrl: Yup.string() + .url(intl.formatMessage(messages.validationApplicationUrl)) + .test( + 'no-trailing-slash', + intl.formatMessage(messages.validationApplicationUrlTrailingSlash), + (value) => { + if (value?.substr(value.length - 1) === '/') { + return false; + } + return true; + } + ), }); const testConnection = useCallback( diff --git a/src/components/Settings/SettingsMain.tsx b/src/components/Settings/SettingsMain.tsx index 6975a18c..3d51ef2e 100644 --- a/src/components/Settings/SettingsMain.tsx +++ b/src/components/Settings/SettingsMain.tsx @@ -39,6 +39,8 @@ const messages = defineMessages({ 'Allows Overseerr to correctly register client IP addresses behind a proxy (Overseerr must be reloaded for changes to take effect)', localLogin: 'Enable Local User Sign-In', validationApplicationTitle: 'You must provide an application title', + validationApplicationUrl: 'You must provide a valid URL', + validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash', }); const SettingsMain: React.FC = () => { @@ -52,6 +54,18 @@ const SettingsMain: React.FC = () => { applicationTitle: Yup.string().required( intl.formatMessage(messages.validationApplicationTitle) ), + applicationUrl: Yup.string() + .url(intl.formatMessage(messages.validationApplicationUrl)) + .test( + 'no-trailing-slash', + intl.formatMessage(messages.validationApplicationUrlTrailingSlash), + (value) => { + if (value?.substr(value.length - 1) === '/') { + return false; + } + return true; + } + ), }); const regenerate = async () => { @@ -200,6 +214,9 @@ const SettingsMain: React.FC = () => { placeholder="https://os.example.com" /> + {errors.applicationUrl && touched.applicationUrl && ( +
{errors.applicationUrl}
+ )}
diff --git a/src/components/Settings/SonarrModal/index.tsx b/src/components/Settings/SonarrModal/index.tsx index 198de910..36816ed6 100644 --- a/src/components/Settings/SonarrModal/index.tsx +++ b/src/components/Settings/SonarrModal/index.tsx @@ -50,6 +50,8 @@ const messages = defineMessages({ externalUrl: 'External URL', externalUrlPlaceholder: 'External URL pointing to your Sonarr server', preventSearch: 'Disable Auto-Search', + validationApplicationUrl: 'You must provide a valid URL', + validationApplicationUrlTrailingSlash: 'URL must not end in a trailing slash', }); interface TestResponse { @@ -102,6 +104,18 @@ const SonarrModal: React.FC = ({ activeProfileId: Yup.string().required( intl.formatMessage(messages.validationProfileRequired) ), + externalUrl: Yup.string() + .url(intl.formatMessage(messages.validationApplicationUrl)) + .test( + 'no-trailing-slash', + intl.formatMessage(messages.validationApplicationUrlTrailingSlash), + (value) => { + if (value?.substr(value.length - 1) === '/') { + return false; + } + return true; + } + ), }); const testConnection = useCallback( diff --git a/src/i18n/locale/en.json b/src/i18n/locale/en.json index 47554464..997061d9 100644 --- a/src/i18n/locale/en.json +++ b/src/i18n/locale/en.json @@ -325,6 +325,8 @@ "components.Settings.RadarrModal.toastRadarrTestFailure": "Failed to connect to Radarr.", "components.Settings.RadarrModal.toastRadarrTestSuccess": "Radarr connection established!", "components.Settings.RadarrModal.validationApiKeyRequired": "You must provide an API key", + "components.Settings.RadarrModal.validationApplicationUrl": "You must provide a valid URL", + "components.Settings.RadarrModal.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash", "components.Settings.RadarrModal.validationHostnameRequired": "You must provide a hostname/IP", "components.Settings.RadarrModal.validationMinimumAvailabilityRequired": "You must select a minimum availability", "components.Settings.RadarrModal.validationNameRequired": "You must provide a server name", @@ -409,6 +411,8 @@ "components.Settings.SonarrModal.toastSonarrTestFailure": "Failed to connect to Sonarr.", "components.Settings.SonarrModal.toastSonarrTestSuccess": "Sonarr connection established!", "components.Settings.SonarrModal.validationApiKeyRequired": "You must provide an API key", + "components.Settings.SonarrModal.validationApplicationUrl": "You must provide a valid URL", + "components.Settings.SonarrModal.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash", "components.Settings.SonarrModal.validationHostnameRequired": "You must provide a hostname/IP", "components.Settings.SonarrModal.validationNameRequired": "You must provide a server name", "components.Settings.SonarrModal.validationPortRequired": "You must provide a port", @@ -502,6 +506,8 @@ "components.Settings.trustProxy": "Enable Proxy Support", "components.Settings.trustProxyTip": "Allows Overseerr to correctly register client IP addresses behind a proxy (Overseerr must be reloaded for changes to take effect)", "components.Settings.validationApplicationTitle": "You must provide an application title", + "components.Settings.validationApplicationUrl": "You must provide a valid URL", + "components.Settings.validationApplicationUrlTrailingSlash": "URL must not end in a trailing slash", "components.Settings.validationHostnameRequired": "You must provide a hostname/IP", "components.Settings.validationPortRequired": "You must provide a port", "components.Setup.configureplex": "Configure Plex",