diff --git a/server/routers/org/applyBlueprint.ts b/server/routers/blueprints/applyJSONBlueprint.ts similarity index 80% rename from server/routers/org/applyBlueprint.ts rename to server/routers/blueprints/applyJSONBlueprint.ts index 982258ee..6860307b 100644 --- a/server/routers/org/applyBlueprint.ts +++ b/server/routers/blueprints/applyJSONBlueprint.ts @@ -1,30 +1,12 @@ import { Request, Response, NextFunction } from "express"; import { z } from "zod"; -import { db } from "@server/db"; -import { eq } from "drizzle-orm"; -import { - apiKeyOrg, - apiKeys, - domains, - Org, - orgDomains, - orgs, - roleActions, - roles, - userOrgs, - users, - actions -} from "@server/db"; import response from "@server/lib/response"; import HttpCode from "@server/types/HttpCode"; import createHttpError from "http-errors"; import logger from "@server/logger"; -import config from "@server/lib/config"; import { fromError } from "zod-validation-error"; -import { defaultRoleAllowedActions } from "../role"; import { OpenAPITags, registry } from "@server/openApi"; -import { isValidCIDR } from "@server/lib/validators"; -import { applyBlueprint as applyBlueprintFunc } from "@server/lib/blueprints/applyBlueprint"; +import { applyBlueprint } from "@server/lib/blueprints/applyBlueprint"; const applyBlueprintSchema = z .object({ @@ -41,8 +23,8 @@ const applyBlueprintParamsSchema = z registry.registerPath({ method: "put", path: "/org/{orgId}/blueprint", - description: "Apply a base64 encoded blueprint to an organization", - tags: [OpenAPITags.Org], + description: "Apply a base64 encoded JSON blueprint to an organization", + tags: [OpenAPITags.Org, OpenAPITags.Blueprint], request: { params: applyBlueprintParamsSchema, body: { @@ -56,7 +38,7 @@ registry.registerPath({ responses: {} }); -export async function applyBlueprint( +export async function applyJSONBlueprint( req: Request, res: Response, next: NextFunction @@ -100,7 +82,11 @@ export async function applyBlueprint( const blueprintParsed = JSON.parse(decoded); // Update the blueprint in the database - await applyBlueprintFunc(orgId, blueprintParsed); + await applyBlueprint({ + orgId, + configData: blueprintParsed, + source: "API" + }); } catch (error) { logger.error(`Failed to update database from config: ${error}`); return next( diff --git a/server/routers/blueprints/createAndApplyBlueprint.ts b/server/routers/blueprints/applyYAMLBlueprint.ts similarity index 71% rename from server/routers/blueprints/createAndApplyBlueprint.ts rename to server/routers/blueprints/applyYAMLBlueprint.ts index 55867fce..307f4851 100644 --- a/server/routers/blueprints/createAndApplyBlueprint.ts +++ b/server/routers/blueprints/applyYAMLBlueprint.ts @@ -7,15 +7,14 @@ import createHttpError from "http-errors"; import HttpCode from "@server/types/HttpCode"; import { fromZodError } from "zod-validation-error"; import response from "@server/lib/response"; -import { type Blueprint, blueprints, db, loginPage } from "@server/db"; +import { type Blueprint } from "@server/db"; import { parse as parseYaml } from "yaml"; import { ConfigSchema } from "@server/lib/blueprints/types"; -import { BlueprintSource } from "./types"; const applyBlueprintSchema = z .object({ name: z.string().min(1).max(255), - contents: z + blueprint: z .string() .min(1) .superRefine((val, ctx) => { @@ -40,10 +39,9 @@ const applyBlueprintParamsSchema = z export type CreateBlueprintResponse = Blueprint; registry.registerPath({ - method: "post", + method: "put", path: "/org/{orgId}/blueprint", - description: - "Create and Apply a base64 encoded blueprint to an organization", + description: "Create and apply a YAML blueprint to an organization", tags: [OpenAPITags.Org, OpenAPITags.Blueprint], request: { params: applyBlueprintParamsSchema, @@ -58,7 +56,7 @@ registry.registerPath({ responses: {} }); -export async function createAndApplyBlueprint( +export async function applyYAMLBlueprint( req: Request, res: Response, next: NextFunction @@ -86,7 +84,7 @@ export async function createAndApplyBlueprint( ); } - const { contents, name } = parsedBody.data; + const { blueprint: contents, name } = parsedBody.data; logger.debug(`Received blueprint:`, contents); @@ -102,42 +100,26 @@ export async function createAndApplyBlueprint( ); } - let blueprintSucceeded: boolean; - let blueprintMessage: string; + let blueprint: Blueprint | null = null; try { - await applyBlueprint(orgId, parsedConfig); - blueprintSucceeded = true; - blueprintMessage = "success"; + blueprint = await applyBlueprint({ + orgId, + name, + source: "UI", + configData: parsedConfig + }); } catch (error) { - blueprintSucceeded = false; - blueprintMessage = `Failed to update blueprint from config: ${error}`; - logger.error(blueprintMessage); + // We do nothing, the error is thrown for the other APIs & websockets for backwards compatibility + // for this API, the error is already saved in the blueprint and we don't need to handle it + logger.error(error); } - let blueprint: Blueprint | null = null; - await db.transaction(async (trx) => { - const newBlueprint = await trx - .insert(blueprints) - .values({ - orgId, - name, - contents, - createdAt: Math.floor(Date.now() / 1000), - succeeded: blueprintSucceeded, - message: blueprintMessage, - source: "UI" as BlueprintSource - }) - .returning(); - - blueprint = newBlueprint[0]; - }); - if (!blueprint) { return next( createHttpError( HttpCode.INTERNAL_SERVER_ERROR, - "Failed to create resource" + "Failed to save blueprint in the database" ) ); } @@ -146,9 +128,9 @@ export async function createAndApplyBlueprint( data: blueprint, success: true, error: false, - message: blueprintSucceeded + message: blueprint.succeeded ? "Blueprint applied with success" - : `Blueprint applied with errors: ${blueprintMessage}`, + : `Blueprint applied with errors: ${blueprint.message}`, status: HttpCode.CREATED }); } catch (error) { diff --git a/server/routers/blueprints/index.ts b/server/routers/blueprints/index.ts index f182b02f..dddc6063 100644 --- a/server/routers/blueprints/index.ts +++ b/server/routers/blueprints/index.ts @@ -1,3 +1,4 @@ export * from "./listBlueprints"; -export * from "./createAndApplyBlueprint"; +export * from "./applyYAMLBlueprint"; +export * from "./applyJSONBlueprint"; export * from "./getBlueprint"; diff --git a/server/routers/external.ts b/server/routers/external.ts index d23de443..3783d7b4 100644 --- a/server/routers/external.ts +++ b/server/routers/external.ts @@ -823,7 +823,7 @@ authenticated.put( "/org/:orgId/blueprint", verifyOrgAccess, verifyUserHasAction(ActionsEnum.applyBlueprint), - blueprints.createAndApplyBlueprint + blueprints.applyYAMLBlueprint ); authenticated.get( diff --git a/server/routers/integration.ts b/server/routers/integration.ts index 8808c931..0fd76b4c 100644 --- a/server/routers/integration.ts +++ b/server/routers/integration.ts @@ -1,5 +1,6 @@ import * as site from "./site"; import * as org from "./org"; +import * as blueprints from "./blueprints"; import * as resource from "./resource"; import * as domain from "./domain"; import * as target from "./target"; @@ -663,5 +664,5 @@ authenticated.put( "/org/:orgId/blueprint", verifyApiKeyOrgAccess, verifyApiKeyHasAction(ActionsEnum.applyBlueprint), - org.applyBlueprint + blueprints.applyJSONBlueprint ); diff --git a/server/routers/org/index.ts b/server/routers/org/index.ts index 7887fcac..c9a44d8d 100644 --- a/server/routers/org/index.ts +++ b/server/routers/org/index.ts @@ -7,4 +7,3 @@ export * from "./checkId"; export * from "./getOrgOverview"; export * from "./listOrgs"; export * from "./pickOrgDefaults"; -export * from "./applyBlueprint";