feat(console): unblock workspace by account email

This commit is contained in:
MrMushrooooom
2026-08-23 16:16:06 +00:00
parent 89451c3e32
commit 45e75c7c56
2 changed files with 47 additions and 15 deletions
@@ -4,7 +4,10 @@ import { safeEqual } from "@opencode-ai/console-core/util/crypto.js"
import { Resource } from "@opencode-ai/console-resource"
import z from "zod"
const Body = z.object({ workspaceID: z.string().startsWith("wrk_") })
const Body = z.union([
z.object({ workspaceID: z.string().startsWith("wrk_") }),
z.object({ email: z.email().transform((email) => email.trim().toLowerCase()) }),
])
export async function POST(event: APIEvent) {
if (!safeEqual(event.request.headers.get("authorization") ?? "", `Bearer ${Resource.SUPPORT_API_KEY.value}`)) {
@@ -15,7 +18,7 @@ export async function POST(event: APIEvent) {
if (!body.success) {
return Response.json({ error: "Invalid request", issues: body.error.issues }, { status: 400 })
}
return Workspace.unblock(body.data.workspaceID)
.then(() => Response.json({ success: true, message: "Workspace unblocked" }))
return Workspace.unblock(body.data)
.then((workspaceIDs) => Response.json({ success: true, message: "Workspace unblocked", workspaceIDs }))
.catch((error) => Response.json({ error: error instanceof Error ? error.message : String(error) }, { status: 400 }))
}
+41 -12
View File
@@ -7,8 +7,9 @@ import { UserTable } from "./schema/user.sql"
import { BillingTable } from "./schema/billing.sql"
import { WorkspaceTable } from "./schema/workspace.sql"
import { AccountTable } from "./schema/account.sql"
import { AuthTable } from "./schema/auth.sql"
import { Key } from "./key"
import { and, eq, isNull, sql } from "drizzle-orm"
import { and, eq, inArray, isNull, sql } from "drizzle-orm"
export namespace Workspace {
export const Region = z.enum(["us", "eu", "sg", "cn"])
@@ -104,15 +105,43 @@ export namespace Workspace {
)
})
export const unblock = fn(z.string().startsWith("wrk_"), async (workspaceID) => {
await Database.transaction(async (tx) => {
const workspace = await tx
.select({ id: WorkspaceTable.id })
.from(WorkspaceTable)
.where(eq(WorkspaceTable.id, workspaceID))
.then((rows) => rows[0])
if (!workspace) throw new Error("Workspace not found")
await tx.update(WorkspaceTable).set({ is_blocked: false }).where(eq(WorkspaceTable.id, workspaceID))
})
})
export const unblock = fn(
z.union([
z.object({ workspaceID: z.string().startsWith("wrk_") }),
z.object({ email: z.email() }),
]),
async (input) => {
return Database.transaction(async (tx) => {
const workspaces = "workspaceID" in input
? await tx
.select({ id: WorkspaceTable.id })
.from(WorkspaceTable)
.where(and(eq(WorkspaceTable.id, input.workspaceID), isNull(WorkspaceTable.timeDeleted)))
: await tx
.selectDistinct({ id: WorkspaceTable.id })
.from(WorkspaceTable)
.innerJoin(
UserTable,
and(eq(UserTable.workspaceID, WorkspaceTable.id), isNull(UserTable.timeDeleted)),
)
.innerJoin(
AuthTable,
and(
eq(AuthTable.accountID, UserTable.accountID),
eq(AuthTable.provider, "email"),
eq(AuthTable.subject, input.email.toLowerCase()),
isNull(AuthTable.timeDeleted),
),
)
.where(isNull(WorkspaceTable.timeDeleted))
if (workspaces.length === 0) throw new Error("Workspace not found")
if (!("workspaceID" in input) && workspaces.length > 1) {
throw new Error("Email is associated with multiple workspaces; use workspaceID")
}
const workspaceIDs = workspaces.map((workspace) => workspace.id)
await tx.update(WorkspaceTable).set({ is_blocked: false }).where(inArray(WorkspaceTable.id, workspaceIDs))
return workspaceIDs
})
},
)
}