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
107 changes: 107 additions & 0 deletions apps/app/src/app/api/retool/reset-org/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import { db } from "@comp/db";
import { type NextRequest, NextResponse } from "next/server";

// Configure this route to use Node.js runtime instead of Edge
export const runtime = "nodejs";

/**
* POST /api/retool/reset-org
*
* Resets an organization's data by deleting tasks, policies, controls, and framework instances.
* This is an internal endpoint for Retool.
*
* Headers:
* - Authorization: Bearer {RETOOL_COMP_API_SECRET}
*
* Body:
* - organization_id: string - The ID of the organization to reset.
*
* Returns:
* - 200: { success: true, message: "Organization reset successfully" }
* - 400: { success: false, error: "Missing organization_id in request body" }
* - 401: { success: false, error: "Unauthorized" }
* - 500: { success: false, error: "Failed to reset organization" }
*/
export async function POST(request: NextRequest) {
const authHeader = request.headers.get("authorization");
const retoolApiSecret = process.env.RETOOL_COMP_API_SECRET;

if (!retoolApiSecret) {
console.error(
"RETOOL_COMP_API_SECRET is not set in environment variables."
);
return NextResponse.json(
{
success: false,
error: "Internal server configuration error.",
},
{ status: 500 }
);
}

const token = authHeader?.split(" ")[1];

if (!token || token !== retoolApiSecret) {
return NextResponse.json(
{
success: false,
error: "Unauthorized",
},
{ status: 401 }
);
}

try {
const body = await request.json();
const { organization_id: organizationId } = body;

if (!organizationId) {
return NextResponse.json(
{
success: false,
error: "Missing organization_id in request body",
},
{ status: 400 }
);
}

// Use a transaction to ensure all or no deletions happen
await db.$transaction([
db.task.deleteMany({
where: { organizationId },
}),
db.policy.deleteMany({
where: { organizationId },
}),
db.control.deleteMany({
where: { organizationId },
}),
db.frameworkInstance.deleteMany({
where: { organizationId },
}),
]);

return NextResponse.json({
success: true,
message: "Organization reset successfully",
});
} catch (error) {
console.error("Error resetting organization:", error);
if (error instanceof SyntaxError) {
return NextResponse.json(
{
success: false,
error: "Invalid JSON in request body",
},
{ status: 400 }
);
}
return NextResponse.json(
{
success: false,
error: "Failed to reset organization",
},
{ status: 500 }
);
}
}
2 changes: 1 addition & 1 deletion packages/db/prisma/schema/auth.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ model Member {

department Departments @default(none)
isActive Boolean @default(true)
EmployeeTrainingVideoCompletion EmployeeTrainingVideoCompletion[]
employeeTrainingVideoCompletion EmployeeTrainingVideoCompletion[]

assignedPolicies Policy[] @relation("PolicyAssignee") // Policies where this member is an assignee
approvedPolicies Policy[] @relation("PolicyApprover") // Policies where this member is an approver
Expand Down
Loading