From a10e37bbd1406ce580a7d54b12e5f471c3114eb5 Mon Sep 17 00:00:00 2001 From: zhangshuai Date: Thu, 10 Oct 2024 11:30:40 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20ASW-97=20playbook=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../net/geedge/asw/common/util/Constants.java | 5 ++ .../net/geedge/asw/common/util/RCode.java | 2 +- .../runner/controller/PlaybookController.java | 65 ++++++++++++++ .../asw/module/runner/dao/PlaybookDao.java | 8 ++ .../module/runner/entity/PlaybookEntity.java | 13 ++- .../runner/service/IPlaybookService.java | 11 +++ .../runner/service/impl/JobServiceImpl.java | 5 -- .../runner/service/impl/PcapServiceImpl.java | 5 -- .../service/impl/PlaybookServiceImpl.java | 71 ++++++++++++++++ .../db/mapper/runner/PlaybookMapper.xml | 85 +++++++++++++++++++ .../db/migration/V1.0.01__INIT_TABLES.sql | 13 ++- 11 files changed, 261 insertions(+), 22 deletions(-) create mode 100644 src/main/java/net/geedge/asw/module/runner/controller/PlaybookController.java create mode 100644 src/main/resources/db/mapper/runner/PlaybookMapper.xml diff --git a/src/main/java/net/geedge/asw/common/util/Constants.java b/src/main/java/net/geedge/asw/common/util/Constants.java index 3632cf9..f81bab1 100644 --- a/src/main/java/net/geedge/asw/common/util/Constants.java +++ b/src/main/java/net/geedge/asw/common/util/Constants.java @@ -19,6 +19,11 @@ public class Constants { */ public static final String TEMP_PATH = System.getProperty("user.dir") + File.separator + "tmp"; + /** + * playbook dir + */ + public static File PLAYBOOK_FILES_DIR = T.FileUtil.file(T.WebPathUtil.getRootPath(), "playbook_files"); + /** * 国际化语言列表 */ diff --git a/src/main/java/net/geedge/asw/common/util/RCode.java b/src/main/java/net/geedge/asw/common/util/RCode.java index 797b179..e448607 100644 --- a/src/main/java/net/geedge/asw/common/util/RCode.java +++ b/src/main/java/net/geedge/asw/common/util/RCode.java @@ -63,7 +63,7 @@ public enum RCode { // Playbook PLAYBOOK_ID_CANNOT_EMPTY(302001, "playbook id cannot be empty"), - + PLAYBOOK_NAME_DUPLICATE(302002, "playbook name duplicate "), // Workspace WORKSPACE_ID_CANNOT_EMPTY(401001, "workspace id cannot be empty"), diff --git a/src/main/java/net/geedge/asw/module/runner/controller/PlaybookController.java b/src/main/java/net/geedge/asw/module/runner/controller/PlaybookController.java new file mode 100644 index 0000000..749a21a --- /dev/null +++ b/src/main/java/net/geedge/asw/module/runner/controller/PlaybookController.java @@ -0,0 +1,65 @@ +package net.geedge.asw.module.runner.controller; + +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import jakarta.servlet.http.HttpServletResponse; +import net.geedge.asw.common.util.R; +import net.geedge.asw.common.util.RCode; +import net.geedge.asw.common.util.ResponseUtil; +import net.geedge.asw.common.util.T; +import net.geedge.asw.module.runner.entity.PlaybookEntity; +import net.geedge.asw.module.runner.service.IPlaybookService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.MediaType; +import org.springframework.web.bind.annotation.*; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +@RestController +@RequestMapping("/api/v1/workspace") +public class PlaybookController { + + @Autowired + private IPlaybookService playbookService; + + @GetMapping("/{workspaceId}/playbook/{id}") + public R detail(@PathVariable("workspaceId") String workspaceId, @PathVariable("id") String id) { + PlaybookEntity playbook = playbookService.detail(workspaceId, id); + return R.ok().put("record", playbook); + } + + @GetMapping("/{workspaceId}/playbook") + public R list(@PathVariable("workspaceId") String workspaceId, @RequestParam Map params) { + Page page = playbookService.queryList(workspaceId, params); + return R.ok(page); + } + + @PostMapping("/{workspaceId}/playbook") + public R save(@PathVariable("workspaceId") String workspaceId, + @RequestParam("file") MultipartFile file, + @RequestParam("name") String name, + @RequestParam(value = "description", required = false) String description) { + PlaybookEntity playbook = playbookService.savePlaybook(workspaceId, file, name, description); + return R.ok().put("record", playbook); + } + + @DeleteMapping("/{workspaceId}/playbook") + public R delete(@PathVariable("workspaceId") String workspaceId, + @RequestParam("ids") String ids) { + playbookService.delete(workspaceId, ids); + return R.ok(); + } + + @GetMapping("/{workspaceId}/playbook/{id}/download") + public void download(@PathVariable("workspaceId") String workspaceId, + @PathVariable("id") String id, HttpServletResponse response) throws IOException { + + PlaybookEntity entity = playbookService.getById(id); + T.VerifyUtil.is(entity).notNull(RCode.SYS_RECORD_NOT_FOUND); + + File playbookFile = T.FileUtil.file(entity.getPath()); + ResponseUtil.downloadFile(response, MediaType.APPLICATION_OCTET_STREAM_VALUE, entity.getName(), T.FileUtil.readBytes(playbookFile)); + } +} diff --git a/src/main/java/net/geedge/asw/module/runner/dao/PlaybookDao.java b/src/main/java/net/geedge/asw/module/runner/dao/PlaybookDao.java index 0ee8531..193db35 100644 --- a/src/main/java/net/geedge/asw/module/runner/dao/PlaybookDao.java +++ b/src/main/java/net/geedge/asw/module/runner/dao/PlaybookDao.java @@ -1,10 +1,18 @@ package net.geedge.asw.module.runner.dao; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import net.geedge.asw.module.runner.entity.PlaybookEntity; import org.apache.ibatis.annotations.Mapper; +import org.apache.ibatis.annotations.Param; + +import java.util.List; +import java.util.Map; @Mapper public interface PlaybookDao extends BaseMapper{ + PlaybookEntity queryInfo(@Param("workspaceId") String workspaceId, @Param("id") String id); + + List queryList(Page page, @Param("workspaceId") String workspaceId, @Param("params") Map params); } diff --git a/src/main/java/net/geedge/asw/module/runner/entity/PlaybookEntity.java b/src/main/java/net/geedge/asw/module/runner/entity/PlaybookEntity.java index 6c49070..2eda2a3 100644 --- a/src/main/java/net/geedge/asw/module/runner/entity/PlaybookEntity.java +++ b/src/main/java/net/geedge/asw/module/runner/entity/PlaybookEntity.java @@ -1,9 +1,11 @@ package net.geedge.asw.module.runner.entity; import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableId; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Data; +import net.geedge.asw.module.sys.entity.SysUserEntity; @Data @TableName("playbook") @@ -12,10 +14,9 @@ public class PlaybookEntity { @TableId(type = IdType.ASSIGN_UUID) private String id; private String name; - private String appId; private String tags; - private String script; - private Long opVersion; + private String path; + private String description; private Long createTimestamp; private Long updateTimestamp; @@ -24,4 +25,10 @@ public class PlaybookEntity { private String workspaceId; + @TableField(exist = false) + private SysUserEntity createUser; + + @TableField(exist = false) + private SysUserEntity updateUser; + } \ No newline at end of file diff --git a/src/main/java/net/geedge/asw/module/runner/service/IPlaybookService.java b/src/main/java/net/geedge/asw/module/runner/service/IPlaybookService.java index c96ffde..b04acbb 100644 --- a/src/main/java/net/geedge/asw/module/runner/service/IPlaybookService.java +++ b/src/main/java/net/geedge/asw/module/runner/service/IPlaybookService.java @@ -1,8 +1,19 @@ package net.geedge.asw.module.runner.service; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.IService; import net.geedge.asw.module.runner.entity.PlaybookEntity; +import org.springframework.web.multipart.MultipartFile; + +import java.util.Map; public interface IPlaybookService extends IService{ + PlaybookEntity detail(String workspaceId, String id); + + Page queryList(String workspaceId, Map params); + + PlaybookEntity savePlaybook(String workspaceId, MultipartFile file, String name, String description); + + void delete(String workspaceId, String ids); } diff --git a/src/main/java/net/geedge/asw/module/runner/service/impl/JobServiceImpl.java b/src/main/java/net/geedge/asw/module/runner/service/impl/JobServiceImpl.java index 29473d6..d27a384 100644 --- a/src/main/java/net/geedge/asw/module/runner/service/impl/JobServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/runner/service/impl/JobServiceImpl.java @@ -79,11 +79,6 @@ public class JobServiceImpl extends ServiceImpl implements IJ PackageEntity pkg = packageService.getById(job.getPackageId()); job.setPkg(pkg); - - if (T.ObjectUtil.isNotNull(playbook)) { - ApplicationEntity application = applicationService.getById(playbook.getAppId()); - job.setApplication(application); - } return job; } diff --git a/src/main/java/net/geedge/asw/module/runner/service/impl/PcapServiceImpl.java b/src/main/java/net/geedge/asw/module/runner/service/impl/PcapServiceImpl.java index cecfef4..5ff66f6 100644 --- a/src/main/java/net/geedge/asw/module/runner/service/impl/PcapServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/runner/service/impl/PcapServiceImpl.java @@ -111,11 +111,6 @@ public class PcapServiceImpl extends ServiceImpl implements PlaybookEntity playbook = playbookService.getById(job.getPlaybookId()); pcap.setPlaybook(playbook); - - if (T.ObjectUtil.isNotNull(playbook)) { - ApplicationEntity application = applicationService.getById(playbook.getAppId()); - pcap.setApplication(application); - } } return pcap; } diff --git a/src/main/java/net/geedge/asw/module/runner/service/impl/PlaybookServiceImpl.java b/src/main/java/net/geedge/asw/module/runner/service/impl/PlaybookServiceImpl.java index 1c3d8b9..e72c712 100644 --- a/src/main/java/net/geedge/asw/module/runner/service/impl/PlaybookServiceImpl.java +++ b/src/main/java/net/geedge/asw/module/runner/service/impl/PlaybookServiceImpl.java @@ -1,13 +1,84 @@ package net.geedge.asw.module.runner.service.impl; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.log.Log; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; +import net.geedge.asw.common.config.Query; +import net.geedge.asw.common.util.*; import net.geedge.asw.module.runner.dao.PlaybookDao; import net.geedge.asw.module.runner.entity.PlaybookEntity; import net.geedge.asw.module.runner.service.IPlaybookService; +import org.apache.commons.io.FileUtils; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.multipart.MultipartFile; + +import java.io.File; +import java.util.Arrays; +import java.util.List; +import java.util.Map; @Service public class PlaybookServiceImpl extends ServiceImpl implements IPlaybookService { + private final static Log log = Log.get(); + @Override + public PlaybookEntity detail(String workspaceId, String id) { + PlaybookEntity playbook = this.baseMapper.queryInfo(workspaceId, id); + return playbook; + } + @Override + public Page queryList(String workspaceId, Map params) { + Page page = new Query(PlaybookEntity.class).getPage(params); + List playbookList = this.baseMapper.queryList(page, workspaceId, params); + page.setRecords(playbookList); + return page; + } + + @Override + @Transactional(rollbackFor = Exception.class) + public PlaybookEntity savePlaybook(String workspaceId, MultipartFile file, String name, String description) { + + List playbookList = this.baseMapper.selectList(new LambdaQueryWrapper().eq(PlaybookEntity::getWorkspaceId, workspaceId).eq(PlaybookEntity::getName, name)); + if (T.CollUtil.isNotEmpty(playbookList)) { + throw new ASWException(RCode.PLAYBOOK_NAME_DUPLICATE); + } + + PlaybookEntity playbook = new PlaybookEntity(); + try { + playbook.setWorkspaceId(workspaceId); + playbook.setName(name); + playbook.setDescription(description); + playbook.setCreateUserId(StpUtil.getLoginIdAsString()); + playbook.setUpdateUserId(StpUtil.getLoginIdAsString()); + playbook.setCreateTimestamp(System.currentTimeMillis()); + playbook.setUpdateTimestamp(System.currentTimeMillis()); + + // path + File destination = T.FileUtil.file(Constants.PLAYBOOK_FILES_DIR, name); + FileUtils.copyInputStreamToFile(file.getInputStream(), destination); + playbook.setPath(destination.getPath()); + this.save(playbook); + } catch (Exception e) { + log.error(e, "[savePlaybook] [error] [file: {}]", file.getName()); + T.FileUtil.del(description); + } + return playbook; + } + + @Override + public void delete(String workspaceId, String ids) { + List idList = Arrays.asList(ids.split(",")); + for (String id : idList) { + PlaybookEntity entity = this.getById(id); + // remove file + T.FileUtil.del(entity.getPath()); + + // remove + this.removeById(id); + } + } } diff --git a/src/main/resources/db/mapper/runner/PlaybookMapper.xml b/src/main/resources/db/mapper/runner/PlaybookMapper.xml new file mode 100644 index 0000000..942c218 --- /dev/null +++ b/src/main/resources/db/mapper/runner/PlaybookMapper.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db/migration/V1.0.01__INIT_TABLES.sql b/src/main/resources/db/migration/V1.0.01__INIT_TABLES.sql index 257e7cf..ca04c0c 100644 --- a/src/main/resources/db/migration/V1.0.01__INIT_TABLES.sql +++ b/src/main/resources/db/migration/V1.0.01__INIT_TABLES.sql @@ -179,10 +179,9 @@ DROP TABLE IF EXISTS `playbook`; CREATE TABLE `playbook` ( `id` varchar(64) NOT NULL COMMENT '主键', `name` varchar(256) NOT NULL DEFAULT '' COMMENT '名称', - `app_id` varchar(64) NOT NULL DEFAULT '' COMMENT '应用程序 ID', `tags` varchar(256) NOT NULL DEFAULT '' COMMENT '标签', - `script` text NOT NULL DEFAULT '' COMMENT '脚本内容', - `op_version` bigint(20) NOT NULL DEFAULT 1 COMMENT '更新版本号, 默认:1;每次更新递增', + `path` text NOT NULL COMMENT '脚本文件路径', + `description` text NOT NULL DEFAULT '' COMMENT '描述信息', `create_timestamp` bigint(20) NOT NULL COMMENT '创建时间戳', `update_timestamp` bigint(20) NOT NULL COMMENT '更新时间戳', `create_user_id` varchar(64) NOT NULL COMMENT '创建人', @@ -190,8 +189,6 @@ CREATE TABLE `playbook` ( `workspace_id` varchar(64) NOT NULL DEFAULT '' COMMENT '工作空间ID', PRIMARY KEY (`id`) USING BTREE, KEY `idx_name` (`name`) USING BTREE, - KEY `idx_app_id` (`app_id`) USING BTREE, - KEY `idx_op_version` (`op_version`) USING BTREE, KEY `idx_workspace_id` (`workspace_id`) USING BTREE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; @@ -508,8 +505,8 @@ CREATE TABLE `environment` ( DROP TABLE IF EXISTS `environment_workspace`; CREATE TABLE `environment_workspace` ( `id` varchar(64) NOT NULL COMMENT '主键', - `env_id` varchar(64) NOT NULL DEFAULT '' COMMENT '名称', - `workspace_id` varchar(64) NOT NULL DEFAULT '' COMMENT '位置', + `env_id` varchar(64) NOT NULL DEFAULT '' COMMENT '环境id', + `workspace_id` varchar(64) NOT NULL DEFAULT '' COMMENT '工作空间id', `create_timestamp` bigint(20) NOT NULL COMMENT '创建时间戳', `create_user_id` varchar(64) NOT NULL COMMENT '创建人', PRIMARY KEY (`id`) USING BTREE, @@ -523,7 +520,7 @@ CREATE TABLE `environment_workspace` ( DROP TABLE IF EXISTS `environment_session`; CREATE TABLE `environment_session` ( `id` varchar(64) NOT NULL COMMENT '主键', - `env_id` varchar(64) NOT NULL DEFAULT '' COMMENT '设备id', + `env_id` varchar(64) NOT NULL DEFAULT '' COMMENT '环境id', `user_id` varchar(64) NOT NULL DEFAULT '' COMMENT '用户id', `start_timestamp` bigint(20) NOT NULL COMMENT '开始时间', `end_timestamp` bigint(20) NOT NULL DEFAULT -1 COMMENT '结束时间',