feat(项目管理): 项目成员功能

This commit is contained in:
song-cc-rock 2023-08-28 14:15:49 +08:00 committed by f2c-ci-robot[bot]
parent ddf4611586
commit 0ba8e85b45
14 changed files with 799 additions and 0 deletions

View File

@ -18,6 +18,7 @@
<artifactId>metersphere-sdk</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>io.metersphere</groupId>
<artifactId>metersphere-sdk</artifactId>
@ -26,6 +27,12 @@
<type>test-jar</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.metersphere</groupId>
<artifactId>metersphere-system-setting</artifactId>
<version>${revision}</version>
</dependency>
</dependencies>
<build>

View File

@ -0,0 +1,101 @@
package io.metersphere.project.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.project.dto.ProjectUserDTO;
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.project.service.ProjectMemberService;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.dto.OptionDTO;
import io.metersphere.sdk.util.PageUtils;
import io.metersphere.sdk.util.Pager;
import io.metersphere.sdk.util.SessionUtils;
import io.metersphere.system.dto.UserExtend;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
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.*;
import java.util.List;
/**
* @author song-cc-rock
*/
@Tag(name = "项目管理-成员")
@RestController
@RequestMapping("/project/member")
public class ProjectMemberController {
@Resource
private ProjectMemberService projectMemberService;
@PostMapping("/list")
@Operation(summary = "项目管理-成员-列表查询")
@RequiresPermissions(PermissionConstants.PROJECT_MEMBER_READ)
public Pager<List<ProjectUserDTO>> listMember(@Validated @RequestBody ProjectMemberRequest request) {
Page<Object> page = PageHelper.startPage(request.getCurrent(), request.getPageSize(), true);
return PageUtils.setPageInfo(page, projectMemberService.listMember(request));
}
@GetMapping("/get-member/option/{projectId}")
@Operation(summary = "项目管理-成员-获取成员下拉选项")
@RequiresPermissions(PermissionConstants.PROJECT_MEMBER_ADD)
public List<UserExtend> getMemberOption(@PathVariable String projectId) {
return projectMemberService.getMemberOption(projectId);
}
@GetMapping("/get-role/option/{projectId}")
@Operation(summary = "项目管理-成员-获取用户组下拉选项")
@RequiresPermissions(PermissionConstants.PROJECT_MEMBER_ADD)
public List<OptionDTO> getRoleOption(@PathVariable String projectId) {
return projectMemberService.getRoleOption(projectId);
}
@PostMapping("/add")
@Operation(summary = "项目管理-成员-添加成员")
@RequiresPermissions(PermissionConstants.PROJECT_MEMBER_ADD)
public void addMember(@RequestBody ProjectMemberAddRequest request) {
projectMemberService.addMember(request, SessionUtils.getUserId());
}
@PostMapping("/update")
@Operation(summary = "项目管理-成员-编辑成员")
@RequiresPermissions(PermissionConstants.PROJECT_MEMBER_UPDATE)
public void updateMember(@RequestBody ProjectMemberEditRequest request) {
projectMemberService.updateMember(request, SessionUtils.getUserId());
}
@GetMapping("/remove/{projectId}/{userId}")
@Operation(summary = "项目管理-成员-移除成员")
@Parameters({
@Parameter(name = "projectId", description = "项目ID", schema = @Schema(requiredMode = Schema.RequiredMode.REQUIRED)),
@Parameter(name = "userId", description = "成员ID", schema = @Schema(requiredMode = Schema.RequiredMode.REQUIRED))
})
@RequiresPermissions(PermissionConstants.PROJECT_MEMBER_DELETE)
public void removeMember(@PathVariable String projectId, @PathVariable String userId) {
projectMemberService.removeMember(projectId, userId);
}
@PostMapping("/add-role")
@Operation(summary = "项目管理-成员-批量添加至用户组")
@RequiresPermissions(PermissionConstants.PROJECT_MEMBER_UPDATE)
public void addMemberRole(@RequestBody ProjectMemberAddRequest request) {
projectMemberService.addMemberRole(request, SessionUtils.getUserId());
}
@PostMapping("/batch/remove")
@Operation(summary = "项目管理-成员-批量从项目移除")
@RequiresPermissions(PermissionConstants.PROJECT_MEMBER_DELETE)
public void batchRemove(@RequestBody ProjectMemberBatchDeleteRequest request) {
projectMemberService.batchRemove(request);
}
}

View File

@ -0,0 +1,20 @@
package io.metersphere.project.dto;
import io.metersphere.system.domain.User;
import io.metersphere.system.domain.UserRole;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.util.List;
/**
* @author song-cc-rock
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class ProjectUserDTO extends User {
@Schema(description = "用户组集合")
private List<UserRole> userRoles;
}

View File

@ -0,0 +1,20 @@
package io.metersphere.project.mapper;
import io.metersphere.project.request.ProjectMemberRequest;
import org.apache.ibatis.annotations.Param;
import java.util.List;
/**
* @author song-cc-rock
*/
public interface ExtProjectMemberMapper {
/**
* 获取项目成员列表
*
* @param request 请求参数
* @return 成员列表及用户组关联信息
*/
List<String> listMember(@Param("request") ProjectMemberRequest request);
}

View File

@ -0,0 +1,17 @@
<?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.project.mapper.ExtProjectMemberMapper">
<select id="listMember" resultType="java.lang.String">
select distinct u.id
from user_role_relation urr
join `user` u on urr.user_id = u.id
<where>
urr.source_id = #{request.projectId} and u.deleted = 0
<if test="request.keyword != null and request.keyword != ''">
and (u.name like CONCAT('%', #{request.keyword},'%')
or u.email like CONCAT('%', #{request.keyword},'%')
or u.phone like CONCAT('%', #{request.keyword},'%'))
</if>
</where>
</select>
</mapper>

View File

@ -0,0 +1,30 @@
package io.metersphere.project.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.List;
/**
* @author song-cc-rock
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class ProjectMemberAddRequest implements Serializable {
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{project.id.not_blank}")
private String projectId;
@Schema(description = "用户ID集合", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{user.id.not_blank}")
private List<String> userIds;
@Schema(description = "用户组ID集合", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{user_role.id.not_blank}")
private List<String> roleIds;
}

View File

@ -0,0 +1,26 @@
package io.metersphere.project.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.List;
/**
* @author song-cc-rock
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class ProjectMemberBatchDeleteRequest implements Serializable {
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{project.id.not_blank}")
private String projectId;
@Schema(description = "用户ID集合", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{user.id.not_blank}")
private List<String> userIds;
}

View File

@ -0,0 +1,30 @@
package io.metersphere.project.request;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotEmpty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serializable;
import java.util.List;
/**
* @author song-cc-rock
*/
@Data
@EqualsAndHashCode(callSuper = false)
public class ProjectMemberEditRequest implements Serializable {
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{project.id.not_blank}")
private String projectId;
@Schema(description = "用户ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{user.id.not_blank}")
private String userId;
@Schema(description = "用户组ID集合", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{user_role.id.not_blank}")
private List<String> roleIds;
}

View File

@ -0,0 +1,16 @@
package io.metersphere.project.request;
import io.metersphere.sdk.dto.BasePageRequest;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import lombok.Data;
import lombok.EqualsAndHashCode;
@Data
@EqualsAndHashCode(callSuper = false)
public class ProjectMemberRequest extends BasePageRequest {
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
@NotBlank(message = "{project.id.not_blank}")
private String projectId;
}

View File

@ -0,0 +1,248 @@
package io.metersphere.project.service;
import io.metersphere.project.domain.Project;
import io.metersphere.project.dto.ProjectUserDTO;
import io.metersphere.project.mapper.ExtProjectMemberMapper;
import io.metersphere.project.mapper.ProjectMapper;
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.UserRoleEnum;
import io.metersphere.sdk.constants.UserRoleType;
import io.metersphere.sdk.dto.OptionDTO;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.mapper.BaseUserMapper;
import io.metersphere.sdk.util.BeanUtils;
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.stream.Collectors;
/**
* @author song-cc-rock
*/
@Service
@Transactional
public class ProjectMemberService {
@Resource
private UserRoleMapper userRoleMapper;
@Resource
private UserMapper userMapper;
@Resource
private UserRoleRelationMapper userRoleRelationMapper;
@Resource
private BaseUserMapper baseUserMapper;
@Resource
private ProjectMapper projectMapper;
@Resource
private ExtOrganizationMapper extOrganizationMapper;
@Resource
private ExtProjectMemberMapper extProjectMemberMapper;
/**
* 获取成员列表
*
* @param request 请求参数
* @return 成员列表
*/
public List<ProjectUserDTO> listMember(ProjectMemberRequest request) {
// 查询当前项目成员
List<String> members = extProjectMemberMapper.listMember(request);
UserRoleRelationExample relationExample = new UserRoleRelationExample();
relationExample.createCriteria().andSourceIdEqualTo(request.getProjectId()).andUserIdIn(members);
List<UserRoleRelation> userRoleRelates = userRoleRelationMapper.selectByExample(relationExample);
Map<String, List<String>> userRoleRelateMap = userRoleRelates.stream().collect(Collectors.groupingBy(UserRoleRelation::getUserId,
Collectors.mapping(UserRoleRelation::getRoleId, Collectors.toList())));
// 查询所有用户
List<User> users = baseUserMapper.findAll();
Map<String, User> userMap = users.stream().collect(Collectors.toMap(User::getId, user -> user));
// 查询所有项目类型用户组
UserRoleExample example = new UserRoleExample();
example.createCriteria().andTypeEqualTo(UserRoleType.PROJECT.name());
List<UserRole> roles = userRoleMapper.selectByExample(example);
Map<String, UserRole> roleMap = roles.stream().collect(Collectors.toMap(UserRole::getId, role -> role));
List<ProjectUserDTO> projectUsers = new ArrayList<>();
userRoleRelateMap.forEach((k, v) -> {
ProjectUserDTO projectUser = new ProjectUserDTO();
User user = userMap.get(k);
BeanUtils.copyBean(projectUser, user);
List<UserRole> userRoles = new ArrayList<>();
v.forEach(roleId -> {
UserRole role = roleMap.get(roleId);
userRoles.add(role);
});
projectUser.setUserRoles(userRoles);
projectUsers.add(projectUser);
});
return projectUsers;
}
/**
* 获取组织成员下拉选项
*
* @param projectId 项目ID
* @return 项目成员下拉选项
*/
public List<UserExtend> getMemberOption(String projectId) {
Project project = projectMapper.selectByPrimaryKey(projectId);
if (project == null) {
return new ArrayList<>();
}
return extOrganizationMapper.getMemberByOrg(project.getOrganizationId());
}
/**
* 获取项目用户组下拉选项
*
* @param projectId 项目ID
* @return 用户组下拉选项
*/
public List<OptionDTO> getRoleOption(String projectId) {
UserRoleExample example = new UserRoleExample();
example.createCriteria().andTypeEqualTo(UserRoleType.PROJECT.name())
.andScopeIdIn(Arrays.asList(projectId, UserRoleEnum.GLOBAL.toString()));
List<UserRole> userRoles = userRoleMapper.selectByExample(example);
return userRoles.stream().map(userRole -> new OptionDTO(userRole.getId(), userRole.getName())).toList();
}
/**
* 添加成员(项目)
*
* @param request 请求参数
* @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);
}
}
/**
* 更新成员(项目)
*
* @param request 请求参数
* @param currentUserId 当前用户ID
*/
public void updateMember(ProjectMemberEditRequest request, String currentUserId) {
// 项目不存在
checkProjectExist(request.getProjectId());
// 移除已经存在的用户组
UserRoleRelationExample example = new UserRoleRelationExample();
example.createCriteria().andSourceIdEqualTo(request.getProjectId())
.andUserIdEqualTo(request.getUserId());
userRoleRelationMapper.deleteByExample(example);
// 添加新的用户组
List<UserRoleRelation> relations = new ArrayList<>();
request.getRoleIds().forEach(roleId -> {
// 用户不存在或用户组不存在, 则不添加
if (isUserOrRoleNotExist(request.getUserId(), roleId)) {
return;
}
UserRoleRelation relation = new UserRoleRelation();
relation.setId(UUID.randomUUID().toString());
relation.setUserId(request.getUserId());
relation.setRoleId(roleId);
relation.setSourceId(request.getProjectId());
relation.setCreateTime(System.currentTimeMillis());
relation.setCreateUser(currentUserId);
relations.add(relation);
});
if (!CollectionUtils.isEmpty(relations)) {
userRoleRelationMapper.batchInsert(relations);
}
}
/**
* 移除成员(项目)
*
* @param projectId 项目ID
* @param userId 用户ID
*/
public void removeMember(String projectId, String userId) {
// 项目不存在, 则不移除
checkProjectExist(projectId);
// 移除成员, 则移除该成员在该项目下的所有用户组
UserRoleRelationExample example = new UserRoleRelationExample();
example.createCriteria().andSourceIdEqualTo(projectId).andUserIdEqualTo(userId);
userRoleRelationMapper.deleteByExample(example);
}
/**
* 批量添加成员至用户组(项目)
* @param request 请求参数
* @param currentUserId 当前用户ID
*/
public void addMemberRole(ProjectMemberAddRequest request, String currentUserId) {
// 添加用户用户组(已经添加的用户组不再添加)
addMember(request, currentUserId);
}
/**
* 批量移除成员(项目)
* @param request 请求参数
*/
public void batchRemove(ProjectMemberBatchDeleteRequest request) {
// 项目不存在, 则不移除
checkProjectExist(request.getProjectId());
// 批量移除成员, 则移除该成员在该项目下的所有用户组
UserRoleRelationExample example = new UserRoleRelationExample();
example.createCriteria().andSourceIdEqualTo(request.getProjectId())
.andUserIdIn(request.getUserIds());
userRoleRelationMapper.deleteByExample(example);
}
private void checkProjectExist(String projectId) {
Project project = projectMapper.selectByPrimaryKey(projectId);
if (project == null) {
throw new MSException(Translator.get("project_not_exist"));
}
}
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;
}
}

View File

@ -0,0 +1,235 @@
package io.metersphere.project.controller;
import io.metersphere.project.dto.ProjectUserDTO;
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.base.BaseTest;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.controller.handler.ResultHolder;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Pager;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.jdbc.Sql;
import org.springframework.test.context.jdbc.SqlConfig;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.nio.charset.StandardCharsets;
import java.util.List;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
public class ProjectMemberControllerTests extends BaseTest {
public static final String LIST_MEMBER = "/project/member/list";
public static final String GET_MEMBER = "/project/member/get-member/option";
public static final String GET_ROLE = "/project/member/get-role/option";
public static final String ADD_MEMBER = "/project/member/add";
public static final String UPDATE_MEMBER = "/project/member/update";
public static final String REMOVE_MEMBER = "/project/member/remove";
public static final String ADD_ROLE = "/project/member/add-role";
public static final String BATCH_REMOVE_MEMBER = "/project/member/batch/remove";
@Test
@Order(1)
@Sql(scripts = {"/dml/init_project_member.sql"}, config = @SqlConfig(encoding = "utf-8", transactionMode = SqlConfig.TransactionMode.ISOLATED))
public void testListMemberSuccess() throws Exception{
ProjectMemberRequest request = new ProjectMemberRequest();
request.setProjectId("default-project-member-test");
request.setCurrent(1);
request.setPageSize(10);
request.setKeyword("default");
MvcResult mvcResult = this.responsePost(LIST_MEMBER, request);
// 获取返回值
String returnData = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
ResultHolder resultHolder = JSON.parseObject(returnData, ResultHolder.class);
// 返回请求正常
Assertions.assertNotNull(resultHolder);
Pager<?> pageData = JSON.parseObject(JSON.toJSONString(resultHolder.getData()), Pager.class);
// 返回值不为空
Assertions.assertNotNull(pageData);
// 返回值的页码和当前页码相同
Assertions.assertEquals(pageData.getCurrent(), request.getCurrent());
// 返回的数据量不超过规定要返回的数据量相同
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= request.getPageSize());
// 返回值中取出第一条数据, 并判断name, email, phone是否包含关键字default
ProjectUserDTO projectUserDTO = JSON.parseArray(JSON.toJSONString(pageData.getList()), ProjectUserDTO.class).get(0);
Assertions.assertTrue(StringUtils.contains(projectUserDTO.getName(), request.getKeyword())
|| StringUtils.contains(projectUserDTO.getEmail(), request.getKeyword())
|| StringUtils.contains(projectUserDTO.getPhone(), request.getKeyword()));
}
@Test
@Order(2)
public void testListMemberError() throws Exception {
// 页码有误
ProjectMemberRequest request = new ProjectMemberRequest();
request.setCurrent(0);
request.setPageSize(10);
this.requestPost(LIST_MEMBER, request, status().isBadRequest());
// 页数有误
request = new ProjectMemberRequest();
request.setCurrent(1);
request.setPageSize(1);
this.requestPost(LIST_MEMBER, request, status().isBadRequest());
}
@Test
@Order(3)
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());
}
@Test
@Order(5)
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());
}
@Test
@Order(6)
public void testAddMemberRepeat() throws Exception {
ProjectMemberAddRequest request = new ProjectMemberAddRequest();
request.setProjectId("default-project-member-test");
request.setUserIds(List.of("default-project-member-user-1"));
request.setRoleIds(List.of("project_admin"));
this.requestPost(ADD_MEMBER, request, status().isOk());
}
@Test
@Order(7)
public void testAddMemberError() throws Exception {
ProjectMemberAddRequest request = new ProjectMemberAddRequest();
request.setProjectId("default-project-member-x");
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().is5xxServerError());
}
@Test
@Order(8)
public void testUpdateMemberSuccess() throws Exception {
// 不存在的用户组
ProjectMemberEditRequest request = new ProjectMemberEditRequest();
request.setProjectId("default-project-member-test");
request.setUserId("default-project-member-user-1");
request.setRoleIds(List.of("project_admin_x"));
this.requestPost(UPDATE_MEMBER, request, status().isOk());
// 存在的用户组
request.setRoleIds(List.of("project_admin", "project_member"));
this.requestPost(UPDATE_MEMBER, request, status().isOk());
}
@Test
@Order(9)
public void testUpdateMemberError() throws Exception {
ProjectMemberEditRequest request = new ProjectMemberEditRequest();
request.setProjectId("default-project-member-x");
request.setUserId("default-project-member-user-1");
request.setRoleIds(List.of("project_admin", "project_admin_x", "project_member"));
this.requestPost(UPDATE_MEMBER, request, status().is5xxServerError());
}
@Test
@Order(10)
public void testRemoveMemberSuccess() throws Exception {
this.requestGet(REMOVE_MEMBER + "/default-project-member-test/default-project-member-user-1", status().isOk());
}
@Test
@Order(11)
public void testRemoveMemberError() throws Exception {
this.requestGet(REMOVE_MEMBER + "/default-project-member-x/default-project-member-user-1", status().is5xxServerError());
}
@Test
@Order(12)
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());
}
@Test
@Order(13)
public void testAddMemberRoleError() throws Exception {
ProjectMemberAddRequest request = new ProjectMemberAddRequest();
request.setProjectId("default-project-member-x");
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().is5xxServerError());
}
@Test
@Order(14)
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());
}
@Test
@Order(15)
public void testBatchRemoveMember() throws Exception {
ProjectMemberBatchDeleteRequest request = new ProjectMemberBatchDeleteRequest();
request.setProjectId("default-project-member-x");
request.setUserIds(List.of("default-project-member-user-1", "default-project-member-user-2"));
this.requestPost(BATCH_REMOVE_MEMBER, request, status().is5xxServerError());
}
private void requestPost(String url, Object param, ResultMatcher resultMatcher) throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post(url)
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.content(JSON.toJSONString(param))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(resultMatcher)
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
}
private MvcResult responsePost(String url, Object param) throws Exception {
return mockMvc.perform(MockMvcRequestBuilders.post(url)
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.content(JSON.toJSONString(param))
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andReturn();
}
private void requestGet(String url, ResultMatcher resultMatcher) throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get(url)
.header(SessionConstants.HEADER_TOKEN, sessionId)
.header(SessionConstants.CSRF_TOKEN, csrfToken)
.contentType(MediaType.APPLICATION_JSON))
.andExpect(resultMatcher)
.andExpect(content().contentType(MediaType.APPLICATION_JSON));
}
}

View File

@ -0,0 +1,25 @@
# 1. 准备组织, 项目, 用户数据
# 2. 准备组织成员数据
# 3. 准备项目成员数据
INSERT INTO organization(id, num, name, description, create_time, update_time, create_user, update_user, deleted, delete_user, delete_time) VALUE
('default-organization-member-test', null, 'efault-organization-member-test', 'efault-organization-member-test', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, 'admin', 'admin', 0, null, null);
INSERT INTO project (id, num, organization_id, name, description, create_user, update_user, create_time, update_time) VALUE
('default-project-member-test', null, 'efault-organization-member-test', '默认项目', '系统默认创建的项目', 'admin', 'admin', UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000);
INSERT INTO user(id, name, email, password, create_time, update_time, language, last_organization_id, phone, source, last_project_id, create_user, update_user, deleted) VALUES
('default-project-member-user-1', 'default-project-member-user1', 'project-member1@metersphere.io', MD5('metersphere'), UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', 0),
('default-project-member-user-2', 'default-project-member-user2', 'project-member2@metersphere.io', MD5('metersphere'), UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', 0),
('default-project-member-user-del', 'default-project-member-userDel', 'project-member-del@metersphere.io', MD5('metersphere'), UNIX_TIMESTAMP() * 1000, UNIX_TIMESTAMP() * 1000, NULL, NUll, '', 'LOCAL', NULL, 'admin', 'admin', 1);
INSERT INTO user_role_relation (id, user_id, role_id, source_id, create_time, create_user) VALUES
(UUID(), 'default-project-member-user-1', 'org_member', 'default-organization-member-test', UNIX_TIMESTAMP() * 1000, 'admin'),
(UUID(), 'default-project-member-user-2', 'org_member', 'default-organization-member-test', UNIX_TIMESTAMP() * 1000, 'admin');
INSERT INTO user_role_relation (id, user_id, role_id, source_id, create_time, create_user) VALUES
(UUID(), 'default-project-member-user-1', 'project_admin', 'default-project-member-test', UNIX_TIMESTAMP() * 1000, 'admin'),
(UUID(), 'default-project-member-user-2', 'project_admin', 'default-project-member-test', UNIX_TIMESTAMP() * 1000, 'admin'),
(UUID(), 'default-project-member-user-del', 'project_admin', 'default-project-member-test', UNIX_TIMESTAMP() * 1000, 'admin');

View File

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

View File

@ -80,6 +80,7 @@
<select id="selectOrganizationOptions" resultType="io.metersphere.system.dto.OrganizationProjectOptionsDTO">
select id, name from organization order by create_time desc
</select>
<select id="getOptionsByIds" resultType="io.metersphere.sdk.dto.OptionDTO">
select id, name from organization where id in
<foreach collection="ids" item="id" open="(" separator="," close=")">
@ -87,6 +88,17 @@
</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">