feat(用户管理): 增加用户管理的用户邀请校验接口
【【系统设置】用户-邮箱邀请用户-收到的注册链接过期后,仍能正常打开注册页面】 https://www.tapd.cn/55049933/bugtrace/bugs/view/1155049933001035202
This commit is contained in:
parent
5bebf4fe7c
commit
13bc39a45c
|
@ -4,6 +4,7 @@ import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
|||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
|
@ -20,4 +21,8 @@ public class RemoteFileAttachInfo implements Serializable {
|
|||
private String filePath;
|
||||
private String commitMessage;
|
||||
private long size;
|
||||
|
||||
public boolean fileIsNotExist() {
|
||||
return StringUtils.isAnyBlank(branch, commitId);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ public class GitRepository implements FileRepository {
|
|||
GitFileRequest gitFileInfo = request.getGitFileRequest();
|
||||
GitRepositoryUtil repositoryUtils = new GitRepositoryUtil(
|
||||
gitFileInfo.getUrl(), gitFileInfo.getUserName(), gitFileInfo.getToken());
|
||||
fileBytes = repositoryUtils.getFile(gitFileInfo.getUrl(), gitFileInfo.getCommitId());
|
||||
fileBytes = repositoryUtils.getFile(request.getFileName(), gitFileInfo.getCommitId());
|
||||
}
|
||||
return fileBytes;
|
||||
}
|
||||
|
|
|
@ -21,13 +21,13 @@ public class FileAssociationSourceUtil {
|
|||
public static final Map<String, String> QUERY_SQL = new HashMap<>();
|
||||
|
||||
static {
|
||||
QUERY_SQL.put(SOURCE_TYPE_BUG, "SELECT id AS sourceId,title AS sourceName FROM bug");
|
||||
QUERY_SQL.put(SOURCE_TYPE_FUNCTIONAL_CASE, "SELECT id AS sourceId,name AS sourceName FROM functional_case");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_DEBUG, "SELECT id AS sourceId,name AS sourceName FROM api_debug");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_SCENARIO, "SELECT id AS sourceId,name AS sourceName FROM api_scenario");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_TEST_CASE, "SELECT id AS sourceId,name AS sourceName FROM api_test_case");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_DEFINITION, "SELECT id AS sourceId,name AS sourceName FROM api_definition");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_DEFINITION_MOCK, "SELECT id AS sourceId,name AS sourceName FROM api_definition_mock");
|
||||
QUERY_SQL.put(SOURCE_TYPE_BUG, "SELECT id AS sourceId, num AS sourceNum, title AS sourceName FROM bug");
|
||||
QUERY_SQL.put(SOURCE_TYPE_FUNCTIONAL_CASE, "SELECT id AS sourceId, num AS sourceNum, name AS sourceName FROM functional_case");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_DEBUG, "SELECT id AS sourceId, id AS sourceNum, name AS sourceName FROM api_debug");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_SCENARIO, "SELECT id AS sourceId, num AS sourceNum, name AS sourceName FROM api_scenario");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_TEST_CASE, "SELECT id AS sourceId, num AS sourceNum, name AS sourceName FROM api_test_case");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_DEFINITION, "SELECT id AS sourceId, num AS sourceNum, name AS sourceName FROM api_definition");
|
||||
QUERY_SQL.put(SOURCE_TYPE_API_DEFINITION_MOCK, "SELECT id AS sourceId, expect_num AS sourceNum, name AS sourceName FROM api_definition_mock");
|
||||
}
|
||||
|
||||
public static void validate(String type) {
|
||||
|
|
|
@ -35,6 +35,7 @@ public class FilterChainUtils {
|
|||
filterChainDefinitionMap.put("/system/version/current", "anon");
|
||||
|
||||
//用户通过邮箱邀请自行注册的接口
|
||||
filterChainDefinitionMap.put("/system/user/check-invite/**", "anon");
|
||||
filterChainDefinitionMap.put("/system/user/register-by-invite", "anon");
|
||||
|
||||
// 下载测试资源
|
||||
|
|
|
@ -50,9 +50,14 @@ public class GitRepositoryUtil {
|
|||
|
||||
public byte[] getFile(String filePath, String commitId) throws Exception {
|
||||
LogUtils.info("准备获取文件. repositoryUrl:" + repositoryUrl + "; filePath:" + filePath + "; commitId:" + commitId);
|
||||
|
||||
InMemoryRepository repo = this.getGitRepositoryInMemory(repositoryUrl, userName, token);
|
||||
ObjectId fileCommitObjectId = repo.resolve(commitId);
|
||||
ObjectId objectId = this.getTreeWork(repo, fileCommitObjectId, filePath).getObjectId(0);
|
||||
TreeWalk treeWalk = this.getTreeWork(repo, fileCommitObjectId, filePath);
|
||||
if (!treeWalk.next()) {
|
||||
return null;
|
||||
}
|
||||
ObjectId objectId = treeWalk.getObjectId(0);
|
||||
ObjectLoader loader = repo.open(objectId);
|
||||
byte[] returnBytes = loader.getBytes();
|
||||
this.closeConnection(repo);
|
||||
|
|
|
@ -39,10 +39,14 @@ public class TempFileUtils {
|
|||
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] compressPic(byte[] fileBytes) throws IOException {
|
||||
byte[] compressBytes = compressPic(new ByteArrayInputStream(fileBytes));
|
||||
return compressBytes.length > 0 ? compressBytes : fileBytes;
|
||||
}
|
||||
|
||||
public static byte[] compressPic(InputStream imgInputStream) throws IOException {
|
||||
// 读取原始图像
|
||||
BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(fileBytes));
|
||||
BufferedImage originalImage = ImageIO.read(imgInputStream);
|
||||
if (originalImage != null) {
|
||||
int width = originalImage.getWidth();
|
||||
int height = originalImage.getHeight();
|
||||
|
@ -65,11 +69,10 @@ public class TempFileUtils {
|
|||
ImageIO.setUseCache(false);
|
||||
ImageIO.write(previewImage, "JPEG", outputStream);
|
||||
return outputStream.toByteArray();
|
||||
} catch (Exception e) {
|
||||
LogUtils.error(e);
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
return fileBytes;
|
||||
return new byte[0];
|
||||
}
|
||||
|
||||
private static int getCompressFactor(int width, int height) {
|
||||
|
|
|
@ -5,5 +5,6 @@ import lombok.Data;
|
|||
@Data
|
||||
public class FileAssociationSource {
|
||||
private String sourceId;
|
||||
private String sourceNum;
|
||||
private String sourceName;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,9 @@ public class FileAssociationResponse {
|
|||
@Schema(description = "资源Id")
|
||||
private String sourceId;
|
||||
|
||||
@Schema(description = "资源编号")
|
||||
private String sourceNum;
|
||||
|
||||
@Schema(description = "文件Id")
|
||||
private String fileId;
|
||||
|
||||
|
|
|
@ -28,8 +28,8 @@
|
|||
resultMap="BaseResultMap">
|
||||
SELECT
|
||||
f.id,
|
||||
updateUser.name as updateUser,
|
||||
createUser.name AS createUser,
|
||||
updateUser.name as update_user,
|
||||
createUser.name AS create_uUser,
|
||||
f.module_id,
|
||||
f.name,
|
||||
f.type,
|
||||
|
|
|
@ -62,7 +62,7 @@ public class FileAssociationService {
|
|||
//查找文件信息
|
||||
Map<String,FileMetadata> fileIdMap = this.getFileIdMap( associationList.stream().map(FileAssociation::getFileId).collect(Collectors.toList()));
|
||||
//查找资源信息
|
||||
Map<String,String> sourceIdNameMap = this.getAssociationSourceMap(
|
||||
Map<String, FileAssociationSource> sourceIdNameMap = this.getAssociationSourceMap(
|
||||
associationList.stream().collect(
|
||||
Collectors.groupingBy(FileAssociation::getSourceType,Collectors.mapping(FileAssociation::getSourceId,Collectors.toList()))
|
||||
));
|
||||
|
@ -75,7 +75,8 @@ public class FileAssociationService {
|
|||
response.setId(item.getId());
|
||||
response.setSourceId(item.getSourceId());
|
||||
response.setFileId(item.getFileId());
|
||||
response.setSourceName(sourceIdNameMap.get(item.getSourceId()));
|
||||
response.setSourceName(sourceIdNameMap.get(item.getSourceId()).getSourceName());
|
||||
response.setSourceNum(sourceIdNameMap.get(item.getSourceId()).getSourceNum());
|
||||
response.setSourceType(item.getSourceType());
|
||||
response.setFileVersion(fileIdMap.get(item.getFileId()).getFileVersion());
|
||||
responseList.add(response);
|
||||
|
@ -94,14 +95,14 @@ public class FileAssociationService {
|
|||
}
|
||||
|
||||
//通过资源类型Map查找关联表
|
||||
private Map<String, String> getAssociationSourceMap(Map<String, List<String>> sourceTypeToIdMap) {
|
||||
private Map<String, FileAssociationSource> getAssociationSourceMap(Map<String, List<String>> sourceTypeToIdMap) {
|
||||
List<FileAssociationSource> sourceQueryList = new ArrayList<>();
|
||||
for (Map.Entry<String, List<String>> entry : sourceTypeToIdMap.entrySet()) {
|
||||
String sourceType =entry.getKey();
|
||||
sourceQueryList.addAll(
|
||||
extFileAssociationMapper.selectAssociationSourceBySourceTableAndIdList(FileAssociationSourceUtil.getQuerySql(sourceType),entry.getValue()));
|
||||
}
|
||||
return sourceQueryList.stream().collect(Collectors.toMap(FileAssociationSource::getSourceId, FileAssociationSource::getSourceName));
|
||||
return sourceQueryList.stream().collect(Collectors.toMap(FileAssociationSource::getSourceId, item -> item));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -182,6 +182,7 @@ public class FileManagementService {
|
|||
FileModuleRepositoryDTO repositoryDTO = getFileModuleRepositoryDTO(fileMetadata.getModuleId());
|
||||
FileMetadataRepositoryDTO metadataRepositoryDTO = getFileMetadataRepositoryDTO(fileMetadata.getId());
|
||||
fileRequest.setGitFileRequest(repositoryDTO, metadataRepositoryDTO);
|
||||
fileRequest.setFileName(fileMetadata.getPath());
|
||||
}
|
||||
|
||||
return fileService.download(fileRequest);
|
||||
|
|
|
@ -271,9 +271,9 @@ public class FileMetadataService {
|
|||
}
|
||||
FileMetadataExample example = new FileMetadataExample();
|
||||
if (StringUtils.isBlank(id)) {
|
||||
example.createCriteria().andNameEqualTo(fileName).andTypeEqualTo(type).andProjectIdEqualTo(projectId).andStorageEqualTo(StorageType.MINIO.name());
|
||||
example.createCriteria().andNameEqualTo(fileName).andTypeEqualTo(type).andLatestEqualTo(true).andProjectIdEqualTo(projectId).andStorageEqualTo(StorageType.MINIO.name());
|
||||
} else {
|
||||
example.createCriteria().andNameEqualTo(fileName).andTypeEqualTo(type).andProjectIdEqualTo(projectId).andIdNotEqualTo(id).andStorageEqualTo(StorageType.MINIO.name());
|
||||
example.createCriteria().andNameEqualTo(fileName).andTypeEqualTo(type).andLatestEqualTo(true).andProjectIdEqualTo(projectId).andIdNotEqualTo(id).andStorageEqualTo(StorageType.MINIO.name());
|
||||
}
|
||||
if (fileMetadataMapper.countByExample(example) > 0) {
|
||||
throw new MSException(Translator.get("file.name.exist") + ":" + fileName);
|
||||
|
@ -289,10 +289,12 @@ public class FileMetadataService {
|
|||
|
||||
if (TempFileUtils.isImage(fileMetadata.getType())) {
|
||||
//图片文件自动生成预览图
|
||||
byte[] previewImg = TempFileUtils.compressPic(file.getBytes());
|
||||
byte[] previewImg = TempFileUtils.compressPic(file.getInputStream());
|
||||
if (previewImg.length > 0) {
|
||||
uploadFileRequest.setFolder(DefaultRepositoryDir.getFileManagementPreviewDir(fileMetadata.getProjectId()));
|
||||
fileService.upload(previewImg, uploadFileRequest);
|
||||
}
|
||||
}
|
||||
return filePath;
|
||||
}
|
||||
|
||||
|
@ -312,14 +314,10 @@ public class FileMetadataService {
|
|||
|
||||
public byte[] getFileByte(FileMetadata fileMetadata) {
|
||||
String filePath = null;
|
||||
if (TempFileUtils.isImgTmpFileExists(fileMetadata.getId())) {
|
||||
filePath = TempFileUtils.getTmpFilePath(fileMetadata.getId());
|
||||
} else {
|
||||
try {
|
||||
filePath = TempFileUtils.createFile(TempFileUtils.getTmpFilePath(fileMetadata.getId()), fileManagementService.getFile(fileMetadata));
|
||||
} catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
return TempFileUtils.getFile(filePath);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,12 +15,12 @@ import io.metersphere.project.mapper.FileMetadataRepositoryMapper;
|
|||
import io.metersphere.project.mapper.FileModuleRepositoryMapper;
|
||||
import io.metersphere.sdk.constants.ModuleConstants;
|
||||
import io.metersphere.sdk.constants.StorageType;
|
||||
import io.metersphere.sdk.dto.RemoteFileAttachInfo;
|
||||
import io.metersphere.sdk.exception.MSException;
|
||||
import io.metersphere.sdk.util.GitRepositoryUtil;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.dto.sdk.BaseTreeNode;
|
||||
import io.metersphere.sdk.dto.RemoteFileAttachInfo;
|
||||
import io.metersphere.system.uid.IDGenerator;
|
||||
import io.metersphere.sdk.util.GitRepositoryUtil;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.apache.commons.collections.CollectionUtils;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
|
@ -137,7 +137,7 @@ public class FileRepositoryService extends FileModuleService {
|
|||
GitRepositoryUtil utils = new GitRepositoryUtil(repository.getUrl(), repository.getUserName(), repository.getToken());
|
||||
|
||||
RemoteFileAttachInfo fileAttachInfo = utils.selectLastCommitIdByBranch(request.getBranch(), request.getFilePath());
|
||||
if (fileAttachInfo == null) {
|
||||
if (fileAttachInfo == null || fileAttachInfo.fileIsNotExist()) {
|
||||
throw new MSException(Translator.get("file.not.exist"));
|
||||
}
|
||||
FileMetadata fileMetadata = fileMetadataService.genFileMetadata(request.getFilePath(), StorageType.GIT.name(), fileAttachInfo.getSize(), request.isEnable(),
|
||||
|
|
|
@ -189,6 +189,12 @@ public class UserController {
|
|||
return userService.saveInviteRecord(request, SessionUtils.getUser());
|
||||
}
|
||||
|
||||
@GetMapping("/check-invite/{inviteId}")
|
||||
@Operation(summary = "系统设置-系统-用户-用户接受注册邀请并创建账户")
|
||||
public void checkInviteNum(@PathVariable String inviteId) {
|
||||
userService.getUserInviteAndCheckEfficient(inviteId);
|
||||
}
|
||||
|
||||
@PostMapping("/register-by-invite")
|
||||
@Operation(summary = "系统设置-系统-用户-用户接受注册邀请并创建账户")
|
||||
public String registerByInvite(@Validated @RequestBody UserRegisterRequest request) throws Exception {
|
||||
|
|
|
@ -6,6 +6,7 @@ import io.metersphere.sdk.constants.OperationLogConstants;
|
|||
import io.metersphere.sdk.constants.UserRoleEnum;
|
||||
import io.metersphere.sdk.constants.UserRoleScope;
|
||||
import io.metersphere.sdk.util.JSON;
|
||||
import io.metersphere.sdk.util.Translator;
|
||||
import io.metersphere.system.domain.*;
|
||||
import io.metersphere.system.dto.user.response.UserTableResponse;
|
||||
import io.metersphere.system.log.constants.OperationLogModule;
|
||||
|
@ -72,8 +73,8 @@ public class UserRoleRelationService {
|
|||
log.setCreateTime(operationTime);
|
||||
log.setSourceId(user.getId());
|
||||
log.setContent(user.getName() + StringUtils.SPACE
|
||||
+ operationType + StringUtils.SPACE
|
||||
+ "UserRole" + StringUtils.SPACE
|
||||
+ Translator.get(StringUtils.lowerCase(operationType)) + StringUtils.SPACE
|
||||
+ Translator.get("permission.project_group.name") + StringUtils.SPACE
|
||||
+ userRole.getName());
|
||||
log.setOriginalValue(JSON.toJSONBytes(userRole));
|
||||
logs.add(log);
|
||||
|
|
|
@ -521,11 +521,16 @@ public class UserService {
|
|||
javaMailSender.send(mimeMessage);
|
||||
}
|
||||
|
||||
public String registerByInvite(UserRegisterRequest request) throws Exception {
|
||||
UserInvite userInvite = userInviteService.selectEfficientInviteById(request.getInviteId());
|
||||
public UserInvite getUserInviteAndCheckEfficient(String inviteId) {
|
||||
UserInvite userInvite = userInviteService.selectEfficientInviteById(inviteId);
|
||||
if (userInvite == null) {
|
||||
throw new MSException(Translator.get("user.not.invite.or.expired"));
|
||||
}
|
||||
return userInvite;
|
||||
}
|
||||
|
||||
public String registerByInvite(UserRegisterRequest request) throws Exception {
|
||||
UserInvite userInvite = this.getUserInviteAndCheckEfficient(request.getInviteId());
|
||||
//检查邮箱是否已经注册
|
||||
this.validateUserInfo(new ArrayList<>() {{
|
||||
this.add(userInvite.getEmail());
|
||||
|
|
|
@ -1362,6 +1362,7 @@ public class UserControllerTests extends BaseTest {
|
|||
this.requestPost(UserRequestUtils.URL_INVITE_REGISTER, request).andExpect(BAD_REQUEST_MATCHER);
|
||||
|
||||
//测试正常创建
|
||||
this.requestGetWithOk("/system/user/check-invite/" + request.getInviteId());
|
||||
request.setName("建国通过邮箱邀请");
|
||||
MvcResult mvcResult = userRequestUtils.responsePost(UserRequestUtils.URL_INVITE_REGISTER, request);
|
||||
String resultHolderStr = mvcResult.getResponse().getContentAsString(StandardCharsets.UTF_8);
|
||||
|
@ -1380,6 +1381,7 @@ public class UserControllerTests extends BaseTest {
|
|||
this.testUserInviteSuccess();
|
||||
}
|
||||
String inviteId = INVITE_RECORD_ID_LIST.get(1);
|
||||
|
||||
//400-用户名为空
|
||||
UserRegisterRequest request = new UserRegisterRequest();
|
||||
request.setInviteId(inviteId);
|
||||
|
@ -1409,8 +1411,9 @@ public class UserControllerTests extends BaseTest {
|
|||
request.setName("建国通过邮箱邀请2");
|
||||
request.setPassword(IDGenerator.nextStr());
|
||||
userRequestUtils.requestPost(UserRequestUtils.URL_INVITE_REGISTER, request, ERROR_REQUEST_MATCHER);
|
||||
this.requestGet("/system/user/check-invite/" + request.getInviteId()).andExpect(ERROR_REQUEST_MATCHER);
|
||||
|
||||
//500-邀请ID已过期,且暂未删除
|
||||
//500-邀请ID已过期,且暂未删除 (同时校验邀请检测接口)
|
||||
UserInvite invite = userInviteMapper.selectByPrimaryKey(inviteId);
|
||||
invite.setInviteTime(invite.getInviteTime() - 1000 * 60 * 60 * 24);
|
||||
userInviteMapper.updateByPrimaryKeySelective(invite);
|
||||
|
@ -1420,6 +1423,7 @@ public class UserControllerTests extends BaseTest {
|
|||
request.setName("建国通过邮箱邀请2");
|
||||
request.setPassword(IDGenerator.nextStr());
|
||||
userRequestUtils.requestPost(UserRequestUtils.URL_INVITE_REGISTER, request, ERROR_REQUEST_MATCHER);
|
||||
this.requestGet("/system/user/check-invite/" + inviteId).andExpect(ERROR_REQUEST_MATCHER);
|
||||
|
||||
//500-用户邮箱在用户注册之前已经被注册过了
|
||||
//首先还原邀请时间
|
||||
|
|
Loading…
Reference in New Issue