diff --git a/model/killara_catalog_language_logic.go b/model/killara_catalog_language_logic.go index 39de384..b7222b1 100644 --- a/model/killara_catalog_language_logic.go +++ b/model/killara_catalog_language_logic.go @@ -1,6 +1,8 @@ package model import ( + "strings" + "gorm.io/gorm" ) @@ -9,3 +11,140 @@ type KillaraCatalogLanguageModel struct { db *gorm.DB TableName string // 表名 } + +func (m *KillaraCatalogLanguageModel) InsertLanguage(language *KillaraCatalogLanguage) (uint64, error) { + if err := m.db.Model(&KillaraCatalogLanguage{}).Create(language).Error; err != nil { + return 0, err + } + return *language.LanguageId, nil +} + +func (m *KillaraCatalogLanguageModel) UpdateLanguage(language *KillaraCatalogLanguage) error { + return m.db.Model(&KillaraCatalogLanguage{}).Where("language_id = ?", *language.LanguageId).Updates(language).Error +} + +func (m *KillaraCatalogLanguageModel) DeleteLanguage(language *KillaraCatalogLanguage) error { + return m.db.Where("language_id = ?", *language.LanguageId).Delete(&KillaraCatalogLanguage{}).Error +} + +func (m *KillaraCatalogLanguageModel) GetLanguage(languageID uint64) (*KillaraCatalogLanguage, error) { + var language KillaraCatalogLanguage + err := m.db.Where("language_id = ?", languageID).First(&language).Error + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return &language, err +} + +func (m *KillaraCatalogLanguageModel) GetLanguagesForBackEnd(data map[string]interface{}) ([]*KillaraCatalogLanguage, error) { + var languages []*KillaraCatalogLanguage + query := m.db.Model(&KillaraCatalogLanguage{}) + + var conditions []interface{} + + if filterName, ok := data["filter_name"].(string); ok && filterName != "" { + conditions = append(conditions, m.db.Where("name LIKE ?", filterName+"%")) + } + + if filterCode, ok := data["filter_code"].(string); ok && filterCode != "" { + conditions = append(conditions, m.db.Where("code LIKE ?", filterCode+"%")) + } + + if filterStatus, ok := data["filter_status"]; ok { + conditions = append(conditions, m.db.Where("status = ?", filterStatus)) + } + + if len(conditions) > 0 { + query = query.Where(strings.Join(make([]string, len(conditions)), " AND "), conditions...) + } + + if sort, ok := data["sort"].(string); ok && sort != "" { + order := "DESC" + if sortOrder, ok := data["order"].(string); ok { + order = sortOrder + } + query = query.Order(sort + " " + order) + } + + if start, ok := data["start"].(int); ok && start > 0 { + query = query.Offset(start) + } + + if limit, ok := data["limit"].(int); ok && limit > 0 { + query = query.Limit(limit) + } else { + query = query.Limit(10) + } + + err := query.Find(&languages).Error + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return languages, err +} + +func (m *KillaraCatalogLanguageModel) GetTotalLanguagesForBackEnd(data map[string]interface{}) (int64, error) { + var count int64 + query := m.db.Model(&KillaraCatalogLanguage{}) + + var conditions []interface{} + + if filterName, ok := data["filter_name"].(string); ok && filterName != "" { + conditions = append(conditions, m.db.Where("name LIKE ?", filterName+"%")) + } + + if filterCode, ok := data["filter_code"].(string); ok && filterCode != "" { + conditions = append(conditions, m.db.Where("code LIKE ?", filterCode+"%")) + } + + if filterStatus, ok := data["filter_status"]; ok { + conditions = append(conditions, m.db.Where("status = ?", filterStatus)) + } + + if len(conditions) > 0 { + query = query.Where(strings.Join(make([]string, len(conditions)), " AND "), conditions...) + } + + err := query.Count(&count).Error + if err == gorm.ErrRecordNotFound { + return 0, nil + } + return count, err +} + +func (m *KillaraCatalogLanguageModel) GetLanguageForBackEnd(languageID uint64) (*KillaraCatalogLanguage, error) { + var language KillaraCatalogLanguage + err := m.db.Where("language_id = ?", languageID).First(&language).Error + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return &language, err +} + +func (m *KillaraCatalogLanguageModel) GetLanguageByCodeForBackEnd(code string) (*KillaraCatalogLanguage, error) { + var language KillaraCatalogLanguage + err := m.db.Where("code = ?", code).First(&language).Error + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return &language, err +} + +// 前台使用的方法 +func (m *KillaraCatalogLanguageModel) GetLanguagesForFrontEnd() ([]*KillaraCatalogLanguage, error) { + var languages []*KillaraCatalogLanguage + err := m.db.Where("status = 1").Order("sort_order").Find(&languages).Error + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return languages, err +} + +func (m *KillaraCatalogLanguageModel) GetLanguageForFrontEnd(languageID uint64) (*KillaraCatalogLanguage, error) { + var language KillaraCatalogLanguage + err := m.db.Where("status = 1 AND language_id = ?", languageID).First(&language).Error + if err == gorm.ErrRecordNotFound { + return nil, nil + } + return &language, err +} diff --git a/model/killara_customer_logic.go b/model/killara_customer_logic.go index d48aa95..63366d4 100644 --- a/model/killara_customer_logic.go +++ b/model/killara_customer_logic.go @@ -32,6 +32,9 @@ func (m *KillaraCustomerModel) DeleteCustomer(customer *KillaraCustomer) error { func (m *KillaraCustomerModel) GetCustomer(customerID uint64) (*KillaraCustomer, error) { var customer KillaraCustomer err := m.db.Where("customer_id = ? AND status = 1", customerID).First(&customer).Error + if err == gorm.ErrRecordNotFound { + return nil, nil + } return &customer, err } diff --git a/model/killara_customer_token_logic.go b/model/killara_customer_token_logic.go index 682ed3b..029e22a 100644 --- a/model/killara_customer_token_logic.go +++ b/model/killara_customer_token_logic.go @@ -44,7 +44,7 @@ func (m *KillaraCustomerTokenModel) InsertToken(data *KillaraCustomerToken) erro if !errors.Is(err, gorm.ErrRecordNotFound) { // 存在记录,先删除 err = tx.Delete(&existingToken).Error - if err != nil { + if err != nil && !errors.Is(err, gorm.ErrRecordNotFound) { tx.Rollback() // 删除错误,回滚事务 return err } diff --git a/server/app/internal/handlers/actions/auth.go b/server/app/internal/handlers/actions/auth.go index 9b1863e..12dae10 100644 --- a/server/app/internal/handlers/actions/auth.go +++ b/server/app/internal/handlers/actions/auth.go @@ -1,6 +1,7 @@ package actions import ( + "encoding/json" "strings" "time" @@ -17,16 +18,99 @@ var CompanyKey = "vestmore-bjwl" // @Action base/getToken // Base_GetToken -// action: string; -// app_market: string; -// lang: string; -// token: string; +// randstr: string; +// sign: string; +// action: string; +// lang: string; +// app_market: int64; +// timestamp: int64; +// token: string; func BaseGetToken(ctx *ActionContext[BaseGetTokenParam]) (resp *basic.Response) { - // model.Models.KillaraCustomerModel.Find() - log.Println() + const ( + TokenExpiry = 864000 // Token过期时间,单位:秒 + ) - return resp.Success() + type TokenData struct { + LanguageID uint64 `json:"language_id"` + LanguageCode string `json:"language_code"` + } + + modelToken := model.Models.KillaraCustomerTokenModel + modelLanguage := model.Models.KillaraCatalogLanguageModel + + lang := ctx.Lang + + language, err := modelLanguage.GetLanguageByCodeForBackEnd(lang) + if err != nil || language == nil { + language, _ = modelLanguage.GetLanguageByCodeForBackEnd("en") + } + + tokenData := TokenData{ + LanguageID: *language.LanguageId, + LanguageCode: *language.Code, + } + + isLogin := false + var token string + + if ctx.Param.Token != "" { + result, err := modelToken.CheckToken(ctx.Param.Token) + if err == nil && result != nil { + token = ctx.Param.Token + + // Token存在并且有效 + modelToken.UpdateTokenExpiry(token, time.Now().Unix()+TokenExpiry) + + tokenDataJSON, _ := json.Marshal(tokenData) + modelToken.UpdateTokenData(token, map[string]interface{}{ + "data": string(tokenDataJSON), + }) + + if result.CustomerId != nil && *result.CustomerId != 0 { + modelCustomer := model.Models.KillaraCustomerModel + customer, err := modelCustomer.GetCustomer(*result.CustomerId) + if err == nil && customer != nil { + isLogin = true + } else { + modelToken.UpdateTokenCustomerID(token, 0) + } + } + } + } + + if token == "" { + // Token不存在或失效,重新创建一个 + token = auth.GenerateMD5() + + tokenDataJSON, err := json.Marshal(tokenData) + if err != nil { + return resp.Error(basic.ErrJSONUnMarshal) + } + + tokenItem := &model.KillaraCustomerToken{ + Token: &token, + CustomerId: basic.Uint64Ptr(0), + Data: basic.StringPtr(string(tokenDataJSON)), + Expiry: basic.Int64Ptr(time.Now().Unix() + TokenExpiry), + Platform: basic.Int64Ptr(1), + } + + err = modelToken.InsertToken(tokenItem) + log.Println(err) + if err != nil { + return resp.ErrorErr(1, err) + } + + } + + return resp.Success(map[string]interface{}{ + "token": token, + "is_login": isLogin, + "lang_data": map[string]interface{}{ + "language_id": tokenData.LanguageID, + "language_code": tokenData.LanguageCode, + }}) } // @Action account/loginWithTelephonePassword @@ -258,7 +342,7 @@ func AccountLoginWithEmailPassword(ctx *ActionContext[AccountLoginWithEmailPassw return resp.ErrorErr(1, err) } - ctx.Localize(translator.AccountNotRegistered) + log.Println(ctx.Localize(translator.AccountNotRegistered)) if customer == nil { return resp.ErrorTrCode(ctx, translator.AccountNotRegistered) } diff --git a/server/app/internal/handlers/actions/types_gen.go b/server/app/internal/handlers/actions/types_gen.go index 4c615d2..4fe64fa 100644 --- a/server/app/internal/handlers/actions/types_gen.go +++ b/server/app/internal/handlers/actions/types_gen.go @@ -233,9 +233,12 @@ func AccountRegisterSmsCodeHandler(ctx *gin.Context) { } type BaseGetTokenParam struct { + Randstr string `json:"randstr" form:"randstr" binding:"-"` + Sign string `json:"sign" form:"sign" binding:"-"` Action string `json:"action" form:"action" binding:"-"` - AppMarket string `json:"app_market" form:"app_market" binding:"-"` Lang string `json:"lang" form:"lang" binding:"-"` + AppMarket int64 `json:"app_market" form:"app_market" binding:"-"` + Timestamp int64 `json:"timestamp" form:"timestamp" binding:"-"` Token string `json:"token" form:"token" binding:"-"` } diff --git a/server/app/main_test.go b/server/app/main_test.go index fe84999..122f379 100644 --- a/server/app/main_test.go +++ b/server/app/main_test.go @@ -1,11 +1,11 @@ package main import ( - "log" "testing" _ "github.com/go-sql-driver/mysql" "github.com/iapologizewhenimwrong/Vestmore_GO/translator" + "github.com/iapologizewhenimwrong/Vestmore_GO/utils/log" "github.com/nicksnyder/go-i18n/v2/i18n" "github.com/pelletier/go-toml/v2" "golang.org/x/text/language" diff --git a/translator/translator.go b/translator/translator.go index d80bf57..1b0a0fe 100644 --- a/translator/translator.go +++ b/translator/translator.go @@ -21,7 +21,27 @@ func init() { globpath := filepath.Join(currentDir, "/*.toml") Bundle = i18n.NewBundle(language.Chinese) - Bundle.RegisterUnmarshalFunc("toml", toml.Unmarshal) + Bundle.RegisterUnmarshalFunc("toml", func(data []byte, v interface{}) error { + var m map[string]any + err := toml.Unmarshal(data, &m) + if err != nil { + return err + } + + for _, v := range m { + vm := v.(map[string]any) + desc := vm["description"].(string) + vm["one"] = desc + vm["other"] = desc + } + + fixdata, err := toml.Marshal(m) + if err != nil { + return err + } + + return toml.Unmarshal(fixdata, v) + }) matches, err := filepath.Glob(globpath) if err != nil { panic(err) @@ -30,14 +50,6 @@ func init() { Bundle.MustLoadMessageFile(m) } - // localizer := i18n.NewLocalizer(Bundle, "zh_cn") - // log.Println(localizer.Localize(&i18n.LocalizeConfig{ - // MessageID: "format_account_is_insufficient", - // TemplateData: map[string]any{ - // "CatalogCurrency": "USDT", - // }, - // })) - } func Localize(MessageID TrCode, Lang string, MessageTemplateParam any) (string, error) { diff --git a/translator/translator_test.go b/translator/translator_test.go index 671891e..3393757 100644 --- a/translator/translator_test.go +++ b/translator/translator_test.go @@ -13,6 +13,7 @@ import ( "text/template" "unicode" + "github.com/nicksnyder/go-i18n/v2/i18n" "github.com/pelletier/go-toml/v2" ) @@ -118,7 +119,10 @@ func createTrCode(filePath string) { } func TestTrOnline(t *testing.T) { - + var localizer = i18n.NewLocalizer(Bundle, "zh_cn") + log.Println(localizer.Localize(&i18n.LocalizeConfig{ + MessageID: string("account_not_registered"), + })) } func toCamelCase(s string) string { diff --git a/translator/zh_cn.toml b/translator/zh_cn.toml index a00b5f5..9f4ca1a 100644 --- a/translator/zh_cn.toml +++ b/translator/zh_cn.toml @@ -280,5 +280,6 @@ description = "默认交易时间段" description = "非默认交易时间段" [all_day_transaction] description = "全天交易" + diff --git a/translator/zh_hk.toml b/translator/zh_hk.toml deleted file mode 100644 index e69de29..0000000 diff --git a/utils/auth/valid_code.go b/utils/auth/valid_code.go index 5e40775..6b18775 100644 --- a/utils/auth/valid_code.go +++ b/utils/auth/valid_code.go @@ -1,21 +1,40 @@ package auth import ( + "crypto/md5" "fmt" "math/rand" + "strconv" + "time" ) +var myRand = rand.New(rand.NewSource(time.Now().UnixNano())) + func GenerateVerificationCode() string { var code string for i := 0; i < 3; i++ { // 生成两个 10-99 之间的随机数 - a := rand.Intn(90-10+1) + 10 - b := rand.Intn(90-10+1) + 10 - c := rand.Intn(90-10+1) + 10 + a := myRand.Intn(90-10+1) + 10 + b := myRand.Intn(90-10+1) + 10 + c := myRand.Intn(90-10+1) + 10 // 将随机数拼接到验证码字符串 code += fmt.Sprintf("%d%d%d", a, b, c) } return code } + +func GenerateMD5() string { + + // 将时间戳转换为字节slice + timestampBytes := []byte(strconv.FormatInt(time.Now().UnixNano(), 10)) + + // 计算MD5哈希 + hashBytes := md5.Sum(timestampBytes) + + // 将哈希值转换为十六进制字符串 + hashHex := fmt.Sprintf("%x", hashBytes) + + return hashHex +} diff --git a/utils/basic/error_code.go b/utils/basic/error_code.go index 57bd89e..fa389ee 100644 --- a/utils/basic/error_code.go +++ b/utils/basic/error_code.go @@ -8,7 +8,8 @@ type ErrorCode struct { var ( ErrRespNotNil = &ErrorCode{Code: 10000, Message: "resp must not nil"} - ErrEncGcm = &ErrorCode{Code: 10001, Message: "gmc加密错误"} + ErrEncGcm = &ErrorCode{Code: 10001, Message: "gmc加密错误"} + ErrJSONUnMarshal = &ErrorCode{Code: 10002, Message: "json 解析错误"} ErrParamParse = &ErrorCode{Code: 10100, Message: "参数解析错误"} diff --git a/utils/basic/lang.go b/utils/basic/lang.go index 3b74c0a..f176390 100644 --- a/utils/basic/lang.go +++ b/utils/basic/lang.go @@ -1,6 +1,9 @@ package basic -import "reflect" +import ( + "reflect" + "strings" +) func GetLangString(param any) string { // 获取参数的反射值 @@ -18,10 +21,11 @@ func GetLangString(param any) string { // 如果字段存在并且是字符串类型 if langField.IsValid() && langField.Kind() == reflect.String { - return langField.String() + return strings.TrimSpace(langField.String()) } } // 如果无法获取有效的字符串值,则返回zh_cn + return "zh_cn" } diff --git a/utils/basic/types.go b/utils/basic/types.go index ee835cf..fb0fc01 100644 --- a/utils/basic/types.go +++ b/utils/basic/types.go @@ -37,6 +37,7 @@ func (resp *Response) ErrorErr(Code int, err error, Data ...interface{}) *Respon resp.ErrorText = err.Error() resp.IsSuccess = false resp.setData(Data) + log.Error(resp.ErrorText) return resp } diff --git a/utils/log/json_format.go b/utils/log/json_format.go index beeb27b..4668012 100644 --- a/utils/log/json_format.go +++ b/utils/log/json_format.go @@ -4,6 +4,7 @@ import ( "bytes" "encoding/json" "fmt" + "log" "runtime" "strings" "sync" @@ -13,14 +14,13 @@ import ( ) type levelSkip struct { - Skip int - Once sync.Once + SkipLogrus int + SkipBasic int } // JSONFormatter formats logs into parsable json type JSONFormatter struct { skip []*levelSkip - once sync.Once } @@ -28,36 +28,79 @@ type JSONFormatter struct { func (h *JSONFormatter) Format(e *logrus.Entry) ([]byte, error) { skipOnce := h.skip[int(e.Level)] - skipOnce.Once.Do(func() { - for i := 4; i < 100; i++ { + + if skipOnce.SkipLogrus == 0 { + var skipLogrus OpenClose + + for i := 4; i < 50; i++ { // log.Println(i) - if pc, _, _, ok := runtime.Caller(i); ok { + if pc, file, line, ok := runtime.Caller(i); ok { funcStruct := runtime.FuncForPC(pc) - // log.Println(funcStruct.Name(), file, line) - if !strings.Contains(funcStruct.Name(), "github.com/sirupsen/logrus.") { - skipOnce.Skip++ - if skipOnce.Skip >= 2 { - skipOnce.Skip = i - 3 - break - } - } + log.Println(funcStruct.Name(), file, line) + + skipLogrus.OpenFunc(func() bool { + return strings.Contains(funcStruct.Name(), "github.com/sirupsen/logrus.") + }, func() { + + // skip = i + skipOnce.SkipLogrus = i + i = 10000 + }) + } else { break } } - }) + } + + if skipOnce.SkipBasic == 0 { + var skipBasic OpenClose + for i := 4; i < 50; i++ { + // log.Println(i) + if pc, file, line, ok := runtime.Caller(i); ok { + funcStruct := runtime.FuncForPC(pc) + log.Println(funcStruct.Name(), file, line) + + skipBasic.OpenFunc(func() bool { + return strings.Contains(funcStruct.Name(), "basic.(*Response).") + }, func() { + skipOnce.SkipBasic = i + 1 + }) + } else { + break + } + } + } var fileinfo string - if _, file, line, ok := runtime.Caller(skipOnce.Skip); ok { - if e.Level == logrus.InfoLevel { - fileinfo = fmt.Sprintf("%s:%d", file, line) - } else { - ps := strings.Split(file, "/") - ps = ps[len(ps)-4:] - fileinfo = fmt.Sprintf("%s:%d", strings.Join(ps, "/"), line) + if pc, _, _, ok := runtime.Caller(skipOnce.SkipBasic - 1); ok { + funcStruct := runtime.FuncForPC(pc) + log.Println(funcStruct.Name()) + if strings.Contains(funcStruct.Name(), "basic.(*Response).") { + if _, file, line, ok := runtime.Caller(skipOnce.SkipBasic); ok { + if e.Level == logrus.InfoLevel { + fileinfo = fmt.Sprintf("%s:%d", file, line) + } else { + ps := strings.Split(file, "/") + // ps = ps[len(ps)-4:] + fileinfo = fmt.Sprintf("%s:%d", strings.Join(ps, "/"), line) + } + } } + } + if fileinfo != "" { + if _, file, line, ok := runtime.Caller(skipOnce.SkipLogrus); ok { + if e.Level == logrus.InfoLevel { + fileinfo = fmt.Sprintf("%s:%d", file, line) + } else { + ps := strings.Split(file, "/") + // ps = ps[len(ps)-4:] + fileinfo = fmt.Sprintf("%s:%d", strings.Join(ps, "/"), line) + } + + } } var Data map[string]any = make(map[string]any, 4) diff --git a/utils/log/log.go b/utils/log/log.go index eb29561..b6c91c1 100644 --- a/utils/log/log.go +++ b/utils/log/log.go @@ -37,7 +37,6 @@ func init() { } type SkipHook struct { - autoSkip int Formatter func(*logrus.Hook, *logrus.Entry) error once sync.Once } @@ -46,28 +45,61 @@ func (h *SkipHook) Levels() []logrus.Level { return logrus.AllLevels } +// OpenClose 开闭空间 +type OpenClose struct { + Open bool + Close bool + Skip int +} + +func (oc *OpenClose) OpenFunc(opendo func() bool, closedo func()) { + + if oc.Open && oc.Close { + return + } + + if opendo() { + if !oc.Open { + oc.Open = true + return + } + } else { + if oc.Open && !oc.Close { + oc.Close = true + closedo() + } + } +} + func (h *SkipHook) Fire(e *logrus.Entry) error { - h.once.Do(func() { - for i := 4; i < 100; i++ { - log.Println(i) - if pc, file, line, ok := runtime.Caller(i); ok { - funcStruct := runtime.FuncForPC(pc) - log.Println(funcStruct.Name(), file, line) - if !strings.Contains(funcStruct.Name(), "github.com/sirupsen/logrus.") { - h.autoSkip++ - if h.autoSkip >= 2 { - h.autoSkip = i - 3 - break - } - } - } else { - break - } + + var skipLogrus, skipBasic OpenClose + var skip int + for i := 4; i < 25; i++ { + log.Println(i) + if pc, file, line, ok := runtime.Caller(i); ok { + funcStruct := runtime.FuncForPC(pc) + log.Println(funcStruct.Name(), file, line) + + skipLogrus.OpenFunc(func() bool { + return strings.Contains(funcStruct.Name(), "github.com/sirupsen/logrus.") + }, func() { + skip = i + 1 + + }) + + skipBasic.OpenFunc(func() bool { + return strings.Contains(funcStruct.Name(), "basic.(*Response).") + }, func() { + skip = i + i = 100 + }) } - }) - if _, file, line, ok := runtime.Caller(h.autoSkip); ok { + } + + if _, file, line, ok := runtime.Caller(skip); ok { // funcStruct := runtime.FuncForPC(pc) // log.Println(file, line, funcStruct.Name()) // funcName := funcStruct.Name()