feat(系统设置): 组织管理和项目管理提供邮箱邀请注册的后台接口

This commit is contained in:
Jianguo-Genius 2024-07-05 15:26:25 +08:00 committed by 刘瑞斌
parent 8ecc9185ac
commit e1c24fa53f
22 changed files with 344 additions and 34 deletions

View File

@ -1,16 +1,12 @@
package io.metersphere.system.domain;
import io.metersphere.validation.groups.Created;
import io.metersphere.validation.groups.Updated;
import io.metersphere.validation.groups.*;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;
import jakarta.validation.constraints.*;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import lombok.Data;
@Data
public class UserInvite implements Serializable {
@ -33,6 +29,12 @@ public class UserInvite implements Serializable {
@NotNull(message = "{user_invite.invite_time.not_blank}", groups = {Created.class})
private Long inviteTime;
@Schema(description = "组织ID")
private String organizationId;
@Schema(description = "项目ID")
private String projectId;
@Schema(description = "所属权限")
private String roles;
@ -43,6 +45,8 @@ public class UserInvite implements Serializable {
email("email", "email", "VARCHAR", false),
inviteUser("invite_user", "inviteUser", "VARCHAR", false),
inviteTime("invite_time", "inviteTime", "BIGINT", false),
organizationId("organization_id", "organizationId", "VARCHAR", false),
projectId("project_id", "projectId", "VARCHAR", false),
roles("roles", "roles", "LONGVARCHAR", false);
private static final String BEGINNING_DELIMITER = "`";

View File

@ -373,6 +373,146 @@ public class UserInviteExample {
addCriterion("invite_time not between", value1, value2, "inviteTime");
return (Criteria) this;
}
public Criteria andOrganizationIdIsNull() {
addCriterion("organization_id is null");
return (Criteria) this;
}
public Criteria andOrganizationIdIsNotNull() {
addCriterion("organization_id is not null");
return (Criteria) this;
}
public Criteria andOrganizationIdEqualTo(String value) {
addCriterion("organization_id =", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdNotEqualTo(String value) {
addCriterion("organization_id <>", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdGreaterThan(String value) {
addCriterion("organization_id >", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdGreaterThanOrEqualTo(String value) {
addCriterion("organization_id >=", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdLessThan(String value) {
addCriterion("organization_id <", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdLessThanOrEqualTo(String value) {
addCriterion("organization_id <=", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdLike(String value) {
addCriterion("organization_id like", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdNotLike(String value) {
addCriterion("organization_id not like", value, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdIn(List<String> values) {
addCriterion("organization_id in", values, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdNotIn(List<String> values) {
addCriterion("organization_id not in", values, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdBetween(String value1, String value2) {
addCriterion("organization_id between", value1, value2, "organizationId");
return (Criteria) this;
}
public Criteria andOrganizationIdNotBetween(String value1, String value2) {
addCriterion("organization_id not between", value1, value2, "organizationId");
return (Criteria) this;
}
public Criteria andProjectIdIsNull() {
addCriterion("project_id is null");
return (Criteria) this;
}
public Criteria andProjectIdIsNotNull() {
addCriterion("project_id is not null");
return (Criteria) this;
}
public Criteria andProjectIdEqualTo(String value) {
addCriterion("project_id =", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotEqualTo(String value) {
addCriterion("project_id <>", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdGreaterThan(String value) {
addCriterion("project_id >", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdGreaterThanOrEqualTo(String value) {
addCriterion("project_id >=", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLessThan(String value) {
addCriterion("project_id <", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLessThanOrEqualTo(String value) {
addCriterion("project_id <=", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdLike(String value) {
addCriterion("project_id like", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotLike(String value) {
addCriterion("project_id not like", value, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdIn(List<String> values) {
addCriterion("project_id in", values, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotIn(List<String> values) {
addCriterion("project_id not in", values, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdBetween(String value1, String value2) {
addCriterion("project_id between", value1, value2, "projectId");
return (Criteria) this;
}
public Criteria andProjectIdNotBetween(String value1, String value2) {
addCriterion("project_id not between", value1, value2, "projectId");
return (Criteria) this;
}
}
public static class Criteria extends GeneratedCriteria {

View File

@ -6,6 +6,8 @@
<result column="email" jdbcType="VARCHAR" property="email" />
<result column="invite_user" jdbcType="VARCHAR" property="inviteUser" />
<result column="invite_time" jdbcType="BIGINT" property="inviteTime" />
<result column="organization_id" jdbcType="VARCHAR" property="organizationId" />
<result column="project_id" jdbcType="VARCHAR" property="projectId" />
</resultMap>
<resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="io.metersphere.system.domain.UserInvite">
<result column="roles" jdbcType="LONGVARCHAR" property="roles" />
@ -69,7 +71,7 @@
</where>
</sql>
<sql id="Base_Column_List">
id, email, invite_user, invite_time
id, email, invite_user, invite_time, organization_id, project_id
</sql>
<sql id="Blob_Column_List">
roles
@ -124,9 +126,11 @@
</delete>
<insert id="insert" parameterType="io.metersphere.system.domain.UserInvite">
insert into user_invite (id, email, invite_user,
invite_time, roles)
invite_time, organization_id, project_id,
roles)
values (#{id,jdbcType=VARCHAR}, #{email,jdbcType=VARCHAR}, #{inviteUser,jdbcType=VARCHAR},
#{inviteTime,jdbcType=BIGINT}, #{roles,jdbcType=LONGVARCHAR})
#{inviteTime,jdbcType=BIGINT}, #{organizationId,jdbcType=VARCHAR}, #{projectId,jdbcType=VARCHAR},
#{roles,jdbcType=LONGVARCHAR})
</insert>
<insert id="insertSelective" parameterType="io.metersphere.system.domain.UserInvite">
insert into user_invite
@ -143,6 +147,12 @@
<if test="inviteTime != null">
invite_time,
</if>
<if test="organizationId != null">
organization_id,
</if>
<if test="projectId != null">
project_id,
</if>
<if test="roles != null">
roles,
</if>
@ -160,6 +170,12 @@
<if test="inviteTime != null">
#{inviteTime,jdbcType=BIGINT},
</if>
<if test="organizationId != null">
#{organizationId,jdbcType=VARCHAR},
</if>
<if test="projectId != null">
#{projectId,jdbcType=VARCHAR},
</if>
<if test="roles != null">
#{roles,jdbcType=LONGVARCHAR},
</if>
@ -186,6 +202,12 @@
<if test="record.inviteTime != null">
invite_time = #{record.inviteTime,jdbcType=BIGINT},
</if>
<if test="record.organizationId != null">
organization_id = #{record.organizationId,jdbcType=VARCHAR},
</if>
<if test="record.projectId != null">
project_id = #{record.projectId,jdbcType=VARCHAR},
</if>
<if test="record.roles != null">
roles = #{record.roles,jdbcType=LONGVARCHAR},
</if>
@ -200,6 +222,8 @@
email = #{record.email,jdbcType=VARCHAR},
invite_user = #{record.inviteUser,jdbcType=VARCHAR},
invite_time = #{record.inviteTime,jdbcType=BIGINT},
organization_id = #{record.organizationId,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR},
roles = #{record.roles,jdbcType=LONGVARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
@ -210,7 +234,9 @@
set id = #{record.id,jdbcType=VARCHAR},
email = #{record.email,jdbcType=VARCHAR},
invite_user = #{record.inviteUser,jdbcType=VARCHAR},
invite_time = #{record.inviteTime,jdbcType=BIGINT}
invite_time = #{record.inviteTime,jdbcType=BIGINT},
organization_id = #{record.organizationId,jdbcType=VARCHAR},
project_id = #{record.projectId,jdbcType=VARCHAR}
<if test="_parameter != null">
<include refid="Update_By_Example_Where_Clause" />
</if>
@ -227,6 +253,12 @@
<if test="inviteTime != null">
invite_time = #{inviteTime,jdbcType=BIGINT},
</if>
<if test="organizationId != null">
organization_id = #{organizationId,jdbcType=VARCHAR},
</if>
<if test="projectId != null">
project_id = #{projectId,jdbcType=VARCHAR},
</if>
<if test="roles != null">
roles = #{roles,jdbcType=LONGVARCHAR},
</if>
@ -238,6 +270,8 @@
set email = #{email,jdbcType=VARCHAR},
invite_user = #{inviteUser,jdbcType=VARCHAR},
invite_time = #{inviteTime,jdbcType=BIGINT},
organization_id = #{organizationId,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR},
roles = #{roles,jdbcType=LONGVARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
@ -245,16 +279,19 @@
update user_invite
set email = #{email,jdbcType=VARCHAR},
invite_user = #{inviteUser,jdbcType=VARCHAR},
invite_time = #{inviteTime,jdbcType=BIGINT}
invite_time = #{inviteTime,jdbcType=BIGINT},
organization_id = #{organizationId,jdbcType=VARCHAR},
project_id = #{projectId,jdbcType=VARCHAR}
where id = #{id,jdbcType=VARCHAR}
</update>
<insert id="batchInsert" parameterType="map">
insert into user_invite
(id, email, invite_user, invite_time, roles)
(id, email, invite_user, invite_time, organization_id, project_id, roles)
values
<foreach collection="list" item="item" separator=",">
(#{item.id,jdbcType=VARCHAR}, #{item.email,jdbcType=VARCHAR}, #{item.inviteUser,jdbcType=VARCHAR},
#{item.inviteTime,jdbcType=BIGINT}, #{item.roles,jdbcType=LONGVARCHAR})
#{item.inviteTime,jdbcType=BIGINT}, #{item.organizationId,jdbcType=VARCHAR}, #{item.projectId,jdbcType=VARCHAR},
#{item.roles,jdbcType=LONGVARCHAR})
</foreach>
</insert>
<insert id="batchInsertSelective" parameterType="map">
@ -279,6 +316,12 @@
<if test="'invite_time'.toString() == column.value">
#{item.inviteTime,jdbcType=BIGINT}
</if>
<if test="'organization_id'.toString() == column.value">
#{item.organizationId,jdbcType=VARCHAR}
</if>
<if test="'project_id'.toString() == column.value">
#{item.projectId,jdbcType=VARCHAR}
</if>
<if test="'roles'.toString() == column.value">
#{item.roles,jdbcType=LONGVARCHAR}
</if>

View File

@ -5,6 +5,10 @@ DROP TABLE IF EXISTS functional_mind_insert_relation;
-- 报告添加默认布局字段
ALTER TABLE test_plan_report ADD `default_layout` BIT NOT NULL DEFAULT 1 COMMENT '是否默认布局';
-- 邮箱邀请表增加字段
ALTER TABLE user_invite
ADD COLUMN organization_id VARCHAR(50) COMMENT '组织ID',
ADD COLUMN project_id VARCHAR(50) COMMENT '项目ID';
CREATE TABLE IF NOT EXISTS test_plan_report_component(
`id` VARCHAR(50) NOT NULL COMMENT 'ID' ,

View File

@ -52,5 +52,9 @@ UPDATE test_plan
SET status = 'NOT_ARCHIVED'
WHERE status != 'ARCHIVED';
-- 组织管理员、项目管理员增加权限
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'org_admin', 'ORGANIZATION_MEMBER:READ+INVITE');
INSERT INTO user_role_permission (id, role_id, permission_id) VALUES (UUID_SHORT(), 'project_admin', 'PROJECT_USER:READ+INVITE');
-- set innodb lock wait timeout to default
SET SESSION innodb_lock_wait_timeout = DEFAULT;

View File

@ -0,0 +1,10 @@
package io.metersphere.sdk.constants;
/**
* 邮箱邀请来源
*/
public enum EmailInviteSource {
SYSTEM,
ORGANIZATION,
PROJECT
}

View File

@ -32,6 +32,7 @@ public class PermissionConstants {
/*------ start: ORGANIZATION_MEMBER ------*/
public static final String ORGANIZATION_MEMBER_READ = "ORGANIZATION_MEMBER:READ";
public static final String ORGANIZATION_MEMBER_ADD = "ORGANIZATION_MEMBER:READ+ADD";
public static final String ORGANIZATION_MEMBER_INVITE = "ORGANIZATION_MEMBER:READ+INVITE";
public static final String ORGANIZATION_MEMBER_UPDATE = "ORGANIZATION_MEMBER:READ+UPDATE";
public static final String ORGANIZATION_MEMBER_DELETE = "ORGANIZATION_MEMBER:READ+DELETE";
/*------ end: ORGANIZATION_MEMBER ------*/
@ -106,6 +107,7 @@ public class PermissionConstants {
/*------ start: PROJECT_USER ------*/
public static final String PROJECT_USER_READ = "PROJECT_USER:READ";
public static final String PROJECT_USER_ADD = "PROJECT_USER:READ+ADD";
public static final String PROJECT_USER_INVITE = "PROJECT_USER:READ+INVITE";
public static final String PROJECT_USER_UPDATE = "PROJECT_USER:READ+UPDATE";
public static final String PROJECT_USER_DELETE = "PROJECT_USER:READ+DELETE";
/*------ end: PROJECT_MEMBER ------*/

View File

@ -263,6 +263,7 @@ permission.my_settings=我的设置
permission.api_key=APIKEY
permission.organization_project.recover=撤销删除
permission.organization_member.add=添加
permission.organization_member.invite=邀请
permission.organization_member.update=编辑
permission.organization_member.delete=移除
# template

View File

@ -277,6 +277,7 @@ permission.my_settings_personal_info=Personal information
permission.api_key=APIKEY
permission.organization_project.recover=Recover
permission.organization_member.add=Add
permission.organization_member.invite=Invite
permission.organization_member.update=Update
permission.organization_member.delete=Remove
# 状态流

View File

@ -265,6 +265,7 @@ permission.api_key=APIKEY
permission.my_settings_personal_info=个人信息
permission.organization_project.recover=撤销删除
permission.organization_member.add=添加
permission.organization_member.invite=邀请
permission.organization_member.update=编辑
permission.organization_member.delete=移除
# template

View File

@ -264,6 +264,7 @@ permission.api_key=APIKEY
permission.my_settings_personal_info=個人信息
permission.organization_project.recover=撤銷刪除
permission.organization_member.add=添加
permission.organization_member.invite=邀請
permission.organization_member.update=編輯
permission.organization_member.delete=移除
# template

View File

@ -5,11 +5,15 @@ import com.github.pagehelper.PageHelper;
import io.metersphere.project.dto.ProjectUserDTO;
import io.metersphere.project.request.*;
import io.metersphere.project.service.ProjectMemberService;
import io.metersphere.sdk.constants.EmailInviteSource;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.dto.CommentUserInfo;
import io.metersphere.system.dto.request.UserInviteRequest;
import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.dto.user.UserExtendDTO;
import io.metersphere.system.dto.user.response.UserInviteResponse;
import io.metersphere.system.security.CheckOwner;
import io.metersphere.system.service.SimpleUserService;
import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager;
import io.metersphere.system.utils.SessionUtils;
@ -35,6 +39,8 @@ public class ProjectMemberController {
@Resource
private ProjectMemberService projectMemberService;
@Resource
private SimpleUserService simpleUserService;
@PostMapping("/list")
@Operation(summary = "项目管理-成员-列表查询")
@ -71,6 +77,13 @@ public class ProjectMemberController {
projectMemberService.addMember(request, SessionUtils.getUserId());
}
@PostMapping("/invite")
@Operation(summary = "系统设置-组织-成员-邀请用户注册")
@RequiresPermissions(PermissionConstants.PROJECT_USER_INVITE)
public UserInviteResponse invite(@Validated @RequestBody UserInviteRequest request) {
return simpleUserService.saveInviteRecord(request, EmailInviteSource.PROJECT.name(), SessionUtils.getUser());
}
@PostMapping("/update")
@Operation(summary = "项目管理-成员-编辑成员")
@RequiresPermissions(PermissionConstants.PROJECT_USER_UPDATE)

View File

@ -26,6 +26,9 @@
{
"id": "PROJECT_USER:READ+ADD"
},
{
"id": "PROJECT_USER:READ+INVITE"
},
{
"id": "PROJECT_USER:READ+UPDATE"
},

View File

@ -7,6 +7,7 @@ import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.dto.request.UserInviteRequest;
import io.metersphere.system.utils.Pager;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.*;
@ -20,6 +21,8 @@ import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
@ -34,6 +37,7 @@ public class ProjectMemberControllerTests extends BaseTest {
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 INVITE = "/project/member/invite";
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";
@ -132,6 +136,18 @@ public class ProjectMemberControllerTests extends BaseTest {
// 权限校验
request.setProjectId(DEFAULT_PROJECT_ID);
requestPostPermissionTest(PermissionConstants.PROJECT_USER_ADD, ADD_MEMBER, request);
//顺便测试邀请
UserInviteRequest userInviteRequest = new UserInviteRequest();
userInviteRequest.setInviteEmails(new ArrayList<>(Collections.singletonList("abcde12345@qq.com")));
userInviteRequest.setUserRoleIds(request.getRoleIds());
userInviteRequest.setProjectId("default-project-member-test");
this.requestPost(INVITE, userInviteRequest);
userInviteRequest.setProjectId("NOT_EXIST_PROJECT_ID_BY_SOMEBODY_J");
this.requestPost(INVITE, userInviteRequest);
// 权限校验
userInviteRequest.setProjectId(DEFAULT_PROJECT_ID);
requestPostPermissionTest(PermissionConstants.PROJECT_USER_INVITE, INVITE, userInviteRequest);
}
@Test

View File

@ -2,17 +2,17 @@ package io.metersphere.system.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.sdk.constants.EmailInviteSource;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.system.dto.OptionDisabledDTO;
import io.metersphere.system.dto.OrgUserExtend;
import io.metersphere.system.dto.request.OrgMemberExtendProjectRequest;
import io.metersphere.system.dto.request.OrganizationMemberExtendRequest;
import io.metersphere.system.dto.request.OrganizationMemberUpdateRequest;
import io.metersphere.system.dto.request.OrganizationRequest;
import io.metersphere.system.dto.request.*;
import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.dto.user.response.UserInviteResponse;
import io.metersphere.system.log.annotation.Log;
import io.metersphere.system.log.constants.OperationLogType;
import io.metersphere.system.service.OrganizationService;
import io.metersphere.system.service.SimpleUserService;
import io.metersphere.system.utils.PageUtils;
import io.metersphere.system.utils.Pager;
import io.metersphere.system.utils.SessionUtils;
@ -39,6 +39,8 @@ public class OrganizationController {
@Resource
private OrganizationService organizationService;
@Resource
private SimpleUserService simpleUserService;
@PostMapping("/member/list")
@Operation(summary = "系统设置-组织-成员-获取组织成员列表")
@ -55,6 +57,13 @@ public class OrganizationController {
organizationService.addMemberByOrg(organizationMemberExtendRequest, SessionUtils.getUserId());
}
@PostMapping("/user/invite")
@Operation(summary = "系统设置-组织-成员-邀请用户注册")
@RequiresPermissions(PermissionConstants.ORGANIZATION_MEMBER_INVITE)
public UserInviteResponse invite(@Validated @RequestBody UserInviteRequest request) {
return simpleUserService.saveInviteRecord(request, EmailInviteSource.ORGANIZATION.name(), SessionUtils.getUser());
}
@PostMapping("/role/update-member")
@Operation(summary = "系统设置-组织-成员-添加组织成员至用户组")
@RequiresPermissions(PermissionConstants.ORGANIZATION_MEMBER_UPDATE)

View File

@ -4,6 +4,7 @@ package io.metersphere.system.controller;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import io.metersphere.project.domain.Project;
import io.metersphere.sdk.constants.EmailInviteSource;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.UserSource;
import io.metersphere.system.domain.Organization;
@ -186,7 +187,7 @@ public class UserController {
@Operation(summary = "系统设置-系统-用户-邀请用户注册")
@RequiresPermissions(PermissionConstants.SYSTEM_USER_INVITE)
public UserInviteResponse invite(@Validated @RequestBody UserInviteRequest request) {
return simpleUserService.saveInviteRecord(request, SessionUtils.getUser());
return simpleUserService.saveInviteRecord(request, EmailInviteSource.SYSTEM.name(), SessionUtils.getUser());
}
@GetMapping("/check-invite/{inviteId}")

View File

@ -24,4 +24,16 @@ public class UserInviteRequest {
@Schema(description = "邀请用户所属用户组", requiredMode = Schema.RequiredMode.REQUIRED)
@NotEmpty(message = "{user_role.id.not_blank}")
List<@Valid @NotBlank(message = "{user_role.id.not_blank}") String> userRoleIds;
/**
* 组织ID
*/
@Schema(description = "组织ID", requiredMode = Schema.RequiredMode.REQUIRED)
private String organizationId;
/**
* 组织ID
*/
@Schema(description = "项目ID", requiredMode = Schema.RequiredMode.REQUIRED)
private String projectId;
}

View File

@ -877,7 +877,7 @@ public class OrganizationService {
*
* @param organizationId 组织ID
*/
private void checkOrgExistById(String organizationId) {
public void checkOrgExistById(String organizationId) {
Organization organization = organizationMapper.selectByPrimaryKey(organizationId);
if (organization == null) {
throw new MSException(Translator.get("organization_not_exist"));
@ -891,7 +891,7 @@ public class OrganizationService {
* @param organizationId 组织ID
* @return 用户组集合
*/
private Map<String, UserRole> checkUseRoleExist(List<String> userRoleIds, String organizationId) {
public Map<String, UserRole> checkUseRoleExist(List<String> userRoleIds, String organizationId) {
UserRoleExample userRoleExample = new UserRoleExample();
List<String> scopeIds = Arrays.asList(UserRoleEnum.GLOBAL.toString(), organizationId);
userRoleExample.createCriteria().andIdIn(userRoleIds).andTypeEqualTo(UserRoleType.ORGANIZATION.toString()).andScopeIdIn(scopeIds);

View File

@ -1,6 +1,9 @@
package io.metersphere.system.service;
import com.alibaba.excel.EasyExcelFactory;
import io.metersphere.project.domain.Project;
import io.metersphere.project.mapper.ProjectMapper;
import io.metersphere.sdk.constants.EmailInviteSource;
import io.metersphere.sdk.constants.ParamConstants;
import io.metersphere.sdk.exception.MSException;
import io.metersphere.sdk.util.*;
@ -424,15 +427,36 @@ public class SimpleUserService {
MailNoticeSender mailNoticeSender;
@Resource
private SystemParameterMapper systemParameterMapper;
@Resource
private ProjectMapper projectMapper;
public UserInviteResponse saveInviteRecord(UserInviteRequest request, SessionUser inviteUser) {
globalUserRoleService.checkRoleIsGlobalAndHaveMember(request.getUserRoleIds(), true);
//校验邮箱和角色的合法性
Map<String, String> errorMap = this.validateUserInfo(request.getInviteEmails());
if (MapUtils.isNotEmpty(errorMap)) {
throw new MSException(SystemResultCode.INVITE_EMAIL_EXIST, JSON.toJSONString(errorMap.keySet()));
public UserInviteResponse saveInviteRecord(UserInviteRequest request, String inviteSource, SessionUser inviteUser) {
if (StringUtils.equals(inviteSource, EmailInviteSource.SYSTEM.name())) {
globalUserRoleService.checkRoleIsGlobalAndHaveMember(request.getUserRoleIds(), true);
//校验邮箱和角色的合法性
Map<String, String> errorMap = this.validateUserInfo(request.getInviteEmails());
if (MapUtils.isNotEmpty(errorMap)) {
throw new MSException(SystemResultCode.INVITE_EMAIL_EXIST, JSON.toJSONString(errorMap.keySet()));
}
request.setOrganizationId(EmailInviteSource.SYSTEM.name());
request.setProjectId(EmailInviteSource.SYSTEM.name());
} else if (StringUtils.equals(inviteSource, EmailInviteSource.ORGANIZATION.name())) {
OrganizationService organizationService = CommonBeanFactory.getBean(OrganizationService.class);
organizationService.checkOrgExistById(request.getOrganizationId());
organizationService.checkUseRoleExist(request.getUserRoleIds(), request.getOrganizationId());
request.setProjectId(EmailInviteSource.SYSTEM.name());
} else if (StringUtils.equals(inviteSource, EmailInviteSource.PROJECT.name())) {
// 项目不存在, 则不添加
Project project = projectMapper.selectByPrimaryKey(request.getProjectId());
if (project == null) {
throw new MSException(Translator.get("project_not_exist"));
}
request.setOrganizationId(project.getOrganizationId());
}
List<UserInvite> inviteList = userInviteService.batchInsert(request.getInviteEmails(), inviteUser.getId(), request.getUserRoleIds());
List<UserInvite> inviteList = userInviteService.batchInsert(
request.getInviteEmails(), inviteUser.getId(), request.getUserRoleIds(), request.getOrganizationId(), request.getProjectId());
//记录日志
userLogService.addEmailInviteLog(inviteList, inviteUser.getId());
this.sendInviteEmail(inviteList, inviteUser.getName());

View File

@ -1,11 +1,11 @@
package io.metersphere.system.service;
import io.metersphere.system.uid.IDGenerator;
import io.metersphere.sdk.util.JSON;
import io.metersphere.sdk.util.Translator;
import io.metersphere.system.domain.UserInvite;
import io.metersphere.system.domain.UserInviteExample;
import io.metersphere.system.mapper.UserInviteMapper;
import io.metersphere.system.uid.IDGenerator;
import jakarta.annotation.Resource;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.stereotype.Service;
@ -28,7 +28,7 @@ public class UserInviteService {
userInviteMapper.deleteByExample(example);
}
public List<UserInvite> batchInsert(List<String> inviteEmails, String inviteUser, List<String> userRoleIds) {
public List<UserInvite> batchInsert(List<String> inviteEmails, String inviteUser, List<String> userRoleIds, String orgId, String projectId) {
long inviteTime = System.currentTimeMillis();
List<UserInvite> inviteList = new ArrayList<>();
for (String email : inviteEmails) {
@ -38,6 +38,8 @@ public class UserInviteService {
userInvite.setInviteUser(inviteUser);
userInvite.setInviteTime(inviteTime);
userInvite.setId(IDGenerator.nextStr());
userInvite.setOrganizationId(orgId);
userInvite.setProjectId(projectId);
inviteList.add(userInvite);
}
userInviteMapper.batchInsert(inviteList);

View File

@ -246,6 +246,10 @@
"id": "ORGANIZATION_MEMBER:READ+ADD",
"name": "permission.organization_member.add"
},
{
"id": "ORGANIZATION_MEMBER:READ+INVITE",
"name": "permission.organization_member.invite"
},
{
"id": "ORGANIZATION_MEMBER:READ+UPDATE",
"name": "permission.organization_member.update"

View File

@ -1,15 +1,13 @@
package io.metersphere.system.controller;
import io.metersphere.sdk.constants.InternalUserRole;
import io.metersphere.sdk.constants.PermissionConstants;
import io.metersphere.sdk.constants.SessionConstants;
import io.metersphere.sdk.util.JSON;
import io.metersphere.system.base.BaseTest;
import io.metersphere.system.controller.handler.ResultHolder;
import io.metersphere.system.dto.OrgUserExtend;
import io.metersphere.system.dto.request.OrgMemberExtendProjectRequest;
import io.metersphere.system.dto.request.OrganizationMemberExtendRequest;
import io.metersphere.system.dto.request.OrganizationMemberUpdateRequest;
import io.metersphere.system.dto.request.OrganizationRequest;
import io.metersphere.system.dto.request.*;
import io.metersphere.system.dto.sdk.OptionDTO;
import io.metersphere.system.utils.Pager;
import jakarta.annotation.Resource;
@ -27,6 +25,7 @@ import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
@ -44,6 +43,7 @@ public class OrganizationControllerTests extends BaseTest {
public static final String ORGANIZATION_LIST_ADD_MEMBER = "/organization/add-member";
public static final String ORGANIZATION_USER_INVITE = "/organization/user/invite";
public static final String ORGANIZATION_UPDATE_MEMBER_TO_ROLE = "/organization/role/update-member";
public static final String ORGANIZATION_UPDATE_MEMBER = "/organization/update-member";
public static final String ORGANIZATION_REMOVE_MEMBER = "/organization/remove-member";
@ -62,6 +62,21 @@ public class OrganizationControllerTests extends BaseTest {
// 批量添加成员成功后, 验证是否添加成功
listByKeyWord("testUserOne", "sys_default_organization_3", true, "sys_default_org_role_id_3", null, false, null, null);
//测试邮箱邀请
UserInviteRequest userInviteRequest = new UserInviteRequest();
userInviteRequest.setInviteEmails(new ArrayList<>(Collections.singletonList("abcde12345@qq.com")));
userInviteRequest.setUserRoleIds(organizationMemberRequest.getUserRoleIds());
userInviteRequest.setOrganizationId(organizationMemberRequest.getOrganizationId());
this.requestPost(ORGANIZATION_USER_INVITE, userInviteRequest);
//输入错误的组织ID
userInviteRequest.setOrganizationId(null);
this.requestPost(ORGANIZATION_USER_INVITE, userInviteRequest).andExpect(status().is5xxServerError());
userInviteRequest.setOrganizationId("not_exist_organization_id_by_somebody_J");
this.requestPost(ORGANIZATION_USER_INVITE, userInviteRequest).andExpect(status().is5xxServerError());
// 权限校验
userInviteRequest.setOrganizationId(DEFAULT_ORGANIZATION_ID);
requestPostPermissionTest(PermissionConstants.ORGANIZATION_MEMBER_INVITE, ORGANIZATION_USER_INVITE, userInviteRequest);
}
@Test