统一项目权限读取模型
1、合并列表与详情读取权限,统一使用 subjects:read、project_members:read、monitoring_issues:read 等业务读取 key。 2、增加历史读取权限 key 的兼容映射,确保存量项目权限覆盖值不会丢失。 3、同步前端权限工具、路由权限与权限管理页面,避免继续引用已合并的旧权限 key。 4、补充项目角色启停保护与抽屉未保存变更守卫,防止停用 PM 或仍有关联成员的角色。
This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { reactive } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
import { useDrawerDirtyGuard } from "./drawerDirtyGuard";
|
||||
|
||||
vi.mock("element-plus", () => ({
|
||||
ElMessage: {
|
||||
warning: vi.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe("useDrawerDirtyGuard", () => {
|
||||
it("allows drawer close when the form has no changes", () => {
|
||||
const form = reactive({ name: "设备A", status: "启用" });
|
||||
const guard = useDrawerDirtyGuard(() => form);
|
||||
const done = vi.fn();
|
||||
|
||||
guard.syncBaseline();
|
||||
guard.beforeClose(done);
|
||||
|
||||
expect(done).toHaveBeenCalledTimes(1);
|
||||
expect(ElMessage.warning).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("blocks drawer close when the form has unsaved changes", () => {
|
||||
const form = reactive({ name: "设备A", status: "启用" });
|
||||
const guard = useDrawerDirtyGuard(() => form);
|
||||
const done = vi.fn();
|
||||
|
||||
guard.syncBaseline();
|
||||
form.name = "设备B";
|
||||
guard.beforeClose(done);
|
||||
|
||||
expect(done).not.toHaveBeenCalled();
|
||||
expect(ElMessage.warning).toHaveBeenCalledWith("请先保存或取消编辑");
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,25 @@
|
||||
import { computed, ref } from "vue";
|
||||
import { ElMessage } from "element-plus";
|
||||
|
||||
const snapshot = (value: unknown) => JSON.stringify(value);
|
||||
|
||||
export const useDrawerDirtyGuard = (getValue: () => unknown) => {
|
||||
const baseline = ref("");
|
||||
const syncBaseline = () => {
|
||||
baseline.value = snapshot(getValue());
|
||||
};
|
||||
const isDirty = computed(() => baseline.value !== snapshot(getValue()));
|
||||
const beforeClose = (done: () => void) => {
|
||||
if (isDirty.value) {
|
||||
ElMessage.warning("请先保存或取消编辑");
|
||||
return;
|
||||
}
|
||||
done();
|
||||
};
|
||||
|
||||
return {
|
||||
isDirty,
|
||||
syncBaseline,
|
||||
beforeClose,
|
||||
};
|
||||
};
|
||||
@@ -12,25 +12,46 @@ describe("permission project role model", () => {
|
||||
expect(source).toContain("getProjectRole");
|
||||
expect(source).toContain("study.currentStudyRole");
|
||||
expect(source).toContain("study.currentPermissions");
|
||||
expect(source).toContain('"subject.delete": "subjects:delete"');
|
||||
expect(source).toContain('"faq.edit": "faq:update"');
|
||||
expect(source).toContain('"faq.update": "faq:update"');
|
||||
expect(source).toContain('"faq.delete": "faq:delete"');
|
||||
expect(source).toContain('"ae.create": "subject_aes:create"');
|
||||
expect(source).toContain('"ae.close": "subject_aes: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('"project.members.list": "project_members:list"');
|
||||
expect(source).toContain('"project.members.candidates": "project_members:candidates"');
|
||||
expect(source).toContain('"project.members.list": "project_members:read"');
|
||||
expect(source).toContain('"project.members.candidates": "project_members:read"');
|
||||
expect(source).toContain('"project.members.create": "project_members:create"');
|
||||
expect(source).toContain('"project.members.update": "project_members:update"');
|
||||
expect(source).toContain('"project.members.delete": "project_members:delete"');
|
||||
expect(source).toContain('"documents.create": "documents:create"');
|
||||
expect(source).toContain('"documents.delete": "documents:delete"');
|
||||
expect(source).toContain('"precautions.create": "precautions:create"');
|
||||
expect(source).toContain('"precautions.update": "precautions:update"');
|
||||
expect(source).toContain('"precautions.delete": "precautions:delete"');
|
||||
expect(source).toContain('"faq.category.create": "faq_category:create"');
|
||||
expect(source).toContain('"faq.category.update": "faq_category:update"');
|
||||
expect(source).toContain('"faq.category.delete": "faq_category:delete"');
|
||||
expect(source).toContain('"faq.reply.delete": "faq_reply:delete"');
|
||||
expect(source).toContain('"startup.initiation.create": "startup_initiation:create"');
|
||||
expect(source).toContain('"startup.initiation.update": "startup_initiation:update"');
|
||||
expect(source).toContain('"startup.initiation.delete": "startup_initiation:delete"');
|
||||
expect(source).toContain('"startup.ethics.create": "startup_ethics:create"');
|
||||
expect(source).toContain('"startup.ethics.update": "startup_ethics:update"');
|
||||
expect(source).toContain('"startup.ethics.delete": "startup_ethics:delete"');
|
||||
expect(source).toContain('"startup.auth.create": "startup_auth:create"');
|
||||
expect(source).toContain('"startup.auth.update": "startup_auth:update"');
|
||||
expect(source).toContain('"startup.auth.delete": "startup_auth:delete"');
|
||||
expect(source).toContain('"project.milestones.update": "project_milestones:update"');
|
||||
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"');
|
||||
expect(source).not.toContain('"precautions.write": "precautions:create"');
|
||||
expect(source).not.toContain("project.members.manage");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -10,11 +10,32 @@ const PERMISSIONS: Record<string, string[]> = {
|
||||
"subject.enroll": ["ADMIN"],
|
||||
"subject.complete": ["ADMIN"],
|
||||
"subject.drop": ["ADMIN"],
|
||||
"subject.delete": ["ADMIN"],
|
||||
"ae.create": ["ADMIN"],
|
||||
"ae.close": ["ADMIN"],
|
||||
"faq.edit": ["ADMIN"],
|
||||
"faq.update": ["ADMIN"],
|
||||
"faq.delete": ["ADMIN"],
|
||||
"faq.create": ["ADMIN"],
|
||||
"faq.reply": ["ADMIN"],
|
||||
"faq.reply.delete": ["ADMIN"],
|
||||
"faq.category.read": ["ADMIN"],
|
||||
"faq.category.create": ["ADMIN"],
|
||||
"faq.category.update": ["ADMIN"],
|
||||
"faq.category.delete": ["ADMIN"],
|
||||
"precautions.create": ["ADMIN"],
|
||||
"precautions.update": ["ADMIN"],
|
||||
"precautions.delete": ["ADMIN"],
|
||||
"startup.initiation.create": ["ADMIN"],
|
||||
"startup.initiation.update": ["ADMIN"],
|
||||
"startup.initiation.delete": ["ADMIN"],
|
||||
"startup.ethics.create": ["ADMIN"],
|
||||
"startup.ethics.update": ["ADMIN"],
|
||||
"startup.ethics.delete": ["ADMIN"],
|
||||
"startup.auth.create": ["ADMIN"],
|
||||
"startup.auth.update": ["ADMIN"],
|
||||
"startup.auth.delete": ["ADMIN"],
|
||||
"project.milestones.update": ["ADMIN"],
|
||||
"project.members.list": ["ADMIN"],
|
||||
"project.members.candidates": ["ADMIN"],
|
||||
"project.members.create": ["ADMIN"],
|
||||
@@ -37,8 +58,28 @@ const REASONS: Record<string, string> = {
|
||||
"subject.drop": TEXT.modules.permissions.subjectDrop,
|
||||
"ae.close": TEXT.modules.permissions.aeClose,
|
||||
"faq.edit": TEXT.modules.permissions.faqEdit,
|
||||
"faq.update": TEXT.modules.permissions.faqEdit,
|
||||
"faq.delete": TEXT.modules.permissions.faqEdit,
|
||||
"faq.create": TEXT.modules.permissions.faqCreate,
|
||||
"faq.reply": TEXT.modules.permissions.faqReply,
|
||||
"faq.reply.delete": TEXT.modules.permissions.faqReply,
|
||||
"faq.category.read": TEXT.modules.permissions.default,
|
||||
"faq.category.create": TEXT.modules.permissions.faqEdit,
|
||||
"faq.category.update": TEXT.modules.permissions.faqEdit,
|
||||
"faq.category.delete": TEXT.modules.permissions.faqEdit,
|
||||
"precautions.create": TEXT.modules.permissions.default,
|
||||
"precautions.update": TEXT.modules.permissions.default,
|
||||
"precautions.delete": TEXT.modules.permissions.default,
|
||||
"startup.initiation.create": TEXT.modules.permissions.default,
|
||||
"startup.initiation.update": TEXT.modules.permissions.default,
|
||||
"startup.initiation.delete": TEXT.modules.permissions.default,
|
||||
"startup.ethics.create": TEXT.modules.permissions.default,
|
||||
"startup.ethics.update": TEXT.modules.permissions.default,
|
||||
"startup.ethics.delete": TEXT.modules.permissions.default,
|
||||
"startup.auth.create": TEXT.modules.permissions.default,
|
||||
"startup.auth.update": TEXT.modules.permissions.default,
|
||||
"startup.auth.delete": TEXT.modules.permissions.default,
|
||||
"project.milestones.update": TEXT.modules.permissions.default,
|
||||
"project.members.list": TEXT.modules.permissions.projectMembersManage,
|
||||
"project.members.candidates": TEXT.modules.permissions.projectMembersManage,
|
||||
"project.members.create": TEXT.modules.permissions.projectMembersManage,
|
||||
@@ -71,16 +112,36 @@ export const usePermission = () => {
|
||||
"subject.enroll": "subjects:update",
|
||||
"subject.complete": "subjects:update",
|
||||
"subject.drop": "subjects:update",
|
||||
"subject.delete": "subjects:delete",
|
||||
"ae.create": "subject_aes:create",
|
||||
"ae.close": "subject_aes:update",
|
||||
"project.overview.read": "project_overview:read",
|
||||
"faq.edit": "faq:update",
|
||||
"faq.update": "faq:update",
|
||||
"faq.delete": "faq:delete",
|
||||
"faq.create": "faq:create",
|
||||
"faq.reply": "faq_reply:create",
|
||||
"faq.reply.delete": "faq_reply:delete",
|
||||
"faq.category.read": "faq_category:read",
|
||||
"faq.category.create": "faq_category:create",
|
||||
"faq.category.update": "faq_category:update",
|
||||
"faq.category.delete": "faq_category:delete",
|
||||
"precautions.read": "precautions:read",
|
||||
"precautions.write": "precautions:create",
|
||||
"project.members.list": "project_members:list",
|
||||
"project.members.candidates": "project_members:candidates",
|
||||
"precautions.create": "precautions:create",
|
||||
"precautions.update": "precautions:update",
|
||||
"precautions.delete": "precautions:delete",
|
||||
"startup.initiation.create": "startup_initiation:create",
|
||||
"startup.initiation.update": "startup_initiation:update",
|
||||
"startup.initiation.delete": "startup_initiation:delete",
|
||||
"startup.ethics.create": "startup_ethics:create",
|
||||
"startup.ethics.update": "startup_ethics:update",
|
||||
"startup.ethics.delete": "startup_ethics:delete",
|
||||
"startup.auth.create": "startup_auth:create",
|
||||
"startup.auth.update": "startup_auth:update",
|
||||
"startup.auth.delete": "startup_auth:delete",
|
||||
"project.milestones.update": "project_milestones:update",
|
||||
"project.members.list": "project_members:read",
|
||||
"project.members.candidates": "project_members:read",
|
||||
"project.members.create": "project_members:create",
|
||||
"project.members.update": "project_members:update",
|
||||
"project.members.delete": "project_members:delete",
|
||||
|
||||
@@ -5,25 +5,30 @@ describe("project route permissions", () => {
|
||||
it("maps project routes to backend operation keys", () => {
|
||||
expect(getProjectRoutePermission("/project/overview")).toEqual({ operationKey: "project_overview:read" });
|
||||
expect(getProjectRoutePermission("/project/milestones")).toEqual({ operationKey: "project_milestones:read" });
|
||||
expect(getProjectRoutePermission("/fees/contracts")).toEqual({ operationKey: "fees_contracts:read" });
|
||||
expect(getProjectRoutePermission("/finance/contracts")).toBeNull();
|
||||
expect(getProjectRoutePermission("/finance/contracts/new")).toBeNull();
|
||||
expect(getProjectRoutePermission("/finance/contracts/abc/edit")).toBeNull();
|
||||
expect(getProjectRoutePermission("/drug/shipments")).toEqual({ operationKey: "drug_shipments:read" });
|
||||
expect(getProjectRoutePermission("/drug/shipments/new")).toEqual({ operationKey: "drug_shipments:create" });
|
||||
expect(getProjectRoutePermission("/drug/shipments/abc/edit")).toEqual({ operationKey: "drug_shipments:update" });
|
||||
expect(getProjectRoutePermission("/drug/shipments/abc")).toEqual({ operationKey: "drug_shipments:read" });
|
||||
expect(getProjectRoutePermission("/subjects/new")).toEqual({ operationKey: "subjects:create" });
|
||||
expect(getProjectRoutePermission("/subjects/abc/edit")).toEqual({ operationKey: "subjects:update" });
|
||||
expect(getProjectRoutePermission("/risk-issues")).toEqual({ operationKey: "subject_aes:list" });
|
||||
expect(getProjectRoutePermission("/risk-issues/sae")).toEqual({ operationKey: "subject_aes:list" });
|
||||
expect(getProjectRoutePermission("/risk-issues")).toEqual({ operationKey: "subject_aes:read" });
|
||||
expect(getProjectRoutePermission("/risk-issues/sae")).toEqual({ operationKey: "subject_aes:read" });
|
||||
expect(getProjectRoutePermission("/risk-issues/pd")).toEqual({ operationKey: "subject_pds:list" });
|
||||
expect(getProjectRoutePermission("/risk-issues/monitoring-visits")).toEqual({ operationKey: "monitoring_issues:list" });
|
||||
expect(getProjectRoutePermission("/risk-issues/monitoring-visits")).toEqual({ operationKey: "monitoring_issues:read" });
|
||||
expect(getProjectRoutePermission("/etmf")).toEqual({ operationKey: "documents:read" });
|
||||
expect(getProjectRoutePermission("/startup/feasibility/new")).toEqual({ operationKey: "startup_initiation:create" });
|
||||
expect(getProjectRoutePermission("/startup/feasibility/abc/edit")).toEqual({ operationKey: "startup_initiation:update" });
|
||||
expect(getProjectRoutePermission("/startup/ethics/new")).toEqual({ operationKey: "startup_ethics:create" });
|
||||
expect(getProjectRoutePermission("/startup/ethics/abc/edit")).toEqual({ operationKey: "startup_ethics:update" });
|
||||
expect(getProjectRoutePermission("/startup/feasibility-ethics")).toEqual({
|
||||
operationKeys: ["startup_initiation:read", "startup_ethics:read"],
|
||||
});
|
||||
expect(getProjectRoutePermission("/startup/kickoff/new")).toEqual({ operationKey: "startup_auth:create" });
|
||||
expect(getProjectRoutePermission("/startup/kickoff/abc/edit")).toEqual({ operationKey: "startup_auth:update" });
|
||||
expect(getProjectRoutePermission("/startup/kickoff/abc/edit")).toBeNull();
|
||||
expect(getProjectRoutePermission("/startup/training/new")).toBeNull();
|
||||
expect(getProjectRoutePermission("/startup/training/abc/edit")).toBeNull();
|
||||
expect(getProjectRoutePermission("/knowledge/medical-consult/abc")).toEqual({ operationKey: "faq:read" });
|
||||
expect(getProjectRoutePermission("/knowledge/precautions/new")).toEqual({ operationKey: "precautions:create" });
|
||||
expect(getProjectRoutePermission("/knowledge/precautions/abc/edit")).toEqual({ operationKey: "precautions:update" });
|
||||
@@ -42,4 +47,46 @@ describe("project route permissions", () => {
|
||||
expect(hasProjectPermission(matrix, "CRA", getProjectRoutePermission("/knowledge/precautions"), false)).toBe(true);
|
||||
expect(findFirstAccessibleProjectPath(matrix, "CRA", false)).toBe("/knowledge/precautions");
|
||||
});
|
||||
|
||||
it("can fall back to every accessible risk issue child module", () => {
|
||||
expect(
|
||||
findFirstAccessibleProjectPath(
|
||||
{
|
||||
QA: {
|
||||
"subject_aes:read": { allowed: false },
|
||||
"subject_pds:list": { allowed: true },
|
||||
"monitoring_issues:read": { allowed: false },
|
||||
},
|
||||
} as any,
|
||||
"QA",
|
||||
false,
|
||||
),
|
||||
).toBe("/risk-issues/pd");
|
||||
|
||||
expect(
|
||||
findFirstAccessibleProjectPath(
|
||||
{
|
||||
QA: {
|
||||
"subject_aes:read": { allowed: false },
|
||||
"subject_pds:list": { allowed: false },
|
||||
"monitoring_issues:read": { allowed: true },
|
||||
},
|
||||
} as any,
|
||||
"QA",
|
||||
false,
|
||||
),
|
||||
).toBe("/risk-issues/monitoring-visits");
|
||||
});
|
||||
|
||||
it("allows combined landing pages when any child module is readable", () => {
|
||||
const matrix = {
|
||||
CRA: {
|
||||
"startup_initiation:read": { allowed: false },
|
||||
"startup_ethics:read": { allowed: true },
|
||||
},
|
||||
} as any;
|
||||
|
||||
expect(hasProjectPermission(matrix, "CRA", getProjectRoutePermission("/startup/feasibility-ethics"), false)).toBe(true);
|
||||
expect(findFirstAccessibleProjectPath(matrix, "CRA", false)).toBe("/startup/feasibility-ethics");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,15 +2,14 @@ import type { ApiEndpointPermissionsResponse } from "../types/api";
|
||||
import { isApiPermissionAllowed } from "./apiPermissionValue";
|
||||
|
||||
export type ProjectRoutePermission = {
|
||||
operationKey: string;
|
||||
operationKey?: string;
|
||||
operationKeys?: string[];
|
||||
};
|
||||
|
||||
const routePermissions: Array<{ prefixes: string[]; permission: ProjectRoutePermission }> = [
|
||||
{ prefixes: ["/fees/contracts/new"], permission: { operationKey: "fees_contracts:create" } },
|
||||
{ prefixes: ["/drug/shipments/new"], permission: { operationKey: "drug_shipments:create" } },
|
||||
{ prefixes: ["/startup/feasibility/new"], permission: { operationKey: "startup_initiation:create" } },
|
||||
{ prefixes: ["/startup/ethics/new"], permission: { operationKey: "startup_ethics:create" } },
|
||||
{ prefixes: ["/startup/kickoff/new", "/startup/training/new"], permission: { operationKey: "startup_auth:create" } },
|
||||
{ prefixes: ["/startup/kickoff/new"], permission: { operationKey: "startup_auth:create" } },
|
||||
{ prefixes: ["/subjects/new"], permission: { operationKey: "subjects:create" } },
|
||||
{ prefixes: ["/knowledge/precautions/new"], permission: { operationKey: "precautions:create" } },
|
||||
{ prefixes: ["/project/overview"], permission: { operationKey: "project_overview:read" } },
|
||||
@@ -19,29 +18,32 @@ const routePermissions: Array<{ prefixes: string[]; permission: ProjectRoutePerm
|
||||
{ prefixes: ["/drug/shipments"], permission: { operationKey: "drug_shipments:read" } },
|
||||
{ prefixes: ["/materials/equipment"], permission: { operationKey: "material_equipments:read" } },
|
||||
{ prefixes: ["/file-versions", "/trial/", "/documents/"], permission: { operationKey: "documents:read" } },
|
||||
{ prefixes: ["/startup/feasibility-ethics", "/startup/feasibility"], permission: { operationKey: "startup_initiation:read" } },
|
||||
{ prefixes: ["/startup/feasibility-ethics"], permission: { operationKeys: ["startup_initiation:read", "startup_ethics:read"] } },
|
||||
{ prefixes: ["/startup/feasibility"], permission: { operationKey: "startup_initiation:read" } },
|
||||
{ prefixes: ["/startup/ethics"], permission: { operationKey: "startup_ethics:read" } },
|
||||
{ prefixes: ["/startup/meeting-auth", "/startup/kickoff", "/startup/training"], permission: { operationKey: "startup_auth:read" } },
|
||||
{ prefixes: ["/subjects"], permission: { operationKey: "subjects:read" } },
|
||||
{ prefixes: ["/risk-issues/monitoring-visits"], permission: { operationKey: "monitoring_issues:list" } },
|
||||
{ prefixes: ["/risk-issues/monitoring-visits"], permission: { operationKey: "monitoring_issues:read" } },
|
||||
{ prefixes: ["/risk-issues/pd"], permission: { operationKey: "subject_pds:list" } },
|
||||
{ prefixes: ["/risk-issues"], permission: { operationKey: "subject_aes:list" } },
|
||||
{ prefixes: ["/risk-issues"], permission: { operationKey: "subject_aes:read" } },
|
||||
{ prefixes: ["/etmf"], permission: { operationKey: "documents:read" } },
|
||||
{ prefixes: ["/knowledge/medical-consult"], permission: { operationKey: "faq:read" } },
|
||||
{ prefixes: ["/knowledge/precautions", "/knowledge/support-files", "/knowledge/instruction-files"], permission: { operationKey: "precautions:read" } },
|
||||
];
|
||||
|
||||
const editRoutePermissions: Array<{ pattern: RegExp; permission: ProjectRoutePermission }> = [
|
||||
{ pattern: /^\/fees\/contracts\/[^/]+\/edit$/, permission: { operationKey: "fees_contracts:update" } },
|
||||
{ pattern: /^\/drug\/shipments\/[^/]+\/edit$/, permission: { operationKey: "drug_shipments:update" } },
|
||||
{ pattern: /^\/startup\/feasibility\/[^/]+\/edit$/, permission: { operationKey: "startup_initiation:update" } },
|
||||
{ pattern: /^\/startup\/ethics\/[^/]+\/edit$/, permission: { operationKey: "startup_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\/precautions\/[^/]+\/edit$/, permission: { operationKey: "precautions:update" } },
|
||||
];
|
||||
|
||||
const removedRoutePatterns = [
|
||||
/^\/startup\/kickoff\/[^/]+\/edit$/,
|
||||
/^\/startup\/training\/new$/,
|
||||
/^\/startup\/training\/[^/]+\/edit$/,
|
||||
];
|
||||
|
||||
export const projectRouteLandingPaths = [
|
||||
"/project/overview",
|
||||
"/project/milestones",
|
||||
@@ -53,6 +55,8 @@ export const projectRouteLandingPaths = [
|
||||
"/startup/meeting-auth",
|
||||
"/subjects",
|
||||
"/risk-issues/sae",
|
||||
"/risk-issues/pd",
|
||||
"/risk-issues/monitoring-visits",
|
||||
"/etmf",
|
||||
"/knowledge/medical-consult",
|
||||
"/knowledge/precautions",
|
||||
@@ -62,6 +66,9 @@ export const projectRouteLandingPaths = [
|
||||
|
||||
export const getProjectRoutePermission = (path: string): ProjectRoutePermission | null => {
|
||||
const normalized = path || "";
|
||||
if (removedRoutePatterns.some((pattern) => pattern.test(normalized))) {
|
||||
return null;
|
||||
}
|
||||
for (const item of editRoutePermissions) {
|
||||
if (item.pattern.test(normalized)) {
|
||||
return item.permission;
|
||||
@@ -83,7 +90,8 @@ export const hasProjectPermission = (
|
||||
) => {
|
||||
if (!permission || isAdmin) return true;
|
||||
if (!role || !permissions) return false;
|
||||
return isApiPermissionAllowed(permissions[role]?.[permission.operationKey]);
|
||||
const operationKeys = permission.operationKeys || (permission.operationKey ? [permission.operationKey] : []);
|
||||
return operationKeys.some((operationKey) => isApiPermissionAllowed(permissions[role]?.[operationKey]));
|
||||
};
|
||||
|
||||
export const findFirstAccessibleProjectPath = (
|
||||
|
||||
Reference in New Issue
Block a user