satellite/{db,console,billing}: fix legal/violation freeze
This change fixes the behavior of legal freeze; it now does not allow lists and deletes for users in that freeze. It also fixes an issue where users who have been legal/violation frozen will have their limits upgraded, partially exiting freeze status when they pay with STORJ tokens. Issue: storj/storj-private/#517 storj/storj-private/#515 Change-Id: I6fa2b6353159984883c60a2888617da1ee51ce0a
This commit is contained in:
parent
e1c12674c5
commit
0590eadc17
@ -199,7 +199,8 @@ func TestProjectLimitCache(t *testing.T) {
|
|||||||
require.EqualValues(t, expectedSegmentLimit, *actualSegmentLimitFromDB)
|
require.EqualValues(t, expectedSegmentLimit, *actualSegmentLimitFromDB)
|
||||||
|
|
||||||
// rate and burst limit
|
// rate and burst limit
|
||||||
require.NoError(t, projects.UpdateRateLimit(ctx, secondTestProject.ID, expectedRateLimit))
|
rateLimit := expectedRateLimit
|
||||||
|
require.NoError(t, projects.UpdateRateLimit(ctx, secondTestProject.ID, &rateLimit))
|
||||||
require.NoError(t, projects.UpdateBurstLimit(ctx, secondTestProject.ID, expectedBurstLimit))
|
require.NoError(t, projects.UpdateBurstLimit(ctx, secondTestProject.ID, expectedBurstLimit))
|
||||||
|
|
||||||
limits, err := projectLimitCache.GetLimits(ctx, secondTestProject.ID)
|
limits, err := projectLimitCache.GetLimits(ctx, secondTestProject.ID)
|
||||||
|
@ -248,7 +248,7 @@ func (server *Server) putProjectLimit(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = server.db.Console().Projects().UpdateRateLimit(ctx, project.ID, *arguments.Rate)
|
err = server.db.Console().Projects().UpdateRateLimit(ctx, project.ID, arguments.Rate)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
sendJSONError(w, "failed to update rate",
|
sendJSONError(w, "failed to update rate",
|
||||||
err.Error(), http.StatusInternalServerError)
|
err.Error(), http.StatusInternalServerError)
|
||||||
|
@ -556,6 +556,11 @@ func (s *AccountFreezeService) LegalFreezeUser(ctx context.Context, userID uuid.
|
|||||||
return errs.New("User is already frozen due to ToS violation")
|
return errs.New("User is already frozen due to ToS violation")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var limits *AccountFreezeEventLimits
|
||||||
|
if freezes.BillingFreeze != nil {
|
||||||
|
limits = freezes.BillingFreeze.Limits
|
||||||
|
}
|
||||||
|
|
||||||
userLimits := UsageLimits{
|
userLimits := UsageLimits{
|
||||||
Storage: user.ProjectStorageLimit,
|
Storage: user.ProjectStorageLimit,
|
||||||
Bandwidth: user.ProjectBandwidthLimit,
|
Bandwidth: user.ProjectBandwidthLimit,
|
||||||
@ -564,13 +569,16 @@ func (s *AccountFreezeService) LegalFreezeUser(ctx context.Context, userID uuid.
|
|||||||
|
|
||||||
legalFreeze := freezes.LegalFreeze
|
legalFreeze := freezes.LegalFreeze
|
||||||
if legalFreeze == nil {
|
if legalFreeze == nil {
|
||||||
|
if limits == nil {
|
||||||
|
limits = &AccountFreezeEventLimits{
|
||||||
|
User: userLimits,
|
||||||
|
Projects: make(map[uuid.UUID]UsageLimits),
|
||||||
|
}
|
||||||
|
}
|
||||||
legalFreeze = &AccountFreezeEvent{
|
legalFreeze = &AccountFreezeEvent{
|
||||||
UserID: userID,
|
UserID: userID,
|
||||||
Type: LegalFreeze,
|
Type: LegalFreeze,
|
||||||
Limits: &AccountFreezeEventLimits{
|
Limits: limits,
|
||||||
User: userLimits,
|
|
||||||
Projects: make(map[uuid.UUID]UsageLimits),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -595,9 +603,15 @@ func (s *AccountFreezeService) LegalFreezeUser(ctx context.Context, userID uuid.
|
|||||||
projLimits.Segment = *p.SegmentLimit
|
projLimits.Segment = *p.SegmentLimit
|
||||||
}
|
}
|
||||||
// If project limits have been zeroed already, we should not override what is in the freeze table.
|
// If project limits have been zeroed already, we should not override what is in the freeze table.
|
||||||
if projLimits != (UsageLimits{}) {
|
if projLimits == (UsageLimits{}) {
|
||||||
legalFreeze.Limits.Projects[p.ID] = projLimits
|
if freezes.BillingFreeze == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// if limits were zeroed in a billing freeze, we should use those
|
||||||
|
projLimits = freezes.BillingFreeze.Limits.Projects[p.ID]
|
||||||
}
|
}
|
||||||
|
projLimits.RateLimit = p.RateLimit
|
||||||
|
legalFreeze.Limits.Projects[p.ID] = projLimits
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = tx.AccountFreezeEvents().Upsert(ctx, legalFreeze)
|
_, err = tx.AccountFreezeEvents().Upsert(ctx, legalFreeze)
|
||||||
@ -615,6 +629,13 @@ func (s *AccountFreezeService) LegalFreezeUser(ctx context.Context, userID uuid.
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// zero project's rate limit to prevent lists/deletes
|
||||||
|
zeroLimit := 0
|
||||||
|
err = tx.Projects().UpdateRateLimit(ctx, proj.ID, &zeroLimit)
|
||||||
|
if err != nil {
|
||||||
|
return ErrAccountFreeze.Wrap(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if freezes.BillingWarning != nil {
|
if freezes.BillingWarning != nil {
|
||||||
@ -662,6 +683,12 @@ func (s *AccountFreezeService) LegalUnfreezeUser(ctx context.Context, userID uui
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// remove rate limit
|
||||||
|
err = tx.Projects().UpdateRateLimit(ctx, id, limits.RateLimit)
|
||||||
|
if err != nil {
|
||||||
|
return ErrAccountFreeze.Wrap(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = tx.Users().UpdateUserProjectLimits(ctx, userID, event.Limits.User)
|
err = tx.Users().UpdateUserProjectLimits(ctx, userID, event.Limits.User)
|
||||||
|
@ -16,6 +16,7 @@ import (
|
|||||||
"storj.io/storj/private/testplanet"
|
"storj.io/storj/private/testplanet"
|
||||||
"storj.io/storj/satellite"
|
"storj.io/storj/satellite"
|
||||||
"storj.io/storj/satellite/console"
|
"storj.io/storj/satellite/console"
|
||||||
|
"storj.io/uplink"
|
||||||
)
|
)
|
||||||
|
|
||||||
func getUserLimits(u *console.User) console.UsageLimits {
|
func getUserLimits(u *console.User) console.UsageLimits {
|
||||||
@ -31,6 +32,7 @@ func getProjectLimits(p *console.Project) console.UsageLimits {
|
|||||||
Storage: p.StorageLimit.Int64(),
|
Storage: p.StorageLimit.Int64(),
|
||||||
Bandwidth: p.BandwidthLimit.Int64(),
|
Bandwidth: p.BandwidthLimit.Int64(),
|
||||||
Segment: *p.SegmentLimit,
|
Segment: *p.SegmentLimit,
|
||||||
|
RateLimit: p.RateLimit,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -261,18 +263,26 @@ func TestAccountLegalFreeze(t *testing.T) {
|
|||||||
require.NoError(t, usersDB.UpdateUserProjectLimits(ctx, user.ID, userLimits))
|
require.NoError(t, usersDB.UpdateUserProjectLimits(ctx, user.ID, userLimits))
|
||||||
|
|
||||||
projLimits := randUsageLimits()
|
projLimits := randUsageLimits()
|
||||||
|
rateLimit := 20000
|
||||||
|
projLimits.RateLimit = &rateLimit
|
||||||
proj, err := sat.AddProject(ctx, user.ID, "")
|
proj, err := sat.AddProject(ctx, user.ID, "")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NoError(t, projectsDB.UpdateUsageLimits(ctx, proj.ID, projLimits))
|
require.NoError(t, projectsDB.UpdateUsageLimits(ctx, proj.ID, projLimits))
|
||||||
|
require.NoError(t, projectsDB.UpdateRateLimit(ctx, proj.ID, projLimits.RateLimit))
|
||||||
|
|
||||||
checkLimits := func(testT *testing.T) {
|
checkLimits := func(t *testing.T) {
|
||||||
user, err = usersDB.Get(ctx, user.ID)
|
user, err = usersDB.Get(ctx, user.ID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Zero(t, getUserLimits(user))
|
require.Zero(t, getUserLimits(user))
|
||||||
|
|
||||||
proj, err = projectsDB.Get(ctx, proj.ID)
|
proj, err = projectsDB.Get(ctx, proj.ID)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Zero(t, getProjectLimits(proj))
|
usageLimits := getProjectLimits(proj)
|
||||||
|
require.Zero(t, usageLimits.Segment)
|
||||||
|
require.Zero(t, usageLimits.Storage)
|
||||||
|
require.Zero(t, usageLimits.Bandwidth)
|
||||||
|
zeroLimit := 0
|
||||||
|
require.Equal(t, &zeroLimit, usageLimits.RateLimit)
|
||||||
}
|
}
|
||||||
|
|
||||||
frozen, err := service.IsUserFrozen(ctx, user.ID, console.LegalFreeze)
|
frozen, err := service.IsUserFrozen(ctx, user.ID, console.LegalFreeze)
|
||||||
@ -322,6 +332,16 @@ func TestAccountLegalFreeze(t *testing.T) {
|
|||||||
require.Nil(t, freezes.LegalFreeze.DaysTillEscalation)
|
require.Nil(t, freezes.LegalFreeze.DaysTillEscalation)
|
||||||
|
|
||||||
checkLimits(t)
|
checkLimits(t)
|
||||||
|
|
||||||
|
require.NoError(t, service.LegalUnfreezeUser(ctx, user.ID))
|
||||||
|
|
||||||
|
user, err = usersDB.Get(ctx, user.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, userLimits, getUserLimits(user))
|
||||||
|
|
||||||
|
proj, err = projectsDB.Get(ctx, proj.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, projLimits, getProjectLimits(proj))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -490,6 +510,9 @@ func TestFreezeEffects(t *testing.T) {
|
|||||||
Reconfigure: testplanet.Reconfigure{
|
Reconfigure: testplanet.Reconfigure{
|
||||||
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
|
Satellite: func(log *zap.Logger, index int, config *satellite.Config) {
|
||||||
config.AccountFreeze.Enabled = true
|
config.AccountFreeze.Enabled = true
|
||||||
|
// disable limit caching
|
||||||
|
config.ProjectLimit.CacheCapacity = 0
|
||||||
|
config.Metainfo.RateLimiter.CacheCapacity = 0
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
||||||
@ -520,67 +543,86 @@ func TestFreezeEffects(t *testing.T) {
|
|||||||
shouldNotUploadAndDownload := func(testT *testing.T) {
|
shouldNotUploadAndDownload := func(testT *testing.T) {
|
||||||
// Should not be able to upload because account is frozen.
|
// Should not be able to upload because account is frozen.
|
||||||
err = uplink1.Upload(ctx, sat, bucketName, path, expectedData)
|
err = uplink1.Upload(ctx, sat, bucketName, path, expectedData)
|
||||||
require.Error(t, err)
|
require.Error(testT, err)
|
||||||
|
|
||||||
// Should not be able to download because account is frozen.
|
// Should not be able to download because account is frozen.
|
||||||
_, err = uplink1.Download(ctx, sat, bucketName, path)
|
_, err = uplink1.Download(ctx, sat, bucketName, path)
|
||||||
require.Error(t, err)
|
require.Error(testT, err)
|
||||||
|
|
||||||
// Should not be able to create bucket because account is frozen.
|
// Should not be able to create bucket because account is frozen.
|
||||||
err = uplink1.CreateBucket(ctx, sat, "anotherBucket")
|
err = uplink1.CreateBucket(ctx, sat, "anotherBucket")
|
||||||
require.Error(t, err)
|
require.Error(testT, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldListAndDelete := func(testT *testing.T) {
|
shouldListAndDelete := func(testT *testing.T) {
|
||||||
// Should be able to list even if frozen.
|
// Should be able to list even if frozen.
|
||||||
objects, err := uplink1.ListObjects(ctx, sat, bucketName)
|
_, err := uplink1.ListObjects(ctx, sat, bucketName)
|
||||||
require.NoError(t, err)
|
require.NoError(testT, err)
|
||||||
require.Len(t, objects, 1)
|
|
||||||
|
|
||||||
// Should be able to delete even if frozen.
|
// Should be able to delete even if frozen.
|
||||||
err = uplink1.DeleteObject(ctx, sat, bucketName, path)
|
err = uplink1.DeleteObject(ctx, sat, bucketName, path)
|
||||||
require.NoError(t, err)
|
require.NoError(testT, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
shouldNotListAndDelete := func(testT *testing.T) {
|
||||||
|
// Should not be able to list.
|
||||||
|
_, err := uplink1.ListObjects(ctx, sat, bucketName)
|
||||||
|
require.Error(testT, err)
|
||||||
|
require.ErrorIs(testT, err, uplink.ErrTooManyRequests)
|
||||||
|
|
||||||
|
// Should not be able to delete.
|
||||||
|
err = uplink1.DeleteObject(ctx, sat, bucketName, path)
|
||||||
|
require.Error(testT, err)
|
||||||
|
require.ErrorIs(testT, err, uplink.ErrTooManyRequests)
|
||||||
}
|
}
|
||||||
|
|
||||||
t.Run("BillingFreeze effect on project owner", func(t *testing.T) {
|
t.Run("BillingFreeze effect on project owner", func(t *testing.T) {
|
||||||
shouldUploadAndDownload(t)
|
shouldUploadAndDownload(t)
|
||||||
|
shouldListAndDelete(t)
|
||||||
|
|
||||||
require.NoError(t, freezeService.BillingWarnUser(ctx, user1.ID))
|
require.NoError(t, freezeService.BillingWarnUser(ctx, user1.ID))
|
||||||
|
|
||||||
// Should be able to download because account is not frozen.
|
// Should be able to download and list because account is not frozen.
|
||||||
shouldUploadAndDownload(t)
|
shouldUploadAndDownload(t)
|
||||||
|
shouldListAndDelete(t)
|
||||||
|
|
||||||
require.NoError(t, freezeService.BillingFreezeUser(ctx, user1.ID))
|
require.NoError(t, freezeService.BillingFreezeUser(ctx, user1.ID))
|
||||||
|
|
||||||
shouldNotUploadAndDownload(t)
|
shouldNotUploadAndDownload(t)
|
||||||
|
|
||||||
shouldListAndDelete(t)
|
shouldListAndDelete(t)
|
||||||
|
|
||||||
require.NoError(t, freezeService.BillingUnfreezeUser(ctx, user1.ID))
|
require.NoError(t, freezeService.BillingUnfreezeUser(ctx, user1.ID))
|
||||||
|
|
||||||
|
shouldUploadAndDownload(t)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("ViolationFreeze effect on project owner", func(t *testing.T) {
|
t.Run("ViolationFreeze effect on project owner", func(t *testing.T) {
|
||||||
shouldUploadAndDownload(t)
|
shouldUploadAndDownload(t)
|
||||||
|
shouldListAndDelete(t)
|
||||||
|
|
||||||
require.NoError(t, freezeService.ViolationFreezeUser(ctx, user1.ID))
|
require.NoError(t, freezeService.ViolationFreezeUser(ctx, user1.ID))
|
||||||
|
|
||||||
shouldNotUploadAndDownload(t)
|
shouldNotUploadAndDownload(t)
|
||||||
|
|
||||||
shouldListAndDelete(t)
|
shouldListAndDelete(t)
|
||||||
|
|
||||||
require.NoError(t, freezeService.ViolationUnfreezeUser(ctx, user1.ID))
|
require.NoError(t, freezeService.ViolationUnfreezeUser(ctx, user1.ID))
|
||||||
|
|
||||||
|
shouldUploadAndDownload(t)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("LegalFreeze effect on project owner", func(t *testing.T) {
|
t.Run("LegalFreeze effect on project owner", func(t *testing.T) {
|
||||||
shouldUploadAndDownload(t)
|
shouldUploadAndDownload(t)
|
||||||
|
shouldListAndDelete(t)
|
||||||
|
|
||||||
require.NoError(t, freezeService.LegalFreezeUser(ctx, user1.ID))
|
require.NoError(t, freezeService.LegalFreezeUser(ctx, user1.ID))
|
||||||
|
|
||||||
shouldNotUploadAndDownload(t)
|
shouldNotUploadAndDownload(t)
|
||||||
|
shouldNotListAndDelete(t)
|
||||||
shouldListAndDelete(t)
|
|
||||||
|
|
||||||
require.NoError(t, freezeService.LegalUnfreezeUser(ctx, user1.ID))
|
require.NoError(t, freezeService.LegalUnfreezeUser(ctx, user1.ID))
|
||||||
|
|
||||||
|
shouldListAndDelete(t)
|
||||||
|
shouldUploadAndDownload(t)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -18,15 +18,17 @@ type UpgradeUserObserver struct {
|
|||||||
transactionsDB billing.TransactionsDB
|
transactionsDB billing.TransactionsDB
|
||||||
usageLimitsConfig UsageLimitsConfig
|
usageLimitsConfig UsageLimitsConfig
|
||||||
userBalanceForUpgrade int64
|
userBalanceForUpgrade int64
|
||||||
|
freezeService *AccountFreezeService
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewUpgradeUserObserver creates new observer instance.
|
// NewUpgradeUserObserver creates new observer instance.
|
||||||
func NewUpgradeUserObserver(consoleDB DB, transactionsDB billing.TransactionsDB, usageLimitsConfig UsageLimitsConfig, userBalanceForUpgrade int64) *UpgradeUserObserver {
|
func NewUpgradeUserObserver(consoleDB DB, transactionsDB billing.TransactionsDB, usageLimitsConfig UsageLimitsConfig, userBalanceForUpgrade int64, freezeService *AccountFreezeService) *UpgradeUserObserver {
|
||||||
return &UpgradeUserObserver{
|
return &UpgradeUserObserver{
|
||||||
consoleDB: consoleDB,
|
consoleDB: consoleDB,
|
||||||
transactionsDB: transactionsDB,
|
transactionsDB: transactionsDB,
|
||||||
usageLimitsConfig: usageLimitsConfig,
|
usageLimitsConfig: usageLimitsConfig,
|
||||||
userBalanceForUpgrade: userBalanceForUpgrade,
|
userBalanceForUpgrade: userBalanceForUpgrade,
|
||||||
|
freezeService: freezeService,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,6 +36,16 @@ func NewUpgradeUserObserver(consoleDB DB, transactionsDB billing.TransactionsDB,
|
|||||||
func (o *UpgradeUserObserver) Process(ctx context.Context, transaction billing.Transaction) (err error) {
|
func (o *UpgradeUserObserver) Process(ctx context.Context, transaction billing.Transaction) (err error) {
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
|
freezes, err := o.freezeService.GetAll(ctx, transaction.UserID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if freezes.LegalFreeze != nil || freezes.ViolationFreeze != nil {
|
||||||
|
// user can not exit these freezes by paying with tokens
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
user, err := o.consoleDB.Users().Get(ctx, transaction.UserID)
|
user, err := o.consoleDB.Users().Get(ctx, transaction.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -43,7 +43,7 @@ type Projects interface {
|
|||||||
ListByOwnerID(ctx context.Context, userID uuid.UUID, cursor ProjectsCursor) (ProjectsPage, error)
|
ListByOwnerID(ctx context.Context, userID uuid.UUID, cursor ProjectsCursor) (ProjectsPage, error)
|
||||||
|
|
||||||
// UpdateRateLimit is a method for updating projects rate limit.
|
// UpdateRateLimit is a method for updating projects rate limit.
|
||||||
UpdateRateLimit(ctx context.Context, id uuid.UUID, newLimit int) error
|
UpdateRateLimit(ctx context.Context, id uuid.UUID, newLimit *int) error
|
||||||
|
|
||||||
// UpdateBurstLimit is a method for updating projects burst limit.
|
// UpdateBurstLimit is a method for updating projects burst limit.
|
||||||
UpdateBurstLimit(ctx context.Context, id uuid.UUID, newLimit int) error
|
UpdateBurstLimit(ctx context.Context, id uuid.UUID, newLimit int) error
|
||||||
|
@ -442,7 +442,7 @@ func TestRateLimit_ProjectRateLimitZero(t *testing.T) {
|
|||||||
require.Len(t, projects, 1)
|
require.Len(t, projects, 1)
|
||||||
|
|
||||||
zeroRateLimit := 0
|
zeroRateLimit := 0
|
||||||
err = satellite.DB.Console().Projects().UpdateRateLimit(ctx, projects[0].ID, zeroRateLimit)
|
err = satellite.DB.Console().Projects().UpdateRateLimit(ctx, projects[0].ID, &zeroRateLimit)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
var group errs2.Group
|
var group errs2.Group
|
||||||
|
@ -24,4 +24,5 @@ type UsageLimits struct {
|
|||||||
Storage int64 `json:"storage"`
|
Storage int64 `json:"storage"`
|
||||||
Bandwidth int64 `json:"bandwidth"`
|
Bandwidth int64 `json:"bandwidth"`
|
||||||
Segment int64 `json:"segment"`
|
Segment int64 `json:"segment"`
|
||||||
|
RateLimit *int `json:"rateLimit"`
|
||||||
}
|
}
|
||||||
|
@ -525,15 +525,12 @@ func New(log *zap.Logger, full *identity.FullIdentity, db DB,
|
|||||||
debug.Cycle("Payments Storjscan", peer.Payments.StorjscanChore.TransactionCycle),
|
debug.Cycle("Payments Storjscan", peer.Payments.StorjscanChore.TransactionCycle),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
freezeService := console.NewAccountFreezeService(peer.DB.Console(), peer.Analytics.Service, config.Console.AccountFreeze)
|
||||||
choreObservers := billing.ChoreObservers{
|
choreObservers := billing.ChoreObservers{
|
||||||
UpgradeUser: console.NewUpgradeUserObserver(peer.DB.Console(), peer.DB.Billing(), config.Console.UsageLimits, config.Console.UserBalanceForUpgrade),
|
UpgradeUser: console.NewUpgradeUserObserver(peer.DB.Console(), peer.DB.Billing(), config.Console.UsageLimits, config.Console.UserBalanceForUpgrade, freezeService),
|
||||||
PayInvoices: console.NewInvoiceTokenPaymentObserver(
|
PayInvoices: console.NewInvoiceTokenPaymentObserver(
|
||||||
peer.DB.Console(), peer.Payments.Accounts.Invoices(),
|
peer.DB.Console(), peer.Payments.Accounts.Invoices(),
|
||||||
console.NewAccountFreezeService(
|
freezeService,
|
||||||
peer.DB.Console(),
|
|
||||||
peer.Analytics.Service,
|
|
||||||
config.Console.AccountFreeze,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -76,7 +76,7 @@ func TestChore(t *testing.T) {
|
|||||||
assert.Equal(t, expected, actual, "unexpected balance for user %s (%q)", userID, names[userID])
|
assert.Equal(t, expected, actual, "unexpected balance for user %s (%q)", userID, names[userID])
|
||||||
}
|
}
|
||||||
|
|
||||||
runTest := func(ctx *testcontext.Context, t *testing.T, consoleDB console.DB, db billing.TransactionsDB, bonusRate int64, mikeTXs, joeTXs, robertTXs []billing.Transaction, mikeBalance, joeBalance, robertBalance currency.Amount, usageLimitsConfig console.UsageLimitsConfig, userBalanceForUpgrade int64) {
|
runTest := func(ctx *testcontext.Context, t *testing.T, consoleDB console.DB, db billing.TransactionsDB, bonusRate int64, mikeTXs, joeTXs, robertTXs []billing.Transaction, mikeBalance, joeBalance, robertBalance currency.Amount, usageLimitsConfig console.UsageLimitsConfig, userBalanceForUpgrade int64, freezeService *console.AccountFreezeService) {
|
||||||
paymentTypes := []billing.PaymentType{
|
paymentTypes := []billing.PaymentType{
|
||||||
newFakePaymentType(billing.StorjScanSource,
|
newFakePaymentType(billing.StorjScanSource,
|
||||||
[]billing.Transaction{mike1, joe1, joe2},
|
[]billing.Transaction{mike1, joe1, joe2},
|
||||||
@ -88,7 +88,7 @@ func TestChore(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
choreObservers := billing.ChoreObservers{
|
choreObservers := billing.ChoreObservers{
|
||||||
UpgradeUser: console.NewUpgradeUserObserver(consoleDB, db, usageLimitsConfig, userBalanceForUpgrade),
|
UpgradeUser: console.NewUpgradeUserObserver(consoleDB, db, usageLimitsConfig, userBalanceForUpgrade, freezeService),
|
||||||
}
|
}
|
||||||
|
|
||||||
chore := billing.NewChore(zaptest.NewLogger(t), paymentTypes, db, time.Hour, false, bonusRate, choreObservers)
|
chore := billing.NewChore(zaptest.NewLogger(t), paymentTypes, db, time.Hour, false, bonusRate, choreObservers)
|
||||||
@ -118,6 +118,8 @@ func TestChore(t *testing.T) {
|
|||||||
sat := planet.Satellites[0]
|
sat := planet.Satellites[0]
|
||||||
db := sat.DB
|
db := sat.DB
|
||||||
|
|
||||||
|
freezeService := console.NewAccountFreezeService(db.Console(), sat.Core.Analytics.Service, sat.Config.Console.AccountFreeze)
|
||||||
|
|
||||||
runTest(ctx, t, db.Console(), db.Billing(), 0,
|
runTest(ctx, t, db.Console(), db.Billing(), 0,
|
||||||
[]billing.Transaction{mike2, mike1},
|
[]billing.Transaction{mike2, mike1},
|
||||||
[]billing.Transaction{joe1, joe2},
|
[]billing.Transaction{joe1, joe2},
|
||||||
@ -127,6 +129,7 @@ func TestChore(t *testing.T) {
|
|||||||
currency.AmountFromBaseUnits(30000000, currency.USDollarsMicro),
|
currency.AmountFromBaseUnits(30000000, currency.USDollarsMicro),
|
||||||
sat.Config.Console.UsageLimits,
|
sat.Config.Console.UsageLimits,
|
||||||
sat.Config.Console.UserBalanceForUpgrade,
|
sat.Config.Console.UserBalanceForUpgrade,
|
||||||
|
freezeService,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -138,6 +141,8 @@ func TestChore(t *testing.T) {
|
|||||||
sat := planet.Satellites[0]
|
sat := planet.Satellites[0]
|
||||||
db := sat.DB
|
db := sat.DB
|
||||||
|
|
||||||
|
freezeService := console.NewAccountFreezeService(db.Console(), sat.Core.Analytics.Service, sat.Config.Console.AccountFreeze)
|
||||||
|
|
||||||
runTest(ctx, t, db.Console(), db.Billing(), 10,
|
runTest(ctx, t, db.Console(), db.Billing(), 10,
|
||||||
[]billing.Transaction{mike2, mike2Bonus, mike1, mike1Bonus},
|
[]billing.Transaction{mike2, mike2Bonus, mike1, mike1Bonus},
|
||||||
[]billing.Transaction{joe1, joe1Bonus, joe2},
|
[]billing.Transaction{joe1, joe1Bonus, joe2},
|
||||||
@ -147,6 +152,7 @@ func TestChore(t *testing.T) {
|
|||||||
currency.AmountFromBaseUnits(30000000, currency.USDollarsMicro),
|
currency.AmountFromBaseUnits(30000000, currency.USDollarsMicro),
|
||||||
sat.Config.Console.UsageLimits,
|
sat.Config.Console.UsageLimits,
|
||||||
sat.Config.Console.UserBalanceForUpgrade,
|
sat.Config.Console.UserBalanceForUpgrade,
|
||||||
|
freezeService,
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -161,29 +167,48 @@ func TestChore_UpgradeUserObserver(t *testing.T) {
|
|||||||
usageLimitsConfig := sat.Config.Console.UsageLimits
|
usageLimitsConfig := sat.Config.Console.UsageLimits
|
||||||
ts := makeTimestamp()
|
ts := makeTimestamp()
|
||||||
|
|
||||||
|
freezeService := console.NewAccountFreezeService(db.Console(), sat.Core.Analytics.Service, sat.Config.Console.AccountFreeze)
|
||||||
|
|
||||||
user, err := sat.AddUser(ctx, console.CreateUser{
|
user, err := sat.AddUser(ctx, console.CreateUser{
|
||||||
FullName: "Test User",
|
FullName: "Test User",
|
||||||
Email: "choreobserver@mail.test",
|
Email: "choreobserver@mail.test",
|
||||||
}, 1)
|
}, 1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
user2, err := sat.AddUser(ctx, console.CreateUser{
|
||||||
|
FullName: "Test User",
|
||||||
|
Email: "choreobserver2@mail.test",
|
||||||
|
}, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
user3, err := sat.AddUser(ctx, console.CreateUser{
|
||||||
|
FullName: "Test User",
|
||||||
|
Email: "choreobserver3@mail.test",
|
||||||
|
}, 1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
_, err = sat.AddProject(ctx, user.ID, "Test Project")
|
_, err = sat.AddProject(ctx, user.ID, "Test Project")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
choreObservers := billing.ChoreObservers{
|
choreObservers := billing.ChoreObservers{
|
||||||
UpgradeUser: console.NewUpgradeUserObserver(db.Console(), db.Billing(), sat.Config.Console.UsageLimits, sat.Config.Console.UserBalanceForUpgrade),
|
UpgradeUser: console.NewUpgradeUserObserver(db.Console(), db.Billing(), sat.Config.Console.UsageLimits, sat.Config.Console.UserBalanceForUpgrade, freezeService),
|
||||||
}
|
}
|
||||||
|
|
||||||
amount1 := int64(200) // $2
|
amount1 := int64(200) // $2
|
||||||
amount2 := int64(800) // $8
|
amount2 := int64(800) // $8
|
||||||
transaction1 := makeFakeTransaction(user.ID, billing.StorjScanSource, billing.TransactionTypeCredit, amount1, ts, `{"fake": "transaction1"}`)
|
transaction1 := makeFakeTransaction(user.ID, billing.StorjScanSource, billing.TransactionTypeCredit, amount1, ts, `{"fake": "transaction1"}`)
|
||||||
transaction2 := makeFakeTransaction(user.ID, billing.StorjScanSource, billing.TransactionTypeCredit, amount2, ts.Add(time.Second*2), `{"fake": "transaction2"}`)
|
transaction2 := makeFakeTransaction(user.ID, billing.StorjScanSource, billing.TransactionTypeCredit, amount2, ts.Add(time.Second*2), `{"fake": "transaction2"}`)
|
||||||
|
transaction3 := makeFakeTransaction(user2.ID, billing.StorjScanSource, billing.TransactionTypeCredit, amount1+amount2, ts, `{"fake": "transaction3"}`)
|
||||||
|
transaction4 := makeFakeTransaction(user3.ID, billing.StorjScanSource, billing.TransactionTypeCredit, amount1+amount2, ts.Add(time.Second*2), `{"fake": "transaction4"}`)
|
||||||
paymentTypes := []billing.PaymentType{
|
paymentTypes := []billing.PaymentType{
|
||||||
newFakePaymentType(billing.StorjScanSource,
|
newFakePaymentType(billing.StorjScanSource,
|
||||||
[]billing.Transaction{transaction1},
|
[]billing.Transaction{transaction1},
|
||||||
[]billing.Transaction{},
|
[]billing.Transaction{},
|
||||||
[]billing.Transaction{transaction2},
|
[]billing.Transaction{transaction2},
|
||||||
[]billing.Transaction{},
|
[]billing.Transaction{},
|
||||||
|
[]billing.Transaction{transaction3},
|
||||||
|
[]billing.Transaction{transaction4},
|
||||||
|
[]billing.Transaction{},
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,6 +266,39 @@ func TestChore_UpgradeUserObserver(t *testing.T) {
|
|||||||
require.Equal(t, usageLimitsConfig.Segment.Paid, *p.SegmentLimit)
|
require.Equal(t, usageLimitsConfig.Segment.Paid, *p.SegmentLimit)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
t.Run("no upgrade for legal/violation freeze", func(t *testing.T) {
|
||||||
|
require.NoError(t, freezeService.LegalFreezeUser(ctx, user2.ID))
|
||||||
|
require.NoError(t, freezeService.ViolationFreezeUser(ctx, user3.ID))
|
||||||
|
|
||||||
|
chore.TransactionCycle.TriggerWait()
|
||||||
|
chore.TransactionCycle.Pause()
|
||||||
|
|
||||||
|
expected := currency.AmountFromBaseUnits((amount1+amount2)*int64(10000), currency.USDollarsMicro)
|
||||||
|
|
||||||
|
chore.TransactionCycle.TriggerWait()
|
||||||
|
chore.TransactionCycle.Pause()
|
||||||
|
|
||||||
|
balance, err := db.Billing().GetBalance(ctx, user2.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, expected.Equal(balance))
|
||||||
|
|
||||||
|
chore.TransactionCycle.TriggerWait()
|
||||||
|
|
||||||
|
balance, err = db.Billing().GetBalance(ctx, user3.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.True(t, expected.Equal(balance))
|
||||||
|
|
||||||
|
// users should not be upgraded though they have enough balance
|
||||||
|
// since they are in legal/violation freeze.
|
||||||
|
user, err = db.Console().Users().Get(ctx, user2.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, user.PaidTier)
|
||||||
|
|
||||||
|
user, err = db.Console().Users().Get(ctx, user3.ID)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.False(t, user.PaidTier)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -275,7 +333,7 @@ func TestChore_PayInvoiceObserver(t *testing.T) {
|
|||||||
freezeService := console.NewAccountFreezeService(consoleDB, sat.Core.Analytics.Service, sat.Config.Console.AccountFreeze)
|
freezeService := console.NewAccountFreezeService(consoleDB, sat.Core.Analytics.Service, sat.Config.Console.AccountFreeze)
|
||||||
|
|
||||||
choreObservers := billing.ChoreObservers{
|
choreObservers := billing.ChoreObservers{
|
||||||
UpgradeUser: console.NewUpgradeUserObserver(consoleDB, db.Billing(), sat.Config.Console.UsageLimits, sat.Config.Console.UserBalanceForUpgrade),
|
UpgradeUser: console.NewUpgradeUserObserver(consoleDB, db.Billing(), sat.Config.Console.UsageLimits, sat.Config.Console.UserBalanceForUpgrade, freezeService),
|
||||||
PayInvoices: console.NewInvoiceTokenPaymentObserver(consoleDB, sat.Core.Payments.Accounts.Invoices(), freezeService),
|
PayInvoices: console.NewInvoiceTokenPaymentObserver(consoleDB, sat.Core.Payments.Accounts.Invoices(), freezeService),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,17 +265,22 @@ func (projects *projects) Update(ctx context.Context, project *console.Project)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UpdateRateLimit is a method for updating projects rate limit.
|
// UpdateRateLimit is a method for updating projects rate limit.
|
||||||
func (projects *projects) UpdateRateLimit(ctx context.Context, id uuid.UUID, newLimit int) (err error) {
|
func (projects *projects) UpdateRateLimit(ctx context.Context, id uuid.UUID, newLimit *int) (err error) {
|
||||||
defer mon.Task()(&ctx)(&err)
|
defer mon.Task()(&ctx)(&err)
|
||||||
|
|
||||||
if newLimit < 0 {
|
if newLimit != nil && *newLimit < 0 {
|
||||||
return Error.New("limit can't be set to negative value")
|
return Error.New("limit can't be set to negative value")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
rateLimit := dbx.Project_RateLimit_Null()
|
||||||
|
if newLimit != nil {
|
||||||
|
rateLimit = dbx.Project_RateLimit(*newLimit)
|
||||||
|
}
|
||||||
|
|
||||||
_, err = projects.db.Update_Project_By_Id(ctx,
|
_, err = projects.db.Update_Project_By_Id(ctx,
|
||||||
dbx.Project_Id(id[:]),
|
dbx.Project_Id(id[:]),
|
||||||
dbx.Project_Update_Fields{
|
dbx.Project_Update_Fields{
|
||||||
RateLimit: dbx.Project_RateLimit(newLimit),
|
RateLimit: rateLimit,
|
||||||
})
|
})
|
||||||
|
|
||||||
return err
|
return err
|
||||||
|
Loading…
Reference in New Issue
Block a user