BIZ8-9 补强付款导出权限回归
这个提交包含在:
@@ -1,6 +1,7 @@
|
||||
const Fastify = require("fastify");
|
||||
|
||||
const exportsRoutes = require("../../../src/routes/exports");
|
||||
const { AppError } = require("../../../src/utils/AppError");
|
||||
|
||||
const ACTOR_ID = "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa";
|
||||
|
||||
@@ -140,7 +141,12 @@ async function buildApp(options = {}) {
|
||||
request.employee = actor;
|
||||
const permissionCodes = actor.permissionCodes ?? [];
|
||||
if (!permissionCodes.includes("*") && !permissionCodes.includes(permissionCode)) {
|
||||
throw new Error(`unexpected permission check: ${permissionCode}`);
|
||||
throw new AppError({
|
||||
code: "PERM_001",
|
||||
message: "无权限",
|
||||
statusCode: 403,
|
||||
details: { permission: permissionCode },
|
||||
});
|
||||
}
|
||||
});
|
||||
app.decorate("config", {
|
||||
@@ -177,6 +183,26 @@ async function buildApp(options = {}) {
|
||||
},
|
||||
});
|
||||
|
||||
app.setErrorHandler((error, request, reply) => {
|
||||
if (error instanceof AppError) {
|
||||
return reply.status(error.statusCode).send({
|
||||
requestId: request.id,
|
||||
error: {
|
||||
code: error.code,
|
||||
message: error.message,
|
||||
details: error.details ?? {},
|
||||
},
|
||||
});
|
||||
}
|
||||
return reply.status(500).send({
|
||||
requestId: request.id,
|
||||
error: {
|
||||
code: "SYS_001",
|
||||
message: error.message,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
await app.register(exportsRoutes, { prefix: "/api" });
|
||||
return {
|
||||
app,
|
||||
@@ -306,4 +332,30 @@ describe("ap operations export route", () => {
|
||||
|
||||
await app.close();
|
||||
});
|
||||
|
||||
it.each([
|
||||
["employee", ["expense.view_own"]],
|
||||
["admin-only", ["system.users"]],
|
||||
])("rejects ap operations export for %s without finance permissions", async (_roleName, permissionCodes) => {
|
||||
const { app, auditCreate } = await buildApp({
|
||||
actor: {
|
||||
id: ACTOR_ID,
|
||||
permissionCodes,
|
||||
},
|
||||
});
|
||||
|
||||
const response = await app.inject({
|
||||
method: "POST",
|
||||
url: "/api/exports/ap-operations",
|
||||
payload: {
|
||||
format: "csv",
|
||||
},
|
||||
});
|
||||
|
||||
expect(response.statusCode).toBe(403);
|
||||
expect(response.json().error.code).toBe("PERM_001");
|
||||
expect(auditCreate).not.toHaveBeenCalled();
|
||||
|
||||
await app.close();
|
||||
});
|
||||
});
|
||||
|
||||
在新工单中引用
屏蔽一个用户