forked from EduCraft/curriculum-project-hub
ef96f8d33d
Co-authored-by: Hong Jiarong <me@jrhim.com> Co-committed-by: Hong Jiarong <me@jrhim.com>
153 lines
5.8 KiB
TypeScript
153 lines
5.8 KiB
TypeScript
/**
|
|
* Mount point for `/api/org/:orgSlug/*` org-admin APIs.
|
|
*/
|
|
import type { PrismaClient } from "@prisma/client";
|
|
import type { FastifyInstance } from "fastify";
|
|
import { requireOrgRole, type GuardDeps } from "../auth/guards.js";
|
|
import { handleRouteError } from "../errors.js";
|
|
import {
|
|
ensureOrganizationProjectSettings,
|
|
setMembersCanCreateProjects,
|
|
} from "../../projectOnboarding.js";
|
|
import { registerAccessRoutes } from "./accessRoutes.js";
|
|
import { registerExplorerRoutes } from "./explorerRoutes.js";
|
|
import { registerMembersRoutes } from "./membersRoutes.js";
|
|
import { registerSessionsAndUsageRoutes } from "./sessionsRoutes.js";
|
|
import { registerTeamsRoutes } from "./teamsRoutes.js";
|
|
import { registerProviderConnectionRoutes } from "./providerConnectionRoutes.js";
|
|
import { registerCapacityRoutes } from "./capacityRoutes.js";
|
|
import { readSkillStoreRoot } from "../../agent/skillStore.js";
|
|
import { registerAgentConfigRoutes } from "./agentConfigRoutes.js";
|
|
import type { LocalSecretEnvelope } from "../../security/secretEnvelope.js";
|
|
import type { ProviderReadinessProbe } from "../../connections/providerReadiness.js";
|
|
import type { FeishuReadinessProbe } from "../../connections/feishuReadiness.js";
|
|
import { registerFeishuApplicationConnectionRoutes } from "./feishuApplicationConnectionRoutes.js";
|
|
import { registerCapabilityConnectionRoutes } from "./capabilityConnectionRoutes.js";
|
|
import type { CapabilityReadinessProbe } from "../../capability/capabilityReadiness.js";
|
|
|
|
export interface OrgRouteConfig {
|
|
readonly prisma: PrismaClient;
|
|
readonly sessionSecret: string;
|
|
readonly projectWorkspaceRoot: string;
|
|
readonly secretEnvelope: LocalSecretEnvelope;
|
|
readonly providerReadinessProbe?: ProviderReadinessProbe;
|
|
readonly feishuConnectionReadinessProbe?: FeishuReadinessProbe;
|
|
readonly capabilityReadinessProbe?: CapabilityReadinessProbe;
|
|
}
|
|
|
|
export async function registerOrgRoutes(app: FastifyInstance, config: OrgRouteConfig): Promise<void> {
|
|
const guardDeps: GuardDeps = { prisma: config.prisma, sessionSecret: config.sessionSecret };
|
|
|
|
app.get("/api/org/:orgSlug", async (request, reply) => {
|
|
try {
|
|
const { orgSlug } = request.params as { orgSlug: string };
|
|
const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
|
|
if (auth === null) return;
|
|
return {
|
|
organization: {
|
|
id: auth.organization.id,
|
|
slug: auth.organization.slug,
|
|
name: auth.organization.name,
|
|
status: auth.organization.status,
|
|
},
|
|
actorRole: auth.membershipRole,
|
|
};
|
|
} catch (err) {
|
|
return handleRouteError(reply, err);
|
|
}
|
|
});
|
|
|
|
app.get("/api/org/:orgSlug/settings", async (request, reply) => {
|
|
try {
|
|
const { orgSlug } = request.params as { orgSlug: string };
|
|
const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
|
|
if (auth === null) return;
|
|
const settings = await ensureOrganizationProjectSettings(config.prisma, auth.organization.id);
|
|
return {
|
|
membersCanCreateProjects: settings.membersCanCreateProjects,
|
|
};
|
|
} catch (err) {
|
|
return handleRouteError(reply, err);
|
|
}
|
|
});
|
|
|
|
app.patch("/api/org/:orgSlug/settings", async (request, reply) => {
|
|
try {
|
|
const { orgSlug } = request.params as { orgSlug: string };
|
|
const auth = await requireOrgRole(request, reply, guardDeps, { orgSlug });
|
|
if (auth === null) return;
|
|
const body = request.body as { membersCanCreateProjects?: unknown };
|
|
if (typeof body.membersCanCreateProjects !== "boolean") {
|
|
return reply.status(400).send({
|
|
error: { code: "bad_request", message: "membersCanCreateProjects must be a boolean" },
|
|
});
|
|
}
|
|
const settings = await setMembersCanCreateProjects(config.prisma, {
|
|
organizationId: auth.organization.id,
|
|
enabled: body.membersCanCreateProjects,
|
|
});
|
|
return {
|
|
membersCanCreateProjects: settings.membersCanCreateProjects,
|
|
};
|
|
} catch (err) {
|
|
return handleRouteError(reply, err);
|
|
}
|
|
});
|
|
|
|
await registerExplorerRoutes(app, {
|
|
prisma: config.prisma,
|
|
sessionSecret: config.sessionSecret,
|
|
projectWorkspaceRoot: config.projectWorkspaceRoot,
|
|
});
|
|
await registerMembersRoutes(app, {
|
|
prisma: config.prisma,
|
|
sessionSecret: config.sessionSecret,
|
|
});
|
|
await registerTeamsRoutes(app, {
|
|
prisma: config.prisma,
|
|
sessionSecret: config.sessionSecret,
|
|
});
|
|
await registerAccessRoutes(app, {
|
|
prisma: config.prisma,
|
|
sessionSecret: config.sessionSecret,
|
|
});
|
|
await registerCapacityRoutes(app, {
|
|
prisma: config.prisma,
|
|
sessionSecret: config.sessionSecret,
|
|
});
|
|
await registerAgentConfigRoutes(app, {
|
|
prisma: config.prisma,
|
|
sessionSecret: config.sessionSecret,
|
|
skillStoreRoot: readSkillStoreRoot(),
|
|
secretEnvelope: config.secretEnvelope,
|
|
});
|
|
await registerSessionsAndUsageRoutes(app, {
|
|
prisma: config.prisma,
|
|
sessionSecret: config.sessionSecret,
|
|
});
|
|
await registerProviderConnectionRoutes(app, {
|
|
prisma: config.prisma,
|
|
sessionSecret: config.sessionSecret,
|
|
secretEnvelope: config.secretEnvelope,
|
|
...(config.providerReadinessProbe !== undefined
|
|
? { providerReadinessProbe: config.providerReadinessProbe }
|
|
: {}),
|
|
});
|
|
await registerFeishuApplicationConnectionRoutes(app, {
|
|
prisma: config.prisma,
|
|
sessionSecret: config.sessionSecret,
|
|
secretEnvelope: config.secretEnvelope,
|
|
...(config.feishuConnectionReadinessProbe !== undefined
|
|
? { readinessProbe: config.feishuConnectionReadinessProbe }
|
|
: {}),
|
|
});
|
|
await registerCapabilityConnectionRoutes(app, {
|
|
prisma: config.prisma,
|
|
sessionSecret: config.sessionSecret,
|
|
secretEnvelope: config.secretEnvelope,
|
|
...(config.capabilityReadinessProbe !== undefined
|
|
? { readinessProbe: config.capabilityReadinessProbe }
|
|
: {}),
|
|
});
|
|
}
|