chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
import { parseWithZod } from "@conform-to/zod";
|
||||
import { type ActionFunction, json } from "@remix-run/node";
|
||||
import { z } from "zod";
|
||||
import { $replica, prisma } from "~/db.server";
|
||||
import { redirectWithErrorMessage, redirectWithSuccessMessage } from "~/models/message.server";
|
||||
import { resolveSessionByIdOrExternalId } from "~/services/realtime/sessions.server";
|
||||
import { logger } from "~/services/logger.server";
|
||||
import { requireUserId } from "~/services/session.server";
|
||||
|
||||
export const closeSessionSchema = z.object({
|
||||
redirectUrl: z.string(),
|
||||
environmentId: z.string(),
|
||||
reason: z.string().optional(),
|
||||
});
|
||||
|
||||
const ParamSchema = z.object({
|
||||
sessionParam: z.string(),
|
||||
});
|
||||
|
||||
export const action: ActionFunction = async ({ request, params }) => {
|
||||
const userId = await requireUserId(request);
|
||||
const { sessionParam } = ParamSchema.parse(params);
|
||||
|
||||
const formData = await request.formData();
|
||||
const submission = parseWithZod(formData, { schema: closeSessionSchema });
|
||||
|
||||
if (submission.status !== "success") {
|
||||
return json(submission.reply());
|
||||
}
|
||||
|
||||
const { redirectUrl, environmentId, reason } = submission.value;
|
||||
const trimmedReason = reason?.trim();
|
||||
const closedReason =
|
||||
trimmedReason && trimmedReason.length > 0 ? trimmedReason : "closed-from-dashboard";
|
||||
|
||||
try {
|
||||
// Confirm the user belongs to the org that owns this environment, then
|
||||
// resolve the session by friendlyId or externalId scoped to that env.
|
||||
const environment = await $replica.runtimeEnvironment.findFirst({
|
||||
where: {
|
||||
id: environmentId,
|
||||
organization: { members: { some: { userId } } },
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
|
||||
if (!environment) {
|
||||
return json(submission.reply({ fieldErrors: { environmentId: ["Environment not found"] } }));
|
||||
}
|
||||
|
||||
const session = await resolveSessionByIdOrExternalId($replica, environment.id, sessionParam);
|
||||
|
||||
if (!session) {
|
||||
return json(submission.reply({ fieldErrors: { sessionParam: ["Session not found"] } }));
|
||||
}
|
||||
|
||||
if (session.closedAt) {
|
||||
// Already closed — no-op, but redirect with a friendly message so the
|
||||
// UI doesn't look like it did nothing.
|
||||
return redirectWithSuccessMessage(redirectUrl, request, `Session already closed`);
|
||||
}
|
||||
|
||||
// Conditional update mirrors the public API: two concurrent closes race
|
||||
// through the read but only one wins this update.
|
||||
await prisma.session.updateMany({
|
||||
where: { id: session.id, closedAt: null },
|
||||
data: {
|
||||
closedAt: new Date(),
|
||||
closedReason,
|
||||
},
|
||||
});
|
||||
|
||||
return redirectWithSuccessMessage(redirectUrl, request, `Closed session`);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
logger.error("Failed to close session", {
|
||||
error: { name: error.name, message: error.message, stack: error.stack },
|
||||
});
|
||||
return redirectWithErrorMessage(
|
||||
redirectUrl,
|
||||
request,
|
||||
`Failed to close session, ${error.message}`
|
||||
);
|
||||
}
|
||||
logger.error("Failed to close session", { error });
|
||||
return redirectWithErrorMessage(
|
||||
redirectUrl,
|
||||
request,
|
||||
`Failed to close session, ${JSON.stringify(error)}`
|
||||
);
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user