Skip to content

Commit

Permalink
feat: implement crowdfund:create command
Browse files Browse the repository at this point in the history
  • Loading branch information
b00f committed Jan 3, 2025
1 parent 2620e27 commit 12444c6
Show file tree
Hide file tree
Showing 27 changed files with 387 additions and 60 deletions.
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ devtools:

### mock
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=./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=./pkg/nowpayments/interface.go -destination=./pkg/nowpayments/mock.go -package=nowpayments

### proto file generate
proto:
Expand Down
14 changes: 8 additions & 6 deletions internal/engine/command/command.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ type InputBox int

const (
InputBoxText InputBox = iota
InputBoxMultilineText
InputBoxNumber
InputBoxFile
InputBoxAmount
Expand Down Expand Up @@ -67,7 +68,7 @@ func (cmd *Command) SuccessfulResult(msg string) CommandResult {
func (cmd *Command) SuccessfulResultF(msg string, a ...any) CommandResult {
return CommandResult{
Color: cmd.Color,
Title: fmt.Sprintf("%v %v", cmd.Help, cmd.Emoji),
Title: fmt.Sprintf("%v %v", cmd.Name, cmd.Emoji),
Message: fmt.Sprintf(msg, a...),
Successful: true,
}
Expand All @@ -80,7 +81,7 @@ func (cmd *Command) FailedResult(msg string) CommandResult {
func (cmd *Command) FailedResultF(msg string, a ...any) CommandResult {
return CommandResult{
Color: cmd.Color,
Title: fmt.Sprintf("%v %v", cmd.Help, cmd.Emoji),
Title: fmt.Sprintf("%v %v", cmd.Name, cmd.Emoji),
Message: fmt.Sprintf(msg, a...),
Error: msg,
Successful: false,
Expand Down Expand Up @@ -112,7 +113,7 @@ func (cmd *Command) HelpMessage() string {
help := cmd.Help
help += "\n\nAvailable commands:\n"
for _, sc := range cmd.SubCommands {
help += fmt.Sprintf(" %-12s %s\n", sc.Name, sc.Help)
help += fmt.Sprintf("- **%-12s**: %s\n", sc.Name, sc.Help)
}

return help
Expand All @@ -128,9 +129,10 @@ func (cmd *Command) AddSubCommand(subCmd *Command) {

func (cmd *Command) AddHelpSubCommand() {
helpCmd := &Command{
Name: "help",
Help: fmt.Sprintf("Help for %v command", cmd.Name),
AppIDs: entity.AllAppIDs(),
Name: "help",
Help: fmt.Sprintf("Help for %v command", cmd.Name),
AppIDs: entity.AllAppIDs(),
TargetFlag: TargetMaskAll,
Handler: func(_ *entity.User, _ *Command, _ map[string]string) CommandResult {
return cmd.SuccessfulResult(cmd.HelpMessage())
},
Expand Down
2 changes: 1 addition & 1 deletion internal/engine/command/crowdfund/claim.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"github.com/pagu-project/pagu/internal/entity"
)

func (*Crowdfund) claimHandler(
func (*CrowdfundCmd) claimHandler(
_ *entity.User,
cmd *command.Command,
_ map[string]string,
Expand Down
35 changes: 32 additions & 3 deletions internal/engine/command/crowdfund/create.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,43 @@
package crowdfund

import (
"encoding/json"

"github.com/pagu-project/pagu/internal/engine/command"
"github.com/pagu-project/pagu/internal/entity"
)

func (*Crowdfund) createHandler(
func (c *CrowdfundCmd) createHandler(
_ *entity.User,
cmd *command.Command,
_ map[string]string,
args map[string]string,
) command.CommandResult {
return cmd.SuccessfulResult("TODO")
title := args["title"]
desc := args["desc"]
packagesJSON := args["packages"]

packages := []entity.Package{}
err := json.Unmarshal([]byte(packagesJSON), &packages)
if err != nil {
return cmd.FailedResult(err.Error())
}

if title == "" {
return cmd.FailedResult("The title of the crowdfunding campaign cannot be empty")
}

if len(packages) < 2 {
return cmd.FailedResult("At least 3 packages are required for the crowdfunding campaign")
}

campaign := &entity.CrowdfundCampaign{
Title: title,
Desc: desc,
Packages: packages,
}
c.db.AddCrowdfundCampaign(campaign)

Check failure on line 38 in internal/engine/command/crowdfund/create.go

View workflow job for this annotation

GitHub Actions / lint

G104: Errors unhandled. (gosec)

return cmd.SuccessfulResultF(
"Crowdfund campaign '%s' created successfully with %d packages",
title, len(packages))
}
65 changes: 65 additions & 0 deletions internal/engine/command/crowdfund/create_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package crowdfund

import (
"testing"

"github.com/pagu-project/pagu/internal/engine/command"
"github.com/pagu-project/pagu/internal/entity"
"github.com/stretchr/testify/assert"
)

func TestCreate(t *testing.T) {
td := setup(t)

caller := &entity.User{DBModel: entity.DBModel{ID: 1}}
cmd := &command.Command{}

t.Run("Invalid Packages", func(t *testing.T) {
args := map[string]string{
"title": "crowdfund-title",
"desc": "crowdfund-desc",
"packages": "INVALID-JSON",
}
result := td.crowdfundCmd.createHandler(caller, cmd, args)
assert.False(t, result.Successful)
assert.Equal(t, result.Message, "invalid character 'I' looking for beginning of value")
})

t.Run("Empty title", func(t *testing.T) {
args := map[string]string{
"title": "",
"desc": "",
"packages": "[]",
}
result := td.crowdfundCmd.createHandler(caller, cmd, args)
assert.False(t, result.Successful)
assert.Equal(t, result.Message, "The title of the crowdfunding campaign cannot be empty")
})

t.Run("Empty Packages", func(t *testing.T) {
args := map[string]string{
"title": "crowdfund-title",
"desc": "crowdfund-desc",
"packages": "[]",
}
result := td.crowdfundCmd.createHandler(caller, cmd, args)
assert.False(t, result.Successful)
assert.Equal(t, result.Message, "At least 3 packages are required for the crowdfunding campaign")
})

t.Run("Ok", func(t *testing.T) {
args := map[string]string{
"title": "crowdfund-title",
"desc": "crowdfund-desc",
"packages": `
[
{"name": "package-1", "usd_amount": 100, "pac_amount": 100},
{"name": "package-2", "usd_amount": 200, "pac_amount": 200},
{"name": "package-3", "usd_amount": 300, "pac_amount": 300}
]`,
}
result := td.crowdfundCmd.createHandler(caller, cmd, args)
assert.True(t, result.Successful)
assert.Equal(t, result.Message, "Crowdfund campaign 'crowdfund-title' created successfully with 3 packages")
})
}
44 changes: 36 additions & 8 deletions internal/engine/command/crowdfund/crowdfund.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,26 +5,54 @@ import (

"github.com/pagu-project/pagu/internal/engine/command"
"github.com/pagu-project/pagu/internal/entity"
"github.com/pagu-project/pagu/internal/nowpayments"
"github.com/pagu-project/pagu/internal/repository"
"github.com/pagu-project/pagu/pkg/nowpayments"
"github.com/pagu-project/pagu/pkg/wallet"
)

type Crowdfund struct {
type CrowdfundCmd struct {
ctx context.Context
db *repository.Database
wallet wallet.IWallet
nowPayments nowpayments.INowpayments
}

func NewCrowdfundCmd(ctx context.Context, nowPayments nowpayments.INowpayments) *Crowdfund {
return &Crowdfund{
func NewCrowdfundCmd(ctx context.Context,
db *repository.Database,
wallet wallet.IWallet,
nowPayments nowpayments.INowpayments) *CrowdfundCmd {

Check failure on line 23 in internal/engine/command/crowdfund/crowdfund.go

View workflow job for this annotation

GitHub Actions / lint

File is not properly formatted (gofumpt)
return &CrowdfundCmd{
ctx: ctx,
db: db,
wallet: wallet,
nowPayments: nowPayments,
}
}

func (n *Crowdfund) GetCommand() *command.Command {
func (n *CrowdfundCmd) GetCommand() *command.Command {

Check failure on line 32 in internal/engine/command/crowdfund/crowdfund.go

View workflow job for this annotation

GitHub Actions / lint

ST1016: methods on the same type should have the same receiver name (seen 1x "c", 1x "n") (stylecheck)
subCmdCreate := &command.Command{
Name: "create",
Help: "Create a new crowdfunding campaign",
Args: []command.Args{},
Name: "create",
Help: "Create a new crowdfunding campaign",
Args: []command.Args{
{
Name: "title",
Desc: "The title of this crowdfunding campaign",
InputBox: command.InputBoxText,
Optional: false,
},
{
Name: "desc",
Desc: "A description of this crowdfunding campaign",
InputBox: command.InputBoxMultilineText,
Optional: false,
},
{
Name: "packages",
Desc: "The packages for this campaign in JSON format",
InputBox: command.InputBoxMultilineText,
Optional: false,
},
},
SubCommands: nil,
AppIDs: entity.AllAppIDs(),
Handler: n.createHandler,
Expand Down
95 changes: 95 additions & 0 deletions internal/engine/command/crowdfund/crowdfund_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package crowdfund

import (
"context"
"testing"

"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/nowpayments"
"github.com/pagu-project/pagu/pkg/wallet"
"github.com/stretchr/testify/require"
"go.uber.org/mock/gomock"
)

type testData struct {
*testsuite.TestSuite

crowdfundCmd *CrowdfundCmd
database *repository.Database
nowpayments *nowpayments.MockINowpayments
wallet *wallet.MockIWallet
}

func setup(t *testing.T) *testData {
t.Helper()

ts := testsuite.NewTestSuite(t)
ctrl := gomock.NewController(t)

testDB := ts.MakeTestDB()
mockNowpayments := nowpayments.NewMockINowpayments(ctrl)
mockWallet := wallet.NewMockIWallet(ctrl)

crowdfundCmd := NewCrowdfundCmd(context.Background(),
testDB, mockWallet, mockNowpayments)

return &testData{
TestSuite: ts,
crowdfundCmd: crowdfundCmd,
database: testDB,
nowpayments: mockNowpayments,
wallet: mockWallet,
}
}

type CampaignOption func(*entity.CrowdfundCampaign)

func WithTitle(title string) CampaignOption {
return func(c *entity.CrowdfundCampaign) {
c.Title = title
}
}

func WithPackages(packages []entity.Package) CampaignOption {
return func(c *entity.CrowdfundCampaign) {
c.Packages = packages
}
}

func (td *testData) createTestCampaign(t *testing.T, opts ...CampaignOption) *entity.CrowdfundCampaign {

Check failure on line 61 in internal/engine/command/crowdfund/crowdfund_test.go

View workflow job for this annotation

GitHub Actions / lint

func `(*testData).createTestCampaign` is unused (unused)
t.Helper()

campaign := &entity.CrowdfundCampaign{
Title: td.RandString(16),
Desc: td.RandString(128),
Packages: []entity.Package{
entity.Package{

Check failure on line 68 in internal/engine/command/crowdfund/crowdfund_test.go

View workflow job for this annotation

GitHub Actions / lint

File is not properly formatted (gofmt)
Name: td.RandString(16),
USDAmount: td.RandInt(1000),
PACAmount: td.RandInt(1000),
},
entity.Package{

Check failure on line 73 in internal/engine/command/crowdfund/crowdfund_test.go

View workflow job for this annotation

GitHub Actions / lint

File is not properly formatted (gofumpt)
Name: td.RandString(16),
USDAmount: td.RandInt(1000),
PACAmount: td.RandInt(1000),
},
entity.Package{
Name: td.RandString(16),
USDAmount: td.RandInt(1000),
PACAmount: td.RandInt(1000),
},
},
}

// Apply options
for _, opt := range opts {
opt(campaign)
}

err := td.database.AddCrowdfundCampaign(campaign)
require.NoError(t, err)

return campaign
}
2 changes: 1 addition & 1 deletion internal/engine/command/crowdfund/disable.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"github.com/pagu-project/pagu/internal/entity"
)

func (*Crowdfund) disableHandler(
func (*CrowdfundCmd) disableHandler(
_ *entity.User,
cmd *command.Command,
_ map[string]string,
Expand Down
2 changes: 1 addition & 1 deletion internal/engine/command/crowdfund/info.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"github.com/pagu-project/pagu/internal/entity"
)

func (*Crowdfund) infoHandler(
func (*CrowdfundCmd) infoHandler(
_ *entity.User,
cmd *command.Command,
_ map[string]string,
Expand Down
2 changes: 1 addition & 1 deletion internal/engine/command/crowdfund/putchase.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"github.com/pagu-project/pagu/internal/entity"
)

func (*Crowdfund) purchaseHandler(
func (*CrowdfundCmd) purchaseHandler(
_ *entity.User,
cmd *command.Command,
_ map[string]string,
Expand Down
2 changes: 1 addition & 1 deletion internal/engine/command/crowdfund/report.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
"github.com/pagu-project/pagu/internal/entity"
)

func (*Crowdfund) reportHandler(
func (*CrowdfundCmd) reportHandler(
_ *entity.User,
cmd *command.Command,
_ map[string]string,
Expand Down
6 changes: 3 additions & 3 deletions internal/engine/command/voucher/claim_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,15 +40,15 @@ func TestClaim(t *testing.T) {
testVoucher := td.createTestVoucher(t, WithCode(voucherCode))
validatorAddr := "pc1p..."

td.clientManager.EXPECT().GetValidatorInfo(validatorAddr).Return(
td.mockClientMgr.EXPECT().GetValidatorInfo(validatorAddr).Return(
nil, nil,
).AnyTimes()

td.clientManager.EXPECT().FindPublicKey(validatorAddr, false).Return(
td.mockClientMgr.EXPECT().FindPublicKey(validatorAddr, false).Return(
validatorAddr, nil,
).AnyTimes()

td.wallet.EXPECT().BondTransaction(gomock.Any(), validatorAddr,
td.mockWallet.EXPECT().BondTransaction(gomock.Any(), validatorAddr,
"voucher 12345678 claimed by Pagu", testVoucher.Amount).Return(
"0x1", nil,
).AnyTimes()
Expand Down
Loading

0 comments on commit 12444c6

Please sign in to comment.