feat: add pi hole summary integration (#521)

* feat: add pi hole summary integration

* feat: add pi hole summary widget

* fix: type issues with integrations and integrationIds

* feat: add middleware for integrations and improve cache redis channel

* feat: add error boundary for widgets

* fix: broken lock file

* fix: format format issues

* fix: typecheck issue

* fix: deepsource issues

* fix: widget sandbox without error boundary

* chore: address pull request feedback

* chore: remove todo comment and created issue

* fix: format issues

* fix: deepsource issue
This commit is contained in:
Meier Lukas
2024-05-26 17:13:34 +02:00
committed by GitHub
parent 96c71aed6e
commit d57b771a17
45 changed files with 902 additions and 124 deletions

View File

@@ -0,0 +1,76 @@
import { TRPCError } from "@trpc/server";
import { and, eq, inArray } from "@homarr/db";
import { integrations } from "@homarr/db/schema/sqlite";
import type { IntegrationKind } from "@homarr/definitions";
import { z } from "@homarr/validation";
import { decryptSecret } from "../router/integration";
import { publicProcedure } from "../trpc";
export const createOneIntegrationMiddleware = <TKind extends IntegrationKind>(...kinds: TKind[]) => {
return publicProcedure.input(z.object({ integrationId: z.string() })).use(async ({ input, ctx, next }) => {
const integration = await ctx.db.query.integrations.findFirst({
where: and(eq(integrations.id, input.integrationId), inArray(integrations.kind, kinds)),
with: {
secrets: true,
},
});
if (!integration) {
throw new TRPCError({
code: "NOT_FOUND",
message: `Integration with id ${input.integrationId} not found or not of kinds ${kinds.join(",")}`,
});
}
const { secrets, kind, ...rest } = integration;
return next({
ctx: {
integration: {
...rest,
kind: kind as TKind,
decryptedSecrets: secrets.map((secret) => ({
...secret,
value: decryptSecret(secret.value),
})),
},
},
});
});
};
export const createManyIntegrationMiddleware = <TKind extends IntegrationKind>(...kinds: TKind[]) => {
return publicProcedure
.input(z.object({ integrationIds: z.array(z.string()).min(1) }))
.use(async ({ ctx, input, next }) => {
const dbIntegrations = await ctx.db.query.integrations.findMany({
where: and(inArray(integrations.id, input.integrationIds), inArray(integrations.kind, kinds)),
with: {
secrets: true,
},
});
const offset = input.integrationIds.length - dbIntegrations.length;
if (offset !== 0) {
throw new TRPCError({
code: "NOT_FOUND",
message: `${offset} of the specified integrations not found or not of kinds ${kinds.join(",")}`,
});
}
return next({
ctx: {
integrations: dbIntegrations.map(({ secrets, kind, ...rest }) => ({
...rest,
kind: kind as TKind,
decryptedSecrets: secrets.map((secret) => ({
...secret,
value: decryptSecret(secret.value),
})),
})),
},
});
});
};