diff --git a/.env b/.env index 0b2dc0c8b..194e347ae 100644 --- a/.env +++ b/.env @@ -1,3 +1,3 @@ -JPOM_VERSION=2.10.28 +JPOM_VERSION=2.10.29 # Server Token 生产部署请更换 SERVER_TOKEN=7094f673-2c53-4fc1-82e7-86e528449d97 diff --git a/.workflow/MasterPipeline.yml b/.workflow/MasterPipeline.yml index 061521870..761d639c9 100644 --- a/.workflow/MasterPipeline.yml +++ b/.workflow/MasterPipeline.yml @@ -29,14 +29,14 @@ stages: artifacts: - name: all_zip path: - - modules/server/target/server-2.10.28-release.zip - - modules/agent/target/agent-2.10.28-release.zip + - modules/server/target/server-2.10.29-release.zip + - modules/agent/target/agent-2.10.29-release.zip - name: server_zip path: - - modules/server/target/server-2.10.28-release.zip + - modules/server/target/server-2.10.29-release.zip - name: agent_zip path: - - modules/agent/target/agent-2.10.28-release.zip + - modules/agent/target/agent-2.10.29-release.zip settings: [] strategy: retry: '0' @@ -50,7 +50,7 @@ stages: name: publish_general_artifacts displayName: 合并打包 dependArtifact: all_zip - artifactName: jpom-2.10.28 + artifactName: jpom-2.10.29 strategy: retry: '0' strategy: diff --git a/CHANGELOG.md b/CHANGELOG.md index 58dbcf522..be09299d0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,11 +1,13 @@ # 🚀 版本日志 -## 2.10.29 +## 2.10.29 (2023-03-10) ### 🐣 新增功能 1. 【server】新增 导入仓库支持 `gitea` 系统 (感谢 [@Smith](https://gitee.com/autools) [Gitee pr 173](https://gitee.com/dromara/Jpom/pulls/173) ) +2. 【server】新增 用户登录日志(取消用户登录生成操作日志的执行日志) +3. 【server】新增 在线工具验证 cron 表达式 (感谢@奇奇) ### 🐞 解决BUG、优化功能 @@ -14,6 +16,12 @@ 3. 【agent】优化 节点分发配置白名单到插件端需要验证合法性 4. 【server】优化 docker 创建容器忽略未配置存储选项参数(感谢@D¹⁹⁹¹) 5. 【server】优化 docker 管理裁剪功能独立菜单 +6. 【server】修复 资产管理未记录操作日志的问题 +7. 【server】优化 操作日志存储用户名、工作空间名字段 +8. 【server】优化 容器构建查询可用标签容器相关提示 +9. 【server】优化 构建历史列表页面在小屏幕数据显示不全 + (感谢 [@一只羊](https://gitee.com/hjdyzy) [Gitee issues I6LLA0](https://gitee.com/dromara/Jpom/issues/I6LLA0) ) +10. 【server】修复 在线构建发布到集群无法正常选择集群服务(感谢@心光) ------ diff --git a/docs/version.txt b/docs/version.txt index 540c2f7a8..60e26ba4b 100644 --- a/docs/version.txt +++ b/docs/version.txt @@ -1 +1 @@ -2.10.28 +2.10.29 diff --git a/modules/agent-transport/agent-transport-common/pom.xml b/modules/agent-transport/agent-transport-common/pom.xml index 0565116c4..e6e6aa3c1 100644 --- a/modules/agent-transport/agent-transport-common/pom.xml +++ b/modules/agent-transport/agent-transport-common/pom.xml @@ -30,7 +30,7 @@ io.jpom.agent-transport jpom-agent-transport-parent - 2.10.28 + 2.10.29 ../pom.xml diff --git a/modules/agent-transport/agent-transport-http/pom.xml b/modules/agent-transport/agent-transport-http/pom.xml index 09c4e8116..45e191105 100644 --- a/modules/agent-transport/agent-transport-http/pom.xml +++ b/modules/agent-transport/agent-transport-http/pom.xml @@ -30,7 +30,7 @@ io.jpom.agent-transport jpom-agent-transport-parent - 2.10.28 + 2.10.29 ../pom.xml diff --git a/modules/agent-transport/pom.xml b/modules/agent-transport/pom.xml index 3f44ccb65..627a8f74f 100644 --- a/modules/agent-transport/pom.xml +++ b/modules/agent-transport/pom.xml @@ -29,7 +29,7 @@ jpom-parent io.jpom - 2.10.28 + 2.10.29 ../../pom.xml pom @@ -38,7 +38,7 @@ agent-transport-http 4.0.0 - 2.10.28 + 2.10.29 io.jpom.agent-transport jpom-agent-transport-parent Jpom Agent Transport diff --git a/modules/agent/pom.xml b/modules/agent/pom.xml index 4701a3eca..6ede08fca 100644 --- a/modules/agent/pom.xml +++ b/modules/agent/pom.xml @@ -29,12 +29,12 @@ jpom-parent io.jpom - 2.10.28 + 2.10.29 ../../pom.xml 4.0.0 agent - 2.10.28 + 2.10.29 Jpom Agent io.jpom.JpomAgentApplication diff --git a/modules/common/pom.xml b/modules/common/pom.xml index cacccc52d..e135e5e54 100644 --- a/modules/common/pom.xml +++ b/modules/common/pom.xml @@ -29,13 +29,13 @@ jpom-parent io.jpom - 2.10.28 + 2.10.29 ../../pom.xml 4.0.0 Jpom Common common - 2.10.28 + 2.10.29 diff --git a/modules/common/src/main/java/io/jpom/system/WebAopLog.java b/modules/common/src/main/java/io/jpom/system/WebAopLog.java index 3fb1d0ec9..be826ae25 100644 --- a/modules/common/src/main/java/io/jpom/system/WebAopLog.java +++ b/modules/common/src/main/java/io/jpom/system/WebAopLog.java @@ -53,7 +53,7 @@ public class WebAopLog { this.aopLogInterface = SpringUtil.getBeansOfType(AopLogInterface.class).values(); } - @Pointcut("execution(public * io.jpom.controller..*.*(..))") + @Pointcut("execution(public * io.jpom..*.*.controller..*.*(..))") public void webLog() { // } diff --git a/modules/common/src/main/resources/banner.txt b/modules/common/src/main/resources/banner.txt index d4997e008..2da801e5f 100644 --- a/modules/common/src/main/resources/banner.txt +++ b/modules/common/src/main/resources/banner.txt @@ -8,4 +8,4 @@ | | |_| - ➜ Jpom \ (•◡•) / (v2.10.28) + ➜ Jpom \ (•◡•) / (v2.10.29) diff --git a/modules/server/DockerfileRelease b/modules/server/DockerfileRelease index 7acf2333c..622dbcf55 100644 --- a/modules/server/DockerfileRelease +++ b/modules/server/DockerfileRelease @@ -29,7 +29,7 @@ LABEL maintainer="bwcx-jzy " LABEL documentation="https://jpom.top" ENV JPOM_HOME /usr/local/jpom-server -ENV JPOM_PKG_VERSION 2.10.28 +ENV JPOM_PKG_VERSION 2.10.29 ENV JPOM_PKG server-${JPOM_PKG_VERSION}-release.tar.gz ENV SHA1_NAME server-${JPOM_PKG_VERSION}-release.tar.gz.sha1 diff --git a/modules/server/pom.xml b/modules/server/pom.xml index 38d2c2e09..dcb0a8abe 100644 --- a/modules/server/pom.xml +++ b/modules/server/pom.xml @@ -29,13 +29,13 @@ jpom-parent io.jpom - 2.10.28 + 2.10.29 ../../pom.xml 4.0.0 Jpom Server server - 2.10.28 + 2.10.29 io.jpom.JpomServerApplication diff --git a/modules/server/src/main/java/io/jpom/build/BuildExecuteService.java b/modules/server/src/main/java/io/jpom/build/BuildExecuteService.java index 49a3d85e1..4f479eac2 100644 --- a/modules/server/src/main/java/io/jpom/build/BuildExecuteService.java +++ b/modules/server/src/main/java/io/jpom/build/BuildExecuteService.java @@ -753,11 +753,11 @@ public class BuildExecuteService { List dockerInfoModels = buildExecuteService .dockerInfoService .queryByTag(buildInfoModel.getWorkspaceId(), fromTag); - DockerInfoModel dockerInfoModel = CollUtil.getFirst(dockerInfoModels); - Assert.notNull(dockerInfoModel, "没有可用的 docker server"); - logRecorder.system("use docker {}", dockerInfoModel.getName()); + Map map = buildExecuteService.machineDockerServer.dockerParameter(dockerInfoModels); + Assert.notNull(map, fromTag + " 没有可用的 docker server"); + logRecorder.system("use docker {}", map.get("name")); String workingDir = "/home/jpom/"; - Map map = buildExecuteService.machineDockerServer.dockerParameter(dockerInfoModel); + map.put("runsOn", dockerYmlDsl.getRunsOn()); map.put("workingDir", workingDir); map.put("tempDir", JpomApplication.getInstance().getTempPath()); 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 7f1d1a091..0bb4f19e4 100644 --- a/modules/server/src/main/java/io/jpom/build/ReleaseManage.java +++ b/modules/server/src/main/java/io/jpom/build/ReleaseManage.java @@ -147,7 +147,7 @@ public class ReleaseManage { } else if (releaseMethod == BuildReleaseMethod.LocalCommand.getCode()) { return this.localCommand(); } else if (releaseMethod == BuildReleaseMethod.DockerImage.getCode()) { - this.doDockerImage(); + return this.doDockerImage(); } else if (releaseMethod == BuildReleaseMethod.No.getCode()) { return true; } else { @@ -199,7 +199,7 @@ public class ReleaseManage { }).collect(Collectors.joining(StrUtil.COMMA)); } - private void doDockerImage() { + private boolean doDockerImage() { // 生成临时目录 File tempPath = FileUtil.file(JpomApplication.getInstance().getTempPath(), "build_temp", "docker_image", this.buildExtraModule.getId() + StrUtil.DASHED + this.buildNumberId); try { @@ -221,7 +221,7 @@ public class ReleaseManage { File dockerfile = FileUtil.file(tempPath, dockerFile); if (!FileUtil.isFile(dockerfile)) { logRecorder.systemError("仓库目录下没有找到 Dockerfile 文件: {}", dockerFile); - return; + return false; } File baseDir = FileUtil.file(tempPath, list.size() == 1 ? StrUtil.SLASH : CollUtil.get(list, 0)); // @@ -230,10 +230,10 @@ public class ReleaseManage { List dockerInfoModels = buildExecuteService .dockerInfoService .queryByTag(this.buildExtraModule.getWorkspaceId(), fromTag); - DockerInfoModel dockerInfoModel = CollUtil.getFirst(dockerInfoModels); - if (dockerInfoModel == null) { - logRecorder.systemError("没有可用的 docker server"); - return; + Map map = buildExecuteService.machineDockerServer.dockerParameter(dockerInfoModels); + if (map == null) { + logRecorder.systemError("{} 没有可用的 docker server", fromTag); + return false; } //String dockerBuildArgs = this.buildExtraModule.getDockerBuildArgs(); for (DockerInfoModel infoModel : dockerInfoModels) { @@ -244,9 +244,7 @@ public class ReleaseManage { if (pushToRepository != null && pushToRepository) { List repositoryList = StrUtil.splitTrim(dockerTag, StrUtil.COMMA); for (String repositoryItem : repositoryList) { - logRecorder.system("start push to repository in({}),{} {}", dockerInfoModel.getName(), StrUtil.emptyToDefault(dockerInfoModel.getRegistryUrl(), StrUtil.EMPTY), repositoryItem); - Map map = buildExecuteService.machineDockerServer.dockerParameter(dockerInfoModel); - //dockerInfoModel.toParameter(); + logRecorder.system("start push to repository in({}),{} {}", map.get("name"), StrUtil.emptyToDefault((String) map.get("registryUrl"), StrUtil.EMPTY), repositoryItem); // map.put("repository", repositoryItem); Consumer logConsumer = s -> logRecorder.info(s); @@ -264,6 +262,7 @@ public class ReleaseManage { } finally { CommandUtil.systemFastDel(tempPath); } + return true; } private void updateSwarmService(String dockerTag, String swarmId, String serviceName) { diff --git a/modules/server/src/main/java/io/jpom/controller/LoginControl.java b/modules/server/src/main/java/io/jpom/controller/LoginControl.java index da5fca8f8..dfdbca4f5 100644 --- a/modules/server/src/main/java/io/jpom/controller/LoginControl.java +++ b/modules/server/src/main/java/io/jpom/controller/LoginControl.java @@ -43,12 +43,12 @@ import io.jpom.common.interceptor.NotLogin; import io.jpom.common.validator.ValidatorConfig; import io.jpom.common.validator.ValidatorItem; import io.jpom.common.validator.ValidatorRule; +import io.jpom.func.user.server.UserLoginLogServer; import io.jpom.model.data.WorkspaceModel; import io.jpom.model.dto.UserLoginDto; import io.jpom.model.user.UserModel; import io.jpom.permission.ClassFeature; import io.jpom.permission.Feature; -import io.jpom.permission.MethodFeature; import io.jpom.service.user.UserBindWorkspaceService; import io.jpom.service.user.UserService; import io.jpom.system.ServerConfig; @@ -89,14 +89,17 @@ public class LoginControl extends BaseServerController { private final UserBindWorkspaceService userBindWorkspaceService; private final ServerConfig.UserConfig userConfig; private final ServerConfig.WebConfig webConfig; + private final UserLoginLogServer userLoginLogServer; public LoginControl(UserService userService, UserBindWorkspaceService userBindWorkspaceService, - ServerConfig serverConfig) { + ServerConfig serverConfig, + UserLoginLogServer userLoginLogServer) { this.userService = userService; this.userBindWorkspaceService = userBindWorkspaceService; this.userConfig = serverConfig.getUser(); this.webConfig = serverConfig.getWeb(); + this.userLoginLogServer = userLoginLogServer; } /** @@ -155,31 +158,34 @@ public class LoginControl extends BaseServerController { /** * 登录接口 * - * @param userName 登录名 - * @param userPwd 登录密码 - * @param code 验证码 + * @param loginName 登录名 + * @param userPwd 登录密码 + * @param code 验证码 * @return json */ @PostMapping(value = "userLogin", produces = MediaType.APPLICATION_JSON_VALUE) @NotLogin - @Feature(method = MethodFeature.EXECUTE, resultCode = {200, 201}, logResponse = false) public JsonMessage userLogin( @ValidatorConfig(value = { @ValidatorItem(value = ValidatorRule.NOT_EMPTY, msg = "请输入登录信息") - }) String userName, + }) String loginName, @ValidatorConfig(value = { @ValidatorItem(value = ValidatorRule.NOT_EMPTY, msg = "请输入登录信息") }) String userPwd, - String code) { + String code, HttpServletRequest request) { if (this.ipLock()) { return new JsonMessage<>(400, "尝试次数太多,请稍后再来"); } - synchronized (userName.intern()) { - UserModel userModel = userService.getByKey(userName); + synchronized (loginName.intern()) { + UserModel userModel = userService.getByKey(loginName); if (userModel == null) { this.ipError(); return new JsonMessage<>(400, "登录失败,请输入正确的密码和账号,多次失败将锁定账号"); } + if (userModel.getStatus() != null && userModel.getStatus() == 0) { + userLoginLogServer.fail(userModel, 4, false, request); + return new JsonMessage<>(ServerConst.ACCOUNT_LOCKED, ServerConst.ACCOUNT_LOCKED_TIP); + } if (!webConfig.isDisabledGuide()) { // 获取验证码 String sCode = getSessionAttribute(LOGIN_CODE); @@ -193,27 +199,31 @@ public class LoginControl extends BaseServerController { String msg = DateUtil.formatBetween(lockTime * 1000, BetweenFormatter.Level.SECOND); updateModel = userModel.errorLock(userConfig.getAlwaysLoginError()); this.ipError(); + userLoginLogServer.fail(userModel, 2, false, request); return new JsonMessage<>(400, "该账户登录失败次数过多,已被锁定" + msg + ",请不要再次尝试"); } // 验证 - if (userService.simpleLogin(userName, userPwd) != null) { - updateModel = UserModel.unLock(userName); + if (userService.simpleLogin(loginName, userPwd) != null) { + updateModel = UserModel.unLock(loginName); this.ipSuccess(); // 判断是否开启 两步验证 - boolean bindMfa = userService.hasBindMfa(userName); + boolean bindMfa = userService.hasBindMfa(loginName); if (bindMfa) { // JSONObject jsonObject = new JSONObject(); String uuid = IdUtil.fastSimpleUUID(); - MFA_TOKEN.put(uuid, userName); + MFA_TOKEN.put(uuid, loginName); jsonObject.put("tempToken", uuid); + userLoginLogServer.success(userModel, 5, true, request); return new JsonMessage<>(201, "请输入两步验证码", jsonObject); } UserLoginDto userLoginDto = this.createToken(userModel); + userLoginLogServer.success(userModel, false, request); return new JsonMessage<>(200, "登录成功", userLoginDto); } else { updateModel = userModel.errorLock(userConfig.getAlwaysLoginError()); this.ipError(); + userLoginLogServer.fail(userModel, 1, false, request); return new JsonMessage<>(501, "登录失败,请输入正确的密码和账号,多次失败将锁定账号"); } } finally { @@ -240,7 +250,7 @@ public class LoginControl extends BaseServerController { @GetMapping(value = "mfa_verify", produces = MediaType.APPLICATION_JSON_VALUE) @NotLogin - public JsonMessage mfaVerify(String token, String code) { + public JsonMessage mfaVerify(String token, String code, HttpServletRequest request) { String userId = MFA_TOKEN.get(token); if (StrUtil.isEmpty(userId)) { return new JsonMessage<>(201, "登录信息已经过期请重新登录"); @@ -251,6 +261,7 @@ public class LoginControl extends BaseServerController { // UserLoginDto userLoginDto = this.createToken(userModel); MFA_TOKEN.remove(token); + userLoginLogServer.success(userModel, true, request); return JsonMessage.success("登录成功", userLoginDto); } @@ -290,6 +301,7 @@ public class LoginControl extends BaseServerController { return new JsonMessage<>(ServerConst.AUTHORIZE_TIME_OUT_CODE, "没有对应的用户"); } UserLoginDto userLoginDto = userService.getUserJwtId(userModel); + userLoginLogServer.success(userModel, 3, true, request); return JsonMessage.success("", userLoginDto); } diff --git a/modules/server/src/main/java/io/jpom/controller/ToolsController.java b/modules/server/src/main/java/io/jpom/controller/ToolsController.java new file mode 100644 index 000000000..a343ced1c --- /dev/null +++ b/modules/server/src/main/java/io/jpom/controller/ToolsController.java @@ -0,0 +1,75 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Code Technology Studio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package io.jpom.controller; + +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.cron.pattern.CronPatternUtil; +import io.jpom.common.JsonMessage; +import io.jpom.common.validator.ValidatorItem; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +/** + * @author bwcx_jzy + * @since 2023/3/10 + */ +@RestController +@RequestMapping(value = "/tools") +public class ToolsController { + + @GetMapping(value = "cron", produces = MediaType.APPLICATION_JSON_VALUE) + public JsonMessage> cron(@ValidatorItem String cron, @ValidatorItem int count, String date, boolean isMatchSecond) { + Date startDate = null; + Date endDate = null; + if (StrUtil.isNotEmpty(date)) { + List split = StrUtil.splitTrim(date, "~"); + try { + startDate = DateUtil.parse(split.get(0)); + startDate = DateUtil.beginOfDay(startDate); + endDate = DateUtil.parse(split.get(1)); + endDate = DateUtil.endOfDay(endDate); + } catch (Exception e) { + return new JsonMessage<>(405, "日期格式错误:" + e.getMessage()); + } + } + try { + List dateList; + if (startDate != null) { + dateList = CronPatternUtil.matchedDates(cron, startDate, endDate, count, isMatchSecond); + } else { + dateList = CronPatternUtil.matchedDates(cron, DateTime.now(), count, isMatchSecond); + } + return JsonMessage.success("", dateList.stream().map(Date::getTime).collect(Collectors.toList())); + } catch (Exception e) { + return new JsonMessage<>(405, "cron 表达式不正确," + e.getMessage()); + } + } +} 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 e735fb17c..1d07cfa2b 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 @@ -284,7 +284,7 @@ public class BuildInfoController extends BaseServerController { // String workspaceId = dockerInfoService.getCheckUserWorkspace(request); int count = dockerInfoService.countByTag(workspaceId, fromTag); - Assert.state(count > 0, "docker tag 填写不正确,没有找到任何docker"); + Assert.state(count > 0, fromTag + " 没有找到任何 docker。可能docker tag 填写不正确,需要为 docker 配置标签"); } } diff --git a/modules/server/src/main/java/io/jpom/controller/build/repository/GitHubUtil.java b/modules/server/src/main/java/io/jpom/controller/build/repository/GitHubUtil.java index 6ef0977c8..22baf55f5 100644 --- a/modules/server/src/main/java/io/jpom/controller/build/repository/GitHubUtil.java +++ b/modules/server/src/main/java/io/jpom/controller/build/repository/GitHubUtil.java @@ -1,3 +1,25 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Code Technology Studio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ package io.jpom.controller.build.repository; import cn.hutool.db.Page; diff --git a/modules/server/src/main/java/io/jpom/controller/build/repository/GitLabUtil.java b/modules/server/src/main/java/io/jpom/controller/build/repository/GitLabUtil.java index 7e8b5a109..ce8adda6d 100644 --- a/modules/server/src/main/java/io/jpom/controller/build/repository/GitLabUtil.java +++ b/modules/server/src/main/java/io/jpom/controller/build/repository/GitLabUtil.java @@ -1,3 +1,25 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Code Technology Studio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ package io.jpom.controller.build.repository; import cn.hutool.core.convert.Convert; diff --git a/modules/server/src/main/java/io/jpom/controller/build/repository/GiteaUtil.java b/modules/server/src/main/java/io/jpom/controller/build/repository/GiteaUtil.java index 39cc9ea49..bbae0c531 100644 --- a/modules/server/src/main/java/io/jpom/controller/build/repository/GiteaUtil.java +++ b/modules/server/src/main/java/io/jpom/controller/build/repository/GiteaUtil.java @@ -1,3 +1,25 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Code Technology Studio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ package io.jpom.controller.build.repository; import cn.hutool.core.convert.Convert; diff --git a/modules/server/src/main/java/io/jpom/controller/build/repository/GiteeUtil.java b/modules/server/src/main/java/io/jpom/controller/build/repository/GiteeUtil.java index 7c68311a5..fdedd7bfe 100644 --- a/modules/server/src/main/java/io/jpom/controller/build/repository/GiteeUtil.java +++ b/modules/server/src/main/java/io/jpom/controller/build/repository/GiteeUtil.java @@ -1,3 +1,25 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Code Technology Studio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ package io.jpom.controller.build.repository; import cn.hutool.core.convert.Convert; diff --git a/modules/server/src/main/java/io/jpom/controller/user/UserBasicInfoController.java b/modules/server/src/main/java/io/jpom/controller/user/UserBasicInfoController.java index 1db2de978..df9b4681a 100644 --- a/modules/server/src/main/java/io/jpom/controller/user/UserBasicInfoController.java +++ b/modules/server/src/main/java/io/jpom/controller/user/UserBasicInfoController.java @@ -33,10 +33,16 @@ import io.jpom.common.JsonMessage; import io.jpom.common.interceptor.PermissionInterceptor; import io.jpom.common.validator.ValidatorItem; import io.jpom.common.validator.ValidatorRule; +import io.jpom.func.user.model.UserLoginLogModel; +import io.jpom.func.user.server.UserLoginLogServer; import io.jpom.model.data.MailAccountModel; import io.jpom.model.data.WorkspaceModel; +import io.jpom.model.log.UserOperateLogV1; import io.jpom.model.user.UserModel; import io.jpom.monitor.EmailUtil; +import io.jpom.permission.Feature; +import io.jpom.permission.MethodFeature; +import io.jpom.service.dblog.DbUserOperateLogService; import io.jpom.service.system.SystemParametersServer; import io.jpom.service.user.UserBindWorkspaceService; import io.jpom.service.user.UserService; @@ -49,7 +55,9 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; +import top.jpom.model.PageResultDto; +import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -71,15 +79,21 @@ public class UserBasicInfoController extends BaseServerController { private final UserBindWorkspaceService userBindWorkspaceService; private final UserService userService; private final ServerConfig.UserConfig userConfig; + private final UserLoginLogServer userLoginLogServer; + private final DbUserOperateLogService dbUserOperateLogService; public UserBasicInfoController(SystemParametersServer systemParametersServer, UserBindWorkspaceService userBindWorkspaceService, UserService userService, - ServerConfig serverConfig) { + ServerConfig serverConfig, + UserLoginLogServer userLoginLogServer, + DbUserOperateLogService dbUserOperateLogService) { this.systemParametersServer = systemParametersServer; this.userBindWorkspaceService = userBindWorkspaceService; this.userService = userService; this.userConfig = serverConfig.getUser(); + this.userLoginLogServer = userLoginLogServer; + this.dbUserOperateLogService = dbUserOperateLogService; } @@ -221,4 +235,30 @@ public class UserBasicInfoController extends BaseServerController { userService.bindMfa(user.getId(), mfa); return JsonMessage.success("绑定成功"); } + + /** + * 登录日志列表 + * + * @return json + */ + @RequestMapping(value = "list-login-log-data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) + @Feature(method = MethodFeature.LIST) + public JsonMessage> listLoginLogData(HttpServletRequest request) { + UserModel user = getUser(); + PageResultDto pageResult = userLoginLogServer.listPageByUserId(request, user.getId()); + return JsonMessage.success("", pageResult); + } + + /** + * 操作日志 + * + * @return json + */ + @RequestMapping(value = "list-operate-log-data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) + @Feature(method = MethodFeature.LIST) + public JsonMessage> listOperateLogData(HttpServletRequest request) { + UserModel user = getUser(); + PageResultDto pageResult = dbUserOperateLogService.listPageByUserId(request, user.getId()); + return JsonMessage.success("", pageResult); + } } diff --git a/modules/server/src/main/java/io/jpom/controller/user/UserOptLogController.java b/modules/server/src/main/java/io/jpom/controller/user/UserOptLogController.java index b70adceb8..9d9314aa9 100644 --- a/modules/server/src/main/java/io/jpom/controller/user/UserOptLogController.java +++ b/modules/server/src/main/java/io/jpom/controller/user/UserOptLogController.java @@ -36,6 +36,8 @@ import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RestController; import top.jpom.model.PageResultDto; +import javax.servlet.http.HttpServletRequest; + /** * 用户操作日志 * @@ -61,8 +63,8 @@ public class UserOptLogController extends BaseServerController { */ @RequestMapping(value = "list_data.json", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) @Feature(method = MethodFeature.LIST) - public JsonMessage> listData() { - PageResultDto pageResult = dbUserOperateLogService.listPage(getRequest()); - return JsonMessage.success("获取成功", pageResult); + public JsonMessage> listData(HttpServletRequest request) { + PageResultDto pageResult = dbUserOperateLogService.listPage(request); + return JsonMessage.success("", pageResult); } } diff --git a/modules/server/src/main/java/io/jpom/func/assets/model/MachineDockerModel.java b/modules/server/src/main/java/io/jpom/func/assets/model/MachineDockerModel.java index 248765834..be4a0680f 100644 --- a/modules/server/src/main/java/io/jpom/func/assets/model/MachineDockerModel.java +++ b/modules/server/src/main/java/io/jpom/func/assets/model/MachineDockerModel.java @@ -156,7 +156,7 @@ public class MachineDockerModel extends BaseGroupNameModel { public Map toParameter() { Map parameter = new HashMap<>(10); parameter.put("dockerHost", this.getHost()); -// parameter.put("apiVersion", this.getApiVersion()); + parameter.put("name", this.getName()); parameter.put("registryUsername", this.getRegistryUsername()); parameter.put("registryPassword", this.getRegistryPassword()); parameter.put("registryEmail", this.getRegistryEmail()); diff --git a/modules/server/src/main/java/io/jpom/func/assets/server/MachineDockerServer.java b/modules/server/src/main/java/io/jpom/func/assets/server/MachineDockerServer.java index 7ff83c6b4..ec9a07286 100644 --- a/modules/server/src/main/java/io/jpom/func/assets/server/MachineDockerServer.java +++ b/modules/server/src/main/java/io/jpom/func/assets/server/MachineDockerServer.java @@ -270,6 +270,29 @@ public class MachineDockerServer extends BaseDbService imple return machineDockerModel.toParameter(); } + /** + * 跟进 docker 列表找到一个可用的 docker 信息 + * + * @param dockerInfoModels docker 列表 + * @return map + */ + public Map dockerParameter(List dockerInfoModels) { + for (DockerInfoModel dockerInfoModel : dockerInfoModels) { + String machineDockerId = dockerInfoModel.getMachineDockerId(); + MachineDockerModel machineDockerModel = this.getByKey(machineDockerId, false); + if (machineDockerModel != null) { + Integer status = machineDockerModel.getStatus(); + if (status != null && status == 1) { + Map parameter = machineDockerModel.toParameter(); + // 更新名称 + parameter.put("name", dockerInfoModel.getName()); + return parameter; + } + } + } + return null; + } + /** * 通过集群 id 获取 docker 管理参数 * @@ -300,6 +323,9 @@ public class MachineDockerServer extends BaseDbService imple } public MachineDockerModel tryMachineDockerBySwarmId(String swarmId) { + if (StrUtil.isEmpty(swarmId)) { + return null; + } // MachineDockerModel dockerInfoModel = new MachineDockerModel(); dockerInfoModel.setSwarmId(swarmId); diff --git a/modules/server/src/main/java/io/jpom/func/user/controller/UserLoginLogController.java b/modules/server/src/main/java/io/jpom/func/user/controller/UserLoginLogController.java new file mode 100644 index 000000000..fe96065ec --- /dev/null +++ b/modules/server/src/main/java/io/jpom/func/user/controller/UserLoginLogController.java @@ -0,0 +1,68 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Code Technology Studio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package io.jpom.func.user.controller; + +import io.jpom.common.BaseServerController; +import io.jpom.common.JsonMessage; +import io.jpom.func.user.model.UserLoginLogModel; +import io.jpom.func.user.server.UserLoginLogServer; +import io.jpom.permission.ClassFeature; +import io.jpom.permission.Feature; +import io.jpom.permission.MethodFeature; +import io.jpom.permission.SystemPermission; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.springframework.web.bind.annotation.RestController; +import top.jpom.model.PageResultDto; + +import javax.servlet.http.HttpServletRequest; + +/** + * @author bwcx_jzy + * @since 2023/3/9 + */ +@RestController +@RequestMapping(value = "/user/login-log") +@Feature(cls = ClassFeature.USER_LOGIN_LOG) +@SystemPermission +public class UserLoginLogController extends BaseServerController { + + private final UserLoginLogServer userLoginLogServer; + + public UserLoginLogController(UserLoginLogServer userLoginLogServer) { + this.userLoginLogServer = userLoginLogServer; + } + + /** + * 登录日志列表 + * + * @return json + */ + @RequestMapping(value = "list-data", method = RequestMethod.POST, produces = MediaType.APPLICATION_JSON_VALUE) + @Feature(method = MethodFeature.LIST) + public JsonMessage> listData(HttpServletRequest request) { + PageResultDto pageResult = userLoginLogServer.listPage(request); + return JsonMessage.success("", pageResult); + } +} diff --git a/modules/server/src/main/java/io/jpom/func/user/model/UserLoginLogModel.java b/modules/server/src/main/java/io/jpom/func/user/model/UserLoginLogModel.java new file mode 100644 index 000000000..662add597 --- /dev/null +++ b/modules/server/src/main/java/io/jpom/func/user/model/UserLoginLogModel.java @@ -0,0 +1,77 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Code Technology Studio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package io.jpom.func.user.model; + +import io.jpom.model.BaseUserModifyDbModel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; +import top.jpom.h2db.TableName; + +/** + * @author bwcx_jzy + * @since 2023/3/9 + */ +@EqualsAndHashCode(callSuper = true) +@TableName(value = "USER_LOGIN_LOG", name = "用户登录日志") +@Data +@NoArgsConstructor +public class UserLoginLogModel extends BaseUserModifyDbModel { + + /** + * 操作ip + */ + private String ip; + + /** + * 用户名称 + */ + private String username; + + /** + * 浏览器标识 + */ + private String userAgent; + + /** + * 是否使用 mfa + */ + private Boolean useMfa; + + /** + * 是否成功 + */ + private Boolean success; + + /** + * 错误原因 + *

+ * 0 正常登录 + * 1 密码错误 + * 2 被锁定 + * 3 续期 + * 4 账号被禁用 + * 5 登录成功,但是需要 mfa 验证 + */ + private Integer operateCode; +} diff --git a/modules/server/src/main/java/io/jpom/func/user/server/UserLoginLogServer.java b/modules/server/src/main/java/io/jpom/func/user/server/UserLoginLogServer.java new file mode 100644 index 000000000..1327f237d --- /dev/null +++ b/modules/server/src/main/java/io/jpom/func/user/server/UserLoginLogServer.java @@ -0,0 +1,111 @@ +/* + * The MIT License (MIT) + * + * Copyright (c) 2019 Code Technology Studio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package io.jpom.func.user.server; + +import cn.hutool.core.util.CharsetUtil; +import cn.hutool.extra.servlet.ServletUtil; +import cn.hutool.http.Header; +import io.jpom.func.user.model.UserLoginLogModel; +import io.jpom.model.user.UserModel; +import io.jpom.service.h2db.BaseDbService; +import org.springframework.stereotype.Service; +import top.jpom.model.PageResultDto; + +import javax.servlet.http.HttpServletRequest; +import java.util.Map; + +/** + * @author bwcx_jzy + * @since 2023/3/9 + */ +@Service +public class UserLoginLogServer extends BaseDbService { + + + /** + * 查询指定用户的登录日志 + * + * @param request 请求信息 + * @param userId 用户id + * @return page + */ + public PageResultDto listPageByUserId(HttpServletRequest request, String userId) { + Map paramMap = ServletUtil.getParamMap(request); + paramMap.put("modifyUser", userId); + return super.listPage(paramMap); + } + + /** + * 记录登录日志 + * + * @param userModel 用户 + * @param success 是否成功 + * @param useMfa 是否使用 mfa + * @param request 请求信息 + */ + public void log(UserModel userModel, boolean success, boolean useMfa, int operateCode, HttpServletRequest request) { + UserLoginLogModel userLoginLogModel = new UserLoginLogModel(); + userLoginLogModel.setModifyUser(userModel.getId()); + userLoginLogModel.setUsername(userModel.getName()); + userLoginLogModel.setSuccess(success); + userLoginLogModel.setUseMfa(useMfa); + userLoginLogModel.setOperateCode(operateCode); + userLoginLogModel.setIp(ServletUtil.getClientIP(request)); + userLoginLogModel.setUserAgent(ServletUtil.getHeader(request, Header.USER_AGENT.getValue(), CharsetUtil.CHARSET_UTF_8)); + this.insert(userLoginLogModel); + } + + /** + * 记录登录日志 + * + * @param userModel 用户 + * @param useMfa 是否使用 mfa + * @param request 请求信息 + */ + public void success(UserModel userModel, boolean useMfa, HttpServletRequest request) { + this.success(userModel, 0, useMfa, request); + } + + /** + * 记录登录日志 + * + * @param userModel 用户 + * @param useMfa 是否使用 mfa + * @param request 请求信息 + */ + public void success(UserModel userModel, int code, boolean useMfa, HttpServletRequest request) { + this.log(userModel, true, useMfa, code, request); + } + + /** + * 记录登录日志 + * + * @param userModel 用户 + * @param useMfa 是否使用 mfa + * @param code 错误码 + * @param request 请求信息 + */ + public void fail(UserModel userModel, int code, boolean useMfa, HttpServletRequest request) { + this.log(userModel, false, useMfa, code, request); + } +} diff --git a/modules/server/src/main/java/io/jpom/model/log/UserOperateLogV1.java b/modules/server/src/main/java/io/jpom/model/log/UserOperateLogV1.java index 843bcda5f..6f3b78ef1 100644 --- a/modules/server/src/main/java/io/jpom/model/log/UserOperateLogV1.java +++ b/modules/server/src/main/java/io/jpom/model/log/UserOperateLogV1.java @@ -61,12 +61,6 @@ public class UserOperateLogV1 extends BaseWorkspaceModel { * 完整消息 */ private String resultMsg; - /** - * 操作id - * 用于socket 回话回调更新 - */ - @Deprecated - private String reqId; /** * 请求参数 */ @@ -86,10 +80,10 @@ public class UserOperateLogV1 extends BaseWorkspaceModel { private String classFeature; private String methodFeature; + /** + * 工作空间名称 + */ + private String workspaceName; - @Override - public void setId(String id) { - super.setId(id); - this.setReqId(id); - } + private String username; } diff --git a/modules/server/src/main/java/io/jpom/permission/ClassFeature.java b/modules/server/src/main/java/io/jpom/permission/ClassFeature.java index c3bcbe903..a3940dde9 100644 --- a/modules/server/src/main/java/io/jpom/permission/ClassFeature.java +++ b/modules/server/src/main/java/io/jpom/permission/ClassFeature.java @@ -22,6 +22,10 @@ */ package io.jpom.permission; +import io.jpom.func.assets.server.MachineDockerServer; +import io.jpom.func.assets.server.MachineNodeServer; +import io.jpom.func.assets.server.MachineSshServer; +import io.jpom.func.user.server.UserLoginLogServer; import io.jpom.service.dblog.*; import io.jpom.service.docker.DockerInfoService; import io.jpom.service.docker.DockerSwarmInfoService; @@ -84,14 +88,15 @@ public enum ClassFeature { BUILD_REPOSITORY("仓库信息", RepositoryService.class), USER("用户管理", UserService.class), USER_LOG("操作日志", DbUserOperateLogService.class), + USER_LOGIN_LOG("登录日志", UserLoginLogServer.class), USER_PERMISSION_GROUP("权限分组", UserPermissionGroupServer.class), SYSTEM_EMAIL("邮箱配置"), SYSTEM_CACHE("系统缓存"), SYSTEM_LOG("系统日志"), SYSTEM_UPGRADE("在线升级"), - SYSTEM_ASSETS_MACHINE("机器资产管理"), - SYSTEM_ASSETS_MACHINE_SSH("SSH资产管理"), - SYSTEM_ASSETS_MACHINE_DOCKER("DOCKER资产管理"), + SYSTEM_ASSETS_MACHINE("机器资产管理", MachineNodeServer.class), + SYSTEM_ASSETS_MACHINE_SSH("SSH资产管理", MachineSshServer.class), + SYSTEM_ASSETS_MACHINE_DOCKER("DOCKER资产管理", MachineDockerServer.class), SYSTEM_CONFIG("服务端系统配置"), SYSTEM_EXT_CONFIG("系统配置目录"), SYSTEM_CONFIG_IP("系统配置IP白名单"), diff --git a/modules/server/src/main/java/io/jpom/permission/Feature.java b/modules/server/src/main/java/io/jpom/permission/Feature.java index c256fa05d..fbbb4c6ad 100644 --- a/modules/server/src/main/java/io/jpom/permission/Feature.java +++ b/modules/server/src/main/java/io/jpom/permission/Feature.java @@ -49,13 +49,6 @@ public @interface Feature { */ MethodFeature method() default MethodFeature.NULL; - /** - * 只记录哪些 状态码 - * - * @return code - */ - int[] resultCode() default {}; - /** * 是否记录响应 日志 * diff --git a/modules/server/src/main/java/io/jpom/service/dblog/DbUserOperateLogService.java b/modules/server/src/main/java/io/jpom/service/dblog/DbUserOperateLogService.java index ae8488fb0..e9bc375fa 100644 --- a/modules/server/src/main/java/io/jpom/service/dblog/DbUserOperateLogService.java +++ b/modules/server/src/main/java/io/jpom/service/dblog/DbUserOperateLogService.java @@ -80,6 +80,19 @@ public class DbUserOperateLogService extends BaseWorkspaceService listPageByUserId(HttpServletRequest request, String userId) { + Map paramMap = ServletUtil.getParamMap(request); + paramMap.put("userId", userId); + return super.listPage(paramMap); + } + /** * 根据 数据ID 和 节点ID 查询相关数据名称 * @@ -247,6 +260,19 @@ public class DbUserOperateLogService extends BaseWorkspaceService { + // 更新用户名和工作空间名 + try { + UserOperateLogV1 update = new UserOperateLogV1(); + update.setId(userOperateLogV1.getId()); + UserModel userModel = userService.getByKey(userOperateLogV1.getUserId()); + Optional.ofNullable(userModel).ifPresent(userModel1 -> update.setUsername(userModel1.getName())); + WorkspaceModel workspaceModel = workspaceService.getByKey(userOperateLogV1.getWorkspaceId()); + Optional.ofNullable(workspaceModel).ifPresent(workspaceModel1 -> update.setWorkspaceName(workspaceModel1.getName())); + this.update(update); + } catch (Exception e) { + log.error("更新操作日志失败", e); + } + // 检查操作监控 try { Map monitor = this.checkMonitor(userOperateLogV1, cacheInfo); if (monitor != null) { diff --git a/modules/server/src/main/java/io/jpom/service/user/TriggerTokenLogServer.java b/modules/server/src/main/java/io/jpom/service/user/TriggerTokenLogServer.java index 336896139..2f0750453 100644 --- a/modules/server/src/main/java/io/jpom/service/user/TriggerTokenLogServer.java +++ b/modules/server/src/main/java/io/jpom/service/user/TriggerTokenLogServer.java @@ -132,7 +132,7 @@ public class TriggerTokenLogServer extends BaseDbService im * @param userId 用户ID * @return token */ - public String createToken(String type, String dataId, String userId) { + private String createToken(String type, String dataId, String userId) { TriggerTokenLogBean trigger = new TriggerTokenLogBean(); String uuid = IdUtil.fastSimpleUUID(); trigger.setId(uuid); diff --git a/modules/server/src/main/java/io/jpom/system/init/OperateLogController.java b/modules/server/src/main/java/io/jpom/system/init/OperateLogController.java index 862e56d29..703de41fe 100644 --- a/modules/server/src/main/java/io/jpom/system/init/OperateLogController.java +++ b/modules/server/src/main/java/io/jpom/system/init/OperateLogController.java @@ -24,7 +24,6 @@ package io.jpom.system.init; import cn.hutool.core.date.SystemClock; import cn.hutool.core.exceptions.ExceptionUtil; -import cn.hutool.core.util.ArrayUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import cn.hutool.db.Entity; @@ -109,10 +108,8 @@ public class OperateLogController implements AopLogInterface { cacheInfo.setClassFeature(classFeature); cacheInfo.setMethodFeature(methodFeature); cacheInfo.setOptTime(SystemClock.now()); - cacheInfo.setResultCode(feature.resultCode()); cacheInfo.setLogResponse(feature.logResponse()); // - return cacheInfo; } @@ -235,11 +232,6 @@ public class OperateLogController implements AopLogInterface { try { JsonMessage jsonMessage = JSONObject.parseObject(json, JsonMessage.class); int code = jsonMessage.getCode(); - int[] resultCode = cacheInfo.getResultCode(); - if (ArrayUtil.isNotEmpty(resultCode) && !ArrayUtil.contains(resultCode, code)) { - // 忽略 - return; - } userOperateLogV1.setOptStatus(code); } catch (Exception ignored) { } @@ -301,7 +293,6 @@ public class OperateLogController implements AopLogInterface { private String dataId; private String userAgent; private String reqData; - private int[] resultCode; private Boolean logResponse; /** * 操作到数据到名称相关 map diff --git a/modules/server/src/main/resources/menus/index.json b/modules/server/src/main/resources/menus/index.json index bb306cba0..8d8c15ac4 100644 --- a/modules/server/src/main/resources/menus/index.json +++ b/modules/server/src/main/resources/menus/index.json @@ -136,5 +136,16 @@ "title": "操作监控" } ] + }, + { + "title": "在线工具", + "icon_v3": "tool", + "id": "tools", + "childs": [ + { + "id": "cronTools", + "title": "Cron表达式" + } + ] } ] diff --git a/modules/server/src/main/resources/menus/system.json b/modules/server/src/main/resources/menus/system.json index 5ace8d4e8..c822abfe9 100644 --- a/modules/server/src/main/resources/menus/system.json +++ b/modules/server/src/main/resources/menus/system.json @@ -57,6 +57,11 @@ "id": "user_log", "title": "操作日志", "role": "system" + }, + { + "id": "user_login_log", + "title": "登录日志", + "role": "system" } ] }, 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 27670bf7f..107b083dd 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 @@ -12,4 +12,7 @@ DROP,DOCKER_SWARM_INFO,status, DROP,DOCKER_SWARM_INFO,failureMsg, DROP,DOCKER_INFO,status DROP,DOCKER_INFO,failureMsg -ADD,MACHINE_NODE_INFO,transportEncryption,TINYINT,,,传输加密方式 0 不加密 1 BASE64 2 AES +DROP,USEROPERATELOGV1,reqId +ADD,USEROPERATELOGV1,workspaceName,String,50,,工作空间名 +ADD,USEROPERATELOGV1,username,String,50,,用户名 +ADD,MACHINE_NODE_INFO,transportEncryption,TINYINT,,,传输加密方式 0 不加密 1 BASE64 2 AES \ No newline at end of file diff --git a/modules/server/src/main/resources/sql-view/table.all.v1.0.csv b/modules/server/src/main/resources/sql-view/table.all.v1.0.csv index 1dd0c5ac4..dbea27ef7 100644 --- a/modules/server/src/main/resources/sql-view/table.all.v1.0.csv +++ b/modules/server/src/main/resources/sql-view/table.all.v1.0.csv @@ -307,7 +307,6 @@ OUT_GIVING,status,Integer,,0,false,false,状态{0: 未分发; 1: 分发中; 2: OUT_GIVING,secondaryDirectory,String,200,,false,false,二级目录, OUT_GIVING,uploadCloseFirst,TINYINT,,0,false,false,是否清空旧包发布, USEROPERATELOGV1,id,String,50,,true,true,id,操作日志 -USEROPERATELOGV1,reqId,String,50,,false,false,请求ID, USEROPERATELOGV1,ip,String,80,,false,false,客户端IP地址, USEROPERATELOGV1,userId,String,30,,false,false,操作的用户ID, USEROPERATELOGV1,resultMsg,TEXT,,,false,false,操作的结果信息, diff --git a/modules/server/src/main/resources/sql-view/table.all.v1.1.csv b/modules/server/src/main/resources/sql-view/table.all.v1.1.csv index 569aa9753..dc0a73dda 100644 --- a/modules/server/src/main/resources/sql-view/table.all.v1.1.csv +++ b/modules/server/src/main/resources/sql-view/table.all.v1.1.csv @@ -84,3 +84,13 @@ MACHINE_DOCKER_INFO,registryUsername,String,255,,false,false,仓库账号, MACHINE_DOCKER_INFO,registryPassword,String,255,,false,false,仓库密码, MACHINE_DOCKER_INFO,registryEmail,String,255,,false,false,仓库邮箱, MACHINE_DOCKER_INFO,registryUrl,String,255,,false,false,仓库地址, +USER_LOGIN_LOG,id,String,50,,true,true,id,用户登录日志 +USER_LOGIN_LOG,createTimeMillis,Long,,,false,false,数据创建时间, +USER_LOGIN_LOG,modifyTimeMillis,Long,,,false,false,数据修改时间, +USER_LOGIN_LOG,modifyUser,String,50,,false,false,修改人, +USER_LOGIN_LOG,ip,String,80,,false,false,客户端IP地址, +USER_LOGIN_LOG,userAgent,TEXT,,,false,false,浏览器标识, +USER_LOGIN_LOG,useMfa,TINYINT,,,false,false,是否使用 mfa, +USER_LOGIN_LOG,success,TINYINT,,,false,false,是否登录成功, +USER_LOGIN_LOG,operateCode,TINYINT,,,false,false,操作状态码(备注码), +USER_LOGIN_LOG,username,String,50,,false,false,昵称, diff --git a/modules/server/src/test/java/TestCron.java b/modules/server/src/test/java/TestCron.java index 58139f61c..e4fda068d 100644 --- a/modules/server/src/test/java/TestCron.java +++ b/modules/server/src/test/java/TestCron.java @@ -20,7 +20,17 @@ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +import cn.hutool.core.date.DatePattern; +import cn.hutool.core.date.DateTime; +import cn.hutool.core.date.DateUtil; import cn.hutool.cron.CronUtil; +import cn.hutool.cron.pattern.CronPattern; +import cn.hutool.cron.pattern.CronPatternUtil; +import org.junit.Test; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; /** * Created by jiangzeyin on 2019/3/4. @@ -36,4 +46,25 @@ public class TestCron { CronUtil.restart(); // System.out.println(JpomApplicationEvent.getPid()); } + + @Test + public void test() { + String cron = "0 0 23 ? * 5 "; + + CronPattern cronPattern = CronPattern.of(cron); + +// Date date = CronPatternUtil.nextDateAfter(cronPattern, DateUtil.offsetDay(DateTime.now(), -1), false); + + List dateList = CronPatternUtil.matchedDates(cron, DateUtil.offsetDay(DateTime.now(), -1), 10, true); + for (Date date1 : dateList) { + System.out.println(DateUtil.format(date1, DatePattern.NORM_DATETIME_FORMAT)); + } + + } + + @Test + public void test2() { + Calendar calendar = DateTime.now().toCalendar(); + System.out.println(calendar.get(Calendar.DAY_OF_WEEK) - 1); + } } diff --git a/modules/storage-module/pom.xml b/modules/storage-module/pom.xml index 931c7c28a..aa3602615 100644 --- a/modules/storage-module/pom.xml +++ b/modules/storage-module/pom.xml @@ -29,7 +29,7 @@ jpom-parent io.jpom - 2.10.28 + 2.10.29 ../../pom.xml pom @@ -39,7 +39,7 @@ storage-module-mysql 4.0.0 - 2.10.28 + 2.10.29 io.jpom.storage-module jpom-storage-module-parent Jpom storage module diff --git a/modules/storage-module/storage-module-common/pom.xml b/modules/storage-module/storage-module-common/pom.xml index a68209a12..fe3b2018b 100644 --- a/modules/storage-module/storage-module-common/pom.xml +++ b/modules/storage-module/storage-module-common/pom.xml @@ -30,7 +30,7 @@ io.jpom.storage-module jpom-storage-module-parent - 2.10.28 + 2.10.29 ../pom.xml diff --git a/modules/storage-module/storage-module-h2/pom.xml b/modules/storage-module/storage-module-h2/pom.xml index 99b890637..a64a6ed5a 100644 --- a/modules/storage-module/storage-module-h2/pom.xml +++ b/modules/storage-module/storage-module-h2/pom.xml @@ -30,7 +30,7 @@ io.jpom.storage-module jpom-storage-module-parent - 2.10.28 + 2.10.29 ../pom.xml diff --git a/modules/storage-module/storage-module-mysql/pom.xml b/modules/storage-module/storage-module-mysql/pom.xml index 03cfa1fd3..50c0facb7 100644 --- a/modules/storage-module/storage-module-mysql/pom.xml +++ b/modules/storage-module/storage-module-mysql/pom.xml @@ -30,7 +30,7 @@ io.jpom.storage-module jpom-storage-module-parent - 2.10.28 + 2.10.29 ../pom.xml diff --git a/modules/sub-plugin/docker-cli/pom.xml b/modules/sub-plugin/docker-cli/pom.xml index 60e526878..fa5ae19ca 100644 --- a/modules/sub-plugin/docker-cli/pom.xml +++ b/modules/sub-plugin/docker-cli/pom.xml @@ -29,7 +29,7 @@ jpom-plugins-parent io.jpom.plugins - 2.10.28 + 2.10.29 ../pom.xml 4.0.0 diff --git a/modules/sub-plugin/email/pom.xml b/modules/sub-plugin/email/pom.xml index 813f983fe..207c9bb77 100644 --- a/modules/sub-plugin/email/pom.xml +++ b/modules/sub-plugin/email/pom.xml @@ -29,7 +29,7 @@ jpom-plugins-parent io.jpom.plugins - 2.10.28 + 2.10.29 ../pom.xml 4.0.0 diff --git a/modules/sub-plugin/git-clone/pom.xml b/modules/sub-plugin/git-clone/pom.xml index 94b0daa61..33bd4ac94 100644 --- a/modules/sub-plugin/git-clone/pom.xml +++ b/modules/sub-plugin/git-clone/pom.xml @@ -29,7 +29,7 @@ jpom-plugins-parent io.jpom.plugins - 2.10.28 + 2.10.29 ../pom.xml 4.0.0 diff --git a/modules/sub-plugin/pom.xml b/modules/sub-plugin/pom.xml index 84200a21a..4fa3ccbdb 100644 --- a/modules/sub-plugin/pom.xml +++ b/modules/sub-plugin/pom.xml @@ -29,7 +29,7 @@ jpom-parent io.jpom - 2.10.28 + 2.10.29 ../../pom.xml pom @@ -42,7 +42,7 @@ encrypt 4.0.0 - 2.10.28 + 2.10.29 io.jpom.plugins jpom-plugins-parent Jpom Plugins diff --git a/modules/sub-plugin/svn-clone/pom.xml b/modules/sub-plugin/svn-clone/pom.xml index dfde96d74..4a7b2e834 100644 --- a/modules/sub-plugin/svn-clone/pom.xml +++ b/modules/sub-plugin/svn-clone/pom.xml @@ -29,7 +29,7 @@ jpom-plugins-parent io.jpom.plugins - 2.10.28 + 2.10.29 ../pom.xml 4.0.0 diff --git a/modules/sub-plugin/webhook/pom.xml b/modules/sub-plugin/webhook/pom.xml index dc2e307aa..aaa2a5e60 100644 --- a/modules/sub-plugin/webhook/pom.xml +++ b/modules/sub-plugin/webhook/pom.xml @@ -29,7 +29,7 @@ jpom-plugins-parent io.jpom.plugins - 2.10.28 + 2.10.29 ../pom.xml 4.0.0 diff --git a/modules/updater/pom.xml b/modules/updater/pom.xml index 4abc1efab..fcb2dc2a4 100644 --- a/modules/updater/pom.xml +++ b/modules/updater/pom.xml @@ -29,7 +29,7 @@ jpom-parent io.jpom - 2.10.28 + 2.10.29 ../../pom.xml 4.0.0 diff --git a/pom.xml b/pom.xml index f07b1759d..1de62fc46 100644 --- a/pom.xml +++ b/pom.xml @@ -50,7 +50,7 @@ 简而轻的低侵入式在线构建、自动部署、日常运维、项目监控软件 2017 - 2.10.28 + 2.10.29 https://gitee.com/dromara/Jpom UTF-8 diff --git a/script/docker.sh b/script/docker.sh index 256528ea0..a35407443 100644 --- a/script/docker.sh +++ b/script/docker.sh @@ -31,12 +31,12 @@ # docker buildx create --use # 服务端 -docker buildx build --platform linux/amd64,linux/arm64 -t jpomdocker/jpom:2.10.28 -t jpomdocker/jpom:latest -f ./modules/server/DockerfileRelease --push . +docker buildx build --platform linux/amd64,linux/arm64 -t jpomdocker/jpom:2.10.29 -t jpomdocker/jpom:latest -f ./modules/server/DockerfileRelease --push . # #docker buildx build --platform linux/amd64,linux/arm64 -t jpomdocker/jpom:latest -f ./modules/server/DockerfileRelease --push . # docker logs --tail="100" jpom-server -# docker run -d -p 2122:2122 --name jpom-server -v /etc/localtime:/etc/localtime:ro -v jpom-server-vol:/usr/local/jpom-server jpomdocker/jpom:mac-arm-2.10.28 +# docker run -d -p 2122:2122 --name jpom-server -v /etc/localtime:/etc/localtime:ro -v jpom-server-vol:/usr/local/jpom-server jpomdocker/jpom:mac-arm-2.10.29 # docker run -d -p 2122:2122 --name jpom-server -v D:/home/jpom-server/logs:/usr/local/jpom-server/logs -v D:/home/jpom-server/data:/usr/local/jpom-server/data -v D:/home/jpom-server/conf:/usr/local/jpom-server/conf jpomdocker/jpom # docker stop jpom-server # docker rm jpom-server diff --git a/script/release-sha1sum.sh b/script/release-sha1sum.sh index 3cb87228b..4fa76d90b 100644 --- a/script/release-sha1sum.sh +++ b/script/release-sha1sum.sh @@ -24,7 +24,7 @@ # 版本 -jpom_version=2.10.28 +jpom_version=2.10.29 #Mirror_Host=download.fastgit.org #Mirror_Host=hub.fastgit.xyz diff --git a/web-vue/package.json b/web-vue/package.json index f80eba8e3..d09ff5eea 100644 --- a/web-vue/package.json +++ b/web-vue/package.json @@ -1,6 +1,6 @@ { "name": "jpom-vue", - "version": "2.10.28", + "version": "2.10.29", "private": true, "scripts": { "serve": "vue-cli-service --max-old-space-size=900 serve --mode dev", diff --git a/web-vue/src/api/tools.js b/web-vue/src/api/tools.js new file mode 100644 index 000000000..0ed57f760 --- /dev/null +++ b/web-vue/src/api/tools.js @@ -0,0 +1,13 @@ +import axios from "./config"; + +/** + * + * @param data + */ +export function cronTools(data) { + return axios({ + url: "/tools/cron", + method: "get", + params: data, + }); +} diff --git a/web-vue/src/api/user/user-login-log.js b/web-vue/src/api/user/user-login-log.js new file mode 100644 index 000000000..fa4faf507 --- /dev/null +++ b/web-vue/src/api/user/user-login-log.js @@ -0,0 +1,18 @@ +import axios from "../config"; + +export function userLoginLgin(params) { + return axios({ + url: "/user/login-log/list-data", + method: "post", + data: params, + }); +} + +export const operateCodeMap = { + 0: "正常登录", + 1: "密码错误", + 2: "账号被锁定", + 3: "自动续期", + 4: "账号被禁用", + 5: "登录成功,需要验证 MFA", +}; diff --git a/web-vue/src/api/user/user.js b/web-vue/src/api/user/user.js index f3b07f9c5..f8f6fa51f 100644 --- a/web-vue/src/api/user/user.js +++ b/web-vue/src/api/user/user.js @@ -238,3 +238,19 @@ export function demoInfo() { params: {}, }); } + +export function listLoginLog(params) { + return axios({ + url: "/user/list-login-log-data", + method: "post", + data: params, + }); +} + +export function listOperaterLog(params) { + return axios({ + url: "/user/list-operate-log-data", + method: "post", + data: params, + }); +} diff --git a/web-vue/src/pages/build/history.vue b/web-vue/src/pages/build/history.vue index 83364b5ea..178718f82 100644 --- a/web-vue/src/pages/build/history.vue +++ b/web-vue/src/pages/build/history.vue @@ -128,9 +128,9 @@ export default { buildLogVisible: false, tableSelections: [], columns: [ - { title: "构建名称", dataIndex: "buildName", /*width: 120,*/ ellipsis: true, scopedSlots: { customRender: "tooltip" } }, - { title: "构建 ID", dataIndex: "buildNumberId", width: 90, align: "center", ellipsis: true, scopedSlots: { customRender: "buildNumberId" } }, - { title: "备注", dataIndex: "buildRemark", /*width: 120,*/ ellipsis: true, scopedSlots: { customRender: "tooltip" } }, + { title: "构建名称", dataIndex: "buildName", width: 120, ellipsis: true, scopedSlots: { customRender: "tooltip" } }, + { title: "构建 ID", dataIndex: "buildNumberId", width: "90px", align: "center", ellipsis: true, scopedSlots: { customRender: "buildNumberId" } }, + { title: "备注", dataIndex: "buildRemark", width: 120, ellipsis: true, scopedSlots: { customRender: "tooltip" } }, { title: "状态", dataIndex: "status", width: "100px", align: "center", ellipsis: true, scopedSlots: { customRender: "status" } }, { title: "触发类型", dataIndex: "triggerBuildType", align: "center", width: "100px", ellipsis: true, scopedSlots: { customRender: "triggerBuildType" } }, @@ -151,7 +151,7 @@ export default { }, { title: "发布方式", dataIndex: "releaseMethod", width: "100px", ellipsis: true, scopedSlots: { customRender: "releaseMethod" } }, { title: "构建人", dataIndex: "modifyUser", width: "130px", ellipsis: true, scopedSlots: { customRender: "modifyUser" } }, - { title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: "200px", align: "center" }, + { title: "操作", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: "200px", align: "center", fixed: "right" }, ], }; }, diff --git a/web-vue/src/pages/build/list-info.vue b/web-vue/src/pages/build/list-info.vue index 2336d3b81..9806ab4fe 100644 --- a/web-vue/src/pages/build/list-info.vue +++ b/web-vue/src/pages/build/list-info.vue @@ -1168,16 +1168,17 @@ export default { afterOptListSimple, buildConfirmVisible: false, columns: [ - { title: "名称", dataIndex: "name", sorter: true, ellipsis: true, scopedSlots: { customRender: "name" } }, - + { title: "名称", dataIndex: "name", sorter: true, width: 200, ellipsis: true, scopedSlots: { customRender: "name" } }, + { title: "分组", dataIndex: "group", width: 100, ellipsis: true, scopedSlots: { customRender: "tooltip" } }, { title: "分支/标签", dataIndex: "branchName", ellipsis: true, + width: 100, scopedSlots: { customRender: "branchName" }, }, - { title: "产物", dataIndex: "resultDirFile", ellipsis: true, scopedSlots: { customRender: "tooltip" } }, - { title: "方式", dataIndex: "buildMode", align: "center", width: "80px", ellipsis: true, scopedSlots: { customRender: "buildMode" } }, + { title: "产物", dataIndex: "resultDirFile", width: 100, ellipsis: true, scopedSlots: { customRender: "tooltip" } }, + { title: "方式", dataIndex: "buildMode", align: "center", width: "80px", sorter: true, ellipsis: true, scopedSlots: { customRender: "buildMode" } }, { title: "状态", dataIndex: "status", align: "center", width: "100px", ellipsis: true, scopedSlots: { customRender: "status" } }, { title: "构建 ID", @@ -1200,28 +1201,24 @@ export default { dataIndex: "modifyTimeMillis", sorter: true, customRender: (text) => { - if (!text) { - return ""; - } return parseTime(text); }, - width: 170, + width: "170px", }, { - title: "其他信息", + title: "发布方式", dataIndex: "releaseMethod", - width: 100, + width: "100px", ellipsis: true, scopedSlots: { customRender: "releaseMethod" }, }, - // { - // title: "产物目录", - // dataIndex: "resultDirFile", - // ellipsis: true, - // width: 100, - // scopedSlots: { customRender: "resultDirFile" }, - // }, - // { title: "构建命令", width: 100, dataIndex: "script", ellipsis: true, scopedSlots: { customRender: "script" } }, + { + title: "定时构建", + dataIndex: "autoBuildCron", + width: 100, + ellipsis: true, + scopedSlots: { customRender: "tooltip" }, + }, { title: "操作", dataIndex: "operation", @@ -1804,9 +1801,10 @@ export default { // 选择发布集群时 渲染服务名称 数据 selectSwarm() { this.swarmServiceListOptions = []; + this.tempExtraData = { ...this.tempExtraData, dockerSwarmServiceName: undefined }; if (this.tempExtraData.dockerSwarmId) { // 选中时才处理 - dockerSwarmServicesList({ + dockerSwarmServicesList("", { id: this.tempExtraData.dockerSwarmId, }).then((res) => { if (res.code === 200) { diff --git a/web-vue/src/pages/docker/list.vue b/web-vue/src/pages/docker/list.vue index 7205df67d..06ad75ac4 100644 --- a/web-vue/src/pages/docker/list.vue +++ b/web-vue/src/pages/docker/list.vue @@ -46,7 +46,7 @@ - + diff --git a/web-vue/src/pages/layout/user-log.vue b/web-vue/src/pages/layout/user-log.vue new file mode 100644 index 000000000..fa0c2d402 --- /dev/null +++ b/web-vue/src/pages/layout/user-log.vue @@ -0,0 +1,226 @@ + + diff --git a/web-vue/src/pages/login/index.vue b/web-vue/src/pages/login/index.vue index 144e335f6..c7f9540fc 100644 --- a/web-vue/src/pages/login/index.vue +++ b/web-vue/src/pages/login/index.vue @@ -30,8 +30,8 @@
@@ -58,6 +62,7 @@ export default { { title: "cron", dataIndex: "cron", + scopedSlots: { customRender: "cron" }, // sorter: (a, b) => (a && b ? a.localeCompare(b, "zh-CN") : 0), // sortDirections: ["descend", "ascend"], }, @@ -100,6 +105,20 @@ export default { refresh() { this.$emit("refresh"); }, + // 前往 cron 详情 + toCronTaskList(cron) { + const newpage = this.$router.resolve({ + name: "cron-task-list", + path: "/tools/cron", + query: { + ...this.$route.query, + sPid: "tools", + sId: "cronTools", + cron: cron, + }, + }); + window.open(newpage.href, "_blank"); + }, }, }; diff --git a/web-vue/src/pages/system/workspace.vue b/web-vue/src/pages/system/workspace.vue index 015f2d212..5c8e22f0d 100644 --- a/web-vue/src/pages/system/workspace.vue +++ b/web-vue/src/pages/system/workspace.vue @@ -56,6 +56,7 @@ + diff --git a/web-vue/src/pages/test/index.vue b/web-vue/src/pages/test/index.vue deleted file mode 100644 index 01eec5958..000000000 --- a/web-vue/src/pages/test/index.vue +++ /dev/null @@ -1,24 +0,0 @@ - - - - - diff --git a/web-vue/src/pages/tools/cron.vue b/web-vue/src/pages/tools/cron.vue new file mode 100644 index 000000000..61405bfc6 --- /dev/null +++ b/web-vue/src/pages/tools/cron.vue @@ -0,0 +1,153 @@ + + diff --git a/web-vue/src/pages/user/operation-log.vue b/web-vue/src/pages/user/operation-log.vue index 1b2369b1b..ddcdb770a 100644 --- a/web-vue/src/pages/user/operation-log.vue +++ b/web-vue/src/pages/user/operation-log.vue @@ -34,6 +34,11 @@ {{ text }} + + + {{ text || item.userId }} + + {{ text }} @@ -84,11 +89,12 @@ export default { detailVisible: false, detailData: [], columns: [ - { title: "操作者", dataIndex: "userId" }, + { title: "操作者", dataIndex: "username", ellipsis: true, scopedSlots: { customRender: "username" } }, { title: "IP", dataIndex: "ip" /*width: 130*/ }, { title: "节点", dataIndex: "nodeId", width: 120, ellipsis: true, scopedSlots: { customRender: "nodeId" } }, { title: "数据名称", dataIndex: "dataName", /*width: 240,*/ ellipsis: true, scopedSlots: { customRender: "tooltip" } }, - { title: "数据 ID", dataIndex: "dataId", /*width: 240,*/ ellipsis: true, scopedSlots: { customRender: "tooltip" } }, + { title: "工作空间名", dataIndex: "workspaceName", /*width: 240,*/ ellipsis: true, scopedSlots: { customRender: "tooltip" } }, + // { title: "数据 ID", dataIndex: "dataId", /*width: 240,*/ ellipsis: true, scopedSlots: { customRender: "tooltip" } }, { title: "操作功能", dataIndex: "classFeature", /*width: 240,*/ ellipsis: true, scopedSlots: { customRender: "classFeature" } }, { title: "操作方法", dataIndex: "methodFeature", /*width: 240,*/ ellipsis: true, scopedSlots: { customRender: "methodFeature" } }, { title: "状态码", dataIndex: "optStatus", width: 90, scopedSlots: { customRender: "optStatus" } }, @@ -99,7 +105,7 @@ export default { customRender: (text, item) => { return parseTime(text || item.optTime); }, - width: 160, + width: "170px", }, { title: "操作", align: "center", dataIndex: "operation", scopedSlots: { customRender: "operation" }, width: 80 }, ], @@ -183,6 +189,7 @@ export default { } catch (e) { console.error(e); } + this.detailData.push({ title: "数据Id", description: this.temp.dataId }); this.detailData.push({ title: "浏览器标识", description: this.temp.userAgent }); this.detailData.push({ title: "请求参数", json: true, value: this.temp.reqData }); this.detailData.push({ title: "响应结果", json: true, value: this.temp.resultMsg }); diff --git a/web-vue/src/pages/user/user-login-log.vue b/web-vue/src/pages/user/user-login-log.vue new file mode 100644 index 000000000..8ca90707c --- /dev/null +++ b/web-vue/src/pages/user/user-login-log.vue @@ -0,0 +1,102 @@ + + + diff --git a/web-vue/src/router/index.js b/web-vue/src/router/index.js index afe601d96..0af19df4e 100644 --- a/web-vue/src/router/index.js +++ b/web-vue/src/router/index.js @@ -129,6 +129,11 @@ const children = [ name: "script-env-list", component: () => import("../pages/script/env"), }, + { + path: "/tools/cron", + name: "cron-tools", + component: () => import("../pages/tools/cron"), + }, ]; const management = [ @@ -162,7 +167,11 @@ const management = [ name: "operation-log", component: () => import("../pages/user/operation-log"), }, - + { + path: "/user/login-log", + name: "user-login-log", + component: () => import("../pages/user/user-login-log"), + }, // 工作空间 { path: "/system/workspace", diff --git a/web-vue/src/router/route-menu.js b/web-vue/src/router/route-menu.js index d0d675361..5bdee86f8 100644 --- a/web-vue/src/router/route-menu.js +++ b/web-vue/src/router/route-menu.js @@ -31,6 +31,7 @@ const routeMenuMap = { userList: "/user/list", permission_group: "/user/permission-group", user_log: "/operation/log", + user_login_log: "/user/login-log", monitorConfigEmail: "/system/mail", cacheManage: "/system/cache", logManage: "/system/log", @@ -46,6 +47,7 @@ const routeMenuMap = { machine_ssh_info: "/system/assets/ssh-list", machine_docker_info: "/system/assets/docker-list", configWorkspaceEnv: "/script/env-list", + cronTools: "/tools/cron", }; export default routeMenuMap; diff --git a/web-vue/src/utils/upload-pieces.js b/web-vue/src/utils/upload-pieces.js index 7fdfbf694..b27823ab3 100644 --- a/web-vue/src/utils/upload-pieces.js +++ b/web-vue/src/utils/upload-pieces.js @@ -108,9 +108,11 @@ export const uploadPieces = ({ file, uploadCallback, success, process, error }) **/ const concurrentUpload = () => { const startTime = new Date().getTime(); + // 设置初始化进度(避免第一份分片卡顿) + process(0.01, 1, total, new Date().getTime() - startTime); concurrentExecution(chunkList, uploadFileConcurrent, (curItem) => { return new Promise((resolve, reject) => { - const { chunk, end } = getChunkInfo(file, curItem, chunkSize); + const { chunk } = getChunkInfo(file, curItem, chunkSize); const chunkInfo = { chunk, currentChunk: curItem, @@ -125,7 +127,7 @@ export const uploadPieces = ({ file, uploadCallback, success, process, error }) uploaded.push(chunkInfo.currentChunk + 1); const sd = parseInt((uploaded.length / chunkInfo.chunkCount) * 100); // console.log(chunk); - process(sd, end, total, new Date().getTime() - startTime); + process(sd, Math.min(uploaded.length * chunkSize, total), total, new Date().getTime() - startTime); // /*** * 创建文件上传参数