refactor(系统设置): 项目成员添加日志及权限&组织列表SQL优化

This commit is contained in:
song-cc-rock 2023-08-31 16:46:36 +08:00 committed by fit2-zhao
parent 7f30c221fd
commit fdbe2d1796
7 changed files with 258 additions and 84 deletions

View File

@ -20,7 +20,6 @@ import io.swagger.v3.oas.annotations.Parameters;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@ -89,7 +88,7 @@ public class ProjectMemberController {
@Operation(summary = "项目管理-成员-批量添加至用户组")
@RequiresPermissions(PermissionConstants.PROJECT_MEMBER_UPDATE)
public void addMemberRole(@RequestBody ProjectMemberAddRequest request) {
projectMemberService.addMemberRole(request, SessionUtils.getUserId());
projectMemberService.addRole(request, SessionUtils.getUserId());
}
@PostMapping("/batch/remove")

View File

@ -1,6 +1,7 @@
package io.metersphere.project.mapper;
import io.metersphere.project.request.ProjectMemberRequest;
import io.metersphere.system.dto.UserExtend;
import org.apache.ibatis.annotations.Param;
import java.util.List;
@ -17,4 +18,11 @@ public interface ExtProjectMemberMapper {
* @return 成员列表及用户组关联信息
*/
List<String> listMember(@Param("request") ProjectMemberRequest request);
/**
* 获取所有组织成员
* @param organizationId 组织ID
* @return 成员
*/
List<UserExtend> getMemberByOrg(String organizationId);
}

View File

@ -12,6 +12,33 @@
or u.email like CONCAT('%', #{request.keyword},'%')
or u.phone like CONCAT('%', #{request.keyword},'%'))
</if>
<include refid="filter"/>
</where>
</select>
<select id="getMemberByOrg" resultType="io.metersphere.system.dto.UserExtend">
select distinct u.* from user_role_relation urr join `user` u on urr.user_id = u.id
<where>
u.deleted = 0
<if test="organizationId != null and organizationId != ''">
and urr.source_id = #{organizationId}
</if>
</where>
order by u.create_time desc
</select>
<sql id="filter">
<if test="request.filter != null and request.filter.size() > 0">
<foreach collection="request.filter.entrySet()" index="key" item="values">
<if test="values != null and values.size() > 0">
<choose>
<when test="key == 'roleIds'">
and urr.id in
<include refid="io.metersphere.sdk.mapper.BaseMapper.filterInWrapper"/>
</when>
</choose>
</if>
</foreach>
</if>
</sql>
</mapper>

View File

@ -8,26 +8,31 @@ import io.metersphere.project.request.ProjectMemberAddRequest;
import io.metersphere.project.request.ProjectMemberBatchDeleteRequest;
import io.metersphere.project.request.ProjectMemberEditRequest;
import io.metersphere.project.request.ProjectMemberRequest;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.constants.UserRoleEnum;
import io.metersphere.sdk.constants.UserRoleType;
import io.metersphere.sdk.dto.LogDTO;
import io.metersphere.sdk.dto.OptionDTO;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.log.constants.OperationLogModule;
import io.metersphere.sdk.log.constants.OperationLogType;
import io.metersphere.sdk.log.service.OperationLogService;
import io.metersphere.sdk.mapper.BaseUserMapper;
import io.metersphere.sdk.util.BeanUtils;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.*;
import io.metersphere.system.dto.UserExtend;
import io.metersphere.system.mapper.ExtOrganizationMapper;
import io.metersphere.system.mapper.UserMapper;
import io.metersphere.system.mapper.UserRoleMapper;
import io.metersphere.system.mapper.UserRoleRelationMapper;
import io.metersphere.system.request.OrganizationRequest;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.stream.Collectors;
/**
@ -48,9 +53,9 @@ public class ProjectMemberService {
@Resource
private ProjectMapper projectMapper;
@Resource
private ExtOrganizationMapper extOrganizationMapper;
@Resource
private ExtProjectMemberMapper extProjectMemberMapper;
@Resource
private OperationLogService operationLogService;
/**
* 获取成员列表
@ -61,6 +66,9 @@ public class ProjectMemberService {
public List<ProjectUserDTO> listMember(ProjectMemberRequest request) {
// 查询当前项目成员
List<String> members = extProjectMemberMapper.listMember(request);
if (CollectionUtils.isEmpty(members)) {
return new ArrayList<>();
}
UserRoleRelationExample relationExample = new UserRoleRelationExample();
relationExample.createCriteria().andSourceIdEqualTo(request.getProjectId()).andUserIdIn(members);
List<UserRoleRelation> userRoleRelates = userRoleRelationMapper.selectByExample(relationExample);
@ -101,7 +109,7 @@ public class ProjectMemberService {
if (project == null) {
return new ArrayList<>();
}
return extOrganizationMapper.getMemberByOrg(project.getOrganizationId());
return extProjectMemberMapper.getMemberByOrg(project.getOrganizationId());
}
/**
@ -125,38 +133,7 @@ public class ProjectMemberService {
* @param currentUserId 当前用户ID
*/
public void addMember(ProjectMemberAddRequest request, String currentUserId) {
// 项目不存在, 则不添加
checkProjectExist(request.getProjectId());
// 获取已经存在的用户组
UserRoleRelationExample example = new UserRoleRelationExample();
example.createCriteria().andSourceIdEqualTo(request.getProjectId())
.andUserIdIn(request.getUserIds()).andRoleIdIn(request.getRoleIds());
List<UserRoleRelation> userRoleRelations = userRoleRelationMapper.selectByExample(example);
Map<String, List<String>> existUserRelations = userRoleRelations.stream().collect(
Collectors.groupingBy(UserRoleRelation::getUserId, Collectors.mapping(UserRoleRelation::getRoleId, Collectors.toList())));
// 比较用户组是否已经存在, 如果不存在则添加
List<UserRoleRelation> relations = new ArrayList<>();
request.getUserIds().forEach(userId -> request.getRoleIds().forEach(roleId -> {
// 用户不存在或用户组不存在, 则不添加
if (isUserOrRoleNotExist(userId, roleId)) {
return;
}
// 如果该用户已经添加至该用户组, 则不再添加
if (existUserRelations.containsKey(userId) && existUserRelations.get(userId).contains(roleId)) {
return;
}
UserRoleRelation relation = new UserRoleRelation();
relation.setId(UUID.randomUUID().toString());
relation.setUserId(userId);
relation.setRoleId(roleId);
relation.setSourceId(request.getProjectId());
relation.setCreateTime(System.currentTimeMillis());
relation.setCreateUser(currentUserId);
relations.add(relation);
}));
if (!CollectionUtils.isEmpty(relations)) {
userRoleRelationMapper.batchInsert(relations);
}
addMemberRole(request, currentUserId, OperationLogType.ADD.name(), "/project/member/add");
}
/**
@ -166,12 +143,16 @@ public class ProjectMemberService {
* @param currentUserId 当前用户ID
*/
public void updateMember(ProjectMemberEditRequest request, String currentUserId) {
// 操作记录
List<LogDTO> logs = new ArrayList<>();
// 项目不存在
checkProjectExist(request.getProjectId());
// 移除已经存在的用户组
UserRoleRelationExample example = new UserRoleRelationExample();
example.createCriteria().andSourceIdEqualTo(request.getProjectId())
.andUserIdEqualTo(request.getUserId());
// 旧的用户组关系, 操作记录使用
List<UserRoleRelation> oldRelations = userRoleRelationMapper.selectByExample(example);
userRoleRelationMapper.deleteByExample(example);
// 添加新的用户组
List<UserRoleRelation> relations = new ArrayList<>();
@ -192,6 +173,19 @@ public class ProjectMemberService {
if (!CollectionUtils.isEmpty(relations)) {
userRoleRelationMapper.batchInsert(relations);
}
// 操作记录
UserRoleExample roleExample = new UserRoleExample();
roleExample.createCriteria().andIdIn(request.getRoleIds());
List<UserRole> newRoles = userRoleMapper.selectByExample(roleExample);
List<UserRole> oldRoles = new ArrayList<>();
if (!CollectionUtils.isEmpty(oldRelations)) {
List<String> oldRoleIds = oldRelations.stream().map(UserRoleRelation::getRoleId).toList();
roleExample.clear();
roleExample.createCriteria().andIdIn(oldRoleIds);
oldRoles = userRoleMapper.selectByExample(roleExample);
}
setLog(request.getProjectId(), request.getUserId(), currentUserId, OperationLogType.UPDATE.name(), "/project/member/update", HttpMethodConstants.POST.name(), oldRoles, newRoles, logs);
operationLogService.batchAdd(logs);
}
/**
@ -201,12 +195,17 @@ public class ProjectMemberService {
* @param userId 用户ID
*/
public void removeMember(String projectId, String userId) {
// 操作记录
List<LogDTO> logs = new ArrayList<>();
// 项目不存在, 则不移除
checkProjectExist(projectId);
// 移除成员, 则移除该成员在该项目下的所有用户组
UserRoleRelationExample example = new UserRoleRelationExample();
example.createCriteria().andSourceIdEqualTo(projectId).andUserIdEqualTo(userId);
userRoleRelationMapper.deleteByExample(example);
// 操作记录
setLog(projectId, userId, null, OperationLogType.DELETE.name(), "/project/member/remove", HttpMethodConstants.GET.name(), null, null, logs);
operationLogService.batchAdd(logs);
}
/**
@ -214,9 +213,71 @@ public class ProjectMemberService {
* @param request 请求参数
* @param currentUserId 当前用户ID
*/
public void addMemberRole(ProjectMemberAddRequest request, String currentUserId) {
public void addRole(ProjectMemberAddRequest request, String currentUserId) {
// 添加用户用户组(已经添加的用户组不再添加)
addMember(request, currentUserId);
addMemberRole(request, currentUserId, OperationLogType.UPDATE.name(), "/project/member/add-role");
}
/**
* 处理成员及用户组关系, 并生成操作记录
*
* @param request 请求参数
* @param currentUserId 创建人
* @param operationType 操作记录类型
* @param path 操作记录路径
*/
public void addMemberRole(ProjectMemberAddRequest request, String currentUserId, String operationType, String path) {
// 操作记录
List<LogDTO> logs = new ArrayList<>();
// 项目不存在, 则不添加
checkProjectExist(request.getProjectId());
// 获取已经存在的用户组
UserRoleRelationExample example = new UserRoleRelationExample();
example.createCriteria().andSourceIdEqualTo(request.getProjectId())
.andUserIdIn(request.getUserIds()).andRoleIdIn(request.getRoleIds());
List<UserRoleRelation> userRoleRelations = userRoleRelationMapper.selectByExample(example);
Map<String, List<String>> existUserRelations = userRoleRelations.stream().collect(
Collectors.groupingBy(UserRoleRelation::getUserId, Collectors.mapping(UserRoleRelation::getRoleId, Collectors.toList())));
// 比较用户组是否已经存在, 如果不存在则添加
List<UserRoleRelation> relations = new ArrayList<>();
request.getUserIds().forEach(userId ->{
AtomicBoolean isLog = new AtomicBoolean(false);
// 追加的用户组ID, 操作记录使用
List<String> roleIds = new ArrayList<>();
request.getRoleIds().forEach(roleId -> {
// 用户不存在或用户组不存在, 则不添加
if (isUserOrRoleNotExist(userId, roleId)) {
return;
}
// 如果该用户已经添加至该用户组, 则不再添加
if (existUserRelations.containsKey(userId) && existUserRelations.get(userId).contains(roleId)) {
return;
}
UserRoleRelation relation = new UserRoleRelation();
relation.setId(UUID.randomUUID().toString());
relation.setUserId(userId);
relation.setRoleId(roleId);
relation.setSourceId(request.getProjectId());
relation.setCreateTime(System.currentTimeMillis());
relation.setCreateUser(currentUserId);
relations.add(relation);
isLog.set(true);
roleIds.add(roleId);
});
// 成员添加操作记录
if (isLog.get()) {
UserRoleExample roleExample = new UserRoleExample();
roleExample.createCriteria().andIdIn(roleIds);
List<UserRole> userRoles = userRoleMapper.selectByExample(roleExample);
// 追加了哪些用户组
setLog(request.getProjectId(), userId, currentUserId, operationType, path, HttpMethodConstants.POST.name(), null, userRoles, logs);
}
});
if (!CollectionUtils.isEmpty(relations)) {
userRoleRelationMapper.batchInsert(relations);
}
// 操作记录
operationLogService.batchAdd(logs);
}
/**
@ -224,6 +285,8 @@ public class ProjectMemberService {
* @param request 请求参数
*/
public void batchRemove(ProjectMemberBatchDeleteRequest request) {
// 操作记录
List<LogDTO> logs = new ArrayList<>();
// 项目不存在, 则不移除
checkProjectExist(request.getProjectId());
// 批量移除成员, 则移除该成员在该项目下的所有用户组
@ -231,8 +294,18 @@ public class ProjectMemberService {
example.createCriteria().andSourceIdEqualTo(request.getProjectId())
.andUserIdIn(request.getUserIds());
userRoleRelationMapper.deleteByExample(example);
// 操作记录
request.getUserIds().forEach(userId -> {
// 操作记录
setLog(request.getProjectId(), userId, null, OperationLogType.DELETE.name(), "/project/member/remove", HttpMethodConstants.GET.name(), null, null, logs);
});
operationLogService.batchAdd(logs);
}
/**
* 查看项目是否存在
* @param projectId 项目ID
*/
private void checkProjectExist(String projectId) {
Project project = projectMapper.selectByPrimaryKey(projectId);
if (project == null) {
@ -240,9 +313,44 @@ public class ProjectMemberService {
}
}
/**
* 查看用户或用户组是否存在
* @param userId 用户ID
* @param roleId 用户组ID
* @return 是否存在
*/
private boolean isUserOrRoleNotExist(String userId, String roleId) {
UserExample example = new UserExample();
example.createCriteria().andIdEqualTo(userId).andDeletedEqualTo(false);
return userMapper.selectByExample(example) == null || userRoleMapper.selectByPrimaryKey(roleId) == null;
}
/**
* 操作记录
*
* @param projectId 项目ID
* @param memberId 成员ID
* @param createUserId 创建用户
* @param type 操作类型
* @param path 路径
* @param method 请求方法
* @param logs 日志集合
*/
private void setLog(String projectId, String memberId, String createUserId, String type, String path, String method, Object originalVal, Object modifiedVal, List<LogDTO> logs) {
Project project = projectMapper.selectByPrimaryKey(projectId);
User user = userMapper.selectByPrimaryKey(memberId);
LogDTO dto = new LogDTO(
projectId,
project.getOrganizationId(),
memberId,
createUserId,
type,
OperationLogModule.PROJECT_MANAGEMENT_PERMISSION_MEMBER,
user.getName());
dto.setPath(path);
dto.setMethod(method);
dto.setOriginalValue(JSON.toJSONBytes(originalVal));
dto.setModifiedValue(JSON.toJSONBytes(modifiedVal));
logs.add(dto);
}
}

View File

@ -6,8 +6,10 @@ import io.metersphere.project.request.ProjectMemberBatchDeleteRequest;
import io.metersphere.project.request.ProjectMemberEditRequest;
import io.metersphere.project.request.ProjectMemberRequest;
import io.metersphere.sdk.base.BaseTest;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.controller.handler.ResultHolder;
import io.metersphere.sdk.log.constants.OperationLogType;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Pager;
import org.apache.commons.lang3.StringUtils;
@ -68,10 +70,24 @@ public class ProjectMemberControllerTests extends BaseTest {
Assertions.assertTrue(StringUtils.contains(projectUserDTO.getName(), request.getKeyword())
|| StringUtils.contains(projectUserDTO.getEmail(), request.getKeyword())
|| StringUtils.contains(projectUserDTO.getPhone(), request.getKeyword()));
// 权限校验
request.setProjectId(DEFAULT_PROJECT_ID);
requestPostPermissionTest(PermissionConstants.PROJECT_MEMBER_READ, LIST_MEMBER, request);
}
@Test
@Order(2)
public void testListMemberEmpty() throws Exception {
// 空数据覆盖
ProjectMemberRequest request = new ProjectMemberRequest();
request.setProjectId("default-project-member-x");
request.setCurrent(1);
request.setPageSize(10);
this.requestPost(LIST_MEMBER, request, status().isOk());
}
@Test
@Order(3)
public void testListMemberError() throws Exception {
// 页码有误
ProjectMemberRequest request = new ProjectMemberRequest();
@ -86,31 +102,40 @@ public class ProjectMemberControllerTests extends BaseTest {
}
@Test
@Order(3)
@Order(4)
public void testGetMemberOption() throws Exception {
this.requestGet(GET_MEMBER + "/default-project-member-test", status().isOk());
// 覆盖空数据
this.requestGet(GET_MEMBER + "/default-project-member-x", status().isOk());
}
@Test
@Order(4)
public void testGetRoleOption() throws Exception {
this.requestGet(GET_ROLE + "/default-project-member-test", status().isOk());
// 权限校验
requestGetPermissionTest(PermissionConstants.PROJECT_MEMBER_ADD, GET_MEMBER + "/" + DEFAULT_PROJECT_ID);
}
@Test
@Order(5)
public void testGetRoleOption() throws Exception {
this.requestGet(GET_ROLE + "/default-project-member-test", status().isOk());
// 权限校验
requestGetPermissionTest(PermissionConstants.PROJECT_MEMBER_ADD, GET_ROLE + "/" + DEFAULT_PROJECT_ID);
}
@Test
@Order(6)
public void testAddMemberSuccess() throws Exception {
ProjectMemberAddRequest request = new ProjectMemberAddRequest();
request.setProjectId("default-project-member-test");
request.setUserIds(List.of("default-project-member-user-1", "default-project-member-user-del"));
request.setRoleIds(List.of("project_admin", "project_admin_x", "project_member"));
this.requestPost(ADD_MEMBER, request, status().isOk());
// 日志
checkLog("default-project-member-user-1", OperationLogType.ADD);
// 权限校验
request.setProjectId(DEFAULT_PROJECT_ID);
requestPostPermissionTest(PermissionConstants.PROJECT_MEMBER_ADD, ADD_MEMBER, request);
}
@Test
@Order(6)
@Order(7)
public void testAddMemberRepeat() throws Exception {
ProjectMemberAddRequest request = new ProjectMemberAddRequest();
request.setProjectId("default-project-member-test");
@ -120,7 +145,7 @@ public class ProjectMemberControllerTests extends BaseTest {
}
@Test
@Order(7)
@Order(8)
public void testAddMemberError() throws Exception {
ProjectMemberAddRequest request = new ProjectMemberAddRequest();
request.setProjectId("default-project-member-x");
@ -130,7 +155,7 @@ public class ProjectMemberControllerTests extends BaseTest {
}
@Test
@Order(8)
@Order(9)
public void testUpdateMemberSuccess() throws Exception {
// 不存在的用户组
ProjectMemberEditRequest request = new ProjectMemberEditRequest();
@ -141,10 +166,15 @@ public class ProjectMemberControllerTests extends BaseTest {
// 存在的用户组
request.setRoleIds(List.of("project_admin", "project_member"));
this.requestPost(UPDATE_MEMBER, request, status().isOk());
// 日志
checkLog("default-project-member-user-1", OperationLogType.UPDATE);
// 权限校验
request.setProjectId(DEFAULT_PROJECT_ID);
requestPostPermissionTest(PermissionConstants.PROJECT_MEMBER_UPDATE, UPDATE_MEMBER, request);
}
@Test
@Order(9)
@Order(10)
public void testUpdateMemberError() throws Exception {
ProjectMemberEditRequest request = new ProjectMemberEditRequest();
request.setProjectId("default-project-member-x");
@ -154,29 +184,38 @@ public class ProjectMemberControllerTests extends BaseTest {
}
@Test
@Order(10)
@Order(11)
public void testRemoveMemberSuccess() throws Exception {
this.requestGet(REMOVE_MEMBER + "/default-project-member-test/default-project-member-user-1", status().isOk());
// 日志
checkLog("default-project-member-user-1", OperationLogType.DELETE);
// 权限校验
requestGetPermissionTest(PermissionConstants.PROJECT_MEMBER_DELETE, REMOVE_MEMBER + "/" + DEFAULT_PROJECT_ID + "/default-project-member-user-1");
}
@Test
@Order(11)
@Order(12)
public void testRemoveMemberError() throws Exception {
this.requestGet(REMOVE_MEMBER + "/default-project-member-x/default-project-member-user-1", status().is5xxServerError());
}
@Test
@Order(12)
@Order(13)
public void testAddMemberRoleSuccess() throws Exception {
ProjectMemberAddRequest request = new ProjectMemberAddRequest();
request.setProjectId("default-project-member-test");
request.setUserIds(List.of("default-project-member-user-1", "default-project-member-user-2"));
request.setRoleIds(List.of("project_admin", "project_member"));
this.requestPost(ADD_ROLE, request, status().isOk());
// 日志
checkLog("default-project-member-user-2", OperationLogType.UPDATE);
// 权限校验
request.setProjectId(DEFAULT_PROJECT_ID);
requestPostPermissionTest(PermissionConstants.PROJECT_MEMBER_UPDATE, ADD_ROLE, request);
}
@Test
@Order(13)
@Order(14)
public void testAddMemberRoleError() throws Exception {
ProjectMemberAddRequest request = new ProjectMemberAddRequest();
request.setProjectId("default-project-member-x");
@ -186,16 +225,21 @@ public class ProjectMemberControllerTests extends BaseTest {
}
@Test
@Order(14)
@Order(15)
public void testBatchRemoveMemberSuccess() throws Exception {
ProjectMemberBatchDeleteRequest request = new ProjectMemberBatchDeleteRequest();
request.setProjectId("default-project-member-test");
request.setUserIds(List.of("default-project-member-user-1", "default-project-member-user-2"));
this.requestPost(BATCH_REMOVE_MEMBER, request, status().isOk());
// 日志
checkLog("default-project-member-user-1", OperationLogType.DELETE);
// 权限校验
request.setProjectId(DEFAULT_PROJECT_ID);
requestPostPermissionTest(PermissionConstants.PROJECT_MEMBER_DELETE, BATCH_REMOVE_MEMBER, request);
}
@Test
@Order(15)
@Order(16)
public void testBatchRemoveMember() throws Exception {
ProjectMemberBatchDeleteRequest request = new ProjectMemberBatchDeleteRequest();
request.setProjectId("default-project-member-x");

View File

@ -83,11 +83,4 @@ public interface ExtOrganizationMapper {
* @return 组织下拉选项
*/
List<OptionDTO> getOptionsByIds(@Param("ids") List<String> ids);
/**
* 获取所有组织成员
* @param organizationId 组织ID
* @return 成员
*/
List<UserExtend> getMemberByOrg(String organizationId);
}

View File

@ -1,15 +1,21 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="io.metersphere.system.mapper.ExtOrganizationMapper">
<select id="list" resultType="io.metersphere.system.dto.OrganizationDTO">
select o.id, o.num, o.name, o.description, o.create_time,
o.update_time, o.create_user, o.deleted, o.delete_user, o.delete_time, o.enable,
count(distinct u.id) as memberCount, count(distinct p.id) as projectCount
from organization o left join user_role_relation ur on ur.source_id = o.id
left join user u on u.id = ur.user_id and u.deleted = 0
left join project p on p.organization_id = o.id
<select id="list" resultType="io.metersphere.system.dto.OrganizationDTO">
select o.id, o.num, o.name, o.description, o.create_time,
o.update_time, o.create_user, o.deleted, o.delete_user, o.delete_time, o.enable,
coalesce(membercount, 0) as memberCount, coalesce(projectcount, 0) as projectCount
from organization o
left join (
select source_id, count(distinct u.id) as membercount from user_role_relation ur
join user u on ur.user_id = u.id and u.deleted = 0
group by source_id
) as members_group on o.id = members_group.source_id
left join (
select organization_id, count(project.id) as projectcount from project
group by organization_id
) as projects_group on o.id = projects_group.organization_id
<include refid="queryWhereCondition"/>
group by o.id
</select>
<select id="listAll" resultType="io.metersphere.system.dto.OrganizationDTO">
@ -88,17 +94,6 @@
</foreach>
</select>
<select id="getMemberByOrg" resultType="io.metersphere.system.dto.UserExtend">
select distinct u.* from user_role_relation urr join `user` u on urr.user_id = u.id
<where>
u.deleted = 0
<if test="organizationId != null and organizationId != ''">
and urr.source_id = #{organizationId}
</if>
</where>
order by u.create_time desc
</select>
<sql id="queryWhereCondition">
<where>
<if test="request.keyword != null">