diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fd85d18f..414b861ba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ ## 2.10.37 +### 🐣 新增功能 + +1. 【server】新增 文件中心添加别名码来为文件进行分类下载,构建添加别名码可以同步到文件中心 + (感谢 [@大灰灰大](https://gitee.com/linjianhui) [Gitee issues I6OUC8](https://gitee.com/dromara/Jpom/issues/I6OUC8) ) + ### 🐞 解决BUG、优化功能 1. 【server】优化 容器构建 maven 插件版本错误提示可用版本号,如果构建容器已经存在则忽略远程版本(感谢@大灰灰) diff --git a/PLANS.md b/PLANS.md index dfc4b2d79..c1f488a98 100644 --- a/PLANS.md +++ b/PLANS.md @@ -29,6 +29,7 @@ 18. 插件端证书验证迁移到服务端 19. 前端表格用户自定义列显示 20. 导入云效仓库 +21. 清理触发器表 ### DONE diff --git a/modules/server/src/main/java/io/jpom/build/ReleaseManage.java b/modules/server/src/main/java/io/jpom/build/ReleaseManage.java index 0d2d5edd2..1188e5259 100644 --- a/modules/server/src/main/java/io/jpom/build/ReleaseManage.java +++ b/modules/server/src/main/java/io/jpom/build/ReleaseManage.java @@ -141,7 +141,11 @@ public class ReleaseManage { if (syncFileStorage != null && syncFileStorage) { logRecorder.system("开始同步到文件管理中心"); File dirPackage = BuildUtil.loadDirPackage(this.buildExtraModule.getId(), this.buildNumberId, this.resultFile, (unZip, file) -> file); - boolean success = fileStorageService.addFile(dirPackage, 1, buildInfoModel.getWorkspaceId(), buildInfoModel.getName()); + boolean success = fileStorageService.addFile(dirPackage, 1, + buildInfoModel.getWorkspaceId(), + buildInfoModel.getName(), + // 默认的别名码为构建id + StrUtil.emptyToDefault(buildInfoModel.getAliasCode(), buildInfoModel.getId())); if (success) { logRecorder.system("构建产物文件成功同步到文件管理中心"); } else { diff --git a/modules/server/src/main/java/io/jpom/controller/build/BuildInfoController.java b/modules/server/src/main/java/io/jpom/controller/build/BuildInfoController.java index f84650417..4ea57e030 100644 --- a/modules/server/src/main/java/io/jpom/controller/build/BuildInfoController.java +++ b/modules/server/src/main/java/io/jpom/controller/build/BuildInfoController.java @@ -189,6 +189,7 @@ public class BuildInfoController extends BaseServerController { String branchName, String branchTagName, String webhook, String autoBuildCron, String extraData, String group, @ValidatorItem(value = ValidatorRule.POSITIVE_INTEGER, msg = "构建方式不正确") int buildMode, + String aliasCode, HttpServletRequest request) { // 根据 repositoryId 查询仓库信息 RepositoryModel repositoryModel = repositoryService.getByKey(repositoryId, request); @@ -218,14 +219,14 @@ public class BuildInfoController extends BaseServerController { BuildInfoModel buildInfoModel = buildInfoService.getByKey(id, request); buildInfoModel = ObjectUtil.defaultIfNull(buildInfoModel, new BuildInfoModel()); // 设置参数 - if (StrUtil.isNotEmpty(webhook)) { - Validator.validateMatchRegex(RegexPool.URL_HTTP, webhook, "WebHooks 地址不合法"); - } + Opt.ofBlankAble(webhook).ifPresent(s -> Validator.validateMatchRegex(RegexPool.URL_HTTP, s, "WebHooks 地址不合法")); + Opt.ofBlankAble(aliasCode).ifPresent(s -> Validator.validateGeneral(s, "别名码只能是英文、数字")); // buildInfoModel.setAutoBuildCron(this.checkCron(autoBuildCron)); buildInfoModel.setWebhook(webhook); buildInfoModel.setRepositoryId(repositoryId); buildInfoModel.setName(name); + buildInfoModel.setAliasCode(aliasCode); buildInfoModel.setBranchName(branchName); buildInfoModel.setBranchTagName(branchTagName); buildInfoModel.setResultDirFile(resultDirFile); @@ -423,7 +424,7 @@ public class BuildInfoController extends BaseServerController { @RequestMapping(value = "/build/branch-list", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @Feature(method = MethodFeature.LIST) public JsonMessage branchList( - @ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "仓库ID不能为空") String repositoryId) throws Exception { + @ValidatorItem(value = ValidatorRule.NOT_BLANK, msg = "仓库ID不能为空") String repositoryId) throws Exception { // 根据 repositoryId 查询仓库信息 RepositoryModel repositoryModel = repositoryService.getByKey(repositoryId, false); Assert.notNull(repositoryModel, "无效的仓库信息"); diff --git a/modules/server/src/main/java/io/jpom/func/files/controller/FileStorageController.java b/modules/server/src/main/java/io/jpom/func/files/controller/FileStorageController.java index 725121753..71d36e03c 100644 --- a/modules/server/src/main/java/io/jpom/func/files/controller/FileStorageController.java +++ b/modules/server/src/main/java/io/jpom/func/files/controller/FileStorageController.java @@ -25,6 +25,8 @@ package io.jpom.func.files.controller; import cn.hutool.core.date.DatePattern; import cn.hutool.core.date.DateTime; import cn.hutool.core.io.FileUtil; +import cn.hutool.core.lang.Opt; +import cn.hutool.core.lang.Validator; import cn.hutool.core.util.StrUtil; import io.jpom.common.*; import io.jpom.common.validator.ValidatorItem; @@ -146,8 +148,10 @@ public class FileStorageController extends BaseServerController { String fileSumMd5, Integer keepDay, String description, + String aliasCode, Boolean global, HttpServletRequest request) throws IOException { + Opt.ofBlankAble(aliasCode).ifPresent(s -> Validator.validateGeneral(s, "别名码只能是英文、数字")); File storageSavePath = serverConfig.fileStorageSavePath(); // 验证文件 FileStorageModel fileStorageModel1 = fileStorageService.getByKey(fileSumMd5); @@ -170,6 +174,7 @@ public class FileStorageController extends BaseServerController { fileStorageModel.setId(fileSumMd5); fileStorageModel.setName(successFile.getName()); fileStorageModel.setDescription(description); + fileStorageModel.setAliasCode(aliasCode); fileStorageModel.setExtName(extName); fileStorageModel.setPath(path); fileStorageModel.setSize(FileUtil.size(fileStorageFile)); @@ -197,8 +202,10 @@ public class FileStorageController extends BaseServerController { @ValidatorItem String name, Integer keepDay, String description, + String aliasCode, Boolean global, HttpServletRequest request) throws IOException { + Opt.ofBlankAble(aliasCode).ifPresent(s -> Validator.validateGeneral(s, "别名码只能是英文、数字")); FileStorageModel storageModel = fileStorageService.getByKey(id); Assert.notNull(storageModel, "不存在对应的文件"); UserModel user = getUser(); @@ -210,6 +217,7 @@ public class FileStorageController extends BaseServerController { FileStorageModel fileStorageModel = new FileStorageModel(); fileStorageModel.setId(id); fileStorageModel.setName(name); + fileStorageModel.setAliasCode(aliasCode); fileStorageModel.setDescription(description); // this.updateGlobal(fileStorageModel, request, global); @@ -252,16 +260,18 @@ public class FileStorageController extends BaseServerController { @PostMapping(value = "remote-download", produces = MediaType.APPLICATION_JSON_VALUE) @Feature(method = MethodFeature.REMOTE_DOWNLOAD) public JsonMessage download( - @ValidatorItem String url, - Integer keepDay, - String description, - Boolean global, - HttpServletRequest request) throws IOException { + @ValidatorItem String url, + Integer keepDay, + String description, + String aliasCode, + Boolean global, + HttpServletRequest request) throws IOException { + Opt.ofBlankAble(aliasCode).ifPresent(s -> Validator.validateGeneral(s, "别名码只能是英文、数字")); // 验证远程 地址 ServerWhitelist whitelist = outGivingWhitelistService.getServerWhitelistData(request); whitelist.checkAllowRemoteDownloadHost(url); String workspace = fileStorageService.getCheckUserWorkspace(request); - fileStorageService.download(url, global, workspace, keepDay, description); + fileStorageService.download(url, global, workspace, keepDay, description, aliasCode); return JsonMessage.success("开始异步下载"); } @@ -284,7 +294,7 @@ public class FileStorageController extends BaseServerController { updateInfo = new FileStorageModel(); updateInfo.setId(id); updateInfo.setTriggerToken(triggerTokenLogServer.restToken(item.getTriggerToken(), fileStorageService.typeName(), - item.getId(), user.getId())); + item.getId(), user.getId())); fileStorageService.updateById(updateInfo); } else { updateInfo = item; @@ -295,12 +305,21 @@ public class FileStorageController extends BaseServerController { private Map getBuildToken(FileStorageModel item, HttpServletRequest request) { String contextPath = UrlRedirectUtil.getHeaderProxyPath(request, ServerConst.PROXY_PATH); - String url = ServerOpenApi.FILE_STORAGE_DOWNLOAD. - replace("{id}", item.getId()). - replace("{token}", item.getTriggerToken()); - String triggerBuildUrl = String.format("/%s/%s", contextPath, url); Map map = new HashMap<>(10); - map.put("triggerDownloadUrl", FileUtil.normalize(triggerBuildUrl)); + { + String url = ServerOpenApi.FILE_STORAGE_DOWNLOAD. + replace("{id}", item.getId()). + replace("{token}", item.getTriggerToken()); + String triggerBuildUrl = String.format("/%s/%s", contextPath, url); + map.put("triggerDownloadUrl", FileUtil.normalize(triggerBuildUrl)); + } + if (StrUtil.isNotEmpty(item.getAliasCode())) { + String url = ServerOpenApi.FILE_STORAGE_DOWNLOAD. + replace("{id}", item.getAliasCode()). + replace("{token}", item.getTriggerToken()); + String triggerBuildUrl = String.format("/%s/%s", contextPath, url); + map.put("triggerAliasDownloadUrl", FileUtil.normalize(triggerBuildUrl)); + } map.put("id", item.getId()); map.put("token", item.getTriggerToken()); return map; diff --git a/modules/server/src/main/java/io/jpom/func/files/model/FileStorageModel.java b/modules/server/src/main/java/io/jpom/func/files/model/FileStorageModel.java index ffc24cf36..2df4b814e 100644 --- a/modules/server/src/main/java/io/jpom/func/files/model/FileStorageModel.java +++ b/modules/server/src/main/java/io/jpom/func/files/model/FileStorageModel.java @@ -104,6 +104,11 @@ public class FileStorageModel extends BaseWorkspaceModel { */ private String triggerToken; + /** + * 别名码 + */ + private String aliasCode; + /** * 设置保留天数的过期时间 * diff --git a/modules/server/src/main/java/io/jpom/func/files/service/FileStorageService.java b/modules/server/src/main/java/io/jpom/func/files/service/FileStorageService.java index 27c8f30d3..6c00d9378 100644 --- a/modules/server/src/main/java/io/jpom/func/files/service/FileStorageService.java +++ b/modules/server/src/main/java/io/jpom/func/files/service/FileStorageService.java @@ -108,7 +108,7 @@ public class FileStorageService extends BaseWorkspaceService i * @param global 是否为全局共享 * @param keepDay 保留天数 */ - public void download(String url, Boolean global, String workspaceId, Integer keepDay, String description) { + public void download(String url, Boolean global, String workspaceId, Integer keepDay, String description, String aliasCode) { FileStorageModel fileStorageModel = new FileStorageModel(); // 临时使用 uuid,代替 String uuid = IdUtil.fastSimpleUUID(); @@ -123,6 +123,7 @@ public class FileStorageService extends BaseWorkspaceService i String path = StrUtil.format("/{}/{}.{}", DateTime.now().toString(DatePattern.PURE_DATE_FORMAT), uuid, extName); fileStorageModel.setExtName("download"); fileStorageModel.setPath(path); + fileStorageModel.setAliasCode(aliasCode); fileStorageModel.setSize(0L); fileStorageModel.setStatus(0); fileStorageModel.setSource(2); @@ -243,11 +244,14 @@ public class FileStorageService extends BaseWorkspaceService i /** * 添加文件 * - * @param source 文件来源 - * @param file 要文件的文件 + * @param source 文件来源 + * @param file 要文件的文件 + * @param description 描述 + * @param workspaceId 工作空间id + * @param aliasCode 别名码 * @return 是否添加成功 */ - public boolean addFile(File file, int source, String workspaceId, String description) { + public boolean addFile(File file, int source, String workspaceId, String description, String aliasCode) { String md5 = SecureUtil.md5(file); File storageSavePath = serverConfig.fileStorageSavePath(); String extName = FileUtil.extName(file); @@ -259,6 +263,7 @@ public class FileStorageService extends BaseWorkspaceService i // 保存 FileStorageModel fileStorageModel = new FileStorageModel(); fileStorageModel.setId(md5); + fileStorageModel.setAliasCode(aliasCode); fileStorageModel.setName(file.getName()); fileStorageModel.setDescription("构建来源," + description); fileStorageModel.setExtName(extName); @@ -302,8 +307,8 @@ public class FileStorageService extends BaseWorkspaceService i Entity updateEntity = this.dataBeanToEntity(update); // Entity where = Entity.create() - .set("source", 2) - .set("status", 0); + .set("source", 2) + .set("status", 0); return this.update(updateEntity, where); } diff --git a/modules/server/src/main/java/io/jpom/func/openapi/controller/FileStorageApiController.java b/modules/server/src/main/java/io/jpom/func/openapi/controller/FileStorageApiController.java index b33e2d290..3d15c60fd 100644 --- a/modules/server/src/main/java/io/jpom/func/openapi/controller/FileStorageApiController.java +++ b/modules/server/src/main/java/io/jpom/func/openapi/controller/FileStorageApiController.java @@ -28,7 +28,10 @@ import cn.hutool.core.date.DateTime; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.NioUtil; +import cn.hutool.core.lang.Opt; import cn.hutool.core.util.*; +import cn.hutool.db.sql.Direction; +import cn.hutool.db.sql.Order; import cn.hutool.extra.servlet.ServletUtil; import io.jpom.common.BaseJpomController; import io.jpom.common.ServerOpenApi; @@ -55,7 +58,10 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import java.util.Collections; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; /** * @author bwcx_jzy @@ -122,13 +128,65 @@ public class FileStorageApiController extends BaseJpomController { return new long[]{fromPos, downloadSize}; } + /** + * 解析别名参数 + * + * @param id 别名 + * @param token token + * @param sort 排序 + * @param request 请求 + * @return 数据 + */ + private FileStorageModel queryByAliasCode(String id, String token, String sort, HttpServletRequest request) { + // 先验证 token 和 id 是否都存在 + { + FileStorageModel data = new FileStorageModel(); + data.setAliasCode(id); + data.setTriggerToken(token); + Assert.state(fileStorageService.exists(data), "别名或者token错误,或者已经失效"); + } + List orders = Opt.ofBlankAble(sort) + .map(s -> StrUtil.splitTrim(s, StrUtil.COMMA)) + .map(strings -> + strings.stream() + .map(s -> { + List list = StrUtil.splitTrim(s, StrUtil.COLON); + Order order = new Order(); + order.setField(CollUtil.getFirst(list)); + String s1 = CollUtil.get(list, 1); + order.setDirection(ObjectUtil.defaultIfNull(Direction.fromString(s1), Direction.DESC)); + return order; + }) + .collect(Collectors.toList())) + .orElse(Collections.emptyList()); + Map paramMap = ServletUtil.getParamMap(request); + FileStorageModel where = new FileStorageModel(); + for (Map.Entry entry : paramMap.entrySet()) { + String key = entry.getKey(); + if (StrUtil.startWith(key, "filter_")) { + key = StrUtil.removePrefix(key, "filter_"); + ReflectUtil.setFieldValue(where, key, entry.getValue()); + } + } + where.setAliasCode(id); + List fileStorageModels = fileStorageService.queryList(where, 1, orders.toArray(new Order[]{})); + return CollUtil.getFirst(fileStorageModels); + } + @GetMapping(value = ServerOpenApi.FILE_STORAGE_DOWNLOAD, produces = MediaType.APPLICATION_JSON_VALUE) - public void download(@PathVariable String id, @PathVariable String token, + public void download(@PathVariable String id, + @PathVariable String token, + String sort, HttpServletRequest request, HttpServletResponse response) throws IOException { FileStorageModel storageModel = fileStorageService.getByKey(id); - Assert.notNull(storageModel, "没有对应数据"); - Assert.state(StrUtil.equals(token, storageModel.getTriggerToken()), "token错误,或者已经失效"); + if (storageModel == null) { + // 根据别名查询 + storageModel = this.queryByAliasCode(id, token, sort, request); + Assert.notNull(storageModel, "没有对应数据"); + } else { + Assert.state(StrUtil.equals(token, storageModel.getTriggerToken()), "token错误,或者已经失效"); + } // UserModel userModel = triggerTokenLogServer.getUserByToken(token, fileStorageService.typeName()); // @@ -148,7 +206,7 @@ public class FileStorageApiController extends BaseJpomController { String contentType = ObjectUtil.defaultIfNull(FileUtil.getMimeType(name), "application/octet-stream"); String charset = ObjectUtil.defaultIfNull(response.getCharacterEncoding(), CharsetUtil.UTF_8); response.setHeader("Content-Disposition", StrUtil.format("attachment;filename=\"{}\"", - URLUtil.encode(name, CharsetUtil.charset(charset)))); + URLUtil.encode(name, CharsetUtil.charset(charset)))); response.setContentType(contentType); // 解析断点续传相关信息 long[] resolveRange = this.resolveRange(request, fileSize, storageModel.getId(), storageModel.getName(), response); diff --git a/modules/server/src/main/java/io/jpom/model/data/BuildInfoModel.java b/modules/server/src/main/java/io/jpom/model/data/BuildInfoModel.java index 87432a921..f97814930 100644 --- a/modules/server/src/main/java/io/jpom/model/data/BuildInfoModel.java +++ b/modules/server/src/main/java/io/jpom/model/data/BuildInfoModel.java @@ -128,6 +128,10 @@ public class BuildInfoModel extends BaseGroupModel { * 构建环境变量 */ private String buildEnvParameter; + /** + * 别名码 + */ + private String aliasCode; @Tolerate public BuildInfoModel() { diff --git a/modules/server/src/main/java/io/jpom/service/h2db/BaseDbService.java b/modules/server/src/main/java/io/jpom/service/h2db/BaseDbService.java index 563d1236c..23da6ec25 100644 --- a/modules/server/src/main/java/io/jpom/service/h2db/BaseDbService.java +++ b/modules/server/src/main/java/io/jpom/service/h2db/BaseDbService.java @@ -74,8 +74,8 @@ public abstract class BaseDbService extends BaseDbCommonS * 默认排序规则 */ private static final Order[] DEFAULT_ORDERS = new Order[]{ - new Order("createTimeMillis", Direction.DESC), - new Order("modifyTimeMillis", Direction.DESC) + new Order("createTimeMillis", Direction.DESC), + new Order("modifyTimeMillis", Direction.DESC) }; public void insert(T t) { @@ -294,6 +294,18 @@ public abstract class BaseDbService extends BaseDbCommonS */ public List queryList(T data, int count, Order... orders) { Entity where = this.dataBeanToEntity(data); + return this.queryList(where, count, orders); + } + + /** + * 查询列表 + * + * @param where 条件 + * @param count 查询数量 + * @param orders 排序 + * @return List + */ + public List queryList(Entity where, int count, Order... orders) { Page page = new Page(1, count); page.addOrder(orders); PageResultDto tPageResultDto = this.listPage(where, page); diff --git a/modules/server/src/main/resources/sql-view/alter.all.v1.3.csv b/modules/server/src/main/resources/sql-view/alter.all.v1.3.csv index efb4a275f..939cdb894 100644 --- a/modules/server/src/main/resources/sql-view/alter.all.v1.3.csv +++ b/modules/server/src/main/resources/sql-view/alter.all.v1.3.csv @@ -36,3 +36,5 @@ ADD,FILE_STORAGE,status,TINYINT,,,0 下载中 1 下载完成 3 下载异常,fals ADD,FILE_STORAGE,progressDesc,String,255,,进度描述,false ADD,FILE_STORAGE,triggerToken,String,200,,触发器token,false ALTER,FILE_STORAGE,name,String,255,,名称,true +ADD,BUILD_INFO,aliasCode,String,50,,别名码,false +ADD,FILE_STORAGE,aliasCode,String,50,,别名码,false diff --git a/web-vue/src/api/build-info.js b/web-vue/src/api/build-info.js index 665fe6169..d9817afca 100644 --- a/web-vue/src/api/build-info.js +++ b/web-vue/src/api/build-info.js @@ -91,6 +91,7 @@ export function editBuild(params) { webhook: params.webhook, autoBuildCron: params.autoBuildCron, buildMode: params.buildMode, + aliasCode: params.aliasCode, }; return axios({ url: "/build/edit", diff --git a/web-vue/src/pages/build/list-info.vue b/web-vue/src/pages/build/list-info.vue index 7cb3eda29..e6e2b6b9c 100644 --- a/web-vue/src/pages/build/list-info.vue +++ b/web-vue/src/pages/build/list-info.vue @@ -798,6 +798,22 @@ + + + + + @@ -1124,7 +1140,7 @@ import { afterOptList, afterOptListSimple, getDishPatchListAll, getDispatchProje import { getNodeListAll, getProjectListAll } from "@/api/node"; import { getSshListAll } from "@/api/ssh"; import codeEditor from "@/components/codeEditor"; -import { CHANGE_PAGE, COMPUTED_PAGINATION, CRON_DATA_SOURCE, PAGE_DEFAULT_LIST_QUERY, itemGroupBy, parseTime } from "@/utils/const"; +import { CHANGE_PAGE, COMPUTED_PAGINATION, CRON_DATA_SOURCE, PAGE_DEFAULT_LIST_QUERY, itemGroupBy, parseTime, randomStr } from "@/utils/const"; import Vue from "vue"; import { dockerSwarmListAll, dockerSwarmServicesList } from "@/api/docker-swarm"; import { getScriptListAll } from "@/api/server-script"; @@ -1405,6 +1421,7 @@ export default { }, methods: { CHANGE_PAGE, + randomStr, // loadDockerSwarmListAll() { dockerSwarmListAll().then((res) => { diff --git a/web-vue/src/pages/docker/images.vue b/web-vue/src/pages/docker/images.vue index e210b4e4f..d1aae816b 100644 --- a/web-vue/src/pages/docker/images.vue +++ b/web-vue/src/pages/docker/images.vue @@ -359,7 +359,18 @@ zIndex: 1, }" > - 确认 + + + 取消 + + 确认 + diff --git a/web-vue/src/pages/file-manager/fileStorage/list.vue b/web-vue/src/pages/file-manager/fileStorage/list.vue index 3ee66afb8..50dcf0c8f 100644 --- a/web-vue/src/pages/file-manager/fileStorage/list.vue +++ b/web-vue/src/pages/file-manager/fileStorage/list.vue @@ -113,6 +113,22 @@ 当前工作空间 + + + + + @@ -133,6 +149,22 @@ 当前工作空间 + + + + + @@ -153,6 +185,22 @@ 当前工作空间 + + + + + @@ -167,7 +215,7 @@ 重置 - + + + + + + + + + + @@ -256,7 +341,7 @@