Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/openstatusHQ/openstatus. ๐ซ Status page with uptime monitoring & API monitoring as code ๐ซ openstatus.dev
bun drizzle-orm monitoring monitoring-as-code nextjs observability on-call open-source shadcn-ui status-page statuspage synthetic-monitoring tinybird turso uptime uptime-checker uptime-monitor
Something went wrong. Try again.
2.4 kB ยท 79 lines
TypeScript
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980import { and, eq, isNull } from "@openstatus/db";import { incident, incidentEvent } from "@openstatus/db/src/schema";
import { emitAudit } from "../audit";import { requireScope } from "../auth";import { requireRole } from "../auth/require-role";import { type ServiceContext, withTransaction } from "../context";import { ConflictError } from "../errors";import { getIncidentInWorkspace, requireIncidentFeature } from "./internal";import { IncidentIdInput } from "./schemas";
/** * For incidents declared by mistake: only while open and never mitigated or * resolved. Anything further along is history. The timeline goes with it; its * events are already in the audit log. */export async function deleteIncident(args: { ctx: ServiceContext; input: IncidentIdInput;}): Promise<void> { const { ctx } = args; requireScope(ctx, "write"); requireIncidentFeature(ctx); const input = IncidentIdInput.parse(args.input);
await withTransaction(ctx, async (tx) => { const existing = await getIncidentInWorkspace( tx, ctx.workspace.id, input.id, ); await requireRole(tx, ctx, ["owner", "admin"]); if (!isDeletable(existing)) { throw new ConflictError( `Incident #${existing.id} has progressed and can no longer be deleted`, ); } await tx .delete(incidentEvent) .where(eq(incidentEvent.incidentId, existing.id)); // Repeats `isDeletable` so an incident that progressed concurrently stays. const deleted = await tx .delete(incident) .where( and( eq(incident.id, existing.id), eq(incident.status, "open"), isNull(incident.mitigatedAt), isNull(incident.resolvedAt), isNull(incident.closedAt), ), ) .returning() .get(); if (!deleted) { throw new ConflictError(`Incident #${existing.id} changed concurrently`); } await emitAudit(tx, ctx, { action: "incident.delete", entityType: "incident", entityId: deleted.id, before: deleted, }); });}
export function isDeletable(row: { status: string; mitigatedAt: Date | null; resolvedAt: Date | null; closedAt: Date | null;}): boolean { return ( row.status === "open" && row.mitigatedAt === null && row.resolvedAt === null && row.closedAt === null );}