mirror of
https://gitee.com/dromara/mayfly-go
synced 2025-11-03 07:50:25 +08:00
refactor: 消息模块重构,infra包路径简写等
This commit is contained in:
@@ -10,16 +10,16 @@ require (
|
||||
github.com/gin-gonic/gin v1.10.1
|
||||
github.com/glebarez/sqlite v1.11.0
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.1.4
|
||||
github.com/go-ldap/ldap/v3 v3.4.8
|
||||
github.com/go-ldap/ldap/v3 v3.4.11
|
||||
github.com/go-playground/locales v0.14.1
|
||||
github.com/go-playground/universal-translator v0.18.1
|
||||
github.com/go-playground/validator/v10 v10.26.0
|
||||
github.com/go-playground/validator/v10 v10.27.0
|
||||
github.com/go-sql-driver/mysql v1.9.3
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/gorilla/websocket v1.5.3
|
||||
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20250508043914-ed57fa5c5274
|
||||
github.com/microsoft/go-mssqldb v1.9.1
|
||||
github.com/lionsoul2014/ip2region/binding/golang v0.0.0-20250630080345-f9402614f6ba
|
||||
github.com/microsoft/go-mssqldb v1.9.2
|
||||
github.com/mojocn/base64Captcha v1.3.8 // 验证码
|
||||
github.com/pkg/errors v0.9.1
|
||||
github.com/pkg/sftp v1.13.9
|
||||
@@ -32,33 +32,32 @@ require (
|
||||
github.com/tidwall/gjson v1.18.0
|
||||
github.com/veops/go-ansiterm v0.0.5
|
||||
go.mongodb.org/mongo-driver/v2 v2.2.2 // mongo
|
||||
golang.org/x/crypto v0.39.0 // ssh
|
||||
golang.org/x/crypto v0.40.0 // ssh
|
||||
golang.org/x/oauth2 v0.30.0
|
||||
golang.org/x/sync v0.15.0
|
||||
golang.org/x/sync v0.16.0
|
||||
gopkg.in/natefinch/lumberjack.v2 v2.2.1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
// gorm
|
||||
gorm.io/driver/mysql v1.6.0
|
||||
gorm.io/gorm v1.30.0
|
||||
gorm.io/gorm v1.30.1
|
||||
)
|
||||
|
||||
require (
|
||||
filippo.io/edwards25519 v1.1.0 // indirect
|
||||
github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect
|
||||
github.com/boombuler/barcode v1.0.1-0.20190219062509-6c824513bacc // indirect
|
||||
github.com/bytedance/sonic v1.11.6 // indirect
|
||||
github.com/bytedance/sonic/loader v0.1.1 // indirect
|
||||
github.com/boombuler/barcode v1.1.0 // indirect
|
||||
github.com/bytedance/sonic v1.14.0 // indirect
|
||||
github.com/bytedance/sonic/loader v0.3.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.4 // indirect
|
||||
github.com/cloudwego/iasm v0.2.0 // indirect
|
||||
github.com/cloudwego/base64x v0.1.5 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||
github.com/gin-contrib/sse v0.1.0 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect
|
||||
github.com/goccy/go-json v0.10.2 // indirect
|
||||
github.com/gabriel-vasile/mimetype v1.4.9 // indirect
|
||||
github.com/gin-contrib/sse v1.1.0 // indirect
|
||||
github.com/glebarez/go-sqlite v1.22.0 // indirect
|
||||
github.com/go-asn1-ber/asn1-ber v1.5.8-0.20250403174932-29230038a667 // indirect
|
||||
github.com/goccy/go-json v0.10.5 // indirect
|
||||
github.com/golang-sql/civil v0.0.0-20220223132316-b832511892a9 // indirect
|
||||
github.com/golang-sql/sqlexp v0.1.0 // indirect
|
||||
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
|
||||
@@ -66,15 +65,16 @@ require (
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/klauspost/compress v1.16.7 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.2.7 // indirect
|
||||
github.com/klauspost/compress v1.18.0 // indirect
|
||||
github.com/klauspost/cpuid/v2 v2.3.0 // indirect
|
||||
github.com/kr/fs v0.1.0 // indirect
|
||||
github.com/leodido/go-urn v1.4.0 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||
github.com/modern-go/reflect2 v1.0.2 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.2 // indirect
|
||||
github.com/ncruces/go-strftime v0.1.9 // indirect
|
||||
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.4.7 // indirect
|
||||
@@ -83,20 +83,20 @@ require (
|
||||
github.com/tidwall/pretty v1.2.1 // indirect
|
||||
github.com/tjfoc/gmsm v1.4.1 // indirect
|
||||
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
|
||||
github.com/ugorji/go/codec v1.2.12 // indirect
|
||||
github.com/ugorji/go/codec v1.3.0 // indirect
|
||||
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
|
||||
github.com/xdg-go/scram v1.1.2 // indirect
|
||||
github.com/xdg-go/stringprep v1.0.4 // indirect
|
||||
github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect
|
||||
golang.org/x/arch v0.14.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250210185358-939b2ce775ac // indirect
|
||||
golang.org/x/image v0.23.0 // indirect
|
||||
golang.org/x/net v0.40.0 // indirect
|
||||
golang.org/x/sys v0.33.0 // indirect
|
||||
golang.org/x/text v0.26.0 // indirect
|
||||
google.golang.org/protobuf v1.34.1 // indirect
|
||||
modernc.org/libc v1.22.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/sqlite v1.23.1 // indirect
|
||||
golang.org/x/arch v0.19.0 // indirect
|
||||
golang.org/x/exp v0.0.0-20250718183923-645b1fa84792 // indirect
|
||||
golang.org/x/image v0.29.0 // indirect
|
||||
golang.org/x/net v0.42.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
google.golang.org/protobuf v1.36.6 // indirect
|
||||
modernc.org/libc v1.66.4 // indirect
|
||||
modernc.org/mathutil v1.7.1 // indirect
|
||||
modernc.org/memory v1.11.0 // indirect
|
||||
modernc.org/sqlite v1.38.1 // indirect
|
||||
)
|
||||
|
||||
@@ -47,7 +47,7 @@ func (a *AccountLogin) ReqConfs() *req.Confs {
|
||||
|
||||
// @router /auth/accounts/login [post]
|
||||
func (a *AccountLogin) Login(rc *req.Ctx) {
|
||||
loginForm := req.BindJsonAndValid[*form.LoginForm](rc)
|
||||
loginForm := req.BindJson[*form.LoginForm](rc)
|
||||
ctx := rc.MetaCtx
|
||||
|
||||
accountLoginSecurity := config.GetAccountLoginSecurity()
|
||||
@@ -96,7 +96,7 @@ type OtpVerifyInfo struct {
|
||||
|
||||
// OTP双因素校验
|
||||
func (a *AccountLogin) OtpVerify(rc *req.Ctx) {
|
||||
otpVerify := req.BindJsonAndValid[*form.OtpVerfiy](rc)
|
||||
otpVerify := req.BindJson[*form.OtpVerfiy](rc)
|
||||
ctx := rc.MetaCtx
|
||||
|
||||
tokenKey := fmt.Sprintf("otp:token:%s", otpVerify.OtpToken)
|
||||
|
||||
@@ -6,13 +6,13 @@ import (
|
||||
"mayfly-go/internal/auth/config"
|
||||
"mayfly-go/internal/auth/imsg"
|
||||
"mayfly-go/internal/auth/pkg/otp"
|
||||
msgapp "mayfly-go/internal/msg/application"
|
||||
msgentity "mayfly-go/internal/msg/domain/entity"
|
||||
msgdto "mayfly-go/internal/msg/application/dto"
|
||||
"mayfly-go/internal/pkg/event"
|
||||
sysapp "mayfly-go/internal/sys/application"
|
||||
sysentity "mayfly-go/internal/sys/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/cache"
|
||||
"mayfly-go/pkg/i18n"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/req"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/netx"
|
||||
@@ -114,14 +114,12 @@ func saveLogin(ctx context.Context, account *sysentity.Account, ip string) {
|
||||
// 偷懒为了方便直接获取accountApp
|
||||
biz.ErrIsNil(sysapp.GetAccountApp().Update(context.TODO(), updateAccount))
|
||||
|
||||
// 创建登录消息
|
||||
loginMsg := &msgentity.Msg{
|
||||
RecipientId: int64(account.Id),
|
||||
Msg: i18n.TC(ctx, imsg.LoginMsg, "ip", ip, "time", timex.DefaultFormat(now)),
|
||||
Type: 1,
|
||||
}
|
||||
loginMsg.CreateTime = &now
|
||||
loginMsg.Creator = account.Username
|
||||
loginMsg.CreatorId = account.Id
|
||||
msgapp.GetMsgApp().Create(context.TODO(), loginMsg)
|
||||
global.EventBus.Publish(ctx, event.EventTopicMsgTmplSend, &msgdto.MsgTmplSendEvent{
|
||||
TmplChannel: msgdto.MsgTmplLogin,
|
||||
Params: collx.M{
|
||||
"ip": ip,
|
||||
"time": timex.DefaultFormat(now),
|
||||
},
|
||||
ReceiverIds: []uint64{account.Id},
|
||||
})
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func (a *LdapLogin) GetLdapEnabled(rc *req.Ctx) {
|
||||
|
||||
// @router /auth/ldap/login [post]
|
||||
func (a *LdapLogin) Login(rc *req.Ctx) {
|
||||
loginForm := req.BindJsonAndValid[*form.LoginForm](rc)
|
||||
loginForm := req.BindJson[*form.LoginForm](rc)
|
||||
ctx := rc.MetaCtx
|
||||
accountLoginSecurity := config.GetAccountLoginSecurity()
|
||||
// 判断是否有开启登录验证码校验
|
||||
@@ -197,14 +197,14 @@ func dial(ldapConf *config.LdapLogin) (*ldap.Conn, error) {
|
||||
InsecureSkipVerify: ldapConf.SkipTLSVerify,
|
||||
}
|
||||
if ldapConf.SecurityProtocol == "LDAPS" {
|
||||
conn, err := ldap.DialTLS("tcp", addr, tlsConfig)
|
||||
conn, err := ldap.DialURL("ldaps://"+addr, ldap.DialWithTLSConfig(tlsConfig))
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("dial TLS: %v", err)
|
||||
}
|
||||
return conn, nil
|
||||
}
|
||||
|
||||
conn, err := ldap.Dial("tcp", addr)
|
||||
conn, err := ldap.DialURL("ldap://" + addr)
|
||||
if err != nil {
|
||||
return nil, errors.Errorf("dial: %v", err)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ var En = map[i18n.MsgId]string{
|
||||
ErrOtpCheckRestrict: "Two-factor validation failed more than 5 times. Try again in 10 minutes",
|
||||
ErrOtpCheckFail: "Two-factor authentication authorization code is incorrect",
|
||||
ErrAccountNotAvailable: "Account is not available",
|
||||
LoginMsg: "Log in to [{{.ip}}]-[{{.time}}]",
|
||||
ErrUsernameOrPwdErr: "Wrong username or password",
|
||||
ErrOauth2NoAutoRegister: "the system does not enable automatic registration, please ask the administrator to add the corresponding account first",
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ const (
|
||||
ErrOtpCheckRestrict
|
||||
ErrOtpCheckFail
|
||||
ErrAccountNotAvailable
|
||||
LoginMsg
|
||||
ErrUsernameOrPwdErr
|
||||
ErrOauth2NoAutoRegister
|
||||
)
|
||||
|
||||
@@ -15,7 +15,6 @@ var Zh_CN = map[i18n.MsgId]string{
|
||||
ErrOtpCheckRestrict: "双因素校验失败超过5次, 请10分钟后再试",
|
||||
ErrOtpCheckFail: "双因素认证授权码不正确",
|
||||
ErrAccountNotAvailable: "账号不可用",
|
||||
LoginMsg: "于[{{.ip}}]-[{{.time}}]登录",
|
||||
ErrUsernameOrPwdErr: "用户名或密码错误",
|
||||
ErrOauth2NoAutoRegister: "系统未开启自动注册, 请先让管理员添加对应账号",
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/internal/auth/api"
|
||||
"mayfly-go/internal/auth/application"
|
||||
"mayfly-go/internal/auth/infrastructure/persistence"
|
||||
"mayfly-go/internal/auth/infra/persistence"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -11,15 +11,13 @@ import (
|
||||
"mayfly-go/internal/db/dbm/dbi"
|
||||
"mayfly-go/internal/db/domain/entity"
|
||||
"mayfly-go/internal/db/imsg"
|
||||
"mayfly-go/internal/event"
|
||||
msgapp "mayfly-go/internal/msg/application"
|
||||
msgdto "mayfly-go/internal/msg/application/dto"
|
||||
"mayfly-go/internal/pkg/event"
|
||||
"mayfly-go/internal/pkg/utils"
|
||||
tagapp "mayfly-go/internal/tag/application"
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/i18n"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/req"
|
||||
@@ -36,7 +34,6 @@ type Db struct {
|
||||
instanceApp application.Instance `inject:"T"`
|
||||
dbApp application.Db `inject:"T"`
|
||||
dbSqlExecApp application.DbSqlExec `inject:"T"`
|
||||
msgApp msgapp.Msg `inject:"T"`
|
||||
tagApp tagapp.TagTree `inject:"T"`
|
||||
}
|
||||
|
||||
@@ -135,7 +132,7 @@ func (d *Db) DeleteDb(rc *req.Ctx) {
|
||||
/** 数据库操作相关、执行sql等 ***/
|
||||
|
||||
func (d *Db) ExecSql(rc *req.Ctx) {
|
||||
form := req.BindJsonAndValid[*form.DbSqlExecForm](rc)
|
||||
form := req.BindJson[*form.DbSqlExecForm](rc)
|
||||
|
||||
ctx, cancel := context.WithTimeout(rc.MetaCtx, time.Duration(config.GetDbms().SqlExecTl)*time.Second)
|
||||
defer cancel()
|
||||
@@ -167,17 +164,6 @@ func (d *Db) ExecSql(rc *req.Ctx) {
|
||||
rc.ResData = execRes
|
||||
}
|
||||
|
||||
// progressCategory sql文件执行进度消息类型
|
||||
const progressCategory = "execSqlFileProgress"
|
||||
|
||||
// progressMsg sql文件执行进度消息
|
||||
type progressMsg struct {
|
||||
Id string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
ExecutedStatements int `json:"executedStatements"`
|
||||
Terminated bool `json:"terminated"`
|
||||
}
|
||||
|
||||
// 执行sql文件
|
||||
func (d *Db) ExecSqlFile(rc *req.Ctx) {
|
||||
multipart, err := rc.GetRequest().MultipartReader()
|
||||
@@ -246,7 +232,11 @@ func (d *Db) DumpSql(rc *req.Ctx) {
|
||||
if len(msg) > 0 {
|
||||
msg = "DB dump error: " + msg
|
||||
rc.GetWriter().Write([]byte(msg))
|
||||
d.msgApp.CreateAndSend(la, msgdto.ErrSysMsg(i18n.T(imsg.DbDumpErr), msg))
|
||||
global.EventBus.Publish(rc.MetaCtx, event.EventTopicMsgTmplSend, &msgdto.MsgTmplSendEvent{
|
||||
TmplChannel: msgdto.MsgTmplDbDumpFail,
|
||||
Params: collx.M{"error": msg},
|
||||
ReceiverIds: []uint64{la.Id},
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
|
||||
@@ -87,7 +87,7 @@ func (d *DataSyncTask) DeleteTask(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *DataSyncTask) ChangeStatus(rc *req.Ctx) {
|
||||
form := req.BindJsonAndValid[*form.DataSyncTaskStatusForm](rc)
|
||||
form := req.BindJson[*form.DataSyncTaskStatusForm](rc)
|
||||
rc.ReqParam = form
|
||||
|
||||
task, err := d.dataSyncTaskApp.GetById(form.Id)
|
||||
|
||||
@@ -30,7 +30,7 @@ func (d *DbSql) ReqConfs() *req.Confs {
|
||||
|
||||
// @router /api/db/:dbId/sql [post]
|
||||
func (d *DbSql) SaveSql(rc *req.Ctx) {
|
||||
dbSqlForm := req.BindJsonAndValid[*form.DbSqlSaveForm](rc)
|
||||
dbSqlForm := req.BindJson[*form.DbSqlSaveForm](rc)
|
||||
rc.ReqParam = dbSqlForm
|
||||
|
||||
dbId := getDbId(rc)
|
||||
|
||||
@@ -93,7 +93,7 @@ func (d *DbTransferTask) DeleteTask(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *DbTransferTask) ChangeStatus(rc *req.Ctx) {
|
||||
form := req.BindJsonAndValid[*form.DbTransferTaskStatusForm](rc)
|
||||
form := req.BindJson[*form.DbTransferTaskStatusForm](rc)
|
||||
rc.ReqParam = form
|
||||
|
||||
task, err := d.dbTransferTaskApp.GetById(form.Id)
|
||||
@@ -136,7 +136,7 @@ func (d *DbTransferTask) FileDel(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (d *DbTransferTask) FileRun(rc *req.Ctx) {
|
||||
fm := req.BindJsonAndValid[*form.DbTransferFileRunForm](rc)
|
||||
fm := req.BindJson[*form.DbTransferFileRunForm](rc)
|
||||
|
||||
rc.ReqParam = fm
|
||||
|
||||
|
||||
@@ -13,19 +13,19 @@ import (
|
||||
"mayfly-go/internal/db/imsg"
|
||||
flowapp "mayfly-go/internal/flow/application"
|
||||
flowentity "mayfly-go/internal/flow/domain/entity"
|
||||
msgapp "mayfly-go/internal/msg/application"
|
||||
msgdto "mayfly-go/internal/msg/application/dto"
|
||||
"mayfly-go/internal/pkg/event"
|
||||
"mayfly-go/pkg/contextx"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/i18n"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/jsonx"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
"mayfly-go/pkg/ws"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type sqlExecParam struct {
|
||||
@@ -71,7 +71,6 @@ type dbSqlExecAppImpl struct {
|
||||
dbSqlExecRepo repository.DbSqlExec `inject:"T"`
|
||||
|
||||
flowProcdefApp flowapp.Procdef `inject:"T"`
|
||||
msgApp msgapp.Msg `inject:"T"`
|
||||
}
|
||||
|
||||
func createSqlExecRecord(ctx context.Context, execSqlReq *dto.DbSqlExecReq, sql string) *entity.DbSqlExec {
|
||||
@@ -206,38 +205,55 @@ func (d *dbSqlExecAppImpl) ExecReader(ctx context.Context, execReader *dto.SqlRe
|
||||
la := contextx.GetLoginAccount(ctx)
|
||||
needSendMsg := la != nil && clientId != ""
|
||||
|
||||
startTime := time.Now()
|
||||
executedStatements := 0
|
||||
progressId := stringx.Rand(32)
|
||||
|
||||
msgEvent := &msgdto.MsgTmplSendEvent{
|
||||
TmplChannel: msgdto.MsgTmplSqlScriptRunSuccess,
|
||||
Params: collx.M{"filename": filename, "db": dbConn.Info.GetLogDesc()},
|
||||
}
|
||||
|
||||
progressMsgEvent := &msgdto.MsgTmplSendEvent{
|
||||
TmplChannel: msgdto.MsgTmplSqlScriptRunProgress,
|
||||
Params: collx.M{
|
||||
"id": progressId,
|
||||
"title": filename,
|
||||
"executedStatements": executedStatements,
|
||||
"terminated": false,
|
||||
"clientId": clientId,
|
||||
},
|
||||
}
|
||||
|
||||
if needSendMsg {
|
||||
msgEvent.ReceiverIds = []uint64{la.Id}
|
||||
progressMsgEvent.ReceiverIds = []uint64{la.Id}
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if needSendMsg {
|
||||
progressMsgEvent.Params["terminated"] = true
|
||||
global.EventBus.Publish(ctx, event.EventTopicMsgTmplSend, progressMsgEvent)
|
||||
}
|
||||
|
||||
if err := recover(); err != nil {
|
||||
errInfo := anyx.ToString(err)
|
||||
logx.Errorf("exec sql reader error: %s", errInfo)
|
||||
if needSendMsg {
|
||||
errInfo = stringx.Truncate(errInfo, 300, 10, "...")
|
||||
d.msgApp.CreateAndSend(la, msgdto.ErrSysMsg(i18n.T(imsg.SqlScriptRunFail), fmt.Sprintf("[%s][%s] execution failure: [%s]", filename, dbConn.Info.GetLogDesc(), errInfo)).WithClientId(clientId))
|
||||
msgEvent.TmplChannel = msgdto.MsgTmplSqlScriptRunFail
|
||||
msgEvent.Params["error"] = errInfo
|
||||
global.EventBus.Publish(ctx, event.EventTopicMsgTmplSend, msgEvent)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
executedStatements := 0
|
||||
progressId := stringx.Rand(32)
|
||||
if needSendMsg {
|
||||
defer ws.SendJsonMsg(ws.UserId(la.Id), clientId, msgdto.InfoSysMsg(i18n.T(imsg.SqlScripRunProgress), &progressMsg{
|
||||
Id: progressId,
|
||||
Title: filename,
|
||||
ExecutedStatements: executedStatements,
|
||||
Terminated: true,
|
||||
}).WithCategory(progressCategory))
|
||||
}
|
||||
|
||||
tx, _ := dbConn.Begin()
|
||||
err := sqlparser.SQLSplit(execReader.Reader, ';', func(sql string) error {
|
||||
if executedStatements%50 == 0 {
|
||||
if needSendMsg {
|
||||
ws.SendJsonMsg(ws.UserId(la.Id), clientId, msgdto.InfoSysMsg(i18n.T(imsg.SqlScripRunProgress), &progressMsg{
|
||||
Id: progressId,
|
||||
Title: filename,
|
||||
ExecutedStatements: executedStatements,
|
||||
Terminated: false,
|
||||
}).WithCategory(progressCategory))
|
||||
progressMsgEvent.Params["executedStatements"] = executedStatements
|
||||
global.EventBus.Publish(ctx, event.EventTopicMsgTmplSend, progressMsgEvent)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -249,12 +265,18 @@ func (d *dbSqlExecAppImpl) ExecReader(ctx context.Context, execReader *dto.SqlRe
|
||||
})
|
||||
if err != nil {
|
||||
_ = tx.Rollback()
|
||||
if needSendMsg {
|
||||
msgEvent.TmplChannel = msgdto.MsgTmplSqlScriptRunFail
|
||||
msgEvent.Params["error"] = err.Error()
|
||||
global.EventBus.Publish(ctx, event.EventTopicMsgTmplSend, msgEvent)
|
||||
}
|
||||
return err
|
||||
}
|
||||
_ = tx.Commit()
|
||||
|
||||
if needSendMsg {
|
||||
d.msgApp.CreateAndSend(la, msgdto.SuccessSysMsg(i18n.T(imsg.SqlScriptRunSuccess), "execution success").WithClientId(clientId))
|
||||
msgEvent.Params["cost"] = fmt.Sprintf("%dms", time.Since(startTime).Milliseconds())
|
||||
global.EventBus.Publish(ctx, event.EventTopicMsgTmplSend, msgEvent)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -14,10 +14,7 @@ var En = map[i18n.MsgId]string{
|
||||
LogDbRunSql: "DB - Run SQL",
|
||||
LogDbDump: "DB - Export DB",
|
||||
|
||||
SqlScriptRunFail: "sql script failed to execute",
|
||||
SqlScriptRunSuccess: "sql script executed successfully",
|
||||
SqlScripRunProgress: "sql execution progress",
|
||||
DbDumpErr: "Database export failed",
|
||||
ErrDbNameExist: "The database name already exists in this instance",
|
||||
ErrDbNotAccess: "The operation permissions of database [{{.dbName}}] are not configured",
|
||||
|
||||
|
||||
@@ -24,10 +24,7 @@ const (
|
||||
LogDbRunSqlFile
|
||||
LogDbDump
|
||||
|
||||
SqlScriptRunFail
|
||||
SqlScriptRunSuccess
|
||||
SqlScripRunProgress
|
||||
DbDumpErr
|
||||
ErrDbNameExist
|
||||
ErrDbNotAccess
|
||||
|
||||
|
||||
@@ -14,10 +14,7 @@ var Zh_CN = map[i18n.MsgId]string{
|
||||
LogDbRunSql: "DB-运行SQL",
|
||||
LogDbDump: "DB-导出数据库",
|
||||
|
||||
SqlScriptRunFail: "sql脚本执行失败",
|
||||
SqlScriptRunSuccess: "sql脚本执行成功",
|
||||
SqlScripRunProgress: "sql执行进度",
|
||||
DbDumpErr: "数据库导出失败",
|
||||
ErrDbNameExist: "该实例下数据库名已存在",
|
||||
ErrDbNotAccess: "未配置数据库【{{.dbName}}】的操作权限",
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/internal/db/api"
|
||||
"mayfly-go/internal/db/application"
|
||||
"mayfly-go/internal/db/infrastructure/persistence"
|
||||
"mayfly-go/internal/db/infra/persistence"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/internal/es/api"
|
||||
"mayfly-go/internal/es/application"
|
||||
"mayfly-go/internal/es/infrastructure/persistence"
|
||||
"mayfly-go/internal/es/infra/persistence"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
package persistence
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/file/domain/entity"
|
||||
"mayfly-go/internal/file/domain/repository"
|
||||
"mayfly-go/pkg/base"
|
||||
)
|
||||
|
||||
type fileRepoImpl struct {
|
||||
base.RepoImpl[*entity.File]
|
||||
}
|
||||
|
||||
func newFileRepo() repository.File {
|
||||
return &fileRepoImpl{}
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
package persistence
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/ioc"
|
||||
)
|
||||
|
||||
func InitIoc() {
|
||||
ioc.Register(newFileRepo(), ioc.WithComponentName("FileRepo"))
|
||||
}
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/internal/file/api"
|
||||
"mayfly-go/internal/file/application"
|
||||
"mayfly-go/internal/file/infrastructure/persistence"
|
||||
"mayfly-go/internal/file/infra/persistence"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -97,7 +97,7 @@ func (a *Procdef) Save(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (a *Procdef) SaveFlowDef(rc *req.Ctx) {
|
||||
form := req.BindJsonAndValid[*form.ProcdefFlow](rc)
|
||||
form := req.BindJson[*form.ProcdefFlow](rc)
|
||||
rc.ReqParam = form
|
||||
|
||||
biz.ErrIsNil(a.procdefApp.SaveFlowDef(rc.MetaCtx, &dto.SaveFlowDef{
|
||||
|
||||
@@ -47,7 +47,7 @@ func (p *Procinst) GetProcinstPage(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (p *Procinst) ProcinstStart(rc *req.Ctx) {
|
||||
startForm := req.BindJsonAndValid[*form.ProcinstStart](rc)
|
||||
startForm := req.BindJson[*form.ProcinstStart](rc)
|
||||
_, err := p.procinstApp.StartProc(rc.MetaCtx, startForm.ProcdefId, &dto.StarProc{
|
||||
BizType: startForm.BizType,
|
||||
BizForm: jsonx.ToStr(startForm.BizForm),
|
||||
|
||||
@@ -74,7 +74,7 @@ func (p *ProcinstTask) GetTasks(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (p *ProcinstTask) PassTask(rc *req.Ctx) {
|
||||
auditForm := req.BindJsonAndValid[*form.ProcinstTaskAudit](rc)
|
||||
auditForm := req.BindJson[*form.ProcinstTaskAudit](rc)
|
||||
rc.ReqParam = auditForm
|
||||
|
||||
la := rc.GetLoginAccount()
|
||||
@@ -84,7 +84,7 @@ func (p *ProcinstTask) PassTask(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (p *ProcinstTask) RejectTask(rc *req.Ctx) {
|
||||
auditForm := req.BindJsonAndValid[*form.ProcinstTaskAudit](rc)
|
||||
auditForm := req.BindJson[*form.ProcinstTaskAudit](rc)
|
||||
rc.ReqParam = auditForm
|
||||
|
||||
la := rc.GetLoginAccount()
|
||||
@@ -94,7 +94,7 @@ func (p *ProcinstTask) RejectTask(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (p *ProcinstTask) BackTask(rc *req.Ctx) {
|
||||
auditForm := req.BindJsonAndValid[*form.ProcinstTaskAudit](rc)
|
||||
auditForm := req.BindJson[*form.ProcinstTaskAudit](rc)
|
||||
rc.ReqParam = auditForm
|
||||
biz.ErrIsNil(p.procinstTaskApp.BackTask(rc.MetaCtx, dto.UserTaskOp{TaskId: auditForm.Id, Remark: auditForm.Remark}))
|
||||
}
|
||||
|
||||
@@ -2,11 +2,11 @@ package application
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mayfly-go/internal/event"
|
||||
"mayfly-go/internal/flow/domain/entity"
|
||||
"mayfly-go/internal/flow/imsg"
|
||||
"mayfly-go/internal/flow/infrastructure/persistence"
|
||||
"mayfly-go/internal/flow/infra/persistence"
|
||||
msgdto "mayfly-go/internal/msg/application/dto"
|
||||
"mayfly-go/internal/pkg/event"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/global"
|
||||
"strings"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/internal/flow/api"
|
||||
"mayfly-go/internal/flow/application"
|
||||
"mayfly-go/internal/flow/infrastructure/persistence"
|
||||
"mayfly-go/internal/flow/infra/persistence"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -2,7 +2,6 @@ package api
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"mayfly-go/internal/event"
|
||||
"mayfly-go/internal/machine/api/form"
|
||||
"mayfly-go/internal/machine/api/vo"
|
||||
"mayfly-go/internal/machine/application"
|
||||
@@ -12,6 +11,7 @@ import (
|
||||
"mayfly-go/internal/machine/imsg"
|
||||
"mayfly-go/internal/machine/mcm"
|
||||
"mayfly-go/internal/pkg/consts"
|
||||
"mayfly-go/internal/pkg/event"
|
||||
tagapp "mayfly-go/internal/tag/application"
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
|
||||
@@ -12,15 +12,14 @@ import (
|
||||
"mayfly-go/internal/machine/domain/entity"
|
||||
"mayfly-go/internal/machine/imsg"
|
||||
"mayfly-go/internal/machine/mcm"
|
||||
msgapp "mayfly-go/internal/msg/application"
|
||||
msgdto "mayfly-go/internal/msg/application/dto"
|
||||
"mayfly-go/internal/pkg/event"
|
||||
"mayfly-go/pkg/biz"
|
||||
"mayfly-go/pkg/errorx"
|
||||
"mayfly-go/pkg/i18n"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/logx"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/req"
|
||||
"mayfly-go/pkg/utils/anyx"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
"mayfly-go/pkg/utils/timex"
|
||||
"mime/multipart"
|
||||
@@ -36,7 +35,6 @@ import (
|
||||
|
||||
type MachineFile struct {
|
||||
machineFileApp application.MachineFile `inject:"T"`
|
||||
msgApp msgapp.Msg `inject:"T"`
|
||||
}
|
||||
|
||||
func (mf *MachineFile) ReqConfs() *req.Confs {
|
||||
@@ -106,7 +104,7 @@ func (m *MachineFile) DeleteFile(rc *req.Ctx) {
|
||||
/*** sftp相关操作 */
|
||||
|
||||
func (m *MachineFile) CreateFile(rc *req.Ctx) {
|
||||
opForm := req.BindJsonAndValid[*form.CreateFileForm](rc)
|
||||
opForm := req.BindJson[*form.CreateFileForm](rc)
|
||||
path := opForm.Path
|
||||
|
||||
attrs := collx.Kvs("path", path)
|
||||
@@ -239,7 +237,7 @@ func (m *MachineFile) GetFileStat(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineFile) WriteFileContent(rc *req.Ctx) {
|
||||
opForm := req.BindJsonAndValid[*form.WriteFileContentForm](rc)
|
||||
opForm := req.BindJson[*form.WriteFileContentForm](rc)
|
||||
path := opForm.Path
|
||||
|
||||
mi, err := m.machineFileApp.WriteFileContent(rc.MetaCtx, opForm.MachineFileOp, []byte(opForm.Content))
|
||||
@@ -264,14 +262,6 @@ func (m *MachineFile) UploadFile(rc *req.Ctx) {
|
||||
file, _ := fileheader.Open()
|
||||
defer file.Close()
|
||||
|
||||
la := rc.GetLoginAccount()
|
||||
defer func() {
|
||||
if anyx.ToString(recover()) != "" {
|
||||
logx.Errorf("upload file error: %s", err)
|
||||
m.msgApp.CreateAndSend(la, msgdto.ErrSysMsg(i18n.TC(ctx, imsg.ErrFileUploadFail), fmt.Sprintf("%s: \n<-e : %s", i18n.TC(ctx, imsg.ErrFileUploadFail), err)))
|
||||
}
|
||||
}()
|
||||
|
||||
opForm := &dto.MachineFileOp{
|
||||
MachineId: machineId,
|
||||
AuthCertName: authCertName,
|
||||
@@ -281,9 +271,27 @@ func (m *MachineFile) UploadFile(rc *req.Ctx) {
|
||||
|
||||
mi, err := m.machineFileApp.UploadFile(ctx, opForm, fileheader.Filename, file)
|
||||
rc.ReqParam = collx.Kvs("machine", mi, "path", fmt.Sprintf("%s/%s", path, fileheader.Filename))
|
||||
|
||||
// 发送文件上传结果消息
|
||||
msgEvent := &msgdto.MsgTmplSendEvent{
|
||||
TmplChannel: msgdto.MsgTmplMachineFileUploadSuccess,
|
||||
Params: collx.M{
|
||||
"filename": fileheader.Filename,
|
||||
"path": path,
|
||||
},
|
||||
ReceiverIds: []uint64{rc.GetLoginAccount().Id},
|
||||
}
|
||||
if err != nil {
|
||||
msgEvent.Params["error"] = err.Error()
|
||||
msgEvent.TmplChannel = msgdto.MsgTmplMachineFileUploadFail
|
||||
}
|
||||
if mi != nil {
|
||||
msgEvent.Params["machineName"] = mi.Name
|
||||
msgEvent.Params["machineIp"] = mi.Ip
|
||||
}
|
||||
global.EventBus.Publish(ctx, event.EventTopicMsgTmplSend, msgEvent)
|
||||
|
||||
biz.ErrIsNilAppendErr(err, "upload file error: %s")
|
||||
// 保存消息并发送文件上传成功通知
|
||||
m.msgApp.CreateAndSend(la, msgdto.SuccessSysMsg(i18n.TC(ctx, imsg.MsgUploadFileSuccess), fmt.Sprintf("[%s] -> %s[%s:%s]", fileheader.Filename, mi.Name, mi.Ip, path)))
|
||||
}
|
||||
|
||||
type FolderFile struct {
|
||||
@@ -350,6 +358,17 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
|
||||
}
|
||||
}
|
||||
|
||||
msgEvent := &msgdto.MsgTmplSendEvent{
|
||||
TmplChannel: msgdto.MsgTmplMachineFileUploadSuccess,
|
||||
Params: collx.M{
|
||||
"filename": folderName,
|
||||
"path": basePath,
|
||||
"machineName": mi.Name,
|
||||
"machineIp": mi.Ip,
|
||||
},
|
||||
ReceiverIds: []uint64{rc.GetLoginAccount().Id},
|
||||
}
|
||||
|
||||
// 分组处理
|
||||
groupNum := 30
|
||||
chunks := collx.ArraySplit(folderFiles, groupNum)
|
||||
@@ -359,7 +378,6 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
|
||||
wg.Add(len(chunks))
|
||||
|
||||
isSuccess := true
|
||||
la := rc.GetLoginAccount()
|
||||
for _, chunk := range chunks {
|
||||
go func(files []FolderFile, wg *sync.WaitGroup) {
|
||||
defer func() {
|
||||
@@ -370,7 +388,11 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
|
||||
logx.Errorf("upload file error: %s", err)
|
||||
switch t := err.(type) {
|
||||
case *errorx.BizError:
|
||||
m.msgApp.CreateAndSend(la, msgdto.ErrSysMsg(i18n.TC(ctx, imsg.ErrFileUploadFail), fmt.Sprintf("%s: \n<-e errCode: %d, errMsg: %s", i18n.TC(ctx, imsg.ErrFileUploadFail), t.Code(), t.Error())))
|
||||
{
|
||||
msgEvent.TmplChannel = msgdto.MsgTmplMachineFileUploadFail
|
||||
msgEvent.Params["error"] = t.Error()
|
||||
global.EventBus.Publish(ctx, event.EventTopicMsgTmplSend, msgEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}()
|
||||
@@ -394,13 +416,12 @@ func (m *MachineFile) UploadFolder(rc *req.Ctx) {
|
||||
// 等待所有协程执行完成
|
||||
wg.Wait()
|
||||
if isSuccess {
|
||||
// 保存消息并发送文件上传成功通知
|
||||
m.msgApp.CreateAndSend(la, msgdto.SuccessSysMsg(i18n.TC(ctx, imsg.MsgUploadFileSuccess), fmt.Sprintf("[%s] -> %s[%s:%s]", folderName, mi.Name, mi.Ip, basePath)))
|
||||
global.EventBus.Publish(ctx, event.EventTopicMsgTmplSend, msgEvent)
|
||||
}
|
||||
}
|
||||
|
||||
func (m *MachineFile) RemoveFile(rc *req.Ctx) {
|
||||
opForm := req.BindJsonAndValid[*form.RemoveFileForm](rc)
|
||||
opForm := req.BindJson[*form.RemoveFileForm](rc)
|
||||
|
||||
mi, err := m.machineFileApp.RemoveFile(rc.MetaCtx, opForm.MachineFileOp, opForm.Paths...)
|
||||
rc.ReqParam = collx.Kvs("machine", mi, "path", opForm)
|
||||
@@ -408,21 +429,21 @@ func (m *MachineFile) RemoveFile(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *MachineFile) CopyFile(rc *req.Ctx) {
|
||||
opForm := req.BindJsonAndValid[*form.CopyFileForm](rc)
|
||||
opForm := req.BindJson[*form.CopyFileForm](rc)
|
||||
mi, err := m.machineFileApp.Copy(rc.MetaCtx, opForm.MachineFileOp, opForm.ToPath, opForm.Paths...)
|
||||
biz.ErrIsNilAppendErr(err, "file copy error: %s")
|
||||
rc.ReqParam = collx.Kvs("machine", mi, "cp", opForm)
|
||||
}
|
||||
|
||||
func (m *MachineFile) MvFile(rc *req.Ctx) {
|
||||
opForm := req.BindJsonAndValid[*form.CopyFileForm](rc)
|
||||
opForm := req.BindJson[*form.CopyFileForm](rc)
|
||||
mi, err := m.machineFileApp.Mv(rc.MetaCtx, opForm.MachineFileOp, opForm.ToPath, opForm.Paths...)
|
||||
rc.ReqParam = collx.Kvs("machine", mi, "mv", opForm)
|
||||
biz.ErrIsNilAppendErr(err, "file move error: %s")
|
||||
}
|
||||
|
||||
func (m *MachineFile) Rename(rc *req.Ctx) {
|
||||
renameForm := req.BindJsonAndValid[*form.RenameForm](rc)
|
||||
renameForm := req.BindJson[*form.RenameForm](rc)
|
||||
mi, err := m.machineFileApp.Rename(rc.MetaCtx, renameForm.MachineFileOp, renameForm.Newname)
|
||||
rc.ReqParam = collx.Kvs("machine", mi, "rename", renameForm)
|
||||
biz.ErrIsNilAppendErr(err, "file rename error: %s")
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"mayfly-go/internal/machine/domain/entity"
|
||||
"mayfly-go/internal/machine/domain/repository"
|
||||
"mayfly-go/internal/machine/imsg"
|
||||
"mayfly-go/internal/machine/infrastructure/cache"
|
||||
"mayfly-go/internal/machine/infra/cache"
|
||||
"mayfly-go/internal/machine/mcm"
|
||||
tagapp "mayfly-go/internal/tag/application"
|
||||
tagdto "mayfly-go/internal/tag/application/dto"
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/internal/machine/api"
|
||||
"mayfly-go/internal/machine/application"
|
||||
"mayfly-go/internal/machine/infrastructure/persistence"
|
||||
"mayfly-go/internal/machine/infra/persistence"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -2,13 +2,13 @@ package api
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mayfly-go/internal/event"
|
||||
"mayfly-go/internal/mongo/api/form"
|
||||
"mayfly-go/internal/mongo/api/vo"
|
||||
"mayfly-go/internal/mongo/application"
|
||||
"mayfly-go/internal/mongo/domain/entity"
|
||||
"mayfly-go/internal/mongo/imsg"
|
||||
"mayfly-go/internal/pkg/consts"
|
||||
"mayfly-go/internal/pkg/event"
|
||||
tagapp "mayfly-go/internal/tag/application"
|
||||
tagentity "mayfly-go/internal/tag/domain/entity"
|
||||
"mayfly-go/pkg/biz"
|
||||
@@ -146,7 +146,7 @@ func (m *Mongo) Collections(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Mongo) RunCommand(rc *req.Ctx) {
|
||||
commandForm := req.BindJsonAndValid[*form.MongoRunCommand](rc)
|
||||
commandForm := req.BindJson[*form.MongoRunCommand](rc)
|
||||
|
||||
conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
|
||||
biz.ErrIsNil(err)
|
||||
@@ -176,7 +176,7 @@ func (m *Mongo) RunCommand(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Mongo) FindCommand(rc *req.Ctx) {
|
||||
commandForm := req.BindJsonAndValid[*form.MongoFindCommand](rc)
|
||||
commandForm := req.BindJson[*form.MongoFindCommand](rc)
|
||||
|
||||
conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
|
||||
biz.ErrIsNil(err)
|
||||
@@ -211,7 +211,7 @@ func (m *Mongo) FindCommand(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Mongo) UpdateByIdCommand(rc *req.Ctx) {
|
||||
commandForm := req.BindJsonAndValid[*form.MongoUpdateByIdCommand](rc)
|
||||
commandForm := req.BindJson[*form.MongoUpdateByIdCommand](rc)
|
||||
|
||||
conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
|
||||
biz.ErrIsNil(err)
|
||||
@@ -235,7 +235,7 @@ func (m *Mongo) UpdateByIdCommand(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Mongo) DeleteByIdCommand(rc *req.Ctx) {
|
||||
commandForm := req.BindJsonAndValid[*form.MongoUpdateByIdCommand](rc)
|
||||
commandForm := req.BindJson[*form.MongoUpdateByIdCommand](rc)
|
||||
|
||||
conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
|
||||
biz.ErrIsNil(err)
|
||||
@@ -258,7 +258,7 @@ func (m *Mongo) DeleteByIdCommand(rc *req.Ctx) {
|
||||
}
|
||||
|
||||
func (m *Mongo) InsertOneCommand(rc *req.Ctx) {
|
||||
commandForm := req.BindJsonAndValid[*form.MongoInsertCommand](rc)
|
||||
commandForm := req.BindJson[*form.MongoInsertCommand](rc)
|
||||
|
||||
conn, err := m.mongoApp.GetMongoConn(rc.MetaCtx, m.GetMongoId(rc))
|
||||
biz.ErrIsNil(err)
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/internal/mongo/api"
|
||||
"mayfly-go/internal/mongo/application"
|
||||
"mayfly-go/internal/mongo/infrastructure/persistence"
|
||||
"mayfly-go/internal/mongo/infra/persistence"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -14,12 +14,14 @@ type Msg struct {
|
||||
func (m *Msg) ReqConfs() *req.Confs {
|
||||
reqs := [...]*req.Conf{
|
||||
req.NewGet("/self", m.GetMsgs),
|
||||
req.NewGet("/self/unread/count", m.GetUnreadCount),
|
||||
req.NewGet("/self/read", m.ReadMsg),
|
||||
}
|
||||
|
||||
return req.NewConfs("/msgs", reqs[:]...)
|
||||
}
|
||||
|
||||
// 获取账号接收的消息列表
|
||||
// GetMsgs 获取账号接收的消息列表
|
||||
func (m *Msg) GetMsgs(rc *req.Ctx) {
|
||||
condition := &entity.Msg{
|
||||
RecipientId: int64(rc.GetLoginAccount().Id),
|
||||
@@ -28,3 +30,25 @@ func (m *Msg) GetMsgs(rc *req.Ctx) {
|
||||
biz.ErrIsNil(err)
|
||||
rc.ResData = res
|
||||
}
|
||||
|
||||
// GetUnreadCount 获取账号接收的未读消息数量
|
||||
func (m *Msg) GetUnreadCount(rc *req.Ctx) {
|
||||
condition := &entity.Msg{
|
||||
RecipientId: int64(rc.GetLoginAccount().Id),
|
||||
Status: entity.MsgStatusUnRead,
|
||||
}
|
||||
rc.ResData = m.msgApp.CountByCond(condition)
|
||||
}
|
||||
|
||||
// ReadMsg 将账号接收的未读消息标记为已读
|
||||
func (m *Msg) ReadMsg(rc *req.Ctx) {
|
||||
cond := &entity.Msg{
|
||||
RecipientId: int64(rc.GetLoginAccount().Id),
|
||||
Status: entity.MsgStatusUnRead,
|
||||
}
|
||||
cond.Id = uint64(rc.QueryInt("id"))
|
||||
|
||||
biz.ErrIsNil(m.msgApp.UpdateByCond(rc.MetaCtx, &entity.Msg{
|
||||
Status: entity.MsgStatusRead,
|
||||
}, cond))
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ func (m *MsgTmpl) DelMsgTmpls(rc *req.Ctx) {
|
||||
|
||||
func (m *MsgTmpl) SendMsg(rc *req.Ctx) {
|
||||
code := rc.PathParam("code")
|
||||
form := req.BindJsonAndValid[*form.SendMsg](rc)
|
||||
form := req.BindJson[*form.SendMsg](rc)
|
||||
|
||||
rc.ReqParam = form
|
||||
|
||||
|
||||
@@ -15,3 +15,7 @@ func InitIoc() {
|
||||
func GetMsgApp() Msg {
|
||||
return ioc.Get[Msg]("MsgApp")
|
||||
}
|
||||
|
||||
func GetMsgTmplApp() MsgTmpl {
|
||||
return ioc.Get[MsgTmpl]("MsgTmplApp")
|
||||
}
|
||||
|
||||
@@ -2,35 +2,93 @@ package dto
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/msg/domain/entity"
|
||||
"mayfly-go/internal/msg/imsg"
|
||||
"mayfly-go/internal/msg/msgx"
|
||||
"mayfly-go/pkg/i18n"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
)
|
||||
|
||||
type MsgTmplSave struct {
|
||||
model.ExtraData
|
||||
|
||||
Id uint64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Remark string `json:"remark"`
|
||||
Status entity.MsgTmplStatus `json:"status" `
|
||||
Title string `json:"title"`
|
||||
Tmpl string `json:"type"`
|
||||
MsgType msgx.MsgType `json:"msgType"`
|
||||
|
||||
ChannelIds []uint64 `json:"channelIds"`
|
||||
}
|
||||
|
||||
// MsgTmplBizSave 消息模板关联业务信息
|
||||
type MsgTmplBizSave struct {
|
||||
TmplId uint64 // 消息模板id
|
||||
BizId uint64 // 业务id
|
||||
BizType string
|
||||
}
|
||||
|
||||
// BizMsgTmplSend 业务消息模板发送消息
|
||||
type BizMsgTmplSend struct {
|
||||
BizId uint64 // 业务id
|
||||
BizType string
|
||||
type MsgTmplSendEvent struct {
|
||||
TmplChannel *MsgTmplChannel
|
||||
Params map[string]any // 模板占位符参数
|
||||
ReceiverIds []uint64 // 接收人id
|
||||
}
|
||||
|
||||
type MsgTmplChannel struct {
|
||||
Tmpl *entity.MsgTmpl
|
||||
Channels []*entity.MsgChannel
|
||||
}
|
||||
|
||||
var (
|
||||
MsgChannelSite = &entity.MsgChannel{
|
||||
Type: msgx.ChannelTypeSiteMsg,
|
||||
Status: entity.ChannelStatusEnable,
|
||||
}
|
||||
|
||||
MsgChannelWs = &entity.MsgChannel{
|
||||
Type: msgx.ChannelTypeWs,
|
||||
Status: entity.ChannelStatusEnable,
|
||||
}
|
||||
)
|
||||
|
||||
var (
|
||||
MsgTmplLogin = newMsgTmpl(entity.MsgTypeNotify,
|
||||
entity.MsgSubtypeUserLogin,
|
||||
entity.MsgStatusRead,
|
||||
imsg.LoginMsg,
|
||||
MsgChannelSite)
|
||||
|
||||
MsgTmplMachineFileUploadSuccess = newMsgTmpl(entity.MsgTypeNotify,
|
||||
entity.MsgSubtypeMachineFileUploadSuccess,
|
||||
entity.MsgStatusRead,
|
||||
imsg.MachineFileUploadSuccessMsg,
|
||||
MsgChannelSite, MsgChannelWs)
|
||||
|
||||
MsgTmplMachineFileUploadFail = newMsgTmpl(entity.MsgTypeNotify,
|
||||
entity.MsgSubtypeMachineFileUploadFail,
|
||||
entity.MsgStatusRead,
|
||||
imsg.MachineFileUploadFailMsg,
|
||||
MsgChannelSite, MsgChannelWs)
|
||||
|
||||
MsgTmplDbDumpFail = newMsgTmpl(entity.MsgTypeNotify,
|
||||
entity.MsgSubtypeDbDumpFail,
|
||||
entity.MsgStatusRead,
|
||||
imsg.DbDumpFailMsg,
|
||||
MsgChannelSite, MsgChannelWs)
|
||||
|
||||
MsgTmplSqlScriptRunFail = newMsgTmpl(entity.MsgTypeNotify,
|
||||
entity.MsgSubtypeSqlScriptRunFail,
|
||||
entity.MsgStatusRead,
|
||||
imsg.SqlScriptRunFailMsg,
|
||||
MsgChannelSite, MsgChannelWs)
|
||||
|
||||
MsgTmplSqlScriptRunSuccess = newMsgTmpl(entity.MsgTypeNotify,
|
||||
entity.MsgSubtypeSqlScriptRunSuccess,
|
||||
entity.MsgStatusRead,
|
||||
imsg.SqlScriptRunSuccessMsg,
|
||||
MsgChannelSite, MsgChannelWs)
|
||||
|
||||
MsgTmplSqlScriptRunProgress = &MsgTmplChannel{
|
||||
Tmpl: &entity.MsgTmpl{
|
||||
ExtraData: model.ExtraData{
|
||||
Extra: collx.M{
|
||||
"category": "sqlScriptRunProgress",
|
||||
},
|
||||
},
|
||||
},
|
||||
Channels: []*entity.MsgChannel{MsgChannelWs},
|
||||
}
|
||||
)
|
||||
|
||||
func newMsgTmpl(mtype entity.MsgType, subtype entity.MsgSubtype, status entity.MsgStatus, msgId i18n.MsgId, channels ...*entity.MsgChannel) *MsgTmplChannel {
|
||||
msgTmpl := &entity.MsgTmpl{}
|
||||
msgTmpl.SetExtraValue("msgId", msgId)
|
||||
msgTmpl.SetExtraValue("subtype", subtype)
|
||||
msgTmpl.SetExtraValue("type", mtype)
|
||||
msgTmpl.SetExtraValue("status", status)
|
||||
return &MsgTmplChannel{
|
||||
Tmpl: msgTmpl,
|
||||
Channels: channels,
|
||||
}
|
||||
}
|
||||
|
||||
43
server/internal/msg/application/dto/msg_tmpl.go
Normal file
43
server/internal/msg/application/dto/msg_tmpl.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package dto
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/msg/domain/entity"
|
||||
"mayfly-go/internal/msg/msgx"
|
||||
"mayfly-go/pkg/model"
|
||||
)
|
||||
|
||||
type MsgTmplSave struct {
|
||||
model.ExtraData
|
||||
|
||||
Id uint64 `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Remark string `json:"remark"`
|
||||
Status entity.MsgTmplStatus `json:"status" `
|
||||
Title string `json:"title"`
|
||||
Tmpl string `json:"type"`
|
||||
MsgType msgx.MsgType `json:"msgType"`
|
||||
|
||||
ChannelIds []uint64 `json:"channelIds"`
|
||||
}
|
||||
|
||||
// MsgTmplBizSave 消息模板关联业务信息
|
||||
type MsgTmplBizSave struct {
|
||||
TmplId uint64 // 消息模板id
|
||||
BizId uint64 // 业务id
|
||||
BizType string
|
||||
}
|
||||
|
||||
// BizMsgTmplSend 业务消息模板发送消息
|
||||
type BizMsgTmplSend struct {
|
||||
BizId uint64 // 业务id
|
||||
BizType string
|
||||
Params map[string]any // 模板占位符参数
|
||||
ReceiverIds []uint64 // 接收人id
|
||||
}
|
||||
|
||||
type MsgTmplSend struct {
|
||||
Tmpl *entity.MsgTmpl
|
||||
Channels []*entity.MsgChannel
|
||||
Params map[string]any // 模板占位符参数
|
||||
ReceiverIds []uint64 // 接收人id
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package dto
|
||||
|
||||
import "mayfly-go/pkg/utils/anyx"
|
||||
|
||||
// ************** 系统消息 **************
|
||||
|
||||
const SuccessSysMsgType = 1
|
||||
const ErrorSysMsgType = 0
|
||||
const InfoSysMsgType = 2
|
||||
|
||||
// websocket消息
|
||||
type SysMsg struct {
|
||||
Type int `json:"type"` // 消息类型
|
||||
Category string `json:"category"` // 消息类别
|
||||
Title string `json:"title"` // 消息标题
|
||||
Msg string `json:"msg"` // 消息内容
|
||||
|
||||
ClientId string
|
||||
}
|
||||
|
||||
func (sm *SysMsg) WithTitle(title string) *SysMsg {
|
||||
sm.Title = title
|
||||
return sm
|
||||
}
|
||||
|
||||
func (sm *SysMsg) WithCategory(category string) *SysMsg {
|
||||
sm.Category = category
|
||||
return sm
|
||||
}
|
||||
|
||||
func (sm *SysMsg) WithMsg(msg any) *SysMsg {
|
||||
sm.Msg = anyx.ToString(msg)
|
||||
return sm
|
||||
}
|
||||
|
||||
func (sm *SysMsg) WithClientId(clientId string) *SysMsg {
|
||||
sm.ClientId = clientId
|
||||
return sm
|
||||
}
|
||||
|
||||
// 普通消息
|
||||
func InfoSysMsg(title string, msg any) *SysMsg {
|
||||
return &SysMsg{Type: InfoSysMsgType, Title: title, Msg: anyx.ToString(msg)}
|
||||
}
|
||||
|
||||
// 成功消息
|
||||
func SuccessSysMsg(title string, msg any) *SysMsg {
|
||||
return &SysMsg{Type: SuccessSysMsgType, Title: title, Msg: anyx.ToString(msg)}
|
||||
}
|
||||
|
||||
// 错误消息
|
||||
func ErrSysMsg(title string, msg any) *SysMsg {
|
||||
return &SysMsg{Type: ErrorSysMsgType, Title: title, Msg: anyx.ToString(msg)}
|
||||
}
|
||||
@@ -1,27 +1,30 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"cmp"
|
||||
"context"
|
||||
"mayfly-go/internal/msg/application/dto"
|
||||
"mayfly-go/internal/msg/domain/entity"
|
||||
"mayfly-go/internal/msg/domain/repository"
|
||||
"mayfly-go/internal/msg/msgx"
|
||||
"mayfly-go/pkg/base"
|
||||
"mayfly-go/pkg/i18n"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/ws"
|
||||
"time"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
)
|
||||
|
||||
type Msg interface {
|
||||
msgx.MsgSender
|
||||
|
||||
base.App[*entity.Msg]
|
||||
|
||||
GetPageList(condition *entity.Msg, pageParam model.PageParam, orderBy ...string) (*model.PageResult[*entity.Msg], error)
|
||||
|
||||
Create(ctx context.Context, msg *entity.Msg)
|
||||
|
||||
// 创建消息,并通过ws发送
|
||||
CreateAndSend(la *model.LoginAccount, msg *dto.SysMsg)
|
||||
}
|
||||
|
||||
var _ (Msg) = (*msgAppImpl)(nil)
|
||||
|
||||
type msgAppImpl struct {
|
||||
base.AppImpl[*entity.Msg, repository.Msg]
|
||||
|
||||
msgRepo repository.Msg `inject:"T"`
|
||||
}
|
||||
|
||||
@@ -29,13 +32,29 @@ func (a *msgAppImpl) GetPageList(condition *entity.Msg, pageParam model.PagePara
|
||||
return a.msgRepo.GetPageList(condition, pageParam)
|
||||
}
|
||||
|
||||
func (a *msgAppImpl) Create(ctx context.Context, msg *entity.Msg) {
|
||||
a.msgRepo.Insert(ctx, msg)
|
||||
}
|
||||
func (a *msgAppImpl) Send(ctx context.Context, channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
// 存在i18n msgId,content则使用msgId翻译
|
||||
if msgId := msg.TmplExtra.GetInt("msgId"); msgId != 0 {
|
||||
msg.Content = i18n.TC(ctx, i18n.MsgId(msgId))
|
||||
}
|
||||
content, err := stringx.TemplateParse(msg.Content, msg.Params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
func (a *msgAppImpl) CreateAndSend(la *model.LoginAccount, wmsg *dto.SysMsg) {
|
||||
now := time.Now()
|
||||
msg := &entity.Msg{Type: 2, Msg: wmsg.Msg, RecipientId: int64(la.Id), CreateTime: &now, CreatorId: la.Id, Creator: la.Username}
|
||||
a.msgRepo.Insert(context.TODO(), msg)
|
||||
ws.SendJsonMsg(ws.UserId(la.Id), wmsg.ClientId, wmsg)
|
||||
for _, receiver := range msg.Receivers {
|
||||
msgEntity := &entity.Msg{
|
||||
Msg: content,
|
||||
RecipientId: int64(receiver.Id),
|
||||
Type: entity.MsgType(msg.TmplExtra.GetInt("type")),
|
||||
Subtype: entity.MsgSubtype(msg.TmplExtra.GetStr("subtype")),
|
||||
Status: cmp.Or(entity.MsgStatus(msg.TmplExtra.GetInt("status")), entity.MsgStatusRead),
|
||||
}
|
||||
msgEntity.Extra = msg.Params
|
||||
if err := a.Save(ctx, msgEntity); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -31,6 +31,8 @@ type MsgTmpl interface {
|
||||
// Send 发送消息
|
||||
Send(ctx context.Context, tmplCode string, params map[string]any, receiverId ...uint64) error
|
||||
|
||||
SendMsg(ctx context.Context, mts *dto.MsgTmplSend) error
|
||||
|
||||
// DeleteTmplChannel 删除指定渠道关联的模板
|
||||
DeleteTmplChannel(ctx context.Context, channelId uint64) error
|
||||
}
|
||||
@@ -153,47 +155,52 @@ func (m *msgTmplAppImpl) Send(ctx context.Context, tmplCode string, params map[s
|
||||
return err
|
||||
}
|
||||
|
||||
// content, err := stringx.TemplateParse(tmpl.Tmpl, params)
|
||||
// if err != nil {
|
||||
// return err
|
||||
// }
|
||||
|
||||
// toAll := len(receiverId) == 0
|
||||
accounts, err := m.accountApp.GetByIds(receiverId)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return m.SendMsg(ctx, &dto.MsgTmplSend{
|
||||
Tmpl: tmpl,
|
||||
Channels: channels,
|
||||
Params: params,
|
||||
ReceiverIds: receiverId,
|
||||
})
|
||||
}
|
||||
|
||||
func (m *msgTmplAppImpl) SendMsg(ctx context.Context, mts *dto.MsgTmplSend) error {
|
||||
tmpl := mts.Tmpl
|
||||
msg := &msgx.Msg{
|
||||
Content: tmpl.Tmpl,
|
||||
Params: params,
|
||||
Params: mts.Params,
|
||||
Title: tmpl.Title,
|
||||
Type: tmpl.MsgType,
|
||||
ExtraData: tmpl.ExtraData,
|
||||
TmplExtra: tmpl.Extra,
|
||||
}
|
||||
|
||||
accounts, err := m.accountApp.GetByIds(mts.ReceiverIds)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(accounts) > 0 {
|
||||
msg.Receivers = collx.ArrayMap(accounts, func(account *sysentity.Account) msgx.Receiver {
|
||||
return msgx.Receiver{
|
||||
ExtraData: account.ExtraData,
|
||||
Email: account.Email,
|
||||
Mobile: account.Mobile,
|
||||
Id: account.Id,
|
||||
Extra: account.Extra,
|
||||
Email: account.Email,
|
||||
Mobile: account.Mobile,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
for _, channel := range channels {
|
||||
for _, channel := range mts.Channels {
|
||||
if channel.Status != entity.ChannelStatusEnable {
|
||||
logx.Warnf("channel is disabled => %s", channel.Code)
|
||||
continue
|
||||
}
|
||||
|
||||
go func(channel *entity.MsgChannel) {
|
||||
if err := msgx.Send(&msgx.Channel{
|
||||
Type: channel.Type,
|
||||
Name: channel.Name,
|
||||
URL: channel.Url,
|
||||
ExtraData: channel.ExtraData,
|
||||
if err := msgx.Send(ctx, &msgx.Channel{
|
||||
Type: channel.Type,
|
||||
Name: channel.Name,
|
||||
URL: channel.Url,
|
||||
Extra: channel.Extra,
|
||||
}, msg); err != nil {
|
||||
logx.Errorf("send msg error => channel=%s, msg=%s, err -> %v", channel.Code, msg.Content, err)
|
||||
}
|
||||
|
||||
@@ -2,21 +2,49 @@ package entity
|
||||
|
||||
import (
|
||||
"mayfly-go/pkg/model"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Msg struct {
|
||||
model.DeletedModel
|
||||
model.ExtraData
|
||||
model.CreateModel
|
||||
|
||||
CreateTime *time.Time `json:"createTime"`
|
||||
CreatorId uint64 `json:"creatorId"`
|
||||
Creator string `json:"creator" gorm:"size:50"`
|
||||
|
||||
Type int8 `json:"type"`
|
||||
Msg string `json:"msg" gorm:"size:2000"`
|
||||
RecipientId int64 `json:"recipientId"` // 接收人id,-1为所有接收
|
||||
Type MsgType `json:"type"` // 消息类型
|
||||
Subtype MsgSubtype `json:"subtype" gorm:"size:100"` // 消息子类型
|
||||
Status MsgStatus `json:"status"`
|
||||
Msg string `json:"msg" gorm:"size:2000"`
|
||||
RecipientId int64 `json:"recipientId"` // 接收人id,-1为所有接收
|
||||
}
|
||||
|
||||
func (a *Msg) TableName() string {
|
||||
return "t_sys_msg"
|
||||
}
|
||||
|
||||
type MsgType int8
|
||||
|
||||
const (
|
||||
MsgTypeNotify MsgType = 1 // 通知
|
||||
MsgTypeTodo MsgType = 2 // 代办
|
||||
)
|
||||
|
||||
type MsgSubtype string
|
||||
|
||||
const (
|
||||
// sys
|
||||
MsgSubtypeUserLogin MsgSubtype = "user.login"
|
||||
|
||||
// machine
|
||||
MsgSubtypeMachineFileUploadSuccess MsgSubtype = "machine.file.upload.success"
|
||||
MsgSubtypeMachineFileUploadFail MsgSubtype = "machine.file.upload.fail"
|
||||
|
||||
// db
|
||||
MsgSubtypeDbDumpFail MsgSubtype = "db.dump.fail"
|
||||
MsgSubtypeSqlScriptRunFail MsgSubtype = "db.sqlscript.run.fail"
|
||||
MsgSubtypeSqlScriptRunSuccess MsgSubtype = "db.sqlscript.run.success"
|
||||
)
|
||||
|
||||
type MsgStatus int8
|
||||
|
||||
const (
|
||||
MsgStatusRead MsgStatus = 1 // 已读
|
||||
MsgStatusUnRead MsgStatus = -1 // 未读
|
||||
)
|
||||
|
||||
@@ -9,4 +9,13 @@ var En = map[i18n.MsgId]string{
|
||||
LogMsgTmplSave: "Message template- save",
|
||||
LogMsgTmplDelete: "Message template- delete",
|
||||
LogMsgTmplSend: "Message template- send",
|
||||
|
||||
LoginMsg: "Log in to [{{.ip}}]-[{{.time}}]",
|
||||
|
||||
MachineFileUploadSuccessMsg: "[{{.filename}}] -> {{.machineName}}[{{.machineIp}}:{{.path}}]",
|
||||
MachineFileUploadFailMsg: "[{{.filename}}] -> {{.machineName}}[{{.machineIp}}:{{.path}}]. error: {{.error}}",
|
||||
|
||||
DbDumpFailMsg: "Database dump failed, error: {{.error}}",
|
||||
SqlScriptRunFailMsg: "Script {{.filename}} execution failed on database {{.db}}, error: {{.error}}",
|
||||
SqlScriptRunSuccessMsg: "Script {{.filename}} executed successfully on database {{.db}}, cost {{.cost}}",
|
||||
}
|
||||
|
||||
@@ -17,4 +17,13 @@ const (
|
||||
LogMsgTmplSave
|
||||
LogMsgTmplDelete
|
||||
LogMsgTmplSend
|
||||
|
||||
LoginMsg
|
||||
|
||||
MachineFileUploadSuccessMsg
|
||||
MachineFileUploadFailMsg
|
||||
|
||||
DbDumpFailMsg
|
||||
SqlScriptRunFailMsg
|
||||
SqlScriptRunSuccessMsg
|
||||
)
|
||||
|
||||
@@ -9,4 +9,13 @@ var Zh_CN = map[i18n.MsgId]string{
|
||||
LogMsgTmplSave: "消息模板-保存",
|
||||
LogMsgTmplDelete: "消息模板-删除",
|
||||
LogMsgTmplSend: "消息模板-发送",
|
||||
|
||||
LoginMsg: "于[{{.ip}}]-[{{.time}}]登录",
|
||||
|
||||
MachineFileUploadSuccessMsg: "[{{.filename}}] -> {{.machineName}}[{{.machineIp}}:{{.path}}]",
|
||||
MachineFileUploadFailMsg: "[{{.filename}}] -> {{.machineName}}[{{.machineIp}}:{{.path}}]。错误信息:{{.error}}",
|
||||
|
||||
DbDumpFailMsg: "数据库dump失败,错误信息:{{.error}}",
|
||||
SqlScriptRunFailMsg: "数据库 {{.db}} 的脚本 {{.filename}} 执行失败,错误:{{.error}}",
|
||||
SqlScriptRunSuccessMsg: "数据库 {{.db}} 的脚本 {{.filename}} 执行成功,耗时 {{.cost}}",
|
||||
}
|
||||
|
||||
@@ -3,11 +3,12 @@ package init
|
||||
import (
|
||||
"context"
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/internal/event"
|
||||
"mayfly-go/internal/msg/api"
|
||||
"mayfly-go/internal/msg/application"
|
||||
"mayfly-go/internal/msg/application/dto"
|
||||
"mayfly-go/internal/msg/infrastructure/persistence"
|
||||
"mayfly-go/internal/msg/infra/persistence"
|
||||
"mayfly-go/internal/msg/msgx"
|
||||
"mayfly-go/internal/pkg/event"
|
||||
"mayfly-go/pkg/eventbus"
|
||||
"mayfly-go/pkg/global"
|
||||
"mayfly-go/pkg/ioc"
|
||||
@@ -24,9 +25,24 @@ func init() {
|
||||
}
|
||||
|
||||
func Init() {
|
||||
// 注册站内消息发送器
|
||||
msgx.RegisterMsgSender(msgx.ChannelTypeSiteMsg, application.GetMsgApp())
|
||||
|
||||
msgTmplBizApp := ioc.Get[application.MsgTmplBiz]("MsgTmplBizApp")
|
||||
|
||||
global.EventBus.SubscribeAsync(event.EventTopicBizMsgTmplSend, "BizMsgTmplSend", func(ctx context.Context, event *eventbus.Event[any]) error {
|
||||
return msgTmplBizApp.Send(ctx, event.Val.(dto.BizMsgTmplSend))
|
||||
}, false)
|
||||
|
||||
msgTmplApp := ioc.Get[application.MsgTmpl]("MsgTmplApp")
|
||||
|
||||
global.EventBus.SubscribeAsync(event.EventTopicMsgTmplSend, "MsgTmplSend", func(ctx context.Context, event *eventbus.Event[any]) error {
|
||||
eventVal := event.Val.(*dto.MsgTmplSendEvent)
|
||||
return msgTmplApp.SendMsg(ctx, &dto.MsgTmplSend{
|
||||
Tmpl: eventVal.TmplChannel.Tmpl,
|
||||
Channels: eventVal.TmplChannel.Channels,
|
||||
Params: eventVal.Params,
|
||||
ReceiverIds: eventVal.ReceiverIds,
|
||||
})
|
||||
}, false)
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package msgx
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"mayfly-go/pkg/model"
|
||||
"mayfly-go/pkg/utils/collx"
|
||||
)
|
||||
|
||||
type MsgType int8
|
||||
@@ -15,6 +16,8 @@ const (
|
||||
)
|
||||
|
||||
const (
|
||||
ChannelTypeSiteMsg ChannelType = "siteMsg" // 站内消息
|
||||
ChannelTypeWs ChannelType = "ws" // websocket
|
||||
ChannelTypeEmail ChannelType = "email"
|
||||
ChannelTypeDingBot ChannelType = "dingBot"
|
||||
ChannelTypeQywxBot ChannelType = "qywxBot"
|
||||
@@ -26,35 +29,35 @@ const (
|
||||
)
|
||||
|
||||
// Send 发送消息
|
||||
func Send(channel *Channel, msg *Msg) error {
|
||||
func Send(ctx context.Context, channel *Channel, msg *Msg) error {
|
||||
sender, err := GetMsgSender(channel.Type)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return sender.Send(channel, msg)
|
||||
return sender.Send(ctx, channel, msg)
|
||||
}
|
||||
|
||||
type Receiver struct {
|
||||
model.ExtraData
|
||||
Extra collx.M
|
||||
|
||||
Id uint64 // 接收人ID
|
||||
Mobile string
|
||||
Email string
|
||||
}
|
||||
|
||||
type Msg struct {
|
||||
model.ExtraData
|
||||
|
||||
Title string // 消息title
|
||||
Type MsgType // 消息类型
|
||||
Content string // 消息内容
|
||||
Params map[string]any // 消息参数(替换消息中的占位符)
|
||||
Title string // 消息title
|
||||
Type MsgType // 消息类型
|
||||
Content string // 模板消息内容
|
||||
Params map[string]any // 消息参数(替换消息中的占位符)
|
||||
TmplExtra collx.M // 模板消息额外信息
|
||||
|
||||
Receivers []Receiver // 消息接收人
|
||||
}
|
||||
|
||||
// Channel 消息发送渠道信息
|
||||
type Channel struct {
|
||||
model.ExtraData
|
||||
Extra collx.M
|
||||
|
||||
Type ChannelType // 渠道类型
|
||||
Name string
|
||||
@@ -64,7 +67,7 @@ type Channel struct {
|
||||
// MsgSender 定义消息发送接口
|
||||
type MsgSender interface {
|
||||
// Send 发送消息
|
||||
Send(channel *Channel, msg *Msg) error
|
||||
Send(ctx context.Context, channel *Channel, msg *Msg) error
|
||||
}
|
||||
|
||||
var messageSenders = make(map[ChannelType]MsgSender)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package sender
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
@@ -40,7 +41,7 @@ type dingBotMsgResp struct {
|
||||
// DingBotSender 钉钉机器人消息发送
|
||||
type DingBotSender struct{}
|
||||
|
||||
func (d DingBotSender) Send(channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
func (d DingBotSender) Send(ctx context.Context, channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
// https://open.dingtalk.com/document/robots/custom-robot-access#title-72m-8ag-pqw
|
||||
msgReq := dingBotMsgReq{}
|
||||
|
||||
@@ -73,7 +74,7 @@ func (d DingBotSender) Send(channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
}
|
||||
|
||||
timestamp := time.Now().UnixMilli()
|
||||
sign, err := d.sign(channel.GetExtraString("secret"), timestamp)
|
||||
sign, err := d.sign(channel.Extra.GetStr("secret"), timestamp)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package sender
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
@@ -16,7 +17,7 @@ import (
|
||||
|
||||
type EmailSender struct{}
|
||||
|
||||
func (e EmailSender) Send(channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
func (e EmailSender) Send(ctx context.Context, channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
return e.SendEmail(channel, msg)
|
||||
}
|
||||
|
||||
@@ -44,8 +45,8 @@ func (e EmailSender) SendEmail(channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
smtpPort = cast.ToInt(serverAndPort[1])
|
||||
}
|
||||
|
||||
smtpAccount := channel.GetExtraString("smtpAccount")
|
||||
smtpPassword := channel.GetExtraString("smtpPassword")
|
||||
smtpAccount := channel.Extra.GetStr("smtpAccount")
|
||||
smtpPassword := channel.Extra.GetStr("smtpPassword")
|
||||
|
||||
encodedSubject := fmt.Sprintf("=?UTF-8?B?%s?=", base64.StdEncoding.EncodeToString([]byte(subject)))
|
||||
mail := []byte(fmt.Sprintf("To: %s\r\n"+
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package sender
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/hmac"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
@@ -34,7 +35,7 @@ type feishuBotMsgResp struct {
|
||||
// FeishuBotSender 发送飞书机器人消息
|
||||
type FeishuBotSender struct{}
|
||||
|
||||
func (f FeishuBotSender) Send(channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
func (f FeishuBotSender) Send(ctx context.Context, channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
// https://open.feishu.cn/document/client-docs/bot-v3/add-custom-bot
|
||||
msgReq := feishuBotMsgReq{
|
||||
MsgType: "text",
|
||||
@@ -45,7 +46,7 @@ func (f FeishuBotSender) Send(channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
// 使用receiver参数替换消息内容中可能存在的接收人信息
|
||||
if len(msg.Receivers) > 0 {
|
||||
if to := collx.ArrayMapFilter(msg.Receivers, func(a msgx.Receiver) (string, bool) {
|
||||
if uid := a.GetExtraString("feishuUserId"); uid != "" {
|
||||
if uid := a.Extra.GetStr("feishuUserId"); uid != "" {
|
||||
// 使用<at user_id="userId"></at>
|
||||
return fmt.Sprintf(`<at user_id="%s"></at>`, uid), true
|
||||
}
|
||||
@@ -62,7 +63,7 @@ func (f FeishuBotSender) Send(channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
|
||||
msgReq.Content.Text = content
|
||||
|
||||
if secret := channel.GetExtraString("secret"); secret != "" {
|
||||
if secret := channel.Extra.GetStr("secret"); secret != "" {
|
||||
timestamp := time.Now().Unix()
|
||||
if sign, err := f.sign(secret, timestamp); err != nil {
|
||||
return err
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package sender
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"mayfly-go/internal/msg/msgx"
|
||||
@@ -29,7 +30,7 @@ type qywxBotMsgResp struct {
|
||||
// QywxBotSender 企业微信机器人消息发送
|
||||
type QywxBotSender struct{}
|
||||
|
||||
func (e QywxBotSender) Send(channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
func (e QywxBotSender) Send(ctx context.Context, channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
// https://developer.work.weixin.qq.com/document/path/91770
|
||||
msgReq := qywxBotMsgReq{}
|
||||
|
||||
@@ -38,7 +39,7 @@ func (e QywxBotSender) Send(channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
// 使用receiver参数替换消息内容中可能存在的接收人信息
|
||||
if len(msg.Receivers) > 0 {
|
||||
if to := collx.ArrayMapFilter(msg.Receivers, func(a msgx.Receiver) (string, bool) {
|
||||
if uid := a.GetExtraString("qywxUserId"); uid != "" {
|
||||
if uid := a.Extra.GetStr("qywxUserId"); uid != "" {
|
||||
// 使用<@userId>用于@指定用户
|
||||
return fmt.Sprintf("<@%s>", uid), true
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package sender
|
||||
|
||||
import "mayfly-go/internal/msg/msgx"
|
||||
import (
|
||||
"mayfly-go/internal/msg/msgx"
|
||||
)
|
||||
|
||||
func init() {
|
||||
msgx.RegisterMsgSender(msgx.ChannelTypeWs, WsSender{})
|
||||
msgx.RegisterMsgSender(msgx.ChannelTypeEmail, EmailSender{})
|
||||
msgx.RegisterMsgSender(msgx.ChannelTypeDingBot, DingBotSender{})
|
||||
msgx.RegisterMsgSender(msgx.ChannelTypeQywxBot, QywxBotSender{})
|
||||
|
||||
40
server/internal/msg/msgx/sender/ws.go
Normal file
40
server/internal/msg/msgx/sender/ws.go
Normal file
@@ -0,0 +1,40 @@
|
||||
package sender
|
||||
|
||||
import (
|
||||
"context"
|
||||
"mayfly-go/internal/msg/msgx"
|
||||
"mayfly-go/pkg/i18n"
|
||||
"mayfly-go/pkg/utils/stringx"
|
||||
"mayfly-go/pkg/ws"
|
||||
|
||||
"github.com/spf13/cast"
|
||||
)
|
||||
|
||||
type WsSender struct{}
|
||||
|
||||
func (e WsSender) Send(ctx context.Context, channel *msgx.Channel, msg *msgx.Msg) error {
|
||||
var err error
|
||||
content := msg.Content
|
||||
|
||||
// 存在i18n msgId,content则使用msgId翻译
|
||||
if msgId := msg.TmplExtra.GetInt("msgId"); msgId != 0 {
|
||||
content = i18n.TC(ctx, i18n.MsgId(msgId))
|
||||
}
|
||||
if content != "" {
|
||||
content, err = stringx.TemplateParse(content, msg.Params)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
jsonMsg := msg.TmplExtra
|
||||
jsonMsg["msg"] = content
|
||||
jsonMsg["title"] = msg.Title
|
||||
jsonMsg["params"] = msg.Params
|
||||
|
||||
for _, receiver := range msg.Receivers {
|
||||
ws.SendJsonMsg(ws.UserId(receiver.Id), cast.ToString(msg.Params["clientId"]), jsonMsg)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -3,4 +3,5 @@ package event
|
||||
const (
|
||||
EventTopicResourceOp = "resource:op" // 资源操作主题
|
||||
EventTopicBizMsgTmplSend = "biz:msgtmpl:send" // 发送业务关联的消息模板
|
||||
EventTopicMsgTmplSend = "msgtmpl:send" // 发送消息模板
|
||||
)
|
||||
@@ -1,7 +1,7 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"mayfly-go/internal/event"
|
||||
"mayfly-go/internal/pkg/event"
|
||||
"mayfly-go/internal/redis/api/form"
|
||||
"mayfly-go/internal/redis/application/dto"
|
||||
"mayfly-go/pkg/biz"
|
||||
|
||||
@@ -17,7 +17,7 @@ import (
|
||||
func (r *Redis) ScanKeys(rc *req.Ctx) {
|
||||
ri := r.getRedisConn(rc)
|
||||
|
||||
form := req.BindJsonAndValid[*form.RedisScanForm](rc)
|
||||
form := req.BindJson[*form.RedisScanForm](rc)
|
||||
|
||||
cmd := ri.GetCmdable()
|
||||
ctx := context.Background()
|
||||
|
||||
@@ -4,7 +4,7 @@ import (
|
||||
"mayfly-go/initialize"
|
||||
"mayfly-go/internal/redis/api"
|
||||
"mayfly-go/internal/redis/application"
|
||||
"mayfly-go/internal/redis/infrastructure/persistence"
|
||||
"mayfly-go/internal/redis/infra/persistence"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
@@ -108,7 +108,7 @@ func (a *Account) GetPermissions(rc *req.Ctx) {
|
||||
func (a *Account) ChangePassword(rc *req.Ctx) {
|
||||
ctx := rc.MetaCtx
|
||||
|
||||
form := req.BindJsonAndValid[*form.AccountChangePasswordForm](rc)
|
||||
form := req.BindJson[*form.AccountChangePasswordForm](rc)
|
||||
|
||||
originOldPwd, err := utils.DefaultRsaDecrypt(form.OldPassword, true)
|
||||
biz.ErrIsNilAppendErr(err, "Wrong to decrypt old password: %s")
|
||||
@@ -307,7 +307,7 @@ func (a *Account) AccountResources(rc *req.Ctx) {
|
||||
|
||||
// 关联账号角色
|
||||
func (a *Account) RelateRole(rc *req.Ctx) {
|
||||
form := req.BindJsonAndValid[*form.AccountRoleForm](rc)
|
||||
form := req.BindJson[*form.AccountRoleForm](rc)
|
||||
rc.ReqParam = form
|
||||
biz.ErrIsNil(a.roleApp.RelateAccountRole(rc.MetaCtx, form.Id, form.RoleId, consts.AccountRoleRelateType(form.RelateType)))
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ func (r *Role) RoleResource(rc *req.Ctx) {
|
||||
|
||||
// 保存角色资源
|
||||
func (r *Role) SaveResource(rc *req.Ctx) {
|
||||
form := req.BindJsonAndValid[*form.RoleResourceForm](rc)
|
||||
form := req.BindJson[*form.RoleResourceForm](rc)
|
||||
rc.ReqParam = form
|
||||
|
||||
// 将,拼接的字符串进行切割并转换
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user