refactor: Move integration search flag to categories (#1637)

This commit is contained in:
SeDemal
2024-12-18 14:14:31 +01:00
committed by GitHub
parent 63a7be35a4
commit 26b6ca2445
2 changed files with 10 additions and 65 deletions

View File

@@ -14,15 +14,16 @@ import {
} from "@homarr/db/schema/sqlite"; } from "@homarr/db/schema/sqlite";
import type { IntegrationSecretKind } from "@homarr/definitions"; import type { IntegrationSecretKind } from "@homarr/definitions";
import { import {
getIntegrationKindsByCategory,
getPermissionsWithParents, getPermissionsWithParents,
integrationDefs, integrationDefs,
integrationKinds, integrationKinds,
integrationSecretKindObject, integrationSecretKindObject,
isIntegrationWithSearchSupport,
} from "@homarr/definitions"; } from "@homarr/definitions";
import { integrationCreatorFromSecrets } from "@homarr/integrations"; import { integrationCreator } from "@homarr/integrations";
import { validation, z } from "@homarr/validation"; import { validation, z } from "@homarr/validation";
import { createOneIntegrationMiddleware } from "../../middlewares/integration";
import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../../trpc"; import { createTRPCRouter, permissionRequiredProcedure, protectedProcedure, publicProcedure } from "../../trpc";
import { throwIfActionForbiddenAsync } from "./integration-access"; import { throwIfActionForbiddenAsync } from "./integration-access";
import { testConnectionAsync } from "./integration-test-connection"; import { testConnectionAsync } from "./integration-test-connection";
@@ -90,7 +91,7 @@ export const integrationRouter = createTRPCRouter({
where: inArray( where: inArray(
integrations.kind, integrations.kind,
objectEntries(integrationDefs) objectEntries(integrationDefs)
.filter(([_, integration]) => integration.supportsSearch) .filter(([_, integration]) => [...integration.category].includes("search"))
.map(([kind, _]) => kind), .map(([kind, _]) => kind),
), ),
}); });
@@ -383,31 +384,11 @@ export const integrationRouter = createTRPCRouter({
}); });
}), }),
searchInIntegration: protectedProcedure searchInIntegration: protectedProcedure
.unstable_concat(createOneIntegrationMiddleware("query", ...getIntegrationKindsByCategory("search")))
.input(z.object({ integrationId: z.string(), query: z.string() })) .input(z.object({ integrationId: z.string(), query: z.string() }))
.query(async ({ ctx, input }) => { .query(async ({ ctx, input }) => {
const integration = await ctx.db.query.integrations.findFirst({ const integrationInstance = integrationCreator(ctx.integration);
where: eq(integrations.id, input.integrationId), return await integrationInstance.searchAsync(encodeURI(input.query));
with: {
secrets: true,
},
});
if (!integration) {
throw new TRPCError({
code: "NOT_FOUND",
message: "The requested integration does not exist",
});
}
if (!isIntegrationWithSearchSupport(integration)) {
throw new TRPCError({
code: "BAD_REQUEST",
message: "The requested integration does not support searching",
});
}
const integrationInstance = integrationCreatorFromSecrets(integration);
return await integrationInstance.searchAsync(input.query);
}), }),
}); });

View File

@@ -14,7 +14,6 @@ interface integrationDefinition {
iconUrl: string; iconUrl: string;
secretKinds: AtLeastOneOf<IntegrationSecretKind[]>; // at least one secret kind set is required secretKinds: AtLeastOneOf<IntegrationSecretKind[]>; // at least one secret kind set is required
category: AtLeastOneOf<IntegrationCategory>; category: AtLeastOneOf<IntegrationCategory>;
supportsSearch: boolean;
} }
export const integrationDefs = { export const integrationDefs = {
@@ -23,140 +22,120 @@ export const integrationDefs = {
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/sabnzbd.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/sabnzbd.png",
category: ["downloadClient", "usenet"], category: ["downloadClient", "usenet"],
supportsSearch: false,
}, },
nzbGet: { nzbGet: {
name: "NZBGet", name: "NZBGet",
secretKinds: [["username", "password"]], secretKinds: [["username", "password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/nzbget.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/nzbget.png",
category: ["downloadClient", "usenet"], category: ["downloadClient", "usenet"],
supportsSearch: false,
}, },
deluge: { deluge: {
name: "Deluge", name: "Deluge",
secretKinds: [["password"]], secretKinds: [["password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/deluge.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/deluge.png",
category: ["downloadClient", "torrent"], category: ["downloadClient", "torrent"],
supportsSearch: false,
}, },
transmission: { transmission: {
name: "Transmission", name: "Transmission",
secretKinds: [["username", "password"]], secretKinds: [["username", "password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/transmission.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/transmission.png",
category: ["downloadClient", "torrent"], category: ["downloadClient", "torrent"],
supportsSearch: false,
}, },
qBittorrent: { qBittorrent: {
name: "qBittorrent", name: "qBittorrent",
secretKinds: [["username", "password"]], secretKinds: [["username", "password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/qbittorrent.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/qbittorrent.png",
category: ["downloadClient", "torrent"], category: ["downloadClient", "torrent"],
supportsSearch: false,
}, },
sonarr: { sonarr: {
name: "Sonarr", name: "Sonarr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/sonarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/sonarr.png",
category: ["calendar"], category: ["calendar"],
supportsSearch: false,
}, },
radarr: { radarr: {
name: "Radarr", name: "Radarr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/radarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/radarr.png",
category: ["calendar"], category: ["calendar"],
supportsSearch: false,
}, },
lidarr: { lidarr: {
name: "Lidarr", name: "Lidarr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/lidarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/lidarr.png",
category: ["calendar"], category: ["calendar"],
supportsSearch: false,
}, },
readarr: { readarr: {
name: "Readarr", name: "Readarr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/readarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/readarr.png",
category: ["calendar"], category: ["calendar"],
supportsSearch: false,
}, },
prowlarr: { prowlarr: {
name: "Prowlarr", name: "Prowlarr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/prowlarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/prowlarr.png",
category: ["indexerManager"], category: ["indexerManager"],
supportsSearch: false,
}, },
jellyfin: { jellyfin: {
name: "Jellyfin", name: "Jellyfin",
secretKinds: [["username", "password"], ["apiKey"]], secretKinds: [["username", "password"], ["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/jellyfin.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/jellyfin.png",
category: ["mediaService"], category: ["mediaService"],
supportsSearch: false,
}, },
plex: { plex: {
name: "Plex", name: "Plex",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/plex.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/plex.png",
category: ["mediaService"], category: ["mediaService"],
supportsSearch: false,
}, },
jellyseerr: { jellyseerr: {
name: "Jellyseerr", name: "Jellyseerr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/jellyseerr.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/jellyseerr.png",
category: ["mediaSearch", "mediaRequest"], category: ["mediaSearch", "mediaRequest", "search"],
supportsSearch: true,
}, },
overseerr: { overseerr: {
name: "Overseerr", name: "Overseerr",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/overseerr.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/overseerr.png",
category: ["mediaSearch", "mediaRequest"], category: ["mediaSearch", "mediaRequest", "search"],
supportsSearch: true,
}, },
piHole: { piHole: {
name: "Pi-hole", name: "Pi-hole",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/pi-hole.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/pi-hole.png",
category: ["dnsHole"], category: ["dnsHole"],
supportsSearch: false,
}, },
adGuardHome: { adGuardHome: {
name: "AdGuard Home", name: "AdGuard Home",
secretKinds: [["username", "password"]], secretKinds: [["username", "password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/adguard-home.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/adguard-home.png",
category: ["dnsHole"], category: ["dnsHole"],
supportsSearch: false,
}, },
homeAssistant: { homeAssistant: {
name: "Home Assistant", name: "Home Assistant",
secretKinds: [["apiKey"]], secretKinds: [["apiKey"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/home-assistant.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/home-assistant.png",
category: ["smartHomeServer"], category: ["smartHomeServer"],
supportsSearch: false,
}, },
openmediavault: { openmediavault: {
name: "OpenMediaVault", name: "OpenMediaVault",
secretKinds: [["username", "password"]], secretKinds: [["username", "password"]],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/openmediavault.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/openmediavault.png",
category: ["healthMonitoring"], category: ["healthMonitoring"],
supportsSearch: false,
}, },
dashDot: { dashDot: {
name: "Dash.", name: "Dash.",
secretKinds: [[]], secretKinds: [[]],
category: ["healthMonitoring"], category: ["healthMonitoring"],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/dashdot.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/dashdot.png",
supportsSearch: false,
}, },
tdarr: { tdarr: {
name: "Tdarr", name: "Tdarr",
secretKinds: [[]], secretKinds: [[]],
category: ["mediaTranscoding"], category: ["mediaTranscoding"],
iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/tdarr.png", iconUrl: "https://cdn.jsdelivr.net/gh/walkxcode/dashboard-icons@master/png/tdarr.png",
supportsSearch: false,
}, },
} as const satisfies Record<string, integrationDefinition>; } as const satisfies Record<string, integrationDefinition>;
@@ -195,22 +174,6 @@ export type IntegrationKindByCategory<TCategory extends IntegrationCategory> = {
U U
: never; : never;
/**
* Checks if search is supported by the integration
* Uses a typescript guard with is to allow only integrations with search support within if statement
* @param integration integration with kind
* @returns true if the integration supports search
*/
export const isIntegrationWithSearchSupport = (integration: {
kind: IntegrationKind;
}): integration is { kind: IntegrationWithSearchSupport } => {
return integrationDefs[integration.kind].supportsSearch;
};
type IntegrationWithSearchSupport = {
[Key in keyof typeof integrationDefs]: true extends (typeof integrationDefs)[Key]["supportsSearch"] ? Key : never;
}[keyof typeof integrationDefs];
export type IntegrationSecretKind = keyof typeof integrationSecretKindObject; export type IntegrationSecretKind = keyof typeof integrationSecretKindObject;
export type IntegrationKind = keyof typeof integrationDefs; export type IntegrationKind = keyof typeof integrationDefs;
export type IntegrationCategory = export type IntegrationCategory =
@@ -225,4 +188,5 @@ export type IntegrationCategory =
| "smartHomeServer" | "smartHomeServer"
| "indexerManager" | "indexerManager"
| "healthMonitoring" | "healthMonitoring"
| "search"
| "mediaTranscoding"; | "mediaTranscoding";