Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/webservice/src/app/api/v1/jobs/[jobId]/get-job.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import type { Tx } from "@ctrlplane/db";
import { getResourceParents } from "node_modules/@ctrlplane/db/src/queries/get-resource-parents";

import { eq } from "@ctrlplane/db";
import { getResourceParents } from "@ctrlplane/db/queries";
import * as schema from "@ctrlplane/db/schema";
import { logger } from "@ctrlplane/logger";
import { variablesAES256 } from "@ctrlplane/secrets";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import type { Swagger } from "atlassian-openapi";

export const openapi: Swagger.SwaggerV3 = {
openapi: "3.0.0",
info: {
title: "Ctrlplane API",
version: "1.0.0",
},
components: {
schemas: {
UpdateResourceRelationshipRule: {
type: "object",
properties: {
name: { type: "string" },
reference: { type: "string" },
dependencyType: {
$ref: "#/components/schemas/ResourceRelationshipRuleDependencyType",
},
dependencyDescription: { type: "string" },
description: { type: "string" },
sourceKind: { type: "string" },
sourceVersion: { type: "string" },
targetKind: { type: "string" },
targetVersion: { type: "string" },
metadataKeysMatch: {
type: "array",
items: { type: "string" },
},
metadataKeysEquals: {
type: "array",
items: {
type: "object",
properties: {
key: { type: "string" },
value: { type: "string" },
},
required: ["key", "value"],
},
},
},
},
},
},
paths: {
"/v1/resource-relationship-rules/{ruleId}": {
patch: {
summary: "Update a resource relationship rule",
operationId: "updateResourceRelationshipRule",
parameters: [
{
name: "ruleId",
in: "path",
required: true,
schema: { type: "string", format: "uuid" },
},
],
requestBody: {
content: {
"application/json": {
schema: {
$ref: "#/components/schemas/UpdateResourceRelationshipRule",
},
},
},
},
responses: {
200: {
description: "The updated resource relationship rule",
content: {
"application/json": {
schema: {
$ref: "#/components/schemas/ResourceRelationshipRule",
},
},
},
},
404: {
description: "The resource relationship rule was not found",
content: {
"application/json": {
schema: {
type: "object",
properties: { error: { type: "string" } },
required: ["error"],
},
},
},
},
500: {
description:
"An error occurred while updating the resource relationship rule",
content: {
"application/json": {
schema: {
type: "object",
properties: { error: { type: "string" } },
required: ["error"],
},
},
},
},
},
},
},
},
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import type { Tx } from "@ctrlplane/db";
import type { z } from "zod";
import { NextResponse } from "next/server";
import { INTERNAL_SERVER_ERROR, NOT_FOUND } from "http-status";
import _ from "lodash";

import { eq, takeFirst } from "@ctrlplane/db";
import * as schema from "@ctrlplane/db/schema";
import { logger } from "@ctrlplane/logger";
import { Permission } from "@ctrlplane/validators/auth";

import { authn, authz } from "~/app/api/v1/auth";
import { parseBody } from "~/app/api/v1/body-parser";
import { request } from "~/app/api/v1/middleware";

const log = logger.child({ route: "/v1/resource-relationship-rules/[ruleId]" });

const replaceMetadataMatchRules = async (
tx: Tx,
ruleId: string,
metadataKeysMatch?: string[],
) => {
await tx
.delete(schema.resourceRelationshipRuleMetadataMatch)
.where(
eq(
schema.resourceRelationshipRuleMetadataMatch.resourceRelationshipRuleId,
ruleId,
),
);

const metadataKeys = _.uniq(metadataKeysMatch ?? []);
if (metadataKeys.length > 0)
await tx.insert(schema.resourceRelationshipRuleMetadataMatch).values(
metadataKeys.map((key) => ({
resourceRelationshipRuleId: ruleId,
key,
})),
);

return metadataKeys;
};

const replaceMetadataEqualsRules = async (
tx: Tx,
ruleId: string,
metadataKeysEquals?: { key: string; value: string }[],
) => {
await tx
.delete(schema.resourceRelationshipRuleMetadataEquals)
.where(
eq(
schema.resourceRelationshipRuleMetadataEquals
.resourceRelationshipRuleId,
ruleId,
),
);

const metadataKeys = _.uniqBy(metadataKeysEquals ?? [], (m) => m.key);
if (metadataKeys.length > 0)
await tx.insert(schema.resourceRelationshipRuleMetadataEquals).values(
metadataKeys.map(({ key, value }) => ({
resourceRelationshipRuleId: ruleId,
key,
value,
})),
);

return metadataKeys;
};

export const PATCH = request()
.use(authn)
.use(parseBody(schema.updateResourceRelationshipRule))
.use(
authz(({ can, params }) =>
can.perform(Permission.ResourceRelationshipRuleUpdate).on({
type: "resourceRelationshipRule",
id: params.ruleId ?? "",
}),
),
)
.handle<
{ body: z.infer<typeof schema.updateResourceRelationshipRule> },
{ params: Promise<{ ruleId: string }> }
>(async ({ db, body }, { params }) => {
try {
const { ruleId } = await params;

const existingRule = await db.query.resourceRelationshipRule.findFirst({
where: eq(schema.resourceRelationshipRule.id, ruleId),
});

if (!existingRule)
return NextResponse.json(
{ error: "Resource relationship rule not found" },
{ status: NOT_FOUND },
);

const rule = await db.transaction(async (tx) => {
const rule = await tx
.update(schema.resourceRelationshipRule)
.set(body)
.where(eq(schema.resourceRelationshipRule.id, ruleId))
.returning()
.then(takeFirst);

const metadataKeysMatch = await replaceMetadataMatchRules(
tx,
ruleId,
body.metadataKeysMatch,
);

const metadataKeysEquals = await replaceMetadataEqualsRules(
tx,
ruleId,
body.metadataKeysEquals,
);

return { ...rule, metadataKeysMatch, metadataKeysEquals };
});

return NextResponse.json(rule);
} catch (error) {
log.error(error);
return NextResponse.json(
{ error: "Failed to update resource relationship rule" },
{ status: INTERNAL_SERVER_ERROR },
);
}
});
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export const openapi: Swagger.SwaggerV3 = {
"/v1/resource-relationship-rules": {
post: {
summary: "Create a resource relationship rule",
operationId: "upsertResourceRelationshipRule",
operationId: "createResourceRelationshipRule",
requestBody: {
required: true,
content: {
Expand All @@ -32,7 +32,20 @@ export const openapi: Swagger.SwaggerV3 = {
},
},
},
"400": {
"409": {
description: "Resource relationship rule already exists",
content: {
"application/json": {
schema: {
type: "object",
properties: {
error: { type: "string" },
},
},
},
},
},
"500": {
description: "Failed to create resource relationship rule",
content: {
"application/json": {
Expand Down Expand Up @@ -65,8 +78,8 @@ export const openapi: Swagger.SwaggerV3 = {
ResourceRelationshipRule: {
type: "object",
properties: {
id: { type: "string" },
workspaceId: { type: "string" },
id: { type: "string", format: "uuid" },
workspaceId: { type: "string", format: "uuid" },
name: { type: "string" },
reference: { type: "string" },
dependencyType: {
Expand All @@ -78,6 +91,20 @@ export const openapi: Swagger.SwaggerV3 = {
sourceVersion: { type: "string" },
targetKind: { type: "string" },
targetVersion: { type: "string" },
metadataKeysMatch: {
type: "array",
items: { type: "string" },
},
metadataKeysEquals: {
type: "array",
items: {
type: "object",
properties: {
key: { type: "string" },
value: { type: "string" },
},
},
},
},
required: [
"id",
Expand Down Expand Up @@ -108,6 +135,17 @@ export const openapi: Swagger.SwaggerV3 = {
type: "array",
items: { type: "string" },
},
metadataKeysEquals: {
type: "array",
items: {
type: "object",
properties: {
key: { type: "string" },
value: { type: "string" },
},
required: ["key", "value"],
},
},
},
required: [
"workspaceId",
Expand All @@ -118,7 +156,6 @@ export const openapi: Swagger.SwaggerV3 = {
"sourceVersion",
"targetKind",
"targetVersion",
"metadataKeysMatch",
],
},
},
Expand Down
Loading
Loading