feat(系统设置): 添加超级管理员用户组

--story=1010746 --user=李玉号 【系统设置】添加超级管理员用户组
https://www.tapd.cn/55049933/s/1314273
This commit is contained in:
shiziyuan9527 2022-12-02 17:44:10 +08:00 committed by 刘瑞斌
parent e0e8d66f44
commit 0a01ed4903
28 changed files with 364 additions and 169 deletions

View File

@ -2,10 +2,8 @@ package io.metersphere.gateway.service;
import io.metersphere.base.domain.*;
import io.metersphere.base.mapper.*;
import io.metersphere.commons.constants.SessionConstants;
import io.metersphere.commons.constants.UserGroupType;
import io.metersphere.commons.constants.UserSource;
import io.metersphere.commons.constants.UserStatus;
import io.metersphere.base.mapper.ext.BaseProjectMapper;
import io.metersphere.commons.constants.*;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.user.SessionUser;
import io.metersphere.commons.utils.CodingUtil;
@ -39,6 +37,8 @@ public class UserLoginService {
private UserGroupPermissionMapper userGroupPermissionMapper;
@Resource
private ProjectMapper projectMapper;
@Resource
private BaseProjectMapper baseProjectMapper;
public Optional<SessionUser> login(LoginRequest request, WebSession session, Locale locale) {
UserDTO userDTO;
@ -173,31 +173,55 @@ public class UserLoginService {
private void checkNewWorkspaceAndProject(WebSession session, UserDTO user) {
List<UserGroup> userGroups = user.getUserGroups();
List<String> projectGroupIds = user.getGroups()
.stream().filter(ug -> StringUtils.equals(ug.getType(), UserGroupType.PROJECT))
List<Group> groups = user.getGroups();
List<String> projectGroupIds = groups
.stream()
.filter(ug -> StringUtils.equals(ug.getType(), UserGroupType.PROJECT))
.map(Group::getId)
.collect(Collectors.toList());
List<UserGroup> project = userGroups.stream().filter(ug -> projectGroupIds.contains(ug.getGroupId()))
List<UserGroup> projects = userGroups
.stream()
.filter(ug -> projectGroupIds.contains(ug.getGroupId()))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(project)) {
List<String> workspaceIds = user.getGroups()
if (CollectionUtils.isEmpty(projects)) {
List<String> workspaceIds = groups
.stream()
.filter(ug -> StringUtils.equals(ug.getType(), UserGroupType.WORKSPACE))
.map(Group::getId)
.collect(Collectors.toList());
List<UserGroup> workspaces = userGroups.stream().filter(ug -> workspaceIds.contains(ug.getGroupId()))
List<UserGroup> workspaces = userGroups
.stream()
.filter(ug -> workspaceIds.contains(ug.getGroupId()))
.collect(Collectors.toList());
if (workspaces.size() > 0) {
String wsId = workspaces.get(0).getSourceId();
switchUserResource(session, "workspace", wsId, user);
} else {
// 用户登录之后没有项目和工作空间的权限就把值清空
user.setLastWorkspaceId("");
user.setLastProjectId("");
updateUser(user);
List<String> superGroupIds = groups
.stream()
.map(Group::getId)
.filter(id -> StringUtils.equals(id, UserGroupConstants.SUPER_GROUP))
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(superGroupIds)) {
Project p = baseProjectMapper.selectOne();
if (p != null) {
switchSuperUserResource(session, p.getId(), p.getWorkspaceId(), user);
}
} else {
UserGroup userGroup = project.stream().filter(p -> StringUtils.isNotBlank(p.getSourceId()))
// 用户登录之后没有项目和工作空间的权限就把值清空
user.setLastWorkspaceId(StringUtils.EMPTY);
user.setLastProjectId(StringUtils.EMPTY);
updateUser(user);
}
}
} else {
UserGroup userGroup = projects.stream()
.filter(p -> StringUtils.isNotBlank(p.getSourceId()))
.collect(Collectors.toList()).get(0);
String projectId = userGroup.getSourceId();
Project p = projectMapper.selectByPrimaryKey(projectId);
@ -231,6 +255,20 @@ public class UserLoginService {
userMapper.updateByPrimaryKeySelective(newUser);
}
private void switchSuperUserResource(WebSession session, String projectId, String workspaceId, UserDTO sessionUser) {
// 获取最新UserDTO
UserDTO user = getUserDTO(sessionUser.getId());
User newUser = new User();
user.setLastWorkspaceId(workspaceId);
sessionUser.setLastWorkspaceId(workspaceId);
user.setLastProjectId(projectId);
BeanUtils.copyProperties(user, newUser);
// 切换工作空间或组织之后更新 session 里的 user
session.getAttributes().put(SessionConstants.ATTR_USER, SessionUser.fromUser(user, session.getId()));
session.getAttributes().put(FindByIndexNameSessionRepository.PRINCIPAL_NAME_INDEX_NAME, sessionUser.getId());
userMapper.updateByPrimaryKeySelective(newUser);
}
public UserDTO getLoginUser(String userId, List<String> list) {
UserExample example = new UserExample();
example.createCriteria().andIdEqualTo(userId).andSourceIn(list);

View File

@ -13,6 +13,20 @@ export function hasPermission(permission) {
});
});
let superGroupPermissions = user.userGroups.filter(ug => ug.group && ug.group.id === 'super_group')
.flatMap(ug => ug.userGroupPermissions)
.map(g => g.permissionId)
.reduce((total, current) => {
total.add(current);
return total;
}, new Set);
for (const p of superGroupPermissions) {
if (p === permission) {
return true;
}
}
// todo 权限验证
let currentProjectPermissions = user.userGroups.filter(ug => ug.group && ug.group.type === 'PROJECT')
.filter(ug => ug.sourceId === getCurrentProjectID())

View File

@ -20,6 +20,7 @@ public class PermissionConfig implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) {
LogUtil.info("load permission form {} service permission.json file", service);
try (InputStream inputStream = PermissionConfig.class.getResourceAsStream("/permission.json")){
String permission = IOUtils.toString(inputStream, StandardCharsets.UTF_8);
stringRedisTemplate.opsForHash().put(RedisKey.MS_PERMISSION_KEY, service, permission);

View File

@ -18,7 +18,7 @@ public interface BaseProjectMapper {
int removeIssuePlatform(@Param("platform") String platform, @Param("workspaceId") String workspaceId);
List<ProjectDTO> getUserProject(@Param("proRequest") ProjectRequest request);
List<Project> getUserProject(@Param("proRequest") ProjectRequest request);
String getSystemIdByProjectId(String projectId);
@ -49,4 +49,6 @@ public interface BaseProjectMapper {
void updateUseDefaultCaseTemplateProject(@Param("originId") String originId,@Param("templateId") String templateId,@Param("projectId") String projectId);
List<String> getThirdPartProjectIds();
Project selectOne();
}

View File

@ -138,7 +138,7 @@
FROM project
WHERE workspace_id = #{workspaceId}
</select>
<select id="getUserProject" resultType="io.metersphere.dto.ProjectDTO">
<select id="getUserProject" resultType="io.metersphere.base.domain.Project">
SELECT DISTINCT p.*
FROM `group` g
JOIN user_group ug ON g.id = ug.group_id
@ -435,4 +435,7 @@
#{id}
</foreach>
</select>
<select id="selectOne" resultType="io.metersphere.base.domain.Project">
SELECT * FROM project LIMIT 1
</select>
</mapper>

View File

@ -34,4 +34,6 @@ public interface BaseUserMapper {
void updateLastProjectIdIfNull(@Param("projectId") String projectId, @Param("userId") String userId);
void updateLastWorkspaceIdIfNull(@Param("workspaceId") String workspaceId, @Param("userId") String userId);
boolean isSuperUser(String userId);
}

View File

@ -112,7 +112,9 @@
FROM user
<include refid="queryWhereCondition"/>
</select>
<select id="isSuperUser" resultType="java.lang.Boolean">
select count(*) from user_group where user_id = #{userId} and group_id = 'super_group'
</select>
<update id="updateLastProjectIdIfNull">
UPDATE user SET last_project_id = #{projectId} WHERE id = #{userId}
AND (last_project_id IS NULL OR last_project_id = '')

View File

@ -4,6 +4,7 @@ package io.metersphere.commons.constants;
* 系统内置用户组常量
*/
public class UserGroupConstants {
public static final String SUPER_GROUP = "super_group";
public static final String ADMIN = "admin";
public static final String ORG_ADMIN = "org_admin";
public static final String ORG_MEMBER = "org_member";

View File

@ -29,7 +29,7 @@ public class BaseProjectController {
* @return List<ProjectDTO>
*/
@PostMapping("/list/related")
public List<ProjectDTO> getUserProject(@RequestBody ProjectRequest request) {
public List<Project> getUserProject(@RequestBody ProjectRequest request) {
return baseProjectService.getUserProject(request);
}

View File

@ -105,4 +105,9 @@ public class BaseUserController {
public void updateCurrentUserByResourceId(@PathVariable String resourceId) {
baseUserService.updateCurrentUserByResourceId(resourceId);
}
@GetMapping("/is/super/{userid}")
public boolean isSuperUser(@PathVariable String userid) {
return baseUserService.isSuperUser(userid);
}
}

View File

@ -11,4 +11,10 @@ public class GroupResource implements Serializable {
private String id;
private String name;
private Boolean license = false;
/**
* 系统设置工作空间项目类型 公用的权限模块
* e.g. 个人信息
*/
private boolean global = false;
}

View File

@ -7,6 +7,7 @@ import io.metersphere.base.mapper.UserMapper;
import io.metersphere.base.mapper.ext.BaseProjectMapper;
import io.metersphere.base.mapper.ext.BaseProjectVersionMapper;
import io.metersphere.base.mapper.ext.BaseUserGroupMapper;
import io.metersphere.base.mapper.ext.BaseUserMapper;
import io.metersphere.commons.constants.ProjectApplicationType;
import io.metersphere.commons.exception.MSException;
import io.metersphere.commons.utils.JSON;
@ -54,6 +55,8 @@ public class BaseProjectService {
private BaseProjectVersionMapper baseProjectVersionMapper;
@Resource
private BaseProjectApplicationService baseProjectApplicationService;
@Resource
private BaseUserMapper baseUserMapper;
private String genSystemId() {
@ -90,7 +93,19 @@ public class BaseProjectService {
return baseProjectMapper.getProjectWithWorkspace(request);
}
public List<ProjectDTO> getUserProject(ProjectRequest request) {
public List<Project> getUserProject(ProjectRequest request) {
boolean isSuper = baseUserMapper.isSuperUser(SessionUtils.getUserId());
if (isSuper) {
ProjectExample example = new ProjectExample();
ProjectExample.Criteria criteria = example.createCriteria();
if (StringUtils.isNotBlank(request.getName())) {
criteria.andNameLike(request.getName());
}
if (StringUtils.isNotBlank(request.getWorkspaceId())) {
criteria.andWorkspaceIdEqualTo(request.getWorkspaceId());
}
return projectMapper.selectByExample(example);
}
if (StringUtils.isNotBlank(request.getName())) {
request.setName(StringUtils.wrapIfMissing(request.getName(), "%"));
}
@ -359,4 +374,8 @@ public class BaseProjectService {
public void deleteFile(String fileId) {
fileMetadataService.deleteFile(fileId);
}
public Project selectOne() {
return baseProjectMapper.selectOne();
}
}

View File

@ -242,17 +242,39 @@ public class BaseUserService {
// 获取最新UserDTO
UserDTO user = getUserDTO(sessionUser.getId());
User newUser = new User();
boolean isSuper = baseUserMapper.isSuperUser(sessionUser.getId());
if (StringUtils.equals("workspace", sign)) {
user.setLastWorkspaceId(sourceId);
sessionUser.setLastWorkspaceId(sourceId);
List<Project> projects = getProjectListByWsAndUserId(sessionUser.getId(), sourceId);
if (projects.size() > 0) {
if (CollectionUtils.isNotEmpty(projects)) {
user.setLastProjectId(projects.get(0).getId());
} else {
if (isSuper) {
ProjectExample example = new ProjectExample();
example.createCriteria().andWorkspaceIdEqualTo(sourceId);
List<Project> allWsProject = projectMapper.selectByExample(example);
if (CollectionUtils.isNotEmpty(allWsProject)) {
user.setLastProjectId(allWsProject.get(0).getId());
}
} else {
user.setLastProjectId(StringUtils.EMPTY);
}
}
}
BeanUtils.copyProperties(user, newUser);
// 切换工作空间或组织之后更新 session 里的 user
SessionUtils.putUser(SessionUser.fromUser(user, SessionUtils.getSessionId()));
userMapper.updateByPrimaryKeySelective(newUser);
}
private void switchSuperUserResource(String projectId, String workspaceId, UserDTO sessionUser) {
// 获取最新UserDTO
UserDTO user = getUserDTO(sessionUser.getId());
User newUser = new User();
user.setLastWorkspaceId(workspaceId);
sessionUser.setLastWorkspaceId(workspaceId);
user.setLastProjectId(projectId);
BeanUtils.copyProperties(user, newUser);
// 切换工作空间或组织之后更新 session 里的 user
SessionUtils.putUser(SessionUser.fromUser(user, SessionUtils.getSessionId()));
@ -417,12 +439,24 @@ public class BaseUserService {
if (workspaces.size() > 0) {
String wsId = workspaces.get(0).getSourceId();
switchUserResource("workspace", wsId, user);
} else {
List<String> superGroupIds = user.getGroups()
.stream()
.map(Group::getId)
.filter(id -> StringUtils.equals(id, UserGroupConstants.SUPER_GROUP))
.collect(Collectors.toList());
if (org.apache.commons.collections4.CollectionUtils.isNotEmpty(superGroupIds)) {
Project p = baseProjectMapper.selectOne();
if (p != null) {
switchSuperUserResource(p.getId(), p.getWorkspaceId(), user);
}
} else {
// 用户登录之后没有项目和工作空间的权限就把值清空
user.setLastWorkspaceId(StringUtils.EMPTY);
user.setLastProjectId(StringUtils.EMPTY);
updateUser(user);
}
}
} else {
UserGroup userGroup = project.stream().filter(p -> StringUtils.isNotBlank(p.getSourceId()))
.collect(Collectors.toList()).get(0);
@ -450,6 +484,8 @@ public class BaseUserService {
user.setLastWorkspaceId(project.getWorkspaceId());
updateUser(user);
return true;
} else {
return baseUserMapper.isSuperUser(user.getId());
}
}
return false;
@ -496,6 +532,8 @@ public class BaseUserService {
user.setLastWorkspaceId(wsId);
updateUser(user);
return true;
} else {
return baseUserMapper.isSuperUser(user.getId());
}
}
return false;
@ -739,4 +777,16 @@ public class BaseUserService {
user.setLastWorkspaceId(project.getWorkspaceId());
userMapper.updateByPrimaryKeySelective(user);
}
public boolean isSuperUser(String userid) {
if (StringUtils.isBlank(userid)) {
MSException.throwException("userid is blank.");
}
return baseUserMapper.isSuperUser(userid);
}
public List<String> getAllUserIds() {
List<User> users = userMapper.selectByExample(new UserExample());
return users.stream().map(User::getId).collect(Collectors.toList());
}
}

View File

@ -4,6 +4,7 @@ import io.metersphere.base.domain.Workspace;
import io.metersphere.base.domain.WorkspaceExample;
import io.metersphere.base.mapper.WorkspaceMapper;
import io.metersphere.base.mapper.ext.BaseUserGroupMapper;
import io.metersphere.base.mapper.ext.BaseUserMapper;
import io.metersphere.dto.RelatedSource;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
@ -19,8 +20,14 @@ public class BaseWorkspaceService {
private BaseUserGroupMapper baseUserGroupMapper;
@Resource
private WorkspaceMapper workspaceMapper;
@Resource
private BaseUserMapper baseUserMapper;
public List<Workspace> getWorkspaceListByUserId(String userId) {
boolean isSuper = baseUserMapper.isSuperUser(userId);
if (isSuper) {
return workspaceMapper.selectByExample(new WorkspaceExample());
}
List<RelatedSource> relatedSource = baseUserGroupMapper.getRelatedSource(userId);
List<String> wsIds = relatedSource
.stream()

View File

@ -5,32 +5,9 @@
<select id="getGroupList" resultType="io.metersphere.dto.GroupDTO">
SELECT *,
<if test="request.onlyQueryCurrentProject == true">
(SELECT COUNT(DISTINCT ug.user_id) FROM user_group ug JOIN user ON ug.user_id = user.id WHERE ug.group_id =
temp.id AND ug.source_id = #{request.projectId}) AS memberSize
</if>
<if test="request.onlyQueryCurrentProject == false">
(SELECT COUNT(DISTINCT ug.user_id) FROM user_group ug JOIN user ON ug.user_id = user.id WHERE ug.group_id =
temp.id) AS memberSize
</if>
FROM (
SELECT g.*, w.name AS scopeName FROM `group` g, workspace w
<where>
and g.scope_id = w.id
<if test="request.types != null and request.types.size() > 0">
AND g.type IN
<foreach collection="request.types" item="type" separator="," open="(" close=")">
#{type}
</foreach>
</if>
<if test="request.scopes != null and request.scopes.size() > 0">
AND g.scope_id IN
<foreach collection="request.scopes" item="scope" separator="," open="(" close=")">
#{scope}
</foreach>
</if>
</where>
UNION DISTINCT
SELECT g.*, 'global' AS scopeName FROM `group` g
<where>
g.scope_id = 'global'
@ -63,7 +40,7 @@
WHERE temp.name LIKE CONCAT('%', #{request.name},'%')
</if>
<if test="request.orders == null or request.orders.size() == 0">
ORDER BY field(temp.type, 'SYSTEM', 'ORGANIZATION', 'WORKSPACE', 'PROJECT'), temp.update_time, temp.name
ORDER BY field(temp.type, 'SYSTEM', 'WORKSPACE', 'PROJECT'), temp.update_time, temp.name
</if>
<if test="request.orders != null and request.orders.size() > 0">
ORDER BY

View File

@ -36,21 +36,12 @@ public class GroupController {
@Resource
private GroupService groupService;
@PostMapping("/get/{goPage}/{pageSize}")
@RequiresPermissions(value = {PermissionConstants.SYSTEM_GROUP_READ}, logical = Logical.OR)
public Pager<List<GroupDTO>> getGroupList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody EditGroupRequest request) {
request.setGoPage(goPage);
request.setPageSize(pageSize);
return groupService.getGroupList(request);
}
@PostMapping("/get/current/project/{goPage}/{pageSize}")
@RequiresPermissions(value = {PermissionConstants.PROJECT_GROUP_READ}, logical = Logical.OR)
public Pager<List<GroupDTO>> getCurrentProjectGroupList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody EditGroupRequest request) {
request.setOnlyQueryCurrentProject(true);
request.setGoPage(goPage);
request.setPageSize(pageSize);
return groupService.getGroupList(request);
return groupService.getProjectGroupList(request);
}
@GetMapping("/get/all")
@ -127,13 +118,6 @@ public class GroupController {
return groupService.getResource(type, id);
}
@PostMapping("/user/{goPage}/{pageSize}")
@RequiresPermissions(value = {PermissionConstants.SYSTEM_GROUP_READ}, logical = Logical.OR)
public Pager<List<User>> getGroupUser(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody EditGroupRequest editGroupRequest) {
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, groupService.getGroupUser(editGroupRequest));
}
@PostMapping("/current/project/user/{goPage}/{pageSize}")
@RequiresPermissions(value = {PermissionConstants.PROJECT_GROUP_READ}, logical = Logical.OR)
public Pager<List<User>> getCurrentProjectGroupUser(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody EditGroupRequest editGroupRequest) {

View File

@ -67,6 +67,8 @@ public class GroupService {
private UserMapper userMapper;
@Resource
private MicroService microService;
@Resource
private BaseUserService baseUserService;
private static final String GLOBAL = "global";
// 服务权限拼装顺序
@ -86,22 +88,27 @@ public class GroupService {
put(UserGroupType.PROJECT, "项目");
}};
public Pager<List<GroupDTO>> getGroupList(EditGroupRequest request) {
public Pager<List<GroupDTO>> getProjectGroupList(EditGroupRequest request) {
SessionUser user = SessionUtils.getUser();
List<UserGroupDTO> userGroup = baseUserGroupMapper.getUserGroup(Objects.requireNonNull(user).getId(), request.getProjectId());
List<String> groupTypeList = userGroup.stream().map(UserGroupDTO::getType).distinct().collect(Collectors.toList());
if (groupTypeList.isEmpty()) {
if (baseUserService.isSuperUser(user.getId())) {
groupTypeList.add(UserGroupType.PROJECT);
}
}
return getGroups(groupTypeList, request);
}
public void buildUserInfo(List<GroupDTO> testCases) {
if (CollectionUtils.isEmpty(testCases)) {
public void buildUserInfo(List<GroupDTO> groups) {
if (CollectionUtils.isEmpty(groups)) {
return;
}
List<String> userIds = testCases.stream().map(GroupDTO::getCreator).collect(Collectors.toList());
List<String> userIds = groups.stream().map(GroupDTO::getCreator).collect(Collectors.toList());
if (!userIds.isEmpty()) {
Map<String, String> userMap = ServiceUtils.getUserNameMap(userIds);
testCases.forEach(caseResult -> {
caseResult.setCreator(userMap.get(caseResult.getCreator()));
groups.forEach(caseResult -> {
caseResult.setCreator(userMap.getOrDefault(caseResult.getCreator(), caseResult.getCreator()));
});
}
}
@ -142,6 +149,9 @@ public class GroupService {
}
public void editGroup(EditGroupRequest request) {
if (StringUtils.equals(request.getId(), UserGroupConstants.SUPER_GROUP)) {
MSException.throwException("超级管理员无法编辑!");
}
if (StringUtils.equals(request.getId(), UserGroupConstants.ADMIN)) {
MSException.throwException("系统管理员无法编辑!");
}

View File

@ -5,14 +5,8 @@
<select id="getGroupList" resultType="io.metersphere.dto.GroupDTO">
SELECT *,
<if test="request.onlyQueryCurrentProject == true">
(SELECT COUNT(DISTINCT ug.user_id) FROM user_group ug JOIN user ON ug.user_id = user.id WHERE ug.group_id =
temp.id AND ug.source_id = #{request.projectId}) AS memberSize
</if>
<if test="request.onlyQueryCurrentProject == false">
(SELECT COUNT(DISTINCT ug.user_id) FROM user_group ug JOIN user ON ug.user_id = user.id WHERE ug.group_id =
temp.id) AS memberSize
</if>
FROM (
SELECT g.*, w.name AS scopeName FROM `group` g, workspace w
<where>
@ -41,6 +35,17 @@
</foreach>
</if>
</where>
UNION DISTINCT
SELECT g.*, 'system' AS scopeName FROM `group` g
<where>
g.scope_id = 'system'
<if test="request.types != null and request.types.size() > 0">
AND g.type IN
<foreach collection="request.types" item="type" separator="," open="(" close=")">
#{type}
</foreach>
</if>
</where>
union distinct
select g.*, p.name as scopeName from `group` g, project p
<where>
@ -63,7 +68,9 @@
WHERE temp.name LIKE CONCAT('%', #{request.name},'%')
</if>
<if test="request.orders == null or request.orders.size() == 0">
ORDER BY field(temp.type, 'SYSTEM', 'ORGANIZATION', 'WORKSPACE', 'PROJECT'), temp.update_time, temp.name
ORDER BY field(temp.type, 'SYSTEM', 'WORKSPACE', 'PROJECT'),
field(temp.scope_id, 'system') desc,
temp.update_time, temp.name
</if>
<if test="request.orders != null and request.orders.size() > 0">
ORDER BY

View File

@ -44,15 +44,6 @@ public class GroupController {
return groupService.getGroupList(request);
}
@PostMapping("/get/current/project/{goPage}/{pageSize}")
@RequiresPermissions(value = {PermissionConstants.PROJECT_GROUP_READ}, logical = Logical.OR)
public Pager<List<GroupDTO>> getCurrentProjectGroupList(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody EditGroupRequest request) {
request.setOnlyQueryCurrentProject(true);
request.setGoPage(goPage);
request.setPageSize(pageSize);
return groupService.getGroupList(request);
}
@GetMapping("/get/all")
public List<GroupDTO> getAllGroup() {
return groupService.getAllGroup();
@ -134,17 +125,6 @@ public class GroupController {
return PageUtils.setPageInfo(page, groupService.getGroupUser(editGroupRequest));
}
@PostMapping("/current/project/user/{goPage}/{pageSize}")
@RequiresPermissions(value = {PermissionConstants.PROJECT_GROUP_READ}, logical = Logical.OR)
public Pager<List<User>> getCurrentProjectGroupUser(@PathVariable int goPage, @PathVariable int pageSize, @RequestBody EditGroupRequest editGroupRequest) {
editGroupRequest.setOnlyQueryCurrentProject(true);
if (StringUtils.isBlank(editGroupRequest.getProjectId())) {
editGroupRequest.setProjectId(SessionUtils.getCurrentProjectId());
}
Page<Object> page = PageHelper.startPage(goPage, pageSize, true);
return PageUtils.setPageInfo(page, groupService.getGroupUser(editGroupRequest));
}
@GetMapping("/rm/{userId}/{groupId}")
public void removeGroupMember(@PathVariable String userId, @PathVariable String groupId) {
groupService.removeGroupMember(userId, groupId);

View File

@ -1,5 +1,6 @@
package io.metersphere.listener;
import io.metersphere.commons.utils.LogUtil;
import io.metersphere.service.PlatformPluginService;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
@ -15,6 +16,7 @@ public class InitListener implements ApplicationRunner {
@Override
public void run(ApplicationArguments applicationArguments) {
LogUtil.info("================= SYSTEM-SETTING 应用启动 =================");
platformPluginService.loadPlatFormPlugins();
}
}

View File

@ -68,11 +68,20 @@ public class GroupService {
private UserMapper userMapper;
private static final String GLOBAL = "global";
private static final String SUPER_GROUP = "super_group";
private static final String PERSONAL_PREFIX = "PERSONAL";
// 服务权限拼装顺序
private static final String[] servicePermissionLoadOrder = {MicroServiceName.PROJECT_MANAGEMENT,
MicroServiceName.TEST_TRACK, MicroServiceName.API_TEST, MicroServiceName.UI_TEST,
MicroServiceName.PERFORMANCE_TEST, MicroServiceName.REPORT_STAT, MicroServiceName.SYSTEM_SETTING};
private static final String[] servicePermissionLoadOrder = {
MicroServiceName.SYSTEM_SETTING,
MicroServiceName.PROJECT_MANAGEMENT,
MicroServiceName.TEST_TRACK,
MicroServiceName.API_TEST,
MicroServiceName.UI_TEST,
MicroServiceName.PERFORMANCE_TEST,
MicroServiceName.REPORT_STAT
};
private static final Map<String, List<String>> map = new HashMap<>(4) {{
put(UserGroupType.SYSTEM, Arrays.asList(UserGroupType.SYSTEM, UserGroupType.WORKSPACE, UserGroupType.PROJECT));
@ -93,14 +102,11 @@ public class GroupService {
return getGroups(groupTypeList, request);
}
public void buildUserInfo(List<GroupDTO> testCases) {
List<String> userIds = new ArrayList();
userIds.addAll(testCases.stream().map(GroupDTO::getCreator).collect(Collectors.toList()));
public void buildUserInfo(List<GroupDTO> groups) {
List<String> userIds = groups.stream().map(GroupDTO::getCreator).collect(Collectors.toList());
if (!userIds.isEmpty()) {
Map<String, String> userMap = ServiceUtils.getUserNameMap(userIds);
testCases.forEach(caseResult -> {
caseResult.setCreator(userMap.get(caseResult.getCreator()));
});
groups.forEach(caseResult -> caseResult.setCreator(userMap.getOrDefault(caseResult.getCreator(), caseResult.getCreator())));
}
}
@ -140,6 +146,9 @@ public class GroupService {
}
public void editGroup(EditGroupRequest request) {
if (StringUtils.equals(request.getId(), UserGroupConstants.SUPER_GROUP)) {
MSException.throwException("超级管理员无法编辑!");
}
if (StringUtils.equals(request.getId(), UserGroupConstants.ADMIN)) {
MSException.throwException("系统管理员无法编辑!");
}
@ -176,19 +185,22 @@ public class GroupService {
example.createCriteria().andGroupIdEqualTo(group.getId());
List<UserGroupPermission> groupPermissions = userGroupPermissionMapper.selectByExample(example);
List<String> groupPermissionIds = groupPermissions.stream().map(UserGroupPermission::getPermissionId).collect(Collectors.toList());
GroupJson groupJson = this.loadPermissionJsonFromService();
if (groupJson == null) {
MSException.throwException(Translator.get("read_permission_file_fail"));
}
List<GroupResource> resource = groupJson.getResource();
List<GroupPermission> permissions = groupJson.getPermissions();
List<GroupResourceDTO> dtoPermissions = dto.getPermissions();
dtoPermissions.addAll(getResourcePermission(resource, permissions, group.getType(), groupPermissionIds));
dtoPermissions.addAll(getResourcePermission(resource, permissions, group, groupPermissionIds));
return dto;
}
private GroupJson loadPermissionJsonFromService() {
GroupJson groupJson = null;
List<GroupResource> globalResource = new ArrayList<>();
try {
for (String service : servicePermissionLoadOrder) {
Object obj = stringRedisTemplate.opsForHash().get(RedisKey.MS_PERMISSION_KEY, service);
@ -199,11 +211,23 @@ public class GroupService {
GroupJson temp = JSON.parseObject((String) obj, GroupJson.class);
if (groupJson == null) {
groupJson = temp;
// 全局权限放系统设置模块
if (StringUtils.equals(service, MicroServiceName.SYSTEM_SETTING)) {
globalResource = temp.getResource()
.stream()
.filter(gp -> BooleanUtils.isTrue(gp.isGlobal()))
.collect(Collectors.toList());
temp.getResource().removeIf(gp -> BooleanUtils.isTrue(gp.isGlobal()));
}
} else {
groupJson.getResource().addAll(temp.getResource());
groupJson.getPermissions().addAll(temp.getPermissions());
}
}
// 拼装权限的时候放在最后
if (groupJson != null && !globalResource.isEmpty()) {
groupJson.getResource().addAll(globalResource);
}
} catch (Exception e) {
LogUtil.error(e);
}
@ -292,8 +316,7 @@ public class GroupService {
scopeList = Arrays.asList(GLOBAL, resourceId, request.getProjectId());
}
GroupExample groupExample = new GroupExample();
groupExample.createCriteria().andScopeIdIn(scopeList)
.andTypeEqualTo(type);
groupExample.createCriteria().andScopeIdIn(scopeList).andTypeEqualTo(type);
return groupMapper.selectByExample(groupExample);
}
@ -301,15 +324,23 @@ public class GroupService {
return baseUserGroupMapper.getWorkspaceMemberGroups(workspaceId, userId);
}
private List<GroupResourceDTO> getResourcePermission(List<GroupResource> resource, List<GroupPermission> permissions, String type, List<String> permissionList) {
private List<GroupResourceDTO> getResourcePermission(List<GroupResource> resources, List<GroupPermission> permissions, Group group, List<String> permissionList) {
List<GroupResourceDTO> dto = new ArrayList<>();
List<GroupResource> resources = resource.stream().filter(g -> g.getId().startsWith(type) || g.getId().startsWith("PERSONAL")).collect(Collectors.toList());
List<GroupResource> grs;
if (StringUtils.equals(group.getId(), SUPER_GROUP)) {
grs = resources;
} else {
grs = resources
.stream()
.filter(g -> g.getId().startsWith(group.getType()) || g.getId().startsWith(PERSONAL_PREFIX))
.collect(Collectors.toList());
}
permissions.forEach(p -> {
if (permissionList.contains(p.getId())) {
p.setChecked(true);
}
});
for (GroupResource r : resources) {
for (GroupResource r : grs) {
GroupResourceDTO resourceDTO = new GroupResourceDTO();
resourceDTO.setResource(r);
List<GroupPermission> collect = permissions
@ -453,9 +484,14 @@ public class GroupService {
UserGroupExample userGroupExample = new UserGroupExample();
userGroupExample.createCriteria().andUserIdEqualTo(userId).andGroupIdEqualTo(group.getId());
List<UserGroup> userGroups = userGroupMapper.selectByExample(userGroupExample);
if (userGroups.size() <= 0) {
UserGroup userGroup = new UserGroup(UUID.randomUUID().toString(), userId, group.getId(),
"system", System.currentTimeMillis(), System.currentTimeMillis());
if (userGroups.size() == 0) {
UserGroup userGroup = new UserGroup(
UUID.randomUUID().toString(),
userId,
group.getId(),
"system",
System.currentTimeMillis(),
System.currentTimeMillis());
userGroupMapper.insertSelective(userGroup);
}
}

View File

@ -195,14 +195,6 @@ public class SystemProjectService {
return baseProjectMapper.getProjectWithWorkspace(request);
}
public List<ProjectDTO> getUserProject(ProjectRequest request) {
if (StringUtils.isNotBlank(request.getName())) {
request.setName(StringUtils.wrapIfMissing(request.getName(), "%"));
}
request.setOrders(ServiceUtils.getDefaultOrder(request.getOrders()));
return baseProjectMapper.getUserProject(request);
}
public List<Project> getProjectByIds(List<String> ids) {
if (!CollectionUtils.isEmpty(ids)) {
ProjectExample example = new ProjectExample();

View File

@ -85,6 +85,8 @@ public class UserService {
private BaseProjectMapper baseProjectMapper;
@Resource
private BaseWorkspaceMapper baseWorkspaceMapper;
@Resource
private BaseUserService baseUserService;
public List<UserDetail> queryTypeByIds(List<String> userIds) {
return baseUserMapper.queryTypeByIds(userIds);
@ -412,20 +414,45 @@ public class UserService {
public void addMember(AddMemberRequest request) {
if (!CollectionUtils.isEmpty(request.getUserIds())) {
if (CollectionUtils.isEmpty(request.getUserIds())
|| CollectionUtils.isEmpty(request.getGroupIds())) {
LogUtil.warn("user ids or group ids is empty.");
return;
}
if (CollectionUtils.isNotEmpty(request.getUserIds())) {
QuotaService quotaService = CommonBeanFactory.getBean(QuotaService.class);
checkQuota(quotaService, "WORKSPACE", Collections.singletonList(request.getWorkspaceId()), request.getUserIds());
}
List<String> allUserIds = baseUserService.getAllUserIds();
GroupExample groupExample = new GroupExample();
groupExample.createCriteria().andTypeEqualTo(UserGroupType.WORKSPACE);
List<Group> wsGroups = groupMapper.selectByExample(groupExample);
List<String> wsGroupIds = wsGroups
.stream()
.map(Group::getId)
.collect(Collectors.toList());
for (String userId : request.getUserIds()) {
if (!allUserIds.contains(userId)) {
LogUtil.warn("user id {} is not exist!", userId);
continue;
}
UserGroupExample userGroupExample = new UserGroupExample();
userGroupExample.createCriteria().andUserIdEqualTo(userId).andSourceIdEqualTo(request.getWorkspaceId());
List<UserGroup> userGroups = userGroupMapper.selectByExample(userGroupExample);
if (userGroups.size() > 0) {
MSException.throwException(Translator.get("user_already_exists"));
} else {
}
for (String groupId : request.getGroupIds()) {
if (!wsGroupIds.contains(groupId)) {
LogUtil.warn("group id {} is not exist or not belong to workspace level.", groupId);
continue;
}
UserGroup userGroup = new UserGroup();
userGroup.setGroupId(groupId);
userGroup.setSourceId(request.getWorkspaceId());
@ -437,8 +464,6 @@ public class UserService {
}
}
}
}
}
public void deleteMember(String workspaceId, String userId) {
GroupExample groupExample = new GroupExample();
@ -1240,7 +1265,7 @@ public class UserService {
private void addGroupMember(String type, String sourceId, List<String> userIds, List<String> groupIds) {
if (!StringUtils.equalsAny(type, "PROJECT", "WORKSPACE") || StringUtils.isBlank(sourceId)
|| CollectionUtils.isEmpty(userIds) || CollectionUtils.isEmpty(groupIds)) {
LogUtil.info("add member warning, please check param!");
LogUtil.warn("add member warning, please check param!");
return;
}
this.checkQuotaOfMemberSize(type, sourceId, userIds);
@ -1248,7 +1273,7 @@ public class UserService {
for (String userId : userIds) {
User user = userMapper.selectByPrimaryKey(userId);
if (user == null) {
LogUtil.info("add member warning, invalid user id: " + userId);
LogUtil.warn("add member warning, invalid user id: " + userId);
continue;
}
List<String> toAddGroupIds = new ArrayList<>(groupIds);
@ -1260,8 +1285,13 @@ public class UserService {
continue;
}
for (String groupId : toAddGroupIds) {
UserGroup userGroup = new UserGroup(UUID.randomUUID().toString(), userId, groupId,
sourceId, System.currentTimeMillis(), System.currentTimeMillis());
UserGroup userGroup = new UserGroup(
UUID.randomUUID().toString(),
userId,
groupId,
sourceId,
System.currentTimeMillis(),
System.currentTimeMillis());
userGroupMapper.insertSelective(userGroup);
}
}

View File

@ -347,6 +347,10 @@
"id": "SYSTEM_OPERATING_LOG",
"name": "permission.system_operation_log.name"
},
{
"id": "SYSTEM_PLUGIN",
"name": "permission.system_plugin.name"
},
{
"id": "WORKSPACE_USER",
"name": "permission.workspace_user.name"
@ -372,13 +376,10 @@
"id": "WORKSPACE_OPERATING_LOG",
"name": "permission.workspace_operation_log.name"
},
{
"id": "SYSTEM_PLUGIN",
"name": "permission.system_plugin.name"
},
{
"id": "PERSONAL_INFORMATION",
"name": "permission.personal_information.name"
"name": "permission.personal_information.name",
"global": true
}
]
}

View File

@ -99,7 +99,7 @@ export default {
},
isReadOnly() {
return function (data) {
const isDefaultSystemGroup = this.group.id === 'admin' && data.resource.id === 'SYSTEM_GROUP';
const isDefaultSystemGroup = (this.group.id === 'admin' || this.group.id === 'super_group') && data.resource.id === 'SYSTEM_GROUP';
return this.readOnly || isDefaultSystemGroup;
}
}
@ -143,8 +143,13 @@ export default {
},
_getUniteMenu() {
let menu = ['TRACK', 'API', 'UI', 'PERFORMANCE', 'REPORT'];
// PROJECT_USER
let isFirstProjectType = false;
for (let i = 0; i < this.tableData.length; i++) {
if (i === 0) {
if (this.tableData[i].type === GROUP_TYPE.PROJECT) {
isFirstProjectType = true;
}
this.spanArr.push(1);
this.pos = 0
} else {
@ -153,8 +158,13 @@ export default {
if (this.tableData[i].type !== GROUP_TYPE.PROJECT) {
sign = this.tableData[i].type === this.tableData[i - 1].type;
} else {
sign = !menu.includes(this.tableData[i].resource.id.split('_')[1]) ?
true : this.tableData[i].resource.id.split('_')[1] === this.tableData[i - 1].resource.id.split('_')[1]
let hasSubModule = menu.includes(this.tableData[i].resource.id.split('_')[1]);
if (hasSubModule) {
sign = this.tableData[i].resource.id.split('_')[1] === this.tableData[i - 1].resource.id.split('_')[1];
} else {
sign = isFirstProjectType;
isFirstProjectType = true;
}
}
if (sign) {
this.spanArr[this.pos] += 1;

View File

@ -47,7 +47,7 @@ export default {
return function (permission) {
//
const isSystemGroupPermission = permission.id === 'SYSTEM_GROUP:READ' || permission.id === 'SYSTEM_GROUP:READ+SETTING_PERMISSION';
const isDefaultSystemGroup = this.group.id === 'admin' && isSystemGroupPermission;
const isDefaultSystemGroup = (this.group.id === 'admin' || this.group.id === 'super_group') && isSystemGroupPermission;
return this.readOnly || isDefaultSystemGroup;
}
}

View File

@ -28,6 +28,7 @@
<el-table-column prop="scopeName" :label="$t('group.scope')">
<template v-slot="scope">
<span v-if="scope.row.scopeId ==='global'">{{ $t('group.global') }}</span>
<span v-else-if="scope.row.scopeId ==='system'">{{ $t('group.system') }}</span>
<span v-else>{{ scope.row.scopeName }}</span>
</template>
</el-table-column>
@ -42,10 +43,22 @@
</template>
</el-table-column>
<el-table-column prop="creator" :label="$t('group.operator')"/>
<el-table-column prop="description" :label="$t('group.description')"/>
<el-table-column prop="description" :label="$t('group.description')" show-overflow-tooltip/>
<el-table-column :label="$t('commons.operating')" min-width="120">
<template v-slot:default="scope">
<div>
<template v-slot="scope">
<div v-if="scope.row.id === 'super_group'">
<ms-table-operator
:is-show="true"
@editClick="edit(scope.row)" @deleteClick="del(scope.row)">
<template v-slot:middle>
<ms-table-operator-button
v-permission="['SYSTEM_GROUP:READ+SETTING_PERMISSION']"
:tip="$t('group.set_permission')" icon="el-icon-s-tools"
@exec="setPermission(scope.row)"/>
</template>
</ms-table-operator>
</div>
<div v-else>
<ms-table-operator
:edit-permission="['SYSTEM_GROUP:READ+EDIT']"
:delete-permission="['SYSTEM_GROUP:READ+DELETE']"

View File

@ -360,6 +360,9 @@ export default {
let data = res.data;
if (data) {
this._setResource(data, index, type);
if (id === 'super_group') {
return;
}
if (isHaveWorkspace === false) {
this.addWorkspaceGroup(id, index);
}