diff --git a/server/routers/external.ts b/server/routers/external.ts index 0d2186c0..13553b3f 100644 --- a/server/routers/external.ts +++ b/server/routers/external.ts @@ -307,6 +307,13 @@ authenticated.get( resource.listResources ); +authenticated.get( + "/org/:orgId/resource-names", + verifyOrgAccess, + verifyUserHasAction(ActionsEnum.listResources), + resource.listAllResourceNames +); + authenticated.get( "/org/:orgId/user-resources", verifyOrgAccess, diff --git a/server/routers/resource/index.ts b/server/routers/resource/index.ts index d1c7011d..687195c9 100644 --- a/server/routers/resource/index.ts +++ b/server/routers/resource/index.ts @@ -25,3 +25,4 @@ export * from "./getUserResources"; export * from "./setResourceHeaderAuth"; export * from "./addEmailToResourceWhitelist"; export * from "./removeEmailFromResourceWhitelist"; +export * from "./listAllResourceNames"; diff --git a/server/routers/resource/listAllResourceNames.ts b/server/routers/resource/listAllResourceNames.ts new file mode 100644 index 00000000..80b21fd4 --- /dev/null +++ b/server/routers/resource/listAllResourceNames.ts @@ -0,0 +1,90 @@ +import { Request, Response, NextFunction } from "express"; +import { z } from "zod"; +import { db, resourceHeaderAuth } from "@server/db"; +import { + resources, + userResources, + roleResources, + resourcePassword, + resourcePincode, + targets, + targetHealthCheck +} from "@server/db"; +import response from "@server/lib/response"; +import HttpCode from "@server/types/HttpCode"; +import createHttpError from "http-errors"; +import { sql, eq, or, inArray, and, count } from "drizzle-orm"; +import logger from "@server/logger"; +import { fromZodError } from "zod-validation-error"; +import { OpenAPITags, registry } from "@server/openApi"; +import type { + ResourceWithTargets, + ListResourcesResponse +} from "./listResources"; + +const listResourcesParamsSchema = z.strictObject({ + orgId: z.string() +}); + +function queryResourceNames(orgId: string) { + return db + .select({ + resourceId: resources.resourceId, + name: resources.name + }) + .from(resources) + + .where(eq(resources.orgId, orgId)); +} + +export type ListResourceNamesResponse = Awaited< + ReturnType +>; + +registry.registerPath({ + method: "get", + path: "/org/{orgId}/resources-names", + description: "List all resource names for an organization.", + tags: [OpenAPITags.Org, OpenAPITags.Resource], + request: { + params: z.object({ + orgId: z.string() + }) + }, + responses: {} +}); + +export async function listAllResourceNames( + req: Request, + res: Response, + next: NextFunction +): Promise { + try { + const parsedParams = listResourcesParamsSchema.safeParse(req.params); + if (!parsedParams.success) { + return next( + createHttpError( + HttpCode.BAD_REQUEST, + fromZodError(parsedParams.error) + ) + ); + } + + const orgId = parsedParams.data.orgId; + + const data = await queryResourceNames(orgId); + + return response(res, { + data, + success: true, + error: false, + message: "Resource Names retrieved successfully", + status: HttpCode.OK + }); + } catch (error) { + logger.error(error); + return next( + createHttpError(HttpCode.INTERNAL_SERVER_ERROR, "An error occurred") + ); + } +} diff --git a/server/routers/resource/listResources.ts b/server/routers/resource/listResources.ts index a72dd763..1c8f0864 100644 --- a/server/routers/resource/listResources.ts +++ b/server/routers/resource/listResources.ts @@ -8,21 +8,19 @@ import { resourcePassword, resourcePincode, targets, - targetHealthCheck, + targetHealthCheck } from "@server/db"; import response from "@server/lib/response"; import HttpCode from "@server/types/HttpCode"; import createHttpError from "http-errors"; import { sql, eq, or, inArray, and, count } from "drizzle-orm"; import logger from "@server/logger"; -import stoi from "@server/lib/stoi"; import { fromZodError } from "zod-validation-error"; import { OpenAPITags, registry } from "@server/openApi"; -import { warn } from "console"; const listResourcesParamsSchema = z.strictObject({ - orgId: z.string() - }); + orgId: z.string() +}); const listResourcesSchema = z.object({ limit: z @@ -67,7 +65,7 @@ type JoinedRow = { hcEnabled: boolean | null; }; -// grouped by resource with targets[]) +// grouped by resource with targets[]) export type ResourceWithTargets = { resourceId: number; name: string; @@ -89,7 +87,7 @@ export type ResourceWithTargets = { ip: string; port: number; enabled: boolean; - healthStatus?: 'healthy' | 'unhealthy' | 'unknown'; + healthStatus?: "healthy" | "unhealthy" | "unknown"; }>; }; @@ -118,7 +116,7 @@ function queryResources(accessibleResourceIds: number[], orgId: string) { targetEnabled: targets.enabled, hcHealth: targetHealthCheck.hcHealth, - hcEnabled: targetHealthCheck.hcEnabled, + hcEnabled: targetHealthCheck.hcEnabled }) .from(resources) .leftJoin( @@ -273,16 +271,25 @@ export async function listResources( enabled: row.enabled, domainId: row.domainId, headerAuthId: row.headerAuthId, - targets: [], + targets: [] }; map.set(row.resourceId, entry); } - if (row.targetId != null && row.targetIp && row.targetPort != null && row.targetEnabled != null) { - let healthStatus: 'healthy' | 'unhealthy' | 'unknown' = 'unknown'; + if ( + row.targetId != null && + row.targetIp && + row.targetPort != null && + row.targetEnabled != null + ) { + let healthStatus: "healthy" | "unhealthy" | "unknown" = + "unknown"; if (row.hcEnabled && row.hcHealth) { - healthStatus = row.hcHealth as 'healthy' | 'unhealthy' | 'unknown'; + healthStatus = row.hcHealth as + | "healthy" + | "unhealthy" + | "unknown"; } entry.targets.push({ @@ -290,7 +297,7 @@ export async function listResources( ip: row.targetIp, port: row.targetPort, enabled: row.targetEnabled, - healthStatus: healthStatus, + healthStatus: healthStatus }); } }