feat(工作台): 工作台首页用户权限开通模块的项目查询

This commit is contained in:
guoyuqi 2024-11-06 10:28:07 +08:00 committed by Craftsman
parent 8212fb094a
commit 93779a655a
6 changed files with 350 additions and 28 deletions

View File

@ -0,0 +1,40 @@
package io.metersphere.dashboard.constants;
public enum DashboardUserLayoutKeys {
/**
* default
*/
CREATE_BY_ME, //我创建的
PROJECT_VIEW,//项目概览
PROJECT_MEMBER_VIEW,//项目成员概览
/**
* functional
*/
CASE_COUNT, //用例数量统计
ASSOCIATE_CASE_COUNT,//关联用例统计
REVIEW_CASE_COUNT,//用例评审数量统计
REVIEWING_BY_ME, //待我评审
/**
* api
*/
API_COUNT,//接口数量统计
API_CASE_COUNT,//接口用例数量统计
SCENARIO_COUNT,//场景用例数量统计
API_CHANGE,//接口变更统计
/**
* test_plan
*/
TEST_PLAN_COUNT,//测试计划数量统计
PLAN_LEGACY_BUG,//计划遗留bug统计
/**
* bug
*/
BUG_COUNT,//缺陷数量统计
CREATE_BUG_BY_ME, //我创建的缺陷
HANDLE_BUG_BY_ME, //待我处理的缺陷
BUG_HANDLE_USER // 缺陷处理人统计
}

View File

@ -0,0 +1,23 @@
package io.metersphere.dashboard.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.util.List;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class LayoutDTO {
@Schema(description = "布局卡片key")
private String id;
@Schema(description = "排序")
private Integer pos;
@Schema(description = "全屏/半屏")
private Boolean fullScreen;
@Schema(description = "选中的项目ID")
private List<String> projectIds;
}

View File

@ -0,0 +1,59 @@
package io.metersphere.dashboard.request;
import com.google.common.base.CaseFormat;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.Valid;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.Pattern;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
import java.util.List;
import java.util.Map;
/**
* @author guoyuqi
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class DashboardBaseRequest {
@Schema(description = "组织ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{organization.id.not_blank}")
private String organizationId;
@Min(value = 1, message = "当前页码必须大于0")
@Schema(description = "当前页码")
private int current;
@Min(value = 5, message = "每页显示条数必须不小于5")
@Max(value = 500, message = "每页显示条数不能大于500")
@Schema(description = "每页显示条数")
private int pageSize;
@Schema(description = "过滤字段")
private Map<String, List<String>> filter;
@Schema(description = "排序字段model中的字段 : asc/desc")
private Map<@Valid @Pattern(regexp = "^[A-Za-z]+$") String, @Valid @NotBlank String> sort;
public String getSortString() {
if (sort == null || sort.isEmpty()) {
return null;
}
StringBuilder sb = new StringBuilder();
for (Map.Entry<String, String> entry : sort.entrySet()) {
String column = CaseFormat.LOWER_CAMEL.to(CaseFormat.LOWER_UNDERSCORE, entry.getKey());
sb.append(column)
.append(StringUtils.SPACE)
.append(StringUtils.equalsIgnoreCase(entry.getValue(), "DESC") ? "DESC" : "ASC")
.append(",");
}
return sb.substring(0, sb.length() - 1);
}
}

View File

@ -0,0 +1,16 @@
package io.metersphere.dashboard.request;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.util.List;
@Data
public class DashboardFrontPageRequest extends DashboardBaseRequest{
@Schema(description = "项目ID集合")
private List<String> projectIds;
@Schema(description = "人员集合")
private List<String> handleUsers;
}

View File

@ -0,0 +1,132 @@
package io.metersphere.dashboard.service;
import io.metersphere.project.domain.Project;
import io.metersphere.project.domain.ProjectExample;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.project.service.PermissionCheckService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.dto.user.UserDTO;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.*;
import java.util.stream.Collectors;
@Service
@Transactional(rollbackFor = Exception.class)
public class DashboardProjectService {
@Resource
private PermissionCheckService permissionCheckService;
@Resource
private ProjectMapper projectMapper;
public static final String API_TEST = "apiTest";
public static final String TEST_PLAN = "testPlan";
public static final String FUNCTIONAL_CASE = "caseManagement";
public static final String BUG = "bugManagement";
public Map<String, Set<String>> getPermissionModuleProjectIds(String organizationId, List<String> projectIds, String userId) {
boolean isAdmin = isAdmin(userId);
Set<String> projectSet;
Map<String, String> moduleMap;
if (CollectionUtils.isNotEmpty(projectIds)) {
projectSet = new HashSet<>(projectIds);
ProjectExample projectExample = new ProjectExample();
projectExample.createCriteria().andIdIn(projectIds);
List<Project> projects = projectMapper.selectByExample(projectExample);
moduleMap = projects.stream().collect(Collectors.toMap(Project::getId, Project::getModuleSetting));
} else {
ProjectExample projectExample = new ProjectExample();
projectExample.createCriteria().andOrganizationIdEqualTo(organizationId);
List<Project> projects = projectMapper.selectByExample(projectExample);
projectSet = projects.stream().map(Project::getId).collect(Collectors.toSet());
moduleMap = projects.stream().collect(Collectors.toMap(Project::getId, Project::getModuleSetting));
}
Map<String, Set<String>> hasModuleProjectIds = new HashMap<>();
Map<String, String> finalModuleMap = moduleMap;
Set<String> searchCaseProjectIds = new HashSet<>();
Set<String> searchReviewProjectIds = new HashSet<>();
Set<String> searchApiProjectIds = new HashSet<>();
Set<String> searchApiCaseProjectIds = new HashSet<>();
Set<String> searchScenarioProjectIds = new HashSet<>();
Set<String> searchPlanProjectIds = new HashSet<>();
Set<String> searchBugProjectIds = new HashSet<>();
//查出用户在选中的项目中有读取权限的, admin所有项目都有权限
if (!isAdmin) {
Set<String> permissionSet = getPermissionSet();
Map<String, Set<String>> hasUserPermissionProjectIds = permissionCheckService.getHasUserPermissionProjectIds(userId, projectSet, permissionSet);
//查出这些项目分别有模块的
Set<String> functionalProjectIds = hasUserPermissionProjectIds.get(PermissionConstants.FUNCTIONAL_CASE_READ);
//检查是否开启功能用例模块
if (CollectionUtils.isNotEmpty(functionalProjectIds)) {
searchCaseProjectIds = functionalProjectIds.stream().filter(t -> finalModuleMap.get(t).contains(FUNCTIONAL_CASE)).collect(Collectors.toSet());
}
Set<String> reviewProjectIds = hasUserPermissionProjectIds.get(PermissionConstants.CASE_REVIEW_READ);
if (CollectionUtils.isNotEmpty(reviewProjectIds)) {
searchReviewProjectIds = reviewProjectIds.stream().filter(t -> finalModuleMap.get(t).contains(FUNCTIONAL_CASE)).collect(Collectors.toSet());
}
//检查是否开启接口模块
Set<String> apiProjectIds = hasUserPermissionProjectIds.get(PermissionConstants.PROJECT_API_DEFINITION_READ);
if (CollectionUtils.isNotEmpty(apiProjectIds)) {
searchApiProjectIds = apiProjectIds.stream().filter(t -> finalModuleMap.get(t).contains(API_TEST)).collect(Collectors.toSet());
}
Set<String> apiCaseProjectIds = hasUserPermissionProjectIds.get(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ);
if (CollectionUtils.isNotEmpty(apiCaseProjectIds)) {
searchApiCaseProjectIds = apiCaseProjectIds.stream().filter(t -> finalModuleMap.get(t).contains(API_TEST)).collect(Collectors.toSet());
}
Set<String> scenarioProjectIds = hasUserPermissionProjectIds.get(PermissionConstants.PROJECT_API_SCENARIO_READ);
if (CollectionUtils.isNotEmpty(scenarioProjectIds)) {
searchScenarioProjectIds = scenarioProjectIds.stream().filter(t -> finalModuleMap.get(t).contains(API_TEST)).collect(Collectors.toSet());
}
//检查是否开启测试计划模块
Set<String> planProjectIds = hasUserPermissionProjectIds.get(PermissionConstants.TEST_PLAN_READ);
if (CollectionUtils.isNotEmpty(scenarioProjectIds)) {
searchPlanProjectIds = planProjectIds.stream().filter(t -> finalModuleMap.get(t).contains(TEST_PLAN)).collect(Collectors.toSet());
}
//检查是否开启缺陷模块
Set<String> bugProjectIds = hasUserPermissionProjectIds.get(PermissionConstants.PROJECT_BUG_READ);
if (CollectionUtils.isNotEmpty(bugProjectIds)) {
searchBugProjectIds = bugProjectIds.stream().filter(t -> finalModuleMap.get(t).contains(BUG)).collect(Collectors.toSet());
}
} else {
//查出这些项目分别有模块的
searchCaseProjectIds = projectSet.stream().filter(t -> finalModuleMap.get(t).contains(FUNCTIONAL_CASE)).collect(Collectors.toSet());
searchReviewProjectIds = projectSet.stream().filter(t -> finalModuleMap.get(t).contains(FUNCTIONAL_CASE)).collect(Collectors.toSet());
searchApiProjectIds = projectSet.stream().filter(t -> finalModuleMap.get(t).contains(API_TEST)).collect(Collectors.toSet());
searchApiCaseProjectIds = projectSet.stream().filter(t -> finalModuleMap.get(t).contains(API_TEST)).collect(Collectors.toSet());
searchScenarioProjectIds = projectSet.stream().filter(t -> finalModuleMap.get(t).contains(API_TEST)).collect(Collectors.toSet());
searchPlanProjectIds = projectSet.stream().filter(t -> finalModuleMap.get(t).contains(TEST_PLAN)).collect(Collectors.toSet());
searchBugProjectIds = projectSet.stream().filter(t -> finalModuleMap.get(t).contains(BUG)).collect(Collectors.toSet());
}
hasModuleProjectIds.put(PermissionConstants.FUNCTIONAL_CASE_READ, searchCaseProjectIds);
hasModuleProjectIds.put(PermissionConstants.CASE_REVIEW_READ, searchReviewProjectIds);
hasModuleProjectIds.put(PermissionConstants.PROJECT_API_DEFINITION_READ, searchApiProjectIds);
hasModuleProjectIds.put(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ, searchApiCaseProjectIds);
hasModuleProjectIds.put(PermissionConstants.PROJECT_API_SCENARIO_READ, searchScenarioProjectIds);
hasModuleProjectIds.put(PermissionConstants.TEST_PLAN_READ, searchPlanProjectIds);
hasModuleProjectIds.put(PermissionConstants.PROJECT_BUG_READ, searchBugProjectIds);
return hasModuleProjectIds;
}
private static Set<String> getPermissionSet() {
Set<String> permissionSet = new HashSet<>();
permissionSet.add(PermissionConstants.FUNCTIONAL_CASE_READ);
permissionSet.add(PermissionConstants.CASE_REVIEW_READ);
permissionSet.add(PermissionConstants.PROJECT_API_DEFINITION_READ);
permissionSet.add(PermissionConstants.PROJECT_API_DEFINITION_CASE_READ);
permissionSet.add(PermissionConstants.PROJECT_API_SCENARIO_READ);
permissionSet.add(PermissionConstants.TEST_PLAN_READ);
permissionSet.add(PermissionConstants.PROJECT_BUG_READ);
return permissionSet;
}
private boolean isAdmin(String userId) {
UserDTO userDTO = permissionCheckService.getUserDTO(userId);
return permissionCheckService.checkAdmin(userDTO);
}
}

View File

@ -8,14 +8,12 @@ import io.metersphere.system.domain.UserRolePermission;
import io.metersphere.system.dto.user.UserDTO; import io.metersphere.system.dto.user.UserDTO;
import io.metersphere.system.service.UserLoginService; import io.metersphere.system.service.UserLoginService;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional; import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap; import java.util.*;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
@Service @Service
@ -25,34 +23,88 @@ public class PermissionCheckService {
private UserLoginService userLoginService; private UserLoginService userLoginService;
public boolean userHasProjectPermission(String userId, String projectId, String permission) { public boolean userHasProjectPermission(String userId, String projectId, String permission) {
UserDTO user = getUserDTO(userId);
if (user == null) return false;
// 判断是否是超级管理员
if (checkAdmin(user)) return true;
return checkHasPermission(projectId, permission, user);
}
private static boolean checkHasPermission(String projectId, String permission, UserDTO user) {
Map<String, List<UserRolePermission>> userRolePermissions = new HashMap<>(); Map<String, List<UserRolePermission>> userRolePermissions = new HashMap<>();
Map<String, UserRole> role = new HashMap<>(); Map<String, UserRole> role = new HashMap<>();
UserDTO user = userLoginService.getUserDTO(userId); getUserAllPermissions(user, userRolePermissions, role);
if (user != null) { Set<String> currentProjectPermissions = user.getUserRoleRelations().stream()
user.getUserRoleRelations().forEach(ug -> user.getUserRolePermissions().forEach(gp -> { .filter(ug -> role.get(ug.getId()) != null && StringUtils.equalsIgnoreCase(role.get(ug.getId()).getType(), UserRoleType.PROJECT.name()))
if (StringUtils.equalsIgnoreCase(gp.getUserRole().getId(), ug.getRoleId())) { .filter(ug -> StringUtils.equalsIgnoreCase(ug.getSourceId(), projectId))
userRolePermissions.put(ug.getId(), gp.getUserRolePermissions()); .flatMap(ug -> userRolePermissions.get(ug.getId()).stream())
role.put(ug.getId(), gp.getUserRole()); .map(UserRolePermission::getPermissionId)
} .collect(Collectors.toSet());
})); return currentProjectPermissions.contains(permission);
// 判断是否是超级管理员 }
long count = user.getUserRoles()
.stream() public UserDTO getUserDTO(String userId) {
.filter(g -> StringUtils.equalsIgnoreCase(g.getId(), InternalUserRole.ADMIN.getValue())) return userLoginService.getUserDTO(userId);
.count(); }
if (count > 0) {
return true; public boolean checkAdmin(UserDTO user) {
long count = user.getUserRoles()
.stream()
.filter(g -> StringUtils.equalsIgnoreCase(g.getId(), InternalUserRole.ADMIN.getValue()))
.count();
return count > 0;
}
private static void getUserAllPermissions(UserDTO user, Map<String, List<UserRolePermission>> userRolePermissions, Map<String, UserRole> role) {
user.getUserRoleRelations().forEach(ug -> user.getUserRolePermissions().forEach(gp -> {
if (StringUtils.equalsIgnoreCase(gp.getUserRole().getId(), ug.getRoleId())) {
userRolePermissions.put(ug.getId(), gp.getUserRolePermissions());
role.put(ug.getId(), gp.getUserRole());
} }
Set<String> currentProjectPermissions = user.getUserRoleRelations().stream() }));
.filter(ug -> role.get(ug.getId()) != null && StringUtils.equalsIgnoreCase(role.get(ug.getId()).getType(), UserRoleType.PROJECT.name())) }
.filter(ug -> StringUtils.equalsIgnoreCase(ug.getSourceId(), projectId))
.flatMap(ug -> userRolePermissions.get(ug.getId()).stream()) /**
.map(UserRolePermission::getPermissionId) * 获取用户某些权限所占据的项目集合
.collect(Collectors.toSet()); *
return currentProjectPermissions.contains(permission); * @param userId 用户ID
} * @param projectIds 项目ids
return false; * @param permissions 需要判断的权限集合
* @return 有该类型权限的项目ids的map
*/
public Map<String, Set<String>> getHasUserPermissionProjectIds(String userId, Set<String>projectIds, Set<String> permissions) {
UserDTO user = getUserDTO(userId);
if (user == null) return new HashMap<>();
// 注意超级管理员包含所有权限这里不予返回请在方法外自行判断
Map<String, Set<String>> permissionProjectIdMap = new HashMap<>();
Map<String, List<UserRolePermission>> projectPermissionMap = new HashMap<>();
Map<String, List<UserRolePermission>>rolePermissionMap = new HashMap<>();
user.getUserRolePermissions().forEach(t->{
if (StringUtils.equalsIgnoreCase(t.getUserRole().getType(), UserRoleType.PROJECT.name())) {
rolePermissionMap.put(t.getUserRole().getId(),t.getUserRolePermissions());
}
});
user.getUserRoleRelations().forEach(ug -> {
List<UserRolePermission> userRolePermissions = rolePermissionMap.get(ug.getRoleId());
if (CollectionUtils.isNotEmpty(userRolePermissions) && projectIds.contains(ug.getSourceId())) {
projectPermissionMap.put(ug.getSourceId(),userRolePermissions);
}
});
projectPermissionMap.forEach((projectId, userRolePermissions)->{
for (UserRolePermission userRolePermission : userRolePermissions) {
if (permissions.contains(userRolePermission.getPermissionId())) {
permissionProjectIdMap.computeIfAbsent(userRolePermission.getPermissionId(), key -> new HashSet<>()).add(projectId);
}
}
});
return permissionProjectIdMap;
} }
} }