diff --git a/apis/admin/log.api b/apis/admin/log.api index 12fc312..727cb02 100644 --- a/apis/admin/log.api +++ b/apis/admin/log.api @@ -12,14 +12,10 @@ import "../types.api" type ( GetMessageLogListRequest { - Page int `form:"page"` - Size int `form:"size"` - Type string `form:"type"` - Platform string `form:"platform,omitempty"` - To string `form:"to,omitempty"` - Subject string `form:"subject,omitempty"` - Content string `form:"content,omitempty"` - Status int `form:"status,omitempty"` + Page int `form:"page"` + Size int `form:"size"` + Type uint8 `form:"type"` + Search string `form:"search,optional"` } GetMessageLogListResponse { Total int64 `json:"total"` diff --git a/apis/types.api b/apis/types.api index 0926c41..9d2fb97 100644 --- a/apis/types.api +++ b/apis/types.api @@ -535,15 +535,14 @@ type ( CreatedAt int64 `json:"created_at"` } MessageLog { - Id int64 `json:"id"` - Type string `json:"type"` - Platform string `json:"platform"` - To string `json:"to"` - Subject string `json:"subject"` - Content string `json:"content"` - Status int `json:"status"` - CreatedAt int64 `json:"created_at"` - UpdatedAt int64 `json:"updated_at"` + Id int64 `json:"id"` + Type uint8 `json:"type"` + Platform string `json:"platform"` + To string `json:"to"` + Subject string `json:"subject"` + Content map[string]interface{} `json:"content"` + Status uint8 `json:"status"` + CreatedAt int64 `json:"created_at"` } Ads { Id int `json:"id"` diff --git a/initialize/migrate/database/02104_system_log.down.sql b/initialize/migrate/database/02104_system_log.down.sql new file mode 100644 index 0000000..2682c97 --- /dev/null +++ b/initialize/migrate/database/02104_system_log.down.sql @@ -0,0 +1,106 @@ +CREATE TABLE IF NOT EXISTS `user_balance_log` +( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `amount` bigint NOT NULL COMMENT 'Amount', + `type` tinyint(1) NOT NULL COMMENT 'Type: 1: Recharge 2: Withdraw 3: Payment 4: Refund 5: Reward', + `order_id` bigint DEFAULT NULL COMMENT 'Order ID', + `balance` bigint NOT NULL COMMENT 'Balance', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `user_commission_log` +( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `order_no` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Order No.', + `amount` bigint NOT NULL COMMENT 'Amount', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `user_gift_amount_log` +( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `user_subscribe_id` bigint DEFAULT NULL COMMENT 'Deduction User Subscribe ID', + `order_no` varchar(191) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Order No.', + `type` tinyint(1) NOT NULL COMMENT 'Type: 1: Increase 2: Reduce', + `amount` bigint NOT NULL COMMENT 'Amount', + `balance` bigint NOT NULL COMMENT 'Balance', + `remark` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci DEFAULT '' COMMENT 'Remark', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `user_login_log` +( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `login_ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Login IP', + `user_agent` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'UserAgent', + `success` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Login Success', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `user_reset_subscribe_log` +( + `id` BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, + `user_id` BIGINT NOT NULL COMMENT 'User ID', + `type` TINYINT(1) NOT NULL COMMENT 'Type: 1: Auto 2: Advance 3: Paid', + `order_no` VARCHAR(255) DEFAULT NULL COMMENT 'Order No.', + `user_subscribe_id` BIGINT NOT NULL COMMENT 'User Subscribe ID', + `created_at` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT 'Creation Time', + INDEX `idx_user_id` (`user_id`), + INDEX `idx_user_subscribe_id` (`user_subscribe_id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `user_subscribe_log` +( + `id` bigint NOT NULL AUTO_INCREMENT, + `user_id` bigint NOT NULL COMMENT 'User ID', + `user_subscribe_id` bigint NOT NULL COMMENT 'User Subscribe ID', + `token` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Token', + `ip` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'IP', + `user_agent` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'UserAgent', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Creation Time', + PRIMARY KEY (`id`), + KEY `idx_user_id` (`user_id`), + KEY `idx_user_subscribe_id` (`user_subscribe_id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +CREATE TABLE IF NOT EXISTS `message_log` +( + `id` bigint NOT NULL AUTO_INCREMENT, + `type` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'email' COMMENT 'Message Type', + `platform` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT 'smtp' COMMENT 'Platform', + `to` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL COMMENT 'To', + `subject` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NOT NULL DEFAULT '' COMMENT 'Subject', + `content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci COMMENT 'Content', + `status` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Status', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + `updated_at` datetime(3) DEFAULT NULL COMMENT 'Update Time', + PRIMARY KEY (`id`) + ) ENGINE = InnoDB + DEFAULT CHARSET = utf8mb4 + COLLATE = utf8mb4_general_ci; + +DROP TABLE IF EXISTS `system_logs`; \ No newline at end of file diff --git a/initialize/migrate/database/02104_system_log.up.sql b/initialize/migrate/database/02104_system_log.up.sql new file mode 100644 index 0000000..b518e68 --- /dev/null +++ b/initialize/migrate/database/02104_system_log.up.sql @@ -0,0 +1,19 @@ +DROP TABLE IF EXISTS `user_balance_log`; +DROP TABLE IF EXISTS `user_commission_log`; +DROP TABLE IF EXISTS `user_gift_amount_log`; +DROP TABLE IF EXISTS `user_login_log`; +DROP TABLE IF EXISTS `user_reset_subscribe_log`; +DROP TABLE IF EXISTS `user_subscribe_log`; +DROP TABLE IF EXISTS `message_log`; +DROP TABLE IF EXISTS `system_logs`; +CREATE TABLE `system_logs` ( + `id` bigint NOT NULL AUTO_INCREMENT, + `type` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'Log Type: 1: Email Message 2: Mobile Message 3: Subscribe 4: Subscribe Traffic 5: Server Traffic 6: Login 7: Register 8: Balance 9: Commission 10: Reset Subscribe 11: Gift', + `date` varchar(20) COLLATE utf8mb4_general_ci DEFAULT NULL COMMENT 'Log Date', + `object_id` bigint NOT NULL DEFAULT '0' COMMENT 'Object ID', + `content` text COLLATE utf8mb4_general_ci NOT NULL COMMENT 'Log Content', + `created_at` datetime(3) DEFAULT NULL COMMENT 'Create Time', + PRIMARY KEY (`id`), + KEY `idx_type` (`type`), + KEY `idx_object_id` (`object_id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; \ No newline at end of file diff --git a/internal/logic/admin/log/getMessageLogListLogic.go b/internal/logic/admin/log/getMessageLogListLogic.go index b4ed00b..3fc46f9 100644 --- a/internal/logic/admin/log/getMessageLogListLogic.go +++ b/internal/logic/admin/log/getMessageLogListLogic.go @@ -7,7 +7,6 @@ import ( "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" ) @@ -28,23 +27,42 @@ func NewGetMessageLogListLogic(ctx context.Context, svcCtx *svc.ServiceContext) } func (l *GetMessageLogListLogic) GetMessageLogList(req *types.GetMessageLogListRequest) (resp *types.GetMessageLogListResponse, err error) { - total, data, err := l.svcCtx.LogModel.FindMessageLogList(l.ctx, req.Page, req.Size, log.MessageLogFilterParams{ - Type: req.Type, - Platform: req.Platform, - To: req.To, - Subject: req.Subject, - Content: req.Content, - Status: req.Status, + + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: req.Type, + Search: req.Search, }) + if err != nil { - l.Errorw("[GetMessageLogList] Database Error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "[GetMessageLogList] Database Error: %s", err.Error()) + l.Errorf("[GetMessageLogList] failed to filter system log: %v", err.Error()) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "failed to filter system log: %v", err.Error()) + } + + var list []*types.MessageLog + + for _, datum := range data { + var content log.Message + err = content.Unmarshal([]byte(datum.Content)) + if err != nil { + l.Errorf("[GetMessageLogList] failed to unmarshal content: %v", err.Error()) + continue + } + list = append(list, &types.MessageLog{ + Id: datum.Id, + Type: datum.Type, + Platform: content.Platform, + To: content.To, + Subject: content.Subject, + Content: content.Content, + Status: content.Status, + CreatedAt: datum.CreatedAt.UnixMilli(), + }) } - var list []types.MessageLog - tool.DeepCopy(&list, data) return &types.GetMessageLogListResponse{ Total: total, - List: list, + List: nil, }, nil } diff --git a/internal/logic/admin/user/getUserLoginLogsLogic.go b/internal/logic/admin/user/getUserLoginLogsLogic.go index f70fd24..7a702e5 100644 --- a/internal/logic/admin/user/getUserLoginLogsLogic.go +++ b/internal/logic/admin/user/getUserLoginLogsLogic.go @@ -3,11 +3,10 @@ package user import ( "context" - "github.com/perfect-panel/server/internal/model/user" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" ) @@ -28,15 +27,34 @@ func NewGetUserLoginLogsLogic(ctx context.Context, svcCtx *svc.ServiceContext) * } func (l *GetUserLoginLogsLogic) GetUserLoginLogs(req *types.GetUserLoginLogsRequest) (resp *types.GetUserLoginLogsResponse, err error) { - data, total, err := l.svcCtx.UserModel.FilterLoginLogList(l.ctx, req.Page, req.Size, &user.LoginLogFilterParams{ - UserId: req.UserId, + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeLogin.Uint8(), + ObjectID: req.UserId, }) if err != nil { l.Errorw("[GetUserLoginLogs] get user login logs failed", logger.Field("error", err.Error()), logger.Field("request", req)) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "get user login logs failed: %v", err.Error()) } var list []types.UserLoginLog - tool.DeepCopy(&list, data) + + for _, datum := range data { + var content log.Login + if err = content.Unmarshal([]byte(datum.Content)); err != nil { + l.Errorf("[GetUserLoginLogs] unmarshal login log content failed: %v", err.Error()) + continue + } + list = append(list, types.UserLoginLog{ + Id: datum.Id, + UserId: datum.ObjectID, + LoginIP: content.LoginIP, + UserAgent: content.UserAgent, + Success: content.Success, + CreatedAt: datum.CreatedAt.UnixMilli(), + }) + } + return &types.GetUserLoginLogsResponse{ Total: total, List: list, diff --git a/internal/logic/admin/user/getUserSubscribeLogsLogic.go b/internal/logic/admin/user/getUserSubscribeLogsLogic.go index aa64873..ca33355 100644 --- a/internal/logic/admin/user/getUserSubscribeLogsLogic.go +++ b/internal/logic/admin/user/getUserSubscribeLogsLogic.go @@ -3,7 +3,7 @@ package user import ( "context" - "github.com/perfect-panel/server/internal/model/user" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" @@ -28,10 +28,7 @@ func NewGetUserSubscribeLogsLogic(ctx context.Context, svcCtx *svc.ServiceContex } func (l *GetUserSubscribeLogsLogic) GetUserSubscribeLogs(req *types.GetUserSubscribeLogsRequest) (resp *types.GetUserSubscribeLogsResponse, err error) { - data, total, err := l.svcCtx.UserModel.FilterSubscribeLogList(l.ctx, req.Page, req.Size, &user.SubscribeLogFilterParams{ - UserSubscribeId: req.SubscribeId, - UserId: req.UserId, - }) + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{}) if err != nil { l.Errorw("[GetUserSubscribeLogs] Get User Subscribe Logs Error:", logger.Field("err", err.Error())) diff --git a/internal/logic/auth/oauth/oAuthLoginGetTokenLogic.go b/internal/logic/auth/oauth/oAuthLoginGetTokenLogic.go index f3ca443..8f0e2ed 100644 --- a/internal/logic/auth/oauth/oAuthLoginGetTokenLogic.go +++ b/internal/logic/auth/oauth/oAuthLoginGetTokenLogic.go @@ -8,6 +8,7 @@ import ( "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/model/auth" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" @@ -52,7 +53,6 @@ func NewOAuthLoginGetTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) } func (l *OAuthLoginGetTokenLogic) OAuthLoginGetToken(req *types.OAuthLoginGetTokenRequest, ip, userAgent string) (resp *types.LoginResponse, err error) { - startTime := time.Now() requestID := uuidx.NewUUID().String() loginStatus := false var userInfo *user.User @@ -65,24 +65,7 @@ func (l *OAuthLoginGetTokenLogic) OAuthLoginGetToken(req *types.OAuthLoginGetTok ) defer func() { - duration := time.Since(startTime) - l.recordLoginStatus(&loginStatus, &userInfo, ip, userAgent, requestID) - - if loginStatus { - l.Infow("oauth login completed successfully", - logger.Field("request_id", requestID), - logger.Field("method", req.Method), - logger.Field("user_id", userInfo.Id), - logger.Field("duration_ms", duration.Milliseconds()), - ) - } else { - l.Errorw("oauth login failed", - logger.Field("request_id", requestID), - logger.Field("method", req.Method), - logger.Field("error", err), - logger.Field("duration_ms", duration.Milliseconds()), - ) - } + l.recordLoginStatus(loginStatus, userInfo, ip, userAgent, requestID) }() userInfo, err = l.handleOAuthProvider(req, requestID) @@ -504,27 +487,28 @@ func (l *OAuthLoginGetTokenLogic) createAuthMethod(db *gorm.DB, userID int64, au return nil } -func (l *OAuthLoginGetTokenLogic) recordLoginStatus(loginStatus *bool, userInfo **user.User, ip, userAgent, requestID string) { - if *userInfo != nil && (*userInfo).Id != 0 { - if err := l.svcCtx.UserModel.InsertLoginLog(l.ctx, &user.LoginLog{ - UserId: (*userInfo).Id, +func (l *OAuthLoginGetTokenLogic) recordLoginStatus(loginStatus bool, userInfo *user.User, ip, userAgent, requestID string) { + + if userInfo != nil && userInfo.Id != 0 { + loginLog := log.Login{ LoginIP: ip, UserAgent: userAgent, Success: loginStatus, + } + content, _ := loginLog.Marshal() + if err := l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Id: 0, + Type: log.TypeLogin.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), }); err != nil { l.Errorw("failed to insert login log", logger.Field("request_id", requestID), - logger.Field("user_id", (*userInfo).Id), + logger.Field("user_id", userInfo.Id), logger.Field("ip", ip), logger.Field("error", err.Error()), ) - } else { - l.Debugw("login log recorded successfully", - logger.Field("request_id", requestID), - logger.Field("user_id", (*userInfo).Id), - logger.Field("ip", ip), - logger.Field("success", *loginStatus), - ) } } } diff --git a/internal/logic/auth/resetPasswordLogic.go b/internal/logic/auth/resetPasswordLogic.go index b489606..ab6b5b4 100644 --- a/internal/logic/auth/resetPasswordLogic.go +++ b/internal/logic/auth/resetPasswordLogic.go @@ -6,6 +6,7 @@ import ( "fmt" "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/pkg/jwt" "github.com/perfect-panel/server/pkg/uuidx" @@ -43,13 +44,24 @@ func (l *ResetPasswordLogic) ResetPassword(req *types.ResetPasswordRequest) (res defer func() { if userInfo.Id != 0 && loginStatus { - if err := l.svcCtx.UserModel.InsertLoginLog(l.ctx, &user.LoginLog{ - UserId: userInfo.Id, + loginLog := log.Login{ LoginIP: req.IP, UserAgent: req.UserAgent, - Success: &loginStatus, + Success: loginStatus, + } + content, _ := loginLog.Marshal() + if err = l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Id: 0, + Type: log.TypeLogin.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), }); err != nil { - l.Logger.Error("[ResetPassword] insert login log error", logger.Field("error", err.Error())) + l.Errorw("failed to insert login log", + logger.Field("user_id", userInfo.Id), + logger.Field("ip", req.IP), + logger.Field("error", err.Error()), + ) } } }() diff --git a/internal/logic/auth/telephoneLoginLogic.go b/internal/logic/auth/telephoneLoginLogic.go index 5457b39..b240e58 100644 --- a/internal/logic/auth/telephoneLoginLogic.go +++ b/internal/logic/auth/telephoneLoginLogic.go @@ -9,6 +9,7 @@ import ( "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/logic/common" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" @@ -51,13 +52,24 @@ func (l *TelephoneLoginLogic) TelephoneLogin(req *types.TelephoneLoginRequest, r // Record login status defer func(svcCtx *svc.ServiceContext) { if userInfo.Id != 0 { - if err := svcCtx.UserModel.InsertLoginLog(l.ctx, &user.LoginLog{ - UserId: userInfo.Id, + loginLog := log.Login{ LoginIP: ip, UserAgent: r.UserAgent(), - Success: &loginStatus, + Success: loginStatus, + } + content, _ := loginLog.Marshal() + if err = l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Id: 0, + Type: log.TypeLogin.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), }); err != nil { - l.Logger.Error("[UserLogin] insert login log error", logger.Field("error", err.Error())) + l.Errorw("failed to insert login log", + logger.Field("user_id", userInfo.Id), + logger.Field("ip", req.IP), + logger.Field("error", err.Error()), + ) } } }(l.svcCtx) diff --git a/internal/logic/auth/userLoginLogic.go b/internal/logic/auth/userLoginLogic.go index c04392c..7976a47 100644 --- a/internal/logic/auth/userLoginLogic.go +++ b/internal/logic/auth/userLoginLogic.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/internal/config" @@ -41,29 +42,44 @@ func (l *UserLoginLogic) UserLogin(req *types.UserLoginRequest) (resp *types.Log // Record login status defer func(svcCtx *svc.ServiceContext) { if userInfo.Id != 0 { - if err := svcCtx.UserModel.InsertLoginLog(l.ctx, &user.LoginLog{ - UserId: userInfo.Id, + loginLog := log.Login{ LoginIP: req.IP, UserAgent: req.UserAgent, - Success: &loginStatus, + Success: loginStatus, + } + content, _ := loginLog.Marshal() + if err := l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Id: 0, + Type: log.TypeLogin.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), }); err != nil { - l.Logger.Error("[UserLogin] insert login log error", logger.Field("error", err.Error())) + l.Errorw("failed to insert login log", + logger.Field("user_id", userInfo.Id), + logger.Field("ip", req.IP), + logger.Field("error", err.Error()), + ) } } }(l.svcCtx) userInfo, err = l.svcCtx.UserModel.FindOneByEmail(l.ctx, req.Email) + + l.Debugf("[用户登陆] user email: %v, user info: %v", req.Email, userInfo) if err != nil { if errors.As(err, &gorm.ErrRecordNotFound) { - logger.WithContext(l.ctx).Error(err) return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserNotExist), "user email not exist: %v", req.Email) } + logger.WithContext(l.ctx).Error(err) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query user info failed: %v", err.Error()) } + // Verify password if !tool.VerifyPassWord(req.Password, userInfo.Password) { return nil, errors.Wrapf(xerr.NewErrCode(xerr.UserPasswordError), "user password") } + l.Debugf("[用户登陆] 密码验证成功") // Generate session id sessionId := uuidx.NewUUID().String() // Generate token @@ -80,6 +96,7 @@ func (l *UserLoginLogic) UserLogin(req *types.UserLoginRequest) (resp *types.Log } sessionIdCacheKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionId) if err = l.svcCtx.Redis.Set(l.ctx, sessionIdCacheKey, userInfo.Id, time.Duration(l.svcCtx.Config.JwtAuth.AccessExpire)*time.Second).Err(); err != nil { + l.Errorf("[用户登陆] set session id error: %v", err.Error()) return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "set session id error: %v", err.Error()) } loginStatus = true diff --git a/internal/logic/auth/userRegisterLogic.go b/internal/logic/auth/userRegisterLogic.go index 19c2282..ebe23e0 100644 --- a/internal/logic/auth/userRegisterLogic.go +++ b/internal/logic/auth/userRegisterLogic.go @@ -8,6 +8,7 @@ import ( "github.com/perfect-panel/server/internal/config" "github.com/perfect-panel/server/internal/logic/common" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" @@ -145,13 +146,24 @@ func (l *UserRegisterLogic) UserRegister(req *types.UserRegisterRequest) (resp * loginStatus := true defer func() { if token != "" && userInfo.Id != 0 { - if err := l.svcCtx.UserModel.InsertLoginLog(l.ctx, &user.LoginLog{ - UserId: userInfo.Id, + loginLog := log.Login{ LoginIP: req.IP, UserAgent: req.UserAgent, - Success: &loginStatus, + Success: loginStatus, + } + content, _ := loginLog.Marshal() + if err = l.svcCtx.LogModel.Insert(l.ctx, &log.SystemLog{ + Id: 0, + Type: log.TypeLogin.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), }); err != nil { - l.Logger.Error("[UserRegister] insert login log error", logger.Field("error", err.Error())) + l.Errorw("failed to insert login log", + logger.Field("user_id", userInfo.Id), + logger.Field("ip", req.IP), + logger.Field("error", err.Error()), + ) } } }() diff --git a/internal/logic/common/sendEmailCodeLogic.go b/internal/logic/common/sendEmailCodeLogic.go index ac37acc..5014584 100644 --- a/internal/logic/common/sendEmailCodeLogic.go +++ b/internal/logic/common/sendEmailCodeLogic.go @@ -1,11 +1,9 @@ package common import ( - "bytes" "context" "encoding/json" "fmt" - "text/template" "time" "github.com/hibiken/asynq" @@ -90,12 +88,13 @@ func (l *SendEmailCodeLogic) SendEmailCode(req *types.SendCodeRequest) (resp *ty code := random.Key(6, 0) taskPayload.Email = req.Email taskPayload.Subject = "Verification code" - content, err := l.initTemplate(req.Type, code) - if err != nil { - l.Logger.Error("[SendEmailCode]: InitTemplate Error", logger.Field("error", err.Error())) - return nil, errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "Failed to init template") + taskPayload.Content = map[string]interface{}{ + "Type": req.Type, + "SiteLogo": l.svcCtx.Config.Site.SiteLogo, + "SiteName": l.svcCtx.Config.Site.SiteName, + "Expire": 5, + "Code": code, } - taskPayload.Content = content // Save to Redis payload = CacheKeyPayload{ Code: code, @@ -134,23 +133,3 @@ func (l *SendEmailCodeLogic) SendEmailCode(req *types.SendCodeRequest) (resp *ty }, nil } } - -func (l *SendEmailCodeLogic) initTemplate(t uint8, code string) (string, error) { - data := VerifyTemplate{ - Type: t, - SiteLogo: l.svcCtx.Config.Site.SiteLogo, - SiteName: l.svcCtx.Config.Site.SiteName, - Expire: 5, - Code: code, - } - tpl, err := template.New("verify").Parse(l.svcCtx.Config.Email.VerifyEmailTemplate) - if err != nil { - return "", err - } - var result bytes.Buffer - err = tpl.Execute(&result, data) - if err != nil { - return "", err - } - return result.String(), nil -} diff --git a/internal/logic/public/order/closeOrderLogic.go b/internal/logic/public/order/closeOrderLogic.go index fc22eec..6400f01 100644 --- a/internal/logic/public/order/closeOrderLogic.go +++ b/internal/logic/public/order/closeOrderLogic.go @@ -3,7 +3,9 @@ package order import ( "context" "encoding/json" + "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/pkg/payment/stripe" "gorm.io/gorm" @@ -92,15 +94,25 @@ func (l *CloseOrderLogic) CloseOrder(req *types.CloseOrderRequest) error { return err } // Record the deduction refund log - giftAmountLog := &user.GiftAmountLog{ - UserId: orderInfo.UserId, - OrderNo: orderInfo.OrderNo, - Amount: orderInfo.GiftAmount, - Type: 1, - Balance: deduction, - Remark: "Order cancellation refund", + + giftLog := log.Gift{ + Type: log.GiftTypeIncrease, + OrderNo: orderInfo.OrderNo, + SubscribeId: 0, + Amount: orderInfo.GiftAmount, + Balance: deduction, + Remark: "Order cancellation refund", + CreatedAt: time.Now().UnixMilli(), } - err = tx.Model(&user.GiftAmountLog{}).Create(giftAmountLog).Error + content, _ := giftLog.Marshal() + + err = tx.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Id: 0, + Type: log.TypeGift.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: userInfo.Id, + Content: string(content), + }).Error if err != nil { l.Errorw("[CloseOrder] Record cancellation refund log failed", logger.Field("error", err.Error()), diff --git a/internal/logic/public/order/purchaseLogic.go b/internal/logic/public/order/purchaseLogic.go index 033ad9a..dd9e2c7 100644 --- a/internal/logic/public/order/purchaseLogic.go +++ b/internal/logic/public/order/purchaseLogic.go @@ -5,6 +5,7 @@ import ( "encoding/json" "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/hibiken/asynq" @@ -196,18 +197,26 @@ func (l *PurchaseLogic) Purchase(req *types.PurchaseOrderRequest) (resp *types.P return e } // create deduction record - giftAmountLog := user.GiftAmountLog{ - UserId: orderInfo.UserId, - OrderNo: orderInfo.OrderNo, - Amount: orderInfo.GiftAmount, - Type: 2, - Balance: u.GiftAmount, - Remark: "Purchase order deduction", + giftLog := log.Gift{ + Type: log.GiftTypeReduce, + OrderNo: orderInfo.OrderNo, + SubscribeId: 0, + Amount: orderInfo.GiftAmount, + Balance: u.GiftAmount, + Remark: "Purchase order deduction", + CreatedAt: time.Now().UnixMilli(), } - if e := db.Model(&user.GiftAmountLog{}).Create(&giftAmountLog).Error; e != nil { + content, _ := giftLog.Marshal() + + if e := db.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeGift.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: u.Id, + Content: string(content), + }).Error; e != nil { l.Errorw("[Purchase] Database insert error", logger.Field("error", e.Error()), - logger.Field("deductionLog", giftAmountLog), + logger.Field("deductionLog", giftLog), ) return e } diff --git a/internal/logic/public/order/renewalLogic.go b/internal/logic/public/order/renewalLogic.go index 6692628..6b4ace2 100644 --- a/internal/logic/public/order/renewalLogic.go +++ b/internal/logic/public/order/renewalLogic.go @@ -5,6 +5,7 @@ import ( "encoding/json" "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "gorm.io/gorm" @@ -163,16 +164,24 @@ func (l *RenewalLogic) Renewal(req *types.RenewalOrderRequest) (resp *types.Rene return err } // create deduction record - deductionLog := user.GiftAmountLog{ - UserId: orderInfo.UserId, - OrderNo: orderInfo.OrderNo, - Amount: orderInfo.GiftAmount, - Type: 2, - Balance: u.GiftAmount, - Remark: "Renewal order deduction", + giftLog := log.Gift{ + Type: log.GiftTypeReduce, + OrderNo: orderInfo.OrderNo, + SubscribeId: 0, + Amount: orderInfo.GiftAmount, + Balance: u.GiftAmount, + Remark: "Renewal order deduction", + CreatedAt: time.Now().UnixMilli(), } - if err := db.Model(&user.GiftAmountLog{}).Create(&deductionLog).Error; err != nil { - l.Errorw("[Renewal] Database insert error", logger.Field("error", err.Error()), logger.Field("deductionLog", deductionLog)) + content, _ := giftLog.Marshal() + + if err := db.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeGift.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: u.Id, + Content: string(content), + }).Error; err != nil { + l.Errorw("[Renewal] Database insert error", logger.Field("error", err.Error()), logger.Field("deductionLog", giftLog)) return err } } diff --git a/internal/logic/public/order/resetTrafficLogic.go b/internal/logic/public/order/resetTrafficLogic.go index 03ec1a0..4762f4f 100644 --- a/internal/logic/public/order/resetTrafficLogic.go +++ b/internal/logic/public/order/resetTrafficLogic.go @@ -5,6 +5,7 @@ import ( "encoding/json" "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/pkg/xerr" @@ -104,16 +105,24 @@ func (l *ResetTrafficLogic) ResetTraffic(req *types.ResetTrafficOrderRequest) (r return err } // create deduction record - deductionLog := user.GiftAmountLog{ - UserId: orderInfo.UserId, - OrderNo: orderInfo.OrderNo, - Amount: orderInfo.GiftAmount, - Type: 2, - Balance: u.GiftAmount, - Remark: "ResetTraffic order deduction", + giftLog := log.Gift{ + Type: log.GiftTypeReduce, + OrderNo: orderInfo.OrderNo, + SubscribeId: 0, + Amount: orderInfo.GiftAmount, + Balance: u.GiftAmount, + Remark: "Renewal order deduction", + CreatedAt: time.Now().UnixMilli(), } - if err := db.Model(&user.GiftAmountLog{}).Create(&deductionLog).Error; err != nil { - l.Errorw("[ResetTraffic] Database insert error", logger.Field("error", err.Error()), logger.Field("deductionLog", deductionLog)) + content, _ := giftLog.Marshal() + + if err = db.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeGift.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: u.Id, + Content: string(content), + }).Error; err != nil { + l.Errorw("[ResetTraffic] Database insert error", logger.Field("error", err.Error()), logger.Field("deductionLog", content)) return err } } diff --git a/internal/logic/public/portal/purchaseCheckoutLogic.go b/internal/logic/public/portal/purchaseCheckoutLogic.go index 1b71b08..381de56 100644 --- a/internal/logic/public/portal/purchaseCheckoutLogic.go +++ b/internal/logic/public/portal/purchaseCheckoutLogic.go @@ -4,7 +4,9 @@ import ( "context" "encoding/json" "strconv" + "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" paymentPlatform "github.com/perfect-panel/server/pkg/payment" @@ -386,16 +388,21 @@ func (l *PurchaseCheckoutLogic) balancePayment(u *user.User, o *order.Order) err // Create gift amount log if gift amount was used if giftUsed > 0 { - giftLog := &user.GiftAmountLog{ - UserId: u.Id, - UserSubscribeId: 0, // Will be updated when subscription is created - OrderNo: o.OrderNo, - Type: 2, // Type 2 represents gift amount decrease/usage - Amount: giftUsed, - Balance: userInfo.GiftAmount, - Remark: "Purchase payment", + giftLog := &log.Gift{ + OrderNo: o.OrderNo, + Type: 2, // Type 2 represents gift amount decrease/usage + Amount: giftUsed, + Balance: userInfo.GiftAmount, + Remark: "Purchase payment", } - err = db.Create(giftLog).Error + content, _ := giftLog.Marshal() + + err = db.Create(&log.SystemLog{ + Type: log.TypeGift.Uint8(), + ObjectID: userInfo.Id, + Date: time.Now().Format(time.DateOnly), + Content: string(content), + }).Error if err != nil { return err } @@ -403,14 +410,19 @@ func (l *PurchaseCheckoutLogic) balancePayment(u *user.User, o *order.Order) err // Create balance log if regular balance was used if balanceUsed > 0 { - balanceLog := &user.BalanceLog{ - UserId: u.Id, + balanceLog := &log.Balance{ Amount: balanceUsed, - Type: 3, // Type 3 represents payment deduction + Type: log.BalanceTypePayment, // Type 3 represents payment deduction OrderId: o.Id, Balance: userInfo.Balance, } - err = db.Create(balanceLog).Error + content, _ := balanceLog.Marshal() + err = db.Create(&log.SystemLog{ + Type: log.TypeBalance.Uint8(), + ObjectID: userInfo.Id, + Date: time.Now().Format(time.DateOnly), + Content: string(content), + }).Error if err != nil { return err } diff --git a/internal/logic/public/user/getLoginLogLogic.go b/internal/logic/public/user/getLoginLogLogic.go index ce61fa8..d1291df 100644 --- a/internal/logic/public/user/getLoginLogLogic.go +++ b/internal/logic/public/user/getLoginLogLogic.go @@ -3,13 +3,13 @@ package user import ( "context" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" ) @@ -35,15 +35,34 @@ func (l *GetLoginLogLogic) GetLoginLog(req *types.GetLoginLogRequest) (resp *typ logger.Error("current user is not found in context") return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") } - data, total, err := l.svcCtx.UserModel.FilterLoginLogList(l.ctx, req.Page, req.Size, &user.LoginLogFilterParams{ - UserId: u.Id, + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeLogin.Uint8(), + ObjectID: u.Id, }) if err != nil { l.Errorw("find login log failed:", logger.Field("error", err.Error()), logger.Field("user_id", u.Id)) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "find login log failed: %v", err.Error()) } list := make([]types.UserLoginLog, 0) - tool.DeepCopy(&list, data) + + for _, datum := range data { + var content log.Login + if err = content.Unmarshal([]byte(datum.Content)); err != nil { + l.Errorf("[GetUserLoginLogs] unmarshal login log content failed: %v", err.Error()) + continue + } + list = append(list, types.UserLoginLog{ + Id: datum.Id, + UserId: datum.ObjectID, + LoginIP: content.LoginIP, + UserAgent: content.UserAgent, + Success: content.Success, + CreatedAt: datum.CreatedAt.UnixMilli(), + }) + } + return &types.GetLoginLogResponse{ Total: total, List: list, diff --git a/internal/logic/public/user/getSubscribeLogLogic.go b/internal/logic/public/user/getSubscribeLogLogic.go index a24308b..f18f511 100644 --- a/internal/logic/public/user/getSubscribeLogLogic.go +++ b/internal/logic/public/user/getSubscribeLogLogic.go @@ -3,13 +3,13 @@ package user import ( "context" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/internal/model/user" "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" - "github.com/perfect-panel/server/pkg/tool" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" ) @@ -35,15 +35,34 @@ func (l *GetSubscribeLogLogic) GetSubscribeLog(req *types.GetSubscribeLogRequest logger.Error("current user is not found in context") return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") } - data, total, err := l.svcCtx.UserModel.FilterSubscribeLogList(l.ctx, req.Page, req.Size, &user.SubscribeLogFilterParams{ - UserId: u.Id, + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeSubscribe.Uint8(), + ObjectID: u.Id, }) if err != nil { l.Errorw("[GetUserSubscribeLogs] Get User Subscribe Logs Error:", logger.Field("err", err.Error())) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Get User Subscribe Logs Error") } var list []types.UserSubscribeLog - tool.DeepCopy(&list, data) + + for _, item := range data { + var content log.Subscribe + if err = content.Unmarshal([]byte(item.Content)); err != nil { + l.Errorf("[GetUserSubscribeLogs] unmarshal subscribe log content failed: %v", err.Error()) + continue + } + list = append(list, types.UserSubscribeLog{ + Id: item.Id, + UserId: item.ObjectID, + UserSubscribeId: content.SubscribeId, + Token: content.Token, + IP: content.ClientIP, + UserAgent: content.UserAgent, + CreatedAt: item.CreatedAt.UnixMilli(), + }) + } return &types.GetSubscribeLogResponse{ List: list, diff --git a/internal/logic/public/user/queryUserAffiliateLogic.go b/internal/logic/public/user/queryUserAffiliateLogic.go index e0435da..7c8e731 100644 --- a/internal/logic/public/user/queryUserAffiliateLogic.go +++ b/internal/logic/public/user/queryUserAffiliateLogic.go @@ -3,6 +3,7 @@ package user import ( "context" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/internal/model/user" @@ -44,14 +45,20 @@ func (l *QueryUserAffiliateLogic) QueryUserAffiliate() (resp *types.QueryUserAff if err != nil { return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Affiliate failed: %v", err) } - err = l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { - return db.Model(&user.CommissionLog{}). - Where("user_id = ?", u.Id). - Select("COALESCE(SUM(amount), 0)"). - Scan(&sum).Error + data, _, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: 1, + Size: 99999, + Type: log.TypeCommission.Uint8(), + ObjectID: u.Id, }) - if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Affiliate failed: %v", err) + + for _, datum := range data { + content := log.Commission{} + if err = content.Unmarshal([]byte(datum.Content)); err != nil { + l.Errorf("[QueryUserAffiliate] unmarshal comission log failed: %v", err.Error()) + continue + } + sum += content.Amount } return &types.QueryUserAffiliateCountResponse{ diff --git a/internal/logic/public/user/queryUserBalanceLogLogic.go b/internal/logic/public/user/queryUserBalanceLogLogic.go index 2a3c72d..6a030f9 100644 --- a/internal/logic/public/user/queryUserBalanceLogLogic.go +++ b/internal/logic/public/user/queryUserBalanceLogLogic.go @@ -3,17 +3,15 @@ package user import ( "context" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" ) type QueryUserBalanceLogLogic struct { @@ -37,19 +35,39 @@ func (l *QueryUserBalanceLogLogic) QueryUserBalanceLog() (resp *types.QueryUserB logger.Error("current user is not found in context") return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") } - var data []*user.BalanceLog - var total int64 - // Query User Balance Log - err = l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { - return db.Model(&user.BalanceLog{}).Order("created_at DESC").Where("user_id = ?", u.Id).Count(&total).Find(&data).Error + + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: 1, + Size: 99999, + Type: log.TypeBalance.Uint8(), + ObjectID: u.Id, }) if err != nil { - return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Balance Log failed: %v", err) + l.Errorw("[QueryUserBalanceLog] Query User Balance Log Error:", logger.Field("err", err.Error())) + return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Balance Log Error") } + resp = &types.QueryUserBalanceLogListResponse{ - List: make([]types.UserBalanceLog, 0), Total: total, } - tool.DeepCopy(&resp.List, data) + + list := make([]types.UserBalanceLog, 0) + for _, datum := range data { + var content log.Balance + if err = content.Unmarshal([]byte(datum.Content)); err != nil { + l.Errorf("[QueryUserBalanceLog] unmarshal balance log content failed: %v", err.Error()) + continue + } + list = append(list, types.UserBalanceLog{ + Id: datum.Id, + UserId: datum.ObjectID, + Amount: content.Amount, + Type: content.Type, + OrderId: content.OrderId, + Balance: content.Balance, + CreatedAt: datum.CreatedAt.UnixMilli(), + }) + } + return } diff --git a/internal/logic/public/user/queryUserCommissionLogLogic.go b/internal/logic/public/user/queryUserCommissionLogLogic.go index 8038197..b7a5f28 100644 --- a/internal/logic/public/user/queryUserCommissionLogLogic.go +++ b/internal/logic/public/user/queryUserCommissionLogLogic.go @@ -3,17 +3,15 @@ package user import ( "context" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/internal/model/user" - "github.com/perfect-panel/server/pkg/tool" - "github.com/perfect-panel/server/pkg/xerr" - "github.com/pkg/errors" - "gorm.io/gorm" - "github.com/perfect-panel/server/internal/svc" "github.com/perfect-panel/server/internal/types" "github.com/perfect-panel/server/pkg/logger" + "github.com/perfect-panel/server/pkg/xerr" + "github.com/pkg/errors" ) type QueryUserCommissionLogLogic struct { @@ -32,22 +30,40 @@ func NewQueryUserCommissionLogLogic(ctx context.Context, svcCtx *svc.ServiceCont } func (l *QueryUserCommissionLogLogic) QueryUserCommissionLog(req *types.QueryUserCommissionLogListRequest) (resp *types.QueryUserCommissionLogListResponse, err error) { - var data []*user.CommissionLog u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User) if !ok { logger.Error("current user is not found in context") return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access") } - err = l.svcCtx.UserModel.Transaction(l.ctx, func(db *gorm.DB) error { - return db.Order("id desc").Limit(req.Size).Offset((req.Page-1)*req.Size).Where("user_id = ?", u.Id).Find(&data).Error + data, total, err := l.svcCtx.LogModel.FilterSystemLog(l.ctx, &log.FilterParams{ + Page: req.Page, + Size: req.Size, + Type: log.TypeCommission.Uint8(), + ObjectID: u.Id, }) if err != nil { l.Errorw("Query User Commission Log failed", logger.Field("error", err.Error())) return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "Query User Commission Log failed: %v", err) } var list []types.CommissionLog - tool.DeepCopy(&list, data) + + for _, datum := range data { + var content log.Commission + if err = content.Unmarshal([]byte(datum.Content)); err != nil { + l.Errorf("unmarshal commission log content failed: %v", err.Error()) + continue + } + list = append(list, types.CommissionLog{ + Id: datum.Id, + UserId: datum.ObjectID, + OrderNo: content.OrderNo, + Amount: content.Amount, + CreatedAt: content.CreatedAt, + }) + } + return &types.QueryUserCommissionLogListResponse{ - List: list, + List: list, + Total: total, }, nil } diff --git a/internal/logic/public/user/unsubscribeLogic.go b/internal/logic/public/user/unsubscribeLogic.go index 9df80d5..7bd6692 100644 --- a/internal/logic/public/user/unsubscribeLogic.go +++ b/internal/logic/public/user/unsubscribeLogic.go @@ -2,7 +2,9 @@ package user import ( "context" + "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/pkg/xerr" "github.com/pkg/errors" @@ -91,30 +93,43 @@ func (l *UnsubscribeLogic) Unsubscribe(req *types.UnsubscribeRequest) error { // Create balance log entry only if there's an actual regular balance refund balanceRefundAmount := balance - u.Balance if balanceRefundAmount > 0 { - balanceLog := user.BalanceLog{ - UserId: userSub.UserId, + balanceLog := log.Balance{ OrderId: userSub.OrderId, Amount: balanceRefundAmount, - Type: 4, // Type 4 represents refund transaction + Type: log.BalanceTypeRefund, // Type 4 represents refund transaction Balance: balance, } - if err := db.Model(&user.BalanceLog{}).Create(&balanceLog).Error; err != nil { + content, _ := balanceLog.Marshal() + + if err := db.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeBalance.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: u.Id, + Content: string(content), + }).Error; err != nil { return err } } // Create gift amount log entry if there's a gift balance refund if gift > 0 { - giftLog := user.GiftAmountLog{ - UserId: userSub.UserId, - UserSubscribeId: userSub.Id, - OrderNo: orderInfo.OrderNo, - Type: 1, // Type 1 represents gift amount increase - Amount: gift, - Balance: u.GiftAmount + gift, - Remark: "Unsubscribe refund", + + giftLog := log.Gift{ + SubscribeId: userSub.Id, + OrderNo: orderInfo.OrderNo, + Type: log.GiftTypeIncrease, // Type 1 represents gift amount increase + Amount: gift, + Balance: u.GiftAmount + gift, + Remark: "Unsubscribe refund", } - if err := db.Model(&user.GiftAmountLog{}).Create(&giftLog).Error; err != nil { + content, _ := giftLog.Marshal() + + if err := db.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeGift.Uint8(), + Date: time.Now().Format(time.DateOnly), + ObjectID: u.Id, + Content: string(content), + }).Error; err != nil { return err } // Update user's gift amount diff --git a/internal/logic/subscribe/subscribeLogic.go b/internal/logic/subscribe/subscribeLogic.go index a51ab90..3ce99e7 100644 --- a/internal/logic/subscribe/subscribeLogic.go +++ b/internal/logic/subscribe/subscribeLogic.go @@ -8,6 +8,7 @@ import ( "github.com/perfect-panel/server/adapter" "github.com/perfect-panel/server/internal/model/client" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/internal/model/server" "github.com/perfect-panel/server/internal/model/user" @@ -175,12 +176,19 @@ func (l *SubscribeLogic) logSubscribeActivity(subscribeStatus bool, userSub *use return } - err := l.svc.UserModel.InsertSubscribeLog(l.ctx.Request.Context(), &user.SubscribeLog{ - UserId: userSub.UserId, - UserSubscribeId: userSub.Id, - Token: req.Token, - IP: l.ctx.ClientIP(), - UserAgent: l.ctx.Request.UserAgent(), + subscribeLog := log.Subscribe{ + Token: req.Token, + UserAgent: req.UA, + ClientIP: l.ctx.ClientIP(), + } + + content, _ := subscribeLog.Marshal() + + err := l.svc.LogModel.Insert(l.ctx.Request.Context(), &log.SystemLog{ + Type: log.TypeSubscribe.Uint8(), + ObjectID: userSub.Id, + Date: time.Now().Format(time.DateOnly), + Content: string(content), }) if err != nil { l.Errorw("[Generate Subscribe]insert subscribe log error: %v", logger.Field("error", err.Error())) diff --git a/internal/middleware/traceMiddleware.go b/internal/middleware/traceMiddleware.go index a697cb5..6e143a8 100644 --- a/internal/middleware/traceMiddleware.go +++ b/internal/middleware/traceMiddleware.go @@ -9,14 +9,12 @@ import ( "github.com/perfect-panel/server/pkg/constant" "github.com/gin-gonic/gin" - "github.com/google/uuid" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" semconv "go.opentelemetry.io/otel/semconv/v1.24.0" oteltrace "go.opentelemetry.io/otel/trace" "github.com/perfect-panel/server/internal/svc" - "github.com/perfect-panel/server/pkg/logger" "github.com/perfect-panel/server/pkg/trace" ) @@ -71,19 +69,13 @@ func TraceMiddleware(_ *svc.ServiceContext) func(ctx *gin.Context) { ) defer span.End() - requestId, err := uuid.NewV7() - if err != nil { - logger.Errorw( - "failed to generate request id in uuid v7 format, fallback to uuid v4", - logger.Field("error", err), - ) - requestId = uuid.New() - } - c.Header(trace.RequestIdKey, requestId.String()) + requestId := trace.TraceIDFromContext(ctx) + + c.Header(trace.RequestIdKey, requestId) span.SetAttributes(requestAttributes(c.Request)...) span.SetAttributes( - attribute.String("http.request_id", requestId.String()), + attribute.String("http.request_id", requestId), semconv.HTTPRouteKey.String(c.FullPath()), ) // context with request host diff --git a/internal/model/log/default.go b/internal/model/log/default.go index 5b8d731..242891a 100644 --- a/internal/model/log/default.go +++ b/internal/model/log/default.go @@ -6,74 +6,50 @@ import ( "gorm.io/gorm" ) -var _ Model = (*customLogModel)(nil) +var _ Model = (*customSystemLogModel)(nil) type ( Model interface { - messageLogModel + systemLogModel + customSystemLogLogicModel } - messageLogModel interface { - InsertMessageLog(ctx context.Context, data *MessageLog) error - FindOneMessageLog(ctx context.Context, id int64) (*MessageLog, error) - UpdateMessageLog(ctx context.Context, data *MessageLog) error - DeleteMessageLog(ctx context.Context, id int64) error - FindMessageLogList(ctx context.Context, page, size int, filter MessageLogFilterParams) (int64, []*MessageLog, error) + systemLogModel interface { + Insert(ctx context.Context, data *SystemLog) error + FindOne(ctx context.Context, id int64) (*SystemLog, error) + Update(ctx context.Context, data *SystemLog) error + Delete(ctx context.Context, id int64) error } - - customLogModel struct { + customSystemLogModel struct { *defaultLogModel } defaultLogModel struct { - Connection *gorm.DB + *gorm.DB } ) -func newLogModel(db *gorm.DB) *defaultLogModel { +func newSystemLogModel(db *gorm.DB) *defaultLogModel { return &defaultLogModel{ - Connection: db, + DB: db, } } -func (m *defaultLogModel) InsertMessageLog(ctx context.Context, data *MessageLog) error { - return m.Connection.WithContext(ctx).Create(&data).Error +func (m *defaultLogModel) Insert(ctx context.Context, data *SystemLog) error { + return m.WithContext(ctx).Create(data).Error } -func (m *defaultLogModel) FindOneMessageLog(ctx context.Context, id int64) (*MessageLog, error) { - var resp MessageLog - err := m.Connection.WithContext(ctx).Model(&MessageLog{}).Where("`id` = ?", id).First(&resp).Error - return &resp, err +func (m *defaultLogModel) FindOne(ctx context.Context, id int64) (*SystemLog, error) { + var log SystemLog + err := m.WithContext(ctx).Where("id = ?", id).First(&log).Error + if err != nil { + return nil, err + } + return &log, nil } -func (m *defaultLogModel) UpdateMessageLog(ctx context.Context, data *MessageLog) error { - return m.Connection.WithContext(ctx).Model(&MessageLog{}).Where("id = ?", data.Id).Updates(data).Error +func (m *defaultLogModel) Update(ctx context.Context, data *SystemLog) error { + return m.WithContext(ctx).Where("`id` = ?", data.Id).Save(data).Error } -func (m *defaultLogModel) DeleteMessageLog(ctx context.Context, id int64) error { - return m.Connection.WithContext(ctx).Model(&MessageLog{}).Where("id = ?", id).Delete(&MessageLog{}).Error -} - -func (m *defaultLogModel) FindMessageLogList(ctx context.Context, page, size int, filter MessageLogFilterParams) (int64, []*MessageLog, error) { - var list []*MessageLog - var total int64 - conn := m.Connection.WithContext(ctx).Model(&MessageLog{}) - if filter.Type != "" { - conn = conn.Where("`type` = ?", filter.Type) - } - if filter.Platform != "" { - conn = conn.Where("`platform` = ?", filter.Platform) - } - if filter.To != "" { - conn = conn.Where("`to` LIKE ?", "%"+filter.To+"%") - } - if filter.Subject != "" { - conn = conn.Where("`subject` LIKE ?", "%"+filter.Subject+"%") - } - if filter.Content != "" { - conn = conn.Where("`content` = ?", "%"+filter.Content+"%") - } - if filter.Status > 0 { - conn = conn.Where("`status` = ?", filter.Status) - } - err := conn.Count(&total).Offset((page - 1) * size).Limit(size).Find(&list).Error - return total, list, err +func (m *defaultLogModel) Delete(ctx context.Context, id int64) error { + return m.WithContext(ctx).Where("`id` = ?", id).Delete(&SystemLog{}).Error } diff --git a/internal/model/log/log.go b/internal/model/log/log.go index af66746..28574c2 100644 --- a/internal/model/log/log.go +++ b/internal/model/log/log.go @@ -1,45 +1,298 @@ package log -import "time" - -type MessageType int - -const ( - Email MessageType = iota + 1 - Mobile +import ( + "encoding/json" + "time" ) -func (t MessageType) String() string { - switch t { - case Email: - return "email" - case Mobile: - return "mobile" - } - return "unknown" +type Type uint8 + +const ( + TypeEmailMessage Type = iota + 1 // Message log + TypeMobileMessage // Mobile message log + TypeSubscribe // Subscription log + TypeSubscribeTraffic // Subscription traffic log + TypeServerTraffic // Server traffic log + TypeLogin // Login log + TypeRegister // Registration log + TypeBalance // Balance log + TypeCommission // Commission log + TypeResetSubscribe // Reset subscription log + TypeGift // Gift log +) + +// Uint8 converts Type to uint8. +func (t Type) Uint8() uint8 { + return uint8(t) } -type MessageLog struct { - Id int64 `gorm:"primaryKey"` - Type string `gorm:"type:varchar(50);not null;default:'email';comment:Message Type"` - Platform string `gorm:"type:varchar(50);not null;default:'smtp';comment:Platform"` - To string `gorm:"type:text;not null;comment:To"` - Subject string `gorm:"type:varchar(255);not null;default:'';comment:Subject"` - Content string `gorm:"type:text;comment:Content"` - Status int `gorm:"type:tinyint(1);not null;default:0;comment:Status"` +// SystemLog represents a log entry in the system. +type SystemLog struct { + Id int64 `gorm:"primaryKey;AUTO_INCREMENT"` + Type uint8 `gorm:"index:idx_type;type:tinyint(1);not null;default:0;comment:Log Type: 1: Email Message 2: Mobile Message 3: Subscribe 4: Subscribe Traffic 5: Server Traffic 6: Login 7: Register 8: Balance 9: Commission 10: Reset Subscribe 11: Gift"` + Date string `gorm:"type:varchar(20);default:null;comment:Log Date"` + ObjectID int64 `gorm:"index:idx_object_id;type:bigint(20);not null;default:0;comment:Object ID"` + Content string `gorm:"type:text;not null;comment:Log Content"` CreatedAt time.Time `gorm:"<-:create;comment:Create Time"` - UpdatedAt time.Time `gorm:"comment:Update Time"` } -func (m *MessageLog) TableName() string { - return "message_log" +// TableName returns the name of the table for SystemLogs. +func (SystemLog) TableName() string { + return "system_logs" } -type MessageLogFilterParams struct { - Type string - Platform string - To string - Subject string - Content string - Status int +// Message represents a message log entry. +type Message struct { + To string `json:"to"` + Subject string `json:"subject,omitempty"` + Content map[string]interface{} `json:"content"` + Platform string `json:"platform"` + Template string `json:"template"` + Status uint8 `json:"status"` // 1: Sent, 2: Failed +} + +// Marshal implements the json.Marshaler interface for Message. +func (m *Message) Marshal() ([]byte, error) { + type Alias Message + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(m), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Message. +func (m *Message) Unmarshal(data []byte) error { + type Alias Message + aux := (*Alias)(m) + return json.Unmarshal(data, aux) +} + +// Traffic represents a subscription traffic log entry. +type Traffic struct { + Download int64 `json:"download"` + Upload int64 `json:"upload"` +} + +// Marshal implements the json.Marshaler interface for SubscribeTraffic. +func (s *Traffic) Marshal() ([]byte, error) { + type Alias Traffic + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(s), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for SubscribeTraffic. +func (s *Traffic) Unmarshal(data []byte) error { + type Alias Traffic + aux := (*Alias)(s) + return json.Unmarshal(data, aux) +} + +// Login represents a login log entry. +type Login struct { + LoginIP string `json:"login_ip"` + UserAgent string `json:"user_agent"` + Success bool `json:"success"` + LoginTime int64 `json:"login_time"` +} + +// Marshal implements the json.Marshaler interface for Login. +func (l *Login) Marshal() ([]byte, error) { + type Alias Login + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(l), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Login. +func (l *Login) Unmarshal(data []byte) error { + type Alias Login + aux := (*Alias)(l) + return json.Unmarshal(data, aux) +} + +// Register represents a registration log entry. +type Register struct { + AuthMethod string `json:"auth_method"` + Identifier string `json:"identifier"` + RegisterIP string `json:"register_ip"` + UserAgent string `json:"user_agent"` + RegisterTime int64 `json:"register_time"` +} + +// Marshal implements the json.Marshaler interface for Register. +func (r *Register) Marshal() ([]byte, error) { + type Alias Register + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(r), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Register. + +func (r *Register) Unmarshal(data []byte) error { + type Alias Register + aux := (*Alias)(r) + return json.Unmarshal(data, aux) +} + +// Subscribe represents a subscription log entry. +type Subscribe struct { + Token string `json:"token"` + UserAgent string `json:"user_agent"` + ClientIP string `json:"client_ip"` + SubscribeId int64 `json:"subscribe_id"` +} + +// Marshal implements the json.Marshaler interface for Subscribe. +func (s *Subscribe) Marshal() ([]byte, error) { + type Alias Subscribe + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(s), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Subscribe. +func (s *Subscribe) Unmarshal(data []byte) error { + type Alias Subscribe + aux := (*Alias)(s) + return json.Unmarshal(data, aux) +} + +const ( + ResetSubscribeTypeAuto uint8 = 1 + ResetSubscribeTypeAdvance uint8 = 2 + ResetSubscribeTypePaid uint8 = 3 +) + +// ResetSubscribe represents a reset subscription log entry. +type ResetSubscribe struct { + Type uint8 `json:"type"` + OrderNo string `json:"order_no,omitempty"` + ResetAt int64 `json:"reset_at"` +} + +// Marshal implements the json.Marshaler interface for ResetSubscribe. +func (r *ResetSubscribe) Marshal() ([]byte, error) { + type Alias ResetSubscribe + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(r), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for ResetSubscribe. +func (r *ResetSubscribe) Unmarshal(data []byte) error { + type Alias ResetSubscribe + aux := (*Alias)(r) + return json.Unmarshal(data, aux) +} + +const ( + BalanceTypeRecharge uint8 = 1 // Recharge + BalanceTypeWithdraw uint8 = 2 // Withdraw + BalanceTypePayment uint8 = 3 // Payment + BalanceTypeRefund uint8 = 4 // Refund + BalanceTypeReward uint8 = 5 // Reward +) + +// Balance represents a balance log entry. +type Balance struct { + Id int64 `json:"id"` + Type uint8 `json:"type"` + Amount int64 `json:"amount"` + OrderId int64 `json:"order_id,omitempty"` + Balance int64 `json:"balance"` + Timestamp int64 `json:"timestamp"` +} + +// Marshal implements the json.Marshaler interface for Balance. +func (b *Balance) Marshal() ([]byte, error) { + type Alias Balance + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(b), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Balance. +func (b *Balance) Unmarshal(data []byte) error { + type Alias Balance + aux := (*Alias)(b) + return json.Unmarshal(data, aux) +} + +const ( + CommissionTypePurchase uint8 = 1 // Purchase + CommissionTypeRenewal uint8 = 2 // Renewal + CommissionTypeRefund uint8 = 3 // Gift +) + +// Commission represents a commission log entry. +type Commission struct { + Type uint8 `json:"type"` + Amount int64 `json:"amount"` + OrderNo string `json:"order_no"` + CreatedAt int64 `json:"created_at"` +} + +// Marshal implements the json.Marshaler interface for Commission. +func (c *Commission) Marshal() ([]byte, error) { + type Alias Commission + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(c), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Commission. +func (c *Commission) Unmarshal(data []byte) error { + type Alias Commission + aux := (*Alias)(c) + return json.Unmarshal(data, aux) +} + +const ( + GiftTypeIncrease uint8 = 1 // Increase + GiftTypeReduce uint8 = 2 // Reduce +) + +// Gift represents a gift log entry. +type Gift struct { + Type uint8 `json:"type"` + OrderNo string `json:"order_no"` + SubscribeId int64 `json:"subscribe_id"` + Amount int64 `json:"amount"` + Balance int64 `json:"balance"` + Remark string `json:"remark,omitempty"` + CreatedAt int64 `json:"created_at"` +} + +// Marshal implements the json.Marshaler interface for Gift. +func (g *Gift) Marshal() ([]byte, error) { + type Alias Gift + return json.Marshal(&struct { + *Alias + }{ + Alias: (*Alias)(g), + }) +} + +// Unmarshal implements the json.Unmarshaler interface for Gift. +func (g *Gift) Unmarshal(data []byte) error { + type Alias Gift + aux := (*Alias)(g) + return json.Unmarshal(data, aux) } diff --git a/internal/model/log/model.go b/internal/model/log/model.go index 8bacf15..c523f40 100644 --- a/internal/model/log/model.go +++ b/internal/model/log/model.go @@ -1,9 +1,57 @@ package log import ( + "context" + "gorm.io/gorm" ) -func NewModel(conn *gorm.DB) Model { - return newLogModel(conn) +func NewModel(db *gorm.DB) Model { + return &customSystemLogModel{ + defaultLogModel: newSystemLogModel(db), + } +} + +type FilterParams struct { + Page int + Size int + Type uint8 + Search string + ObjectID int64 +} + +type customSystemLogLogicModel interface { + FilterSystemLog(ctx context.Context, filter *FilterParams) ([]*SystemLog, int64, error) +} + +func (m *customSystemLogModel) FilterSystemLog(ctx context.Context, filter *FilterParams) ([]*SystemLog, int64, error) { + tx := m.WithContext(ctx).Model(&SystemLog{}) + if filter == nil { + filter = &FilterParams{ + Page: 1, + Size: 10, + } + } + + if filter.Page < 1 { + filter.Page = 1 + } + if filter.Size < 1 { + filter.Size = 10 + } + + if filter.Type != 0 { + tx = tx.Where("`type` = ?", filter.Type) + } + if filter.ObjectID != 0 { + tx = tx.Where("`object_id` = ?", filter.ObjectID) + } + if filter.Search != "" { + tx = tx.Where("`content` LIKE ?", "%"+filter.Search+"%") + } + + var total int64 + var logs []*SystemLog + err := tx.Count(&total).Limit(filter.Size).Offset((filter.Page - 1) * filter.Size).Find(&logs).Error + return logs, total, err } diff --git a/internal/model/user/default.go b/internal/model/user/default.go index 988d9e9..e2a326a 100644 --- a/internal/model/user/default.go +++ b/internal/model/user/default.go @@ -144,30 +144,10 @@ func (m *defaultUserModel) Delete(ctx context.Context, id int64, tx ...*gorm.DB) return err } - if err := db.Model(&BalanceLog{}).Where("`user_id` = ?", id).Delete(&BalanceLog{}).Error; err != nil { - return err - } - - if err := db.Model(&GiftAmountLog{}).Where("`user_id` = ?", id).Delete(&GiftAmountLog{}).Error; err != nil { - return err - } - - if err := db.Model(&LoginLog{}).Where("`user_id` = ?", id).Delete(&LoginLog{}).Error; err != nil { - return err - } - - if err := db.Model(&SubscribeLog{}).Where("`user_id` = ?", id).Delete(&SubscribeLog{}).Error; err != nil { - return err - } - if err := db.Model(&Device{}).Where("`user_id` = ?", id).Delete(&Device{}).Error; err != nil { return err } - if err := db.Model(&CommissionLog{}).Where("`user_id` = ?", id).Delete(&CommissionLog{}).Error; err != nil { - return err - } - return nil }) } diff --git a/internal/model/user/log.go b/internal/model/user/log.go deleted file mode 100644 index d3e1105..0000000 --- a/internal/model/user/log.go +++ /dev/null @@ -1,81 +0,0 @@ -package user - -import ( - "context" - - "github.com/pkg/errors" - "gorm.io/gorm" -) - -func (m *customUserModel) InsertSubscribeLog(ctx context.Context, log *SubscribeLog) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - return conn.Create(log).Error - }) -} - -func (m *customUserModel) FilterSubscribeLogList(ctx context.Context, page, size int, filter *SubscribeLogFilterParams) ([]*SubscribeLog, int64, error) { - var list []*SubscribeLog - var total int64 - err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - query := conn.Model(&SubscribeLog{}) - if filter != nil { - if filter.UserId != 0 { - query = query.Where("user_id = ?", filter.UserId) - } - if filter.UserSubscribeId != 0 { - query = query.Where("user_subscribe_id = ?", filter.UserSubscribeId) - } - if filter.IP != "" { - query = query.Where("ip LIKE ?", "%"+filter.IP+"%") - } - if filter.Token != "" { - query = query.Where("token LIKE ?", "%"+filter.Token+"%") - } - if filter.UserAgent != "" { - query = query.Where("user_agent LIKE ?", "%"+filter.UserAgent+"%") - } - } - return query.Count(&total).Limit(size).Offset((page - 1) * size).Find(v).Error - }) - - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return nil, 0, err - } - - return list, total, nil -} - -func (m *customUserModel) InsertLoginLog(ctx context.Context, log *LoginLog) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - return conn.Create(log).Error - }) -} - -func (m *customUserModel) FilterLoginLogList(ctx context.Context, page, size int, filter *LoginLogFilterParams) ([]*LoginLog, int64, error) { - var list []*LoginLog - var total int64 - err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - query := conn.Model(&LoginLog{}) - if filter != nil { - if filter.UserId != 0 { - query = query.Where("user_id = ?", filter.UserId) - } - if filter.IP != "" { - query = query.Where("ip LIKE ?", "%"+filter.IP+"%") - } - if filter.UserAgent != "" { - query = query.Where("user_agent LIKE ?", "%"+filter.UserAgent+"%") - } - if filter.Success != nil { - query = query.Where("success = ?", *filter.Success) - } - } - return query.Count(&total).Limit(size).Offset((page - 1) * size).Find(v).Error - }) - - if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { - return nil, 0, err - } - - return list, total, nil -} diff --git a/internal/model/user/model.go b/internal/model/user/model.go index cc3d32c..8da89ea 100644 --- a/internal/model/user/model.go +++ b/internal/model/user/model.go @@ -2,11 +2,11 @@ package user import ( "context" - "errors" "fmt" "time" "github.com/perfect-panel/server/internal/model/subscribe" + "github.com/redis/go-redis/v9" "gorm.io/gorm" ) @@ -76,7 +76,6 @@ type customUserLogicModel interface { QueryUserSubscribe(ctx context.Context, userId int64, status ...int64) ([]*SubscribeDetails, error) FindOneSubscribeDetailsById(ctx context.Context, id int64) (*SubscribeDetails, error) FindOneUserSubscribe(ctx context.Context, id int64) (*SubscribeDetails, error) - InsertBalanceLog(ctx context.Context, data *BalanceLog, tx ...*gorm.DB) error FindUsersSubscribeBySubscribeId(ctx context.Context, subscribeId int64) ([]*Subscribe, error) UpdateUserSubscribeWithTraffic(ctx context.Context, id, download, upload int64, tx ...*gorm.DB) error QueryResisterUserTotalByDate(ctx context.Context, date time.Time) (int64, error) @@ -85,7 +84,6 @@ type customUserLogicModel interface { QueryAdminUsers(ctx context.Context) ([]*User, error) UpdateUserCache(ctx context.Context, data *User) error UpdateUserSubscribeCache(ctx context.Context, data *Subscribe) error - InsertCommissionLog(ctx context.Context, data *CommissionLog, tx ...*gorm.DB) error QueryActiveSubscriptions(ctx context.Context, subscribeId ...int64) (map[int64]int64, error) FindUserAuthMethods(ctx context.Context, userId int64) ([]*AuthMethods, error) InsertUserAuthMethods(ctx context.Context, data *AuthMethods, tx ...*gorm.DB) error @@ -101,20 +99,9 @@ type customUserLogicModel interface { FindOneDeviceByIdentifier(ctx context.Context, id string) (*Device, error) DeleteDevice(ctx context.Context, id int64, tx ...*gorm.DB) error - InsertSubscribeLog(ctx context.Context, log *SubscribeLog) error - FilterSubscribeLogList(ctx context.Context, page, size int, filter *SubscribeLogFilterParams) ([]*SubscribeLog, int64, error) - InsertLoginLog(ctx context.Context, log *LoginLog) error - FilterLoginLogList(ctx context.Context, page, size int, filter *LoginLogFilterParams) ([]*LoginLog, int64, error) - ClearSubscribeCache(ctx context.Context, data ...*Subscribe) error clearUserCache(ctx context.Context, data ...*User) error - InsertResetSubscribeLog(ctx context.Context, log *ResetSubscribeLog, tx ...*gorm.DB) error - UpdateResetSubscribeLog(ctx context.Context, log *ResetSubscribeLog, tx ...*gorm.DB) error - FindResetSubscribeLog(ctx context.Context, id int64) (*ResetSubscribeLog, error) - DeleteResetSubscribeLog(ctx context.Context, id int64, tx ...*gorm.DB) error - FilterResetSubscribeLogList(ctx context.Context, filter *FilterResetSubscribeLogParams) ([]*ResetSubscribeLog, int64, error) - QueryDailyUserStatisticsList(ctx context.Context, date time.Time) ([]UserStatisticsWithDate, error) QueryMonthlyUserStatisticsList(ctx context.Context, date time.Time) ([]UserStatisticsWithDate, error) } @@ -180,27 +167,6 @@ func (m *customUserModel) BatchDeleteUser(ctx context.Context, ids []int64, tx . }, m.batchGetCacheKeys(users...)...) } -// InsertBalanceLog insert BalanceLog into the database. -func (m *customUserModel) InsertBalanceLog(ctx context.Context, data *BalanceLog, tx ...*gorm.DB) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - if len(tx) > 0 { - conn = tx[0] - } - return conn.Create(data).Error - }) -} - -// FindUserBalanceLogList returns a list of records that meet the conditions. -func (m *customUserModel) FindUserBalanceLogList(ctx context.Context, userId int64, page, size int) ([]*BalanceLog, int64, error) { - var list []*BalanceLog - var total int64 - err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - - return conn.Model(&BalanceLog{}).Where("`user_id` = ?", userId).Count(&total).Limit(size).Offset((page - 1) * size).Find(&list).Error - }) - return list, total, err -} - func (m *customUserModel) UpdateUserSubscribeWithTraffic(ctx context.Context, id, download, upload int64, tx ...*gorm.DB) error { sub, err := m.FindOneSubscribe(ctx, id) if err != nil { @@ -265,15 +231,6 @@ func (m *customUserModel) UpdateUserCache(ctx context.Context, data *User) error return m.ClearUserCache(ctx, data) } -func (m *customUserModel) InsertCommissionLog(ctx context.Context, data *CommissionLog, tx ...*gorm.DB) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - if len(tx) > 0 { - conn = tx[0] - } - return conn.Model(&CommissionLog{}).Create(data).Error - }) -} - func (m *customUserModel) FindOneByReferCode(ctx context.Context, referCode string) (*User, error) { var data User err := m.QueryNoCacheCtx(ctx, &data, func(conn *gorm.DB, v interface{}) error { @@ -290,85 +247,6 @@ func (m *customUserModel) FindOneSubscribeDetailsById(ctx context.Context, id in return &data, err } -func (m *customUserModel) InsertResetSubscribeLog(ctx context.Context, log *ResetSubscribeLog, tx ...*gorm.DB) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - if len(tx) > 0 { - conn = tx[0] - } - return conn.Model(&ResetSubscribeLog{}).Create(log).Error - }) -} - -func (m *customUserModel) UpdateResetSubscribeLog(ctx context.Context, log *ResetSubscribeLog, tx ...*gorm.DB) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - if len(tx) > 0 { - conn = tx[0] - } - return conn.Model(&ResetSubscribeLog{}).Where("id = ?", log.Id).Updates(log).Error - }) -} - -func (m *customUserModel) FindResetSubscribeLog(ctx context.Context, id int64) (*ResetSubscribeLog, error) { - var data ResetSubscribeLog - err := m.QueryNoCacheCtx(ctx, &data, func(conn *gorm.DB, v interface{}) error { - return conn.Model(&ResetSubscribeLog{}).Where("id = ?", id).First(&data).Error - }) - return &data, err -} - -func (m *customUserModel) DeleteResetSubscribeLog(ctx context.Context, id int64, tx ...*gorm.DB) error { - return m.ExecNoCacheCtx(ctx, func(conn *gorm.DB) error { - if len(tx) > 0 { - conn = tx[0] - } - return conn.Model(&ResetSubscribeLog{}).Where("id = ?", id).Delete(&ResetSubscribeLog{}).Error - }) -} - -func (m *customUserModel) FilterResetSubscribeLogList(ctx context.Context, filter *FilterResetSubscribeLogParams) ([]*ResetSubscribeLog, int64, error) { - if filter == nil { - return nil, 0, errors.New("filter params is nil") - } - - var list []*ResetSubscribeLog - var total int64 - - err := m.QueryNoCacheCtx(ctx, &list, func(conn *gorm.DB, v interface{}) error { - query := conn.Model(&ResetSubscribeLog{}) - - // 应用筛选条件 - if filter.UserId != 0 { - query = query.Where("user_id = ?", filter.UserId) - } - if filter.UserSubscribeId != 0 { - query = query.Where("user_subscribe_id = ?", filter.UserSubscribeId) - } - if filter.Type != 0 { - query = query.Where("type = ?", filter.Type) - } - if filter.OrderNo != "" { - query = query.Where("order_no = ?", filter.OrderNo) - } - - // 计算总数 - if err := query.Count(&total).Error; err != nil { - return err - } - - // 应用分页 - if filter.Page > 0 && filter.Size > 0 { - query = query.Offset((filter.Page - 1) * filter.Size) - } - if filter.Size > 0 { - query = query.Limit(filter.Size) - } - - return query.Find(&list).Error - }) - - return list, total, err -} - // QueryDailyUserStatisticsList Query daily user statistics list for the current month (from 1st to current date) func (m *customUserModel) QueryDailyUserStatisticsList(ctx context.Context, date time.Time) ([]UserStatisticsWithDate, error) { var results []UserStatisticsWithDate diff --git a/internal/model/user/user.go b/internal/model/user/user.go index 784d531..bbdfce3 100644 --- a/internal/model/user/user.go +++ b/internal/model/user/user.go @@ -52,48 +52,6 @@ func (*Subscribe) TableName() string { return "user_subscribe" } -type BalanceLog struct { - Id int64 `gorm:"primaryKey"` - UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"` - Amount int64 `gorm:"not null;comment:Amount"` - Type uint8 `gorm:"type:tinyint(1);not null;comment:Type: 1: Recharge 2: Withdraw 3: Payment 4: Refund 5: Reward"` - OrderId int64 `gorm:"default:null;comment:Order ID"` - Balance int64 `gorm:"not null;comment:Balance"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` -} - -func (BalanceLog) TableName() string { - return "user_balance_log" -} - -type GiftAmountLog struct { - Id int64 `gorm:"primaryKey"` - UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"` - UserSubscribeId int64 `gorm:"default:null;comment:Deduction User Subscribe ID"` - OrderNo string `gorm:"default:null;comment:Order No."` - Type uint8 `gorm:"type:tinyint(1);not null;comment:Type: 1: Increase 2: Reduce"` - Amount int64 `gorm:"not null;comment:Amount"` - Balance int64 `gorm:"not null;comment:Balance"` - Remark string `gorm:"type:varchar(255);default:'';comment:Remark"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` -} - -func (GiftAmountLog) TableName() string { - return "user_gift_amount_log" -} - -type CommissionLog struct { - Id int64 `gorm:"primaryKey"` - UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"` - OrderNo string `gorm:"default:null;comment:Order No."` - Amount int64 `gorm:"not null;comment:Amount"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` -} - -func (*CommissionLog) TableName() string { - return "user_commission_log" -} - type AuthMethods struct { Id int64 `gorm:"primaryKey"` UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"` @@ -138,58 +96,3 @@ type DeviceOnlineRecord struct { func (DeviceOnlineRecord) TableName() string { return "user_device_online_record" } - -type LoginLog struct { - Id int64 `gorm:"primaryKey"` - UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"` - LoginIP string `gorm:"type:varchar(255);not null;comment:Login IP"` - UserAgent string `gorm:"type:text;not null;comment:UserAgent"` - Success *bool `gorm:"default:false;not null;comment:Login Success"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` -} - -func (LoginLog) TableName() string { - return "user_login_log" -} - -type SubscribeLog struct { - Id int64 `gorm:"primaryKey"` - UserId int64 `gorm:"index:idx_user_id;not null;comment:User ID"` - UserSubscribeId int64 `gorm:"index:idx_user_subscribe_id;not null;comment:User Subscribe ID"` - Token string `gorm:"type:varchar(255);not null;comment:Token"` - IP string `gorm:"type:varchar(255);not null;comment:IP"` - UserAgent string `gorm:"type:text;not null;comment:UserAgent"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` -} - -func (SubscribeLog) TableName() string { - return "user_subscribe_log" -} - -const ( - ResetSubscribeTypeAuto uint8 = 1 - ResetSubscribeTypeAdvance uint8 = 2 - ResetSubscribeTypePaid uint8 = 3 -) - -type FilterResetSubscribeLogParams struct { - Page int - Size int - Type uint8 - UserId int64 - OrderNo string - UserSubscribeId int64 -} - -type ResetSubscribeLog struct { - Id int64 `gorm:"primaryKey"` - UserId int64 `gorm:"type:bigint;index:idx_user_id;not null;comment:User ID"` - Type uint8 `gorm:"type:tinyint(1);not null;comment:Type: 1: Auto 2: Advance 3: Paid"` - OrderNo string `gorm:"type:varchar(255);default:null;comment:Order No."` - UserSubscribeId int64 `gorm:"type:bigint;index:idx_user_subscribe_id;not null;comment:User Subscribe ID"` - CreatedAt time.Time `gorm:"<-:create;comment:Creation Time"` -} - -func (ResetSubscribeLog) TableName() string { - return "user_reset_subscribe_log" -} diff --git a/internal/types/types.go b/internal/types/types.go index 8f893c7..c06a0f2 100644 --- a/internal/types/types.go +++ b/internal/types/types.go @@ -701,14 +701,10 @@ type GetLoginLogResponse struct { } type GetMessageLogListRequest struct { - Page int `form:"page"` - Size int `form:"size"` - Type string `form:"type"` - Platform string `form:"platform,omitempty"` - To string `form:"to,omitempty"` - Subject string `form:"subject,omitempty"` - Content string `form:"content,omitempty"` - Status int `form:"status,omitempty"` + Page int `form:"page"` + Size int `form:"size"` + Type uint8 `form:"type"` + Search string `form:"search,optional"` } type GetMessageLogListResponse struct { @@ -1022,15 +1018,14 @@ type LoginResponse struct { } type MessageLog struct { - Id int64 `json:"id"` - Type string `json:"type"` - Platform string `json:"platform"` - To string `json:"to"` - Subject string `json:"subject"` - Content string `json:"content"` - Status int `json:"status"` - CreatedAt int64 `json:"created_at"` - UpdatedAt int64 `json:"updated_at"` + Id int64 `json:"id"` + Type uint8 `json:"type"` + Platform string `json:"platform"` + To string `json:"to"` + Subject string `json:"subject"` + Content map[string]interface{} `json:"content"` + Status uint8 `json:"status"` + CreatedAt int64 `json:"created_at"` } type MobileAuthenticateConfig struct { diff --git a/pkg/orm/tool_test.go b/pkg/orm/tool_test.go index 95dcdd4..f73e62b 100644 --- a/pkg/orm/tool_test.go +++ b/pkg/orm/tool_test.go @@ -3,7 +3,8 @@ package orm import ( "testing" - "github.com/perfect-panel/server/internal/model/task" + "github.com/perfect-panel/server/internal/model/log" + "gorm.io/driver/mysql" "gorm.io/gorm" ) @@ -30,7 +31,7 @@ func TestMysql(t *testing.T) { if err != nil { t.Fatalf("Failed to connect to MySQL: %v", err) } - err = db.Migrator().AutoMigrate(&task.EmailTask{}) + err = db.Migrator().AutoMigrate(&log.SystemLog{}) if err != nil { t.Fatalf("Failed to auto migrate: %v", err) return diff --git a/queue/logic/email/sendEmailLogic.go b/queue/logic/email/sendEmailLogic.go index 26ee1c0..231ba55 100644 --- a/queue/logic/email/sendEmailLogic.go +++ b/queue/logic/email/sendEmailLogic.go @@ -1,8 +1,11 @@ package emailLogic import ( + "bytes" "context" "encoding/json" + "text/template" + "time" "github.com/perfect-panel/server/pkg/logger" @@ -31,8 +34,7 @@ func (l *SendEmailLogic) ProcessTask(ctx context.Context, task *asynq.Task) erro ) return nil } - messageLog := log.MessageLog{ - Type: log.Email.String(), + messageLog := log.Message{ Platform: l.svcCtx.Config.Email.Platform, To: payload.Email, Subject: payload.Subject, @@ -43,18 +45,108 @@ func (l *SendEmailLogic) ProcessTask(ctx context.Context, task *asynq.Task) erro logger.WithContext(ctx).Error("[SendEmailLogic] NewSender failed", logger.Field("error", err.Error())) return nil } - err = sender.Send([]string{payload.Email}, payload.Subject, payload.Content) + var content string + switch payload.Type { + case types.EmailTypeVerify: + tpl, _ := template.New("verify").Parse(l.svcCtx.Config.Email.VerifyEmailTemplate) + var result bytes.Buffer + err = tpl.Execute(&result, payload.Content) + if err != nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", + logger.Field("error", err.Error()), + logger.Field("template", l.svcCtx.Config.Email.VerifyEmailTemplate), + logger.Field("data", payload.Content), + ) + return nil + } + content = result.String() + case types.EmailTypeMaintenance: + tpl, _ := template.New("maintenance").Parse(l.svcCtx.Config.Email.MaintenanceEmailTemplate) + var result bytes.Buffer + err = tpl.Execute(&result, payload.Content) + if err != nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", + logger.Field("error", err.Error()), + logger.Field("template", l.svcCtx.Config.Email.MaintenanceEmailTemplate), + logger.Field("data", payload.Content), + ) + return nil + } + content = result.String() + case types.EmailTypeExpiration: + tpl, _ := template.New("expiration").Parse(l.svcCtx.Config.Email.ExpirationEmailTemplate) + var result bytes.Buffer + err = tpl.Execute(&result, payload.Content) + if err != nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", + logger.Field("error", err.Error()), + logger.Field("template", l.svcCtx.Config.Email.ExpirationEmailTemplate), + logger.Field("data", payload.Content), + ) + return nil + } + content = result.String() + case types.EmailTypeTrafficExceed: + tpl, _ := template.New("traffic_exceed").Parse(l.svcCtx.Config.Email.TrafficExceedEmailTemplate) + var result bytes.Buffer + err = tpl.Execute(&result, payload.Content) + if err != nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Execute template failed", + logger.Field("error", err.Error()), + logger.Field("template", l.svcCtx.Config.Email.TrafficExceedEmailTemplate), + logger.Field("data", payload.Content), + ) + return nil + } + content = result.String() + case types.EmailTypeCustom: + if payload.Content == nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Custom email content is empty", + logger.Field("payload", payload), + ) + return nil + } + if tpl, ok := payload.Content["content"].(string); !ok { + logger.WithContext(ctx).Error("[SendEmailLogic] Custom email content is not a string", + logger.Field("payload", payload), + ) + return nil + } else { + content = tpl + } + default: + logger.WithContext(ctx).Error("[SendEmailLogic] Unsupported email type", + logger.Field("type", payload.Type), + logger.Field("payload", payload), + ) + } + + err = sender.Send([]string{payload.Email}, payload.Subject, content) if err != nil { logger.WithContext(ctx).Error("[SendEmailLogic] Send email failed", logger.Field("error", err.Error())) return nil } messageLog.Status = 1 - if err = l.svcCtx.LogModel.InsertMessageLog(ctx, &messageLog); err != nil { - logger.WithContext(ctx).Error("[SendEmailLogic] InsertMessageLog failed", + emailLog, err := messageLog.Marshal() + if err != nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Marshal message log failed", logger.Field("error", err.Error()), logger.Field("messageLog", messageLog), ) + return nil + } + + if err = l.svcCtx.LogModel.Insert(ctx, &log.SystemLog{ + Type: log.TypeEmailMessage.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: 0, + Content: string(emailLog), + }); err != nil { + logger.WithContext(ctx).Error("[SendEmailLogic] Insert email log failed", + logger.Field("error", err.Error()), + logger.Field("emailLog", string(emailLog)), + ) + return nil } - logger.WithContext(ctx).Info("[SendEmailLogic] Send email", logger.Field("email", payload.Email), logger.Field("content", payload.Content)) return nil } diff --git a/queue/logic/order/activateOrderLogic.go b/queue/logic/order/activateOrderLogic.go index 39788d7..0ddba05 100644 --- a/queue/logic/order/activateOrderLogic.go +++ b/queue/logic/order/activateOrderLogic.go @@ -9,6 +9,7 @@ import ( "strconv" "time" + "github.com/perfect-panel/server/internal/model/log" "github.com/perfect-panel/server/pkg/constant" "github.com/perfect-panel/server/pkg/logger" @@ -375,12 +376,28 @@ func (l *ActivateOrderLogic) handleCommission(ctx context.Context, userInfo *use return err } - commissionLog := &user.CommissionLog{ - UserId: referer.Id, - OrderNo: orderInfo.OrderNo, - Amount: amount, + var commissionType uint8 + switch orderInfo.Type { + case OrderTypeSubscribe: + commissionType = log.CommissionTypePurchase + case OrderTypeRenewal: + commissionType = log.CommissionTypeRenewal } - return l.svc.UserModel.InsertCommissionLog(ctx, commissionLog, tx) + + commissionLog := &log.Commission{ + Type: commissionType, + Amount: amount, + OrderNo: orderInfo.OrderNo, + CreatedAt: orderInfo.CreatedAt.UnixMilli(), + } + + content, _ := commissionLog.Marshal() + return tx.Model(&log.SystemLog{}).Create(&log.SystemLog{ + Type: log.TypeCommission.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: referer.Id, + Content: string(content), + }).Error }) if err != nil { @@ -594,14 +611,20 @@ func (l *ActivateOrderLogic) Recharge(ctx context.Context, orderInfo *order.Orde return err } - balanceLog := &user.BalanceLog{ - UserId: orderInfo.UserId, + balanceLog := &log.Balance{ Amount: orderInfo.Price, Type: CommissionTypeRecharge, OrderId: orderInfo.Id, Balance: userInfo.Balance, } - return l.svc.UserModel.InsertBalanceLog(ctx, balanceLog, tx) + content, _ := balanceLog.Marshal() + + return tx.Model(&log.Balance{}).Create(&log.SystemLog{ + Type: log.TypeBalance.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: userInfo.Id, + Content: string(content), + }).Error }) if err != nil { diff --git a/queue/logic/sms/sendSmsLogic.go b/queue/logic/sms/sendSmsLogic.go index 196309b..76cef6d 100644 --- a/queue/logic/sms/sendSmsLogic.go +++ b/queue/logic/sms/sendSmsLogic.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "time" "github.com/perfect-panel/server/pkg/logger" @@ -43,17 +44,16 @@ func (l *SendSmsLogic) ProcessTask(ctx context.Context, task *asynq.Task) error logger.WithContext(ctx).Error("[SendSmsLogic] New send sms client failed", logger.Field("error", err.Error()), logger.Field("payload", payload)) return err } - createSms := &log.MessageLog{ - Type: log.Mobile.String(), + createSms := &log.Message{ Platform: l.svcCtx.Config.Mobile.Platform, To: fmt.Sprintf("+%s%s", payload.TelephoneArea, payload.Telephone), Subject: constant.ParseVerifyType(payload.Type).String(), - Content: "", + Content: map[string]interface{}{ + "content": client.GetSendCodeContent(payload.Content), + }, } err = client.SendCode(payload.TelephoneArea, payload.Telephone, payload.Content) - createSms.Content = client.GetSendCodeContent(payload.Content) - if err != nil { logger.WithContext(ctx).Error("[SendSmsLogic] Send sms failed", logger.Field("error", err.Error()), logger.Field("payload", payload)) if l.svcCtx.Config.Model != constant.DevMode { @@ -64,7 +64,14 @@ func (l *SendSmsLogic) ProcessTask(ctx context.Context, task *asynq.Task) error } createSms.Status = 1 logger.WithContext(ctx).Info("[SendSmsLogic] Send sms", logger.Field("telephone", payload.Telephone), logger.Field("content", createSms.Content)) - err = l.svcCtx.LogModel.InsertMessageLog(ctx, createSms) + + content, _ := createSms.Marshal() + err = l.svcCtx.LogModel.Insert(ctx, &log.SystemLog{ + Type: log.TypeMobileMessage.Uint8(), + Date: time.Now().Format("2006-01-02"), + ObjectID: 0, + Content: string(content), + }) if err != nil { logger.WithContext(ctx).Error("[SendSmsLogic] Send sms failed", logger.Field("error", err.Error()), logger.Field("payload", payload)) return nil diff --git a/queue/logic/subscription/checkSubscriptionLogic.go b/queue/logic/subscription/checkSubscriptionLogic.go index ef77130..7894f0b 100644 --- a/queue/logic/subscription/checkSubscriptionLogic.go +++ b/queue/logic/subscription/checkSubscriptionLogic.go @@ -1,10 +1,8 @@ package subscription import ( - "bytes" "context" "encoding/json" - "text/template" "time" queue "github.com/perfect-panel/server/queue/types" @@ -129,24 +127,14 @@ func (l *CheckSubscriptionLogic) sendExpiredNotify(ctx context.Context, subs []i continue } var taskPayload queue.SendEmailPayload + taskPayload.Type = queue.EmailTypeExpiration taskPayload.Email = method.AuthIdentifier taskPayload.Subject = "Subscription Expired" - tpl, err := template.New("Expired").Parse(l.svc.Config.Email.ExpirationEmailTemplate) - if err != nil { - logger.Errorw("[CheckSubscription] Parse template failed", logger.Field("error", err.Error())) - continue - } - var result bytes.Buffer - err = tpl.Execute(&result, map[string]interface{}{ + taskPayload.Content = map[string]interface{}{ "SiteLogo": l.svc.Config.Site.SiteLogo, "SiteName": l.svc.Config.Site.SiteName, "ExpireDate": sub.ExpireTime.Format("2006-01-02 15:04:05"), - }) - if err != nil { - logger.Errorw("[CheckSubscription] Execute template failed", logger.Field("error", err.Error())) - continue } - taskPayload.Content = result.String() payloadBuy, err := json.Marshal(taskPayload) if err != nil { logger.Errorw("[CheckSubscription] Marshal payload failed", logger.Field("error", err.Error())) @@ -179,23 +167,13 @@ func (l *CheckSubscriptionLogic) sendTrafficNotify(ctx context.Context, subs []i continue } var taskPayload queue.SendEmailPayload + taskPayload.Type = queue.EmailTypeTrafficExceed taskPayload.Email = method.AuthIdentifier taskPayload.Subject = "Subscription Traffic Exceed" - tpl, err := template.New("Traffic").Parse(l.svc.Config.Email.TrafficExceedEmailTemplate) - if err != nil { - logger.Errorw("[CheckSubscription] Parse template failed", logger.Field("error", err.Error())) - continue - } - var result bytes.Buffer - err = tpl.Execute(&result, map[string]interface{}{ + taskPayload.Content = map[string]interface{}{ "SiteLogo": l.svc.Config.Site.SiteLogo, "SiteName": l.svc.Config.Site.SiteName, - }) - if err != nil { - logger.Errorw("[CheckSubscription] Execute template failed", logger.Field("error", err.Error())) - continue } - taskPayload.Content = result.String() payloadBuy, err := json.Marshal(taskPayload) if err != nil { logger.Errorw("[CheckSubscription] Marshal payload failed", logger.Field("error", err.Error())) diff --git a/queue/types/email.go b/queue/types/email.go index c3aa403..45bc1b6 100644 --- a/queue/types/email.go +++ b/queue/types/email.go @@ -7,11 +7,19 @@ const ( ScheduledBatchSendEmail = "scheduled:email:batch" ) +const ( + EmailTypeVerify = "verify" + EmailTypeMaintenance = "maintenance" + EmailTypeExpiration = "expiration" + EmailTypeTrafficExceed = "traffic_exceed" + EmailTypeCustom = "custom" +) + type ( SendEmailPayload struct { - Type string `json:"type"` - Email string `json:"to"` - Subject string `json:"subject"` - Content string `json:"content"` + Type string `json:"type"` + Email string `json:"to"` + Subject string `json:"subject"` + Content map[string]interface{} `json:"content"` } ) diff --git a/queue/types/sms.go b/queue/types/sms.go index 8d9f9e7..affb521 100644 --- a/queue/types/sms.go +++ b/queue/types/sms.go @@ -1,7 +1,7 @@ package types const ( - // ForthwithSendEmail forthwith send email + // ForthwithSendSms forthwith send email ForthwithSendSms = "forthwith:sms:send" )