feat(工作台): 返回用户布局过滤项目已禁用的和项目成员已禁用的

This commit is contained in:
guoyuqi 2024-11-08 19:48:06 +08:00 committed by Craftsman
parent f129ba1233
commit 5906472833
8 changed files with 247 additions and 16 deletions

View File

@ -36,14 +36,14 @@ public class DashboardController {
return dashboardService.getLayout(organizationId, SessionUtils.getUserId());
}
@PostMapping("/CREATE_BY_ME")
@PostMapping("/create_by_me")
@Operation(summary = "我创建的")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
public OverViewCountDTO createByMeCount(@Validated @RequestBody DashboardFrontPageRequest request) {
return dashboardService.createByMeCount(request, SessionUtils.getUserId());
}
@PostMapping("/PROJECT_VIEW")
@PostMapping("/project_view")
@Operation(summary = "概览")
@CheckOwner(resourceId = "#request.getOrganizationId()", resourceType = "organization")
public OverViewCountDTO projectViewCount(@Validated @RequestBody DashboardFrontPageRequest request) {

View File

@ -4,6 +4,7 @@ import io.metersphere.api.mapper.ExtApiDefinitionMapper;
import io.metersphere.api.mapper.ExtApiScenarioMapper;
import io.metersphere.api.mapper.ExtApiTestCaseMapper;
import io.metersphere.bug.mapper.ExtBugMapper;
import io.metersphere.dashboard.constants.DashboardUserLayoutKeys;
import io.metersphere.dashboard.dto.LayoutDTO;
import io.metersphere.dashboard.dto.NameArrayDTO;
import io.metersphere.dashboard.request.DashboardFrontPageRequest;
@ -14,15 +15,18 @@ import io.metersphere.plan.mapper.ExtTestPlanMapper;
import io.metersphere.project.domain.Project;
import io.metersphere.project.dto.ProjectCountDTO;
import io.metersphere.project.mapper.ExtProjectMapper;
import io.metersphere.project.mapper.ExtProjectMemberMapper;
import io.metersphere.project.service.ProjectService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.domain.UserLayout;
import io.metersphere.system.domain.UserLayoutExample;
import io.metersphere.system.dto.user.ProjectUserMemberDTO;
import io.metersphere.system.mapper.UserLayoutMapper;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@ -56,6 +60,8 @@ public class DashboardService {
@Resource
private ExtProjectMapper extProjectMapper;
@Resource
private ExtProjectMemberMapper extProjectMemberMapper;
@Resource
private ProjectService projectService;
@Resource
private UserLayoutMapper userLayoutMapper;
@ -87,9 +93,7 @@ public class DashboardService {
private OverViewCountDTO getModuleCountMap(Map<String, Set<String>> permissionModuleProjectIdMap, List<Project> projects, Long toStartTime, Long toEndTime, String userId) {
Map<String, Integer> map = new HashMap<>();
List<String> xaxis = new ArrayList<>();
//TODO 返回数量顺序
List<NameArrayDTO> nameArrayDTOList = new ArrayList<>();
//功能用例
Map<String, ProjectCountDTO> caseProjectCount = new HashMap<>();
Set<String> caseProjectIds = permissionModuleProjectIdMap.get(PermissionConstants.FUNCTIONAL_CASE_READ);
@ -162,7 +166,7 @@ public class DashboardService {
List<ProjectCountDTO> projectBugCount = extBugMapper.projectBugCount(bugProjectIds, toStartTime, toEndTime, userId);
int bugCount = projectBugCount.stream().mapToInt(ProjectCountDTO::getCount).sum();
map.put(BUG_COUNT, bugCount);
xaxis.add(TEST_PLAN);
xaxis.add(BUG_COUNT);
bugProjectCount = projectBugCount.stream().collect(Collectors.toMap(ProjectCountDTO::getProjectId, t -> t));
}
@ -226,14 +230,24 @@ public class DashboardService {
}
public OverViewCountDTO projectViewCount(DashboardFrontPageRequest request, String userId) {
List<Project> userProject = projectService.getUserProject(request.getOrganizationId(), userId);
List<Project> collect = userProject.stream().filter(t -> request.getProjectIds().contains(t.getId())).toList();
List<Project> collect = getHasPermissionProjects(request, userId);
Map<String, Set<String>> permissionModuleProjectIdMap = dashboardProjectService.getModuleProjectIds(collect);
Long toStartTime = request.getToStartTime();
Long toEndTime = request.getToEndTime();
return getModuleCountMap(permissionModuleProjectIdMap, collect, toStartTime, toEndTime, null);
}
private List<Project> getHasPermissionProjects(DashboardFrontPageRequest request, String userId) {
List<Project> userProject = projectService.getUserProject(request.getOrganizationId(), userId);
List<Project> collect;
if (CollectionUtils.isNotEmpty(request.getProjectIds())) {
collect = userProject.stream().filter(t -> request.getProjectIds().contains(t.getId())).toList();
} else {
collect = userProject;
}
return collect;
}
public List<LayoutDTO> editLayout(String organizationId, String userId, List<LayoutDTO> layoutDTO) {
UserLayoutExample userLayoutExample = new UserLayoutExample();
@ -258,9 +272,93 @@ public class DashboardService {
UserLayoutExample userLayoutExample = new UserLayoutExample();
userLayoutExample.createCriteria().andUserIdEqualTo(userId).andOrgIdEqualTo(organizationId);
List<UserLayout> userLayouts = userLayoutMapper.selectByExampleWithBLOBs(userLayoutExample);
if (CollectionUtils.isEmpty(userLayouts)) {
return getDefaultLayoutDTOS(organizationId);
}
UserLayout userLayout = userLayouts.getFirst();
byte[] configuration = userLayout.getConfiguration();
String layoutDTOStr = new String(configuration);
return JSON.parseArray(layoutDTOStr, LayoutDTO.class);
List<LayoutDTO> layoutDTOS = JSON.parseArray(layoutDTOStr, LayoutDTO.class);
//重新查询排除项目禁用的或者用户已经移除某个项目的项目或者成员
List<String> allProjectIds = new ArrayList<>();
List<String> allHandleUsers = new ArrayList<>();
for (LayoutDTO layoutDTO : layoutDTOS) {
allProjectIds.addAll(layoutDTO.getProjectIds());
allHandleUsers.addAll(layoutDTO.getHandleUsers());
}
List<String> projectIds = allProjectIds.stream().distinct().toList();
List<Project> getUserProjectIdName = extProjectMapper.getUserProjectIdName(null, projectIds, userId);
Map<String, Project> projectMap = getUserProjectIdName.stream().collect(Collectors.toMap(Project::getId, t -> t));
List<String> handleUsers = allHandleUsers.stream().distinct().toList();
List<ProjectUserMemberDTO> orgProjectMemberList = extProjectMemberMapper.getOrgProjectMemberList(organizationId, handleUsers);
//重新填充填充返回的项目id 用户id
rebuildProjectOrUser(layoutDTOS, getUserProjectIdName, projectMap, orgProjectMemberList);
return layoutDTOS;
}
/**
* 获取默认布局
*
* @param organizationId 组织ID
* @return List<LayoutDTO>
*/
private static List<LayoutDTO> getDefaultLayoutDTOS(String organizationId) {
List<LayoutDTO> layoutDTOS = new ArrayList<>();
LayoutDTO projectLayoutDTO = buildDefaultLayoutDTO(DashboardUserLayoutKeys.PROJECT_VIEW, "workbench.homePage.projectOverview", 0, new ArrayList<>());
layoutDTOS.add(projectLayoutDTO);
LayoutDTO createByMeLayoutDTO = buildDefaultLayoutDTO(DashboardUserLayoutKeys.CREATE_BY_ME, "workbench,homePage.createdByMe", 1, new ArrayList<>());
layoutDTOS.add(createByMeLayoutDTO);
LayoutDTO projectMemberLayoutDTO = buildDefaultLayoutDTO(DashboardUserLayoutKeys.PROJECT_MEMBER_VIEW, "workbench,homePage.staffOverview", 2, List.of(organizationId));
layoutDTOS.add(projectMemberLayoutDTO);
return layoutDTOS;
}
/**
* 构建默认布局内容
*
* @param layoutKey 布局卡片的key
* @param label 布局卡片页面显示的label
* @param pos 布局卡片 排序
* @param projectIds 布局卡片所选的项目ids
* @return LayoutDTO
*/
private static LayoutDTO buildDefaultLayoutDTO(DashboardUserLayoutKeys layoutKey, String label, int pos, List<String> projectIds) {
LayoutDTO layoutDTO = new LayoutDTO();
layoutDTO.setId(UUID.randomUUID().toString());
layoutDTO.setKey(layoutKey.toString());
layoutDTO.setLabel(label);
layoutDTO.setPos(pos);
layoutDTO.setFullScreen(true);
layoutDTO.setProjectIds(projectIds);
layoutDTO.setHandleUsers(new ArrayList<>());
return layoutDTO;
}
/**
* 过滤用户在当前项目是否有移除或者项目是否被禁用以及用户是否被删除禁用
*
* @param layoutDTOS 获取的所有布局卡片
* @param getUserProjectIdName 用户有任意权限的项目
* @param projectMap 用户有任意权限的项目Map
* @param orgProjectMemberList 组织下所有的项目人员
*/
private static void rebuildProjectOrUser(List<LayoutDTO> layoutDTOS, List<Project> getUserProjectIdName, Map<String, Project> projectMap, List<ProjectUserMemberDTO> orgProjectMemberList) {
for (LayoutDTO layoutDTO : layoutDTOS) {
if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.PROJECT_VIEW.toString()) || StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.CREATE_BY_ME.toString())) {
List<Project> list = getUserProjectIdName.stream().filter(t -> layoutDTO.getProjectIds().contains(t.getId())).toList();
layoutDTO.setProjectIds(list.stream().map(Project::getId).toList());
} else if (StringUtils.equalsIgnoreCase(layoutDTO.getKey(), DashboardUserLayoutKeys.PROJECT_MEMBER_VIEW.toString())) {
List<ProjectUserMemberDTO> list = orgProjectMemberList.stream().filter(t -> layoutDTO.getHandleUsers().contains(t.getId())).toList();
layoutDTO.setHandleUsers(list.stream().map(ProjectUserMemberDTO::getId).toList());
} else {
if (CollectionUtils.isNotEmpty(layoutDTO.getProjectIds()) && projectMap.get(layoutDTO.getProjectIds().getFirst()) == null) {
layoutDTO.setProjectIds(List.of(getUserProjectIdName.get(0).getId()));
}
}
}
}
}

View File

@ -6,6 +6,12 @@ import io.metersphere.dashboard.dto.LayoutDTO;
import io.metersphere.dashboard.request.DashboardFrontPageRequest;
import io.metersphere.dashboard.response.OverViewCountDTO;
import io.metersphere.dashboard.service.DashboardService;
import io.metersphere.project.domain.Project;
import io.metersphere.project.domain.ProjectExample;
import io.metersphere.project.dto.ProjectUserDTO;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.project.request.ProjectMemberRequest;
import io.metersphere.project.service.ProjectMemberService;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
@ -30,13 +36,18 @@ public class DashboardFrontPageControllerTests extends BaseTest {
@Resource
private DashboardService dashboardService;
@Resource
private ProjectMapper projectMapper;
@Resource
private ProjectMemberService projectMemberService;
private static final String EDIT_LAYOUT = "/dashboard/layout/edit/";
private static final String GET_LAYOUT = "/dashboard/layout/get/";
private static final String CREATE_BY_ME = "/dashboard/CREATE_BY_ME";
private static final String PROJECT_VIEW = "/dashboard/PROJECT_VIEW";
private static final String CREATE_BY_ME = "/dashboard/create_by_me";
private static final String PROJECT_VIEW = "/dashboard/project_view";
@Test
@ -88,7 +99,55 @@ public class DashboardFrontPageControllerTests extends BaseTest {
@Test
@Order(2)
public void testLayout() throws Exception {
MvcResult mvcResultGrt = this.requestGetWithOkAndReturn(GET_LAYOUT+DEFAULT_ORGANIZATION_ID);
String contentAsString = mvcResultGrt.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
List<LayoutDTO> layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class);
Assertions.assertEquals(3, layoutDTOS.size());
ProjectExample projectExample = new ProjectExample();
projectExample.createCriteria().andOrganizationIdEqualTo(DEFAULT_ORGANIZATION_ID);
List<Project> projects = projectMapper.selectByExample(projectExample);
ProjectMemberRequest projectMemberRequest = new ProjectMemberRequest();
projectMemberRequest.setProjectId(DEFAULT_PROJECT_ID);
projectMemberRequest.setCurrent(1);
projectMemberRequest.setPageSize(5);
List<ProjectUserDTO> projectUserDTOS = projectMemberService.listMember(projectMemberRequest);
List<LayoutDTO> layoutDTO = new ArrayList<>();
LayoutDTO layoutDTOa = new LayoutDTO();
layoutDTOa.setId(UUID.randomUUID().toString());
layoutDTOa.setPos(3);
layoutDTOa.setKey(DashboardUserLayoutKeys.PROJECT_VIEW.toString());
layoutDTOa.setLabel("项目概览");
layoutDTOa.setProjectIds(new ArrayList<>());
layoutDTOa.setHandleUsers(new ArrayList<>());
layoutDTOa.setFullScreen(false);
layoutDTO.add(layoutDTOa);
LayoutDTO layoutDTOb = new LayoutDTO();
layoutDTOb.setId(UUID.randomUUID().toString());
layoutDTOb.setPos(4);
layoutDTOb.setKey(DashboardUserLayoutKeys.CREATE_BY_ME.toString());
layoutDTOb.setLabel("我的创建");
layoutDTOb.setProjectIds(projects.stream().map(Project::getId).toList());
layoutDTOb.setHandleUsers(new ArrayList<>());
layoutDTOb.setFullScreen(false);
layoutDTO.add(layoutDTOb);
List<String> userIds = projectUserDTOS.stream().map(ProjectUserDTO::getId).toList();
LayoutDTO layoutDTOc = new LayoutDTO();
layoutDTOc.setId(UUID.randomUUID().toString());
layoutDTOc.setPos(4);
layoutDTOc.setKey(DashboardUserLayoutKeys.PROJECT_MEMBER_VIEW.toString());
layoutDTOc.setLabel("人员概览");
layoutDTOc.setProjectIds(List.of(DEFAULT_PROJECT_ID));
layoutDTOc.setHandleUsers(userIds);
layoutDTOc.setFullScreen(false);
layoutDTO.add(layoutDTOc);
LayoutDTO layoutDTO1 = new LayoutDTO();
layoutDTO1.setId(UUID.randomUUID().toString());
layoutDTO1.setPos(1);
@ -99,12 +158,12 @@ public class DashboardFrontPageControllerTests extends BaseTest {
layoutDTO1.setFullScreen(false);
layoutDTO.add(layoutDTO1);
MvcResult mvcResult = this.requestPostWithOkAndReturn(EDIT_LAYOUT+DEFAULT_ORGANIZATION_ID, layoutDTO);
String contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
List<LayoutDTO> layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class);
contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class);
Assertions.assertNotNull(layoutDTOS);
MvcResult mvcResultGrt = this.requestGetWithOkAndReturn(GET_LAYOUT+DEFAULT_ORGANIZATION_ID);
mvcResultGrt = this.requestGetWithOkAndReturn(GET_LAYOUT+DEFAULT_ORGANIZATION_ID);
contentAsString = mvcResultGrt.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class);
@ -115,16 +174,17 @@ public class DashboardFrontPageControllerTests extends BaseTest {
layoutDTO2.setPos(2);
layoutDTO2.setKey(DashboardUserLayoutKeys.ASSOCIATE_CASE_COUNT.toString());
layoutDTO2.setLabel("关联用例数量");
layoutDTO2.setProjectIds(new ArrayList<>());
layoutDTO2.setProjectIds(List.of(DEFAULT_PROJECT_ID));
layoutDTO2.setHandleUsers(new ArrayList<>());
layoutDTO2.setFullScreen(false);
layoutDTO.add(layoutDTO1);
mvcResult = this.requestPostWithOkAndReturn(EDIT_LAYOUT+DEFAULT_ORGANIZATION_ID, layoutDTO);
contentAsString = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
resultHolder = JSON.parseObject(contentAsString, ResultHolder.class);
layoutDTOS = JSON.parseArray(JSON.toJSONString(resultHolder.getData()), LayoutDTO.class);
Assertions.assertNotNull(layoutDTOS);
}
}

View File

@ -34,4 +34,14 @@ public interface ExtProjectMapper {
List<Project> getProjectNameModule(@Param("organizationId") String organizationId, @Param("ids") List<String>projectIds);
/**
* 获取用户在所选项目中仍然有任意权限的项目
* @param organizationId 组织id
* @param projectIds 所选项目ids
* @param userId 用户
* @return List<Project>
*/
List<Project> getUserProjectIdName(@Param("organizationId") String organizationId, @Param("ids") List<String>projectIds, @Param("userId") String userId);
}

View File

@ -133,4 +133,26 @@
</if>
</select>
<select id="getUserProjectIdName" resultType="io.metersphere.project.domain.Project">
SELECT DISTINCT p.id, p.name
FROM user_role u
JOIN user_role_relation urr ON u.id = urr.role_id
JOIN project p ON p.id = urr.source_id
JOIN user on urr.user_id = user.id
where urr.user_id = #{userId} and u.type = 'PROJECT'
<if test="organizationId != null and organizationId != ''">
and
p.organization_id = #{organizationId}
</if>
<if test="ids != null and ids.size() > 0">
and p.id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</if>
and p.enable = 1 and user.deleted = 0
order by
CONVERT( p.name USING GBK) ASC
</select>
</mapper>

View File

@ -2,6 +2,7 @@ package io.metersphere.project.mapper;
import io.metersphere.project.request.ProjectMemberRequest;
import io.metersphere.system.dto.CommentUserInfo;
import io.metersphere.system.dto.user.ProjectUserMemberDTO;
import io.metersphere.system.dto.user.UserExtendDTO;
import org.apache.ibatis.annotations.Param;
@ -35,4 +36,13 @@ public interface ExtProjectMemberMapper {
* @return 用户集合信息
*/
List<CommentUserInfo> getCommentAtUserInfoByParam(@Param("projectId") String projectId, @Param("keyword") String keyword);
/**
* 获取组织下所有有项目权限的成员
* @param organizationId 组织ID
* @param userIds 用户过滤
* @return List<ProjectUserMemberDTO>
*/
List<ProjectUserMemberDTO> getOrgProjectMemberList(@Param("organizationId") String organizationId, @Param("userIds") List<String>userIds );
}

View File

@ -60,4 +60,18 @@
</foreach>
</if>
</sql>
<select id="getOrgProjectMemberList" resultType="io.metersphere.system.dto.user.ProjectUserMemberDTO">
SELECT distinct u.id AS id,urr.source_id from user_role_relation urr
join `user` u on urr.user_id = u.id where
urr.source_id in (select p.id from project p where p.organization_id = #{organizationId} and p.enable = 1 and p.deleted = 0 ) and u.deleted = 0 and u.enable = 1
<if test="userIds != null and userIds.size() > 0">
and u.id in
<foreach collection="userIds" item="userId" separator="," open="(" close=")">
#{userId}
</foreach>
</if>
order by urr.create_time desc
</select>
</mapper>

View File

@ -0,0 +1,17 @@
package io.metersphere.system.dto.user;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class ProjectUserMemberDTO {
@Schema(description = "用户id")
private String id;
@Schema(description = "项目id")
private String projectId;
@Schema(description = "用户名称")
private String name;
}