release: v1.9.0

This commit is contained in:
meilin.huang
2024-10-23 17:30:05 +08:00
parent 44a1bd626e
commit 2118acf244
26 changed files with 60 additions and 59 deletions

View File

@@ -10,7 +10,7 @@ RUN yarn config set registry 'https://registry.npmmirror.com' && \
yarn build
# 构建后端资源
FROM golang:1.22 as be-builder
FROM golang:1.23 as be-builder
ENV GOPROXY https://goproxy.cn
WORKDIR /mayfly

View File

@@ -1,6 +1,7 @@
{
"name": "mayfly",
"version": "1.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
@@ -32,7 +33,7 @@
"screenfull": "^6.0.2",
"sortablejs": "^1.15.3",
"splitpanes": "^3.1.5",
"sql-formatter": "^15.4.2",
"sql-formatter": "^15.4.5",
"trzsz": "^1.1.5",
"uuid": "^9.0.1",
"vue": "^3.5.12",
@@ -59,7 +60,7 @@
"prettier": "^3.2.5",
"sass": "^1.80.3",
"typescript": "^5.6.3",
"vite": "^5.4.9",
"vite": "^5.4.10",
"vue-eslint-parser": "^9.4.3"
},
"browserslist": [

View File

@@ -1,9 +1,9 @@
<template>
<el-tooltip :content="formatByteSize(fileDetail.size)" placement="left">
<el-tooltip :content="formatByteSize(fileDetail?.size)" placement="left">
<el-link v-if="props.canDownload" target="_blank" rel="noopener noreferrer" icon="Download" type="primary" :href="getFileUrl(props.fileKey)"></el-link>
</el-tooltip>
{{ fileDetail.filename }}
{{ fileDetail?.filename }}
</template>
<script lang="ts" setup>

View File

@@ -162,7 +162,7 @@ watch(props, (newValue: any) => {
} else {
state.form = { status: ProcdefStatus.Enable.value } as any;
state.form.condition = `{{/* DBMS-执行sql规则; param参数描述如下 */}}
{{/* stmtType: select / read / insert / update / delete ; */}}
{{/* stmtType: select / read / insert / update / delete / ddl ; */}}
{{ if eq .bizType "db_sql_exec_flow"}}
{{/* 不是select和read语句时开启流程审批 */}}
{{ if and (ne .param.stmtType "select") (ne .param.stmtType "read") }}

View File

@@ -28,7 +28,7 @@
:limit="100"
>
<el-tooltip :show-after="1000" class="box-item" effect="dark" content="SQL脚本执行" placement="top">
<el-link type="success" :underline="false" icon="Document"></el-link>
<el-link v-auth="'db:sqlscript:run'" type="success" :underline="false" icon="Document"></el-link>
</el-tooltip>
</el-upload>
</div>

View File

@@ -403,8 +403,9 @@ export class DbInst {
dbInst.type = inst.type;
dbInst.databases = inst.databases;
// 获取兼容版本信息
dbInst.version = await dbApi.getCompatibleDbVersion.request({ id: inst.id, db: dbInst.databases[0] });
if (dbInst.databases?.[0]) {
dbInst.version = await dbApi.getCompatibleDbVersion.request({ id: inst.id, db: dbInst.databases?.[0] });
}
dbInstCache.set(dbInst.id, dbInst);
return dbInst;

View File

@@ -25,7 +25,7 @@ require (
github.com/pkg/errors v0.9.1
github.com/pkg/sftp v1.13.6
github.com/pquerna/otp v1.4.0
github.com/redis/go-redis/v9 v9.6.1
github.com/redis/go-redis/v9 v9.7.0
github.com/robfig/cron/v3 v3.0.1 //
github.com/sijms/go-ora/v2 v2.8.22
github.com/stretchr/testify v1.9.0

View File

@@ -84,10 +84,6 @@ func (d *dbAppImpl) SaveDb(ctx context.Context, dbEntity *entity.Db) error {
if err == nil {
return errorx.NewBiz("该实例下数据库名已存在")
}
if d.CountByCond(&entity.Db{Name: dbEntity.Name}) > 0 {
return errorx.NewBiz("该编码已存在")
}
dbEntity.Code = stringx.Rand(10)
return d.Tx(ctx, func(ctx context.Context) error {

View File

@@ -105,10 +105,6 @@ func (app *instanceAppImpl) SaveDbInstance(ctx context.Context, instance *dto.Sa
if err == nil {
return 0, errorx.NewBiz("该数据库实例已存在")
}
if app.CountByCond(&entity.DbInstance{Name: instanceEntity.Name}) > 0 {
return 0, errorx.NewBiz("该名称已存在")
}
instanceEntity.Code = stringx.Rand(10)
return instanceEntity.Id, app.Tx(ctx, func(ctx context.Context) error {

View File

@@ -184,7 +184,6 @@ func (app *dbTransferAppImpl) CreateLog(ctx context.Context, taskId uint64) (uin
}
func (app *dbTransferAppImpl) Run(ctx context.Context, taskId uint64, logId uint64) {
task, err := app.GetById(taskId)
if err != nil {
logx.Errorf("创建DBMS-执行数据迁移日志失败:%v", err)
@@ -288,15 +287,16 @@ func (app *dbTransferAppImpl) transfer2File(ctx context.Context, taskId uint64,
}
// 2、把源库数据迁移到文件
app.Log(ctx, logId, fmt.Sprintf("开始迁移表数据到文件: %s", filename))
app.Log(ctx, logId, fmt.Sprintf("目标库文件语言类型: %s", task.TargetFileDbType))
go func() {
defer saveFileFunc()
var err error
defer saveFileFunc(&err)
defer app.MarkStop(taskId)
defer app.logApp.Flush(logId, true)
ctx = context.Background()
err := app.dbApp.DumpDb(ctx, &dto.DumpDb{
err = app.dbApp.DumpDb(ctx, &dto.DumpDb{
LogId: logId,
DbId: uint64(task.SrcDbId),
DbName: task.SrcDbName,
@@ -313,8 +313,6 @@ func (app *dbTransferAppImpl) transfer2File(ctx context.Context, taskId uint64,
app.EndTransfer(ctx, logId, taskId, "数据库迁移失败", err, nil)
tFile.Status = entity.DbTransferFileStatusFail
_ = app.transferFileApp.UpdateById(ctx, tFile)
// 删除文件
_ = app.fileApp.Remove(ctx, fileKey)
return
}
app.EndTransfer(ctx, logId, taskId, "数据库迁移完成", err, nil)
@@ -323,7 +321,6 @@ func (app *dbTransferAppImpl) transfer2File(ctx context.Context, taskId uint64,
tFile.FileKey = fileKey
_ = app.transferFileApp.UpdateById(ctx, tFile)
}()
}
func (app *dbTransferAppImpl) Stop(ctx context.Context, taskId uint64) error {

View File

@@ -36,7 +36,7 @@ func InitDbRouter(router *gin.RouterGroup) {
req.NewPost(":dbId/exec-sql", d.ExecSql).Log(req.NewLog("db-执行Sql")),
req.NewPost(":dbId/exec-sql-file", d.ExecSqlFile).Log(req.NewLogSave("db-执行Sql文件")),
req.NewPost(":dbId/exec-sql-file", d.ExecSqlFile).Log(req.NewLogSave("db-执行Sql文件")).RequiredPermissionCode("db:sqlscript:run"),
req.NewGet(":dbId/dump", d.DumpSql).Log(req.NewLogSave("db-导出sql文件")).NoRes(),

View File

@@ -41,8 +41,8 @@ type File interface {
//
// @return writer 文件writer
//
// @return saveFunc 保存文件信息的回调函数 (必须要defer中调用才会入库保存该文件信息)
NewWriter(ctx context.Context, canEmptyFileKey string, filename string) (fileKey string, writer *writerx.CountingWriteCloser, saveFunc func() error, err error)
// @return saveFunc(*error) 保存文件信息的回调函数 (必须要defer中调用才会入库保存该文件信息),若*error不为nil则表示业务逻辑处理失败不需要保存文件信息并将创建的文件删除
NewWriter(ctx context.Context, canEmptyFileKey string, filename string) (fileKey string, writer *writerx.CountingWriteCloser, saveFunc func(*error) error, err error)
// GetReader 获取文件reader
//
@@ -66,19 +66,20 @@ func (f *fileAppImpl) InjectFileRepo(repo repository.File) {
}
func (f *fileAppImpl) Upload(ctx context.Context, fileKey string, filename string, r io.Reader) (string, error) {
var err error
fileKey, writer, saveFileFunc, err := f.NewWriter(ctx, fileKey, filename)
if err != nil {
return fileKey, err
}
defer saveFileFunc()
defer saveFileFunc(&err)
if _, err := io.Copy(writer, r); err != nil {
if _, err = io.Copy(writer, r); err != nil {
return fileKey, err
}
return fileKey, nil
}
func (f *fileAppImpl) NewWriter(ctx context.Context, canEmptyFileKey string, filename string) (fileKey string, writer *writerx.CountingWriteCloser, saveFunc func() error, err error) {
func (f *fileAppImpl) NewWriter(ctx context.Context, canEmptyFileKey string, filename string) (fileKey string, writer *writerx.CountingWriteCloser, saveFunc func(*error) error, err error) {
isNewFile := true
file := &entity.File{}
@@ -109,7 +110,16 @@ func (f *fileAppImpl) NewWriter(ctx context.Context, canEmptyFileKey string, fil
fileKey = canEmptyFileKey
writer = writerx.NewCountingWriteCloser(w)
// 创建回调函数
saveFunc = func() error {
saveFunc = func(e *error) error {
if e != nil {
err := *e
if err != nil {
logx.Errorf("写入文件业务逻辑处理失败: %s", err.Error())
// 删除已经创建的文件
f.remove(ctx, file)
return err
}
}
// 获取已写入的字节数
file.Size = writer.BytesWritten()
writer.Close()

View File

@@ -323,7 +323,7 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
isSuccess = false
logx.Errorf("文件上传失败: %s", err)
switch t := err.(type) {
case errorx.BizError:
case *errorx.BizError:
m.MsgApp.CreateAndSend(la, msgdto.ErrSysMsg("文件上传失败", fmt.Sprintf("执行文件上传失败:\n<-e errCode: %d, errMsg: %s", t.Code(), t.Error())))
}
}

View File

@@ -105,9 +105,6 @@ func (m *machineAppImpl) SaveMachine(ctx context.Context, param *dto.SaveMachine
if err == nil {
return errorx.NewBiz("该机器信息已存在")
}
if m.CountByCond(&entity.Machine{Name: me.Name}) > 0 {
return errorx.NewBiz("该名称已存在")
}
// 新增机器,默认启用状态
me.Status = entity.MachineStatusEnable

View File

@@ -49,6 +49,7 @@ func (m *machineTermOpAppImpl) InjectMachineTermOpRepo(repo repository.MachineTe
func (m *machineTermOpAppImpl) TermConn(ctx context.Context, cli *mcm.Cli, wsConn *websocket.Conn, rows, cols int) error {
var recorder *mcm.Recorder
var termOpRecord *entity.MachineTermOp
var err error
// 开启终端操作记录
if cli.Info.EnableRecorder == 1 {
@@ -68,7 +69,7 @@ func (m *machineTermOpAppImpl) TermConn(ctx context.Context, cli *mcm.Cli, wsCon
if err != nil {
return errorx.NewBiz("创建终端回放记录文件失败: %s", err.Error())
}
defer saveFileFunc()
defer saveFileFunc(&err)
termOpRecord.FileKey = fileKey
recorder = mcm.NewRecorder(wc)

View File

@@ -78,14 +78,13 @@ func (d *mongoAppImpl) TestConn(me *entity.Mongo) error {
}
func (d *mongoAppImpl) SaveMongo(ctx context.Context, m *entity.Mongo, tagCodePaths ...string) error {
oldMongo := &entity.Mongo{Name: m.Name, SshTunnelMachineId: m.SshTunnelMachineId}
oldMongo := &entity.Mongo{Uri: m.Uri, SshTunnelMachineId: m.SshTunnelMachineId}
err := d.GetByCond(oldMongo)
if m.Id == 0 {
if err == nil {
return errorx.NewBiz("该名称已存在")
return errorx.NewBiz("该信息已存在")
}
// 生成随机编号
m.Code = stringx.Rand(10)
@@ -105,7 +104,7 @@ func (d *mongoAppImpl) SaveMongo(ctx context.Context, m *entity.Mongo, tagCodePa
// 如果存在该库,则校验修改的库是否为该库
if err == nil && oldMongo.Id != m.Id {
return errorx.NewBiz("该名称已存在")
return errorx.NewBiz("该信息已存在")
}
// 如果调整了ssh等会查不到旧数据故需要根据id获取旧信息将code赋值给标签进行关联
if oldMongo.Code == "" {

View File

@@ -103,10 +103,6 @@ func (r *redisAppImpl) SaveRedis(ctx context.Context, param *dto.SaveRedis) erro
if err == nil {
return errorx.NewBiz("该实例已存在")
}
if r.CountByCond(&entity.Redis{Name: re.Name}) > 0 {
return errorx.NewBiz("该名称已存在")
}
// 生成随机编号
re.Code = stringx.Rand(10)

View File

@@ -96,7 +96,7 @@ func (m *syslogAppImpl) SaveFromReq(req *req.Ctx) {
syslog.Type = entity.SyslogTypeError
var errMsg string
switch t := err.(type) {
case errorx.BizError:
case *errorx.BizError:
errMsg = fmt.Sprintf("errCode: %d, errMsg: %s", t.Code(), t.Error())
case error:
errMsg = t.Error()

View File

@@ -42,7 +42,7 @@ func IsTrue(exp bool, msg string, params ...any) {
}
}
func IsTrueBy(exp bool, err errorx.BizError) {
func IsTrueBy(exp bool, err *errorx.BizError) {
if !exp {
panic(err)
}

View File

@@ -11,11 +11,11 @@ type BizError struct {
}
var (
Success BizError = NewBizCode(200, "success")
BizErr BizError = NewBizCode(400, "biz error")
ServerError BizError = NewBizCode(500, "server error")
PermissionErr BizError = NewBizCode(501, "token error")
AccessTokenInvalid BizError = NewBizCode(502, "access token invalid")
Success *BizError = NewBizCode(200, "success")
BizErr *BizError = NewBizCode(400, "biz error")
ServerError *BizError = NewBizCode(500, "server error")
PermissionErr *BizError = NewBizCode(501, "token error")
AccessTokenInvalid *BizError = NewBizCode(502, "access token invalid")
)
// 错误消息
@@ -33,11 +33,11 @@ func (e BizError) String() string {
}
// 创建业务逻辑错误结构体,默认为业务逻辑错误
func NewBiz(msg string, formats ...any) BizError {
return BizError{code: BizErr.code, err: fmt.Sprintf(msg, formats...)}
func NewBiz(msg string, formats ...any) *BizError {
return &BizError{code: BizErr.code, err: fmt.Sprintf(msg, formats...)}
}
// 创建业务逻辑错误结构体可设置指定错误code
func NewBizCode(code int16, msg string, formats ...any) BizError {
return BizError{code: code, err: fmt.Sprintf(msg, formats...)}
func NewBizCode(code int16, msg string, formats ...any) *BizError {
return &BizError{code: code, err: fmt.Sprintf(msg, formats...)}
}

View File

@@ -44,7 +44,7 @@ func SuccessNoData() *Result {
return &Result{Code: SuccessCode, Msg: SuccessMsg}
}
func Error(bizerr errorx.BizError) *Result {
func Error(bizerr *errorx.BizError) *Result {
return &Result{Code: bizerr.Code(), Msg: bizerr.Error()}
}

View File

@@ -125,7 +125,7 @@ func getErrMsg(rc *Ctx, err any) string {
nFrames := DefaultLogFrames
var errMsg string
switch t := err.(type) {
case errorx.BizError:
case *errorx.BizError:
errMsg = fmt.Sprintf("\n<-e %s", t.String())
nFrames = nFrames / 2
case error:

View File

@@ -102,7 +102,7 @@ func (rc *Ctx) GetLogInfo() *LogInfo {
func (rc *Ctx) res() {
if err := rc.Error; err != nil {
switch t := err.(type) {
case errorx.BizError:
case *errorx.BizError:
rc.JSONRes(http.StatusOK, model.Error(t))
default:
logx.ErrorTrace("服务器错误", t)

View File

@@ -859,6 +859,7 @@ INSERT INTO `t_sys_resource` (`id`, `pid`, `type`, `status`, `name`, `code`, `we
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1714032002, 1713875842, '12sSjal1/UnWIUhW0/0tJwC3Gf/', 2, 1, '命令配置-删除', 'cmdconf:del', 1714032002, 'null', 1, 'admin', 1, 'admin', '2024-04-25 16:00:02', '2024-04-25 16:00:02', 0, NULL);
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1714031981, 1713875842, '12sSjal1/UnWIUhW0/tEzIKecl/', 2, 1, '命令配置-保存', 'cmdconf:save', 1714031981, 'null', 1, 'admin', 1, 'admin', '2024-04-25 15:59:41', '2024-04-25 15:59:41', 0, NULL);
INSERT INTO t_sys_resource (id, pid, ui_path, `type`, status, name, code, weight, meta, creator_id, creator, modifier_id, modifier, create_time, update_time, is_deleted, delete_time) VALUES(1713875842, 2, '12sSjal1/UnWIUhW0/', 1, 1, '安全配置', 'security', 1713875842, '{"component":"ops/machine/security/SecurityConfList","icon":"Setting","isKeepAlive":true,"routeName":"SecurityConfList"}', 1, 'admin', 1, 'admin', '2024-04-23 20:37:22', '2024-04-23 20:37:22', 0, NULL);
INSERT INTO `t_sys_resource` (`id`, `pid`, `ui_path`, `type`, `status`, `name`, `code`, `weight`, `meta`, `creator_id`, `creator`, `modifier_id`, `modifier`, `create_time`, `update_time`, `is_deleted`, `delete_time`) VALUES(1729668131, 38, 'dbms23ax/exaeca2x/TGFPA3Ez/', 2, 1, 'SQL脚本执行', 'db:sqlscript:run', 1729668131, 'null', 1, 'admin', 1, 'admin', '2024-10-23 15:22:12', '2024-10-23 15:22:12', 0, NULL);
COMMIT;
-- ----------------------------

View File

@@ -8,6 +8,7 @@ INSERT INTO `t_sys_resource` (`id`, `pid`, `type`, `status`, `name`, `code`, `we
INSERT INTO `t_sys_resource` (`id`, `pid`, `type`, `status`, `name`, `code`, `weight`, `meta`, `creator_id`, `creator`, `modifier_id`, `modifier`, `create_time`, `update_time`, `ui_path`, `is_deleted`, `delete_time`) VALUES(1724395850, 1709194669, 2, 1, '文件-下载', 'db:transfer:files:down', 1724395850, 'null', 12, 'liuzongyang', 12, 'liuzongyang', '2024-08-23 14:50:51', '2024-08-23 14:50:51', 'SmLcpu6c/FmqK4azt/', 0, NULL);
INSERT INTO `t_sys_resource` (`id`, `pid`, `type`, `status`, `name`, `code`, `weight`, `meta`, `creator_id`, `creator`, `modifier_id`, `modifier`, `create_time`, `update_time`, `ui_path`, `is_deleted`, `delete_time`) VALUES(1724398262, 1709194669, 2, 1, '文件', 'db:transfer:files', 1724376021, 'null', 12, 'liuzongyang', 12, 'liuzongyang', '2024-08-23 15:31:02', '2024-08-23 15:31:16', 'SmLcpu6c/btVtrbhk/', 0, NULL);
INSERT INTO `t_sys_resource` (`id`, `pid`, `type`, `status`, `name`, `code`, `weight`, `meta`, `creator_id`, `creator`, `modifier_id`, `modifier`, `create_time`, `update_time`, `ui_path`, `is_deleted`, `delete_time`) VALUES(1724998419, 1709194669, 2, 1, '文件-执行', 'db:transfer:files:run', 1724998419, 'null', 12, 'liuzongyang', 12, 'liuzongyang', '2024-08-30 14:13:39', '2024-08-30 14:13:39', 'SmLcpu6c/qINungml/', 0, NULL);
INSERT INTO `t_sys_resource` (`id`, `pid`, `ui_path`, `type`, `status`, `name`, `code`, `weight`, `meta`, `creator_id`, `creator`, `modifier_id`, `modifier`, `create_time`, `update_time`, `is_deleted`, `delete_time`) VALUES(1729668131, 38, 'dbms23ax/exaeca2x/TGFPA3Ez/', 2, 1, 'SQL脚本执行', 'db:sqlscript:run', 1729668131, 'null', 1, 'admin', 1, 'admin', '2024-10-23 15:22:12', '2024-10-23 15:22:12', 0, NULL);
-- 新增数据库迁移相关的系统配置
DELETE FROM `t_sys_config` WHERE `key` = 'DbBackupRestore';
@@ -46,6 +47,11 @@ CREATE TABLE `t_db_transfer_files` (
ALTER TABLE `t_flow_procdef`
ADD COLUMN `condition` text NULL comment '触发审批的条件计算结果返回1则需要启用该流程';
UPDATE `t_flow_procinst`
SET `biz_type` = 'redis_run_cmd_flow'
WHERE
`biz_type` = 'redis_run_write_cmd_flow';
CREATE TABLE `t_sys_file` (
`id` bigint UNSIGNED NOT NULL AUTO_INCREMENT,
`file_key` varchar(32) NOT NULL COMMENT 'key',