From 265db85e8b57058e58a3c52cbe5f6c74f1b7c556 Mon Sep 17 00:00:00 2001 From: mantre Date: Tue, 31 Dec 2024 14:05:54 +0800 Subject: [PATCH 1/2] refactor: remove database interface --- .golangci.yml | 2 + Makefile | 1 - cmd/cli/main.go | 2 +- go.mod | 2 +- internal/delivery/grpc/pagu.go | 2 +- internal/delivery/http/http.go | 2 +- internal/engine/command/command.go | 4 +- internal/engine/command/middleware.go | 4 +- internal/engine/command/phoenix/faucet.go | 8 +- internal/engine/command/phoenix/phoenix.go | 4 +- internal/engine/command/phoenix/wallet.go | 7 +- internal/engine/command/voucher/claim_test.go | 109 +++---- .../engine/command/voucher/create_test.go | 100 ++---- internal/engine/command/voucher/status.go | 2 +- .../engine/command/voucher/status_test.go | 102 +----- internal/engine/command/voucher/voucher.go | 14 +- .../engine/command/voucher/voucher_test.go | 104 ++++++ internal/engine/command/zealy/claim.go | 4 +- internal/engine/command/zealy/zealy.go | 10 +- internal/engine/engine.go | 12 +- internal/entity/application.go | 42 +-- internal/entity/faucet.go | 12 +- internal/entity/model.go | 13 + internal/entity/notification.go | 10 +- internal/entity/user.go | 20 +- internal/entity/validator.go | 20 -- internal/entity/voucher.go | 12 +- internal/entity/zealy.go | 7 +- internal/job/notification.go | 4 +- internal/platforms/discord/discord.go | 4 +- internal/platforms/telegram/telegram.go | 4 +- internal/repository/database.go | 4 +- internal/repository/faucet.go | 9 +- internal/repository/interface.go | 10 - internal/repository/mock.go | 300 ------------------ internal/repository/notification.go | 12 +- internal/repository/user.go | 14 +- internal/repository/validator.go | 29 -- internal/repository/voucher.go | 15 +- internal/repository/zealy.go | 15 +- internal/testsuite/testsuite.go | 7 + 41 files changed, 310 insertions(+), 748 deletions(-) create mode 100644 internal/engine/command/voucher/voucher_test.go create mode 100644 internal/entity/model.go delete mode 100644 internal/entity/validator.go delete mode 100644 internal/repository/interface.go delete mode 100644 internal/repository/mock.go delete mode 100644 internal/repository/validator.go diff --git a/.golangci.yml b/.golangci.yml index 67fb008e..3f8aabc3 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -193,6 +193,8 @@ linters-settings: - ok - ip - no + - td # test_data + - ts # test_suite - db - tt # table tests - i # i *discordgo.InteractionCreate diff --git a/Makefile b/Makefile index 7ddabc68..3dfdfe75 100644 --- a/Makefile +++ b/Makefile @@ -11,7 +11,6 @@ devtools: mock: mockgen -source=./pkg/client/interface.go -destination=./pkg/client/mock.go -package=client mockgen -source=./pkg/wallet/interface.go -destination=./pkg/wallet/mock.go -package=wallet - mockgen -source=./internal/repository/interface.go -destination=./internal/repository/mock.go -package=repository ### proto file generate proto: diff --git a/cmd/cli/main.go b/cmd/cli/main.go index a632a88d..8c7e2968 100644 --- a/cmd/cli/main.go +++ b/cmd/cli/main.go @@ -49,7 +49,7 @@ func run(cmd *cobra.Command, _ []string) { return } - response := botEngine.ParseAndExecute(entity.AppIDCLI, "0", input) + response := botEngine.ParseAndExecute(entity.PlatformIDCLI, "0", input) cmd.Printf("%v\n%v", response.Title, response.Message) } diff --git a/go.mod b/go.mod index d30272bd..21bf0d44 100644 --- a/go.mod +++ b/go.mod @@ -13,7 +13,6 @@ require ( github.com/spf13/cobra v1.8.1 github.com/stretchr/testify v1.10.0 go.uber.org/mock v0.5.0 - golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 golang.org/x/text v0.21.0 google.golang.org/grpc v1.69.2 google.golang.org/protobuf v1.36.1 @@ -58,6 +57,7 @@ require ( github.com/valyala/fasttemplate v1.2.2 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/crypto v0.31.0 // indirect + golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect golang.org/x/net v0.33.0 // indirect golang.org/x/sys v0.28.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20241223144023-3abc09e42ca8 // indirect diff --git a/internal/delivery/grpc/pagu.go b/internal/delivery/grpc/pagu.go index a15bec73..55230ccc 100644 --- a/internal/delivery/grpc/pagu.go +++ b/internal/delivery/grpc/pagu.go @@ -18,7 +18,7 @@ func newPaguServer(server *Server) *paguServer { } func (ps *paguServer) Run(_ context.Context, req *pagu.RunRequest) (*pagu.RunResponse, error) { - res := ps.engine.ParseAndExecute(entity.AppIDgRPC, req.Id, req.Command) + res := ps.engine.ParseAndExecute(entity.PlatformIDWeb, req.Id, req.Command) return &pagu.RunResponse{ Response: res.Message, diff --git a/internal/delivery/http/http.go b/internal/delivery/http/http.go index 920a5776..b445af61 100644 --- a/internal/delivery/http/http.go +++ b/internal/delivery/http/http.go @@ -51,7 +51,7 @@ func (hh *HTTPHandler) Run(ctx echo.Context) error { return err } - cmdResult := hh.engine.ParseAndExecute(entity.AppIDHTTP, ctx.RealIP(), r.Command) + cmdResult := hh.engine.ParseAndExecute(entity.PlatformIDReserved, ctx.RealIP(), r.Command) return ctx.JSON(http.StatusOK, RunResponse{ Result: cmdResult.Message, diff --git a/internal/engine/command/command.go b/internal/engine/command/command.go index cf9d610f..22cdcd0b 100644 --- a/internal/engine/command/command.go +++ b/internal/engine/command/command.go @@ -45,7 +45,7 @@ type Command struct { Name string Help string Args []Args // should be nil for commands. - AppIDs []entity.AppID + AppIDs []entity.PlatformID SubCommands []*Command Middlewares []MiddlewareFunc Handler HandlerFunc @@ -100,7 +100,7 @@ func (cmd *Command) HelpResult() CommandResult { } } -func (cmd *Command) HasAppID(appID entity.AppID) bool { +func (cmd *Command) HasAppID(appID entity.PlatformID) bool { return slices.Contains(cmd.AppIDs, appID) } diff --git a/internal/engine/command/middleware.go b/internal/engine/command/middleware.go index da3c91f4..eaf7cde2 100644 --- a/internal/engine/command/middleware.go +++ b/internal/engine/command/middleware.go @@ -9,11 +9,11 @@ import ( type MiddlewareFunc func(caller *entity.User, cmd *Command, args map[string]string) error type MiddlewareHandler struct { - db repository.IDatabase + db *repository.Database wallet wallet.IWallet } -func NewMiddlewareHandler(d repository.IDatabase, w wallet.IWallet) *MiddlewareHandler { +func NewMiddlewareHandler(d *repository.Database, w wallet.IWallet) *MiddlewareHandler { return &MiddlewareHandler{ db: d, wallet: w, diff --git a/internal/engine/command/phoenix/faucet.go b/internal/engine/command/phoenix/faucet.go index 1f84a9e1..2310e0b8 100644 --- a/internal/engine/command/phoenix/faucet.go +++ b/internal/engine/command/phoenix/faucet.go @@ -31,10 +31,10 @@ func (pt *Phoenix) faucetHandler( } if err = pt.db.AddFaucet(&entity.PhoenixFaucet{ - UserID: caller.ID, - Address: toAddr, - Amount: pt.faucetAmount, - TransactionHash: txHash, + UserID: caller.ID, + Address: toAddr, + Amount: pt.faucetAmount, + TxHash: txHash, }); err != nil { return cmd.ErrorResult(err) } diff --git a/internal/engine/command/phoenix/phoenix.go b/internal/engine/command/phoenix/phoenix.go index ae7556bc..86bdd111 100644 --- a/internal/engine/command/phoenix/phoenix.go +++ b/internal/engine/command/phoenix/phoenix.go @@ -25,13 +25,13 @@ const ( type Phoenix struct { ctx context.Context wallet wallet.IWallet - db repository.IDatabase + db *repository.Database clientMgr client.IManager faucetAmount amount.Amount } func NewPhoenix(ctx context.Context, wlt wallet.IWallet, faucetAmount amount.Amount, - clientMgr client.IManager, db repository.IDatabase, + clientMgr client.IManager, db *repository.Database, ) *Phoenix { return &Phoenix{ ctx: ctx, diff --git a/internal/engine/command/phoenix/wallet.go b/internal/engine/command/phoenix/wallet.go index b6b8c877..8c54be5d 100644 --- a/internal/engine/command/phoenix/wallet.go +++ b/internal/engine/command/phoenix/wallet.go @@ -6,6 +6,9 @@ import ( ) //nolint:unused // remove me after I am used -func (pt *Phoenix) walletHandler(cmd *command.Command, _ entity.AppID, _ string, _ ...string) command.CommandResult { - return cmd.SuccessfulResultF("Pagu Phoenix Address: %s\nBalance: %d", pt.wallet.Address(), pt.wallet.Balance()) +func (pt *Phoenix) walletHandler(cmd *command.Command, + _ entity.PlatformID, _ string, _ ...string, +) command.CommandResult { + return cmd.SuccessfulResultF( + "Pagu Phoenix Address: %s\nBalance: %d", pt.wallet.Address(), pt.wallet.Balance()) } diff --git a/internal/engine/command/voucher/claim_test.go b/internal/engine/command/voucher/claim_test.go index 2522dbcd..867c904d 100644 --- a/internal/engine/command/voucher/claim_test.go +++ b/internal/engine/command/voucher/claim_test.go @@ -1,103 +1,70 @@ package voucher import ( - "errors" "testing" "github.com/pagu-project/pagu/internal/engine/command" "github.com/pagu-project/pagu/internal/entity" - "github.com/pagu-project/pagu/pkg/amount" "github.com/stretchr/testify/assert" + "go.uber.org/mock/gomock" ) -func TestClaimNormal(t *testing.T) { - voucher, db, client, wallet := setup(t) +func TestClaim(t *testing.T) { + td := setup(t) - validatorAddr := "pc1p123" - t.Run("normal", func(t *testing.T) { - amt, _ := amount.NewAmount(100) - db.EXPECT().GetVoucherByCode("12345678").Return( - entity.Voucher{ - ValidMonths: 1, - Amount: amt, - ID: 1, - }, nil, - ).AnyTimes() + voucherCode := "12345678" + caller := &entity.User{DBModel: entity.DBModel{ID: 1}} + cmd := &command.Command{} + + t.Run("Invalid Voucher Code", func(t *testing.T) { + args := make(map[string]string) + args["code"] = "0" + args["address"] = "pc1z" + result := td.voucherCmd.claimHandler(caller, cmd, args) + assert.False(t, result.Successful) + assert.Equal(t, result.Message, "An error occurred: voucher code is not valid, length must be 8") + }) - client.EXPECT().GetValidatorInfo(validatorAddr).Return( + t.Run("Voucher Code Not Issued Yet", func(t *testing.T) { + args := make(map[string]string) + args["code"] = voucherCode + args["address"] = "pc1z" + result := td.voucherCmd.claimHandler(caller, cmd, args) + assert.False(t, result.Successful) + assert.Equal(t, result.Message, "An error occurred: voucher code is not valid, no voucher found") + }) + + t.Run("Claim a Voucher", func(t *testing.T) { + testVoucher := td.createTestVoucher(t, WithCode(voucherCode)) + validatorAddr := "pc1p123" + + td.clientManager.EXPECT().GetValidatorInfo(validatorAddr).Return( nil, nil, ).AnyTimes() - client.EXPECT().FindPublicKey(validatorAddr, false).Return( + td.clientManager.EXPECT().FindPublicKey(validatorAddr, false).Return( validatorAddr, nil, ).AnyTimes() - wallet.EXPECT().BondTransaction(validatorAddr, validatorAddr, "voucher 12345678 claimed by Pagu", amt).Return( + td.wallet.EXPECT().BondTransaction(gomock.Any(), validatorAddr, + "voucher 12345678 claimed by Pagu", testVoucher.Amount).Return( "0x1", nil, ).AnyTimes() - db.EXPECT().ClaimVoucher(uint(1), "0x1", uint(1)).Return( - nil, - ).AnyTimes() - - cmd := &command.Command{} - caller := &entity.User{ID: 1} - args := make(map[string]string) - args["code"] = "12345678" + args["code"] = testVoucher.Code args["address"] = validatorAddr - result := voucher.claimHandler(caller, cmd, args) + result := td.voucherCmd.claimHandler(caller, cmd, args) assert.True(t, result.Successful) assert.Equal(t, result.Message, "Voucher claimed successfully!\n\n https://pacviewer.com/transaction/0x1") }) - t.Run("wrong code", func(t *testing.T) { - cmd := &command.Command{} - caller := &entity.User{ID: 1} - + t.Run("Claim again", func(t *testing.T) { args := make(map[string]string) - args["code"] = "0" + args["code"] = voucherCode args["address"] = "pc1z" - result := voucher.claimHandler(caller, cmd, args) + result := td.voucherCmd.claimHandler(caller, cmd, args) assert.False(t, result.Successful) - assert.Equal(t, result.Message, "An error occurred: voucher code is not valid, length must be 8") + assert.Equal(t, result.Message, "An error occurred: voucher code claimed before") }) } - -func TestClaimNotFound(t *testing.T) { - voucher, db, _, _ := setup(t) - - db.EXPECT().GetVoucherByCode("12345678").Return( - entity.Voucher{}, errors.New(""), - ).AnyTimes() - - cmd := &command.Command{} - caller := &entity.User{ID: 1} - - args := make(map[string]string) - args["code"] = "12345678" - args["address"] = "pc1z" - result := voucher.claimHandler(caller, cmd, args) - assert.False(t, result.Successful) - assert.Equal(t, result.Message, "An error occurred: voucher code is not valid, no voucher found") -} - -func TestClaimAlreadyClaimed(t *testing.T) { - voucher, db, _, _ := setup(t) - - db.EXPECT().GetVoucherByCode("12345678").Return( - entity.Voucher{ - TxHash: "123456789", - }, nil, - ).AnyTimes() - - cmd := &command.Command{} - caller := &entity.User{ID: 1} - - args := make(map[string]string) - args["code"] = "12345678" - args["address"] = "pc1z" - result := voucher.claimHandler(caller, cmd, args) - assert.False(t, result.Successful) - assert.Equal(t, result.Message, "An error occurred: voucher code claimed before") -} diff --git a/internal/engine/command/voucher/create_test.go b/internal/engine/command/voucher/create_test.go index 74e2c596..3f273e35 100644 --- a/internal/engine/command/voucher/create_test.go +++ b/internal/engine/command/voucher/create_test.go @@ -1,112 +1,64 @@ package voucher import ( - "errors" "testing" "github.com/h2non/gock" "github.com/pagu-project/pagu/internal/engine/command" "github.com/pagu-project/pagu/internal/entity" - "github.com/pagu-project/pagu/internal/repository" - "github.com/pagu-project/pagu/pkg/client" - "github.com/pagu-project/pagu/pkg/wallet" "github.com/stretchr/testify/assert" - "go.uber.org/mock/gomock" ) -func setup(t *testing.T) (*Voucher, repository.MockIDatabase, client.MockIManager, wallet.MockIWallet) { - t.Helper() - - ctrl := gomock.NewController(t) - - mockDB := repository.NewMockIDatabase(ctrl) - mockClient := client.NewMockIManager(ctrl) - mockWallet := wallet.NewMockIWallet(ctrl) - - mockVoucher := NewVoucher(mockDB, mockWallet, mockClient) - - return mockVoucher, *mockDB, *mockClient, *mockWallet -} - func TestCreateOne(t *testing.T) { - voucher, db, _, _ := setup(t) - - t.Run("normal", func(t *testing.T) { - db.EXPECT().GetVoucherByCode(gomock.Any()).Return( - entity.Voucher{}, errors.New(""), - ).AnyTimes() + td := setup(t) - db.EXPECT().AddVoucher(gomock.Any()).Return(nil).AnyTimes() - - cmd := &command.Command{} - caller := &entity.User{ID: 1} - - args := make(map[string]string) - args["amount"] = "100" - args["valid-months"] = "1" - result := voucher.createOneHandler(caller, cmd, args) - assert.True(t, result.Successful) - assert.Contains(t, result.Message, "Voucher created successfully!") - }) + cmd := &command.Command{} + caller := &entity.User{DBModel: entity.DBModel{ID: 1}} t.Run("more than 1000 PAC", func(t *testing.T) { - db.EXPECT().GetVoucherByCode(gomock.Any()).Return( - entity.Voucher{}, errors.New(""), - ).AnyTimes() - - db.EXPECT().AddVoucher(gomock.Any()).Return(nil).AnyTimes() - - cmd := &command.Command{} - caller := &entity.User{ID: 1} - args := make(map[string]string) args["amount"] = "1001" args["valid-months"] = "1" - result := voucher.createOneHandler(caller, cmd, args) + result := td.voucherCmd.createOneHandler(caller, cmd, args) assert.False(t, result.Successful) assert.Contains(t, result.Message, "stake amount is more than 1000") }) t.Run("wrong month", func(t *testing.T) { - db.EXPECT().GetVoucherByCode(gomock.Any()).Return( - entity.Voucher{}, errors.New(""), - ).AnyTimes() - - db.EXPECT().AddVoucher(gomock.Any()).Return(nil).AnyTimes() - - cmd := &command.Command{} - caller := &entity.User{ID: 1} - args := make(map[string]string) args["amount"] = "100" args["valid-months"] = "1.1" - result := voucher.createOneHandler(caller, cmd, args) + result := td.voucherCmd.createOneHandler(caller, cmd, args) assert.False(t, result.Successful) }) - t.Run("normal with optional arguments", func(t *testing.T) { - db.EXPECT().GetVoucherByCode(gomock.Any()).Return( - entity.Voucher{}, errors.New(""), - ).AnyTimes() - - db.EXPECT().AddVoucher(gomock.Any()).Return(nil).AnyTimes() - - cmd := &command.Command{} - caller := &entity.User{ID: 1} + t.Run("normal", func(t *testing.T) { + args := make(map[string]string) + args["amount"] = "100" + args["valid-months"] = "1" + result := td.voucherCmd.createOneHandler(caller, cmd, args) + assert.True(t, result.Successful) + assert.Contains(t, result.Message, "Voucher created successfully!") + }) + t.Run("normal with optional arguments", func(t *testing.T) { args := make(map[string]string) args["amount"] = "100" args["valid-months"] = "12" args["recipient"] = "Kayhan" args["description"] = "Testnet node" - result := voucher.createOneHandler(caller, cmd, args) + result := td.voucherCmd.createOneHandler(caller, cmd, args) assert.True(t, result.Successful) assert.Contains(t, result.Message, "Voucher created successfully!") }) } func TestCreateBulk(t *testing.T) { - voucher, db, _, _ := setup(t) + td := setup(t) + + cmd := &command.Command{} + caller := &entity.User{DBModel: entity.DBModel{ID: 1}} + t.Run("normal", func(t *testing.T) { defer gock.Off() gock.New("http://foo.com"). @@ -116,19 +68,11 @@ func TestCreateBulk(t *testing.T) { "foo.bar,a@gmail.com,1,2,Some Descriptions\n" + "foo.bar,b@gmail.com,1,2,Some Descriptions") - cmd := &command.Command{} - - db.EXPECT().AddVoucher(gomock.Any()).Return(nil).AnyTimes() - db.EXPECT().AddNotification(gomock.Any()).Return(nil).AnyTimes() - db.EXPECT().GetVoucherByCode(gomock.Any()).Return( - entity.Voucher{}, errors.New(""), - ).AnyTimes() - args := make(map[string]string) args["file"] = "http://foo.com/bar" args["notify"] = "TRUE" - caller := &entity.User{ID: 1} - result := voucher.createBulkHandler(caller, cmd, args) + + result := td.voucherCmd.createBulkHandler(caller, cmd, args) assert.True(t, result.Successful) assert.Contains(t, result.Message, "Vouchers created successfully!") diff --git a/internal/engine/command/voucher/status.go b/internal/engine/command/voucher/status.go index 01873201..0aa60e48 100644 --- a/internal/engine/command/voucher/status.go +++ b/internal/engine/command/voucher/status.go @@ -73,7 +73,7 @@ func (v *Voucher) statusAllVouchers(cmd *command.Command) command.CommandResult } } - return cmd.SuccessfulResultF("Total Codes: %d\nTotal Amount: %s\n\n\n"+ + return cmd.SuccessfulResultF("Total Vouchers: %d\nTotal Amount: %s\n\n\n"+ "Claimed: %d\nTotal Claimed Amount: %s\nTotal Expired: %d"+ "\n", total, diff --git a/internal/engine/command/voucher/status_test.go b/internal/engine/command/voucher/status_test.go index 8ef9169d..b538e3a4 100644 --- a/internal/engine/command/voucher/status_test.go +++ b/internal/engine/command/voucher/status_test.go @@ -1,118 +1,50 @@ package voucher import ( - "errors" - "fmt" "testing" "time" "github.com/pagu-project/pagu/internal/engine/command" "github.com/pagu-project/pagu/internal/entity" - "github.com/pagu-project/pagu/pkg/amount" "github.com/stretchr/testify/assert" - "gorm.io/gorm" ) func TestStatusNormal(t *testing.T) { - voucher, db, _, _ := setup(t) + td := setup(t) - t.Run("one code status normal", func(t *testing.T) { - now := time.Now() - validMonths := uint8(2) - voucherAmount, _ := amount.NewAmount(100) - - db.EXPECT().GetVoucherByCode("12345678").Return( - entity.Voucher{ - ID: 1, - Code: "12345678", - Desc: "some_desc", - Recipient: "some_recipient", - ValidMonths: validMonths, - Amount: voucherAmount, - TxHash: "some_transaction_hash", - ClaimedBy: 0, - Model: gorm.Model{ - CreatedAt: now, - }, - }, nil, - ).AnyTimes() + cmd := &command.Command{} + caller := &entity.User{DBModel: entity.DBModel{ID: 1}} - expTime := now.AddDate(0, int(validMonths), 0).Format("02/01/2006, 15:04:05") - - cmd := &command.Command{} - caller := &entity.User{ID: 1} + voucherCode := "12345678" + testVoucher := td.createTestVoucher(t, WithCode(voucherCode), WithAmount(100e9)) + t.Run("one code status normal", func(t *testing.T) { args := make(map[string]string) - args["code"] = "12345678" - result := voucher.statusHandler(caller, cmd, args) + args["code"] = voucherCode + result := td.voucherCmd.statusHandler(caller, cmd, args) assert.True(t, result.Successful) - assert.Equal(t, result.Message, fmt.Sprintf("Code: 12345678\nAmount: 100 PAC\n"+ - "Expire At: %s\nRecipient: some_recipient\nDescription: some_desc\nClaimed: YES\n"+ - "Tx Link: https://pacviewer.com/transaction/some_transaction_hash"+ - "\n", expTime)) + assert.Contains(t, result.Message, "Code: 12345678") + assert.Contains(t, result.Message, testVoucher.Recipient) }) t.Run("wrong code", func(t *testing.T) { - db.EXPECT().GetVoucherByCode("000").Return( - entity.Voucher{}, errors.New(""), - ).AnyTimes() - - cmd := &command.Command{} - caller := &entity.User{ID: 1} - args := make(map[string]string) args["code"] = "000" - result := voucher.statusHandler(caller, cmd, args) + result := td.voucherCmd.statusHandler(caller, cmd, args) assert.False(t, result.Successful) assert.Equal(t, result.Message, "An error occurred: voucher code is not valid, no voucher found") }) t.Run("list vouchers status normal", func(t *testing.T) { - now := time.Now() - validMonths := uint8(2) - voucherAmount, _ := amount.NewAmount(100) - - db.EXPECT().ListVoucher().Return( - []*entity.Voucher{ - { - ID: 1, - Code: "code1", - ValidMonths: validMonths, - Amount: voucherAmount, - TxHash: "some_transaction_hash", - Model: gorm.Model{ - CreatedAt: now, - }, - }, - { - ID: 2, - Code: "code2", - ValidMonths: validMonths, - Amount: voucherAmount, - Model: gorm.Model{ - CreatedAt: now, - }, - }, - { - ID: 3, - Code: "code3", - ValidMonths: validMonths, - Amount: voucherAmount, - Model: gorm.Model{ - CreatedAt: now.AddDate(0, -3, 0), - }, - }, - }, nil, - ).AnyTimes() - - cmd := &command.Command{} - caller := &entity.User{ID: 1} + td.createTestVoucher(t, WithAmount(50e9), WithTxHash("claimed_tx_hash")) + td.createTestVoucher(t, WithAmount(20e9), WithValidMonths(1), + WithCreatedAt(time.Now().AddDate(0, -2, 0))) args := make(map[string]string) - result := voucher.statusHandler(caller, cmd, args) + result := td.voucherCmd.statusHandler(caller, cmd, args) assert.True(t, result.Successful) - assert.Equal(t, result.Message, "Total Codes: 3\nTotal Amount: 300 PAC\n\n\n"+ - "Claimed: 1\nTotal Claimed Amount: 100 PAC\nTotal Expired: 1"+ + assert.Equal(t, result.Message, "Total Vouchers: 3\nTotal Amount: 170 PAC\n\n\n"+ + "Claimed: 1\nTotal Claimed Amount: 50 PAC\nTotal Expired: 1"+ "\n") }) } diff --git a/internal/engine/command/voucher/voucher.go b/internal/engine/command/voucher/voucher.go index 81d00245..d7d4580b 100644 --- a/internal/engine/command/voucher/voucher.go +++ b/internal/engine/command/voucher/voucher.go @@ -18,12 +18,12 @@ const ( ) type Voucher struct { - db repository.IDatabase + db *repository.Database wallet wallet.IWallet clientManager client.IManager } -func NewVoucher(db repository.IDatabase, wlt wallet.IWallet, cli client.IManager) *Voucher { +func NewVoucher(db *repository.Database, wlt wallet.IWallet, cli client.IManager) *Voucher { return &Voucher{ db: db, wallet: wlt, @@ -52,7 +52,7 @@ func (v *Voucher) GetCommand() *command.Command { }, }, SubCommands: nil, - AppIDs: []entity.AppID{entity.AppIDDiscord}, + AppIDs: []entity.PlatformID{entity.PlatformIDDiscord}, Middlewares: []command.MiddlewareFunc{middlewareHandler.WalletBalance}, Handler: v.claimHandler, TargetFlag: command.TargetMaskMainnet, @@ -88,7 +88,7 @@ func (v *Voucher) GetCommand() *command.Command { }, }, SubCommands: nil, - AppIDs: []entity.AppID{entity.AppIDDiscord}, + AppIDs: []entity.PlatformID{entity.PlatformIDDiscord}, Middlewares: []command.MiddlewareFunc{middlewareHandler.OnlyModerator}, Handler: v.createOneHandler, TargetFlag: command.TargetMaskModerator, @@ -112,7 +112,7 @@ func (v *Voucher) GetCommand() *command.Command { }, }, SubCommands: nil, - AppIDs: []entity.AppID{entity.AppIDDiscord}, + AppIDs: []entity.PlatformID{entity.PlatformIDDiscord}, Middlewares: []command.MiddlewareFunc{middlewareHandler.OnlyModerator}, Handler: v.createBulkHandler, TargetFlag: command.TargetMaskModerator, @@ -130,7 +130,7 @@ func (v *Voucher) GetCommand() *command.Command { }, }, SubCommands: nil, - AppIDs: []entity.AppID{entity.AppIDDiscord}, + AppIDs: []entity.PlatformID{entity.PlatformIDDiscord}, Middlewares: []command.MiddlewareFunc{middlewareHandler.OnlyModerator}, Handler: v.statusHandler, TargetFlag: command.TargetMaskModerator, @@ -140,7 +140,7 @@ func (v *Voucher) GetCommand() *command.Command { Name: CommandName, Help: "Voucher Commands", Args: nil, - AppIDs: []entity.AppID{entity.AppIDDiscord}, + AppIDs: []entity.PlatformID{entity.PlatformIDDiscord}, SubCommands: make([]*command.Command, 0), Handler: nil, TargetFlag: command.TargetMaskMainnet | command.TargetMaskModerator, diff --git a/internal/engine/command/voucher/voucher_test.go b/internal/engine/command/voucher/voucher_test.go new file mode 100644 index 00000000..405bde6d --- /dev/null +++ b/internal/engine/command/voucher/voucher_test.go @@ -0,0 +1,104 @@ +package voucher + +import ( + "testing" + "time" + + "github.com/pagu-project/pagu/internal/entity" + "github.com/pagu-project/pagu/internal/repository" + "github.com/pagu-project/pagu/internal/testsuite" + "github.com/pagu-project/pagu/pkg/amount" + "github.com/pagu-project/pagu/pkg/client" + "github.com/pagu-project/pagu/pkg/wallet" + "github.com/stretchr/testify/require" + "go.uber.org/mock/gomock" +) + +type testData struct { + *testsuite.TestSuite + + voucherCmd *Voucher + database *repository.Database + clientManager *client.MockIManager + wallet *wallet.MockIWallet +} + +func setup(t *testing.T) *testData { + t.Helper() + + ts := testsuite.NewTestSuite(t) + ctrl := gomock.NewController(t) + + testDB := ts.MakeTestDB() + mockClientManager := client.NewMockIManager(ctrl) + mockWallet := wallet.NewMockIWallet(ctrl) + + voucher := NewVoucher(testDB, mockWallet, mockClientManager) + + return &testData{ + TestSuite: ts, + voucherCmd: voucher, + database: testDB, + clientManager: mockClientManager, + wallet: mockWallet, + } +} + +type VoucherOption func(*entity.Voucher) + +func WithCode(code string) VoucherOption { + return func(v *entity.Voucher) { + v.Code = code + } +} + +func WithAmount(amt amount.Amount) VoucherOption { + return func(v *entity.Voucher) { + v.Amount = amt + } +} + +func WithTxHash(txHash string) VoucherOption { + return func(v *entity.Voucher) { + v.TxHash = txHash + } +} + +func WithValidMonths(validMonths uint8) VoucherOption { + return func(v *entity.Voucher) { + v.ValidMonths = validMonths + } +} + +func WithCreatedAt(createdAt time.Time) VoucherOption { + return func(v *entity.Voucher) { + v.CreatedAt = createdAt + } +} + +func WithRecipient(recipient string) VoucherOption { + return func(v *entity.Voucher) { + v.Recipient = recipient + } +} + +func (td *testData) createTestVoucher(t *testing.T, opts ...VoucherOption) *entity.Voucher { + t.Helper() + + voucher := &entity.Voucher{ + ValidMonths: 1, + Amount: td.RandAmount(), + Creator: uint(td.RandInt(100)), + Code: td.RandString(8), + } + + // Apply options + for _, opt := range opts { + opt(voucher) + } + + err := td.database.AddVoucher(voucher) + require.NoError(t, err) + + return voucher +} diff --git a/internal/engine/command/zealy/claim.go b/internal/engine/command/zealy/claim.go index d3321854..af63f235 100644 --- a/internal/engine/command/zealy/claim.go +++ b/internal/engine/command/zealy/claim.go @@ -9,7 +9,7 @@ import ( ) func (z *Zealy) claimHandler(caller *entity.User, cmd *command.Command, args map[string]string) command.CommandResult { - user, err := z.db.GetZealyUser(caller.CallerID) + user, err := z.db.GetZealyUser(caller.UserID) if err != nil { return cmd.ErrorResult(err) } @@ -28,7 +28,7 @@ func (z *Zealy) claimHandler(caller *entity.User, cmd *command.Command, args map return cmd.ErrorResult(transferErr) } - if err = z.db.UpdateZealyUser(caller.CallerID, txHash); err != nil { + if err = z.db.UpdateZealyUser(caller.UserID, txHash); err != nil { return cmd.ErrorResult(err) } diff --git a/internal/engine/command/zealy/zealy.go b/internal/engine/command/zealy/zealy.go index ae42ba67..5d8bdd82 100644 --- a/internal/engine/command/zealy/zealy.go +++ b/internal/engine/command/zealy/zealy.go @@ -15,11 +15,11 @@ const ( ) type Zealy struct { - db repository.IDatabase + db *repository.Database wallet wallet.IWallet } -func NewZealy(db repository.IDatabase, wlt wallet.IWallet) *Zealy { +func NewZealy(db *repository.Database, wlt wallet.IWallet) *Zealy { return &Zealy{ db: db, wallet: wlt, @@ -39,7 +39,7 @@ func (z *Zealy) GetCommand() *command.Command { }, }, SubCommands: nil, - AppIDs: []entity.AppID{entity.AppIDDiscord}, + AppIDs: []entity.PlatformID{entity.PlatformIDDiscord}, Handler: z.claimHandler, TargetFlag: command.TargetMaskMainnet, } @@ -49,7 +49,7 @@ func (z *Zealy) GetCommand() *command.Command { Help: "Status of Zealy reward claims", Args: nil, SubCommands: nil, - AppIDs: []entity.AppID{entity.AppIDDiscord}, + AppIDs: []entity.PlatformID{entity.PlatformIDDiscord}, Handler: z.statusHandler, TargetFlag: command.TargetMaskModerator, } @@ -58,7 +58,7 @@ func (z *Zealy) GetCommand() *command.Command { Name: CommandName, Help: "Zealy Commands", Args: nil, - AppIDs: []entity.AppID{entity.AppIDDiscord}, + AppIDs: []entity.PlatformID{entity.PlatformIDDiscord}, SubCommands: make([]*command.Command, 0), Handler: nil, TargetFlag: command.TargetMaskMainnet | command.TargetMaskModerator, diff --git a/internal/engine/engine.go b/internal/engine/engine.go index 02784d27..0939e59d 100644 --- a/internal/engine/engine.go +++ b/internal/engine/engine.go @@ -32,7 +32,7 @@ type BotEngine struct { cancel context.CancelFunc clientMgr client.IManager - db repository.IDatabase + db *repository.Database rootCmd *command.Command // commands @@ -129,7 +129,7 @@ func (be *BotEngine) RegisterAllCommands() { // ParseAndExecute parses the input string and executes it. // It returns an error if parsing fails or execution is unsuccessful. func (be *BotEngine) ParseAndExecute( - appID entity.AppID, + appID entity.PlatformID, callerID string, input string, ) command.CommandResult { @@ -186,7 +186,7 @@ func parseCommand(input string) ([]string, map[string]string, error) { // executeCommand executes the parsed commands with their corresponding arguments. // It returns an error if the execution fails. func (be *BotEngine) executeCommand( - appID entity.AppID, + appID entity.PlatformID, callerID string, commands []string, args map[string]string, @@ -276,12 +276,12 @@ func (be *BotEngine) NetworkStatus() (*network.NetStatus, error) { }, nil } -func (be *BotEngine) GetUser(appID entity.AppID, callerID string) (*entity.User, error) { +func (be *BotEngine) GetUser(appID entity.PlatformID, callerID string) (*entity.User, error) { if u, _ := be.db.GetUserByApp(appID, callerID); u != nil { return u, nil } - user := &entity.User{ApplicationID: appID, CallerID: callerID} + user := &entity.User{PlatformID: appID, UserID: callerID} if err := be.db.AddUser(user); err != nil { return nil, err } @@ -304,7 +304,7 @@ func (be *BotEngine) Start() { func newBotEngine(ctx context.Context, cancel context.CancelFunc, - db repository.IDatabase, + db *repository.Database, mgr client.IManager, wlt wallet.IWallet, phoenixFaucetAmount amount.Amount, diff --git a/internal/entity/application.go b/internal/entity/application.go index 2f8e9dd0..de049400 100644 --- a/internal/entity/application.go +++ b/internal/entity/application.go @@ -1,38 +1,38 @@ package entity -type AppID int +type PlatformID int const ( - AppIDCLI AppID = 1 - AppIDDiscord AppID = 2 - AppIDgRPC AppID = 3 - AppIDHTTP AppID = 4 - AppIDTelegram AppID = 5 + PlatformIDCLI PlatformID = 1 + PlatformIDDiscord PlatformID = 2 + PlatformIDWeb PlatformID = 3 + PlatformIDReserved PlatformID = 4 + PlatformIDTelegram PlatformID = 5 ) -func (appID AppID) String() string { +func (appID PlatformID) String() string { switch appID { - case AppIDCLI: + case PlatformIDCLI: return "CLI" - case AppIDDiscord: + case PlatformIDDiscord: return "Discord" - case AppIDgRPC: - return "gRPC" - case AppIDHTTP: - return "HTTP" - case AppIDTelegram: + case PlatformIDWeb: + return "Web" + case PlatformIDReserved: + return "Reserved" + case PlatformIDTelegram: return "Telegram" } return "" } -func AllAppIDs() []AppID { - return []AppID{ - AppIDCLI, - AppIDDiscord, - AppIDgRPC, - AppIDHTTP, - AppIDTelegram, +func AllAppIDs() []PlatformID { + return []PlatformID{ + PlatformIDCLI, + PlatformIDDiscord, + PlatformIDWeb, + PlatformIDReserved, + PlatformIDTelegram, } } diff --git a/internal/entity/faucet.go b/internal/entity/faucet.go index 31b3f8bf..aa5a948a 100644 --- a/internal/entity/faucet.go +++ b/internal/entity/faucet.go @@ -4,17 +4,15 @@ import ( "time" "github.com/pagu-project/pagu/pkg/amount" - "gorm.io/gorm" ) type PhoenixFaucet struct { - ID uint `gorm:"primaryKey;unique"` - UserID uint `gorm:"size:255"` - Address string - Amount amount.Amount `gorm:"column:amount"` - TransactionHash string + DBModel - gorm.Model + UserID uint `gorm:"type:bigint"` + Address string `gorm:"type:char(43)"` + Amount amount.Amount `gorm:"column:amount"` + TxHash string `gorm:"default:null"` } func (*PhoenixFaucet) TableName() string { diff --git a/internal/entity/model.go b/internal/entity/model.go new file mode 100644 index 00000000..efed5a4d --- /dev/null +++ b/internal/entity/model.go @@ -0,0 +1,13 @@ +package entity + +import ( + "database/sql" + "time" +) + +type DBModel struct { + ID uint `gorm:"primarykey"` + CreatedAt time.Time `gorm:"not_null"` + UpdatedAt time.Time `gorm:"not_null"` + DeletedAt sql.NullTime `gorm:"index"` +} diff --git a/internal/entity/notification.go b/internal/entity/notification.go index 8f166c38..5f1fbe2d 100644 --- a/internal/entity/notification.go +++ b/internal/entity/notification.go @@ -3,7 +3,6 @@ package entity import ( "github.com/pagu-project/pagu/pkg/notification" "gorm.io/datatypes" - "gorm.io/gorm" ) type NotificationStatus int @@ -15,13 +14,12 @@ const ( ) type Notification struct { - ID uint `gorm:"primaryKey;unique"` - Type notification.NotificationType `gorm:"size:2"` + DBModel + + Type notification.NotificationType `gorm:"type:tinyint"` Recipient string `gorm:"size:255"` Data datatypes.JSON - Status NotificationStatus `gorm:"size:2"` - - gorm.Model + Status NotificationStatus `gorm:"type:tinyint"` } type VoucherNotificationData struct { diff --git a/internal/entity/user.go b/internal/entity/user.go index 965b0acd..201e3e31 100644 --- a/internal/entity/user.go +++ b/internal/entity/user.go @@ -1,12 +1,5 @@ package entity -import ( - "database/sql" - "time" - - "gorm.io/gorm" -) - type Role int const ( @@ -16,14 +9,9 @@ const ( ) type User struct { - ID uint `gorm:"primaryKey;unique"` - ApplicationID AppID - CallerID string - Role Role - - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt sql.NullTime + DBModel - gorm.Model + PlatformID PlatformID `gorm:"type:tinyint"` + UserID string + Role Role `gorm:"type:tinyint"` } diff --git a/internal/entity/validator.go b/internal/entity/validator.go deleted file mode 100644 index b3219691..00000000 --- a/internal/entity/validator.go +++ /dev/null @@ -1,20 +0,0 @@ -package entity - -import ( - "database/sql" - "time" - - "gorm.io/gorm" -) - -type Validator struct { - ID uint `gorm:"primaryKey;unique"` - Name string - Email string `gorm:"size:255;unique;not null"` - - CreatedAt time.Time - UpdatedAt time.Time - DeletedAt sql.NullTime - - gorm.Model -} diff --git a/internal/entity/voucher.go b/internal/entity/voucher.go index eeb4276e..d092d788 100644 --- a/internal/entity/voucher.go +++ b/internal/entity/voucher.go @@ -2,22 +2,20 @@ package entity import ( "github.com/pagu-project/pagu/pkg/amount" - "gorm.io/gorm" ) type Voucher struct { - ID uint `gorm:"primaryKey;unique"` - Creator uint `gorm:"size:255"` - Code string `gorm:"size:8"` + DBModel + + Creator uint + Code string `gorm:"type:char(8);unique"` Amount amount.Amount `gorm:"column:amount"` Desc string Email string Recipient string ValidMonths uint8 - TxHash string + TxHash string `gorm:"type:char(64);unique;default:null"` ClaimedBy uint - - gorm.Model } func (Voucher) TableName() string { diff --git a/internal/entity/zealy.go b/internal/entity/zealy.go index e3a18980..a0627865 100644 --- a/internal/entity/zealy.go +++ b/internal/entity/zealy.go @@ -2,15 +2,14 @@ package entity import ( "github.com/pagu-project/pagu/pkg/amount" - "gorm.io/gorm" ) type ZealyUser struct { + DBModel + Amount amount.Amount `gorm:"column:amount"` DiscordID string `gorm:"column:discord_id"` - TxHash string - - gorm.Model + TxHash string `gorm:"type:char(64);unique"` } func (z *ZealyUser) IsClaimed() bool { diff --git a/internal/job/notification.go b/internal/job/notification.go index d62fb1a6..74292e4b 100644 --- a/internal/job/notification.go +++ b/internal/job/notification.go @@ -15,12 +15,12 @@ type mailSenderJob struct { ctx context.Context ticker *time.Ticker cancel context.CancelFunc - db repository.IDatabase + db *repository.Database mailSender notification.ISender templates map[string]string } -func NewMailSender(db repository.IDatabase, mailSender notification.ISender, templates map[string]string) Job { +func NewMailSender(db *repository.Database, mailSender notification.ISender, templates map[string]string) Job { ctx, cancel := context.WithCancel(context.Background()) return &mailSenderJob{ diff --git a/internal/platforms/discord/discord.go b/internal/platforms/discord/discord.go index f6faf200..be08dc2f 100644 --- a/internal/platforms/discord/discord.go +++ b/internal/platforms/discord/discord.go @@ -84,7 +84,7 @@ func (bot *Bot) registerCommands() error { beCmds := bot.engine.Commands() for i, beCmd := range beCmds { - if !beCmd.HasAppID(entity.AppIDDiscord) { + if !beCmd.HasAppID(entity.PlatformIDDiscord) { continue } @@ -220,7 +220,7 @@ func (bot *Bot) commandHandler(s *discordgo.Session, i *discordgo.InteractionCre inputBuilder.WriteString(fmt.Sprintf(" --%s=%s", k, v)) } - res := bot.engine.ParseAndExecute(entity.AppIDDiscord, i.Member.User.ID, inputBuilder.String()) + res := bot.engine.ParseAndExecute(entity.PlatformIDDiscord, i.Member.User.ID, inputBuilder.String()) bot.respondResultMsg(res, s, i) } diff --git a/internal/platforms/telegram/telegram.go b/internal/platforms/telegram/telegram.go index 5ea3f62d..2bdcf52e 100644 --- a/internal/platforms/telegram/telegram.go +++ b/internal/platforms/telegram/telegram.go @@ -95,7 +95,7 @@ func (bot *Bot) registerCommands() error { commands := make([]tele.Command, 0) for i, beCmd := range bot.engine.Commands() { - if !beCmd.HasAppID(entity.AppIDTelegram) { + if !beCmd.HasAppID(entity.PlatformIDTelegram) { continue } @@ -252,7 +252,7 @@ func (bot *Bot) handleCommand(ctx tele.Context, commands []string) error { } // Call the engine's Run method with the full command string - res := bot.engine.ParseAndExecute(entity.AppIDTelegram, callerID, fullCommand) + res := bot.engine.ParseAndExecute(entity.PlatformIDTelegram, callerID, fullCommand) _ = bot.botInstance.Delete(ctx.Message()) // Clear the stored command context and arguments for the sender diff --git a/internal/repository/database.go b/internal/repository/database.go index 2149679d..64c6b158 100644 --- a/internal/repository/database.go +++ b/internal/repository/database.go @@ -11,7 +11,7 @@ import ( ) type Database struct { - *gorm.DB + gormDB *gorm.DB } func NewDB(path string) (*Database, error) { @@ -59,6 +59,6 @@ func NewDB(path string) (*Database, error) { } return &Database{ - DB: db, + gormDB: db, }, nil } diff --git a/internal/repository/faucet.go b/internal/repository/faucet.go index 3db2e041..ee8733c6 100644 --- a/internal/repository/faucet.go +++ b/internal/repository/faucet.go @@ -6,13 +6,8 @@ import ( "github.com/pagu-project/pagu/internal/entity" ) -type IFaucet interface { - AddFaucet(f *entity.PhoenixFaucet) error - CanGetFaucet(user *entity.User) bool -} - func (db *Database) AddFaucet(f *entity.PhoenixFaucet) error { - tx := db.Create(f) + tx := db.gormDB.Create(f) if tx.Error != nil { return WriteError{ Message: tx.Error.Error(), @@ -24,7 +19,7 @@ func (db *Database) AddFaucet(f *entity.PhoenixFaucet) error { func (db *Database) CanGetFaucet(user *entity.User) bool { var lastFaucet entity.PhoenixFaucet - err := db.Model(&entity.PhoenixFaucet{}).Where("user_id = ?", user.ID).Order("id DESC").First(&lastFaucet).Error + err := db.gormDB.Model(&entity.PhoenixFaucet{}).Where("user_id = ?", user.ID).Order("id DESC").First(&lastFaucet).Error if err != nil { return true } diff --git a/internal/repository/interface.go b/internal/repository/interface.go deleted file mode 100644 index 21b6ec49..00000000 --- a/internal/repository/interface.go +++ /dev/null @@ -1,10 +0,0 @@ -package repository - -type IDatabase interface { - IUser - IVoucher - IFaucet - IZealy - IValidator - INotification -} diff --git a/internal/repository/mock.go b/internal/repository/mock.go deleted file mode 100644 index ef6b6292..00000000 --- a/internal/repository/mock.go +++ /dev/null @@ -1,300 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: ./internal/repository/interface.go -// -// Generated by this command: -// -// mockgen -source=./internal/repository/interface.go -destination=./internal/repository/mock.go -package=repository -// - -// Package repository is a generated GoMock package. -package repository - -import ( - reflect "reflect" - - entity "github.com/pagu-project/pagu/internal/entity" - gomock "go.uber.org/mock/gomock" -) - -// MockIDatabase is a mock of IDatabase interface. -type MockIDatabase struct { - ctrl *gomock.Controller - recorder *MockIDatabaseMockRecorder - isgomock struct{} -} - -// MockIDatabaseMockRecorder is the mock recorder for MockIDatabase. -type MockIDatabaseMockRecorder struct { - mock *MockIDatabase -} - -// NewMockIDatabase creates a new mock instance. -func NewMockIDatabase(ctrl *gomock.Controller) *MockIDatabase { - mock := &MockIDatabase{ctrl: ctrl} - mock.recorder = &MockIDatabaseMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockIDatabase) EXPECT() *MockIDatabaseMockRecorder { - return m.recorder -} - -// AddFaucet mocks base method. -func (m *MockIDatabase) AddFaucet(f *entity.PhoenixFaucet) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddFaucet", f) - ret0, _ := ret[0].(error) - return ret0 -} - -// AddFaucet indicates an expected call of AddFaucet. -func (mr *MockIDatabaseMockRecorder) AddFaucet(f any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddFaucet", reflect.TypeOf((*MockIDatabase)(nil).AddFaucet), f) -} - -// AddNotification mocks base method. -func (m *MockIDatabase) AddNotification(v *entity.Notification) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddNotification", v) - ret0, _ := ret[0].(error) - return ret0 -} - -// AddNotification indicates an expected call of AddNotification. -func (mr *MockIDatabaseMockRecorder) AddNotification(v any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNotification", reflect.TypeOf((*MockIDatabase)(nil).AddNotification), v) -} - -// AddUser mocks base method. -func (m *MockIDatabase) AddUser(u *entity.User) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddUser", u) - ret0, _ := ret[0].(error) - return ret0 -} - -// AddUser indicates an expected call of AddUser. -func (mr *MockIDatabaseMockRecorder) AddUser(u any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddUser", reflect.TypeOf((*MockIDatabase)(nil).AddUser), u) -} - -// AddValidator mocks base method. -func (m *MockIDatabase) AddValidator(arg0 *entity.Validator) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddValidator", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// AddValidator indicates an expected call of AddValidator. -func (mr *MockIDatabaseMockRecorder) AddValidator(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddValidator", reflect.TypeOf((*MockIDatabase)(nil).AddValidator), arg0) -} - -// AddVoucher mocks base method. -func (m *MockIDatabase) AddVoucher(v *entity.Voucher) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddVoucher", v) - ret0, _ := ret[0].(error) - return ret0 -} - -// AddVoucher indicates an expected call of AddVoucher. -func (mr *MockIDatabaseMockRecorder) AddVoucher(v any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddVoucher", reflect.TypeOf((*MockIDatabase)(nil).AddVoucher), v) -} - -// AddZealyUser mocks base method. -func (m *MockIDatabase) AddZealyUser(u *entity.ZealyUser) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "AddZealyUser", u) - ret0, _ := ret[0].(error) - return ret0 -} - -// AddZealyUser indicates an expected call of AddZealyUser. -func (mr *MockIDatabaseMockRecorder) AddZealyUser(u any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddZealyUser", reflect.TypeOf((*MockIDatabase)(nil).AddZealyUser), u) -} - -// CanGetFaucet mocks base method. -func (m *MockIDatabase) CanGetFaucet(user *entity.User) bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CanGetFaucet", user) - ret0, _ := ret[0].(bool) - return ret0 -} - -// CanGetFaucet indicates an expected call of CanGetFaucet. -func (mr *MockIDatabaseMockRecorder) CanGetFaucet(user any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CanGetFaucet", reflect.TypeOf((*MockIDatabase)(nil).CanGetFaucet), user) -} - -// ClaimVoucher mocks base method. -func (m *MockIDatabase) ClaimVoucher(id uint, txHash string, claimer uint) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ClaimVoucher", id, txHash, claimer) - ret0, _ := ret[0].(error) - return ret0 -} - -// ClaimVoucher indicates an expected call of ClaimVoucher. -func (mr *MockIDatabaseMockRecorder) ClaimVoucher(id, txHash, claimer any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ClaimVoucher", reflect.TypeOf((*MockIDatabase)(nil).ClaimVoucher), id, txHash, claimer) -} - -// GetAllZealyUser mocks base method. -func (m *MockIDatabase) GetAllZealyUser() ([]*entity.ZealyUser, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetAllZealyUser") - ret0, _ := ret[0].([]*entity.ZealyUser) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetAllZealyUser indicates an expected call of GetAllZealyUser. -func (mr *MockIDatabaseMockRecorder) GetAllZealyUser() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAllZealyUser", reflect.TypeOf((*MockIDatabase)(nil).GetAllZealyUser)) -} - -// GetPendingMailNotification mocks base method. -func (m *MockIDatabase) GetPendingMailNotification() (*entity.Notification, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetPendingMailNotification") - ret0, _ := ret[0].(*entity.Notification) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetPendingMailNotification indicates an expected call of GetPendingMailNotification. -func (mr *MockIDatabaseMockRecorder) GetPendingMailNotification() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetPendingMailNotification", reflect.TypeOf((*MockIDatabase)(nil).GetPendingMailNotification)) -} - -// GetUserByApp mocks base method. -func (m *MockIDatabase) GetUserByApp(appID entity.AppID, callerID string) (*entity.User, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetUserByApp", appID, callerID) - ret0, _ := ret[0].(*entity.User) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetUserByApp indicates an expected call of GetUserByApp. -func (mr *MockIDatabaseMockRecorder) GetUserByApp(appID, callerID any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetUserByApp", reflect.TypeOf((*MockIDatabase)(nil).GetUserByApp), appID, callerID) -} - -// GetValidator mocks base method. -func (m *MockIDatabase) GetValidator(arg0 uint) (entity.Validator, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetValidator", arg0) - ret0, _ := ret[0].(entity.Validator) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetValidator indicates an expected call of GetValidator. -func (mr *MockIDatabaseMockRecorder) GetValidator(arg0 any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetValidator", reflect.TypeOf((*MockIDatabase)(nil).GetValidator), arg0) -} - -// GetVoucherByCode mocks base method. -func (m *MockIDatabase) GetVoucherByCode(code string) (entity.Voucher, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetVoucherByCode", code) - ret0, _ := ret[0].(entity.Voucher) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetVoucherByCode indicates an expected call of GetVoucherByCode. -func (mr *MockIDatabaseMockRecorder) GetVoucherByCode(code any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetVoucherByCode", reflect.TypeOf((*MockIDatabase)(nil).GetVoucherByCode), code) -} - -// GetZealyUser mocks base method. -func (m *MockIDatabase) GetZealyUser(id string) (*entity.ZealyUser, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetZealyUser", id) - ret0, _ := ret[0].(*entity.ZealyUser) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetZealyUser indicates an expected call of GetZealyUser. -func (mr *MockIDatabaseMockRecorder) GetZealyUser(id any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetZealyUser", reflect.TypeOf((*MockIDatabase)(nil).GetZealyUser), id) -} - -// HasUser mocks base method. -func (m *MockIDatabase) HasUser(id string) bool { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HasUser", id) - ret0, _ := ret[0].(bool) - return ret0 -} - -// HasUser indicates an expected call of HasUser. -func (mr *MockIDatabaseMockRecorder) HasUser(id any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HasUser", reflect.TypeOf((*MockIDatabase)(nil).HasUser), id) -} - -// ListVoucher mocks base method. -func (m *MockIDatabase) ListVoucher() ([]*entity.Voucher, error) { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "ListVoucher") - ret0, _ := ret[0].([]*entity.Voucher) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ListVoucher indicates an expected call of ListVoucher. -func (mr *MockIDatabaseMockRecorder) ListVoucher() *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ListVoucher", reflect.TypeOf((*MockIDatabase)(nil).ListVoucher)) -} - -// UpdateNotificationStatus mocks base method. -func (m *MockIDatabase) UpdateNotificationStatus(id uint, status entity.NotificationStatus) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateNotificationStatus", id, status) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpdateNotificationStatus indicates an expected call of UpdateNotificationStatus. -func (mr *MockIDatabaseMockRecorder) UpdateNotificationStatus(id, status any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateNotificationStatus", reflect.TypeOf((*MockIDatabase)(nil).UpdateNotificationStatus), id, status) -} - -// UpdateZealyUser mocks base method. -func (m *MockIDatabase) UpdateZealyUser(id, txHash string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpdateZealyUser", id, txHash) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpdateZealyUser indicates an expected call of UpdateZealyUser. -func (mr *MockIDatabaseMockRecorder) UpdateZealyUser(id, txHash any) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateZealyUser", reflect.TypeOf((*MockIDatabase)(nil).UpdateZealyUser), id, txHash) -} diff --git a/internal/repository/notification.go b/internal/repository/notification.go index cdd97455..225d9478 100644 --- a/internal/repository/notification.go +++ b/internal/repository/notification.go @@ -5,14 +5,8 @@ import ( "github.com/pagu-project/pagu/pkg/notification" ) -type INotification interface { - AddNotification(v *entity.Notification) error - GetPendingMailNotification() (*entity.Notification, error) - UpdateNotificationStatus(id uint, status entity.NotificationStatus) error -} - func (db *Database) AddNotification(v *entity.Notification) error { - tx := db.Create(v) + tx := db.gormDB.Create(v) if tx.Error != nil { return WriteError{ Message: tx.Error.Error(), @@ -24,7 +18,7 @@ func (db *Database) AddNotification(v *entity.Notification) error { func (db *Database) GetPendingMailNotification() (*entity.Notification, error) { var notif *entity.Notification - tx := db.Model(&entity.Notification{}). + tx := db.gormDB.Model(&entity.Notification{}). Where("status = ?", entity.NotificationStatusPending). Where("type = ?", notification.NotificationTypeMail). First(¬if) @@ -39,7 +33,7 @@ func (db *Database) GetPendingMailNotification() (*entity.Notification, error) { } func (db *Database) UpdateNotificationStatus(id uint, status entity.NotificationStatus) error { - tx := db.Model(&entity.Notification{}).Where("id = ?", id).Update("status", status) + tx := db.gormDB.Model(&entity.Notification{}).Where("id = ?", id).Update("status", status) if tx.Error != nil { return WriteError{ Message: tx.Error.Error(), diff --git a/internal/repository/user.go b/internal/repository/user.go index ca1c08b8..0401858f 100644 --- a/internal/repository/user.go +++ b/internal/repository/user.go @@ -2,14 +2,8 @@ package repository import "github.com/pagu-project/pagu/internal/entity" -type IUser interface { - AddUser(u *entity.User) error - HasUser(id string) bool - GetUserByApp(appID entity.AppID, callerID string) (*entity.User, error) -} - func (db *Database) AddUser(u *entity.User) error { - tx := db.Create(u) + tx := db.gormDB.Create(u) if tx.Error != nil { return WriteError{ Message: tx.Error.Error(), @@ -22,7 +16,7 @@ func (db *Database) AddUser(u *entity.User) error { func (db *Database) HasUser(id string) bool { var exists bool - _ = db.Model(&entity.User{}). + _ = db.gormDB.Model(&entity.User{}). Select("count(*) > 0"). Where("id = ?", id). Find(&exists). @@ -31,9 +25,9 @@ func (db *Database) HasUser(id string) bool { return exists } -func (db *Database) GetUserByApp(appID entity.AppID, callerID string) (*entity.User, error) { +func (db *Database) GetUserByApp(appID entity.PlatformID, callerID string) (*entity.User, error) { var user *entity.User - tx := db.Model(&entity.User{}). + tx := db.gormDB.Model(&entity.User{}). Where("application_id = ?", appID). Where("caller_id = ?", callerID). First(&user) diff --git a/internal/repository/validator.go b/internal/repository/validator.go deleted file mode 100644 index cdb16915..00000000 --- a/internal/repository/validator.go +++ /dev/null @@ -1,29 +0,0 @@ -package repository - -import "github.com/pagu-project/pagu/internal/entity" - -type IValidator interface { - AddValidator(*entity.Validator) error - GetValidator(uint) (entity.Validator, error) -} - -func (db *Database) AddValidator(v *entity.Validator) error { - tx := db.Create(v) - if tx.Error != nil { - return WriteError{ - Message: tx.Error.Error(), - } - } - - return nil -} - -func (db *Database) GetValidator(id uint) (entity.Validator, error) { - var validator entity.Validator - err := db.Model(&entity.Validator{}).Where("id = ?", id).First(&validator).Error - if err != nil { - return entity.Validator{}, err - } - - return validator, nil -} diff --git a/internal/repository/voucher.go b/internal/repository/voucher.go index 32a5d579..146c6f0b 100644 --- a/internal/repository/voucher.go +++ b/internal/repository/voucher.go @@ -4,15 +4,8 @@ import ( "github.com/pagu-project/pagu/internal/entity" ) -type IVoucher interface { - AddVoucher(v *entity.Voucher) error - GetVoucherByCode(code string) (entity.Voucher, error) - ClaimVoucher(id uint, txHash string, claimer uint) error - ListVoucher() ([]*entity.Voucher, error) -} - func (db *Database) AddVoucher(v *entity.Voucher) error { - tx := db.Create(v) + tx := db.gormDB.Create(v) if tx.Error != nil { return WriteError{ Message: tx.Error.Error(), @@ -24,7 +17,7 @@ func (db *Database) AddVoucher(v *entity.Voucher) error { func (db *Database) GetVoucherByCode(code string) (entity.Voucher, error) { var voucher entity.Voucher - err := db.Model(&entity.Voucher{}).Where("code = ?", code).First(&voucher).Error + err := db.gormDB.Model(&entity.Voucher{}).Where("code = ?", code).First(&voucher).Error if err != nil { return entity.Voucher{}, err } @@ -33,7 +26,7 @@ func (db *Database) GetVoucherByCode(code string) (entity.Voucher, error) { } func (db *Database) ClaimVoucher(id uint, txHash string, claimer uint) error { - tx := db.Model(&entity.Voucher{}).Where("id = ?", id).Update("tx_hash", txHash).Update("claimed_by", claimer) + tx := db.gormDB.Model(&entity.Voucher{}).Where("id = ?", id).Update("tx_hash", txHash).Update("claimed_by", claimer) if tx.Error != nil { return WriteError{ Message: tx.Error.Error(), @@ -45,7 +38,7 @@ func (db *Database) ClaimVoucher(id uint, txHash string, claimer uint) error { func (db *Database) ListVoucher() ([]*entity.Voucher, error) { var vouchers []*entity.Voucher - tx := db.Find(&vouchers) + tx := db.gormDB.Find(&vouchers) if tx.Error != nil { return nil, ReadError{ Message: tx.Error.Error(), diff --git a/internal/repository/zealy.go b/internal/repository/zealy.go index e9d5bd3f..b86cb96c 100644 --- a/internal/repository/zealy.go +++ b/internal/repository/zealy.go @@ -2,16 +2,9 @@ package repository import "github.com/pagu-project/pagu/internal/entity" -type IZealy interface { - GetZealyUser(id string) (*entity.ZealyUser, error) - AddZealyUser(u *entity.ZealyUser) error - UpdateZealyUser(id string, txHash string) error - GetAllZealyUser() ([]*entity.ZealyUser, error) -} - func (db *Database) GetZealyUser(id string) (*entity.ZealyUser, error) { var user *entity.ZealyUser - tx := db.Model(&entity.ZealyUser{}).First(&user, "discord_id = ?", id) + tx := db.gormDB.Model(&entity.ZealyUser{}).First(&user, "discord_id = ?", id) if tx.Error != nil { return &entity.ZealyUser{}, ReadError{ Message: tx.Error.Error(), @@ -22,7 +15,7 @@ func (db *Database) GetZealyUser(id string) (*entity.ZealyUser, error) { } func (db *Database) AddZealyUser(u *entity.ZealyUser) error { - tx := db.Create(u) + tx := db.gormDB.Create(u) if tx.Error != nil { return WriteError{ Message: tx.Error.Error(), @@ -33,7 +26,7 @@ func (db *Database) AddZealyUser(u *entity.ZealyUser) error { } func (db *Database) UpdateZealyUser(id, txHash string) error { - tx := db.Model(&entity.ZealyUser{ + tx := db.gormDB.Model(&entity.ZealyUser{ DiscordID: id, }).Where("discord_id = ?", id).Update("tx_hash", txHash) if tx.Error != nil { @@ -47,7 +40,7 @@ func (db *Database) UpdateZealyUser(id, txHash string) error { func (db *Database) GetAllZealyUser() ([]*entity.ZealyUser, error) { var users []*entity.ZealyUser - tx := db.Find(&users) + tx := db.gormDB.Find(&users) if tx.Error != nil { return nil, ReadError{ Message: tx.Error.Error(), diff --git a/internal/testsuite/testsuite.go b/internal/testsuite/testsuite.go index 13a41b89..4a3bf87a 100644 --- a/internal/testsuite/testsuite.go +++ b/internal/testsuite/testsuite.go @@ -7,6 +7,7 @@ import ( "testing" "time" + "github.com/pagu-project/pagu/internal/repository" "github.com/pagu-project/pagu/pkg/amount" ) @@ -47,6 +48,12 @@ func NewTestSuite(t *testing.T) *TestSuite { } } +func (*TestSuite) MakeTestDB() *repository.Database { + db, _ := repository.NewDB("sqlite:file::memory:") + + return db +} + // RandBool returns a random boolean value. func (ts *TestSuite) RandBool() bool { return ts.RandInt64(2) == 0 From ecf9eb4ee8a7bbe702764418246c0bf42aabffa9 Mon Sep 17 00:00:00 2001 From: mantre Date: Tue, 31 Dec 2024 15:35:50 +0800 Subject: [PATCH 2/2] chore: update tx-hash gorm tags --- internal/engine/command/zealy/claim.go | 4 ++-- internal/engine/engine.go | 6 +++--- internal/entity/faucet.go | 2 +- internal/entity/user.go | 6 +++--- internal/entity/zealy.go | 2 +- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/internal/engine/command/zealy/claim.go b/internal/engine/command/zealy/claim.go index af63f235..c6d772de 100644 --- a/internal/engine/command/zealy/claim.go +++ b/internal/engine/command/zealy/claim.go @@ -9,7 +9,7 @@ import ( ) func (z *Zealy) claimHandler(caller *entity.User, cmd *command.Command, args map[string]string) command.CommandResult { - user, err := z.db.GetZealyUser(caller.UserID) + user, err := z.db.GetZealyUser(caller.PlatformUserID) if err != nil { return cmd.ErrorResult(err) } @@ -28,7 +28,7 @@ func (z *Zealy) claimHandler(caller *entity.User, cmd *command.Command, args map return cmd.ErrorResult(transferErr) } - if err = z.db.UpdateZealyUser(caller.UserID, txHash); err != nil { + if err = z.db.UpdateZealyUser(caller.PlatformUserID, txHash); err != nil { return cmd.ErrorResult(err) } diff --git a/internal/engine/engine.go b/internal/engine/engine.go index 0939e59d..d4e0c18c 100644 --- a/internal/engine/engine.go +++ b/internal/engine/engine.go @@ -276,12 +276,12 @@ func (be *BotEngine) NetworkStatus() (*network.NetStatus, error) { }, nil } -func (be *BotEngine) GetUser(appID entity.PlatformID, callerID string) (*entity.User, error) { - if u, _ := be.db.GetUserByApp(appID, callerID); u != nil { +func (be *BotEngine) GetUser(appID entity.PlatformID, platformUserID string) (*entity.User, error) { + if u, _ := be.db.GetUserByApp(appID, platformUserID); u != nil { return u, nil } - user := &entity.User{PlatformID: appID, UserID: callerID} + user := &entity.User{PlatformID: appID, PlatformUserID: platformUserID} if err := be.db.AddUser(user); err != nil { return nil, err } diff --git a/internal/entity/faucet.go b/internal/entity/faucet.go index aa5a948a..47a21aed 100644 --- a/internal/entity/faucet.go +++ b/internal/entity/faucet.go @@ -12,7 +12,7 @@ type PhoenixFaucet struct { UserID uint `gorm:"type:bigint"` Address string `gorm:"type:char(43)"` Amount amount.Amount `gorm:"column:amount"` - TxHash string `gorm:"default:null"` + TxHash string `gorm:"type:char(64);unique;not_null"` } func (*PhoenixFaucet) TableName() string { diff --git a/internal/entity/user.go b/internal/entity/user.go index 201e3e31..405bde5c 100644 --- a/internal/entity/user.go +++ b/internal/entity/user.go @@ -11,7 +11,7 @@ const ( type User struct { DBModel - PlatformID PlatformID `gorm:"type:tinyint"` - UserID string - Role Role `gorm:"type:tinyint"` + PlatformID PlatformID `gorm:"type:tinyint"` + PlatformUserID string + Role Role `gorm:"type:tinyint"` } diff --git a/internal/entity/zealy.go b/internal/entity/zealy.go index a0627865..18894ca2 100644 --- a/internal/entity/zealy.go +++ b/internal/entity/zealy.go @@ -9,7 +9,7 @@ type ZealyUser struct { Amount amount.Amount `gorm:"column:amount"` DiscordID string `gorm:"column:discord_id"` - TxHash string `gorm:"type:char(64);unique"` + TxHash string `gorm:"type:char(64);unique;default:null"` } func (z *ZealyUser) IsClaimed() bool {