Skip to content

Commit

Permalink
feat: ChallengeSubscriptionClose + related small fixes & refactors
Browse files Browse the repository at this point in the history
  • Loading branch information
moul committed Nov 5, 2019
1 parent 02b8100 commit 27f0378
Show file tree
Hide file tree
Showing 14 changed files with 1,099 additions and 523 deletions.
17 changes: 14 additions & 3 deletions api/pwdb.proto
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,14 @@ message ChallengeSubscription {
// fields
//

enum Status {
Unknown = 0;
Active = 1;
Closed = 2;
}
Status status = 100;
google.protobuf.Timestamp closed_at = 101 [(gogoproto.stdtime) = true, (gogoproto.nullable) = true];

//
// associations
//
Expand All @@ -436,10 +444,13 @@ message ChallengeSubscription {
SeasonChallenge season_challenge = 202 [(gogoproto.moretags) = "gorm:\"foreignkey:SeasonChallengeID\""];
int64 season_challenge_id = 203 [(gogoproto.customname) = "SeasonChallengeID", (gogoproto.moretags) = "sql:\"not null\" gorm:\"unique_index:idx_team_season_challenge\""];

User author = 204 [(gogoproto.moretags) = "gorm:\"foreignkey:AuthorID\""];
int64 author_id = 205 [(gogoproto.customname) = "AuthorID", (gogoproto.moretags) = "sql:\"not null\" gorm:\"index\""];
User buyer = 204 [(gogoproto.moretags) = "gorm:\"foreignkey:BuyerID\""];
int64 buyer_id = 205 [(gogoproto.customname) = "BuyerID", (gogoproto.moretags) = "sql:\"not null\" gorm:\"index\""];

User closer = 206 [(gogoproto.moretags) = "gorm:\"foreignkey:CloserID\""];
int64 closer_id = 207 [(gogoproto.customname) = "CloserID", (gogoproto.moretags) = "sql:\"not null\" gorm:\"index\""];

repeated ChallengeValidation validations = 206 [(gogoproto.moretags) = "gorm:\"PRELOAD:false\""];
repeated ChallengeValidation validations = 208 [(gogoproto.moretags) = "gorm:\"PRELOAD:false\""];
}

message InventoryItem {
Expand Down
2 changes: 1 addition & 1 deletion api/pwengine.proto
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ message ChallengeSubscriptionValidateOutput {
}

message ChallengeSubscriptionCloseInput { int64 challenge_subscription_id = 1 [(gogoproto.customname) = "ChallengeSubscriptionID"]; }
message ChallengeSubscriptionCloseOutput {}
message ChallengeSubscriptionCloseOutput { pathwar.db.ChallengeSubscription challenge_subscription = 1; }

message TeamListInput { int64 season_id = 1 [(gogoproto.customname) = "SeasonID"]; }
message TeamListOutput { repeated pathwar.db.Team items = 1; }
Expand Down
4 changes: 2 additions & 2 deletions docs/gen.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions go/gen.sum

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 3 additions & 2 deletions go/pkg/pwdb/entity.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,16 @@ func All() []interface{} {
func ForeignKeys() [][3]string {
return [][3]string{
// {"User", "active_team_member_id", "team_member(id)"}, // FIXME: check why this cause an error!?
{"Achievement", "user_id", "user(id)"},
{"Achievement", "author_id", "user(id)"},
{"Achievement", "team_id", "team(id)"},
{"Achievement", "challenge_validation_id", "challenge_validation(id)"},
{"ChallengeFlavor", "challenge_id", "challenge(id)"},
{"ChallengeInstance", "flavor_id", "challenge_flavor(id)"},
{"ChallengeInstance", "hypervisor_id", "hypervisor(id)"},
{"ChallengeSubscription", "season_challenge_id", "season_challenge(id)"},
{"ChallengeSubscription", "team_id", "team(id)"},
{"ChallengeSubscription", "author_id", "user(id)"},
{"ChallengeSubscription", "buyer_id", "user(id)"},
{"ChallengeSubscription", "closer_id", "user(id)"},
{"ChallengeValidation", "challenge_subscription_id", "challenge_subscription(id)"},
{"ChallengeValidation", "author_id", "user(id)"},
{"Coupon", "season_id", "season(id)"},
Expand Down
875 changes: 553 additions & 322 deletions go/pkg/pwdb/pwdb.pb.go

Large diffs are not rendered by default.

59 changes: 53 additions & 6 deletions go/pkg/pwengine/api_challenge-subscription-close.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,62 @@
package pwengine

import "context"
import (
"context"
"fmt"
"time"

"pathwar.land/go/pkg/pwdb"
)

func (e *engine) ChallengeSubscriptionClose(ctx context.Context, in *ChallengeSubscriptionCloseInput) (*ChallengeSubscriptionCloseOutput, error) {
{ // validation
if in.ChallengeSubscriptionID == 0 {
return nil, ErrMissingArgument
}
// validation
if in == nil || in.ChallengeSubscriptionID == 0 {
return nil, ErrMissingArgument
}

userID, err := userIDFromContext(ctx, e.db)
if err != nil {
return nil, fmt.Errorf("get userid from context: %w", err)
}

// fetch subscription
var subscription pwdb.ChallengeSubscription
err = e.db.
Preload("Team").
Preload("SeasonChallenge").
Preload("Validations").
Joins("JOIN team ON team.id = challenge_subscription.team_id").
Joins("JOIN team_member ON team_member.team_id = team.id AND team_member.user_id = ?", userID).
Where(pwdb.ChallengeSubscription{
Status: pwdb.ChallengeSubscription_Active,
}).
First(&subscription, in.ChallengeSubscriptionID).
Error
if err != nil {
return nil, ErrInvalidArgument // fmt.Errorf("fetch challenge subscription: %w", err)
}

ret := ChallengeSubscriptionCloseOutput{}
// check for required validations
// FIXME: check for required validation, not just for amount of validations
if len(subscription.Validations) == 0 {
return nil, ErrMissingRequiredValidation
}

// FIXME: add more validations

// update challenge subscription
now := time.Now()
err = e.db.
Model(&subscription).
Updates(pwdb.ChallengeSubscription{
Status: pwdb.ChallengeSubscription_Closed,
ClosedAt: &now,
CloserID: userID,
}).Error
if err != nil {
return nil, fmt.Errorf("update challenge subscription: %w", err)
}

ret := ChallengeSubscriptionCloseOutput{ChallengeSubscription: &subscription}
return &ret, nil
}
95 changes: 95 additions & 0 deletions go/pkg/pwengine/api_challenge-subscription-close_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package pwengine

import (
"context"
"testing"

"pathwar.land/go/internal/testutil"
"pathwar.land/go/pkg/pwdb"
)

func TestEngine_ChallengeSubscriptionClose(t *testing.T) {
engine, cleanup := TestingEngine(t, Opts{Logger: testutil.Logger(t)})
defer cleanup()
ctx := testingSetContextToken(context.Background(), t)

solo := testingSoloSeason(t, engine)

// fetch challenges
challenges, err := engine.SeasonChallengeList(ctx, &SeasonChallengeListInput{solo.ID})
if err != nil {
t.Fatalf("err: %v", err)
}

// fetch user session
session, err := engine.UserGetSession(ctx, nil)
if err != nil {
t.Fatalf("err: %v", err)
}
activeTeam := session.User.ActiveTeamMember.Team

// buy two challenges
subscription1, err := engine.SeasonChallengeBuy(ctx, &SeasonChallengeBuyInput{
SeasonChallengeID: challenges.Items[0].ID,
TeamID: activeTeam.ID,
})
if err != nil {
t.Fatalf("err: %v", err)
}
subscription2, err := engine.SeasonChallengeBuy(ctx, &SeasonChallengeBuyInput{
SeasonChallengeID: challenges.Items[1].ID,
TeamID: activeTeam.ID,
})
if err != nil {
t.Fatalf("err: %v", err)
}

// validate second challenge
_, err = engine.ChallengeSubscriptionValidate(ctx, &ChallengeSubscriptionValidateInput{
ChallengeSubscriptionID: subscription2.ChallengeSubscription.ID,
Passphrase: "secret",
})
if err != nil {
t.Fatalf("err: %v", err)
}

var tests = []struct {
name string
input *ChallengeSubscriptionCloseInput
expectedErr error
}{
{"nil", nil, ErrMissingArgument},
{"empty", &ChallengeSubscriptionCloseInput{}, ErrMissingArgument},
{"subscription1", &ChallengeSubscriptionCloseInput{ChallengeSubscriptionID: subscription1.ChallengeSubscription.ID}, ErrMissingRequiredValidation},
{"subscription2", &ChallengeSubscriptionCloseInput{ChallengeSubscriptionID: subscription2.ChallengeSubscription.ID}, nil},
{"subscription2", &ChallengeSubscriptionCloseInput{ChallengeSubscriptionID: subscription2.ChallengeSubscription.ID}, ErrInvalidArgument},
}
for _, test := range tests {
ret, err := engine.ChallengeSubscriptionClose(ctx, test.input)
if test.expectedErr != err {
t.Errorf("%s: Expected %v, got %v.", test.name, test.expectedErr, err)
}
if err != nil {
continue
}

if ret.ChallengeSubscription.ClosedAt == nil {
t.Errorf("%s: Expected ClosedAt != nil.", test.name)
}
if ret.ChallengeSubscription.CloserID != session.User.ID {
t.Errorf("%s: Expected %d, got %d.", test.name, session.User.ID, ret.ChallengeSubscription.CloserID)
}
if ret.ChallengeSubscription.Status != pwdb.ChallengeSubscription_Closed {
t.Errorf("%s: Expected %v, got %v.", test.name, pwdb.ChallengeSubscription_Closed, ret.ChallengeSubscription.Status)
}
if ret.ChallengeSubscription.Team.ID != activeTeam.ID {
t.Errorf("%s: Expected %d, got %d.", test.name, activeTeam.ID, ret.ChallengeSubscription.Team.ID)
}
if test.input.ChallengeSubscriptionID != ret.ChallengeSubscription.ID {
t.Errorf("%s: Expected %d, got %d.", test.name, test.input.ChallengeSubscriptionID, ret.ChallengeSubscription.ID)
}
if len(ret.ChallengeSubscription.Validations) == 0 {
t.Errorf("%s: should have at least one validation", test.name)
}
}
}
8 changes: 6 additions & 2 deletions go/pkg/pwengine/api_season-challenge-buy.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,8 @@ func (e *engine) SeasonChallengeBuy(ctx context.Context, in *SeasonChallengeBuyI
subscription := pwdb.ChallengeSubscription{
SeasonChallengeID: in.SeasonChallengeID,
TeamID: in.TeamID,
AuthorID: userID,
BuyerID: userID,
Status: pwdb.ChallengeSubscription_Active,
}
err = e.db.Create(&subscription).Error
if err != nil {
Expand All @@ -75,8 +76,11 @@ func (e *engine) SeasonChallengeBuy(ctx context.Context, in *SeasonChallengeBuyI
// load and return the freshly inserted entry
err = e.db.
Preload("Team").
Preload("Author").
Preload("Team.Season").
Preload("Buyer").
Preload("SeasonChallenge").
Preload("SeasonChallenge.Flavor").
Preload("SeasonChallenge.Flavor.Challenge").
First(&subscription, subscription.ID).
Error
if err != nil {
Expand Down
4 changes: 2 additions & 2 deletions go/pkg/pwengine/api_season-challenge-buy_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,8 +75,8 @@ func TestEngine_ChallengeBuy(t *testing.T) {
if subscription.ChallengeSubscription.SeasonChallengeID != test.input.SeasonChallengeID {
t.Errorf("%s: Expected %d, got %d.", test.name, test.input.SeasonChallengeID, subscription.ChallengeSubscription.SeasonChallengeID)
}
if subscription.ChallengeSubscription.AuthorID != session.User.ID {
t.Errorf("%s: Expected %d, got %d.", test.name, session.User.ID, subscription.ChallengeSubscription.AuthorID)
if subscription.ChallengeSubscription.BuyerID != session.User.ID {
t.Errorf("%s: Expected %d, got %d.", test.name, session.User.ID, subscription.ChallengeSubscription.BuyerID)
}
}
}
4 changes: 3 additions & 1 deletion go/pkg/pwengine/api_season-challenge-list.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@ func (e *engine) SeasonChallengeList(ctx context.Context, in *SeasonChallengeLis

var ret SeasonChallengeListOutput
err := e.db.
Set("gorm:auto_preload", true).
Preload("Season").
Preload("Flavor").
Preload("Flavor.Challenge").
Where(pwdb.SeasonChallenge{SeasonID: in.SeasonID}).
Find(&ret.Items).
Error
Expand Down
9 changes: 5 additions & 4 deletions go/pkg/pwengine/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package pwengine
import "errors"

var (
ErrNotImplemented = errors.New("not implemented")
ErrMissingArgument = errors.New("missing argument(s)")
ErrInvalidArgument = errors.New("invalid argument(s)")
ErrDuplicate = errors.New("duplicate")
ErrNotImplemented = errors.New("not implemented")
ErrMissingArgument = errors.New("missing argument(s)")
ErrInvalidArgument = errors.New("invalid argument(s)")
ErrDuplicate = errors.New("duplicate")
ErrMissingRequiredValidation = errors.New("missing required validation")
)
Loading

0 comments on commit 27f0378

Please sign in to comment.