feat(系统): 系统-组织与项目-项目添加成员可选用户组

This commit is contained in:
WangXu10 2024-09-02 16:56:58 +08:00 committed by Craftsman
parent b56994d56c
commit 6020b0781c
10 changed files with 80 additions and 21 deletions

View File

@ -0,0 +1,7 @@
-- set innodb lock wait timeout
SET SESSION innodb_lock_wait_timeout = 7200;
-- 组织管理员增加权限
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'org_admin', 'ORGANIZATION_PROJECT_MEMBER_UPDATE');

View File

@ -19,6 +19,7 @@ public class PermissionConstants {
public static final String SYSTEM_ORGANIZATION_PROJECT_READ_DELETE = "SYSTEM_ORGANIZATION_PROJECT:READ+DELETE"; public static final String SYSTEM_ORGANIZATION_PROJECT_READ_DELETE = "SYSTEM_ORGANIZATION_PROJECT:READ+DELETE";
public static final String SYSTEM_ORGANIZATION_PROJECT_READ_RECOVER = "SYSTEM_ORGANIZATION_PROJECT:READ+RECOVER"; public static final String SYSTEM_ORGANIZATION_PROJECT_READ_RECOVER = "SYSTEM_ORGANIZATION_PROJECT:READ+RECOVER";
public static final String SYSTEM_ORGANIZATION_PROJECT_MEMBER_ADD = "SYSTEM_ORGANIZATION_PROJECT:READ+ADD_MEMBER"; public static final String SYSTEM_ORGANIZATION_PROJECT_MEMBER_ADD = "SYSTEM_ORGANIZATION_PROJECT:READ+ADD_MEMBER";
public static final String SYSTEM_ORGANIZATION_PROJECT_MEMBER_UPDATE = "SYSTEM_ORGANIZATION_PROJECT:READ+UPDATE_MEMBER";
public static final String SYSTEM_ORGANIZATION_PROJECT_MEMBER_DELETE = "SYSTEM_ORGANIZATION_PROJECT:READ+DELETE_MEMBER"; public static final String SYSTEM_ORGANIZATION_PROJECT_MEMBER_DELETE = "SYSTEM_ORGANIZATION_PROJECT:READ+DELETE_MEMBER";
/*------ end: SYSTEM_ORGANIZATION_PROJECT ------*/ /*------ end: SYSTEM_ORGANIZATION_PROJECT ------*/
@ -44,6 +45,7 @@ public class PermissionConstants {
public static final String ORGANIZATION_PROJECT_READ_DELETE = "ORGANIZATION_PROJECT:READ+DELETE"; public static final String ORGANIZATION_PROJECT_READ_DELETE = "ORGANIZATION_PROJECT:READ+DELETE";
public static final String ORGANIZATION_PROJECT_READ_RECOVER = "ORGANIZATION_PROJECT:READ+RECOVER"; public static final String ORGANIZATION_PROJECT_READ_RECOVER = "ORGANIZATION_PROJECT:READ+RECOVER";
public static final String ORGANIZATION_PROJECT_MEMBER_ADD = "ORGANIZATION_PROJECT:READ+ADD_MEMBER"; public static final String ORGANIZATION_PROJECT_MEMBER_ADD = "ORGANIZATION_PROJECT:READ+ADD_MEMBER";
public static final String ORGANIZATION_PROJECT_MEMBER_UPDATE = "ORGANIZATION_PROJECT:READ+UPDATE_MEMBER";
public static final String ORGANIZATION_PROJECT_MEMBER_DELETE = "ORGANIZATION_PROJECT:READ+DELETE_MEMBER"; public static final String ORGANIZATION_PROJECT_MEMBER_DELETE = "ORGANIZATION_PROJECT:READ+DELETE_MEMBER";
/*------ end: ORGANIZATION_PROJECT ------*/ /*------ end: ORGANIZATION_PROJECT ------*/

View File

@ -193,4 +193,11 @@ public class SystemOrganizationController {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize()); Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize());
return PageUtils.setPageInfo(page, simpleUserService.getMemberList(request)); return PageUtils.setPageInfo(page, simpleUserService.getMemberList(request));
} }
@PostMapping("/update-member")
@Operation(summary = "系统设置-系统-组织与项目-组织-成员-更新成员用户组")
@RequiresPermissions(PermissionConstants.SYSTEM_ORGANIZATION_PROJECT_MEMBER_UPDATE)
public void updateMember(@Validated @RequestBody OrganizationMemberUpdateRequest organizationMemberExtendRequest) {
organizationService.updateMember(organizationMemberExtendRequest, SessionUtils.getUserId());
}
} }

View File

@ -135,10 +135,7 @@ public class SystemProjectController {
@Operation(summary = "系统设置-系统-组织与项目-项目-添加成员") @Operation(summary = "系统设置-系统-组织与项目-项目-添加成员")
@CheckOwner(resourceId = "#request.projectId", resourceType = "project") @CheckOwner(resourceId = "#request.projectId", resourceType = "project")
public void addProjectMember(@Validated @RequestBody ProjectAddMemberRequest request) { public void addProjectMember(@Validated @RequestBody ProjectAddMemberRequest request) {
ProjectAddMemberBatchRequest batchRequest = new ProjectAddMemberBatchRequest(); systemProjectService.addMemberByProject(request, SessionUtils.getUserId());
batchRequest.setProjectIds(List.of(request.getProjectId()));
batchRequest.setUserIds(request.getUserIds());
systemProjectService.addProjectMember(batchRequest, SessionUtils.getUserId());
} }
@GetMapping("/remove-member/{projectId}/{userId}") @GetMapping("/remove-member/{projectId}/{userId}")

View File

@ -32,6 +32,5 @@ public class OrganizationMemberRequest implements Serializable {
@Schema(description = "用户组ID集合", requiredMode = Schema.RequiredMode.REQUIRED) @Schema(description = "用户组ID集合", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{user_role.id.not_blank}")
private List<String> userRoleIds; private List<String> userRoleIds;
} }

View File

@ -20,4 +20,7 @@ public class ProjectAddMemberRequest {
private List< private List<
@NotBlank(message = "{user_role_relation.user_id.not_blank}", groups = {Created.class, Updated.class}) @NotBlank(message = "{user_role_relation.user_id.not_blank}", groups = {Created.class, Updated.class})
String> userIds; String> userIds;
@Schema(description = "用户组ID集合", requiredMode = Schema.RequiredMode.REQUIRED)
private List<String> userRoleIds;
} }

View File

@ -393,7 +393,7 @@ public class CommonProjectService {
List<UserRoleRelation> userRoleRelations = new ArrayList<>(); List<UserRoleRelation> userRoleRelations = new ArrayList<>();
request.getProjectIds().forEach(projectId -> { request.getProjectIds().forEach(projectId -> {
Project project = projectMapper.selectByPrimaryKey(projectId); Project project = projectMapper.selectByPrimaryKey(projectId);
Map<String, String> nameMap = addUserPre(request, createUser, path, module, projectId, project); Map<String, String> nameMap = addUserPre(request.getUserIds(), createUser, path, module, projectId, project);
request.getUserIds().forEach(userId -> { request.getUserIds().forEach(userId -> {
UserRoleRelationExample userRoleRelationExample = new UserRoleRelationExample(); UserRoleRelationExample userRoleRelationExample = new UserRoleRelationExample();
userRoleRelationExample.createCriteria().andUserIdEqualTo(userId) userRoleRelationExample.createCriteria().andUserIdEqualTo(userId)
@ -423,17 +423,17 @@ public class CommonProjectService {
operationLogService.batchAdd(logDTOList); operationLogService.batchAdd(logDTOList);
} }
private Map<String, String> addUserPre(ProjectAddMemberBatchRequest request, String createUser, String path, String module, String projectId, Project project) { public Map<String, String> addUserPre(List<String> userIds, String createUser, String path, String module, String projectId, Project project) {
checkProjectNotExist(projectId); checkProjectNotExist(projectId);
UserExample userExample = new UserExample(); UserExample userExample = new UserExample();
userExample.createCriteria().andIdIn(request.getUserIds()).andDeletedEqualTo(false); userExample.createCriteria().andIdIn(userIds).andDeletedEqualTo(false);
List<User> users = userMapper.selectByExample(userExample); List<User> users = userMapper.selectByExample(userExample);
if (request.getUserIds().size() != users.size()) { if (userIds.size() != users.size()) {
throw new MSException(Translator.get("user_not_exist")); throw new MSException(Translator.get("user_not_exist"));
} }
//把id和名称放一个map中 //把id和名称放一个map中
Map<String, String> userMap = users.stream().collect(Collectors.toMap(User::getId, User::getName)); Map<String, String> userMap = users.stream().collect(Collectors.toMap(User::getId, User::getName));
this.checkOrgRoleExit(request.getUserIds(), project.getOrganizationId(), createUser, userMap, path, module); this.checkOrgRoleExit(userIds, project.getOrganizationId(), createUser, userMap, path, module);
return userMap; return userMap;
} }
@ -453,7 +453,7 @@ public class CommonProjectService {
List<UserRoleRelation> userRoleRelations = new ArrayList<>(); List<UserRoleRelation> userRoleRelations = new ArrayList<>();
request.getProjectIds().forEach(projectId -> { request.getProjectIds().forEach(projectId -> {
Project project = projectMapper.selectByPrimaryKey(projectId); Project project = projectMapper.selectByPrimaryKey(projectId);
Map<String, String> userMap = addUserPre(request, createUser, path, module, projectId, project); Map<String, String> userMap = addUserPre(request.getUserIds(), createUser, path, module, projectId, project);
request.getUserIds().forEach(userId -> { request.getUserIds().forEach(userId -> {
UserRoleRelationExample userRoleRelationExample = new UserRoleRelationExample(); UserRoleRelationExample userRoleRelationExample = new UserRoleRelationExample();
userRoleRelationExample.createCriteria().andUserIdEqualTo(userId) userRoleRelationExample.createCriteria().andUserIdEqualTo(userId)
@ -595,7 +595,7 @@ public class CommonProjectService {
* @param method 请求方法 * @param method 请求方法
* @param logDTOList 日志集合 * @param logDTOList 日志集合
*/ */
private void setLog(LogDTO dto, String path, String method, List<LogDTO> logDTOList) { public void setLog(LogDTO dto, String path, String method, List<LogDTO> logDTOList) {
dto.setPath(path); dto.setPath(path);
dto.setMethod(method); dto.setMethod(method);
dto.setOriginalValue(JSON.toJSONBytes(StringUtils.EMPTY)); dto.setOriginalValue(JSON.toJSONBytes(StringUtils.EMPTY));

View File

@ -1,23 +1,31 @@
package io.metersphere.system.service; package io.metersphere.system.service;
import io.metersphere.project.domain.Project; import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.HttpMethodConstants;
import io.metersphere.sdk.constants.OperationLogConstants;
import io.metersphere.sdk.util.Translator; import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.UserRoleRelation;
import io.metersphere.system.dto.*; import io.metersphere.system.dto.*;
import io.metersphere.system.dto.request.ProjectAddMemberBatchRequest; import io.metersphere.system.dto.request.*;
import io.metersphere.system.dto.request.ProjectMemberRequest;
import io.metersphere.system.dto.request.ProjectPoolRequest;
import io.metersphere.system.dto.request.ProjectRequest;
import io.metersphere.system.dto.sdk.OptionDTO; import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.dto.user.UserExtendDTO; import io.metersphere.system.dto.user.UserExtendDTO;
import io.metersphere.system.log.constants.OperationLogModule; import io.metersphere.system.log.constants.OperationLogModule;
import io.metersphere.system.log.constants.OperationLogType; import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.log.dto.LogDTO;
import io.metersphere.system.log.service.OperationLogService;
import io.metersphere.system.mapper.ExtSystemProjectMapper; import io.metersphere.system.mapper.ExtSystemProjectMapper;
import io.metersphere.system.mapper.UserRoleRelationMapper;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource; import jakarta.annotation.Resource;
import org.apache.commons.collections.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.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map;
@Service @Service
@Transactional(rollbackFor = Exception.class) @Transactional(rollbackFor = Exception.class)
@ -27,6 +35,12 @@ public class SystemProjectService {
private ExtSystemProjectMapper extSystemProjectMapper; private ExtSystemProjectMapper extSystemProjectMapper;
@Resource @Resource
private CommonProjectService commonProjectService; private CommonProjectService commonProjectService;
@Resource
private ProjectMapper projectMapper;
@Resource
private UserRoleRelationMapper userRoleRelationMapper;
@Resource
private OperationLogService operationLogService;
private final static String PREFIX = "/system/project"; private final static String PREFIX = "/system/project";
private final static String ADD_PROJECT = PREFIX + "/add"; private final static String ADD_PROJECT = PREFIX + "/add";
@ -110,4 +124,30 @@ public class SystemProjectService {
return extSystemProjectMapper.getSystemProject(keyword); return extSystemProjectMapper.getSystemProject(keyword);
} }
public void addMemberByProject(ProjectAddMemberRequest request, String createUser) {
List<LogDTO> logDTOList = new ArrayList<>();
List<UserRoleRelation> userRoleRelations = new ArrayList<>();
Project project = projectMapper.selectByPrimaryKey(request.getProjectId());
Map<String, String> userMap = commonProjectService.addUserPre(request.getUserIds(), createUser, ADD_MEMBER, OperationLogModule.SETTING_SYSTEM_ORGANIZATION, request.getProjectId(), project);
request.getUserIds().forEach(userId -> {
request.getUserRoleIds().forEach(userRoleId -> {
UserRoleRelation userRoleRelation = new UserRoleRelation();
userRoleRelation.setId(IDGenerator.nextStr());
userRoleRelation.setUserId(userId);
userRoleRelation.setSourceId(request.getProjectId());
userRoleRelation.setRoleId(userRoleId);
userRoleRelation.setCreateTime(System.currentTimeMillis());
userRoleRelation.setCreateUser(createUser);
userRoleRelation.setOrganizationId(project.getOrganizationId());
userRoleRelations.add(userRoleRelation);
LogDTO logDTO = new LogDTO(OperationLogConstants.SYSTEM, OperationLogConstants.SYSTEM, userRoleRelation.getId(), createUser, OperationLogType.ADD.name(), OperationLogModule.SETTING_SYSTEM_ORGANIZATION, Translator.get("add") + Translator.get("project_member") + ": " + userMap.get(userId));
commonProjectService.setLog(logDTO, ADD_MEMBER, HttpMethodConstants.POST.name(), logDTOList);
});
});
if (CollectionUtils.isNotEmpty(userRoleRelations)) {
userRoleRelationMapper.batchInsert(userRoleRelations);
}
operationLogService.batchAdd(logDTOList);
}
} }

View File

@ -307,6 +307,10 @@
"id": "ORGANIZATION_PROJECT:READ+ADD_MEMBER", "id": "ORGANIZATION_PROJECT:READ+ADD_MEMBER",
"name": "permission.system_organization_project_member.add" "name": "permission.system_organization_project_member.add"
}, },
{
"id": "ORGANIZATION_PROJECT:READ+UPDATE_MEMBER",
"name": "permission.system_organization_project_member.update"
},
{ {
"id": "ORGANIZATION_PROJECT:READ+DELETE_MEMBER", "id": "ORGANIZATION_PROJECT:READ+DELETE_MEMBER",
"name": "permission.system_organization_project_member.delete" "name": "permission.system_organization_project_member.delete"

View File

@ -897,12 +897,8 @@ public class SystemProjectControllerTests extends BaseTest {
projectAddMemberRequest.setProjectId("projectId"); projectAddMemberRequest.setProjectId("projectId");
List<String> userIds = List.of("admin1", "admin2"); List<String> userIds = List.of("admin1", "admin2");
projectAddMemberRequest.setUserIds(userIds); projectAddMemberRequest.setUserIds(userIds);
projectAddMemberRequest.setUserRoleIds(List.of(InternalUserRole.PROJECT_MEMBER.getValue()));
this.requestPost(addProjectMember, projectAddMemberRequest, status().isOk()); this.requestPost(addProjectMember, projectAddMemberRequest, status().isOk());
UserRoleRelationExample userRoleRelationExample = new UserRoleRelationExample();
userRoleRelationExample.createCriteria().andSourceIdEqualTo("projectId").andRoleIdEqualTo(InternalUserRole.PROJECT_MEMBER.getValue());
List<UserRoleRelation> userRoleRelations = userRoleRelationMapper.selectByExample(userRoleRelationExample);
Assertions.assertTrue(userRoleRelations.stream().map(UserRoleRelation::getUserId).toList().containsAll(userIds));
Assertions.assertTrue(userRoleRelations.stream().map(UserRoleRelation::getUserId).toList().containsAll(userIds));
// @@校验权限 // @@校验权限
requestPostPermissionTest(PermissionConstants.SYSTEM_ORGANIZATION_PROJECT_MEMBER_ADD, addProjectMember, projectAddMemberRequest); requestPostPermissionTest(PermissionConstants.SYSTEM_ORGANIZATION_PROJECT_MEMBER_ADD, addProjectMember, projectAddMemberRequest);
} }
@ -913,20 +909,24 @@ public class SystemProjectControllerTests extends BaseTest {
//项目Id为空 //项目Id为空
ProjectAddMemberRequest projectAddMemberRequest = new ProjectAddMemberRequest(); ProjectAddMemberRequest projectAddMemberRequest = new ProjectAddMemberRequest();
projectAddMemberRequest.setProjectId(null); projectAddMemberRequest.setProjectId(null);
projectAddMemberRequest.setUserRoleIds(List.of(InternalUserRole.PROJECT_MEMBER.getValue()));
this.requestPost(addProjectMember, projectAddMemberRequest, BAD_REQUEST_MATCHER); this.requestPost(addProjectMember, projectAddMemberRequest, BAD_REQUEST_MATCHER);
//用户Id为空 //用户Id为空
projectAddMemberRequest = new ProjectAddMemberRequest(); projectAddMemberRequest = new ProjectAddMemberRequest();
projectAddMemberRequest.setProjectId("projectId"); projectAddMemberRequest.setProjectId("projectId");
projectAddMemberRequest.setUserRoleIds(List.of(InternalUserRole.PROJECT_MEMBER.getValue()));
this.requestPost(addProjectMember, projectAddMemberRequest, BAD_REQUEST_MATCHER); this.requestPost(addProjectMember, projectAddMemberRequest, BAD_REQUEST_MATCHER);
//用户Id不存在 //用户Id不存在
projectAddMemberRequest = new ProjectAddMemberRequest(); projectAddMemberRequest = new ProjectAddMemberRequest();
projectAddMemberRequest.setProjectId("projectId"); projectAddMemberRequest.setProjectId("projectId");
projectAddMemberRequest.setUserIds(List.of("admin3")); projectAddMemberRequest.setUserIds(List.of("admin3"));
projectAddMemberRequest.setUserRoleIds(List.of(InternalUserRole.PROJECT_MEMBER.getValue()));
this.requestPost(addProjectMember, projectAddMemberRequest, ERROR_REQUEST_MATCHER); this.requestPost(addProjectMember, projectAddMemberRequest, ERROR_REQUEST_MATCHER);
//项目id不存在 //项目id不存在
projectAddMemberRequest = new ProjectAddMemberRequest(); projectAddMemberRequest = new ProjectAddMemberRequest();
projectAddMemberRequest.setProjectId("projectId111"); projectAddMemberRequest.setProjectId("projectId111");
projectAddMemberRequest.setUserIds(List.of("admin1")); projectAddMemberRequest.setUserIds(List.of("admin1"));
projectAddMemberRequest.setUserRoleIds(List.of(InternalUserRole.PROJECT_MEMBER.getValue()));
this.requestPost(addProjectMember, projectAddMemberRequest, ERROR_REQUEST_MATCHER); this.requestPost(addProjectMember, projectAddMemberRequest, ERROR_REQUEST_MATCHER);
} }