修正项目访问与角色排序体验
- 登录成功后按用户恢复上次项目,管理员优先选择启用项目\n- 项目详情路由增加 setup_config:read 权限校验,未授权时回到可访问页面\n- 项目管理操作按当前项目行角色读取权限,避免误用首个角色权限\n- 角色模板排序中固定 PM 优先,保持角色列表、生效管理和权限编辑器顺序一致\n- 补充登录、路由、项目管理和角色排序相关测试
This commit is contained in:
@@ -61,4 +61,17 @@ describe("Login protocol agreement", () => {
|
||||
expect(source).toContain(":autocomplete=\"form.rememberPassword ? 'current-password' : 'new-password'\"");
|
||||
expect(source).not.toContain('autocomplete="current-password"');
|
||||
});
|
||||
|
||||
it("restores the current user's last project before routing after login", () => {
|
||||
const source = readLoginView();
|
||||
const loginCallIndex = source.indexOf("auth.login(form.email, form.password)");
|
||||
const userKeyIndex = source.indexOf("const userKey = auth.user?.email || form.email");
|
||||
const restoreIndex = source.indexOf("studyStore.restoreStudyForUser(userKey");
|
||||
const projectOverviewRouteIndex = source.indexOf('router.push("/project/overview")');
|
||||
|
||||
expect(userKeyIndex).toBeGreaterThan(loginCallIndex);
|
||||
expect(restoreIndex).toBeGreaterThan(loginCallIndex);
|
||||
expect(restoreIndex).toBeLessThan(projectOverviewRouteIndex);
|
||||
expect(source).toContain("preferActive: !!auth.user?.is_admin");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -239,13 +239,8 @@ const onSubmit = async () => {
|
||||
await auth.login(form.email, form.password);
|
||||
await tryStoreBrowserCredential(form.email, form.password);
|
||||
const studyStore = useStudyStore();
|
||||
if (!studyStore.currentStudy) {
|
||||
if (auth.user?.is_admin) {
|
||||
await studyStore.ensureDefaultActiveStudy();
|
||||
} else {
|
||||
await studyStore.ensureDefaultStudy();
|
||||
}
|
||||
}
|
||||
const userKey = auth.user?.email || form.email;
|
||||
await studyStore.restoreStudyForUser(userKey, { preferActive: !!auth.user?.is_admin });
|
||||
if (studyStore.currentStudy) {
|
||||
router.push("/project/overview");
|
||||
} else {
|
||||
|
||||
@@ -83,6 +83,14 @@ describe("project management access", () => {
|
||||
expect(source).toContain('if (!canProject(row, "setup_config", "read"))');
|
||||
});
|
||||
|
||||
it("checks project management actions against the current row role instead of the first permission role", () => {
|
||||
const source = readProjects();
|
||||
|
||||
expect(source).toContain("const role = row.role_in_study || \"\";");
|
||||
expect(source).toContain("const rolePerms = perms[role];");
|
||||
expect(source).not.toContain("Object.values(perms)[0]");
|
||||
});
|
||||
|
||||
it("keeps audit export write mappings on the export operation", () => {
|
||||
const projects = readProjects();
|
||||
const router = readRouter();
|
||||
|
||||
@@ -226,7 +226,8 @@ const canProject = (row: Study, module: string, action: "read" | "write") => {
|
||||
if (!operationKey) return false;
|
||||
const perms = permissionsByProject.value[row.id];
|
||||
if (!perms) return false;
|
||||
const rolePerms = Object.values(perms)[0];
|
||||
const role = row.role_in_study || "";
|
||||
const rolePerms = perms[role];
|
||||
if (!rolePerms) return false;
|
||||
return isApiPermissionAllowed(rolePerms[operationKey]);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user