add user credit usage method into console service (#2240)

This commit is contained in:
Yingrong Zhao 2019-06-19 16:49:04 -04:00 committed by Stefan Benten
parent 213bcacc83
commit d583ab707b
5 changed files with 84 additions and 75 deletions

View File

@ -21,9 +21,7 @@ import (
"storj.io/storj/satellite/payments" "storj.io/storj/satellite/payments"
) )
var ( var mon = monkit.Package()
mon = monkit.Package()
)
const ( const (
// maxLimit specifies the limit for all paged queries // maxLimit specifies the limit for all paged queries
@ -457,6 +455,22 @@ func (s *Service) GetUsersProjects(ctx context.Context) (ps []Project, err error
return return
} }
// GetUserCreditUsage is a method for querying users' credit information up until now
func (s *Service) GetUserCreditUsage(ctx context.Context) (usage *UserCreditUsage, err error) {
defer mon.Task()(&ctx)(&err)
auth, err := GetAuth(ctx)
if err != nil {
return nil, errs.Wrap(err)
}
usage, err = s.store.UserCredits().GetCreditUsage(ctx, auth.User.ID, time.Now().UTC())
if err != nil {
return nil, errs.Wrap(err)
}
return usage, nil
}
// CreateProject is a method for creating new project // CreateProject is a method for creating new project
func (s *Service) CreateProject(ctx context.Context, projectInfo ProjectInfo) (p *Project, err error) { func (s *Service) CreateProject(ctx context.Context, projectInfo ProjectInfo) (p *Project, err error) {
defer mon.Task()(&ctx)(&err) defer mon.Task()(&ctx)(&err)

View File

@ -12,8 +12,7 @@ import (
// UserCredits holds information to interact with database // UserCredits holds information to interact with database
type UserCredits interface { type UserCredits interface {
TotalReferredCount(ctx context.Context, userID uuid.UUID) (int64, error) GetCreditUsage(ctx context.Context, userID uuid.UUID, expirationEndDate time.Time) (*UserCreditUsage, error)
GetAvailableCredits(ctx context.Context, userID uuid.UUID, expirationEndDate time.Time) ([]UserCredit, error)
Create(ctx context.Context, userCredit UserCredit) (*UserCredit, error) Create(ctx context.Context, userCredit UserCredit) (*UserCredit, error)
UpdateAvailableCredits(ctx context.Context, creditsToCharge int, id uuid.UUID, billingStartDate time.Time) (remainingCharge int, err error) UpdateAvailableCredits(ctx context.Context, creditsToCharge int, id uuid.UUID, billingStartDate time.Time) (remainingCharge int, err error)
} }
@ -29,3 +28,10 @@ type UserCredit struct {
ExpiresAt time.Time ExpiresAt time.Time
CreatedAt time.Time CreatedAt time.Time
} }
// UserCreditUsage holds information about credit usage information
type UserCreditUsage struct {
Referred int64
AvailableCredits int64
UsedCredits int64
}

View File

@ -503,16 +503,10 @@ func (m *lockedUserCredits) Create(ctx context.Context, userCredit console.UserC
return m.db.Create(ctx, userCredit) return m.db.Create(ctx, userCredit)
} }
func (m *lockedUserCredits) GetAvailableCredits(ctx context.Context, userID uuid.UUID, expirationEndDate time.Time) ([]console.UserCredit, error) { func (m *lockedUserCredits) GetCreditUsage(ctx context.Context, userID uuid.UUID, expirationEndDate time.Time) (*console.UserCreditUsage, error) {
m.Lock() m.Lock()
defer m.Unlock() defer m.Unlock()
return m.db.GetAvailableCredits(ctx, userID, expirationEndDate) return m.db.GetCreditUsage(ctx, userID, expirationEndDate)
}
func (m *lockedUserCredits) TotalReferredCount(ctx context.Context, userID uuid.UUID) (int64, error) {
m.Lock()
defer m.Unlock()
return m.db.TotalReferredCount(ctx, userID)
} }
func (m *lockedUserCredits) UpdateAvailableCredits(ctx context.Context, creditsToCharge int, id uuid.UUID, billingStartDate time.Time) (remainingCharge int, err error) { func (m *lockedUserCredits) UpdateAvailableCredits(ctx context.Context, creditsToCharge int, id uuid.UUID, billingStartDate time.Time) (remainingCharge int, err error) {

View File

@ -5,6 +5,7 @@ package satellitedb
import ( import (
"context" "context"
"database/sql"
"time" "time"
"github.com/lib/pq" "github.com/lib/pq"
@ -20,27 +21,36 @@ type usercredits struct {
db *dbx.DB db *dbx.DB
} }
// TotalReferredCount returns the total amount of referral a user has made based on user id // GetCreditUsage returns the total amount of referral a user has made based on user id, total available credits, and total used credits based on user id
func (c *usercredits) TotalReferredCount(ctx context.Context, id uuid.UUID) (int64, error) { func (c *usercredits) GetCreditUsage(ctx context.Context, userID uuid.UUID, expirationEndDate time.Time) (*console.UserCreditUsage, error) {
totalReferred, err := c.db.Count_UserCredit_By_ReferredBy(ctx, dbx.UserCredit_ReferredBy(id[:])) usageRows, err := c.db.DB.QueryContext(ctx, c.db.Rebind(`SELECT a.used_credit, b.available_credit, c.referred
if err != nil { FROM (SELECT SUM(credits_used_in_cents) AS used_credit FROM user_credits WHERE user_id = ?) AS a,
return totalReferred, errs.Wrap(err) (SELECT SUM(credits_earned_in_cents - credits_used_in_cents) AS available_credit FROM user_credits WHERE expires_at > ? AND user_id = ?) AS b,
} (SELECT count(id) AS referred FROM user_credits WHERE user_credits.referred_by = ?) AS c;`), userID[:], expirationEndDate, userID[:], userID[:])
return totalReferred, nil
}
// GetAvailableCredits returns all records of user credit that are not expired or used
func (c *usercredits) GetAvailableCredits(ctx context.Context, referrerID uuid.UUID, expirationEndDate time.Time) ([]console.UserCredit, error) {
availableCredits, err := c.db.All_UserCredit_By_UserId_And_ExpiresAt_Greater_And_CreditsUsedInCents_Less_CreditsEarnedInCents_OrderBy_Asc_ExpiresAt(ctx,
dbx.UserCredit_UserId(referrerID[:]),
dbx.UserCredit_ExpiresAt(expirationEndDate),
)
if err != nil { if err != nil {
return nil, errs.Wrap(err) return nil, errs.Wrap(err)
} }
return userCreditsFromDBX(availableCredits) usage := console.UserCreditUsage{}
for usageRows.Next() {
var (
usedCredit sql.NullInt64
availableCredit sql.NullInt64
referred sql.NullInt64
)
err = usageRows.Scan(&usedCredit, &availableCredit, &referred)
if err != nil {
return nil, errs.Wrap(err)
}
usage.UsedCredits += usedCredit.Int64
usage.Referred += referred.Int64
usage.AvailableCredits += availableCredit.Int64
}
return &usage, nil
} }
// Create insert a new record of user credit // Create insert a new record of user credit
@ -141,23 +151,6 @@ func generateQuery(totalRows int, toInt bool) (query string) {
return query return query
} }
func userCreditsFromDBX(userCreditsDBX []*dbx.UserCredit) ([]console.UserCredit, error) {
var userCredits []console.UserCredit
errList := new(errs.Group)
for _, credit := range userCreditsDBX {
uc, err := convertDBCredit(credit)
if err != nil {
errList.Add(err)
continue
}
userCredits = append(userCredits, *uc)
}
return userCredits, errList.Err()
}
func convertDBCredit(userCreditDBX *dbx.UserCredit) (*console.UserCredit, error) { func convertDBCredit(userCreditDBX *dbx.UserCredit) (*console.UserCredit, error) {
if userCreditDBX == nil { if userCreditDBX == nil {
return nil, errs.New("userCreditDBX parameter is nil") return nil, errs.New("userCreditDBX parameter is nil")

View File

@ -66,9 +66,9 @@ func TestUsercredits(t *testing.T) {
} }
type result struct { type result struct {
remainingCharge int remainingCharge int
availableCredits int usage console.UserCreditUsage
hasErr bool hasErr bool
} }
var validUserCredits = []struct { var validUserCredits = []struct {
@ -86,9 +86,13 @@ func TestUsercredits(t *testing.T) {
}, },
chargedCredits: 120, chargedCredits: 120,
expected: result{ expected: result{
remainingCharge: 20, remainingCharge: 20,
availableCredits: 0, usage: console.UserCreditUsage{
hasErr: false, AvailableCredits: 0,
UsedCredits: 100,
Referred: 0,
},
hasErr: false,
}, },
}, },
{ {
@ -102,9 +106,13 @@ func TestUsercredits(t *testing.T) {
}, },
chargedCredits: 60, chargedCredits: 60,
expected: result{ expected: result{
remainingCharge: 60, remainingCharge: 60,
availableCredits: 0, usage: console.UserCreditUsage{
hasErr: true, AvailableCredits: 0,
UsedCredits: 100,
Referred: 0,
},
hasErr: true,
}, },
}, },
{ {
@ -118,9 +126,13 @@ func TestUsercredits(t *testing.T) {
}, },
chargedCredits: 80, chargedCredits: 80,
expected: result{ expected: result{
remainingCharge: 0, remainingCharge: 0,
availableCredits: 20, usage: console.UserCreditUsage{
hasErr: false, AvailableCredits: 20,
UsedCredits: 180,
Referred: 0,
},
hasErr: false,
}, },
}, },
} }
@ -129,16 +141,6 @@ func TestUsercredits(t *testing.T) {
_, err = consoleDB.UserCredits().Create(ctx, vc.userCredit) _, err = consoleDB.UserCredits().Create(ctx, vc.userCredit)
require.NoError(t, err) require.NoError(t, err)
{
referredCount, err := consoleDB.UserCredits().TotalReferredCount(ctx, vc.userCredit.ReferredBy)
if err != nil {
require.True(t, uuid.Equal(*randomID, vc.userCredit.ReferredBy))
continue
}
require.NoError(t, err)
require.Equal(t, int64(i+1), referredCount)
}
{ {
remainingCharge, err := consoleDB.UserCredits().UpdateAvailableCredits(ctx, vc.chargedCredits, vc.userCredit.UserID, time.Now().UTC()) remainingCharge, err := consoleDB.UserCredits().UpdateAvailableCredits(ctx, vc.chargedCredits, vc.userCredit.UserID, time.Now().UTC())
if vc.expected.hasErr { if vc.expected.hasErr {
@ -150,15 +152,15 @@ func TestUsercredits(t *testing.T) {
} }
{ {
availableCredits, err := consoleDB.UserCredits().GetAvailableCredits(ctx, vc.userCredit.UserID, time.Now().UTC()) usage, err := consoleDB.UserCredits().GetCreditUsage(ctx, vc.userCredit.UserID, time.Now().UTC())
require.NoError(t, err) require.NoError(t, err)
var sum int require.Equal(t, vc.expected.usage, *usage)
for i := range availableCredits { }
sum += availableCredits[i].CreditsEarnedInCents - availableCredits[i].CreditsUsedInCents
}
{
referred, err := consoleDB.UserCredits().GetCreditUsage(ctx, referrer.ID, time.Now().UTC())
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, vc.expected.availableCredits, sum) require.Equal(t, int64(i+1), referred.Referred)
} }
} }
}) })