import { eq } from "drizzle-orm"; import { jsonFailure, jsonSuccess, readJsonBody } from "@/modules/core/server/api"; import { recordAuditLog } from "@/modules/core/server/audit"; import { requirePermission } from "@/modules/core/server/auth"; import { getDatabase } from "@/modules/core/server/db"; import { seedOrganizationRoles } from "@/modules/core/server/permissions"; import { organizations } from "@/modules/core/server/schema"; import { getSystemSettings } from "@/modules/core/server/system-settings"; import { RESERVED_WORKSPACE_SLUGS } from "@/modules/shared/lib/workspace-routing"; function isRecord(value: unknown): value is Record { return typeof value === "object" && value !== null && !Array.isArray(value); } function readString(source: Record, key: string): string { const value = source[key]; return typeof value === "string" ? value.trim() : ""; } function isValidSlug(value: string): boolean { return /^[a-z0-9][a-z0-9-]{1,47}$/.test(value) && !value.endsWith("-") && !RESERVED_WORKSPACE_SLUGS.has(value); } export async function GET(): Promise { const database = getDatabase(); const [settings, rows] = await Promise.all([ getSystemSettings(), database.select().from(organizations).where(eq(organizations.status, "active")), ]); return jsonSuccess("机构列表已加载", { organizations: rows .filter((organization) => settings.registrationEnabled && organization.registrationEnabled) .map((organization) => ({ id: organization.id, name: organization.name, slug: organization.slug, status: organization.status, registrationEnabled: organization.registrationEnabled, oidcEnabled: organization.oidcEnabled, oidcIssuerUrl: "", oidcClientId: "", oidcHasClientSecret: organization.oidcClientSecret.length > 0, oidcScopes: organization.oidcScopes, oidcRedirectUri: organization.oidcRedirectUri, oidcAvatarClaim: organization.oidcAvatarClaim, oidcAutoProvision: organization.oidcAutoProvision, createdAt: organization.createdAt.toISOString(), updatedAt: organization.updatedAt.toISOString(), })), }); } export async function POST(request: Request): Promise { const auth = await requirePermission("organization:manage", { action: "organization.create", targetType: "organization", }); if (!auth.success) { return auth.response; } const body = await readJsonBody(request); if (!isRecord(body)) { return jsonFailure("请求数据格式无效"); } const name = readString(body, "name"); if (!name) { return jsonFailure("机构名称不能为空"); } const slug = readString(body, "slug").toLowerCase(); if (!slug) { return jsonFailure("机构标识不能为空"); } if (!isValidSlug(slug)) { return jsonFailure("机构标识仅支持小写字母、数字和连字符,长度 2-48 位,不能以连字符结尾,且不能使用系统路径保留字"); } const database = getDatabase(); try { const rows = await database .insert(organizations) .values({ name, slug, status: "active", }) .returning(); const organization = rows[0]; if (!organization) { return jsonFailure("机构创建失败", 500); } await seedOrganizationRoles(organization.id); await recordAuditLog({ actor: auth.context.account, organizationId: organization.id, action: "organization.create", targetType: "organization", targetId: organization.id, result: "success", reason: `创建机构:${organization.name}`, }); return jsonSuccess("机构已创建", { organization }, 201); } catch (error) { const message = error instanceof Error ? error.message : ""; if (message.includes("organizations_slug_unique")) { return jsonFailure("机构标识已存在", 409); } return jsonFailure("机构创建失败", 500); } }