forked from EduCraft/curriculum-project-hub
feat(hub): add Feishu OAuth session for org admin
Introduce signed cookie sessions, Feishu web OAuth, requireOrgRole guards, and the first org admin APIs (summary + project settings).
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* 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";
|
||||
|
||||
export interface OrgRouteConfig {
|
||||
readonly prisma: PrismaClient;
|
||||
readonly sessionSecret: string;
|
||||
readonly projectWorkspaceRoot: string;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user