diff --git a/apps/webservice/src/app/api/v1/release-channels/openapi.ts b/apps/webservice/src/app/api/v1/release-channels/openapi.ts new file mode 100644 index 000000000..75c68fbc7 --- /dev/null +++ b/apps/webservice/src/app/api/v1/release-channels/openapi.ts @@ -0,0 +1,93 @@ +import type { Swagger } from "atlassian-openapi"; + +export const openapi: Swagger.SwaggerV3 = { + openapi: "3.0.0", + info: { + title: "Ctrlplane API", + version: "1.0.0", + }, + paths: { + "/v1/release-channels": { + post: { + summary: "Create a release channel", + operationId: "createReleaseChannel", + requestBody: { + required: true, + content: { + "application/json": { + schema: { + type: "object", + required: ["deploymentId", "name"], + properties: { + deploymentId: { type: "string" }, + name: { type: "string" }, + description: { type: "string", nullable: true }, + }, + }, + }, + }, + }, + responses: { + "200": { + description: "Release channel created successfully", + content: { + "application/json": { + schema: { + type: "object", + properties: { + id: { type: "string" }, + deploymentId: { type: "string" }, + name: { type: "string" }, + description: { type: "string", nullable: true }, + createdAt: { type: "string", format: "date-time" }, + }, + required: ["id", "deploymentId", "name", "createdAt"], + }, + }, + }, + }, + "500": { + description: "Failed to create release channel", + content: { + "application/json": { + schema: { + type: "object", + properties: { error: { type: "string" } }, + required: ["error"], + }, + }, + }, + }, + "401": { + description: "Unauthorized", + content: { + "application/json": { + schema: { + type: "object", + properties: { error: { type: "string" } }, + required: ["error"], + }, + }, + }, + }, + "403": { + description: "Forbidden", + content: { + "application/json": { + schema: { + type: "object", + properties: { error: { type: "string" } }, + required: ["error"], + }, + }, + }, + }, + }, + security: [{ bearerAuth: [] }], + }, + }, + }, + components: { + securitySchemes: { bearerAuth: { type: "http", scheme: "bearer" } }, + }, +}; diff --git a/apps/webservice/src/app/api/v1/release-channels/route.ts b/apps/webservice/src/app/api/v1/release-channels/route.ts new file mode 100644 index 000000000..e9dd22cc8 --- /dev/null +++ b/apps/webservice/src/app/api/v1/release-channels/route.ts @@ -0,0 +1,32 @@ +import type { z } from "zod"; +import { NextResponse } from "next/server"; + +import { takeFirst } from "@ctrlplane/db"; +import { createReleaseChannel } from "@ctrlplane/db/schema"; +import * as SCHEMA from "@ctrlplane/db/schema"; +import { Permission } from "@ctrlplane/validators/auth"; + +import { authn, authz } from "../auth"; +import { parseBody } from "../body-parser"; +import { request } from "../middleware"; + +export const POST = request() + .use(authn) + .use(parseBody(createReleaseChannel)) + .use( + authz(({ ctx, can }) => + can + .perform(Permission.ReleaseChannelCreate) + .on({ type: "deployment", id: ctx.body.deploymentId }), + ), + ) + .handle<{ body: z.infer }>( + async ({ db, body }) => + db + .insert(SCHEMA.releaseChannel) + .values(body) + .returning() + .then(takeFirst) + .then((releaseChannel) => NextResponse.json(releaseChannel)) + .catch((error) => NextResponse.json({ error }, { status: 500 })), + );