优化前后端权限一致性
This commit is contained in:
@@ -13,10 +13,16 @@ describe("permission project role model", () => {
|
||||
expect(source).toContain("study.currentStudyRole");
|
||||
expect(source).toContain("study.currentPermissions");
|
||||
expect(source).toContain('"faq.edit": "faq:update"');
|
||||
expect(source).toContain('"fees.contract.create": "fees_contracts:create"');
|
||||
expect(source).toContain('"fees.contract.update": "fees_contracts:update"');
|
||||
expect(source).toContain('"fees.contract.delete": "fees_contracts:delete"');
|
||||
expect(source).toContain('"documents.create": "documents:create"');
|
||||
expect(source).toContain('"documents.delete": "documents:delete"');
|
||||
expect(source).toContain("isApiPermissionAllowed");
|
||||
expect(source).toContain("projectPermissions.value?.[projectRole.value]?.[operationKey]");
|
||||
expect(source).not.toContain("projectPermissions.value?.roles");
|
||||
expect(source).not.toContain('"faq.edit": "etmf');
|
||||
expect(source).not.toContain('"ADMIN", "PM"');
|
||||
expect(source).not.toContain('"fees.contract.write": "fees_contracts:create"');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,7 +18,11 @@ const PERMISSIONS: Record<string, string[]> = {
|
||||
"project.members.manage": ["ADMIN"],
|
||||
"site.manage": ["ADMIN"],
|
||||
"site.cra.bind": ["ADMIN"],
|
||||
"fees.contract.write": ["ADMIN"],
|
||||
"fees.contract.create": ["ADMIN"],
|
||||
"fees.contract.update": ["ADMIN"],
|
||||
"fees.contract.delete": ["ADMIN"],
|
||||
"documents.create": ["ADMIN"],
|
||||
"documents.delete": ["ADMIN"],
|
||||
};
|
||||
|
||||
const REASONS: Record<string, string> = {
|
||||
@@ -32,7 +36,11 @@ const REASONS: Record<string, string> = {
|
||||
"project.members.manage": TEXT.modules.permissions.projectMembersManage,
|
||||
"site.manage": TEXT.modules.permissions.siteManage,
|
||||
"site.cra.bind": TEXT.modules.permissions.siteCraBind,
|
||||
"fees.contract.write": TEXT.modules.permissions.feeContractsWrite,
|
||||
"fees.contract.create": TEXT.modules.permissions.feeContractsWrite,
|
||||
"fees.contract.update": TEXT.modules.permissions.feeContractsWrite,
|
||||
"fees.contract.delete": TEXT.modules.permissions.feeContractsWrite,
|
||||
"documents.create": TEXT.modules.permissions.default,
|
||||
"documents.delete": TEXT.modules.permissions.default,
|
||||
};
|
||||
|
||||
export const usePermission = () => {
|
||||
@@ -63,7 +71,11 @@ export const usePermission = () => {
|
||||
"project.members.manage": "project_members:update",
|
||||
"site.manage": "sites:update",
|
||||
"site.cra.bind": "sites:update",
|
||||
"fees.contract.write": "fees_contracts:create",
|
||||
"fees.contract.create": "fees_contracts:create",
|
||||
"fees.contract.update": "fees_contracts:update",
|
||||
"fees.contract.delete": "fees_contracts:delete",
|
||||
"documents.create": "documents:create",
|
||||
"documents.delete": "documents:delete",
|
||||
"fees.attachment.delete": "fees_attachments:delete",
|
||||
"file.attachment.delete": "attachments:delete",
|
||||
"audit.export.read": "audit_logs:read",
|
||||
|
||||
@@ -6,11 +6,20 @@ describe("project route permissions", () => {
|
||||
expect(getProjectRoutePermission("/project/overview")).toEqual({ operationKey: "project_overview:read" });
|
||||
expect(getProjectRoutePermission("/project/milestones")).toEqual({ operationKey: "project_milestones:read" });
|
||||
expect(getProjectRoutePermission("/finance/contracts")).toEqual({ operationKey: "finance_contracts:read" });
|
||||
expect(getProjectRoutePermission("/finance/contracts/new")).toEqual({ operationKey: "finance_contracts:create" });
|
||||
expect(getProjectRoutePermission("/finance/contracts/abc/edit")).toEqual({ operationKey: "finance_contracts:update" });
|
||||
expect(getProjectRoutePermission("/drug/shipments")).toEqual({ operationKey: "drug_shipments:read" });
|
||||
expect(getProjectRoutePermission("/startup/feasibility/new")).toEqual({ operationKey: "ethics:read" });
|
||||
expect(getProjectRoutePermission("/startup/kickoff/new")).toEqual({ operationKey: "startup_auth:read" });
|
||||
expect(getProjectRoutePermission("/drug/shipments/new")).toEqual({ operationKey: "drug_shipments:create" });
|
||||
expect(getProjectRoutePermission("/drug/shipments/abc/edit")).toEqual({ operationKey: "drug_shipments:update" });
|
||||
expect(getProjectRoutePermission("/subjects/new")).toEqual({ operationKey: "subjects:create" });
|
||||
expect(getProjectRoutePermission("/subjects/abc/edit")).toEqual({ operationKey: "subjects:update" });
|
||||
expect(getProjectRoutePermission("/startup/feasibility/new")).toEqual({ operationKey: "ethics:create" });
|
||||
expect(getProjectRoutePermission("/startup/feasibility/abc/edit")).toEqual({ operationKey: "ethics:update" });
|
||||
expect(getProjectRoutePermission("/startup/kickoff/new")).toEqual({ operationKey: "startup_auth:create" });
|
||||
expect(getProjectRoutePermission("/startup/kickoff/abc/edit")).toEqual({ operationKey: "startup_auth:update" });
|
||||
expect(getProjectRoutePermission("/knowledge/medical-consult/abc")).toEqual({ operationKey: "faq:read" });
|
||||
expect(getProjectRoutePermission("/knowledge/notes/new")).toEqual({ operationKey: "knowledge_notes:read" });
|
||||
expect(getProjectRoutePermission("/knowledge/notes/new")).toEqual({ operationKey: "knowledge_notes:create" });
|
||||
expect(getProjectRoutePermission("/knowledge/notes/abc/edit")).toEqual({ operationKey: "knowledge_notes:update" });
|
||||
});
|
||||
|
||||
it("rejects project routes when the role lacks operation permission", () => {
|
||||
|
||||
@@ -6,6 +6,13 @@ export type ProjectRoutePermission = {
|
||||
};
|
||||
|
||||
const routePermissions: Array<{ prefixes: string[]; permission: ProjectRoutePermission }> = [
|
||||
{ prefixes: ["/fees/contracts/new"], permission: { operationKey: "fees_contracts:create" } },
|
||||
{ prefixes: ["/finance/contracts/new"], permission: { operationKey: "finance_contracts:create" } },
|
||||
{ prefixes: ["/drug/shipments/new"], permission: { operationKey: "drug_shipments:create" } },
|
||||
{ prefixes: ["/startup/feasibility/new", "/startup/ethics/new"], permission: { operationKey: "ethics:create" } },
|
||||
{ prefixes: ["/startup/kickoff/new", "/startup/training/new"], permission: { operationKey: "startup_auth:create" } },
|
||||
{ prefixes: ["/subjects/new"], permission: { operationKey: "subjects:create" } },
|
||||
{ prefixes: ["/knowledge/notes/new"], permission: { operationKey: "knowledge_notes:create" } },
|
||||
{ prefixes: ["/project/overview"], permission: { operationKey: "project_overview:read" } },
|
||||
{ prefixes: ["/project/milestones"], permission: { operationKey: "project_milestones:read" } },
|
||||
{ prefixes: ["/fees/contracts"], permission: { operationKey: "fees_contracts:read" } },
|
||||
@@ -23,6 +30,18 @@ const routePermissions: Array<{ prefixes: string[]; permission: ProjectRoutePerm
|
||||
{ prefixes: ["/knowledge/notes", "/knowledge/support-files", "/knowledge/instruction-files"], permission: { operationKey: "knowledge_notes:read" } },
|
||||
];
|
||||
|
||||
const editRoutePermissions: Array<{ pattern: RegExp; permission: ProjectRoutePermission }> = [
|
||||
{ pattern: /^\/fees\/contracts\/[^/]+\/edit$/, permission: { operationKey: "fees_contracts:update" } },
|
||||
{ pattern: /^\/finance\/contracts\/[^/]+\/edit$/, permission: { operationKey: "finance_contracts:update" } },
|
||||
{ pattern: /^\/drug\/shipments\/[^/]+\/edit$/, permission: { operationKey: "drug_shipments:update" } },
|
||||
{ pattern: /^\/startup\/feasibility\/[^/]+\/edit$/, permission: { operationKey: "ethics:update" } },
|
||||
{ pattern: /^\/startup\/ethics\/[^/]+\/edit$/, permission: { operationKey: "ethics:update" } },
|
||||
{ pattern: /^\/startup\/kickoff\/[^/]+\/edit$/, permission: { operationKey: "startup_auth:update" } },
|
||||
{ pattern: /^\/startup\/training\/[^/]+\/edit$/, permission: { operationKey: "startup_auth:update" } },
|
||||
{ pattern: /^\/subjects\/[^/]+\/edit$/, permission: { operationKey: "subjects:update" } },
|
||||
{ pattern: /^\/knowledge\/notes\/[^/]+\/edit$/, permission: { operationKey: "knowledge_notes:update" } },
|
||||
];
|
||||
|
||||
export const projectRouteLandingPaths = [
|
||||
"/project/overview",
|
||||
"/project/milestones",
|
||||
@@ -44,6 +63,11 @@ export const projectRouteLandingPaths = [
|
||||
|
||||
export const getProjectRoutePermission = (path: string): ProjectRoutePermission | null => {
|
||||
const normalized = path || "";
|
||||
for (const item of editRoutePermissions) {
|
||||
if (item.pattern.test(normalized)) {
|
||||
return item.permission;
|
||||
}
|
||||
}
|
||||
for (const item of routePermissions) {
|
||||
if (item.prefixes.some((prefix) => normalized === prefix || normalized.startsWith(prefix.endsWith("/") ? prefix : `${prefix}/`))) {
|
||||
return item.permission;
|
||||
|
||||
Reference in New Issue
Block a user