feat/member (#1)

建立 Member 基礎功能
接下來要做的事情還有
1.  golint
2. 寫單元測試
3. 寫 readme
4. 撰寫產生mock 的指令
5. 撰寫build 指令

Co-authored-by: daniel.w <daniel.w@intteam.net>
Reviewed-on: Wanderland/ark-member#1
This commit is contained in:
王性驊 2024-08-02 02:20:15 +00:00
parent 0bbe2ace83
commit 6d3c8fbc63
45 changed files with 2552 additions and 130 deletions

View File

@ -95,6 +95,8 @@ message UpdateUserInfoReq {
optional int64 birthday = 6; optional int64 birthday = 6;
optional VerifyType verify_type = 7; optional VerifyType verify_type = 7;
optional AlarmType alarm_type = 8; optional AlarmType alarm_type = 8;
optional string role_id = 9;
optional MemberStatus status = 10;
} }
message GetUIDByAccountReq { message GetUIDByAccountReq {
@ -136,7 +138,7 @@ message VerifyRefreshCodeReq {
} }
message UpdateStatusReq { message UpdateStatusReq {
string account = 1; string uid = 1;
MemberStatus status = 2; MemberStatus status = 2;
} }

4
go.mod
View File

@ -3,6 +3,7 @@ module member
go 1.22.3 go 1.22.3
require ( require (
github.com/alicebob/miniredis/v2 v2.33.0
github.com/bwmarrin/snowflake v0.3.0 github.com/bwmarrin/snowflake v0.3.0
github.com/go-playground/validator/v10 v10.22.0 github.com/go-playground/validator/v10 v10.22.0
github.com/go-sql-driver/mysql v1.8.1 github.com/go-sql-driver/mysql v1.8.1
@ -10,6 +11,7 @@ require (
github.com/stretchr/testify v1.9.0 github.com/stretchr/testify v1.9.0
github.com/zeromicro/go-zero v1.6.6 github.com/zeromicro/go-zero v1.6.6
go.uber.org/goleak v1.2.1 go.uber.org/goleak v1.2.1
go.uber.org/mock v0.4.0
golang.org/x/crypto v0.24.0 golang.org/x/crypto v0.24.0
google.golang.org/grpc v1.65.0 google.golang.org/grpc v1.65.0
google.golang.org/protobuf v1.34.2 google.golang.org/protobuf v1.34.2
@ -17,6 +19,7 @@ require (
require ( require (
filippo.io/edwards25519 v1.1.0 // indirect filippo.io/edwards25519 v1.1.0 // indirect
github.com/alicebob/gopher-json v0.0.0-20230218143504-906a9b012302 // indirect
github.com/beorn7/perks v1.0.1 // indirect github.com/beorn7/perks v1.0.1 // indirect
github.com/cenkalti/backoff/v4 v4.2.1 // indirect github.com/cenkalti/backoff/v4 v4.2.1 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect github.com/cespare/xxhash/v2 v2.3.0 // indirect
@ -60,6 +63,7 @@ require (
github.com/prometheus/procfs v0.12.0 // indirect github.com/prometheus/procfs v0.12.0 // indirect
github.com/redis/go-redis/v9 v9.5.3 // indirect github.com/redis/go-redis/v9 v9.5.3 // indirect
github.com/spaolacci/murmur3 v1.1.0 // indirect github.com/spaolacci/murmur3 v1.1.0 // indirect
github.com/yuin/gopher-lua v1.1.1 // indirect
go.etcd.io/etcd/api/v3 v3.5.14 // indirect go.etcd.io/etcd/api/v3 v3.5.14 // indirect
go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect go.etcd.io/etcd/client/pkg/v3 v3.5.14 // indirect
go.etcd.io/etcd/client/v3 v3.5.14 // indirect go.etcd.io/etcd/client/v3 v3.5.14 // indirect

View File

@ -2,6 +2,7 @@ package config
import ( import (
"github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/zrpc" "github.com/zeromicro/go-zero/zrpc"
) )
@ -12,8 +13,8 @@ type Config struct {
DsnString string DsnString string
} }
Cache cache.CacheConf Cache cache.CacheConf
Bcrypt struct { Bcrypt struct {
Cost int Cost int
} }
RedisCluster redis.RedisConf
} }

View File

@ -1,5 +1,7 @@
package domain package domain
const ( const (
DefaultPageSize = 100
DefaultPageIndex = 0
Scope = 10 Scope = 10
) )

View File

@ -3,12 +3,13 @@ package error
import ( import (
"errors" "errors"
"fmt" "fmt"
"member/internal/lib/error/code"
"strings"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
_ "github.com/zeromicro/go-zero/core/logx" _ "github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"member/internal/lib/error/code"
"strings"
) )
func newErr(scope, detail uint32, msg string) *Err { func newErr(scope, detail uint32, msg string) *Err {

View File

@ -4,15 +4,16 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"member/internal/lib/error/code"
"reflect"
"strconv"
"testing"
"github.com/golang/mock/gomock" "github.com/golang/mock/gomock"
"github.com/stretchr/testify/assert" "github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc/codes" "google.golang.org/grpc/codes"
"google.golang.org/grpc/status" "google.golang.org/grpc/status"
"member/internal/lib/error/code"
"reflect"
"strconv"
"testing"
) )
func TestFromGRPCError_GivenStatusWithCodeAndMessage_ShouldReturnErr(t *testing.T) { func TestFromGRPCError_GivenStatusWithCodeAndMessage_ShouldReturnErr(t *testing.T) {
@ -398,7 +399,7 @@ func TestXBCInternal_WithStrings_ShouldHasCatResource_DetailCodeXBCInternal(t *t
}() }()
// act // act
e := XBCInternal("field A", "Error description") e := ArkInternal("field A", "Error description")
// assert // assert
assert.Equal(t, code.CatArk, e.Category()) assert.Equal(t, code.CatArk, e.Category())
@ -816,7 +817,10 @@ func TestStructErr_WithInternalErr_ShouldIsFuncReportCorrectly(t *testing.T) {
// act with error chain: InvalidFormat -> layer 2 err -> layer 1 err // act with error chain: InvalidFormat -> layer 2 err -> layer 1 err
e := InvalidFormat("field A", "Error description") e := InvalidFormat("field A", "Error description")
e.Wrap(layer2Err) err := e.Wrap(layer2Err)
if err != nil {
t.Fatalf("Failed to wrap error: %v", err)
}
// assert // assert
assert.Equal(t, code.CatInput, e.Category()) assert.Equal(t, code.CatInput, e.Category())
@ -839,7 +843,10 @@ func TestStructErr_WithInternalErr_ShouldErrorOutputChainErrMessage(t *testing.T
layer1Err := fmt.Errorf("layer 1 error") layer1Err := fmt.Errorf("layer 1 error")
// act with error chain: InvalidFormat -> layer 1 err // act with error chain: InvalidFormat -> layer 1 err
e := InvalidFormat("field A", "Error description") e := InvalidFormat("field A", "Error description")
e.Wrap(layer1Err) err := e.Wrap(layer1Err)
if err != nil {
t.Fatalf("Failed to wrap error: %v", err)
}
// assert // assert
assert.Equal(t, "invalid format: field A Error description: layer 1 error", e.Error()) assert.Equal(t, "invalid format: field A Error description: layer 1 error", e.Error())
@ -864,7 +871,10 @@ func TestStructErr_WithInternalErr_ShouldAsFuncReportCorrectly(t *testing.T) {
// act with error chain: InvalidFormat -> layer 2 err -> testErr // act with error chain: InvalidFormat -> layer 2 err -> testErr
e := InvalidFormat("field A", "Error description") e := InvalidFormat("field A", "Error description")
e.Wrap(layer2Err) err := e.Wrap(layer2Err)
if err != nil {
t.Fatalf("Failed to wrap error: %v", err)
}
// assert // assert
assert.Equal(t, code.CatInput, e.Category()) assert.Equal(t, code.CatInput, e.Category())
@ -905,7 +915,10 @@ func Benchmark_ErrorsIs_TwoLayerError(b *testing.B) {
// act with error chain: InvalidFormat(layer 2) -> testErr(layer 1) // act with error chain: InvalidFormat(layer 2) -> testErr(layer 1)
layer2Err := InvalidFormat("field A", "Error description") layer2Err := InvalidFormat("field A", "Error description")
layer2Err.Wrap(layer1Err) err := layer2Err.Wrap(layer1Err)
if err != nil {
b.Fatalf("Failed to wrap error: %v", err)
}
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
@ -920,7 +933,10 @@ func Benchmark_ErrorsIs_FourLayerError(b *testing.B) {
layer3Err := fmt.Errorf("layer 3: %w", layer2Err) layer3Err := fmt.Errorf("layer 3: %w", layer2Err)
// act with error chain: InvalidFormat(layer 4) -> Error(layer 3) -> Error(layer 2) -> testErr(layer 1) // act with error chain: InvalidFormat(layer 4) -> Error(layer 3) -> Error(layer 2) -> testErr(layer 1)
layer4Err := InvalidFormat("field A", "Error description") layer4Err := InvalidFormat("field A", "Error description")
layer4Err.Wrap(layer3Err) err := layer4Err.Wrap(layer3Err)
if err != nil {
b.Fatalf("Failed to wrap error: %v", err)
}
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
@ -946,7 +962,10 @@ func Benchmark_ErrorsAs_TwoLayerError(b *testing.B) {
// act with error chain: InvalidFormat(layer 2) -> testErr(layer 1) // act with error chain: InvalidFormat(layer 2) -> testErr(layer 1)
layer2Err := InvalidFormat("field A", "Error description") layer2Err := InvalidFormat("field A", "Error description")
layer2Err.Wrap(layer1Err) err := layer2Err.Wrap(layer1Err)
if err != nil {
b.Fatalf("Failed to wrap error: %v", err)
}
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()
@ -962,7 +981,10 @@ func Benchmark_ErrorsAs_FourLayerError(b *testing.B) {
layer3Err := fmt.Errorf("layer 3: %w", layer2Err) layer3Err := fmt.Errorf("layer 3: %w", layer2Err)
// act with error chain: InvalidFormat(layer 4) -> Error(layer 3) -> Error(layer 2) -> testErr(layer 1) // act with error chain: InvalidFormat(layer 4) -> Error(layer 3) -> Error(layer 2) -> testErr(layer 1)
layer4Err := InvalidFormat("field A", "Error description") layer4Err := InvalidFormat("field A", "Error description")
layer4Err.Wrap(layer3Err) err := layer4Err.Wrap(layer3Err)
if err != nil {
b.Fatalf("Failed to wrap error: %v", err)
}
b.ReportAllocs() b.ReportAllocs()
b.ResetTimer() b.ResetTimer()

View File

@ -3,12 +3,13 @@ package error
import ( import (
"errors" "errors"
"fmt" "fmt"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"member/internal/lib/error/code" "member/internal/lib/error/code"
"net/http" "net/http"
"testing" "testing"
"github.com/stretchr/testify/assert"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
) )
func TestCode_GivenNilReceiver_CodeReturnOK_CodeStrReturns00000(t *testing.T) { func TestCode_GivenNilReceiver_CodeReturnOK_CodeStrReturns00000(t *testing.T) {

View File

@ -3,10 +3,11 @@ package middleware
import ( import (
"context" "context"
"errors" "errors"
"github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc"
ers "member/internal/lib/error" ers "member/internal/lib/error"
"time" "time"
"github.com/zeromicro/go-zero/core/logx"
"google.golang.org/grpc"
) )
const defaultTimeout = 30 * time.Second const defaultTimeout = 30 * time.Second

View File

@ -1,10 +1,25 @@
package required package required
import "github.com/go-playground/validator/v10" import (
"fmt"
"github.com/zeromicro/go-zero/core/logx"
"github.com/go-playground/validator/v10"
)
type Validate interface {
ValidateAll(obj any) error
BindToValidator(opts ...Option) error
}
type Validator struct {
V *validator.Validate
}
// ValidateAll TODO 要移到common 包 // ValidateAll TODO 要移到common 包
func ValidateAll(validate *validator.Validate, obj any) error { func (v *Validator) ValidateAll(obj any) error {
err := validate.Struct(obj) err := v.V.Struct(obj)
if err != nil { if err != nil {
return err return err
} }
@ -12,12 +27,24 @@ func ValidateAll(validate *validator.Validate, obj any) error {
return nil return nil
} }
func MustValidator(option ...Option) *validator.Validate { func (v *Validator) BindToValidator(opts ...Option) error {
// TODO Validator 要抽出來 for _, item := range opts {
v := validator.New() err := v.V.RegisterValidation(item.ValidatorName, item.ValidatorFunc)
err := BindToValidator(v, option...)
if err != nil { if err != nil {
// log return fmt.Errorf("failed to register validator : %w", err)
}
}
return nil
}
func MustValidator(option ...Option) Validate {
v := &Validator{
V: validator.New(),
}
if err := v.BindToValidator(option...); err != nil {
logx.Error("failed to bind validator")
} }
return v return v

View File

@ -1,7 +1,6 @@
package required package required
import ( import (
"fmt"
"regexp" "regexp"
"github.com/go-playground/validator/v10" "github.com/go-playground/validator/v10"
@ -12,17 +11,6 @@ type Option struct {
ValidatorFunc func(fl validator.FieldLevel) bool ValidatorFunc func(fl validator.FieldLevel) bool
} }
func BindToValidator(v *validator.Validate, opts ...Option) error {
for _, item := range opts {
err := v.RegisterValidation(item.ValidatorName, item.ValidatorFunc)
if err != nil {
return fmt.Errorf("failed to register validator : %w", err)
}
}
return nil
}
// WithAccount 創建一個新的 Option 結構,包含自定義的驗證函數,用於驗證 email 和台灣的手機號碼格式 // WithAccount 創建一個新的 Option 結構,包含自定義的驗證函數,用於驗證 email 和台灣的手機號碼格式
func WithAccount(tagName string) Option { func WithAccount(tagName string) Option {
return Option{ return Option{

View File

@ -5,7 +5,6 @@ import (
"fmt" "fmt"
"member/internal/domain" "member/internal/domain"
ers "member/internal/lib/error" ers "member/internal/lib/error"
"member/internal/lib/required"
"member/internal/model" "member/internal/model"
"strconv" "strconv"
@ -37,10 +36,9 @@ type bindLoginUserReq struct {
// BindAccount 綁定帳號 -> account bind to UID // BindAccount 綁定帳號 -> account bind to UID
func (l *BindAccountLogic) BindAccount(in *member.BindingUserReq) (*member.Response, error) { func (l *BindAccountLogic) BindAccount(in *member.BindingUserReq) (*member.Response, error) {
// 驗證資料 // 驗證資料
err := required.ValidateAll(l.svcCtx.Validate, &bindLoginUserReq{ if err := l.svcCtx.Validate.ValidateAll(&bindLoginUserReq{
Account: in.GetLoginId(), Account: in.GetLoginId(),
}) }); err != nil {
if err != nil {
return nil, ers.InvalidFormat(err.Error()) return nil, ers.InvalidFormat(err.Error())
} }
@ -50,16 +48,14 @@ func (l *BindAccountLogic) BindAccount(in *member.BindingUserReq) (*member.Respo
uid = strconv.FormatInt(int64(l.svcCtx.SnackFlowGen.Generate()), 10) uid = strconv.FormatInt(int64(l.svcCtx.SnackFlowGen.Generate()), 10)
} }
// 先確定有這個Account // 先確定有這個Account
_, err = l.svcCtx.AccountModel.FindOneByAccount(l.ctx, in.GetLoginId()) if _, err := l.svcCtx.AccountModel.FindOneByAccount(l.ctx, in.GetLoginId()); err != nil {
if err != nil {
return nil, ers.ResourceNotFound(fmt.Sprintf("failed to get account : %s ", in.GetLoginId())) return nil, ers.ResourceNotFound(fmt.Sprintf("failed to get account : %s ", in.GetLoginId()))
} }
_, err = l.svcCtx.AccountToUidModel.Insert(l.ctx, &model.AccountToUid{ if _, err := l.svcCtx.AccountToUidModel.Insert(l.ctx, &model.AccountToUid{
Account: in.LoginId, Account: in.LoginId,
Uid: uid, Uid: uid,
}) }); err != nil {
if err != nil {
return nil, ers.DBError(err.Error()) return nil, ers.DBError(err.Error())
} }

View File

@ -0,0 +1,179 @@
package logic
import (
"context"
"errors"
"fmt"
"member/gen_result/pb/member"
"member/internal/domain"
libMock "member/internal/mock/lib"
modelMock "member/internal/mock/model"
svcMock "member/internal/mock/svc"
"member/internal/model"
"member/internal/svc"
"testing"
"github.com/alicebob/miniredis/v2"
"github.com/bwmarrin/snowflake"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stores/redis"
"go.uber.org/mock/gomock"
)
func TestBindAccountLogic_BindAccount(t *testing.T) {
// mock
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockAccountModel := modelMock.NewMockAccountModel(ctrl)
mockAccountToUidModel := modelMock.NewMockAccountToUidModel(ctrl)
mockSnackFlow := svcMock.NewMockSnackFlow(ctrl)
mockValidate := libMock.NewMockValidate(ctrl)
r1, err := miniredis.Run()
assert.NoError(t, err)
defer r1.Close()
newRedis, err := redis.NewRedis(redis.RedisConf{
Host: r1.Addr(),
Type: redis.ClusterType,
Pass: "",
})
assert.NoError(t, err)
sc := svc.ServiceContext{
AccountModel: mockAccountModel,
AccountToUidModel: mockAccountToUidModel,
SnackFlowGen: mockSnackFlow,
Redis: *newRedis,
Validate: mockValidate,
}
l := NewBindAccountLogic(context.Background(), &sc)
tests := []struct {
name string
input *member.BindingUserReq
setupMocks func()
expectError bool
expected *member.Response
}{
{
name: "ok",
input: &member.BindingUserReq{
LoginId: "cat1@30cm.net",
Uid: "12345",
},
setupMocks: func() {
// mock validate returns
mockValidate.EXPECT().
ValidateAll(gomock.Any()).Return(nil)
mockAccountModel.EXPECT().
FindOneByAccount(gomock.Any(), "cat1@30cm.net").
Return(&model.Account{Account: "cat1@30cm.net"}, nil)
mockAccountToUidModel.EXPECT().
Insert(gomock.Any(), gomock.Any()).
Return(nil, nil)
},
expectError: false,
expected: &member.Response{
Status: &member.BaseResp{
Code: domain.CodeOk.ToString(),
Message: "success",
Error: "",
},
},
},
{
name: "valid account without UID",
input: &member.BindingUserReq{
LoginId: "cat1@30cm.net",
Uid: "",
},
setupMocks: func() {
// mock validate returns
mockValidate.EXPECT().
ValidateAll(gomock.Any()).Return(nil)
mockAccountModel.EXPECT().
FindOneByAccount(gomock.Any(), "cat1@30cm.net").
Return(&model.Account{Account: "cat1@30cm.net"}, nil)
mockSnackFlow.EXPECT().
Generate().
Return(snowflake.ID(202408013345678))
mockAccountToUidModel.EXPECT().
Insert(gomock.Any(), &model.AccountToUid{Account: "cat1@30cm.net", Uid: "202408013345678"}).
Return(nil, nil)
},
expectError: false,
expected: &member.Response{
Status: &member.BaseResp{
Code: domain.CodeOk.ToString(),
Message: "success",
Error: "",
},
},
},
{
name: "account not found",
input: &member.BindingUserReq{
LoginId: "cat2@30cm.net",
Uid: "12345",
},
setupMocks: func() {
// mock validate returns
mockValidate.EXPECT().
ValidateAll(gomock.Any()).Return(nil)
mockAccountModel.EXPECT().
FindOneByAccount(gomock.Any(), "cat2@30cm.net").
Return(nil, errors.New("account not found"))
},
expectError: true,
},
{
name: "insert account to UID failed",
input: &member.BindingUserReq{
LoginId: "cat2@30cm.net",
Uid: "202408013345679",
},
setupMocks: func() {
// mock validate returns
mockValidate.EXPECT().
ValidateAll(gomock.Any()).Return(nil)
mockAccountModel.EXPECT().
FindOneByAccount(gomock.Any(), "cat2@30cm.net").
Return(&model.Account{Account: "cat2@30cm.net"}, nil)
mockAccountToUidModel.EXPECT().
Insert(gomock.Any(), &model.AccountToUid{Account: "cat2@30cm.net", Uid: "202408013345679"}).
Return(nil, errors.New("insert failed"))
},
expectError: true,
},
{
name: "failed to validate param",
input: &member.BindingUserReq{
LoginId: "cat3",
Uid: "202408013345679",
},
setupMocks: func() {
// mock validate returns
mockValidate.EXPECT().
ValidateAll(gomock.Any()).Return(fmt.Errorf("invalid format: failed to get correct formate loginID "))
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.setupMocks()
resp, err := l.BindAccount(tt.input)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.expected, resp)
}
})
}
}

View File

@ -2,6 +2,13 @@ package logic
import ( import (
"context" "context"
"errors"
"member/internal/domain"
ers "member/internal/lib/error"
"member/internal/model"
"time"
"github.com/go-sql-driver/mysql"
"member/gen_result/pb/member" "member/gen_result/pb/member"
"member/internal/svc" "member/internal/svc"
@ -23,9 +30,67 @@ 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 // BindUserInfo 初次,綁定 User Info
func (l *BindUserInfoLogic) BindUserInfo(in *member.CreateUserInfoReq) (*member.Response, error) { func (l *BindUserInfoLogic) BindUserInfo(in *member.CreateUserInfoReq) (*member.Response, error) {
// todo: add your logic here and delete this line // 驗證資料
if err := l.svcCtx.Validate.ValidateAll(&createUserInfo{
return &member.Response{}, nil 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(),
}); err != nil {
return nil, ers.InvalidFormat(err.Error())
}
now := time.Now().UTC().Unix()
if _, 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,
}); 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
} }

View File

@ -0,0 +1,164 @@
package logic
import (
"context"
"fmt"
"member/gen_result/pb/member"
"member/internal/domain"
libMock "member/internal/mock/lib"
modelMock "member/internal/mock/model"
svcMock "member/internal/mock/svc"
"member/internal/svc"
"testing"
"github.com/alicebob/miniredis/v2"
"github.com/go-sql-driver/mysql"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stores/redis"
"go.uber.org/mock/gomock"
"google.golang.org/protobuf/proto"
)
func TestBindUserInfoLogic_BindUserInfo(t *testing.T) {
// mock
ctrl := gomock.NewController(t)
defer ctrl.Finish()
mockUserModel := modelMock.NewMockUserTableModel(ctrl)
mockSnackFlow := svcMock.NewMockSnackFlow(ctrl)
mockValidate := libMock.NewMockValidate(ctrl)
r1, err := miniredis.Run()
assert.NoError(t, err)
defer r1.Close()
newRedis, err := redis.NewRedis(redis.RedisConf{
Host: r1.Addr(),
Type: redis.ClusterType,
Pass: "",
})
assert.NoError(t, err)
sc := svc.ServiceContext{
UserModel: mockUserModel,
SnackFlowGen: mockSnackFlow,
Redis: *newRedis,
Validate: mockValidate,
}
l := NewBindUserInfoLogic(context.Background(), &sc)
tests := []struct {
name string
input *member.CreateUserInfoReq
setupMocks func()
expectError bool
expected *member.Response
}{
{
name: "ok",
input: &member.CreateUserInfoReq{
Uid: "2024101598765",
VerifyType: 1,
AlarmType: 2,
Status: 3,
RoleId: "cat_01",
Language: "en",
Currency: "USDT",
NickName: proto.String("Test User"),
Gender: proto.Uint32(1),
Birthday: proto.Int64(1722327098),
},
setupMocks: func() {
mockValidate.EXPECT().
ValidateAll(gomock.Any()).
Return(nil)
mockUserModel.EXPECT().
Insert(gomock.Any(), gomock.Any()).
Return(nil, nil)
},
expectError: false,
expected: &member.Response{
Status: &member.BaseResp{
Code: domain.CodeOk.ToString(),
Message: "success",
Error: "",
},
},
},
{
name: "invalid user info",
input: &member.CreateUserInfoReq{
Uid: "",
},
setupMocks: func() {
mockValidate.EXPECT().
ValidateAll(gomock.Any()).
Return(fmt.Errorf("validation error"))
},
expectError: true,
},
{
name: "duplicate entry",
input: &member.CreateUserInfoReq{
Uid: "test_uid",
VerifyType: 1,
AlarmType: 2,
Status: 3,
RoleId: "test_role",
Language: "en",
Currency: "USD",
NickName: proto.String("Test User"),
Gender: proto.Uint32(1),
Birthday: proto.Int64(1622517800),
},
setupMocks: func() {
mockValidate.EXPECT().
ValidateAll(gomock.Any()).
Return(nil)
mockUserModel.EXPECT().
Insert(gomock.Any(), gomock.Any()).
Return(nil, &mysql.MySQLError{Number: 1062, Message: "Duplicate entry"})
},
expectError: true,
},
{
name: "database error",
input: &member.CreateUserInfoReq{
Uid: "test_uid",
VerifyType: 1,
AlarmType: 2,
Status: 3,
RoleId: "test_role",
Language: "en",
Currency: "USD",
NickName: proto.String("Test User"),
Gender: proto.Uint32(1),
Birthday: proto.Int64(1622517800),
},
setupMocks: func() {
mockValidate.EXPECT().
ValidateAll(gomock.Any()).
Return(nil)
mockUserModel.EXPECT().
Insert(gomock.Any(), gomock.Any()).
Return(nil, fmt.Errorf("database error"))
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.setupMocks()
resp, err := l.BindUserInfo(tt.input)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.expected, resp)
}
})
}
}

View File

@ -4,15 +4,16 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"github.com/go-sql-driver/mysql"
"github.com/zeromicro/go-zero/core/logx"
"member/gen_result/pb/member" "member/gen_result/pb/member"
"member/internal/domain"
ers "member/internal/lib/error" ers "member/internal/lib/error"
"member/internal/lib/required"
"member/internal/model" "member/internal/model"
"member/internal/svc" "member/internal/svc"
"member/internal/utils" "member/internal/utils"
"time" "time"
"github.com/go-sql-driver/mysql"
"github.com/zeromicro/go-zero/core/logx"
) )
type CreateUserAccountLogic struct { type CreateUserAccountLogic struct {
@ -35,19 +36,21 @@ type createLoginUserReq struct {
Token string `json:"token" validate:"required"` Token string `json:"token" validate:"required"`
} }
// HasPasswordFunc 這樣方便測試
var HasPasswordFunc = utils.HashPassword
// CreateUserAccount 建立帳號與密碼 -> 可登入,但可不可以做其他事情看業務流程,也可以只註冊就好 // CreateUserAccount 建立帳號與密碼 -> 可登入,但可不可以做其他事情看業務流程,也可以只註冊就好
func (l *CreateUserAccountLogic) CreateUserAccount(in *member.CreateLoginUserReq) (*member.Response, error) { func (l *CreateUserAccountLogic) CreateUserAccount(in *member.CreateLoginUserReq) (*member.Response, error) {
// 驗證資料 // 驗證資料
err := required.ValidateAll(l.svcCtx.Validate, &createLoginUserReq{ if err := l.svcCtx.Validate.ValidateAll(&createLoginUserReq{
LoginId: in.GetLoginId(), LoginId: in.GetLoginId(),
Platform: in.GetPlatform(), Platform: in.GetPlatform(),
Token: in.GetToken(), Token: in.GetToken(),
}) }); err != nil {
if err != nil {
return nil, ers.InvalidFormat(err.Error()) return nil, ers.InvalidFormat(err.Error())
} }
token, err := utils.HashPassword(in.GetToken(), l.svcCtx.Config.Bcrypt.Cost) token, err := HasPasswordFunc(in.GetToken(), l.svcCtx.Config.Bcrypt.Cost)
if err != nil { if err != nil {
return nil, ers.ArkInternal(fmt.Sprintf("failed to encrypt err: %v", err.Error())) return nil, ers.ArkInternal(fmt.Sprintf("failed to encrypt err: %v", err.Error()))
} }
@ -72,5 +75,11 @@ func (l *CreateUserAccountLogic) CreateUserAccount(in *member.CreateLoginUserReq
return nil, ers.DBError(err.Error()) return nil, ers.DBError(err.Error())
} }
return nil, nil return &member.Response{
Status: &member.BaseResp{
Code: domain.CodeOk.ToString(),
Message: "success",
Error: "",
},
}, nil
} }

View File

@ -0,0 +1,166 @@
package logic
import (
"context"
"fmt"
"member/gen_result/pb/member"
"member/internal/domain"
libMock "member/internal/mock/lib"
modelMock "member/internal/mock/model"
svcMock "member/internal/mock/svc"
"member/internal/svc"
"testing"
"github.com/alicebob/miniredis/v2"
"github.com/go-sql-driver/mysql"
"github.com/stretchr/testify/assert"
"github.com/zeromicro/go-zero/core/stores/redis"
"go.uber.org/mock/gomock"
)
func TestCreateUserAccountLogic_CreateUserAccount(t *testing.T) {
// mock
ctrl := gomock.NewController(t)
defer ctrl.Finish()
modelAccountModel := modelMock.NewMockAccountModel(ctrl)
mockSnackFlow := svcMock.NewMockSnackFlow(ctrl)
mockValidate := libMock.NewMockValidate(ctrl)
r1, err := miniredis.Run()
assert.NoError(t, err)
defer r1.Close()
newRedis, err := redis.NewRedis(redis.RedisConf{
Host: r1.Addr(),
Type: redis.ClusterType,
Pass: "",
})
assert.NoError(t, err)
sc := svc.ServiceContext{
AccountModel: modelAccountModel,
SnackFlowGen: mockSnackFlow,
Redis: *newRedis,
Validate: mockValidate,
}
l := NewCreateUserAccountLogic(context.Background(), &sc)
tests := []struct {
name string
input *member.CreateLoginUserReq
setupMocks func()
expectError bool
expected *member.Response
}{
{
name: "ok",
input: &member.CreateLoginUserReq{
LoginId: "test_user",
Platform: 1,
Token: "password123",
},
setupMocks: func() {
mockValidate.EXPECT().
ValidateAll(gomock.Any()).
Return(nil)
modelAccountModel.EXPECT().
Insert(gomock.Any(), gomock.Any()).
Return(nil, nil)
},
expectError: false,
expected: &member.Response{
Status: &member.BaseResp{
Code: domain.CodeOk.ToString(),
Message: "success",
Error: "",
},
},
},
{
name: "validation failure",
input: &member.CreateLoginUserReq{
LoginId: "test_user",
Platform: 1,
Token: "password123",
},
setupMocks: func() {
mockValidate.EXPECT().
ValidateAll(gomock.Any()).
Return(fmt.Errorf("validation error"))
},
expectError: true,
},
{
name: "password hash failure",
input: &member.CreateLoginUserReq{
LoginId: "test_user",
Platform: 1,
Token: "password123",
},
setupMocks: func() {
mockValidate.EXPECT().
ValidateAll(gomock.Any()).
Return(nil)
HasPasswordFunc = func(password string, cost int) (string, error) {
return "", fmt.Errorf("hash error")
}
},
expectError: true,
},
{
name: "duplicate entry error",
input: &member.CreateLoginUserReq{
LoginId: "test_user",
Platform: 1,
Token: "password123",
},
setupMocks: func() {
mockValidate.EXPECT().
ValidateAll(gomock.Any()).
Return(nil)
HasPasswordFunc = func(password string, cost int) (string, error) {
return "hashedpassword", nil
}
modelAccountModel.EXPECT().
Insert(gomock.Any(), gomock.Any()).
Return(nil, &mysql.MySQLError{Number: 1062, Message: "Duplicate entry"})
},
expectError: true,
},
{
name: "database error",
input: &member.CreateLoginUserReq{
LoginId: "test_user",
Platform: 1,
Token: "password123",
},
setupMocks: func() {
mockValidate.EXPECT().
ValidateAll(gomock.Any()).
Return(nil)
HasPasswordFunc = func(password string, cost int) (string, error) {
return "hashedpassword", nil
}
modelAccountModel.EXPECT().
Insert(gomock.Any(), gomock.Any()).
Return(nil, fmt.Errorf("database error"))
},
expectError: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
tt.setupMocks()
resp, err := l.CreateUserAccount(tt.input)
if tt.expectError {
assert.Error(t, err)
} else {
assert.NoError(t, err)
assert.Equal(t, tt.expected, resp)
}
})
}
}

View File

@ -2,9 +2,14 @@ package logic
import ( import (
"context" "context"
"crypto/rand"
"fmt"
"math/big"
"member/gen_result/pb/member" "member/gen_result/pb/member"
"member/internal/domain"
ers "member/internal/lib/error"
"member/internal/svc" "member/internal/svc"
"strconv"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
) )
@ -23,9 +28,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 這個帳號驗證碼(十分鐘),通用的 // GenerateRefreshCode 這個帳號驗證碼(十分鐘),通用的
func (l *GenerateRefreshCodeLogic) GenerateRefreshCode(in *member.GenerateRefreshCodeReq) (*member.GenerateRefreshCodeResp, error) { func (l *GenerateRefreshCodeLogic) GenerateRefreshCode(in *member.GenerateRefreshCodeReq) (*member.GenerateRefreshCodeResp, error) {
// todo: add your logic here and delete this line // 驗證資料
if err := l.svcCtx.Validate.ValidateAll(&generateRefreshCodeReq{
return &member.GenerateRefreshCodeResp{}, nil Account: in.GetAccount(),
CodeType: in.GetCodeType(),
}); err != nil {
return nil, ers.InvalidFormat(err.Error())
}
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
} }

View File

@ -0,0 +1,51 @@
package logic
import (
"testing"
"github.com/stretchr/testify/assert"
)
func Test_getCodeNameByCode(t *testing.T) {
type args struct {
code int32
}
tests := []struct {
name string
args args
want string
want1 bool
}{
{
name: "email",
args: args{
code: 1,
},
want: "email",
want1: true,
},
{
name: "phone",
args: args{
code: 2,
},
want: "phone",
want1: true,
},
{
name: "none",
args: args{
code: 3,
},
want: "",
want1: false,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, got1 := getCodeNameByCode(tt.args.code)
assert.Equalf(t, tt.want, got, "getCodeNameByCode(%v)", tt.args.code)
assert.Equalf(t, tt.want1, got1, "getCodeNameByCode(%v)", tt.args.code)
})
}
}

View File

@ -2,8 +2,9 @@ package logic
import ( import (
"context" "context"
"member/gen_result/pb/member" "member/gen_result/pb/member"
"member/internal/domain"
ers "member/internal/lib/error"
"member/internal/svc" "member/internal/svc"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
@ -23,9 +24,32 @@ func NewGetUidByAccountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *G
} }
} }
type getUidByAccountReq struct {
Account string `json:"account" validate:"account"`
}
// GetUidByAccount 用帳號換取 UID // GetUidByAccount 用帳號換取 UID
func (l *GetUidByAccountLogic) GetUidByAccount(in *member.GetUIDByAccountReq) (*member.GetUidByAccountResp, error) { func (l *GetUidByAccountLogic) GetUidByAccount(in *member.GetUIDByAccountReq) (*member.GetUidByAccountResp, error) {
// todo: add your logic here and delete this line // 驗證資料
if err := l.svcCtx.Validate.ValidateAll(&getUidByAccountReq{
return &member.GetUidByAccountResp{}, nil Account: in.GetAccount(),
}); err != nil {
return nil, ers.InvalidFormat(err.Error())
}
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
} }

View File

@ -5,7 +5,6 @@ import (
"member/gen_result/pb/member" "member/gen_result/pb/member"
"member/internal/domain" "member/internal/domain"
ers "member/internal/lib/error" ers "member/internal/lib/error"
"member/internal/lib/required"
"member/internal/svc" "member/internal/svc"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
@ -31,11 +30,10 @@ type getUserAccountReq struct {
// GetUserAccountInfo 取得帳號密碼資料 // GetUserAccountInfo 取得帳號密碼資料
func (l *GetUserAccountInfoLogic) GetUserAccountInfo(in *member.GetUIDByAccountReq) (*member.GetAccountInfoResp, error) { func (l *GetUserAccountInfoLogic) GetUserAccountInfo(in *member.GetUIDByAccountReq) (*member.GetAccountInfoResp, error) {
// 驗證輸入資料 // 驗證資料
err := required.ValidateAll(l.svcCtx.Validate, &getUserAccountReq{ if err := l.svcCtx.Validate.ValidateAll(getUserAccountReq{
LoginId: in.GetAccount(), LoginId: in.GetAccount(),
}) }); err != nil {
if err != nil {
return nil, ers.InvalidFormat(err.Error()) return nil, ers.InvalidFormat(err.Error())
} }

View File

@ -2,8 +2,9 @@ package logic
import ( import (
"context" "context"
"member/gen_result/pb/member" "member/gen_result/pb/member"
ers "member/internal/lib/error"
"member/internal/model"
"member/internal/svc" "member/internal/svc"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
@ -23,9 +24,29 @@ func NewGetUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUs
} }
} }
// UpdateStatus 取得會員資訊 // GetUserInfo 取得會員資訊
func (l *GetUserInfoLogic) GetUserInfo(in *member.GetUserInfoReq) (*member.GetUserInfoResp, error) { func (l *GetUserInfoLogic) GetUserInfo(in *member.GetUserInfoReq) (*member.GetUserInfoResp, error) {
// todo: add your logic here and delete this line 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 &member.GetUserInfoResp{}, nil
} }
return nil, ers.ResourceNotFound("filed to get user info")
}

View File

@ -2,9 +2,13 @@ package logic
import ( import (
"context" "context"
"fmt"
"member/gen_result/pb/member" "member/gen_result/pb/member"
"member/internal/domain"
ers "member/internal/lib/error"
"member/internal/model"
"member/internal/svc" "member/internal/svc"
"strconv"
"github.com/zeromicro/go-zero/core/logx" "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 取得會員列表 // ListMember 取得會員列表
func (l *ListMemberLogic) ListMember(in *member.ListUserInfoReq) (*member.ListUserInfoResp, error) { 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 &member.ListUserInfoResp{}, nil return nil, ers.InvalidFormat("failed to get correct param", err.Error())
}
members, err := l.svcCtx.UserModel.ListMembers(l.ctx, &params)
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
} }

View File

@ -2,8 +2,9 @@ package logic
import ( import (
"context" "context"
"member/gen_result/pb/member" "member/gen_result/pb/member"
"member/internal/domain"
ers "member/internal/lib/error"
"member/internal/svc" "member/internal/svc"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
@ -23,9 +24,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 修改狀態 // UpdateStatus 修改狀態
func (l *UpdateStatusLogic) UpdateStatus(in *member.UpdateStatusReq) (*member.Response, error) { func (l *UpdateStatusLogic) UpdateStatus(in *member.UpdateStatusReq) (*member.Response, error) {
// todo: add your logic here and delete this line // 驗證資料
if err := l.svcCtx.Validate.ValidateAll(&updateStatusReq{
return &member.Response{}, nil UID: in.GetUid(),
Status: int32(in.GetStatus()),
}); err != nil {
return nil, ers.InvalidFormat(err.Error())
}
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
} }

View File

@ -2,8 +2,9 @@ package logic
import ( import (
"context" "context"
"member/gen_result/pb/member" "member/gen_result/pb/member"
"member/internal/domain"
ers "member/internal/lib/error"
"member/internal/svc" "member/internal/svc"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
@ -25,7 +26,16 @@ func NewUpdateUserInfoLogic(ctx context.Context, svcCtx *svc.ServiceContext) *Up
// UpdateUserInfo 更新 User Info // UpdateUserInfo 更新 User Info
func (l *UpdateUserInfoLogic) UpdateUserInfo(in *member.UpdateUserInfoReq) (*member.Response, error) { func (l *UpdateUserInfoLogic) UpdateUserInfo(in *member.UpdateUserInfoReq) (*member.Response, error) {
// todo: add your logic here and delete this line err := l.svcCtx.UserModel.UpdateSome(l.ctx, in)
if err != nil {
return &member.Response{}, nil return nil, ers.DBError(err.Error())
}
return &member.Response{
Status: &member.BaseResp{
Code: domain.CodeOk.ToString(),
Message: "success",
Error: "",
},
}, nil
} }

View File

@ -2,6 +2,10 @@ package logic
import ( import (
"context" "context"
"fmt"
"member/internal/domain"
ers "member/internal/lib/error"
"member/internal/utils"
"member/gen_result/pb/member" "member/gen_result/pb/member"
"member/internal/svc" "member/internal/svc"
@ -23,9 +27,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 更新密碼 // UpdateUserToken 更新密碼
func (l *UpdateUserTokenLogic) UpdateUserToken(in *member.UpdateTokenReq) (*member.Response, error) { func (l *UpdateUserTokenLogic) UpdateUserToken(in *member.UpdateTokenReq) (*member.Response, error) {
// todo: add your logic here and delete this line // 驗證資料
if err := l.svcCtx.Validate.ValidateAll(&updateUserTokenReq{
return &member.Response{}, nil LoginId: in.GetAccount(),
Token: in.GetToken(),
}); err != nil {
return nil, ers.InvalidFormat(err.Error())
}
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
} }

View File

@ -2,8 +2,10 @@ package logic
import ( import (
"context" "context"
"fmt"
"member/gen_result/pb/member" "member/gen_result/pb/member"
"member/internal/domain"
ers "member/internal/lib/error"
"member/internal/svc" "member/internal/svc"
"github.com/zeromicro/go-zero/core/logx" "github.com/zeromicro/go-zero/core/logx"
@ -25,7 +27,42 @@ func NewVerifyRefreshCodeLogic(ctx context.Context, svcCtx *svc.ServiceContext)
// VerifyRefreshCode 驗證忘記密碼 token // VerifyRefreshCode 驗證忘記密碼 token
func (l *VerifyRefreshCodeLogic) VerifyRefreshCode(in *member.VerifyRefreshCodeReq) (*member.Response, error) { func (l *VerifyRefreshCodeLogic) VerifyRefreshCode(in *member.VerifyRefreshCodeReq) (*member.Response, error) {
// todo: add your logic here and delete this line // 驗證資料
if err := l.svcCtx.Validate.ValidateAll(&generateRefreshCodeReq{
return &member.Response{}, nil Account: in.GetAccount(),
CodeType: in.GetCodeType(),
}); err != nil {
return nil, ers.InvalidFormat(err.Error())
}
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
} }

View File

@ -0,0 +1,72 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./validate.go
//
// Generated by this command:
//
// mockgen -source=./validate.go -destination=../../mock/lib/validate.go -package=lib
//
// Package lib is a generated GoMock package.
package lib
import (
required "member/internal/lib/required"
reflect "reflect"
gomock "go.uber.org/mock/gomock"
)
// MockValidate is a mock of Validate interface.
type MockValidate struct {
ctrl *gomock.Controller
recorder *MockValidateMockRecorder
}
// MockValidateMockRecorder is the mock recorder for MockValidate.
type MockValidateMockRecorder struct {
mock *MockValidate
}
// NewMockValidate creates a new mock instance.
func NewMockValidate(ctrl *gomock.Controller) *MockValidate {
mock := &MockValidate{ctrl: ctrl}
mock.recorder = &MockValidateMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockValidate) EXPECT() *MockValidateMockRecorder {
return m.recorder
}
// BindToValidator mocks base method.
func (m *MockValidate) BindToValidator(opts ...required.Option) error {
m.ctrl.T.Helper()
varargs := []any{}
for _, a := range opts {
varargs = append(varargs, a)
}
ret := m.ctrl.Call(m, "BindToValidator", varargs...)
ret0, _ := ret[0].(error)
return ret0
}
// BindToValidator indicates an expected call of BindToValidator.
func (mr *MockValidateMockRecorder) BindToValidator(opts ...any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BindToValidator", reflect.TypeOf((*MockValidate)(nil).BindToValidator), opts...)
}
// ValidateAll mocks base method.
func (m *MockValidate) ValidateAll(obj any) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ValidateAll", obj)
ret0, _ := ret[0].(error)
return ret0
}
// ValidateAll indicates an expected call of ValidateAll.
func (mr *MockValidateMockRecorder) ValidateAll(obj any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateAll", reflect.TypeOf((*MockValidate)(nil).ValidateAll), obj)
}

View File

@ -0,0 +1,129 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./account_model.go
//
// Generated by this command:
//
// mockgen -source=./account_model.go -destination=../mock/model/account_model.go -package=model
//
// Package model is a generated GoMock package.
package model
import (
context "context"
sql "database/sql"
model "member/internal/model"
reflect "reflect"
gomock "go.uber.org/mock/gomock"
)
// MockAccountModel is a mock of AccountModel interface.
type MockAccountModel struct {
ctrl *gomock.Controller
recorder *MockAccountModelMockRecorder
}
// MockAccountModelMockRecorder is the mock recorder for MockAccountModel.
type MockAccountModelMockRecorder struct {
mock *MockAccountModel
}
// NewMockAccountModel creates a new mock instance.
func NewMockAccountModel(ctrl *gomock.Controller) *MockAccountModel {
mock := &MockAccountModel{ctrl: ctrl}
mock.recorder = &MockAccountModelMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockAccountModel) EXPECT() *MockAccountModelMockRecorder {
return m.recorder
}
// Delete mocks base method.
func (m *MockAccountModel) Delete(ctx context.Context, id int64) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", ctx, id)
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockAccountModelMockRecorder) Delete(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockAccountModel)(nil).Delete), ctx, id)
}
// FindOne mocks base method.
func (m *MockAccountModel) FindOne(ctx context.Context, id int64) (*model.Account, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOne", ctx, id)
ret0, _ := ret[0].(*model.Account)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOne indicates an expected call of FindOne.
func (mr *MockAccountModelMockRecorder) FindOne(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockAccountModel)(nil).FindOne), ctx, id)
}
// FindOneByAccount mocks base method.
func (m *MockAccountModel) FindOneByAccount(ctx context.Context, account string) (*model.Account, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOneByAccount", ctx, account)
ret0, _ := ret[0].(*model.Account)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOneByAccount indicates an expected call of FindOneByAccount.
func (mr *MockAccountModelMockRecorder) FindOneByAccount(ctx, account any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOneByAccount", reflect.TypeOf((*MockAccountModel)(nil).FindOneByAccount), ctx, account)
}
// Insert mocks base method.
func (m *MockAccountModel) Insert(ctx context.Context, data *model.Account) (sql.Result, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Insert", ctx, data)
ret0, _ := ret[0].(sql.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Insert indicates an expected call of Insert.
func (mr *MockAccountModelMockRecorder) Insert(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockAccountModel)(nil).Insert), ctx, data)
}
// Update mocks base method.
func (m *MockAccountModel) Update(ctx context.Context, data *model.Account) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Update", ctx, data)
ret0, _ := ret[0].(error)
return ret0
}
// Update indicates an expected call of Update.
func (mr *MockAccountModelMockRecorder) Update(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockAccountModel)(nil).Update), ctx, data)
}
// UpdateTokenByLoginID mocks base method.
func (m *MockAccountModel) UpdateTokenByLoginID(ctx context.Context, account, token string) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateTokenByLoginID", ctx, account, token)
ret0, _ := ret[0].(error)
return ret0
}
// UpdateTokenByLoginID indicates an expected call of UpdateTokenByLoginID.
func (mr *MockAccountModelMockRecorder) UpdateTokenByLoginID(ctx, account, token any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateTokenByLoginID", reflect.TypeOf((*MockAccountModel)(nil).UpdateTokenByLoginID), ctx, account, token)
}

View File

@ -0,0 +1,115 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./account_model_gen.go
//
// Generated by this command:
//
// mockgen -source=./account_model_gen.go -destination=../mock/model/account_model_gen.go -package=model
//
// Package model is a generated GoMock package.
package model
import (
context "context"
sql "database/sql"
model "member/internal/model"
reflect "reflect"
gomock "go.uber.org/mock/gomock"
)
// MockaccountModel is a mock of accountModel interface.
type MockaccountModel struct {
ctrl *gomock.Controller
recorder *MockaccountModelMockRecorder
}
// MockaccountModelMockRecorder is the mock recorder for MockaccountModel.
type MockaccountModelMockRecorder struct {
mock *MockaccountModel
}
// NewMockaccountModel creates a new mock instance.
func NewMockaccountModel(ctrl *gomock.Controller) *MockaccountModel {
mock := &MockaccountModel{ctrl: ctrl}
mock.recorder = &MockaccountModelMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockaccountModel) EXPECT() *MockaccountModelMockRecorder {
return m.recorder
}
// Delete mocks base method.
func (m *MockaccountModel) Delete(ctx context.Context, id int64) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", ctx, id)
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockaccountModelMockRecorder) Delete(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockaccountModel)(nil).Delete), ctx, id)
}
// FindOne mocks base method.
func (m *MockaccountModel) FindOne(ctx context.Context, id int64) (*model.Account, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOne", ctx, id)
ret0, _ := ret[0].(*model.Account)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOne indicates an expected call of FindOne.
func (mr *MockaccountModelMockRecorder) FindOne(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockaccountModel)(nil).FindOne), ctx, id)
}
// FindOneByAccount mocks base method.
func (m *MockaccountModel) FindOneByAccount(ctx context.Context, account string) (*model.Account, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOneByAccount", ctx, account)
ret0, _ := ret[0].(*model.Account)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOneByAccount indicates an expected call of FindOneByAccount.
func (mr *MockaccountModelMockRecorder) FindOneByAccount(ctx, account any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOneByAccount", reflect.TypeOf((*MockaccountModel)(nil).FindOneByAccount), ctx, account)
}
// Insert mocks base method.
func (m *MockaccountModel) Insert(ctx context.Context, data *model.Account) (sql.Result, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Insert", ctx, data)
ret0, _ := ret[0].(sql.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Insert indicates an expected call of Insert.
func (mr *MockaccountModelMockRecorder) Insert(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockaccountModel)(nil).Insert), ctx, data)
}
// Update mocks base method.
func (m *MockaccountModel) Update(ctx context.Context, data *model.Account) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Update", ctx, data)
ret0, _ := ret[0].(error)
return ret0
}
// Update indicates an expected call of Update.
func (mr *MockaccountModelMockRecorder) Update(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockaccountModel)(nil).Update), ctx, data)
}

View File

@ -0,0 +1,115 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./account_to_uid_model.go
//
// Generated by this command:
//
// mockgen -source=./account_to_uid_model.go -destination=../mock/model/account_to_uid_model.go -package=model
//
// Package model is a generated GoMock package.
package model
import (
context "context"
sql "database/sql"
model "member/internal/model"
reflect "reflect"
gomock "go.uber.org/mock/gomock"
)
// MockAccountToUidModel is a mock of AccountToUidModel interface.
type MockAccountToUidModel struct {
ctrl *gomock.Controller
recorder *MockAccountToUidModelMockRecorder
}
// MockAccountToUidModelMockRecorder is the mock recorder for MockAccountToUidModel.
type MockAccountToUidModelMockRecorder struct {
mock *MockAccountToUidModel
}
// NewMockAccountToUidModel creates a new mock instance.
func NewMockAccountToUidModel(ctrl *gomock.Controller) *MockAccountToUidModel {
mock := &MockAccountToUidModel{ctrl: ctrl}
mock.recorder = &MockAccountToUidModelMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockAccountToUidModel) EXPECT() *MockAccountToUidModelMockRecorder {
return m.recorder
}
// Delete mocks base method.
func (m *MockAccountToUidModel) Delete(ctx context.Context, id int64) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", ctx, id)
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockAccountToUidModelMockRecorder) Delete(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockAccountToUidModel)(nil).Delete), ctx, id)
}
// FindOne mocks base method.
func (m *MockAccountToUidModel) FindOne(ctx context.Context, id int64) (*model.AccountToUid, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOne", ctx, id)
ret0, _ := ret[0].(*model.AccountToUid)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOne indicates an expected call of FindOne.
func (mr *MockAccountToUidModelMockRecorder) FindOne(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockAccountToUidModel)(nil).FindOne), ctx, id)
}
// FindOneByAccount mocks base method.
func (m *MockAccountToUidModel) FindOneByAccount(ctx context.Context, account string) (*model.AccountToUid, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOneByAccount", ctx, account)
ret0, _ := ret[0].(*model.AccountToUid)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOneByAccount indicates an expected call of FindOneByAccount.
func (mr *MockAccountToUidModelMockRecorder) FindOneByAccount(ctx, account any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOneByAccount", reflect.TypeOf((*MockAccountToUidModel)(nil).FindOneByAccount), ctx, account)
}
// Insert mocks base method.
func (m *MockAccountToUidModel) Insert(ctx context.Context, data *model.AccountToUid) (sql.Result, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Insert", ctx, data)
ret0, _ := ret[0].(sql.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Insert indicates an expected call of Insert.
func (mr *MockAccountToUidModelMockRecorder) Insert(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockAccountToUidModel)(nil).Insert), ctx, data)
}
// Update mocks base method.
func (m *MockAccountToUidModel) Update(ctx context.Context, data *model.AccountToUid) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Update", ctx, data)
ret0, _ := ret[0].(error)
return ret0
}
// Update indicates an expected call of Update.
func (mr *MockAccountToUidModelMockRecorder) Update(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockAccountToUidModel)(nil).Update), ctx, data)
}

View File

@ -0,0 +1,115 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./account_to_uid_model_gen.go
//
// Generated by this command:
//
// mockgen -source=./account_to_uid_model_gen.go -destination=../mock/model/account_to_uid_model_gen.go -package=model
//
// Package model is a generated GoMock package.
package model
import (
context "context"
sql "database/sql"
model "member/internal/model"
reflect "reflect"
gomock "go.uber.org/mock/gomock"
)
// MockaccountToUidModel is a mock of accountToUidModel interface.
type MockaccountToUidModel struct {
ctrl *gomock.Controller
recorder *MockaccountToUidModelMockRecorder
}
// MockaccountToUidModelMockRecorder is the mock recorder for MockaccountToUidModel.
type MockaccountToUidModelMockRecorder struct {
mock *MockaccountToUidModel
}
// NewMockaccountToUidModel creates a new mock instance.
func NewMockaccountToUidModel(ctrl *gomock.Controller) *MockaccountToUidModel {
mock := &MockaccountToUidModel{ctrl: ctrl}
mock.recorder = &MockaccountToUidModelMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockaccountToUidModel) EXPECT() *MockaccountToUidModelMockRecorder {
return m.recorder
}
// Delete mocks base method.
func (m *MockaccountToUidModel) Delete(ctx context.Context, id int64) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", ctx, id)
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockaccountToUidModelMockRecorder) Delete(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockaccountToUidModel)(nil).Delete), ctx, id)
}
// FindOne mocks base method.
func (m *MockaccountToUidModel) FindOne(ctx context.Context, id int64) (*model.AccountToUid, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOne", ctx, id)
ret0, _ := ret[0].(*model.AccountToUid)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOne indicates an expected call of FindOne.
func (mr *MockaccountToUidModelMockRecorder) FindOne(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockaccountToUidModel)(nil).FindOne), ctx, id)
}
// FindOneByAccount mocks base method.
func (m *MockaccountToUidModel) FindOneByAccount(ctx context.Context, account string) (*model.AccountToUid, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOneByAccount", ctx, account)
ret0, _ := ret[0].(*model.AccountToUid)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOneByAccount indicates an expected call of FindOneByAccount.
func (mr *MockaccountToUidModelMockRecorder) FindOneByAccount(ctx, account any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOneByAccount", reflect.TypeOf((*MockaccountToUidModel)(nil).FindOneByAccount), ctx, account)
}
// Insert mocks base method.
func (m *MockaccountToUidModel) Insert(ctx context.Context, data *model.AccountToUid) (sql.Result, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Insert", ctx, data)
ret0, _ := ret[0].(sql.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Insert indicates an expected call of Insert.
func (mr *MockaccountToUidModelMockRecorder) Insert(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockaccountToUidModel)(nil).Insert), ctx, data)
}
// Update mocks base method.
func (m *MockaccountToUidModel) Update(ctx context.Context, data *model.AccountToUid) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Update", ctx, data)
ret0, _ := ret[0].(error)
return ret0
}
// Update indicates an expected call of Update.
func (mr *MockaccountToUidModelMockRecorder) Update(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockaccountToUidModel)(nil).Update), ctx, data)
}

View File

@ -0,0 +1,115 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./machine_node_model.go
//
// Generated by this command:
//
// mockgen -source=./machine_node_model.go -destination=../mock/model/machine_node_model.go -package=model
//
// Package model is a generated GoMock package.
package model
import (
context "context"
sql "database/sql"
model "member/internal/model"
reflect "reflect"
gomock "go.uber.org/mock/gomock"
)
// MockMachineNodeModel is a mock of MachineNodeModel interface.
type MockMachineNodeModel struct {
ctrl *gomock.Controller
recorder *MockMachineNodeModelMockRecorder
}
// MockMachineNodeModelMockRecorder is the mock recorder for MockMachineNodeModel.
type MockMachineNodeModelMockRecorder struct {
mock *MockMachineNodeModel
}
// NewMockMachineNodeModel creates a new mock instance.
func NewMockMachineNodeModel(ctrl *gomock.Controller) *MockMachineNodeModel {
mock := &MockMachineNodeModel{ctrl: ctrl}
mock.recorder = &MockMachineNodeModelMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockMachineNodeModel) EXPECT() *MockMachineNodeModelMockRecorder {
return m.recorder
}
// Delete mocks base method.
func (m *MockMachineNodeModel) Delete(ctx context.Context, id int64) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", ctx, id)
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockMachineNodeModelMockRecorder) Delete(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockMachineNodeModel)(nil).Delete), ctx, id)
}
// FindOne mocks base method.
func (m *MockMachineNodeModel) FindOne(ctx context.Context, id int64) (*model.MachineNode, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOne", ctx, id)
ret0, _ := ret[0].(*model.MachineNode)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOne indicates an expected call of FindOne.
func (mr *MockMachineNodeModelMockRecorder) FindOne(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockMachineNodeModel)(nil).FindOne), ctx, id)
}
// FindOneByHostName mocks base method.
func (m *MockMachineNodeModel) FindOneByHostName(ctx context.Context, hostName string) (*model.MachineNode, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOneByHostName", ctx, hostName)
ret0, _ := ret[0].(*model.MachineNode)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOneByHostName indicates an expected call of FindOneByHostName.
func (mr *MockMachineNodeModelMockRecorder) FindOneByHostName(ctx, hostName any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOneByHostName", reflect.TypeOf((*MockMachineNodeModel)(nil).FindOneByHostName), ctx, hostName)
}
// Insert mocks base method.
func (m *MockMachineNodeModel) Insert(ctx context.Context, data *model.MachineNode) (sql.Result, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Insert", ctx, data)
ret0, _ := ret[0].(sql.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Insert indicates an expected call of Insert.
func (mr *MockMachineNodeModelMockRecorder) Insert(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockMachineNodeModel)(nil).Insert), ctx, data)
}
// Update mocks base method.
func (m *MockMachineNodeModel) Update(ctx context.Context, data *model.MachineNode) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Update", ctx, data)
ret0, _ := ret[0].(error)
return ret0
}
// Update indicates an expected call of Update.
func (mr *MockMachineNodeModelMockRecorder) Update(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockMachineNodeModel)(nil).Update), ctx, data)
}

View File

@ -0,0 +1,100 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./machine_node_model_gen.go
//
// Generated by this command:
//
// mockgen -source=./machine_node_model_gen.go -destination=../mock/model/machine_node_model_gen.go -package=model
//
// Package model is a generated GoMock package.
package model
import (
context "context"
sql "database/sql"
model "member/internal/model"
reflect "reflect"
gomock "go.uber.org/mock/gomock"
)
// MockmachineNodeModel is a mock of machineNodeModel interface.
type MockmachineNodeModel struct {
ctrl *gomock.Controller
recorder *MockmachineNodeModelMockRecorder
}
// MockmachineNodeModelMockRecorder is the mock recorder for MockmachineNodeModel.
type MockmachineNodeModelMockRecorder struct {
mock *MockmachineNodeModel
}
// NewMockmachineNodeModel creates a new mock instance.
func NewMockmachineNodeModel(ctrl *gomock.Controller) *MockmachineNodeModel {
mock := &MockmachineNodeModel{ctrl: ctrl}
mock.recorder = &MockmachineNodeModelMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockmachineNodeModel) EXPECT() *MockmachineNodeModelMockRecorder {
return m.recorder
}
// Delete mocks base method.
func (m *MockmachineNodeModel) Delete(ctx context.Context, id int64) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", ctx, id)
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockmachineNodeModelMockRecorder) Delete(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockmachineNodeModel)(nil).Delete), ctx, id)
}
// FindOne mocks base method.
func (m *MockmachineNodeModel) FindOne(ctx context.Context, id int64) (*model.MachineNode, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOne", ctx, id)
ret0, _ := ret[0].(*model.MachineNode)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOne indicates an expected call of FindOne.
func (mr *MockmachineNodeModelMockRecorder) FindOne(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockmachineNodeModel)(nil).FindOne), ctx, id)
}
// Insert mocks base method.
func (m *MockmachineNodeModel) Insert(ctx context.Context, data *model.MachineNode) (sql.Result, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Insert", ctx, data)
ret0, _ := ret[0].(sql.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Insert indicates an expected call of Insert.
func (mr *MockmachineNodeModelMockRecorder) Insert(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockmachineNodeModel)(nil).Insert), ctx, data)
}
// Update mocks base method.
func (m *MockmachineNodeModel) Update(ctx context.Context, data *model.MachineNode) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Update", ctx, data)
ret0, _ := ret[0].(error)
return ret0
}
// Update indicates an expected call of Update.
func (mr *MockmachineNodeModelMockRecorder) Update(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockmachineNodeModel)(nil).Update), ctx, data)
}

View File

@ -0,0 +1,189 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./user_table_model.go
//
// Generated by this command:
//
// mockgen -source=./user_table_model.go -destination=../mock/model/user_table_model.go -package=model
//
// Package model is a generated GoMock package.
package model
import (
context "context"
sql "database/sql"
member "member/gen_result/pb/member"
model "member/internal/model"
reflect "reflect"
gomock "go.uber.org/mock/gomock"
)
// MockUserTableModel is a mock of UserTableModel interface.
type MockUserTableModel struct {
ctrl *gomock.Controller
recorder *MockUserTableModelMockRecorder
}
// MockUserTableModelMockRecorder is the mock recorder for MockUserTableModel.
type MockUserTableModelMockRecorder struct {
mock *MockUserTableModel
}
// NewMockUserTableModel creates a new mock instance.
func NewMockUserTableModel(ctrl *gomock.Controller) *MockUserTableModel {
mock := &MockUserTableModel{ctrl: ctrl}
mock.recorder = &MockUserTableModelMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockUserTableModel) EXPECT() *MockUserTableModelMockRecorder {
return m.recorder
}
// Count mocks base method.
func (m *MockUserTableModel) Count(ctx context.Context) (int64, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Count", ctx)
ret0, _ := ret[0].(int64)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Count indicates an expected call of Count.
func (mr *MockUserTableModelMockRecorder) Count(ctx any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Count", reflect.TypeOf((*MockUserTableModel)(nil).Count), ctx)
}
// Delete mocks base method.
func (m *MockUserTableModel) Delete(ctx context.Context, id int64) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", ctx, id)
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockUserTableModelMockRecorder) Delete(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockUserTableModel)(nil).Delete), ctx, id)
}
// FindOne mocks base method.
func (m *MockUserTableModel) FindOne(ctx context.Context, id int64) (*model.UserTable, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOne", ctx, id)
ret0, _ := ret[0].(*model.UserTable)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOne indicates an expected call of FindOne.
func (mr *MockUserTableModelMockRecorder) FindOne(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockUserTableModel)(nil).FindOne), ctx, id)
}
// FindOneByNickName mocks base method.
func (m *MockUserTableModel) FindOneByNickName(ctx context.Context, uid string) (*model.UserTable, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOneByNickName", ctx, uid)
ret0, _ := ret[0].(*model.UserTable)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOneByNickName indicates an expected call of FindOneByNickName.
func (mr *MockUserTableModelMockRecorder) FindOneByNickName(ctx, uid any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOneByNickName", reflect.TypeOf((*MockUserTableModel)(nil).FindOneByNickName), ctx, uid)
}
// FindOneByUid mocks base method.
func (m *MockUserTableModel) FindOneByUid(ctx context.Context, uid string) (*model.UserTable, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOneByUid", ctx, uid)
ret0, _ := ret[0].(*model.UserTable)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOneByUid indicates an expected call of FindOneByUid.
func (mr *MockUserTableModelMockRecorder) FindOneByUid(ctx, uid any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOneByUid", reflect.TypeOf((*MockUserTableModel)(nil).FindOneByUid), ctx, uid)
}
// Insert mocks base method.
func (m *MockUserTableModel) Insert(ctx context.Context, data *model.UserTable) (sql.Result, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Insert", ctx, data)
ret0, _ := ret[0].(sql.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Insert indicates an expected call of Insert.
func (mr *MockUserTableModelMockRecorder) Insert(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockUserTableModel)(nil).Insert), ctx, data)
}
// ListMembers mocks base method.
func (m *MockUserTableModel) ListMembers(ctx context.Context, params *model.UserQueryParams) ([]*model.UserTable, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "ListMembers", ctx, params)
ret0, _ := ret[0].([]*model.UserTable)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// ListMembers indicates an expected call of ListMembers.
func (mr *MockUserTableModelMockRecorder) ListMembers(ctx, params any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListMembers", reflect.TypeOf((*MockUserTableModel)(nil).ListMembers), ctx, params)
}
// Update mocks base method.
func (m *MockUserTableModel) Update(ctx context.Context, data *model.UserTable) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Update", ctx, data)
ret0, _ := ret[0].(error)
return ret0
}
// Update indicates an expected call of Update.
func (mr *MockUserTableModelMockRecorder) Update(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockUserTableModel)(nil).Update), ctx, data)
}
// UpdateSome mocks base method.
func (m *MockUserTableModel) UpdateSome(ctx context.Context, newData *member.UpdateUserInfoReq) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateSome", ctx, newData)
ret0, _ := ret[0].(error)
return ret0
}
// UpdateSome indicates an expected call of UpdateSome.
func (mr *MockUserTableModelMockRecorder) UpdateSome(ctx, newData any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateSome", reflect.TypeOf((*MockUserTableModel)(nil).UpdateSome), ctx, newData)
}
// UpdateStatus mocks base method.
func (m *MockUserTableModel) UpdateStatus(ctx context.Context, uid string, status int32) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "UpdateStatus", ctx, uid, status)
ret0, _ := ret[0].(error)
return ret0
}
// UpdateStatus indicates an expected call of UpdateStatus.
func (mr *MockUserTableModelMockRecorder) UpdateStatus(ctx, uid, status any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateStatus", reflect.TypeOf((*MockUserTableModel)(nil).UpdateStatus), ctx, uid, status)
}

View File

@ -0,0 +1,115 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./user_table_model_gen.go
//
// Generated by this command:
//
// mockgen -source=./user_table_model_gen.go -destination=../mock/model/user_table_model_gen.go -package=model
//
// Package model is a generated GoMock package.
package model
import (
context "context"
sql "database/sql"
model "member/internal/model"
reflect "reflect"
gomock "go.uber.org/mock/gomock"
)
// MockuserTableModel is a mock of userTableModel interface.
type MockuserTableModel struct {
ctrl *gomock.Controller
recorder *MockuserTableModelMockRecorder
}
// MockuserTableModelMockRecorder is the mock recorder for MockuserTableModel.
type MockuserTableModelMockRecorder struct {
mock *MockuserTableModel
}
// NewMockuserTableModel creates a new mock instance.
func NewMockuserTableModel(ctrl *gomock.Controller) *MockuserTableModel {
mock := &MockuserTableModel{ctrl: ctrl}
mock.recorder = &MockuserTableModelMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockuserTableModel) EXPECT() *MockuserTableModelMockRecorder {
return m.recorder
}
// Delete mocks base method.
func (m *MockuserTableModel) Delete(ctx context.Context, id int64) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Delete", ctx, id)
ret0, _ := ret[0].(error)
return ret0
}
// Delete indicates an expected call of Delete.
func (mr *MockuserTableModelMockRecorder) Delete(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Delete", reflect.TypeOf((*MockuserTableModel)(nil).Delete), ctx, id)
}
// FindOne mocks base method.
func (m *MockuserTableModel) FindOne(ctx context.Context, id int64) (*model.UserTable, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOne", ctx, id)
ret0, _ := ret[0].(*model.UserTable)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOne indicates an expected call of FindOne.
func (mr *MockuserTableModelMockRecorder) FindOne(ctx, id any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOne", reflect.TypeOf((*MockuserTableModel)(nil).FindOne), ctx, id)
}
// FindOneByUid mocks base method.
func (m *MockuserTableModel) FindOneByUid(ctx context.Context, uid string) (*model.UserTable, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "FindOneByUid", ctx, uid)
ret0, _ := ret[0].(*model.UserTable)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// FindOneByUid indicates an expected call of FindOneByUid.
func (mr *MockuserTableModelMockRecorder) FindOneByUid(ctx, uid any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "FindOneByUid", reflect.TypeOf((*MockuserTableModel)(nil).FindOneByUid), ctx, uid)
}
// Insert mocks base method.
func (m *MockuserTableModel) Insert(ctx context.Context, data *model.UserTable) (sql.Result, error) {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Insert", ctx, data)
ret0, _ := ret[0].(sql.Result)
ret1, _ := ret[1].(error)
return ret0, ret1
}
// Insert indicates an expected call of Insert.
func (mr *MockuserTableModelMockRecorder) Insert(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Insert", reflect.TypeOf((*MockuserTableModel)(nil).Insert), ctx, data)
}
// Update mocks base method.
func (m *MockuserTableModel) Update(ctx context.Context, data *model.UserTable) error {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Update", ctx, data)
ret0, _ := ret[0].(error)
return ret0
}
// Update indicates an expected call of Update.
func (mr *MockuserTableModelMockRecorder) Update(ctx, data any) *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Update", reflect.TypeOf((*MockuserTableModel)(nil).Update), ctx, data)
}

View File

@ -0,0 +1,68 @@
// Code generated by MockGen. DO NOT EDIT.
// Source: ./machine_node.go
//
// Generated by this command:
//
// mockgen -source=./machine_node.go -destination=../mock/svc/machine_node.go -package=svc
//
// Package svc is a generated GoMock package.
package svc
import (
reflect "reflect"
snowflake "github.com/bwmarrin/snowflake"
gomock "go.uber.org/mock/gomock"
)
// MockSnackFlow is a mock of SnackFlow interface.
type MockSnackFlow struct {
ctrl *gomock.Controller
recorder *MockSnackFlowMockRecorder
}
// MockSnackFlowMockRecorder is the mock recorder for MockSnackFlow.
type MockSnackFlowMockRecorder struct {
mock *MockSnackFlow
}
// NewMockSnackFlow creates a new mock instance.
func NewMockSnackFlow(ctrl *gomock.Controller) *MockSnackFlow {
mock := &MockSnackFlow{ctrl: ctrl}
mock.recorder = &MockSnackFlowMockRecorder{mock}
return mock
}
// EXPECT returns an object that allows the caller to indicate expected use.
func (m *MockSnackFlow) EXPECT() *MockSnackFlowMockRecorder {
return m.recorder
}
// Generate mocks base method.
func (m *MockSnackFlow) Generate() snowflake.ID {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "Generate")
ret0, _ := ret[0].(snowflake.ID)
return ret0
}
// Generate indicates an expected call of Generate.
func (mr *MockSnackFlowMockRecorder) Generate() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Generate", reflect.TypeOf((*MockSnackFlow)(nil).Generate))
}
// GetSnackFlowNode mocks base method.
func (m *MockSnackFlow) GetSnackFlowNode() *snowflake.Node {
m.ctrl.T.Helper()
ret := m.ctrl.Call(m, "GetSnackFlowNode")
ret0, _ := ret[0].(*snowflake.Node)
return ret0
}
// GetSnackFlowNode indicates an expected call of GetSnackFlowNode.
func (mr *MockSnackFlowMockRecorder) GetSnackFlowNode() *gomock.Call {
mr.mock.ctrl.T.Helper()
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetSnackFlowNode", reflect.TypeOf((*MockSnackFlow)(nil).GetSnackFlowNode))
}

View File

@ -1,6 +1,10 @@
package model package model
import ( import (
"context"
"database/sql"
"fmt"
"github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/core/stores/sqlx"
) )
@ -12,6 +16,7 @@ type (
// and implement the added methods in customAccountModel. // and implement the added methods in customAccountModel.
AccountModel interface { AccountModel interface {
accountModel accountModel
UpdateTokenByLoginID(ctx context.Context, account string, token string) error
} }
customAccountModel struct { customAccountModel struct {
@ -19,6 +24,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)
return conn.ExecCtx(ctx, query, token, data.Id)
}, accountAccountKey, accountIdKey)
return err
}
// NewAccountModel returns a model for the database table. // NewAccountModel returns a model for the database table.
func NewAccountModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) AccountModel { func NewAccountModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Option) AccountModel {
return &customAccountModel{ return &customAccountModel{

View File

@ -8,6 +8,7 @@ import (
var _ AccountToUidModel = (*customAccountToUidModel)(nil) var _ AccountToUidModel = (*customAccountToUidModel)(nil)
var ( var (
// nolint:unused
cacheAccountPrefix = "cache:accountToUid:account:" cacheAccountPrefix = "cache:accountToUid:account:"
) )

View File

@ -2,7 +2,9 @@ package model
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlc" "github.com/zeromicro/go-zero/core/stores/sqlc"
"github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/core/stores/sqlx"
@ -37,10 +39,10 @@ func (m *defaultMachineNodeModel) FindOneByHostName(ctx context.Context, hostNam
query := fmt.Sprintf("select %s from %s where `host_name` = ? limit 1", machineNodeRows, m.table) query := fmt.Sprintf("select %s from %s where `host_name` = ? limit 1", machineNodeRows, m.table)
return conn.QueryRowCtx(ctx, v, query, hostName) return conn.QueryRowCtx(ctx, v, query, hostName)
}) })
switch err { switch {
case nil: case err == nil:
return &resp, nil return &resp, nil
case sqlc.ErrNotFound: case errors.Is(err, sqlc.ErrNotFound):
return nil, ErrNotFound return nil, ErrNotFound
default: default:
return nil, err return nil, err

View File

@ -1,7 +1,15 @@
package model package model
import ( import (
"context"
"database/sql"
"fmt"
"member/gen_result/pb/member"
"strings"
"time"
"github.com/zeromicro/go-zero/core/stores/cache" "github.com/zeromicro/go-zero/core/stores/cache"
"github.com/zeromicro/go-zero/core/stores/sqlc"
"github.com/zeromicro/go-zero/core/stores/sqlx" "github.com/zeromicro/go-zero/core/stores/sqlx"
) )
@ -12,11 +20,27 @@ type (
// and implement the added methods in customUserTableModel. // and implement the added methods in customUserTableModel.
UserTableModel interface { UserTableModel interface {
userTableModel 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
UpdateSome(ctx context.Context, newData *member.UpdateUserInfoReq) error
} }
customUserTableModel struct { customUserTableModel struct {
*defaultUserTableModel *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. // NewUserTableModel returns a model for the database table.
@ -25,3 +49,173 @@ func NewUserTableModel(conn sqlx.SqlConn, c cache.CacheConf, opts ...cache.Optio
defaultUserTableModel: newUserTableModel(conn, c, opts...), 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
}
func (m *defaultUserTableModel) UpdateSome(ctx context.Context, newData *member.UpdateUserInfoReq) error {
data, err := m.FindOneByUid(ctx, newData.Uid)
if err != nil {
return err
}
// 初始化缓存键
userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, data.Id)
userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid)
query := fmt.Sprintf("update %s set ", m.table)
var args []interface{}
var updates []string
if newData.VerifyType != nil {
updates = append(updates, "verify_type = ?")
args = append(args, *newData.VerifyType)
}
if newData.AlarmType != nil {
updates = append(updates, "alarm_type = ?")
args = append(args, *newData.AlarmType)
}
if newData.Status != nil {
updates = append(updates, "status = ?")
args = append(args, *newData.Status)
}
if newData.RoleId != nil {
updates = append(updates, "role_id = ?")
args = append(args, *newData.RoleId)
}
if newData.Language != nil {
updates = append(updates, "language = ?")
args = append(args, *newData.Language)
}
if newData.Currency != nil {
updates = append(updates, "currency = ?")
args = append(args, *newData.Currency)
}
if newData.NickName != nil {
updates = append(updates, "nick_name = ?")
args = append(args, *newData.NickName)
}
if newData.Gender != nil {
updates = append(updates, "gender = ?")
args = append(args, *newData.Gender)
}
if newData.Birthday != nil {
updates = append(updates, "birthday = ?")
args = append(args, *newData.Birthday)
}
if len(updates) == 0 {
return nil
}
update := time.Now().UTC().Unix()
updates = append(updates, "update_time = ?")
args = append(args, &update)
query += strings.Join(updates, ", ") + " where `id` = ?"
args = append(args, data.Id)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) {
return conn.ExecCtx(ctx, query, args...)
}, userTableIdKey, userTableUidKey)
return err
}

View File

@ -18,14 +18,15 @@ import (
var ( var (
userTableFieldNames = builder.RawFieldNames(&UserTable{}) userTableFieldNames = builder.RawFieldNames(&UserTable{})
userTableRows = strings.Join(userTableFieldNames, ",") userTableRows = strings.Join(userTableFieldNames, ",")
userTableRowsExpectAutoSet = 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`", "`create_at`", "`create_time`", "`created_at`", "`update_at`", "`update_time`", "`updated_at`"), "=?,") + "=?" userTableRowsWithPlaceHolder = strings.Join(stringx.Remove(userTableFieldNames, "`id`"), "=?,") + "=?"
cacheUserTableIdPrefix = "cache:userTable:id:" cacheUserTableIdPrefix = "cache:userTable:id:"
cacheUserTableUidPrefix = "cache:userTable:uid:" cacheUserTableUidPrefix = "cache:userTable:uid:"
) )
type ( type (
// go:generate mockgen -source=./user_table_model_gen.go -destination=../../mock/model/user_table_model_gen.go -package=model
userTableModel interface { userTableModel interface {
Insert(ctx context.Context, data *UserTable) (sql.Result, error) Insert(ctx context.Context, data *UserTable) (sql.Result, error)
FindOne(ctx context.Context, id int64) (*UserTable, error) FindOne(ctx context.Context, id int64) (*UserTable, error)
@ -126,8 +127,8 @@ func (m *defaultUserTableModel) Insert(ctx context.Context, data *UserTable) (sq
userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, data.Id) userTableIdKey := fmt.Sprintf("%s%v", cacheUserTableIdPrefix, data.Id)
userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid) 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) { 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) 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) 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) }, userTableIdKey, userTableUidKey)
return ret, err return ret, err
} }
@ -142,7 +143,7 @@ func (m *defaultUserTableModel) Update(ctx context.Context, newData *UserTable)
userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid) userTableUidKey := fmt.Sprintf("%s%v", cacheUserTableUidPrefix, data.Uid)
_, err = m.ExecCtx(ctx, func(ctx context.Context, conn sqlx.SqlConn) (result sql.Result, err error) { _, 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) 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) }, userTableIdKey, userTableUidKey)
return err return err
} }

View File

@ -2,25 +2,36 @@ package svc
import ( import (
"context" "context"
"github.com/bwmarrin/snowflake"
sf "member/internal/lib/snackflow"
"member/internal/model" "member/internal/model"
"os" "os"
"time" "time"
"github.com/bwmarrin/snowflake"
) )
type machineNode struct { type SnackFlow interface {
MachineNodeID int64 `json:"machine_node_id"` GetSnackFlowNode() *snowflake.Node
Generate() snowflake.ID
} }
type MachineNodeCreateParams struct { type SnackFlowNode struct {
HostName string *snowflake.Node
} }
func NewMachineNode(node model.MachineNodeModel) int64 { func NewSnackFlow(node model.MachineNodeModel) (SnackFlow, error) {
nodeID := newMachineNodeID(node)
ringNodeID := getMachineNodeID(nodeID)
s, err := snowflake.NewNode(ringNodeID)
if err != nil {
return nil, err
}
return &SnackFlowNode{Node: s}, nil
}
func newMachineNodeID(node model.MachineNodeModel) int64 {
ctx := context.Background() ctx := context.Background()
nodeName := os.Getenv("POD_NAME") nodeName := os.Getenv("POD_NAME")
if os.Getenv("POD_NAME") == "" { if nodeName == "" {
nodeName = "default_node" nodeName = "default_node"
} }
@ -37,14 +48,13 @@ func NewMachineNode(node model.MachineNodeModel) int64 {
if err != nil { if err != nil {
return 1 return 1
} }
return id return id
} }
return machine.Id return machine.Id
} }
func GetMachineNodeID(machineNodeID int64) int64 { func getMachineNodeID(machineNodeID int64) int64 {
// Snowflake 公式,工作機器 ID 佔用 10bit最多容納 1024 節點, // Snowflake 公式,工作機器 ID 佔用 10bit最多容納 1024 節點,
// 故用 % 1024 取餘數做 ring // 故用 % 1024 取餘數做 ring
const nodeMax = 1024 const nodeMax = 1024
@ -52,15 +62,10 @@ func GetMachineNodeID(machineNodeID int64) int64 {
return machineNodeID % nodeMax return machineNodeID % nodeMax
} }
func newSnackFlowNode(node model.MachineNodeModel) (*snowflake.Node, error) { func (n *SnackFlowNode) GetSnackFlowNode() *snowflake.Node {
return n.Node
nodeID := NewMachineNode(node)
ringNodeID := GetMachineNodeID(nodeID)
s := sf.New(sf.WithMachineNodeID(ringNodeID))
n, err := s.NewNode()
if err != nil {
return nil, err
} }
return n, nil func (n *SnackFlowNode) Generate() snowflake.ID {
return n.Node.Generate()
} }

View File

@ -1,25 +1,27 @@
package svc package svc
import ( import (
"github.com/bwmarrin/snowflake"
"member/internal/config" "member/internal/config"
"member/internal/domain" "member/internal/domain"
"member/internal/lib/required" "member/internal/lib/required"
"member/internal/model" "member/internal/model"
"github.com/go-playground/validator/v10" "github.com/zeromicro/go-zero/core/stores/redis"
"github.com/zeromicro/go-zero/core/stores/sqlx"
ers "member/internal/lib/error" ers "member/internal/lib/error"
"github.com/zeromicro/go-zero/core/stores/sqlx"
) )
type ServiceContext struct { type ServiceContext struct {
Config config.Config Config config.Config
Validate *validator.Validate Redis redis.Redis
Validate required.Validate
AccountModel model.AccountModel AccountModel model.AccountModel
UserModel model.UserTableModel UserModel model.UserTableModel
AccountToUidModel model.AccountToUidModel AccountToUidModel model.AccountToUidModel
SnackFlowGen *snowflake.Node SnackFlowGen SnackFlow
} }
func NewServiceContext(c config.Config) *ServiceContext { func NewServiceContext(c config.Config) *ServiceContext {
@ -27,13 +29,19 @@ func NewServiceContext(c config.Config) *ServiceContext {
// 設置 // 設置
ers.Scope = domain.Scope ers.Scope = domain.Scope
n, err := newSnackFlowNode(model.NewMachineNodeModel(sqlConn, c.Cache)) n, err := NewSnackFlow(model.NewMachineNodeModel(sqlConn, c.Cache))
if err != nil {
panic(err)
}
newRedis, err := redis.NewRedis(c.RedisCluster, redis.Cluster())
if err != nil { if err != nil {
panic(err) panic(err)
} }
return &ServiceContext{ return &ServiceContext{
Config: c, Config: c,
Redis: *newRedis,
Validate: required.MustValidator(required.WithAccount("account")), Validate: required.MustValidator(required.WithAccount("account")),
UserModel: model.NewUserTableModel(sqlConn, c.Cache), UserModel: model.NewUserTableModel(sqlConn, c.Cache),
AccountToUidModel: model.NewAccountToUidModel(sqlConn, c.Cache), AccountToUidModel: model.NewAccountToUidModel(sqlConn, c.Cache),

View File

@ -35,7 +35,7 @@ func main() {
}) })
defer s.Stop() defer s.Stop()
// 加入中間件 // 加入中間件
s.AddUnaryInterceptors(middleware.TimeoutMiddleware) s.AddUnaryInterceptors(middleware.TimeoutMiddleware)
fmt.Printf("Starting rpc server at %s...\n", c.ListenOn) fmt.Printf("Starting rpc server at %s...\n", c.ListenOn)

View File

@ -5,6 +5,8 @@
goctl goctl
go get -d github.com/envoyproxy/protoc-gen-validate go get -d github.com/envoyproxy/protoc-gen-validate
mockgen -source=./validate.go -destination=../../mock/lib/validate.go -package=lib
``` ```