diff --git a/src/pages/api/modules/calendar.ts b/src/pages/api/modules/calendar.ts index e892ae6f9..3f0169ec3 100644 --- a/src/pages/api/modules/calendar.ts +++ b/src/pages/api/modules/calendar.ts @@ -5,8 +5,9 @@ import Consola from 'consola'; import { NextApiRequest, NextApiResponse } from 'next'; import { z } from 'zod'; -import { AppIntegrationType } from '../../../types/app'; +import { AppIntegrationType, IntegrationType } from '../../../types/app'; import { getConfig } from '../../../tools/config/getConfig'; +import { checkIntegrationsType } from '~/tools/client/app-properties'; export default async (req: NextApiRequest, res: NextApiResponse) => { // Filter out if the reuqest is a POST or a GET @@ -51,14 +52,14 @@ async function Get(req: NextApiRequest, res: NextApiResponse) { const calendar = config.widgets.find((w) => w.type === 'calendar' && w.id === widgetId); const useSonarrv4 = calendar?.properties.useSonarrv4 ?? false; - const mediaAppIntegrationTypes: AppIntegrationType['type'][] = [ + const mediaAppIntegrationTypes = [ 'sonarr', 'radarr', 'readarr', 'lidarr', - ]; - const mediaApps = config.apps.filter( - (app) => app.integration && mediaAppIntegrationTypes.includes(app.integration.type) + ] as const satisfies readonly IntegrationType[]; + const mediaApps = config.apps.filter((app) => + checkIntegrationsType(app.integration, mediaAppIntegrationTypes) ); const IntegrationTypeEndpointMap = new Map([ diff --git a/src/pages/api/modules/downloads/index.ts b/src/pages/api/modules/downloads/index.ts index d49290039..442da77d5 100644 --- a/src/pages/api/modules/downloads/index.ts +++ b/src/pages/api/modules/downloads/index.ts @@ -22,6 +22,7 @@ import { NormalizedDownloadAppStat, NormalizedDownloadQueueResponse, } from '../../../../types/api/downloads/queue/NormalizedDownloadQueueResponse'; +import { findAppProperty } from '~/tools/client/app-properties'; const Get = async (request: NextApiRequest, response: NextApiResponse) => { const configName = getCookie('config-name', { req: request }); @@ -151,8 +152,8 @@ const GetDataFromClient = async ( const options = { host: url.hostname, port: url.port, - login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, - hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined, + login: findAppProperty(app, 'username'), + hash: findAppProperty(app, 'password'), }; const nzbGet = NzbgetClient(options); diff --git a/src/pages/api/modules/media-requests/index.ts b/src/pages/api/modules/media-requests/index.ts index 48d13a738..9e9c0e866 100644 --- a/src/pages/api/modules/media-requests/index.ts +++ b/src/pages/api/modules/media-requests/index.ts @@ -5,13 +5,14 @@ import { getConfig } from '../../../../tools/config/getConfig'; import { MediaRequest } from '../../../../widgets/media-requests/media-request-types'; import { MediaRequestListWidget } from '../../../../widgets/media-requests/MediaRequestListTile'; +import { checkIntegrationsType } from '~/tools/client/app-properties'; const Get = async (request: NextApiRequest, response: NextApiResponse) => { const configName = getCookie('config-name', { req: request }); const config = getConfig(configName?.toString() ?? 'default'); const apps = config.apps.filter((app) => - ['overseerr', 'jellyseerr'].includes(app.integration?.type ?? '') + checkIntegrationsType(app.integration, ['overseerr', 'jellyseerr']) ); Consola.log(`Retrieving media requests from ${apps.length} apps`); @@ -24,11 +25,12 @@ const Get = async (request: NextApiRequest, response: NextApiResponse) => { }) .then(async (response) => { const body = (await response.json()) as OverseerrResponse; - const mediaWidget = config.widgets.find( - (x) => x.type === 'media-requests-list') as MediaRequestListWidget | undefined; + const mediaWidget = config.widgets.find((x) => x.type === 'media-requests-list') as + | MediaRequestListWidget + | undefined; if (!mediaWidget) { - Consola.log('No media-requests-list found'); - return Promise.resolve([]); + Consola.log('No media-requests-list found'); + return Promise.resolve([]); } const appUrl = mediaWidget.properties.replaceLinksWithExternalHost ? app.behaviour.externalUrl diff --git a/src/pages/api/modules/media-server/index.ts b/src/pages/api/modules/media-server/index.ts index 9085c02bc..f1bee1f55 100644 --- a/src/pages/api/modules/media-server/index.ts +++ b/src/pages/api/modules/media-server/index.ts @@ -18,6 +18,7 @@ import { GenericSessionInfo, } from '../../../../types/api/media-server/session-info'; import { PlexClient } from '../../../../tools/server/sdk/plex/plexClient'; +import { checkIntegrationsType, findAppProperty } from '~/tools/client/app-properties'; const jellyfin = new Jellyfin({ clientInfo: { @@ -35,7 +36,7 @@ const Get = async (request: NextApiRequest, response: NextApiResponse) => { const config = getConfig(configName?.toString() ?? 'default'); const apps = config.apps.filter((app) => - ['jellyfin', 'plex'].includes(app.integration?.type ?? '') + checkIntegrationsType(app.integration, ['jellyfin', 'plex']) ); const servers = await Promise.all( @@ -66,9 +67,9 @@ const Get = async (request: NextApiRequest, response: NextApiResponse) => { const handleServer = async (app: ConfigAppType): Promise => { switch (app.integration?.type) { case 'jellyfin': { - const username = app.integration.properties.find((x) => x.field === 'username'); + const username = findAppProperty(app, 'username'); - if (!username || !username.value) { + if (!username) { return { appId: app.id, serverAddress: app.url, @@ -79,9 +80,9 @@ const handleServer = async (app: ConfigAppType): Promise x.field === 'password'); + const password = findAppProperty(app, 'password'); - if (!password || !password.value) { + if (!password) { return { appId: app.id, serverAddress: app.url, @@ -94,7 +95,7 @@ const handleServer = async (app: ConfigAppType): Promise x.field === 'apiKey'); + const apiKey = findAppProperty(app, 'apiKey'); - if (!apiKey || !apiKey.value) { + if (!apiKey) { return { serverAddress: app.url, sessions: [], @@ -179,7 +180,7 @@ const handleServer = async (app: ConfigAppType): Promise x.field === 'username')?.value ?? undefined, - hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined, + login: findAppProperty(app, 'username'), + hash: findAppProperty(app, 'password'), }; const nzbGet = NzbgetClient(options); @@ -77,7 +78,7 @@ async function Get(req: NextApiRequest, res: NextApiResponse) { case 'sabnzbd': { const { origin } = new URL(app.url); - const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value; + const apiKey = findAppProperty(app, 'apiKey'); if (!apiKey) { throw new Error(`API Key for app "${app.name}" is missing`); } diff --git a/src/pages/api/modules/usenet/index.ts b/src/pages/api/modules/usenet/index.ts index bf539c38f..13f84b0f8 100644 --- a/src/pages/api/modules/usenet/index.ts +++ b/src/pages/api/modules/usenet/index.ts @@ -6,6 +6,7 @@ import { Client } from 'sabnzbd-api'; import { getConfig } from '../../../../tools/config/getConfig'; import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client'; import { NzbgetStatus } from '../../../../server/api/routers/usenet/nzbget/types'; +import { findAppProperty } from '~/tools/client/app-properties'; dayjs.extend(duration); @@ -39,8 +40,8 @@ async function Get(req: NextApiRequest, res: NextApiResponse) { const options = { host: url.hostname, port: url.port || (url.protocol === 'https:' ? '443' : '80'), - login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, - hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined, + login: findAppProperty(app, 'username'), + hash: findAppProperty(app, 'password'), }; const nzbGet = NzbgetClient(options); @@ -70,7 +71,7 @@ async function Get(req: NextApiRequest, res: NextApiResponse) { break; } case 'sabnzbd': { - const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value; + const apiKey = findAppProperty(app, 'apiKey'); if (!apiKey) { throw new Error(`API Key for app "${app.name}" is missing`); } diff --git a/src/pages/api/modules/usenet/pause.ts b/src/pages/api/modules/usenet/pause.ts index 4faef1ba3..c6d4fe1f3 100644 --- a/src/pages/api/modules/usenet/pause.ts +++ b/src/pages/api/modules/usenet/pause.ts @@ -5,6 +5,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { Client } from 'sabnzbd-api'; import { getConfig } from '../../../../tools/config/getConfig'; import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client'; +import { findAppProperty } from '~/tools/client/app-properties'; dayjs.extend(duration); @@ -31,8 +32,8 @@ async function Post(req: NextApiRequest, res: NextApiResponse) { const options = { host: url.hostname, port: url.port || (url.protocol === 'https:' ? '443' : '80'), - login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, - hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined, + login: findAppProperty(app, 'username'), + hash: findAppProperty(app, 'password'), }; const nzbGet = NzbgetClient(options); @@ -49,7 +50,7 @@ async function Post(req: NextApiRequest, res: NextApiResponse) { break; } case 'sabnzbd': { - const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value; + const apiKey = findAppProperty(app, 'apiKey'); if (!apiKey) { throw new Error(`API Key for app "${app.name}" is missing`); } diff --git a/src/pages/api/modules/usenet/queue.ts b/src/pages/api/modules/usenet/queue.ts index 1dc3d84e8..c52c59fc6 100644 --- a/src/pages/api/modules/usenet/queue.ts +++ b/src/pages/api/modules/usenet/queue.ts @@ -7,6 +7,7 @@ import { getConfig } from '../../../../tools/config/getConfig'; import { UsenetQueueItem } from '../../../../widgets/useNet/types'; import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client'; import { NzbgetQueueItem, NzbgetStatus } from '../../../../server/api/routers/usenet/nzbget/types'; +import { findAppProperty } from '~/tools/client/app-properties'; dayjs.extend(duration); @@ -40,8 +41,8 @@ async function Get(req: NextApiRequest, res: NextApiResponse) { const options = { host: url.hostname, port: url.port || (url.protocol === 'https:' ? '443' : '80'), - login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, - hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined, + login: findAppProperty(app, 'username'), + hash: findAppProperty(app, 'password'), }; const nzbGet = NzbgetClient(options); @@ -91,7 +92,7 @@ async function Get(req: NextApiRequest, res: NextApiResponse) { break; } case 'sabnzbd': { - const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value; + const apiKey = findAppProperty(app, 'apiKey'); if (!apiKey) { throw new Error(`API Key for app "${app.name}" is missing`); } diff --git a/src/pages/api/modules/usenet/resume.ts b/src/pages/api/modules/usenet/resume.ts index 17afa9fe7..7df66b824 100644 --- a/src/pages/api/modules/usenet/resume.ts +++ b/src/pages/api/modules/usenet/resume.ts @@ -5,6 +5,7 @@ import { NextApiRequest, NextApiResponse } from 'next'; import { Client } from 'sabnzbd-api'; import { getConfig } from '../../../../tools/config/getConfig'; import { NzbgetClient } from '../../../../server/api/routers/usenet/nzbget/nzbget-client'; +import { findAppProperty } from '~/tools/client/app-properties'; dayjs.extend(duration); @@ -32,8 +33,8 @@ async function Post(req: NextApiRequest, res: NextApiResponse) { const options = { host: url.hostname, port: url.port || (url.protocol === 'https:' ? '443' : '80'), - login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, - hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined, + login: findAppProperty(app, 'username'), + hash: findAppProperty(app, 'password'), }; const nzbGet = NzbgetClient(options); @@ -50,7 +51,7 @@ async function Post(req: NextApiRequest, res: NextApiResponse) { break; } case 'sabnzbd': { - const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value; + const apiKey = findAppProperty(app, 'apiKey'); if (!apiKey) { throw new Error(`API Key for app "${app.name}" is missing`); } diff --git a/src/server/api/root.ts b/src/server/api/root.ts index e3731c3aa..5395df87d 100644 --- a/src/server/api/root.ts +++ b/src/server/api/root.ts @@ -10,7 +10,7 @@ import { downloadRouter } from './routers/download'; import { mediaRequestsRouter } from './routers/media-request'; import { mediaServerRouter } from './routers/media-server'; import { overseerrRouter } from './routers/overseerr'; -import { usenetRouter } from './routers/usenet/route'; +import { usenetRouter } from './routers/usenet/router'; import { calendarRouter } from './routers/calendar'; /** diff --git a/src/server/api/routers/calendar.ts b/src/server/api/routers/calendar.ts index 42761c073..2b83a6d79 100644 --- a/src/server/api/routers/calendar.ts +++ b/src/server/api/routers/calendar.ts @@ -2,8 +2,9 @@ import axios from 'axios'; import Consola from 'consola'; import { z } from 'zod'; import { getConfig } from '~/tools/config/getConfig'; -import { AppIntegrationType } from '~/types/app'; +import { AppIntegrationType, IntegrationType } from '~/types/app'; import { createTRPCRouter, publicProcedure } from '../trpc'; +import { checkIntegrationsType } from '~/tools/client/app-properties'; export const calendarRouter = createTRPCRouter({ medias: publicProcedure @@ -21,14 +22,14 @@ export const calendarRouter = createTRPCRouter({ const { configName, month, year, options } = input; const config = getConfig(configName); - const mediaAppIntegrationTypes: AppIntegrationType['type'][] = [ + const mediaAppIntegrationTypes = [ 'sonarr', 'radarr', 'readarr', 'lidarr', - ]; - const mediaApps = config.apps.filter( - (app) => app.integration && mediaAppIntegrationTypes.includes(app.integration.type) + ] as const satisfies readonly IntegrationType[]; + const mediaApps = config.apps.filter((app) => + checkIntegrationsType(app.integration, mediaAppIntegrationTypes) ); const integrationTypeEndpointMap = new Map([ diff --git a/src/server/api/routers/download.ts b/src/server/api/routers/download.ts index c1171f50c..654a58f88 100644 --- a/src/server/api/routers/download.ts +++ b/src/server/api/routers/download.ts @@ -16,6 +16,7 @@ import { import { ConfigAppType, IntegrationField } from '~/types/app'; import { UsenetQueueItem } from '~/widgets/useNet/types'; import { createTRPCRouter, publicProcedure } from '../trpc'; +import { findAppProperty } from '~/tools/client/app-properties'; export const downloadRouter = createTRPCRouter({ get: publicProcedure @@ -155,8 +156,8 @@ const GetDataFromClient = async ( const options = { host: url.hostname, port: url.port, - login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, - hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined, + login: findAppProperty(app, 'username'), + hash: findAppProperty(app, 'password'), }; const nzbGet = NzbgetClient(options); diff --git a/src/server/api/routers/media-request.ts b/src/server/api/routers/media-request.ts index daf69aa20..c68227730 100644 --- a/src/server/api/routers/media-request.ts +++ b/src/server/api/routers/media-request.ts @@ -4,6 +4,7 @@ import { getConfig } from '~/tools/config/getConfig'; import { MediaRequest } from '~/widgets/media-requests/media-request-types'; import { createTRPCRouter, publicProcedure } from '../trpc'; import { MediaRequestListWidget } from '~/widgets/media-requests/MediaRequestListTile'; +import { checkIntegrationsType } from '~/tools/client/app-properties'; export const mediaRequestsRouter = createTRPCRouter({ all: publicProcedure @@ -16,7 +17,7 @@ export const mediaRequestsRouter = createTRPCRouter({ const config = getConfig(input.configName); const apps = config.apps.filter((app) => - ['overseerr', 'jellyseerr'].includes(app.integration?.type ?? '') + checkIntegrationsType(app.integration, ['overseerr', 'jellyseerr']) ); Consola.log(`Retrieving media requests from ${apps.length} apps`); diff --git a/src/server/api/routers/media-server.ts b/src/server/api/routers/media-server.ts index f645fe62b..7a70a76d7 100644 --- a/src/server/api/routers/media-server.ts +++ b/src/server/api/routers/media-server.ts @@ -11,6 +11,7 @@ import { MediaServersResponseType } from '~/types/api/media-server/response'; import { GenericCurrentlyPlaying, GenericSessionInfo } from '~/types/api/media-server/session-info'; import { ConfigAppType } from '~/types/app'; import { createTRPCRouter, publicProcedure } from '../trpc'; +import { checkIntegrationsType, findAppProperty } from '~/tools/client/app-properties'; const jellyfin = new Jellyfin({ clientInfo: { @@ -34,7 +35,7 @@ export const mediaServerRouter = createTRPCRouter({ const config = getConfig(input.configName); const apps = config.apps.filter((app) => - ['jellyfin', 'plex'].includes(app.integration?.type ?? '') + checkIntegrationsType(app.integration, ['jellyfin', 'plex']) ); const servers = await Promise.all( @@ -68,9 +69,9 @@ export const mediaServerRouter = createTRPCRouter({ const handleServer = async (app: ConfigAppType): Promise => { switch (app.integration?.type) { case 'jellyfin': { - const username = app.integration.properties.find((x) => x.field === 'username'); + const username = findAppProperty(app, 'username'); - if (!username || !username.value) { + if (!username) { return { appId: app.id, serverAddress: app.url, @@ -81,9 +82,9 @@ const handleServer = async (app: ConfigAppType): Promise x.field === 'password'); + const password = findAppProperty(app, 'password'); - if (!password || !password.value) { + if (!password) { return { appId: app.id, serverAddress: app.url, @@ -96,7 +97,7 @@ const handleServer = async (app: ConfigAppType): Promise x.field === 'apiKey'); + const apiKey = findAppProperty(app, 'apiKey'); - if (!apiKey || !apiKey.value) { + if (!apiKey) { return { serverAddress: app.url, sessions: [], @@ -181,7 +182,7 @@ const handleServer = async (app: ConfigAppType): Promise x.id === input.appId); - if (!app || (app.integration?.type !== 'nzbGet' && app.integration?.type !== 'sabnzbd')) { + if (!app || !checkIntegrationsType(app.integration, ['nzbGet', 'sabnzbd'])) { throw new TRPCError({ code: 'BAD_REQUEST', message: `App with ID "${input.appId}" could not be found.`, }); } - if (app.integration?.type === 'nzbGet') { + if (app.integration.type === 'nzbGet') { const url = new URL(app.url); const options = { host: url.hostname, port: url.port || (url.protocol === 'https:' ? '443' : '80'), - login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, - hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined, + login: findAppProperty(app, 'username'), + hash: findAppProperty(app, 'password'), }; const nzbGet = NzbgetClient(options); @@ -70,7 +71,7 @@ export const usenetRouter = createTRPCRouter({ }; } - const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value; + const apiKey = findAppProperty(app, 'apiKey'); if (!apiKey) { throw new TRPCError({ code: 'BAD_REQUEST', @@ -110,17 +111,17 @@ export const usenetRouter = createTRPCRouter({ const app = config.apps.find((x) => x.id === input.appId); - if (!app || (app.integration?.type !== 'nzbGet' && app.integration?.type !== 'sabnzbd')) { + if (!app || !checkIntegrationsType(app.integration, ['nzbGet', 'sabnzbd'])) { throw new Error(`App with ID "${input.appId}" could not be found.`); } - if (app.integration?.type === 'nzbGet') { + if (app.integration.type === 'nzbGet') { const url = new URL(app.url); const options = { host: url.hostname, port: url.port || (url.protocol === 'https:' ? '443' : '80'), - login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, - hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined, + login: findAppProperty(app, 'username'), + hash: findAppProperty(app, 'password'), }; const nzbGet = NzbgetClient(options); @@ -155,7 +156,7 @@ export const usenetRouter = createTRPCRouter({ const { origin } = new URL(app.url); - const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value; + const apiKey = findAppProperty(app, 'apiKey'); if (!apiKey) { throw new Error(`API Key for app "${app.name}" is missing`); } @@ -185,7 +186,7 @@ export const usenetRouter = createTRPCRouter({ const config = getConfig(input.configName); const app = config.apps.find((x) => x.id === input.appId); - if (!app || (app.integration?.type !== 'nzbGet' && app.integration?.type !== 'sabnzbd')) { + if (!app || !checkIntegrationsType(app.integration, ['nzbGet', 'sabnzbd'])) { throw new Error(`App with ID "${input.appId}" could not be found.`); } @@ -194,8 +195,8 @@ export const usenetRouter = createTRPCRouter({ const options = { host: url.hostname, port: url.port || (url.protocol === 'https:' ? '443' : '80'), - login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, - hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined, + login: findAppProperty(app, 'username'), + hash: findAppProperty(app, 'password'), }; const nzbGet = NzbgetClient(options); @@ -211,7 +212,7 @@ export const usenetRouter = createTRPCRouter({ }); } - const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value; + const apiKey = findAppProperty(app, 'apiKey'); if (!apiKey) { throw new Error(`API Key for app "${app.name}" is missing`); } @@ -232,7 +233,7 @@ export const usenetRouter = createTRPCRouter({ const app = config.apps.find((x) => x.id === input.appId); - if (!app || (app.integration?.type !== 'nzbGet' && app.integration?.type !== 'sabnzbd')) { + if (!app || !checkIntegrationsType(app.integration, ['nzbGet', 'sabnzbd'])) { throw new Error(`App with ID "${input.appId}" could not be found.`); } @@ -241,8 +242,8 @@ export const usenetRouter = createTRPCRouter({ const options = { host: url.hostname, port: url.port || (url.protocol === 'https:' ? '443' : '80'), - login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, - hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined, + login: findAppProperty(app, 'username'), + hash: findAppProperty(app, 'password'), }; const nzbGet = NzbgetClient(options); @@ -258,7 +259,7 @@ export const usenetRouter = createTRPCRouter({ }); } - const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value; + const apiKey = findAppProperty(app, 'apiKey'); if (!apiKey) { throw new Error(`API Key for app "${app.name}" is missing`); } @@ -281,7 +282,7 @@ export const usenetRouter = createTRPCRouter({ const app = config.apps.find((x) => x.id === input.appId); - if (!app || (app.integration?.type !== 'nzbGet' && app.integration?.type !== 'sabnzbd')) { + if (!app || !checkIntegrationsType(app.integration, ['nzbGet', 'sabnzbd'])) { throw new Error(`App with ID "${input.appId}" could not be found.`); } @@ -290,8 +291,8 @@ export const usenetRouter = createTRPCRouter({ const options = { host: url.hostname, port: url.port || (url.protocol === 'https:' ? '443' : '80'), - login: app.integration.properties.find((x) => x.field === 'username')?.value ?? undefined, - hash: app.integration.properties.find((x) => x.field === 'password')?.value ?? undefined, + login: findAppProperty(app, 'username'), + hash: findAppProperty(app, 'password'), }; const nzbGet = NzbgetClient(options); @@ -340,7 +341,7 @@ export const usenetRouter = createTRPCRouter({ }; } - const apiKey = app.integration.properties.find((x) => x.field === 'apiKey')?.value; + const apiKey = findAppProperty(app, 'apiKey'); if (!apiKey) { throw new Error(`API Key for app "${app.name}" is missing`); } diff --git a/src/tools/client/app-properties.ts b/src/tools/client/app-properties.ts index a53b38dbf..9965fa984 100644 --- a/src/tools/client/app-properties.ts +++ b/src/tools/client/app-properties.ts @@ -1,4 +1,27 @@ -import { ConfigAppType, IntegrationField } from '../../types/app'; +import { ConfigAppType, IntegrationField, IntegrationType } from '../../types/app'; export const findAppProperty = (app: ConfigAppType, key: IntegrationField) => app.integration?.properties.find((prop) => prop.field === key)?.value ?? ''; + +/** Checks if the type of an integration is part of the TIntegrations array with propper typing */ +export const checkIntegrationsType = < + TTest extends CheckIntegrationTypeInput, + TIntegrations extends readonly IntegrationType[] +>( + test: TTest | undefined | null, + integrations: TIntegrations +): test is CheckIntegrationType => { + if (!test) return false; + return integrations.includes(test.type!); +}; + +type CheckIntegrationTypeInput = { + type: IntegrationType | null; +}; + +type CheckIntegrationType< + TInput extends CheckIntegrationTypeInput, + TIntegrations extends readonly IntegrationType[] +> = TInput & { + type: TIntegrations[number]; +};