diff --git a/src/main/java/net/geedge/asw/module/app/controller/ApplicationController.java b/src/main/java/net/geedge/asw/module/app/controller/ApplicationController.java index b0a1eed..9f1777b 100644 --- a/src/main/java/net/geedge/asw/module/app/controller/ApplicationController.java +++ b/src/main/java/net/geedge/asw/module/app/controller/ApplicationController.java @@ -2,24 +2,21 @@ package net.geedge.asw.module.app.controller; import cn.hutool.json.JSONObject; import cn.hutool.log.Log; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import jakarta.servlet.http.HttpServletResponse; import net.geedge.asw.common.util.ASWException; import net.geedge.asw.common.util.R; import net.geedge.asw.common.util.RCode; import net.geedge.asw.common.util.T; -import net.geedge.asw.module.app.entity.*; -import net.geedge.asw.module.app.service.*; +import net.geedge.asw.module.app.entity.ApplicationEntity; +import net.geedge.asw.module.app.service.IApplicationService; import net.geedge.asw.module.workspace.entity.WorkspaceEntity; import net.geedge.asw.module.workspace.service.IWorkspaceService; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.*; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; -import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.Map; import java.util.stream.Collectors; @@ -36,7 +33,7 @@ public class ApplicationController { @Autowired private IApplicationService applicationService; - @Autowired + /*@Autowired private IApplicationSignatureService signatureService; @Autowired @@ -267,11 +264,11 @@ public class ApplicationController { .eq(ApplicationHrefEntity::getApplicationId, applicationId) .in(ApplicationHrefEntity::getId, T.ListUtil.of(ids))); return R.ok(); - } - + }*/ @PostMapping("/import") - public R importApplication(@RequestParam String workspaceId, + public synchronized R importApplication(@RequestParam String workspaceId, + @RequestParam String branchName, @RequestParam(defaultValue = "tsg2402") String format, @RequestParam(value = "files") List fileList) { // validate @@ -292,25 +289,36 @@ public class ApplicationController { throw new ASWException(RCode.APP_IMPORT_FILE_FORMAT_ERROR); } + // 名称重复校验 + List applicationList = dataList.stream() + .map(entries -> entries.getJSONArray("applications")) + .flatMap(Collection::stream) + .collect(Collectors.toList()); + long distinctNameCount = applicationList.stream() + .map(obj -> ((JSONObject) obj).getStr("app_name")) + .distinct() + .count(); + long size = applicationList.size(); + if (T.ObjectUtil.notEqual(size, distinctNameCount)) { + throw new ASWException(RCode.APP_DUPLICATE_RECORD); + } + // import - List entityList = applicationService.importAppByFormat(workspaceId, format, dataList); + List entityList = applicationService.importAppByFormat(workspaceId, branchName, format, dataList); List> records = entityList.stream() - .map(entity -> Map.of("id", entity.getId())) + .map(entity -> Map.of("name", entity.getName())) .collect(Collectors.toList()); return R.ok().putData("records", records); } @GetMapping("/export") public void exportApplication(@RequestParam String workspaceId, - @RequestParam String ids, + @RequestParam String branchName, + @RequestParam String names, @RequestParam(defaultValue = "tsg2402") String format, HttpServletResponse response) throws IOException { // validate - List appList = applicationService.list( - new LambdaQueryWrapper() - .eq(ApplicationEntity::getWorkspaceId, workspaceId) - .in(ApplicationEntity::getId, T.ListUtil.of(ids.split(","))) - ); + List appList = applicationService.queryList(workspaceId, branchName, T.StrUtil.splitToArray(names, ",")); T.VerifyUtil.is(appList).notEmpty(RCode.APP_NOT_EXIST); // format diff --git a/src/main/java/net/geedge/asw/module/app/entity/ApplicationEntity.java b/src/main/java/net/geedge/asw/module/app/entity/ApplicationEntity.java index b2adfae..190ab20 100644 --- a/src/main/java/net/geedge/asw/module/app/entity/ApplicationEntity.java +++ b/src/main/java/net/geedge/asw/module/app/entity/ApplicationEntity.java @@ -1,67 +1,26 @@ package net.geedge.asw.module.app.entity; -import com.baomidou.mybatisplus.annotation.IdType; import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import lombok.Data; -import net.geedge.asw.module.sys.entity.SysUserEntity; - -import java.util.List; @Data -@TableName(value = "application", autoResultMap = true) public class ApplicationEntity { - @TableId(type = IdType.ASSIGN_UUID) private String id; - private String name; - - private String tags; - - private String packageName; - + private String longName; + private String developer; private String website; + private String description; - private String provider; + @TableField(typeHandler = JacksonTypeHandler.class) + private Object packageName; @TableField(typeHandler = JacksonTypeHandler.class) private Object properties; - private String status; - - private String description; - - private Long createTimestamp; - - private Long updateTimestamp; - - private String createUserId; - - private String updateUserId; - - private String workspaceId; - - private Integer opVersion; - - @TableField(exist = false) - private SysUserEntity createUser; - - @TableField(exist = false) - private SysUserEntity updateUser; - - @TableField(exist = false) - private ApplicationSignatureEntity signature; - - @TableField(exist = false) - private ApplicationNoteEntity note; - - @TableField(exist = false) - private List attatchments; - - @TableField(exist = false) - private List hrefs; + @TableField(typeHandler = JacksonTypeHandler.class) + private Object signature; } \ No newline at end of file diff --git a/src/main/java/net/geedge/asw/module/app/entity/ApplicationMergeEntity.java b/src/main/java/net/geedge/asw/module/app/entity/ApplicationMergeEntity.java index 6b242eb..63cd4ef 100644 --- a/src/main/java/net/geedge/asw/module/app/entity/ApplicationMergeEntity.java +++ b/src/main/java/net/geedge/asw/module/app/entity/ApplicationMergeEntity.java @@ -15,7 +15,8 @@ public class ApplicationMergeEntity { private String id; private String sourceBranch; private String targetBranch; - private String commitId; + private String startCommitId; + private String endCommitId; private String title; private Integer removeSourceBranch = 0; private String description; diff --git a/src/main/java/net/geedge/asw/module/app/service/IApplicationService.java b/src/main/java/net/geedge/asw/module/app/service/IApplicationService.java index aa4a5ef..e0bb4a3 100644 --- a/src/main/java/net/geedge/asw/module/app/service/IApplicationService.java +++ b/src/main/java/net/geedge/asw/module/app/service/IApplicationService.java @@ -1,29 +1,16 @@ package net.geedge.asw.module.app.service; import cn.hutool.json.JSONObject; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.IService; import net.geedge.asw.module.app.entity.ApplicationEntity; import java.util.List; -import java.util.Map; -public interface IApplicationService extends IService{ +public interface IApplicationService { - ApplicationEntity detail(String id, String workspaceId); - - Page queryList(Map params); - - ApplicationEntity saveApplication(ApplicationEntity entity); - - ApplicationEntity updateApplication(ApplicationEntity entity); - - ApplicationEntity updateBasic(ApplicationEntity entity); - - void removeApplication(List ids); + List queryList(String workspaceId, String branchName, String... names); byte[] exportAppByFormat(List appList, String format); - List importAppByFormat(String workspaceId, String format, List dataList); + List importAppByFormat(String workspaceId, String branchName, String format, List dataList); } diff --git a/src/main/java/net/geedge/asw/module/app/service/IGitService.java b/src/main/java/net/geedge/asw/module/app/service/IGitService.java index 939ceda..7fbb532 100644 --- a/src/main/java/net/geedge/asw/module/app/service/IGitService.java +++ b/src/main/java/net/geedge/asw/module/app/service/IGitService.java @@ -3,6 +3,8 @@ package net.geedge.asw.module.app.service; import org.eclipse.jgit.api.Git; import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.lib.FileMode; import org.eclipse.jgit.lib.ObjectId; import org.eclipse.jgit.lib.Repository; @@ -32,8 +34,12 @@ public interface IGitService { String getLatestCommitId(String workspaceId, String branch); + String getMergeBase(String workspaceId, String branchA, String branchB); + ObjectId insertBlobFileToDatabase(Repository repository, byte[] data) throws IOException; + DirCacheEntry buildDirCacheEntry(String path, FileMode mode, ObjectId objectId); + List> getDiffFileListInCommits(String workspaceId, String newCommitId, String oldCommitId); String mergeBranch(String workspaceId, String sourceBranch, String targetBranch, String message, List> resolveConflictFileContent) throws RuntimeException; @@ -52,7 +58,7 @@ public interface IGitService { Map infoApplicationFileContent(String workspaceId, String branch, String applicationName, String commitId, String file); - List> listCommitAfterMergeBase(String workspaceId, String srcBranch, String tgtBranch); + List> listCommitRange(String workspaceId, String newCommitId, String oldCommitId); List getConflictFilePathInBranches(String workspaceId, String srcBranch, String tgtBranch); diff --git a/src/main/java/net/geedge/asw/module/app/service/ITSGApplicationService.java b/src/main/java/net/geedge/asw/module/app/service/ITSGApplicationService.java index eda42bc..0607c82 100644 --- a/src/main/java/net/geedge/asw/module/app/service/ITSGApplicationService.java +++ b/src/main/java/net/geedge/asw/module/app/service/ITSGApplicationService.java @@ -12,4 +12,8 @@ public interface ITSGApplicationService { List tsg2402ToAsw(String workspaceId, List dataList); + Map aswToTsg2410(List appList); + + List tsg2410ToAsw(String workspaceId, List dataList); + } \ No newline at end of file diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationAttachmentServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationAttachmentServiceImpl.java index eda3339..9b7ca5a 100644 --- a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationAttachmentServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationAttachmentServiceImpl.java @@ -30,41 +30,42 @@ public class ApplicationAttachmentServiceImpl extends ServiceImpl() - .eq(ApplicationAttachmentEntity::getApplicationId, applicationId) - .eq(ApplicationAttachmentEntity::getPath, destination.getPath())); - if (T.ObjectUtil.isNotNull(attachment)) { - return attachment; - } - - // save - this.save(entity); - - } catch (IOException e) { - log.error(e, "[saveAttachment] [error] [applicationId: {}]", applicationId); - throw new ASWException(RCode.ERROR); - } - return entity; +// ApplicationEntity app = applicationService.getById(applicationId); +// ApplicationAttachmentEntity entity = new ApplicationAttachmentEntity(); +// try { +// entity.setName(fileResource.getFilename()); +// entity.setCreateTimestamp(System.currentTimeMillis()); +// entity.setCreateUserId(StpUtil.getLoginIdAsString()); +// entity.setApplicationId(applicationId); +// +// // path +// File destination = T.FileUtil.file(T.WebPathUtil.getRootPath(), app.getId(), fileResource.getFilename()); +// FileUtils.copyInputStreamToFile(fileResource.getInputStream(), destination); +// entity.setPath(destination.getPath()); +// +// // 根据文件 applicationId path 判断是否已上存在,存在则响应当前实体 +// ApplicationAttachmentEntity attachment = this.getOne(new LambdaQueryWrapper() +// .eq(ApplicationAttachmentEntity::getApplicationId, applicationId) +// .eq(ApplicationAttachmentEntity::getPath, destination.getPath())); +// if (T.ObjectUtil.isNotNull(attachment)) { +// return attachment; +// } +// +// // save +// this.save(entity); +// +// } catch (IOException e) { +// log.error(e, "[saveAttachment] [error] [applicationId: {}]", applicationId); +// throw new ASWException(RCode.ERROR); +// } +// return entity; + return null; } @Override diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationMergeServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationMergeServiceImpl.java index adf60d1..10fe30b 100644 --- a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationMergeServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationMergeServiceImpl.java @@ -39,15 +39,6 @@ public class ApplicationMergeServiceImpl extends ServiceImpl infoCommit = gitService.infoCommit(entity.getWorkspaceId(), commitId); - entity.setCommit(infoCommit); - } catch (Exception e) { - } - } - SysUserEntity user = userService.getById(entity.getCreateUserId()); entity.setCreateUser(user); return entity; @@ -57,18 +48,6 @@ public class ApplicationMergeServiceImpl extends ServiceImpl params) { Page page = new Query(ApplicationMergeEntity.class).getPage(params); List list = this.getBaseMapper().queryList(page, params); - - for (ApplicationMergeEntity mergeEntity : list) { - String commitId = mergeEntity.getCommitId(); - if (T.StrUtil.isNotEmpty(commitId)) { - try { - Map infoCommit = gitService.infoCommit(mergeEntity.getWorkspaceId(), commitId); - mergeEntity.setCommit(infoCommit); - } catch (Exception e) { - } - } - } - page.setRecords(list); return page; } @@ -81,6 +60,13 @@ public class ApplicationMergeServiceImpl extends ServiceImpl> listCommitAfterMergeBase = gitService.listCommitAfterMergeBase(workspaceId, sourceBranch, targetBranch); - return listCommitAfterMergeBase; + // newCommitId-oldCommitId 期间的提交信息 + List> commitRange = gitService.listCommitRange(workspaceId, newCommitId, oldCommitId); + return commitRange; } @Override @@ -113,14 +111,28 @@ public class ApplicationMergeServiceImpl extends ServiceImpl conflictFileList = gitService.getConflictFilePathInBranches(workspaceId, sourceBranch, targetBranch); + List conflictFileList = T.ListUtil.list(true); + // src branch changed files + String oldCommitId = entity.getStartCommitId(); + String newCommitId = null; + MergeRequestStatus mergeRequestStatus = MergeRequestStatus.getInstance(entity.getStatus()); + switch (mergeRequestStatus) { + case OPEN: { + newCommitId = gitService.getLatestCommitId(workspaceId, sourceBranch); + // open 状态下,获取 sourceBranch,targetBranch 冲突文件 + conflictFileList = gitService.getConflictFilePathInBranches(workspaceId, sourceBranch, targetBranch); + break; + } + case CLOSED: + case MERGED: { + newCommitId = entity.getEndCommitId(); + break; + } + } - // 获取 sourceBranch,targetBranch 文件差异 - String commitA = gitService.getLatestCommitId(workspaceId, sourceBranch); - String commitB = gitService.getLatestCommitId(workspaceId, targetBranch); - - List> diffFileListInCommits = gitService.getDiffFileListInCommits(workspaceId, commitA, commitB); + List> diffFileListInCommits = gitService.getDiffFileListInCommits(workspaceId, newCommitId, oldCommitId); + List finalConflictFileList = conflictFileList; diffFileListInCommits.parallelStream() .forEach(m -> { T.MapUtil.renameKey(m, "oldContent", "sourceContent"); @@ -132,19 +144,19 @@ public class ApplicationMergeServiceImpl extends ServiceImpl sourceCommit = gitService.infoCommit(workspaceId, commitA); - Map targetCommit = gitService.infoCommit(workspaceId, commitB); + Map sourceCommit = gitService.infoCommit(workspaceId, oldCommitId); + Map targetCommit = gitService.infoCommit(workspaceId, newCommitId); Map m = T.MapUtil.builder() .put("sourceBranch", sourceBranch) .put("targetBranch", targetBranch) - .put("sourceCommitId", commitA) - .put("targetCommitId", commitB) + .put("sourceCommitId", oldCommitId) + .put("targetCommitId", newCommitId) .put("sourceCommit", sourceCommit) .put("targetCommit", targetCommit) .put("files", diffFileListInCommits) @@ -243,7 +255,7 @@ public class ApplicationMergeServiceImpl extends ServiceImpl() .eq(ApplicationMergeEntity::getId, mrId) - .set(ApplicationMergeEntity::getCommitId, entity.getCommitId()) + .set(ApplicationMergeEntity::getEndCommitId, entity.getEndCommitId()) .set(ApplicationMergeEntity::getStatus, entity.getStatus()) .set(ApplicationMergeEntity::getMessage, entity.getMessage()) ); @@ -273,9 +285,12 @@ public class ApplicationMergeServiceImpl extends ServiceImpl() .eq(ApplicationMergeEntity::getId, mrId) .set(ApplicationMergeEntity::getStatus, updateStatus) + .set(ApplicationMergeEntity::getEndCommitId, latestCommitId) ); return entity; } diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationServiceImpl.java index ac55cda..42495ad 100644 --- a/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/app/service/impl/ApplicationServiceImpl.java @@ -1,249 +1,220 @@ package net.geedge.asw.module.app.service.impl; -import cn.dev33.satoken.stp.StpUtil; import cn.hutool.json.JSON; import cn.hutool.json.JSONConfig; import cn.hutool.json.JSONObject; import cn.hutool.log.Log; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; -import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; -import net.geedge.asw.common.config.Query; import net.geedge.asw.common.util.ASWException; import net.geedge.asw.common.util.RCode; import net.geedge.asw.common.util.T; -import net.geedge.asw.module.app.dao.ApplicationDao; -import net.geedge.asw.module.app.entity.*; -import net.geedge.asw.module.app.service.*; -import net.geedge.asw.module.sys.entity.SysUserEntity; -import net.geedge.asw.module.sys.service.ISysUserService; +import net.geedge.asw.module.app.entity.ApplicationEntity; +import net.geedge.asw.module.app.service.IApplicationService; +import net.geedge.asw.module.app.service.IGitService; +import net.geedge.asw.module.app.service.ITSGApplicationService; +import org.eclipse.jgit.api.Git; +import org.eclipse.jgit.api.errors.ConcurrentRefUpdateException; +import org.eclipse.jgit.dircache.DirCache; +import org.eclipse.jgit.dircache.DirCacheBuilder; +import org.eclipse.jgit.dircache.DirCacheEntry; +import org.eclipse.jgit.lib.FileMode; +import org.eclipse.jgit.lib.ObjectId; +import org.eclipse.jgit.lib.ObjectLoader; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevTree; +import org.eclipse.jgit.revwalk.RevWalk; +import org.eclipse.jgit.treewalk.TreeWalk; +import org.eclipse.jgit.treewalk.filter.PathFilter; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; +import java.io.IOException; +import java.nio.file.Path; +import java.util.*; @Service -public class ApplicationServiceImpl extends ServiceImpl implements IApplicationService { +public class ApplicationServiceImpl implements IApplicationService { private static final Log log = Log.get(); @Autowired - private IApplicationLogService applicationLogService; - + private IGitService gitService; @Autowired - private ISysUserService userService; - - @Autowired - private IApplicationSignatureService signatureService; - - @Autowired - private IApplicationNoteService noteService; - - @Autowired - private IApplicationHrefService hrefService; - - @Autowired - private IApplicationAttachmentService attachmentService; - - @Autowired - private ITSGApplicationService tsgApplicationService; + @Qualifier("tsg2402ApplicationService") + private ITSGApplicationService tsg2402ApplicationService; @Override - public ApplicationEntity detail(String id, String workspaceId) { - ApplicationEntity app = this.getOne(new LambdaQueryWrapper() - .eq(ApplicationEntity::getId, id) - .eq(ApplicationEntity::getWorkspaceId, workspaceId)); + public List queryList(String workspaceId, String branch, String... names) { + List resultList = T.ListUtil.list(true); - ApplicationSignatureEntity signature = signatureService.getOne(new LambdaQueryWrapper() - .eq(ApplicationSignatureEntity::getApplicationId, app.getId()) - .orderByDesc(ApplicationSignatureEntity::getOpVersion) - .last("limit 1")); - app.setSignature(signature); + try (Git git = gitService.getGitInstance(workspaceId)) { + Repository repository = git.getRepository(); - ApplicationNoteEntity note = noteService.getOne(new LambdaQueryWrapper() - .eq(ApplicationNoteEntity::getApplicationId, app.getId()) - .orderByDesc(ApplicationNoteEntity::getOpVersion) - .last("limit 1")); - app.setNote(note); + try (TreeWalk treeWalk = new TreeWalk(repository); + RevWalk revWalk = new RevWalk(repository)) { - List attachmentEntityList = attachmentService.list(new LambdaQueryWrapper() - .eq(ApplicationAttachmentEntity::getApplicationId, app.getId())); - attachmentEntityList.stream().forEach(x -> x.setPath(null)); - app.setAttatchments(attachmentEntityList); + ObjectId branchRef = repository.resolve(branch); + treeWalk.addTree(revWalk.parseTree(branchRef)); + treeWalk.setFilter(PathFilter.create("applications/")); + treeWalk.setRecursive(true); - List hrefEntityList = hrefService.list(new LambdaQueryWrapper() - .eq(ApplicationHrefEntity::getApplicationId, app.getId())); - app.setHrefs(hrefEntityList); + Map signatureMapping = T.MapUtil.newHashMap(); - SysUserEntity createUser = userService.getById(app.getCreateUserId()); - SysUserEntity updateUser = userService.getById(app.getUpdateUserId()); - app.setCreateUser(createUser); - app.setUpdateUser(updateUser); + while (treeWalk.next()) { + String filePath = treeWalk.getPathString(); + String applicationName = T.PathUtil.getPathEle(Path.of(filePath), 1).toString(); + if (T.BooleanUtil.and( + T.ObjectUtil.isNotEmpty(names), + !Arrays.asList(names).contains(applicationName))) { + continue; + } - return app; - } + switch (treeWalk.getNameString()) { + case "meta.json": { + ObjectLoader loader = repository.open(treeWalk.getObjectId(0)); + String metaJsonStr = T.StrUtil.utf8Str(loader.getBytes()); + metaJsonStr = T.StrUtil.emptyToDefault(metaJsonStr, T.StrUtil.EMPTY_JSON); - @Override - public Page queryList(Map params) { - Page page = new Query(ApplicationEntity.class).getPage(params); - List packageList = this.getBaseMapper().queryList(page, params); - page.setRecords(packageList); - return page; - } + ApplicationEntity application = T.JSONUtil.toBean(metaJsonStr, ApplicationEntity.class); + application.setName(applicationName); + resultList.add(application); + break; + } + case "signature.json": { + ObjectLoader loader = repository.open(treeWalk.getObjectId(0)); + signatureMapping.put(applicationName, T.StrUtil.utf8Str(loader.getBytes())); + break; + } + default: + break; + } + } - private void validateParam(ApplicationEntity entity, boolean isUpdate) { - ApplicationEntity one = this.getOne(new LambdaQueryWrapper() - .eq(ApplicationEntity::getWorkspaceId, entity.getWorkspaceId()) - .eq(ApplicationEntity::getName, entity.getName())); - - if (T.ObjectUtil.isNotNull(one) && !isUpdate || T.ObjectUtil.isNotNull(one) && isUpdate && !T.StrUtil.equals(entity.getId(), one.getId())) { - throw ASWException.builder().rcode(RCode.APP_DUPLICATE_RECORD).build(); - } - - // package name format - if (T.ObjectUtil.isNotEmpty(entity.getPackageName()) && !T.JSONUtil.isTypeJSON(entity.getPackageName())) { - throw ASWException.builder().rcode(RCode.APP_PACKAGE_NAME_FORMAT_ERROR).build(); - } else if (T.ObjectUtil.isEmpty(entity.getPackageName())) { - entity.setPackageName("{}"); - } - - // tags name format - if (T.StrUtil.isNotEmpty(entity.getTags()) && !T.JSONUtil.isTypeJSON(entity.getTags())) { - throw ASWException.builder().rcode(RCode.APP_TAGS_FORMAT_ERROR).build(); - } - - // signature - if (T.ObjectUtil.isNotEmpty(entity.getSignature())) { - if (!T.StrUtil.isNotEmpty(entity.getSignature().getContent())){ - throw ASWException.builder().rcode(RCode.APP_SIGNATURE_CONTENT_CANNOT_EMPTY).build(); - } - - if (!T.JSONUtil.isTypeJSON(entity.getSignature().getContent())){ - throw ASWException.builder().rcode(RCode.APP_SIGNATURE_CONTENT_CANNOT_EMPTY).build(); + for (ApplicationEntity entity : resultList) { + String name = entity.getName(); + String signature = signatureMapping.getOrDefault(name, ""); + if (T.StrUtil.isNotEmpty(signature)) { + JSONObject jsonObject = T.JSONUtil.parseObj(signature); + entity.setSignature(jsonObject); + } + } + } catch (IOException e) { + log.error(e, "[queryList] [error] [workspaceId: {}] [branch: {}]", workspaceId, branch); + throw new RuntimeException(e); } } - - // note - /* if (T.ObjectUtil.isNotEmpty(entity.getNote()) && !T.StrUtil.isNotEmpty(entity.getNote().getContent())) { - throw ASWException.builder().rcode(RCode.APP_NOTE_CONTENT_CANNOT_EMPTY).build(); - }*/ - - // properties - if (T.ObjectUtil.isNotEmpty(entity.getProperties()) && !T.JSONUtil.isTypeJSON(entity.getProperties().toString())) { - throw ASWException.builder().rcode(RCode.APP_PROPERTIES_FORMAT_ERROR).build(); - } - + return resultList; } - @Override - @Transactional(rollbackFor = Exception.class) - public ApplicationEntity saveApplication(ApplicationEntity entity) { + public void saveOrUpdateBatch(String workspaceId, String branch, String commitMessage, List list) { + try (Git git = gitService.getGitInstance(workspaceId); + Repository repository = git.getRepository(); + RevWalk revWalk = new RevWalk(repository)) { - this.validateParam(entity, false); + ObjectId branchRef = repository.resolve(branch); + RevTree revTree = revWalk.parseTree(branchRef); - // save - entity.setCreateTimestamp(System.currentTimeMillis()); - entity.setUpdateTimestamp(System.currentTimeMillis()); - entity.setCreateUserId(StpUtil.getLoginIdAsString()); - entity.setUpdateUserId(StpUtil.getLoginIdAsString()); - this.save(entity); + // 先查询,区分 新增APP、修改APP + List addAppList = T.ListUtil.list(true); + List updateAppList = T.ListUtil.list(true); + try (TreeWalk treeWalk = new TreeWalk(repository)) { + treeWalk.addTree(revTree); + treeWalk.setRecursive(true); + treeWalk.setFilter(PathFilter.create("applications/")); + HashSet appNameListInDb = new HashSet<>(); + while (treeWalk.next()) { + String appName = T.PathUtil.getPathEle(Path.of(treeWalk.getPathString()), 1).toString(); + appNameListInDb.add(appName); + } + list.parallelStream().forEach(entity -> { + if (appNameListInDb.contains(entity.getName())) { + updateAppList.add(entity); + } else { + addAppList.add(entity); + } + }); + } - if (T.ObjectUtil.isNotEmpty(entity.getSignature())){ - // save signature - signatureService.saveSignature(entity.getSignature(), entity.getId()); + // 修改文件路径信息 + List updateFilePath = T.ListUtil.list(true); + updateAppList.parallelStream().forEach(entity -> { + updateFilePath.add(T.StrUtil.concat(true, "applications/", entity.getName(), "/meta.json")); + updateFilePath.add(T.StrUtil.concat(true, "applications/", entity.getName(), "/signature.json")); + }); + + // build tree + DirCache newTree = DirCache.newInCore(); + DirCacheBuilder newTreeBuilder = newTree.builder(); + try (TreeWalk treeWalk = new TreeWalk(repository)) { + treeWalk.addTree(revTree); + treeWalk.setRecursive(true); + + while (treeWalk.next()) { + // 先删 + String filePath = treeWalk.getPathString(); + if (!updateFilePath.contains(filePath)) { + DirCacheEntry entry = new DirCacheEntry(filePath); + entry.setFileMode(treeWalk.getFileMode(0)); + entry.setObjectId(treeWalk.getObjectId(0)); + newTreeBuilder.add(entry); + } + } + // 新增APP + for (ApplicationEntity entity : addAppList) { + for (String fileName : T.ListUtil.of("README.md", "meta.json", "signature.json", "icon.png")) { + String fileContent = T.StrUtil.EMPTY; + if ("meta.json".equals(fileName)) { + JSONObject tempJSONObject = T.JSONUtil.parseObj(entity); + tempJSONObject.remove("signature"); + fileContent = T.JSONUtil.parse(tempJSONObject).toJSONString(2); + } + if ("signature.json".equals(fileName)) { + String jsonStr = T.JSONUtil.toJsonStr(entity.getSignature()); + JSONObject tempJSONObject = T.JSONUtil.parseObj(jsonStr); + fileContent = T.JSONUtil.parse(tempJSONObject).toJSONString(2); + } + // save + String filePath = T.StrUtil.concat(true, "applications/", entity.getName(), "/", fileName); + DirCacheEntry dirCacheEntry = new DirCacheEntry(filePath); + dirCacheEntry.setFileMode(FileMode.REGULAR_FILE); + + ObjectId blobId = gitService.insertBlobFileToDatabase(repository, fileContent.getBytes()); + dirCacheEntry.setObjectId(blobId); + newTreeBuilder.add(dirCacheEntry); + } + } + // 修改APP + for (ApplicationEntity entity : updateAppList) { + // meta.json + JSONObject jsonObject = T.JSONUtil.parseObj(entity); + jsonObject.remove("signature"); + + String fileContent = T.JSONUtil.parse(jsonObject).toJSONString(2); + ObjectId objectId = gitService.insertBlobFileToDatabase(repository, fileContent.getBytes()); + DirCacheEntry dirCacheEntry = gitService.buildDirCacheEntry(T.StrUtil.concat(true, "applications/", entity.getName(), "/meta.json"), FileMode.REGULAR_FILE, objectId); + newTreeBuilder.add(dirCacheEntry); + + // signature.json + String jsonStr = T.JSONUtil.toJsonStr(entity.getSignature()); + JSONObject jsonObject2 = T.JSONUtil.parseObj(jsonStr); + + String fileContent2 = T.JSONUtil.parse(jsonObject2).toJSONString(2); + ObjectId objectId2 = gitService.insertBlobFileToDatabase(repository, fileContent2.getBytes()); + DirCacheEntry dirCacheEntry2 = gitService.buildDirCacheEntry(T.StrUtil.concat(true, "applications/", entity.getName(), "/signature.json"), FileMode.REGULAR_FILE, objectId2); + newTreeBuilder.add(dirCacheEntry2); + } + newTreeBuilder.finish(); + + RevCommit commitId = revWalk.parseCommit(branchRef); + boolean success = gitService.commitIndex(repository, branch, newTree, commitId, null, commitMessage); + log.info("[saveOrUpdateBatch] [workspaceId: {}] [branch: {}] [commitId: {}] [success: {}]", workspaceId, branch, commitId, success); + } + } catch (IOException | ConcurrentRefUpdateException e) { + log.error(e, "[saveOrUpdateBatch] [error] [workspaceId: {}] [branch: {}]", workspaceId, branch); + throw new RuntimeException(e); } - - if (T.ObjectUtil.isNotEmpty(entity.getNote())){ - //save note - noteService.saveNote(entity.getNote(), entity.getId()); - } - - - return entity; - } - - @Override - @Transactional(rollbackFor = Exception.class) - public ApplicationEntity updateApplication(ApplicationEntity entity) { - - this.validateParam(entity, true); - - ApplicationEntity one = this.getById(entity.getId()); - entity.setUpdateTimestamp(System.currentTimeMillis()); - entity.setUpdateUserId(StpUtil.getLoginIdAsString()); - entity.setOpVersion(one.getOpVersion() + 1); - - // update - this.updateById(entity); - - // save log - this.saveApplicationToLog(one); - - if (T.ObjectUtil.isNotEmpty(entity.getSignature())){ - // save signature - signatureService.saveSignature(entity.getSignature(), entity.getId()); - } - - if (T.ObjectUtil.isNotEmpty(entity.getNote())){ - //save note - noteService.saveNote(entity.getNote(), entity.getId()); - } - - return entity; - } - - private void saveApplicationToLog(ApplicationEntity one) { - ApplicationLogEntity applicationLogEntity = T.BeanUtil.toBean(one, ApplicationLogEntity.class); - applicationLogEntity.setUpdateTimestamp(System.currentTimeMillis()); - applicationLogEntity.setUpdateUserId(StpUtil.getLoginIdAsString()); - applicationLogEntity.setCreateTimestamp(System.currentTimeMillis()); - applicationLogEntity.setCreateUserId(StpUtil.getLoginIdAsString()); - applicationLogService.save(applicationLogEntity); - } - - @Override - @Transactional(rollbackFor = Exception.class) - public void removeApplication(List ids) { - // remove - this.removeBatchByIds(ids); - applicationLogService.removeBatchByIds(ids); - signatureService.remove(new LambdaQueryWrapper().in(ApplicationSignatureEntity::getApplicationId, ids)); - noteService.remove(new LambdaQueryWrapper().in(ApplicationNoteEntity::getApplicationId, ids)); - attachmentService.remove(new LambdaQueryWrapper().in(ApplicationAttachmentEntity::getApplicationId, ids)); - hrefService.remove(new LambdaQueryWrapper().in(ApplicationHrefEntity::getApplicationId, ids)); - } - - @Override - public ApplicationEntity updateBasic(ApplicationEntity entity) { - - ApplicationEntity one = this.getById(entity.getId()); - if (T.ObjectUtil.isNotNull(one) && !T.StrUtil.equals(entity.getId(), one.getId())) { - throw ASWException.builder().rcode(RCode.APP_DUPLICATE_RECORD).build(); - } - - // package name format - if (T.ObjectUtil.isNotEmpty(entity.getPackageName()) && !T.JSONUtil.isTypeJSON(entity.getPackageName())) { - throw ASWException.builder().rcode(RCode.APP_PACKAGE_NAME_FORMAT_ERROR).build(); - } else if (T.ObjectUtil.isEmpty(entity.getPackageName())) { - entity.setPackageName("{}"); - } - - // properties - if (T.ObjectUtil.isNotEmpty(entity.getProperties()) && !T.JSONUtil.isTypeJSON(entity.getProperties().toString())) { - throw ASWException.builder().rcode(RCode.APP_PROPERTIES_FORMAT_ERROR).build(); - } - - entity.setUpdateTimestamp(System.currentTimeMillis()); - entity.setUpdateUserId(StpUtil.getLoginIdAsString()); - entity.setOpVersion(one.getOpVersion() + 1); - - this.saveApplicationToLog(one); - this.updateById(entity); - return entity; } @Override @@ -251,7 +222,7 @@ public class ApplicationServiceImpl extends ServiceImpl m = tsgApplicationService.aswToTsg2402(appList); + Map m = tsg2402ApplicationService.aswToTsg2402(appList); JSON json = new JSONObject(m, JSONConfig.create().setIgnoreNullValue(false).setKeyComparator(String::compareToIgnoreCase)); return T.StrUtil.bytes(json.toJSONString(0)); } @@ -266,12 +237,15 @@ public class ApplicationServiceImpl extends ServiceImpl importAppByFormat(String workspaceId, String format, List dataList) { + public List importAppByFormat(String workspaceId, String branchName, String format, List dataList) { try { switch (format) { case "tsg2402": { - List records = tsgApplicationService.tsg2402ToAsw(workspaceId, dataList); + List records = tsg2402ApplicationService.tsg2402ToAsw(workspaceId, dataList); + + // commit + String commitMessage = "feat: import application data from TSG system (version 2402)"; + this.saveOrUpdateBatch(workspaceId, branchName, commitMessage, records); return records; } default: diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/GitServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/GitServiceImpl.java index dcb15a0..ae051c3 100644 --- a/src/main/java/net/geedge/asw/module/app/service/impl/GitServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/app/service/impl/GitServiceImpl.java @@ -27,7 +27,6 @@ import org.eclipse.jgit.merge.MergeStrategy; import org.eclipse.jgit.merge.RecursiveMerger; import org.eclipse.jgit.merge.ThreeWayMerger; import org.eclipse.jgit.revwalk.RevCommit; -import org.eclipse.jgit.revwalk.RevSort; import org.eclipse.jgit.revwalk.RevWalk; import org.eclipse.jgit.revwalk.filter.RevFilter; import org.eclipse.jgit.storage.file.FileRepositoryBuilder; @@ -152,15 +151,11 @@ public class GitServiceImpl implements IGitService { Repository repository = git.getRepository(); ObjectInserter inserter = repository.getObjectDatabase().newInserter(); ) { - - ObjectId objectId = this.insertBlobFileToDatabase(repository, "".getBytes()); - - DirCacheEntry entry = new DirCacheEntry("README.md"); - entry.setFileMode(FileMode.REGULAR_FILE); - entry.setObjectId(objectId); - DirCache dirCache = DirCache.newInCore(); DirCacheBuilder builder = dirCache.builder(); + + ObjectId objectId = this.insertBlobFileToDatabase(repository, "".getBytes()); + DirCacheEntry entry = this.buildDirCacheEntry("README.md", FileMode.REGULAR_FILE, objectId); builder.add(entry); builder.finish(); @@ -338,6 +333,19 @@ public class GitServiceImpl implements IGitService { } } + @Override + public String getMergeBase(String workspaceId, String branchA, String branchB) { + try (Git git = this.getGitInstance(workspaceId); + Repository repository = git.getRepository();) { + ObjectId branchAId = repository.resolve(branchA); + ObjectId branchBId = repository.resolve(branchB); + + return this.getMergeBase(repository, branchAId, branchBId); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + /** * 获取 commitIdA -> commitIdB 文件差异 * @@ -348,6 +356,7 @@ public class GitServiceImpl implements IGitService { */ @Override public List> getDiffFileListInCommits(String workspaceId, String commitIdA, String commitIdB) { + log.info("[getDiffFileListInCommits] [begin] [workspaceId: {}] [commitIdA: {}] [commitIdB: {}]", workspaceId, commitIdA, commitIdB); try (Git git = this.getGitInstance(workspaceId); Repository repository = git.getRepository(); RevWalk revWalk = new RevWalk(repository); @@ -570,15 +579,19 @@ public class GitServiceImpl implements IGitService { ObjectLoader loader = repository.open(treeWalk.getObjectId(0)); String metaJsonStr = T.StrUtil.utf8Str(loader.getBytes()); metaJsonStr = T.StrUtil.emptyToDefault(metaJsonStr, T.StrUtil.EMPTY_JSON); - Map metaJsonMap = T.JSONUtil.toBean(metaJsonStr, Map.class); + Map metaJsonMap = T.MapUtil.empty(); + try { + metaJsonMap = T.JSONUtil.toBean(metaJsonStr, Map.class); + } catch (Exception e) { + log.error(e, "[listApplication] [meat.json format error] [applicationName: {}]", applicationName); + } Map m = T.MapUtil.newHashMap(true); m.putAll(metaJsonMap); m.put("name", applicationName); - String appId = T.MapUtil.getStr(metaJsonMap, "id", ""); String appDirPath = treeWalk.getPathString().replaceAll(fileName, ""); - appDirPathMapping.put(appId, appDirPath); + appDirPathMapping.put(applicationName, appDirPath); resultList.add(m); } else if (T.StrUtil.equals("icon.png", fileName)) { @@ -602,8 +615,7 @@ public class GitServiceImpl implements IGitService { } } - String appId = T.MapUtil.getStr(map, "id"); - RevCommit lastCommit = T.MapUtil.get(lastCommitMapping, appId, RevCommit.class); + RevCommit lastCommit = T.MapUtil.get(lastCommitMapping, applicationName, RevCommit.class); map.put("commit", this.buildAswCommitInfo(lastCommit)); } } @@ -711,9 +723,7 @@ public class GitServiceImpl implements IGitService { DirCache newTree = DirCache.newInCore(); DirCacheBuilder newTreeBuilder = newTree.builder(); while (treeWalk.next()) { - DirCacheEntry entry = new DirCacheEntry(treeWalk.getPathString()); - entry.setFileMode(treeWalk.getFileMode(0)); - entry.setObjectId(treeWalk.getObjectId(0)); + DirCacheEntry entry = this.buildDirCacheEntry(treeWalk.getPathString(), treeWalk.getFileMode(0), treeWalk.getObjectId(0)); newTreeBuilder.add(entry); } @@ -723,9 +733,7 @@ public class GitServiceImpl implements IGitService { ObjectId blobId = entry.getValue(); // add file ref - DirCacheEntry dirCacheEntry = new DirCacheEntry(filePath); - dirCacheEntry.setFileMode(FileMode.REGULAR_FILE); - dirCacheEntry.setObjectId(blobId); + DirCacheEntry dirCacheEntry = this.buildDirCacheEntry(filePath, FileMode.REGULAR_FILE, blobId); newTreeBuilder.add(dirCacheEntry); } @@ -761,9 +769,7 @@ public class GitServiceImpl implements IGitService { while (treeWalk.next()) { String pathString = treeWalk.getPathString(); if (!pathString.startsWith(appFilePrefixStr)) { - DirCacheEntry entry = new DirCacheEntry(pathString); - entry.setFileMode(treeWalk.getFileMode(0)); - entry.setObjectId(treeWalk.getObjectId(0)); + DirCacheEntry entry = this.buildDirCacheEntry(pathString, treeWalk.getFileMode(0), treeWalk.getObjectId(0)); newTreeBuilder.add(entry); } } @@ -838,9 +844,7 @@ public class GitServiceImpl implements IGitService { String pathString = treeWalk.getPathString(); // 先删 if (!updateFilePath.contains(pathString)) { - DirCacheEntry entry = new DirCacheEntry(pathString); - entry.setFileMode(treeWalk.getFileMode(0)); - entry.setObjectId(treeWalk.getObjectId(0)); + DirCacheEntry entry = this.buildDirCacheEntry(pathString, treeWalk.getFileMode(0), treeWalk.getObjectId(0)); newTreeBuilder.add(entry); } } @@ -940,51 +944,45 @@ public class GitServiceImpl implements IGitService { } /** - * 获取 srcBranch tgtBranch 共同祖先之后, srcBranch 的提交记录 + * commit range + * 沿着 parent(0) 的主路径提交列表,忽略所有分支路径的提交 * * @param workspaceId - * @param srcBranch - * @param tgtBranch + * @param newCommitId + * @param oldCommitId * @return */ - @Override - public List> listCommitAfterMergeBase(String workspaceId, String srcBranch, String tgtBranch) { - log.info("[listCommitAfterMergeBase] [begin] [workspaceId: {}] [srcBranch: {}] [tgtBranch: {}]", workspaceId, srcBranch, tgtBranch); + public List> listCommitRange(String workspaceId, String newCommitId, String oldCommitId) { + log.info("[listCommitRange] [begin] [workspaceId: {}] [newCommitId: {}] [oldCommitId: {}]", workspaceId, newCommitId, oldCommitId); List> commitList = T.ListUtil.list(true); try (Git git = this.getGitInstance(workspaceId); Repository repository = git.getRepository();) { - ObjectId branch1Id = repository.resolve(srcBranch); - ObjectId branch2Id = repository.resolve(tgtBranch); - // Find the merge base - String mergeBaseId = this.getMergeBase(repository, branch1Id, branch2Id); - log.info("[listCommitAfterMergeBase] [mergeBase: {}]", mergeBaseId); - if (T.StrUtil.isEmpty(mergeBaseId)) { - return commitList; - } - - // Walk branch1's commits since the merge base try (RevWalk revWalk = new RevWalk(repository)) { - revWalk.sort(RevSort.TOPO); + RevCommit revCommit = revWalk.parseCommit(repository.resolve(newCommitId)); - RevCommit mergeBase = revWalk.parseCommit(ObjectId.fromString(mergeBaseId)); - revWalk.markStart(revWalk.parseCommit(branch1Id)); - revWalk.markUninteresting(mergeBase); - - for (RevCommit commit : revWalk) { - commitList.add(this.buildAswCommitInfo(commit)); - - List parentIds = Arrays.stream(commit.getParents()).map(RevCommit::getName).collect(Collectors.toList()); - if (parentIds.contains(mergeBaseId)) { + Set visitedCommits = new HashSet<>(); + while (revCommit != null && !visitedCommits.contains(revCommit.getId())) { + if (oldCommitId != null && revCommit.getId().getName().equals(oldCommitId)) { break; } + + commitList.add(this.buildAswCommitInfo(revCommit)); + visitedCommits.add(revCommit.getId()); + + // 沿着 parent(0) 前进 + if (revCommit.getParentCount() > 0) { + revCommit = revWalk.parseCommit(revCommit.getParent(0)); + } else { + revCommit = null; + } } + } catch (IOException e) { + log.error(e, "[listCommitRange] [error]"); + throw new RuntimeException(e); + } finally { + log.info("[listCommitRange] [finshed] [workspaceId: {}] [commits size: {}]", workspaceId, commitList.size()); } - } catch (IOException e) { - log.error(e, "[listCommitAfterMergeBase] [error]"); - throw new RuntimeException(e.getMessage()); - } finally { - log.info("[listCommitAfterMergeBase] [finshed] [workspaceId: {}] [commits size: {}]", workspaceId, commitList.size()); } return commitList; } @@ -1112,6 +1110,14 @@ public class GitServiceImpl implements IGitService { } } + @Override + public DirCacheEntry buildDirCacheEntry(String path, FileMode mode, ObjectId objectId) { + DirCacheEntry dirCacheEntry = new DirCacheEntry(path); + dirCacheEntry.setFileMode(mode); + dirCacheEntry.setObjectId(objectId); + return dirCacheEntry; + } + /** * 根据 path,objectId 读取文件内容 * 响应 Map,key=encoding,content @@ -1162,8 +1168,8 @@ public class GitServiceImpl implements IGitService { return mergeBase.getName(); } catch (Exception e) { log.error(e, "Failed to determine merge base"); + throw new RuntimeException(e); } - return null; } /** diff --git a/src/main/java/net/geedge/asw/module/app/service/impl/TSGApplicationServiceImpl.java b/src/main/java/net/geedge/asw/module/app/service/impl/TSG2402ApplicationServiceImpl.java similarity index 81% rename from src/main/java/net/geedge/asw/module/app/service/impl/TSGApplicationServiceImpl.java rename to src/main/java/net/geedge/asw/module/app/service/impl/TSG2402ApplicationServiceImpl.java index da42a17..567b4a6 100644 --- a/src/main/java/net/geedge/asw/module/app/service/impl/TSGApplicationServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/app/service/impl/TSG2402ApplicationServiceImpl.java @@ -1,40 +1,31 @@ package net.geedge.asw.module.app.service.impl; -import cn.dev33.satoken.stp.StpUtil; import cn.hutool.core.lang.Validator; import cn.hutool.json.JSONArray; import cn.hutool.json.JSONObject; import cn.hutool.log.Log; -import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import net.geedge.asw.common.util.T; import net.geedge.asw.module.app.entity.ApplicationEntity; -import net.geedge.asw.module.app.entity.ApplicationSignatureEntity; -import net.geedge.asw.module.app.service.IApplicationService; -import net.geedge.asw.module.app.service.IApplicationSignatureService; import net.geedge.asw.module.app.service.ITSGApplicationService; import net.geedge.asw.module.attribute.entity.AttributeEntity; import net.geedge.asw.module.attribute.service.IAttributeService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; -import java.util.*; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import java.util.stream.Collectors; -@Service -public class TSGApplicationServiceImpl implements ITSGApplicationService { +@Service("tsg2402ApplicationService") +public class TSG2402ApplicationServiceImpl implements ITSGApplicationService { private static final Log log = Log.get(); @Autowired private IAttributeService attributeService; - @Autowired - private IApplicationService applicationService; - - @Autowired - private IApplicationSignatureService applicationSignatureService; - @Override public Map aswToTsg2402(List appList) { @@ -63,12 +54,11 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { Map properties = (Map) app.getProperties(); Map app_properties = T.MapUtil.builder() .put("parent_app_id", 0) - .put("parent_app_name", "null") + .put("parent_app_name", T.MapUtil.getStr(properties, "parentApp", "")) .put("category", T.MapUtil.getStr(properties, "category", "")) .put("subcategory", T.MapUtil.getStr(properties, "subcategory", "")) .put("content", T.MapUtil.getStr(properties, "content", "")) .put("risk", T.MapUtil.getStr(properties, "risk", "1")) - .put("characteristics", T.MapUtil.getStr(properties, "characteristics", "")) .put("deny_action", T.MapUtil.builder() .put("method", "drop") .put("after_n_packets", 0) @@ -85,8 +75,7 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { application.put("app_properties", app_properties); // app_surrogates - ApplicationSignatureEntity signature = applicationSignatureService.queryLastVersionSignatureByAppId(app.getId()); - JSONObject jsonObject = T.JSONUtil.parseObj(signature.getContent()); + JSONObject jsonObject = (JSONObject) app.getSignature(); JSONArray surrogates = jsonObject.getJSONArray("surrogates"); if (!surrogates.isEmpty()) { List app_surrogates = T.ListUtil.list(true); @@ -124,8 +113,7 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { int sig_object_id = 10, signature_id = 0; for (ApplicationEntity app : appList) { - ApplicationSignatureEntity signature = applicationSignatureService.queryLastVersionSignatureByAppId(app.getId()); - JSONObject jsonObject = T.JSONUtil.parseObj(signature.getContent()); + JSONObject jsonObject = (JSONObject) app.getSignature(); JSONArray surrogates = jsonObject.getJSONArray("surrogates"); List signaturesForApp = surrogates.stream() .map(obj -> ((JSONObject) obj).getJSONArray("signatures")) @@ -160,56 +148,64 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { List source_object_ids = T.ListUtil.list(true); - // sig_objects - JSONArray items = conditionJSONObj.getJSONArray("items"); + // objects + JSONArray objects = conditionJSONObj.getJSONArray("objects"); + for (Object tempObject : objects) { + JSONObject tempJsonObject = (JSONObject) tempObject; - String conditionType = attributeEntity.getObjectType(); - if ("application".equalsIgnoreCase(conditionType)) { - continue; - } else if ("boolean".equals(conditionType)) { - items.stream() - .map(obj -> (JSONObject) obj) - .forEach(item -> { - String itemValue = T.MapUtil.getStr((JSONObject) item, "item"); - if ("True".equalsIgnoreCase(itemValue)) { - source_object_ids.add(2); - } else if ("False".equalsIgnoreCase(itemValue)) { - source_object_ids.add(3); - } - }); - } else if ("ip_protocol".equals(conditionType)) { - items.stream() - .map(obj -> (JSONObject) obj) - .forEach(item -> { - String itemValue = T.MapUtil.getStr((JSONObject) item, "item"); - if ("ICMP".equalsIgnoreCase(itemValue)) { - source_object_ids.add(5); - } else if ("TCP".equalsIgnoreCase(itemValue)) { - source_object_ids.add(6); - } else if ("UDP".equalsIgnoreCase(itemValue)) { - source_object_ids.add(7); - } - }); - } else { - String name = T.MapUtil.getStr((JSONObject) items.getFirst(), "item"); - Map sig_object = T.MapUtil.builder() - .put("id", sig_object_id) - .put("source_id", sig_object_id) - .put("name", name) - .put("source_name", name) - .put("type", conditionType) - .put("sub_type", attributeEntity.getType()) - .put("member_type", "item") - .put("uuid", T.IdUtil.fastSimpleUUID()) - .put("statistics_option", "none") - .build(); + // sig_objects + JSONArray items = tempJsonObject.getJSONArray("items"); + String objectName = tempJsonObject.getStr("name"); + String objectType = tempJsonObject.getStr("type"); + String objectDescription = tempJsonObject.getStr("description"); - Map member = this.buildTSG2402SignaturesMember(attributeEntity, items); - sig_object.put("member", member); + if ("application".equalsIgnoreCase(objectType)) { + continue; + } else if ("boolean".equals(objectType)) { + items.stream() + .map(obj -> (JSONObject) obj) + .forEach(item -> { + String itemValue = T.MapUtil.getStr((JSONObject) item, "item"); + if ("True".equalsIgnoreCase(itemValue)) { + source_object_ids.add(2); + } else if ("False".equalsIgnoreCase(itemValue)) { + source_object_ids.add(3); + } + }); + } else if ("ip_protocol".equals(objectType)) { + items.stream() + .map(obj -> (JSONObject) obj) + .forEach(item -> { + String itemValue = T.MapUtil.getStr((JSONObject) item, "item"); + if ("ICMP".equalsIgnoreCase(itemValue)) { + source_object_ids.add(5); + } else if ("TCP".equalsIgnoreCase(itemValue)) { + source_object_ids.add(6); + } else if ("UDP".equalsIgnoreCase(itemValue)) { + source_object_ids.add(7); + } + }); + } else { + Map sig_object = T.MapUtil.builder() + .put("id", sig_object_id) + .put("source_id", sig_object_id) + .put("name", objectName) + .put("source_name", objectName) + .put("type", objectType) + .put("sub_type", attributeEntity.getType()) + .put("member_type", "item") + .put("uuid", T.IdUtil.fastSimpleUUID()) + .put("statistics_option", "none") + .put("description", objectDescription) + .build(); - sig_objects.add(sig_object); - source_object_ids.add(sig_object_id); - sig_object_id++; + Map member = this.buildTSG2402SignaturesMember(objectType.toLowerCase(), items); + sig_object.put("member", member); + + sig_objects.add(sig_object); + source_object_ids.add(sig_object_id); + sig_object_id++; + } } or_condition_obj.put("source_object_ids", source_object_ids); @@ -303,12 +299,11 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { return m; } - private Map buildTSG2402SignaturesMember(AttributeEntity attributeEntity, JSONArray itemArr) { + private Map buildTSG2402SignaturesMember(String objectType, JSONArray itemArr) { List list = T.ListUtil.list(true); itemArr.stream() .map(obj -> (JSONObject) obj) .forEach(item -> { - String objectType = attributeEntity.getObjectType().toLowerCase(); switch (objectType) { case "keywords": case "http_signature": { @@ -484,7 +479,6 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { // ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ @Override - @Transactional(rollbackFor = Exception.class) public List tsg2402ToAsw(String workspaceId, List dataList) { List records = T.ListUtil.list(true); for (JSONObject tsgAppSourceData : dataList) { @@ -497,46 +491,42 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { .map(obj -> (JSONObject) obj) .forEach(application -> { // application + String app_id = application.getStr("app_id"); String app_name = application.getStr("app_name"); + String app_longname = application.getStr("app_longname"); String description = application.getStr("description"); JSONObject appProperties = application.getJSONObject("app_properties"); String category = T.MapUtil.getStr(appProperties, "category", ""); String subcategory = T.MapUtil.getStr(appProperties, "subcategory", ""); String content = T.MapUtil.getStr(appProperties, "content", ""); + String parent_app_name = T.MapUtil.getStr(appProperties, "parent_app_name", ""); int risk = T.MapUtil.getInt(appProperties, "risk", 1); - String characteristics = T.MapUtil.getStr(appProperties, "characteristics", ""); Map properties = T.MapUtil.builder() .put("category", category) .put("subcategory", subcategory) .put("content", content) + .put("parentApp", parent_app_name) .put("risk", risk) - .put("characteristics", characteristics) .build(); - // save or update application + // meta.json ApplicationEntity entity = new ApplicationEntity(); + entity.setId(app_id); entity.setName(app_name); + entity.setLongName(app_longname); entity.setDescription(description); entity.setProperties(properties); - entity.setPackageName("{}"); - entity.setWorkspaceId(workspaceId); - entity.setCreateTimestamp(System.currentTimeMillis()); - entity.setUpdateTimestamp(System.currentTimeMillis()); - entity.setCreateUserId(StpUtil.getLoginIdAsString()); - entity.setUpdateUserId(StpUtil.getLoginIdAsString()); - - ApplicationEntity one = applicationService.getOne(new LambdaQueryWrapper() - .eq(ApplicationEntity::getWorkspaceId, workspaceId) - .eq(ApplicationEntity::getName, app_name)); - if (null != one) { - entity.setId(one.getId()); - } - applicationService.saveOrUpdate(entity); - - records.add(entity); - String applicationId = entity.getId(); + // default value + entity.setDeveloper(""); + entity.setWebsite(""); + entity.setPackageName( + T.MapUtil.builder() + .put("android", "") + .put("ios", "") + .build() + ); // surrogate - signature Map> surrAndSignListMap = T.MapUtil.newHashMap(); @@ -549,7 +539,6 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { } } - List insertSurrogateList = T.ListUtil.list(true); for (Map.Entry> entry : surrAndSignListMap.entrySet()) { String surrogateName = entry.getKey(); @@ -575,19 +564,11 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { .put("surrogates", insertSurrogateList) .build(); - // save application signatrue - ApplicationSignatureEntity signatureEntity = new ApplicationSignatureEntity(); - signatureEntity.setApplicationId(applicationId); - signatureEntity.setContent(T.JSONUtil.toJsonStr(sm)); - signatureEntity.setCreateTimestamp(System.currentTimeMillis()); - signatureEntity.setCreateUserId(StpUtil.getLoginIdAsString()); - signatureEntity.setOpVersion(0L); + // signature.json + entity.setSignature(T.JSONUtil.parseObj(sm)); - ApplicationSignatureEntity signatureLast = applicationSignatureService.queryLastVersionSignatureByAppId(applicationId); - if (T.ObjectUtil.isNotEmpty(signatureLast)) { - signatureEntity.setOpVersion(signatureLast.getOpVersion() + 1); - } - applicationSignatureService.save(signatureEntity); + // add records + records.add(entity); }); } return records; @@ -642,20 +623,10 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { }) .collect(Collectors.toList()); - List> itemList = this.buildAswConditionItemsFromTSG2402(sourceObjectList); - if (T.CollUtil.isEmpty(itemList)) continue; + List> objects = this.buildAswConditionObjectsFromTSG2402(sourceObjectList); + if (T.CollUtil.isEmpty(objects)) continue; - // 按 item value 去重 - List> distinctItemList = itemList.stream() - .collect(Collectors.collectingAndThen( - Collectors.toMap( - map -> map.get("item"), - map -> map, - (existing, replacement) -> existing // 保留第一个出现的元素 - ), - map -> new ArrayList(map.values()) - )); - m.put("items", distinctItemList); + m.put("objects", objects); conditionMapList.add(m); } @@ -667,14 +638,17 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { return surrogate; } - private List> buildAswConditionItemsFromTSG2402(List sourceObjectList) { - List> iiemList = T.ListUtil.list(true); + private List> buildAswConditionObjectsFromTSG2402(List sourceObjectList) { + List> objectList = T.ListUtil.list(true); for (JSONObject jsonObject : sourceObjectList) { - + String name = jsonObject.getStr("name"); String type = jsonObject.getStr("type"); + String description = jsonObject.getStr("description"); + JSONArray itemArr = (JSONArray) T.JSONUtil.getByPath(jsonObject, "member.items"); itemArr = T.CollUtil.defaultIfEmpty(itemArr, new JSONArray()); + List> items = T.ListUtil.list(true); switch (type) { case "http_signature": case "keywords": { @@ -727,7 +701,7 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { if (T.StrUtil.isNotEmpty(context_name)) { m.put("district", context_name); } - iiemList.add(m); + items.add(m); }); break; } @@ -737,7 +711,7 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { .map(obj -> (JSONObject) obj) .forEach(item -> { String str = (String) T.JSONUtil.getByPath(item, "string.patterns[0].keywords"); - iiemList.add( + items.add( T.MapUtil.builder() .put("item", str) .put("description", "") @@ -761,7 +735,7 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { if (!"0-65535" .equalsIgnoreCase(port)) { ipAddress = T.StrUtil.concat(true, ipAddress, "#", port); } - iiemList.add( + items.add( T.MapUtil.builder() .put("item", ipAddress) .put("description", "") @@ -778,7 +752,7 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { if (T.StrUtil.isEmpty(port)) { port = (String) T.JSONUtil.getByPath(item, "port.port_range"); } - iiemList.add( + items.add( T.MapUtil.builder() .put("item", port) .put("description", "") @@ -797,7 +771,7 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { .put("item", low_boundary + "-" + up_boundary) .put("description", "") .build(); - iiemList.add(m); + items.add(m); }); break; } @@ -807,7 +781,7 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { .put("item", jsonObject.getStr("name")) .put("description", "") .build(); - iiemList.add(m); + items.add(m); break; } case "application": { @@ -816,8 +790,28 @@ public class TSGApplicationServiceImpl implements ITSGApplicationService { default: break; } + + Map m = T.MapUtil.builder() + .put("name", name) + .put("type", type) + .put("description", description) + .put("items", items) + .build(); + objectList.add(m); } - return iiemList; + return objectList; + } + + @Override + public Map aswToTsg2410(List appList) { + // 不在这个类处理,在 TSG2410ApplicationServiceImpl 实现 + return null; + } + + @Override + public List tsg2410ToAsw(String workspaceId, List dataList) { + // 不在这个类处理,在 TSG2410ApplicationServiceImpl 实现 + return null; } } \ No newline at end of file diff --git a/src/main/resources/db/mapper/app/ApplicationMergeMapper.xml b/src/main/resources/db/mapper/app/ApplicationMergeMapper.xml index ca0ef6d..8a6396f 100644 --- a/src/main/resources/db/mapper/app/ApplicationMergeMapper.xml +++ b/src/main/resources/db/mapper/app/ApplicationMergeMapper.xml @@ -7,7 +7,8 @@ - + + diff --git a/src/main/resources/db/migration/V1.0.01__INIT_TABLES.sql b/src/main/resources/db/migration/V1.0.01__INIT_TABLES.sql index bfb48c3..50daf76 100644 --- a/src/main/resources/db/migration/V1.0.01__INIT_TABLES.sql +++ b/src/main/resources/db/migration/V1.0.01__INIT_TABLES.sql @@ -361,7 +361,8 @@ CREATE TABLE `application_merge` ( `id` VARCHAR(64) NOT NULL COMMENT '主键', `source_branch` VARCHAR(256) NOT NULL DEFAULT '' COMMENT '源分支', `target_branch` VARCHAR(256) NOT NULL DEFAULT '' COMMENT '目标分支', - `commit_id` VARCHAR(256) NOT NULL DEFAULT '' COMMENT '提交ID', + `start_commit_id` VARCHAR(256) NOT NULL DEFAULT '' COMMENT '起始提交ID,即source和target分支的共同parent id', + `end_commit_id` VARCHAR(256) NOT NULL DEFAULT '' COMMENT '终止提交ID,记录合并后的commit id', `title` VARCHAR(4096) NOT NULL DEFAULT '' COMMENT '标题', `remove_source_branch` int(1) NOT NULL DEFAULT 0 COMMENT '是否删除源分支, 1:删除;0:不删除 默认:0', `description` text NOT NULL DEFAULT '' COMMENT '描述信息',