refactor(系统设置): 组织至少保留一个管理员
This commit is contained in:
parent
68bd55647d
commit
5662e5abe7
|
@ -9,6 +9,7 @@ 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.InternalUserRole;
|
||||
import io.metersphere.sdk.constants.UserRoleEnum;
|
||||
import io.metersphere.sdk.constants.UserRoleType;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
|
@ -223,6 +224,14 @@ public class ProjectMemberService {
|
|||
List<LogDTO> logs = new ArrayList<>();
|
||||
// 项目不存在, 则不移除
|
||||
checkProjectExist(projectId);
|
||||
//判断用户是不是最后一个管理员 如果是 就报错
|
||||
UserRoleRelationExample userRoleRelationExample = new UserRoleRelationExample();
|
||||
userRoleRelationExample.createCriteria().andUserIdNotEqualTo(userId)
|
||||
.andSourceIdEqualTo(projectId)
|
||||
.andRoleIdEqualTo(InternalUserRole.PROJECT_ADMIN.getValue());
|
||||
if (userRoleRelationMapper.countByExample(userRoleRelationExample) == 0) {
|
||||
throw new MSException(Translator.get("keep_at_least_one_administrator"));
|
||||
}
|
||||
// 移除成员, 则移除该成员在该项目下的所有用户组
|
||||
UserRoleRelationExample example = new UserRoleRelationExample();
|
||||
example.createCriteria().andSourceIdEqualTo(projectId).andUserIdEqualTo(userId);
|
||||
|
@ -331,7 +340,8 @@ public class ProjectMemberService {
|
|||
|
||||
/**
|
||||
* 获取项目评论下拉成员选项
|
||||
* @param keyword 搜索关键字
|
||||
*
|
||||
* @param keyword 搜索关键字
|
||||
* @param projectId 项目ID
|
||||
* @return 用户集合信息
|
||||
*/
|
||||
|
|
|
@ -28,7 +28,7 @@ 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(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class ProjectMemberControllerTests extends BaseTest {
|
||||
|
@ -196,6 +196,7 @@ public class ProjectMemberControllerTests extends BaseTest {
|
|||
@Order(12)
|
||||
public void testRemoveMemberError() throws Exception {
|
||||
this.requestGet(REMOVE_MEMBER + "/default-project-member-x/default-project-member-user-1", status().is5xxServerError());
|
||||
this.requestGet(REMOVE_MEMBER + "/default-project-member-test-1/admin", status().is5xxServerError());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -21,7 +21,8 @@ INSERT INTO user_role_relation (id, user_id, role_id, source_id, organization_id
|
|||
INSERT INTO user_role_relation (id, user_id, role_id, source_id, organization_id, create_time, create_user) VALUES
|
||||
(UUID(), 'default-project-member-user-1', 'project_admin', 'default-project-member-test', 'default-organization-member-test', UNIX_TIMESTAMP() * 1000, 'admin'),
|
||||
(UUID(), 'default-project-member-user-2', 'project_admin', 'default-project-member-test', 'default-organization-member-test', UNIX_TIMESTAMP() * 1000, 'admin'),
|
||||
(UUID(), 'default-project-member-user-del', 'project_admin', 'default-project-member-test', 'default-organization-member-test', UNIX_TIMESTAMP() * 1000, 'admin');
|
||||
(UUID(), 'default-project-member-user-del', 'project_admin', 'default-project-member-test', 'default-organization-member-test', UNIX_TIMESTAMP() * 1000, 'admin'),
|
||||
(UUID(), 'admin', 'org_admin', 'default-project-member-test-1', 'default-organization-member-test', UNIX_TIMESTAMP() * 1000, 'admin');
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import io.metersphere.validation.groups.Created;
|
|||
import io.metersphere.validation.groups.Updated;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotEmpty;
|
||||
import jakarta.validation.constraints.Size;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
@ -15,17 +16,18 @@ import java.util.List;
|
|||
@EqualsAndHashCode(callSuper = false)
|
||||
public class OrganizationEditRequest implements Serializable {
|
||||
|
||||
@Schema(description = "组织ID")
|
||||
@Schema(description = "组织ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "组织名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@Schema(description = "组织名称", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "{organization.name.not_blank}", groups = {Created.class, Updated.class})
|
||||
@Size(min = 1, max = 255, message = "{organization.name.length_range}", groups = {Created.class, Updated.class})
|
||||
private String name;
|
||||
|
||||
@Schema(description = "描述")
|
||||
@Schema(description = "描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "成员ID集合")
|
||||
@Schema(description = "成员ID集合")
|
||||
@NotEmpty(message = "{project.member_count.not_blank}", groups = {Created.class, Updated.class})
|
||||
private List<String> userIds;
|
||||
}
|
||||
|
|
|
@ -107,6 +107,7 @@ public class OrganizationService {
|
|||
|
||||
/**
|
||||
* 更新组织名称
|
||||
*
|
||||
* @param organizationDTO 组织请求参数
|
||||
*/
|
||||
public void updateName(OrganizationDTO organizationDTO) {
|
||||
|
@ -120,6 +121,7 @@ public class OrganizationService {
|
|||
|
||||
/**
|
||||
* 更新组织
|
||||
*
|
||||
* @param organizationDTO 组织请求参数
|
||||
*/
|
||||
public void update(OrganizationDTO organizationDTO) {
|
||||
|
@ -134,36 +136,28 @@ public class OrganizationService {
|
|||
List<String> addOrgAdmins = organizationDTO.getUserIds();
|
||||
// 旧的组织管理员ID
|
||||
List<String> oldOrgAdmins = getOrgAdminIds(organizationDTO.getId());
|
||||
if (CollectionUtils.isNotEmpty(addOrgAdmins)) {
|
||||
// 需要新增组织管理员ID
|
||||
List<String> addIds = addOrgAdmins.stream().filter(addOrgAdmin -> !oldOrgAdmins.contains(addOrgAdmin)).toList();
|
||||
// 需要删除的组织管理员ID
|
||||
List<String> deleteIds = oldOrgAdmins.stream().filter(oldOrgAdmin -> !addOrgAdmins.contains(oldOrgAdmin)).toList();
|
||||
// 添加组织管理员
|
||||
if (CollectionUtils.isNotEmpty(addIds)) {
|
||||
addIds.forEach(userId -> {
|
||||
// 添加组织管理员
|
||||
createAdmin(userId, organizationDTO.getId(), organizationDTO.getUpdateUser());
|
||||
});
|
||||
}
|
||||
// 删除组织管理员
|
||||
if (CollectionUtils.isNotEmpty(deleteIds)) {
|
||||
UserRoleRelationExample deleteExample = new UserRoleRelationExample();
|
||||
deleteExample.createCriteria().andSourceIdEqualTo(organizationDTO.getId()).andRoleIdEqualTo(InternalUserRole.ORG_ADMIN.getValue()).andUserIdIn(deleteIds);
|
||||
userRoleRelationMapper.deleteByExample(deleteExample);
|
||||
}
|
||||
} else {
|
||||
// 前端传入的组织管理员ID为空,删除所有组织管理员
|
||||
if (CollectionUtils.isNotEmpty(oldOrgAdmins)) {
|
||||
UserRoleRelationExample example = new UserRoleRelationExample();
|
||||
example.createCriteria().andSourceIdEqualTo(organizationDTO.getId()).andRoleIdEqualTo(InternalUserRole.ORG_ADMIN.getValue());
|
||||
userRoleRelationMapper.deleteByExample(example);
|
||||
}
|
||||
// 需要新增组织管理员ID
|
||||
List<String> addIds = addOrgAdmins.stream().filter(addOrgAdmin -> !oldOrgAdmins.contains(addOrgAdmin)).toList();
|
||||
// 需要删除的组织管理员ID
|
||||
List<String> deleteIds = oldOrgAdmins.stream().filter(oldOrgAdmin -> !addOrgAdmins.contains(oldOrgAdmin)).toList();
|
||||
// 添加组织管理员
|
||||
if (CollectionUtils.isNotEmpty(addIds)) {
|
||||
addIds.forEach(userId -> {
|
||||
// 添加组织管理员
|
||||
createAdmin(userId, organizationDTO.getId(), organizationDTO.getUpdateUser());
|
||||
});
|
||||
}
|
||||
// 删除组织管理员
|
||||
if (CollectionUtils.isNotEmpty(deleteIds)) {
|
||||
UserRoleRelationExample deleteExample = new UserRoleRelationExample();
|
||||
deleteExample.createCriteria().andSourceIdEqualTo(organizationDTO.getId()).andRoleIdEqualTo(InternalUserRole.ORG_ADMIN.getValue()).andUserIdIn(deleteIds);
|
||||
userRoleRelationMapper.deleteByExample(deleteExample);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除组织
|
||||
*
|
||||
* @param organizationDeleteRequest 组织删除参数
|
||||
*/
|
||||
public void delete(OrganizationDeleteRequest organizationDeleteRequest) {
|
||||
|
@ -176,6 +170,7 @@ public class OrganizationService {
|
|||
|
||||
/**
|
||||
* 恢复组织
|
||||
*
|
||||
* @param id 组织ID
|
||||
*/
|
||||
public void recover(String id) {
|
||||
|
@ -185,6 +180,7 @@ public class OrganizationService {
|
|||
|
||||
/**
|
||||
* 开启组织
|
||||
*
|
||||
* @param id 组织ID
|
||||
*/
|
||||
public void enable(String id) {
|
||||
|
@ -194,6 +190,7 @@ public class OrganizationService {
|
|||
|
||||
/**
|
||||
* 结束组织
|
||||
*
|
||||
* @param id 组织ID
|
||||
*/
|
||||
public void disable(String id) {
|
||||
|
@ -318,6 +315,14 @@ public class OrganizationService {
|
|||
public void removeMember(String organizationId, String userId, String currentUser) {
|
||||
List<LogDTO> logs = new ArrayList<>();
|
||||
checkOrgExistById(organizationId);
|
||||
//检查用户是不是最后一个管理员
|
||||
UserRoleRelationExample userRoleRelationExample = new UserRoleRelationExample();
|
||||
userRoleRelationExample.createCriteria().andUserIdNotEqualTo(userId)
|
||||
.andSourceIdEqualTo(organizationId)
|
||||
.andRoleIdEqualTo(InternalUserRole.ORG_ADMIN.getValue());
|
||||
if (userRoleRelationMapper.countByExample(userRoleRelationExample) == 0) {
|
||||
throw new MSException(Translator.get("keep_at_least_one_administrator"));
|
||||
}
|
||||
//删除组织下项目与成员的关系
|
||||
List<String> projectIds = getProjectIds(organizationId);
|
||||
if (CollectionUtils.isNotEmpty(projectIds)) {
|
||||
|
@ -1015,15 +1020,17 @@ public class OrganizationService {
|
|||
/**
|
||||
* 校验组织是否存在
|
||||
* 这里使用静态方法,避免需要注入,导致循环依赖
|
||||
*
|
||||
* @param id
|
||||
* @return
|
||||
*/
|
||||
public static Organization checkResourceExist(String id) {
|
||||
return ServiceUtils.checkResourceExist( CommonBeanFactory.getBean(OrganizationMapper.class).selectByPrimaryKey(id), "permission.system_organization_project.name");
|
||||
return ServiceUtils.checkResourceExist(CommonBeanFactory.getBean(OrganizationMapper.class).selectByPrimaryKey(id), "permission.system_organization_project.name");
|
||||
}
|
||||
|
||||
/**
|
||||
* 剩余天数
|
||||
*
|
||||
* @param deleteTime 删除时间
|
||||
* @return 剩余天数
|
||||
*/
|
||||
|
|
|
@ -34,7 +34,7 @@ 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(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class OrganizationControllerTests extends BaseTest {
|
||||
|
@ -160,7 +160,7 @@ public class OrganizationControllerTests extends BaseTest {
|
|||
//组织ID正确
|
||||
// 成员为空
|
||||
updateOrganizationMemberError(ORGANIZATION_UPDATE_MEMBER, "sys_default_organization_3", null, Arrays.asList("sys_default_org_role_id_2", "sys_default_org_role_id_3"), Arrays.asList("sys_org_projectId", "sys_org_projectId1"), status().isBadRequest());
|
||||
//成员不存在
|
||||
//成员不存在
|
||||
updateOrganizationMemberError(ORGANIZATION_UPDATE_MEMBER, "sys_default_organization_3", "sys_default_userX", Arrays.asList("sys_default_org_role_id_2", "sys_default_org_role_id_3"), Arrays.asList("sys_org_projectId", "sys_org_projectId1"), status().is5xxServerError());
|
||||
// 组织ID不存在
|
||||
updateOrganizationMemberError(ORGANIZATION_UPDATE_MEMBER, "sys_default_organization_X", "sys_default_user2", Arrays.asList("sys_default_org_role_id_2", "sys_default_org_role_id_3"), Arrays.asList("sys_org_projectId", "sys_org_projectId1"), status().is5xxServerError());
|
||||
|
@ -282,7 +282,7 @@ public class OrganizationControllerTests extends BaseTest {
|
|||
Assertions.assertTrue(JSON.parseArray(JSON.toJSONString(pageData.getList())).size() <= organizationRequest.getPageSize());
|
||||
//判断是否为空
|
||||
List<OrgUserExtend> orgUserExtends = JSON.parseArray(JSON.toJSONString(pageData.getList()), OrgUserExtend.class);
|
||||
Assertions.assertTrue(CollectionUtils.isEmpty(orgUserExtends));
|
||||
Assertions.assertTrue(CollectionUtils.isNotEmpty(orgUserExtends));
|
||||
|
||||
}
|
||||
|
||||
|
@ -309,13 +309,14 @@ public class OrganizationControllerTests extends BaseTest {
|
|||
@Test
|
||||
@Order(14)
|
||||
public void removeOrgMemberSuccess() throws Exception {
|
||||
this.requestGet(ORGANIZATION_REMOVE_MEMBER + "/sys_default_organization_6/sys_default_user", status().isOk());
|
||||
this.requestGet(ORGANIZATION_REMOVE_MEMBER + "/sys_default_organization_6/sys_default_user4", status().isOk());
|
||||
this.requestGet(ORGANIZATION_REMOVE_MEMBER + "/sys_default_organization_6/sys_default_user", status().is5xxServerError());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Order(15)
|
||||
public void removeOrgMemberSuccessWithNoProject() throws Exception {
|
||||
this.requestGet(ORGANIZATION_REMOVE_MEMBER + "/sys_default_organization_3/sys_default_user", status().isOk());
|
||||
this.requestGet(ORGANIZATION_REMOVE_MEMBER + "/sys_default_organization_3/sys_default_user4", status().isOk());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -425,7 +426,6 @@ public class OrganizationControllerTests extends BaseTest {
|
|||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
@Order(23)
|
||||
public void getNotExistUserListByOrgSuccess() throws Exception {
|
||||
|
@ -474,7 +474,6 @@ public class OrganizationControllerTests extends BaseTest {
|
|||
}
|
||||
|
||||
|
||||
|
||||
private void listByKeyWord(String keyWord, String orgId, boolean compare, String userRoleId, String projectId, boolean checkPart, String noUserRoleId, String noProjectId) throws Exception {
|
||||
OrganizationRequest organizationRequest = new OrganizationRequest();
|
||||
organizationRequest.setCurrent(1);
|
||||
|
|
|
@ -30,10 +30,10 @@ import java.util.*;
|
|||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
|
||||
|
||||
@SpringBootTest(webEnvironment= SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@AutoConfigureMockMvc
|
||||
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
|
||||
public class SystemOrganizationControllerTests extends BaseTest{
|
||||
public class SystemOrganizationControllerTests extends BaseTest {
|
||||
|
||||
@Resource
|
||||
private MockMvc mockMvc;
|
||||
|
@ -145,8 +145,8 @@ public class SystemOrganizationControllerTests extends BaseTest{
|
|||
request.setUserIds(List.of("user-id1"));
|
||||
this.requestPost(ORGANIZATION_UPDATE, request).andExpect(status().isOk());
|
||||
request.setUserIds(List.of());
|
||||
this.requestPost(ORGANIZATION_UPDATE, request).andExpect(status().isOk());
|
||||
this.requestPost(ORGANIZATION_UPDATE, request).andExpect(status().isOk());
|
||||
this.requestPost(ORGANIZATION_UPDATE, request).andExpect(status().isBadRequest());
|
||||
this.requestPost(ORGANIZATION_UPDATE, request).andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -154,12 +154,15 @@ public class SystemOrganizationControllerTests extends BaseTest{
|
|||
public void testUpdateOrganizationError() throws Exception {
|
||||
OrganizationEditRequest request = new OrganizationEditRequest();
|
||||
request.setName("default-4");
|
||||
request.setUserIds(List.of("user-id1", "user-id2"));
|
||||
// 组织不存在
|
||||
request.setId("default-organization-x");
|
||||
this.requestPost(ORGANIZATION_UPDATE, request).andExpect(status().is5xxServerError());
|
||||
// 组织存在, 但是名称重复
|
||||
request.setId("default-organization-5");
|
||||
this.requestPost(ORGANIZATION_UPDATE, request).andExpect(status().is5xxServerError());
|
||||
request.setUserIds(new ArrayList<>());
|
||||
this.requestPost(ORGANIZATION_UPDATE, request).andExpect(status().isBadRequest());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -381,6 +384,8 @@ public class SystemOrganizationControllerTests extends BaseTest{
|
|||
this.requestGet(ORGANIZATION_REMOVE_MEMBER + "/default-organization-3/admin", status().isOk());
|
||||
// 日志校验
|
||||
checkLog("default-organization-3", OperationLogType.DELETE);
|
||||
|
||||
this.requestGet(ORGANIZATION_REMOVE_MEMBER + "/default-organization-5/user-id1", status().is5xxServerError());
|
||||
// 权限校验
|
||||
requestGetPermissionTest(PermissionConstants.SYSTEM_ORGANIZATION_PROJECT_MEMBER_DELETE, ORGANIZATION_REMOVE_MEMBER + "/default-organization-3/admin");
|
||||
}
|
||||
|
|
|
@ -50,4 +50,9 @@ INSERT INTO user_role(id, name, description, internal, type, create_time, update
|
|||
|
||||
INSERT INTO user_role_relation(id, user_id, role_id, source_id, organization_id, create_time, create_user) VALUE
|
||||
('gyq_user_role_relation_test', 'sys_default_user4', 'sys_default_org_role_id_5', 'sys_default_organization_6', 'sys_default_organization_6', UNIX_TIMESTAMP() * 1000, 'admin');
|
||||
|
||||
INSERT INTO user_role_relation(id, user_id, role_id, source_id, organization_id, create_time, create_user) VALUE
|
||||
('gyq_user_role_relation_test-1', 'sys_default_user', 'org_admin', 'sys_default_organization_6', 'sys_default_organization_6', UNIX_TIMESTAMP() * 1000, 'admin');
|
||||
INSERT INTO user_role_relation(id, user_id, role_id, source_id, organization_id, create_time, create_user) VALUE
|
||||
('gyq_user_role_relation_test-2', 'admin', 'org_admin', 'sys_default_organization_3', 'sys_default_organization_3', UNIX_TIMESTAMP() * 1000, 'admin');
|
||||
INSERT INTO user_role_relation(id, user_id, role_id, source_id, organization_id, create_time, create_user) VALUE
|
||||
('gyq_user_role_relation_test-3', 'sys_default_user4', 'sys_default_project_role_id_3', 'sys_org_projectId', 'sys_default_organization_3', UNIX_TIMESTAMP() * 1000, 'admin');
|
Loading…
Reference in New Issue