forked from EduCraft/curriculum-project-hub
feat(database): init database folder frontend and permission
This commit is contained in:
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 文件库 HTTP 门禁(契约 C4 的入驻适配)。
|
||||
*
|
||||
* 身份链:hub session(飞书 OAuth / dev bypass)→ silo org membership。
|
||||
* 网站管理员 = org 的 OWNER/ADMIN(D19:仅 root 创建与 force_adjust 特权,
|
||||
* 不给内容读旁路);普通成员 = 任何活跃 membership;非成员 = 403。
|
||||
*/
|
||||
|
||||
import type { FastifyReply, FastifyRequest } from "fastify";
|
||||
import type { OrganizationMemberRole, PrismaClient } from "@prisma/client";
|
||||
import { requireSession, sendError } from "../../admin/auth/guards.js";
|
||||
import type { FileLibActor } from "./treeService.js";
|
||||
|
||||
export interface FileLibGuardDeps {
|
||||
readonly prisma: PrismaClient;
|
||||
readonly sessionSecret: string;
|
||||
/** 文件库归属的 silo org(ADR-0020/0025)。 */
|
||||
readonly organizationId: string;
|
||||
}
|
||||
|
||||
const WEBSITE_ADMIN_ROLES: readonly OrganizationMemberRole[] = ["OWNER", "ADMIN"];
|
||||
|
||||
/** 每个 /database/api/* 端点第一行调它;返回 null 时响应已发出,fail closed。 */
|
||||
export async function requireFileLibActor(
|
||||
request: FastifyRequest,
|
||||
reply: FastifyReply,
|
||||
deps: FileLibGuardDeps,
|
||||
): Promise<FileLibActor | null> {
|
||||
const auth = await requireSession(request, reply, {
|
||||
prisma: deps.prisma,
|
||||
sessionSecret: deps.sessionSecret,
|
||||
});
|
||||
if (auth === null) return null;
|
||||
|
||||
const membership = await deps.prisma.organizationMembership.findFirst({
|
||||
where: { organizationId: deps.organizationId, userId: auth.user.id, revokedAt: null },
|
||||
select: { role: true },
|
||||
});
|
||||
if (membership === null) {
|
||||
await sendError(reply, 403, "forbidden", "not a member of this organization");
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
userId: auth.user.id,
|
||||
isWebsiteAdmin: WEBSITE_ADMIN_ROLES.includes(membership.role),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user