From 5c98a03391d54e87e6f8867237cb05f905cc93d9 Mon Sep 17 00:00:00 2001 From: "daniel.w" Date: Thu, 25 Jul 2024 22:01:22 +0800 Subject: [PATCH] fix: data-statustucs-wallet kafka --- generate/protobuf/member.proto | 2 +- internal/config/config.go | 5 +- internal/domain/const.go | 4 +- internal/lib/error/easy_func.go | 5 +- internal/lib/error/easy_func_test.go | 9 +- internal/lib/error/errors_test.go | 7 +- internal/lib/middleware/with_context.go | 5 +- internal/logic/bind_user_info_logic.go | 72 ++++++++- internal/logic/create_user_account_logic.go | 5 +- internal/logic/generate_refresh_code_logic.go | 104 ++++++++++++- internal/logic/get_uid_by_account_logic.go | 30 +++- internal/logic/get_user_info_logic.go | 37 ++++- internal/logic/list_member_logic.go | 142 +++++++++++++++++- internal/logic/update_status_logic.go | 29 +++- internal/logic/update_user_token_logic.go | 36 ++++- internal/logic/verify_refresh_code_logic.go | 43 +++++- internal/model/account_model.go | 19 +++ internal/model/machine_node_model.go | 1 + internal/model/user_table_model.go | 121 +++++++++++++++ internal/model/user_table_model_gen.go | 10 +- internal/svc/machine_node.go | 3 +- internal/svc/service_context.go | 14 +- 22 files changed, 656 insertions(+), 47 deletions(-) diff --git a/generate/protobuf/member.proto b/generate/protobuf/member.proto index 9e8f18d..df24185 100644 --- a/generate/protobuf/member.proto +++ b/generate/protobuf/member.proto @@ -136,7 +136,7 @@ message VerifyRefreshCodeReq { } message UpdateStatusReq { - string account = 1; + string uid = 1; MemberStatus status = 2; } diff --git a/internal/config/config.go b/internal/config/config.go index c1927ff..25bb788 100755 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -2,6 +2,7 @@ package config import ( "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/redis" "github.com/zeromicro/go-zero/zrpc" ) @@ -11,9 +12,9 @@ type Config struct { DB struct { DsnString string } - Cache cache.CacheConf - + Cache cache.CacheConf Bcrypt struct { Cost int } + RedisCluster redis.RedisConf } diff --git a/internal/domain/const.go b/internal/domain/const.go index c5725b7..b67307b 100644 --- a/internal/domain/const.go +++ b/internal/domain/const.go @@ -1,5 +1,7 @@ package domain const ( - Scope = 10 + DefaultPageSize = 100 + DefaultPageIndex = 0 + Scope = 10 ) diff --git a/internal/lib/error/easy_func.go b/internal/lib/error/easy_func.go index a0f802b..f85d4db 100644 --- a/internal/lib/error/easy_func.go +++ b/internal/lib/error/easy_func.go @@ -3,12 +3,13 @@ package error import ( "errors" "fmt" + "member/internal/lib/error/code" + "strings" + "github.com/zeromicro/go-zero/core/logx" _ "github.com/zeromicro/go-zero/core/logx" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "member/internal/lib/error/code" - "strings" ) func newErr(scope, detail uint32, msg string) *Err { diff --git a/internal/lib/error/easy_func_test.go b/internal/lib/error/easy_func_test.go index f92e680..40571af 100644 --- a/internal/lib/error/easy_func_test.go +++ b/internal/lib/error/easy_func_test.go @@ -4,15 +4,16 @@ import ( "context" "errors" "fmt" + "member/internal/lib/error/code" + "reflect" + "strconv" + "testing" + "github.com/golang/mock/gomock" "github.com/stretchr/testify/assert" "github.com/zeromicro/go-zero/core/logx" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - "member/internal/lib/error/code" - "reflect" - "strconv" - "testing" ) func TestFromGRPCError_GivenStatusWithCodeAndMessage_ShouldReturnErr(t *testing.T) { diff --git a/internal/lib/error/errors_test.go b/internal/lib/error/errors_test.go index 33c1625..a0f5325 100644 --- a/internal/lib/error/errors_test.go +++ b/internal/lib/error/errors_test.go @@ -3,12 +3,13 @@ package error import ( "errors" "fmt" - "github.com/stretchr/testify/assert" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" "member/internal/lib/error/code" "net/http" "testing" + + "github.com/stretchr/testify/assert" + "google.golang.org/grpc/codes" + "google.golang.org/grpc/status" ) func TestCode_GivenNilReceiver_CodeReturnOK_CodeStrReturns00000(t *testing.T) { diff --git a/internal/lib/middleware/with_context.go b/internal/lib/middleware/with_context.go index 65f21b1..66ba484 100644 --- a/internal/lib/middleware/with_context.go +++ b/internal/lib/middleware/with_context.go @@ -3,10 +3,11 @@ package middleware import ( "context" "errors" - "github.com/zeromicro/go-zero/core/logx" - "google.golang.org/grpc" ers "member/internal/lib/error" "time" + + "github.com/zeromicro/go-zero/core/logx" + "google.golang.org/grpc" ) const defaultTimeout = 30 * time.Second diff --git a/internal/logic/bind_user_info_logic.go b/internal/logic/bind_user_info_logic.go index ac5f39d..0b17c16 100644 --- a/internal/logic/bind_user_info_logic.go +++ b/internal/logic/bind_user_info_logic.go @@ -2,6 +2,14 @@ package logic import ( "context" + "errors" + "member/internal/domain" + ers "member/internal/lib/error" + "member/internal/lib/required" + "member/internal/model" + "time" + + "github.com/go-sql-driver/mysql" "member/gen_result/pb/member" "member/internal/svc" @@ -23,9 +31,69 @@ func NewBindUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Bind } } +type createUserInfo struct { + Uid string `validate:"required"` + VerifyType int32 `validate:"required,oneof=0 1 2 3"` + AlarmType int32 `validate:"required,oneof=0 1 2"` + Status int32 `validate:"required,oneof=1 2 3 4 5 6"` + RoleId string `validate:"required"` + Language string `validate:"required"` + Currency string `validate:"required"` + NickName string + Gender int8 + Birthday int64 +} + // BindUserInfo 初次,綁定 User Info func (l *BindUserInfoLogic) BindUserInfo(in *member.CreateUserInfoReq) (*member.Response, error) { - // todo: add your logic here and delete this line + // 驗證資料 + err := required.ValidateAll(l.svcCtx.Validate, &createUserInfo{ + Uid: in.GetUid(), + VerifyType: int32(in.GetVerifyType()), + AlarmType: int32(in.GetAlarmType()), + Status: int32(in.GetStatus()), + RoleId: in.GetRoleId(), + Language: in.GetLanguage(), + Currency: in.GetCurrency(), + NickName: in.GetNickName(), + Gender: int8(in.GetGender()), + Birthday: in.GetBirthday(), + }) + if err != nil { + return nil, ers.InvalidFormat(err.Error()) + } - return &member.Response{}, nil + now := time.Now().UTC().Unix() + _, err = l.svcCtx.UserModel.Insert(l.ctx, &model.UserTable{ + Uid: in.GetUid(), + VerifyType: int64(in.GetVerifyType()), + AlarmType: int64(in.GetAlarmType()), + Status: int64(in.GetStatus()), + RoleId: in.GetRoleId(), + Language: in.GetLanguage(), + Currency: in.GetCurrency(), + NickName: in.GetNickName(), + Gender: int64(in.GetGender()), + Birthday: in.GetBirthday(), + CreateTime: now, + UpdateTime: now, + }) + if err != nil { + // 新增進去 + var mysqlErr *mysql.MySQLError + if errors.As(err, &mysqlErr) && mysqlErr.Number == 1062 { + // 處理重複條目錯誤 + return nil, ers.DBDuplicate(in.GetUid()) + } + + return nil, ers.DBError(err.Error()) + } + + return &member.Response{ + Status: &member.BaseResp{ + Code: domain.CodeOk.ToString(), + Message: "success", + Error: "", + }, + }, nil } diff --git a/internal/logic/create_user_account_logic.go b/internal/logic/create_user_account_logic.go index 0b91070..e192a3f 100644 --- a/internal/logic/create_user_account_logic.go +++ b/internal/logic/create_user_account_logic.go @@ -4,8 +4,6 @@ import ( "context" "errors" "fmt" - "github.com/go-sql-driver/mysql" - "github.com/zeromicro/go-zero/core/logx" "member/gen_result/pb/member" ers "member/internal/lib/error" "member/internal/lib/required" @@ -13,6 +11,9 @@ import ( "member/internal/svc" "member/internal/utils" "time" + + "github.com/go-sql-driver/mysql" + "github.com/zeromicro/go-zero/core/logx" ) type CreateUserAccountLogic struct { diff --git a/internal/logic/generate_refresh_code_logic.go b/internal/logic/generate_refresh_code_logic.go index 2d263a2..aca8001 100644 --- a/internal/logic/generate_refresh_code_logic.go +++ b/internal/logic/generate_refresh_code_logic.go @@ -2,9 +2,15 @@ package logic import ( "context" - + "crypto/rand" + "fmt" + "math/big" "member/gen_result/pb/member" + "member/internal/domain" + ers "member/internal/lib/error" + "member/internal/lib/required" "member/internal/svc" + "strconv" "github.com/zeromicro/go-zero/core/logx" ) @@ -23,9 +29,101 @@ func NewGenerateRefreshCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext } } +type generateRefreshCodeReq struct { + Account string `json:"account" validate:"account"` + // CodeType 1 email 2 phone + CodeType int32 `json:"code_type" validate:"required,oneof=1 2 3"` +} + +var codeMap = map[int32]string{ + 1: "email", + 2: "phone", +} + +func getCodeNameByCode(code int32) (string, bool) { + res, ok := codeMap[code] + if !ok { + return "", false + } + + return res, true +} + +func generateVerifyCode(digits int) (string, error) { + if digits <= 0 { + // 預設為六位數 + digits = 6 + } + + // 計算最大值 (10^digits - 1) + exp := new(big.Int).Exp(big.NewInt(10), big.NewInt(int64(digits)), nil) + // 生成隨機數 + randomNumber, err := rand.Int(rand.Reader, exp) + if err != nil { + return "", err + } + + // 將隨機數轉換為 string + verifyCode := strconv.Itoa(int(randomNumber.Int64())) + // 如果隨機數的位數少於指定的位數,則補 0 + if len(verifyCode) < digits { + verifyCode = fmt.Sprintf("%0*d", digits, randomNumber) + } + + return verifyCode, nil +} + // GenerateRefreshCode 這個帳號驗證碼(十分鐘),通用的 func (l *GenerateRefreshCodeLogic) GenerateRefreshCode(in *member.GenerateRefreshCodeReq) (*member.GenerateRefreshCodeResp, error) { - // todo: add your logic here and delete this line + err := required.ValidateAll(l.svcCtx.Validate, &generateRefreshCodeReq{ + Account: in.GetAccount(), + CodeType: in.GetCodeType(), + }) + if err != nil { + return nil, ers.InvalidFormat(err.Error()) + } - return &member.GenerateRefreshCodeResp{}, nil + checkType, status := getCodeNameByCode(in.GetCodeType()) + if !status { + return nil, ers.InvalidFormat(fmt.Errorf("failed to get correct code type").Error()) + } + rk := fmt.Sprintf("verify:%s:%s", checkType, in.GetAccount()) + // 拿過就不要再拿了 + get, err := l.svcCtx.Redis.Get(rk) + if err != nil { + return nil, ers.DBError("failed to connect to redis", err.Error()) + } + if get != "" { + return &member.GenerateRefreshCodeResp{ + Status: &member.BaseResp{ + Code: domain.CodeOk.ToString(), + Message: "success", + Error: "", + }, + Data: &member.VerifyCode{ + VerifyCode: get, + }, + }, nil + } + + code, err := generateVerifyCode(6) + if !status { + return nil, ers.ArkInternal(err.Error()) + } + + err = l.svcCtx.Redis.Setex(rk, code, 600) + if err != nil { + return nil, ers.ArkInternal(err.Error()) + } + + return &member.GenerateRefreshCodeResp{ + Status: &member.BaseResp{ + Code: domain.CodeOk.ToString(), + Message: "success", + Error: "", + }, + Data: &member.VerifyCode{ + VerifyCode: code, + }, + }, nil } diff --git a/internal/logic/get_uid_by_account_logic.go b/internal/logic/get_uid_by_account_logic.go index 68eab23..8a3b70a 100644 --- a/internal/logic/get_uid_by_account_logic.go +++ b/internal/logic/get_uid_by_account_logic.go @@ -2,6 +2,9 @@ package logic import ( "context" + "member/internal/domain" + ers "member/internal/lib/error" + "member/internal/lib/required" "member/gen_result/pb/member" "member/internal/svc" @@ -23,9 +26,32 @@ func NewGetUidByAccountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *G } } +type getUidByAccountReq struct { + Account string `json:"account" validate:"account"` +} + // GetUidByAccount 用帳號換取 UID func (l *GetUidByAccountLogic) GetUidByAccount(in *member.GetUIDByAccountReq) (*member.GetUidByAccountResp, error) { - // todo: add your logic here and delete this line + err := required.ValidateAll(l.svcCtx.Validate, &getUidByAccountReq{ + Account: in.GetAccount(), + }) + if err != nil { + return nil, ers.InvalidFormat(err.Error()) + } - return &member.GetUidByAccountResp{}, nil + account, err := l.svcCtx.AccountToUidModel.FindOneByAccount(l.ctx, in.GetAccount()) + if err != nil { + return nil, err + } + + return &member.GetUidByAccountResp{ + Status: &member.BaseResp{ + Code: domain.CodeOk.ToString(), + Message: "success", + Error: "", + }, + Data: &member.UID{ + Uid: account.Uid, + }, + }, nil } diff --git a/internal/logic/get_user_info_logic.go b/internal/logic/get_user_info_logic.go index 0f56cfc..09c9d1b 100644 --- a/internal/logic/get_user_info_logic.go +++ b/internal/logic/get_user_info_logic.go @@ -2,8 +2,9 @@ package logic import ( "context" - "member/gen_result/pb/member" + ers "member/internal/lib/error" + "member/internal/model" "member/internal/svc" "github.com/zeromicro/go-zero/core/logx" @@ -23,9 +24,33 @@ func NewGetUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUs } } -// UpdateStatus 取得會員資訊 -func (l *GetUserInfoLogic) GetUserInfo(in *member.GetUserInfoReq) (*member.GetUserInfoResp, error) { - // todo: add your logic here and delete this line - - return &member.GetUserInfoResp{}, nil +type getUserInfoReq struct { + Uid string `json:"account" validate:"account"` +} + +// GetUserInfo 取得會員資訊 +func (l *GetUserInfoLogic) GetUserInfo(in *member.GetUserInfoReq) (*member.GetUserInfoResp, error) { + var entity *model.UserTable + var err error + + if in.GetUid() != "" { + entity, err = l.svcCtx.UserModel.FindOneByUid(l.ctx, in.GetUid()) + if err != nil { + return nil, ers.DBError(err.Error()) + } + } else { + if in.GetNickName() != "" { + entity, err = l.svcCtx.UserModel.FindOneByNickName(l.ctx, in.GetNickName()) + if err != nil { + return nil, ers.DBError(err.Error()) + } + + } + } + + if entity != nil { + return &member.GetUserInfoResp{}, nil + } + + return nil, ers.ResourceNotFound("filed to get user info") } diff --git a/internal/logic/list_member_logic.go b/internal/logic/list_member_logic.go index 9cf98c3..5a0902b 100644 --- a/internal/logic/list_member_logic.go +++ b/internal/logic/list_member_logic.go @@ -2,9 +2,13 @@ package logic import ( "context" - + "fmt" "member/gen_result/pb/member" + "member/internal/domain" + ers "member/internal/lib/error" + "member/internal/model" "member/internal/svc" + "strconv" "github.com/zeromicro/go-zero/core/logx" ) @@ -23,9 +27,141 @@ func NewListMemberLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ListMe } } +func parse(in *member.ListUserInfoReq) (model.UserQueryParams, error) { + var filter model.UserQueryParams + + // 設置 PageSize + filter.PageSize = getValidPageSize(in.PageSize) + + // 設置 PageIndex + filter.PageIndex = getValidPageIndex(in.PageIndex) + + // 設置 RoleId + if in.RoleId != nil { + filter.RoleId = in.RoleId + } + + // 設置 VerifyType + svt := fmt.Sprintf("%d", in.GetVerifyType().Number()) + vt, err := getInt32FromStringPointer(&svt) + if err != nil { + return model.UserQueryParams{}, err + } + if vt != nil { + filter.VerifyType = vt + } + + // 設置 AlarmType + sat := fmt.Sprintf("%d", in.GetAlarmType().Number()) + at, err := getInt32FromStringPointer(&sat) + if err != nil { + return model.UserQueryParams{}, err + } + + if at != nil { + filter.AlarmType = at + } + + // 設置 Status + sst := fmt.Sprintf("%d", in.GetStatus().Number()) + st, err := getInt32FromStringPointer(&sst) + if err != nil { + return model.UserQueryParams{}, err + } + if st != nil { + filter.Status = st + } + + // 設置 CreateStartTime + if in.CreateStartTime != nil { + ct := in.GetCreateStartTime() + filter.CreateStartTime = &ct + } + + // 設置 CreateEndTime + if in.CreateEndTime != nil { + et := in.GetCreateEndTime() + filter.CreateEndTime = &et + } + + return filter, nil +} + +func getValidPageSize(pageSize int64) int64 { + if pageSize <= 0 { + return domain.DefaultPageSize + } + return pageSize +} + +func getValidPageIndex(pageIndex int64) int64 { + if pageIndex <= 0 { + return domain.DefaultPageIndex + } + return pageIndex +} + +func getInt32FromStringPointer(strPtr *string) (*int32, error) { + if strPtr == nil { + return nil, nil + } + value, err := strconv.Atoi(*strPtr) + if err != nil { + return nil, err + } + int32Value := int32(value) + if int32Value == 0 { + return nil, nil + } + return &int32Value, nil +} + // ListMember 取得會員列表 func (l *ListMemberLogic) ListMember(in *member.ListUserInfoReq) (*member.ListUserInfoResp, error) { - // todo: add your logic here and delete this line + params, err := parse(in) + if err != nil { + return nil, ers.InvalidFormat("failed to get correct param", err.Error()) + } - return &member.ListUserInfoResp{}, nil + members, err := l.svcCtx.UserModel.ListMembers(l.ctx, ¶ms) + if err != nil { + return nil, ers.DBError(err.Error()) + } + + count, err := l.svcCtx.UserModel.Count(l.ctx) + if err != nil { + return nil, ers.DBError(err.Error()) + } + + var data = make([]*member.UserInfo, 0, len(members)) + + for _, item := range members { + g := uint32(item.Gender) + data = append(data, &member.UserInfo{ + Uid: item.Uid, + VerifyType: member.VerifyType(item.VerifyType), + AlarmType: member.AlarmType(item.AlarmType), + Status: member.MemberStatus(item.Status), + RoleId: item.RoleId, + Language: item.Language, + Currency: item.Currency, + NickName: &item.NickName, + Gender: &g, + Birthday: &item.Birthday, + }) + } + + return &member.ListUserInfoResp{ + Status: &member.BaseResp{ + Code: domain.CodeOk.ToString(), + Message: "success", + Error: "", + }, + Data: data, + Page: &member.Pager{ + Total: count, + Size: in.PageSize, + Index: in.PageIndex, + }, + }, nil } diff --git a/internal/logic/update_status_logic.go b/internal/logic/update_status_logic.go index c71d5c2..34dace0 100644 --- a/internal/logic/update_status_logic.go +++ b/internal/logic/update_status_logic.go @@ -2,6 +2,9 @@ package logic import ( "context" + "member/internal/domain" + ers "member/internal/lib/error" + "member/internal/lib/required" "member/gen_result/pb/member" "member/internal/svc" @@ -23,9 +26,31 @@ func NewUpdateStatusLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Upda } } +type updateStatusReq struct { + UID string `json:"uid" validate:"required"` + Status int32 `json:"status" validate:"required,oneof=1 2 3 4 5 6"` +} + // UpdateStatus 修改狀態 func (l *UpdateStatusLogic) UpdateStatus(in *member.UpdateStatusReq) (*member.Response, error) { - // todo: add your logic here and delete this line + err := required.ValidateAll(l.svcCtx.Validate, &updateStatusReq{ + UID: in.GetUid(), + Status: int32(in.GetStatus()), + }) + if err != nil { + return nil, ers.InvalidFormat(err.Error()) + } - return &member.Response{}, nil + err = l.svcCtx.UserModel.UpdateStatus(l.ctx, in.GetUid(), int32(in.GetStatus())) + if err != nil { + return nil, ers.DBError(err.Error()) + } + + return &member.Response{ + Status: &member.BaseResp{ + Code: domain.CodeOk.ToString(), + Message: "success", + Error: "", + }, + }, nil } diff --git a/internal/logic/update_user_token_logic.go b/internal/logic/update_user_token_logic.go index d6c6635..8d018f9 100644 --- a/internal/logic/update_user_token_logic.go +++ b/internal/logic/update_user_token_logic.go @@ -2,6 +2,11 @@ package logic import ( "context" + "fmt" + "member/internal/domain" + ers "member/internal/lib/error" + "member/internal/lib/required" + "member/internal/utils" "member/gen_result/pb/member" "member/internal/svc" @@ -23,9 +28,36 @@ func NewUpdateUserTokenLogic(ctx context.Context, svcCtx *svc.ServiceContext) *U } } +type updateUserTokenReq struct { + LoginId string `json:"login_id" validate:"account"` + Token string `json:"token" validate:"required"` +} + // UpdateUserToken 更新密碼 func (l *UpdateUserTokenLogic) UpdateUserToken(in *member.UpdateTokenReq) (*member.Response, error) { - // todo: add your logic here and delete this line + err := required.ValidateAll(l.svcCtx.Validate, &updateUserTokenReq{ + LoginId: in.GetAccount(), + Token: in.GetToken(), + }) + if err != nil { + return nil, ers.InvalidFormat(err.Error()) + } - return &member.Response{}, nil + token, err := utils.HashPassword(in.GetToken(), l.svcCtx.Config.Bcrypt.Cost) + if err != nil { + return nil, ers.ArkInternal(fmt.Sprintf("failed to encrypt err: %v", err.Error())) + } + + err = l.svcCtx.AccountModel.UpdateTokenByLoginID(l.ctx, in.GetAccount(), token) + if err != nil { + return nil, ers.DBError(err.Error()) + } + + return &member.Response{ + Status: &member.BaseResp{ + Code: domain.CodeOk.ToString(), + Message: "success", + Error: "", + }, + }, nil } diff --git a/internal/logic/verify_refresh_code_logic.go b/internal/logic/verify_refresh_code_logic.go index a316a82..e227e34 100644 --- a/internal/logic/verify_refresh_code_logic.go +++ b/internal/logic/verify_refresh_code_logic.go @@ -2,6 +2,10 @@ package logic import ( "context" + "fmt" + "member/internal/domain" + ers "member/internal/lib/error" + "member/internal/lib/required" "member/gen_result/pb/member" "member/internal/svc" @@ -25,7 +29,42 @@ func NewVerifyRefreshCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext) // VerifyRefreshCode 驗證忘記密碼 token func (l *VerifyRefreshCodeLogic) VerifyRefreshCode(in *member.VerifyRefreshCodeReq) (*member.Response, error) { - // todo: add your logic here and delete this line + err := required.ValidateAll(l.svcCtx.Validate, &generateRefreshCodeReq{ + Account: in.GetAccount(), + CodeType: in.GetCodeType(), + }) + if err != nil { + return nil, ers.InvalidFormat(err.Error()) + } - return &member.Response{}, nil + checkType, status := getCodeNameByCode(in.GetCodeType()) + if !status { + return nil, ers.InvalidFormat(fmt.Errorf("failed to get correct code type").Error()) + } + rk := fmt.Sprintf("verify:%s:%s", checkType, in.GetAccount()) + get, err := l.svcCtx.Redis.Get(rk) + if err != nil { + return nil, ers.DBError("failed to connect to redis", err.Error()) + } + + if get == "" { + return nil, ers.DBError("failed to get data from redis") + } + + if get != fmt.Sprintf("%d", in.CodeType) { + return nil, ers.ArkInternal("Illegible Verify Code") + } + + _, err = l.svcCtx.Redis.Del(rk) + if err != nil { + return nil, ers.DBError("failed to del redis key", rk) + } + + return &member.Response{ + Status: &member.BaseResp{ + Code: domain.CodeOk.ToString(), + Message: "success", + Error: "", + }, + }, nil } diff --git a/internal/model/account_model.go b/internal/model/account_model.go index 958d6dc..85aebb8 100755 --- a/internal/model/account_model.go +++ b/internal/model/account_model.go @@ -1,6 +1,9 @@ package model import ( + "context" + "database/sql" + "fmt" "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/sqlx" ) @@ -12,6 +15,7 @@ type ( // and implement the added methods in customAccountModel. AccountModel interface { accountModel + UpdateTokenByLoginID(ctx context.Context, account string, token string) error } customAccountModel struct { @@ -19,6 +23,21 @@ type ( } ) +func (m *defaultAccountModel) UpdateTokenByLoginID(ctx context.Context, account string, token string) error { + data, err := m.FindOneByAccount(ctx, account) + if err != nil { + return err + } + + accountAccountKey := fmt.Sprintf("%s%v", cacheAccountAccountPrefix, data.Account) + accountIdKey := fmt.Sprintf("%s%v", cacheAccountIdPrefix, data.Id) + _, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("update %s set `token` = ? where `id` = ?", m.table, accountRowsWithPlaceHolder) + return conn.ExecCtx(ctx, query, token, data.Id) + }, accountAccountKey, accountIdKey) + return err +} + // NewAccountModel returns a model for the database table. func NewAccountModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) AccountModel { return &customAccountModel{ diff --git a/internal/model/machine_node_model.go b/internal/model/machine_node_model.go index 86b044e..5336676 100755 --- a/internal/model/machine_node_model.go +++ b/internal/model/machine_node_model.go @@ -3,6 +3,7 @@ package model import ( "context" "fmt" + "github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/sqlc" "github.com/zeromicro/go-zero/core/stores/sqlx" diff --git a/internal/model/user_table_model.go b/internal/model/user_table_model.go index 13f2b1d..fd80b2a 100755 --- a/internal/model/user_table_model.go +++ b/internal/model/user_table_model.go @@ -1,8 +1,13 @@ package model import ( + "context" + "database/sql" + "fmt" "github.com/zeromicro/go-zero/core/stores/cache" + "github.com/zeromicro/go-zero/core/stores/sqlc" "github.com/zeromicro/go-zero/core/stores/sqlx" + "strings" ) var _ UserTableModel = (*customUserTableModel)(nil) @@ -12,11 +17,26 @@ type ( // and implement the added methods in customUserTableModel. UserTableModel interface { userTableModel + FindOneByNickName(ctx context.Context, uid string) (*UserTable, error) + ListMembers(ctx context.Context, params *UserQueryParams) ([]*UserTable, error) + Count(ctx context.Context) (int64, error) + UpdateStatus(ctx context.Context, uid string, status int32) error } customUserTableModel struct { *defaultUserTableModel } + + UserQueryParams struct { + RoleId *string + VerifyType *int32 + AlarmType *int32 + Status *int32 + CreateStartTime *int64 + CreateEndTime *int64 + PageSize int64 + PageIndex int64 + } ) // NewUserTableModel returns a model for the database table. @@ -25,3 +45,104 @@ func NewUserTableModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Optio defaultUserTableModel: newUserTableModel(conn, c, opts...), } } + +func (m *defaultUserTableModel) FindOneByNickName(ctx context.Context, nickName string) (*UserTable, error) { + userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, nickName) + var resp UserTable + err := m.QueryRowIndexCtx(ctx, &resp, userTableUidKey, m.formatPrimary, func(ctx context.Context, conn sqlx.SqlConn, v any) (i any, e error) { + query := fmt.Sprintf("select %s from %s where `nick_name` = ? limit 1", userTableRows, m.table) + if err := conn.QueryRowCtx(ctx, &resp, query, nickName); err != nil { + return nil, err + } + return resp.Id, nil + }, m.queryPrimary) + switch err { + case nil: + return &resp, nil + case sqlc.ErrNotFound: + return nil, ErrNotFound + default: + return nil, err + } +} + +func (m *defaultUserTableModel) ListMembers(ctx context.Context, params *UserQueryParams) ([]*UserTable, error) { + query := fmt.Sprintf("select %s from %s", userTableRows, m.table) + var args = make([]any, 0, 10) + var conditions []string + + if params.RoleId != nil { + conditions = append(conditions, "role_id = ?") + args = append(args, *params.RoleId) + } + + if params.VerifyType != nil { + conditions = append(conditions, "verify_type = ?") + args = append(args, *params.VerifyType) + } + + if params.AlarmType != nil { + conditions = append(conditions, "alarm_type = ?") + args = append(args, *params.AlarmType) + } + + if params.Status != nil { + conditions = append(conditions, "status = ?") + args = append(args, *params.Status) + } + + if params.CreateStartTime != nil { + conditions = append(conditions, "create_time >= ?") + args = append(args, *params.CreateStartTime) + } + + if params.CreateEndTime != nil { + conditions = append(conditions, "create_time <= ?") + args = append(args, *params.CreateEndTime) + } + + // 加入條件到查詢語句中 + if len(conditions) > 0 { + query += " WHERE " + strings.Join(conditions, " AND ") + } + + // 分頁處理 + offset := (params.PageIndex - 1) * params.PageSize + query += " LIMIT ? OFFSET ?" + args = append(args, params.PageSize, offset) + + var users []*UserTable + fmt.Println("query:", query) + fmt.Println("args:", args) + err := m.QueryRowsNoCacheCtx(ctx, &users, query, args...) + if err != nil { + return nil, err + } + + return users, nil +} + +func (m *defaultUserTableModel) Count(ctx context.Context) (int64, error) { + var count int64 + query := fmt.Sprintf("select count(*) from %s", m.table) + err := m.QueryRowNoCacheCtx(ctx, &count, query) + if err != nil { + return 0, err + } + return count, nil +} + +func (m *defaultUserTableModel) UpdateStatus(ctx context.Context, uid string, status int32) error { + data, err := m.FindOneByUid(ctx, uid) + if err != nil { + return err + } + + userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, data.Id) + userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid) + _, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { + query := fmt.Sprintf("update %s set `status` = ? where `id` = ?", m.table) + return conn.ExecCtx(ctx, query, status, data.Id) + }, userTableIdKey, userTableUidKey) + return err +} diff --git a/internal/model/user_table_model_gen.go b/internal/model/user_table_model_gen.go index 7ee1f9b..653b28d 100755 --- a/internal/model/user_table_model_gen.go +++ b/internal/model/user_table_model_gen.go @@ -18,8 +18,8 @@ import ( var ( userTableFieldNames = builder.RawFieldNames(&UserTable{}) userTableRows = strings.Join(userTableFieldNames, ",") - userTableRowsExpectAutoSet = strings.Join(stringx.Remove(userTableFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), ",") - userTableRowsWithPlaceHolder = strings.Join(stringx.Remove(userTableFieldNames, "`id`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?" + userTableRowsExpectAutoSet = strings.Join(stringx.Remove(userTableFieldNames, "`id`"), ",") + userTableRowsWithPlaceHolder = strings.Join(stringx.Remove(userTableFieldNames, "`id`"), "=?,") + "=?" cacheUserTableIdPrefix = "cache:userTable:id:" cacheUserTableUidPrefix = "cache:userTable:uid:" @@ -126,8 +126,8 @@ func (m *defaultUserTableModel) Insert(ctx context.Context, data *UserTable) (sq userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, data.Id) userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid) ret, err := m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { - query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, userTableRowsExpectAutoSet) - return conn.ExecCtx(ctx, query, data.VerifyType, data.AlarmType, data.Status, data.Uid, data.RoleId, data.Language, data.Currency, data.NickName, data.Gender, data.Birthday) + query := fmt.Sprintf("insert into %s (%s) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", m.table, userTableRowsExpectAutoSet) + return conn.ExecCtx(ctx, query, data.VerifyType, data.AlarmType, data.Status, data.Uid, data.RoleId, data.Language, data.Currency, data.NickName, data.Gender, data.Birthday, data.CreateTime, data.UpdateTime) }, userTableIdKey, userTableUidKey) return ret, err } @@ -142,7 +142,7 @@ func (m *defaultUserTableModel) Update(ctx context.Context, newData *UserTable) userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid) _, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { query := fmt.Sprintf("update %s set %s where `id` = ?", m.table, userTableRowsWithPlaceHolder) - return conn.ExecCtx(ctx, query, newData.VerifyType, newData.AlarmType, newData.Status, newData.Uid, newData.RoleId, newData.Language, newData.Currency, newData.NickName, newData.Gender, newData.Birthday, newData.Id) + return conn.ExecCtx(ctx, query, newData.VerifyType, newData.AlarmType, newData.Status, newData.Uid, newData.RoleId, newData.Language, newData.Currency, newData.NickName, newData.Gender, newData.Birthday, newData.CreateTime, newData.UpdateTime, newData.Id) }, userTableIdKey, userTableUidKey) return err } diff --git a/internal/svc/machine_node.go b/internal/svc/machine_node.go index a044bd7..0520dba 100644 --- a/internal/svc/machine_node.go +++ b/internal/svc/machine_node.go @@ -2,11 +2,12 @@ package svc import ( "context" - "github.com/bwmarrin/snowflake" sf "member/internal/lib/snackflow" "member/internal/model" "os" "time" + + "github.com/bwmarrin/snowflake" ) type machineNode struct { diff --git a/internal/svc/service_context.go b/internal/svc/service_context.go index db92094..393ad9a 100644 --- a/internal/svc/service_context.go +++ b/internal/svc/service_context.go @@ -1,20 +1,24 @@ package svc import ( - "github.com/bwmarrin/snowflake" + "github.com/zeromicro/go-zero/core/stores/redis" "member/internal/config" "member/internal/domain" "member/internal/lib/required" "member/internal/model" + "github.com/bwmarrin/snowflake" + + ers "member/internal/lib/error" + "github.com/go-playground/validator/v10" "github.com/zeromicro/go-zero/core/stores/sqlx" - ers "member/internal/lib/error" ) type ServiceContext struct { Config config.Config + Redis redis.Redis Validate *validator.Validate AccountModel model.AccountModel UserModel model.UserTableModel @@ -32,8 +36,14 @@ func NewServiceContext(c config.Config) *ServiceContext { panic(err) } + newRedis, err := redis.NewRedis(c.RedisCluster, redis.Cluster()) + if err != nil { + panic(err) + } + return &ServiceContext{ Config: c, + Redis: *newRedis, Validate: required.MustValidator(required.WithAccount("account")), UserModel: model.NewUserTableModel(sqlConn, c.Cache), AccountToUidModel: model.NewAccountToUidModel(sqlConn, c.Cache),