chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,103 @@
|
||||
import type { ActionFunctionArgs } from "@remix-run/server-runtime";
|
||||
import { json } from "@remix-run/server-runtime";
|
||||
import { z } from "zod";
|
||||
import {
|
||||
ApiAlertChannelPresenter,
|
||||
ApiCreateAlertChannel,
|
||||
} from "~/presenters/v3/ApiAlertChannelPresenter.server";
|
||||
import { logger } from "~/services/logger.server";
|
||||
import { authenticateApiRequestWithPersonalAccessToken } from "~/services/personalAccessToken.server";
|
||||
import { CreateAlertChannelService } from "~/v3/services/alerts/createAlertChannel.server";
|
||||
import { ServiceValidationError } from "~/v3/services/baseService.server";
|
||||
|
||||
const ParamsSchema = z.object({
|
||||
projectRef: z.string(),
|
||||
});
|
||||
|
||||
export async function action({ request, params }: ActionFunctionArgs) {
|
||||
try {
|
||||
const authenticationResult = await authenticateApiRequestWithPersonalAccessToken(request);
|
||||
|
||||
if (!authenticationResult) {
|
||||
return json({ error: "Invalid or Missing Access Token" }, { status: 401 });
|
||||
}
|
||||
|
||||
const parsedParams = ParamsSchema.safeParse(params);
|
||||
|
||||
if (!parsedParams.success) {
|
||||
return json({ error: "Invalid Params" }, { status: 400 });
|
||||
}
|
||||
|
||||
const { projectRef } = parsedParams.data;
|
||||
|
||||
const rawBody = await request.json();
|
||||
|
||||
const body = ApiCreateAlertChannel.safeParse(rawBody);
|
||||
|
||||
if (!body.success) {
|
||||
return json({ error: "Invalid request body", issues: body.error.issues }, { status: 400 });
|
||||
}
|
||||
|
||||
const service = new CreateAlertChannelService();
|
||||
|
||||
try {
|
||||
if (body.data.channel === "email") {
|
||||
if (!body.data.channelData.email) {
|
||||
return json({ error: "Email is required" }, { status: 422 });
|
||||
}
|
||||
|
||||
const alertChannel = await service.call(projectRef, authenticationResult.userId, {
|
||||
name: body.data.name,
|
||||
alertTypes: body.data.alertTypes.map((type) =>
|
||||
ApiAlertChannelPresenter.alertTypeFromApi(type)
|
||||
),
|
||||
channel: {
|
||||
type: "EMAIL",
|
||||
email: body.data.channelData.email,
|
||||
},
|
||||
deduplicationKey: body.data.deduplicationKey,
|
||||
environmentTypes: body.data.environmentTypes,
|
||||
});
|
||||
|
||||
return json(await ApiAlertChannelPresenter.alertChannelToApi(alertChannel));
|
||||
}
|
||||
|
||||
if (body.data.channel === "webhook") {
|
||||
if (!body.data.channelData.url) {
|
||||
return json({ error: "webhook url is required" }, { status: 422 });
|
||||
}
|
||||
|
||||
// The webhook URL is validated in CreateAlertChannelService.call();
|
||||
// an unsafe URL surfaces as a ServiceValidationError -> 422 below.
|
||||
const alertChannel = await service.call(projectRef, authenticationResult.userId, {
|
||||
name: body.data.name,
|
||||
alertTypes: body.data.alertTypes.map((type) =>
|
||||
ApiAlertChannelPresenter.alertTypeFromApi(type)
|
||||
),
|
||||
channel: {
|
||||
type: "WEBHOOK",
|
||||
url: body.data.channelData.url,
|
||||
secret: body.data.channelData.secret,
|
||||
},
|
||||
deduplicationKey: body.data.deduplicationKey,
|
||||
environmentTypes: body.data.environmentTypes,
|
||||
});
|
||||
|
||||
return json(await ApiAlertChannelPresenter.alertChannelToApi(alertChannel));
|
||||
}
|
||||
|
||||
return json({ error: "Invalid channel type" }, { status: 422 });
|
||||
} catch (error) {
|
||||
if (error instanceof ServiceValidationError) {
|
||||
return json({ error: error.message }, { status: 422 });
|
||||
}
|
||||
|
||||
logger.error("Failed to create alert channel", { error });
|
||||
return json({ error: "Something went wrong, please try again." }, { status: 500 });
|
||||
}
|
||||
} catch (error) {
|
||||
if (error instanceof Response) throw error;
|
||||
logger.error("Failed to create alert channel (outer)", { error });
|
||||
return json({ error: "Internal Server Error" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user