src/server/services/access.ts
此代码来自构建时的仓库快照。修改源码后重新构建即可更新。
import { TRPCError } from '@trpc/server';
import type { Prisma, PrismaClient } from '@/generated/prisma/client';
type Db = PrismaClient | Prisma.TransactionClient;
export async function requireMembership(
db: Db,
userId: string,
teamId: string,
) {
// teamId 相当于客户端选择的“工作区”,不是权限证明;每次请求都查真实成员关系。
const member = await db.membership.findUnique({
where: { teamId_userId: { teamId, userId } },
});
if (!member)
throw new TRPCError({
code: 'FORBIDDEN',
message: '你不是该团队成员,或成员资格已被移除',
});
return member;
}
export async function requireAdmin(db: Db, userId: string, teamId: string) {
const member = await requireMembership(db, userId, teamId);
if (member.role !== 'ADMIN')
throw new TRPCError({
code: 'FORBIDDEN',
message: '仅管理员可以管理团队成员',
});
return member;
}
export async function requireTicketAccess(
db: Db,
userId: string,
teamId: string,
id: string,
) {
const member = await requireMembership(db, userId, teamId);
// 工单详情、回复与操作记录共用这一可见性边界,避免新增接口漏掉客户归属条件。
const ticket = await db.ticket.findFirst({
where: {
id,
teamId,
...(member.role === 'CUSTOMER' ? { creatorId: userId } : {}),
},
});
if (!ticket)
throw new TRPCError({ code: 'NOT_FOUND', message: '工单不存在或无权访问' });
return { ticket, member };
}