satellite/admin: add endpoints to violation freeze/unfreeze users
This change adds two new admin endpoints to freeze users for ToS violation and to remove them from that state, Issue: https://github.com/storj/storj-private/issues/386 Change-Id: I49c922377c9cdb315ce2777fcd35dcad432b0539
This commit is contained in:
parent
594e63f13a
commit
c9421d11e7
@ -219,7 +219,7 @@ func NewAdmin(log *zap.Logger, full *identity.FullIdentity, db DB, metabaseDB *m
|
||||
adminConfig := config.Admin
|
||||
adminConfig.AuthorizationToken = config.Console.AuthToken
|
||||
|
||||
peer.Admin.Server = admin.NewServer(log.Named("admin"), peer.Admin.Listener, peer.DB, peer.Buckets.Service, peer.REST.Keys, peer.FreezeAccounts.Service, peer.Payments.Accounts, config.Console, adminConfig)
|
||||
peer.Admin.Server = admin.NewServer(log.Named("admin"), peer.Admin.Listener, peer.DB, peer.Buckets.Service, peer.REST.Keys, peer.FreezeAccounts.Service, peer.Analytics.Service, peer.Payments.Accounts, config.Console, adminConfig)
|
||||
peer.Servers.Add(lifecycle.Item{
|
||||
Name: "admin",
|
||||
Run: peer.Admin.Server.Run,
|
||||
|
@ -19,8 +19,13 @@ Requires setting `Authorization` header for requests.
|
||||
* [DELETE /api/users/{user-email}](#delete-apiusersuser-email)
|
||||
* [PUT /api/users/{user-email}/limits](#put-apiusersuser-emaillimits)
|
||||
* [DELETE /api/users/{user-email}/mfa](#delete-apiusersuser-emailmfa)
|
||||
* [PUT /api/users/{user-email}/freeze](#put-apiusersuser-emailfreeze)
|
||||
* [DELETE /api/users/{user-email}/freeze](#delete-apiusersuser-emailfreeze)
|
||||
* [PUT /api/users/{user-email}/billing-freeze](#put-apiusersuser-emailbilling-freeze)
|
||||
* [DELETE /api/users/{user-email}/billing-freeze](#delete-apiusersuser-emailbilling-freeze)
|
||||
* [PUT /api/users/{user-email}/violation-freeze](#put-apiusersuser-emailviolation-freeze)
|
||||
* [DELETE /api/users/{user-email}/violation-freeze](#delete-apiusersuser-emailviolation-freeze)
|
||||
* [DELETE /api/users/{user-email}/billing-warning](#delete-apiusersuser-emailbilling-warning)
|
||||
* [PATCH /api/users/{user-email}/geofence](#patch-apiusersuser-emailgeofence)
|
||||
* [DELETE /api/users/{user-email}/geofence](#delete-apiusersuser-emailgeofence)
|
||||
* [OAuth Client Management](#oauth-client-management)
|
||||
* [POST /api/oauth/clients](#post-apioauthclients)
|
||||
* [PUT /api/oauth/clients/{id}](#put-apioauthclientsid)
|
||||
@ -171,18 +176,28 @@ Updates the limits of the user and user's existing project(s) limits found by it
|
||||
|
||||
Disables the user's mfa.
|
||||
|
||||
#### PUT /api/users/{user-email}/freeze
|
||||
#### PUT /api/users/{user-email}/billing-freeze
|
||||
|
||||
Freezes a user account so no uploads or downloads may occur.
|
||||
This is a billing freeze the user can exit automatically by paying their invoice.
|
||||
|
||||
#### DELETE /api/users/{user-email}/freeze
|
||||
#### DELETE /api/users/{user-email}/billing-freeze
|
||||
|
||||
Unfreezes a user account so uploads and downloads may resume.
|
||||
Unfreezes a previously billing frozen user account so uploads and downloads may resume.
|
||||
|
||||
#### DELETE /api/users/{user-email}/warning
|
||||
#### PUT /api/users/{user-email}/violation-freeze
|
||||
|
||||
Removes the warning status from a user's account.
|
||||
Freezes a user account for violation so no uploads or downloads may occur
|
||||
User status is also set to Pending Deletion. The user cannot exit this state automatically.
|
||||
|
||||
#### DELETE /api/users/{user-email}/violation-freeze
|
||||
|
||||
Removes the violation freeze on a user account so uploads and downloads may resume.
|
||||
User status is set back to Active. This is the only way to exit the violation frozen state.
|
||||
|
||||
#### DELETE /api/users/{user-email}/billing-warning
|
||||
|
||||
Removes the billing warning status from a user's account.
|
||||
|
||||
#### PATCH /api/users/{user-email}/geofence
|
||||
|
||||
|
@ -22,6 +22,7 @@ import (
|
||||
"storj.io/storj/satellite/accounting"
|
||||
backofficeui "storj.io/storj/satellite/admin/back-office/ui"
|
||||
adminui "storj.io/storj/satellite/admin/ui"
|
||||
"storj.io/storj/satellite/analytics"
|
||||
"storj.io/storj/satellite/attribution"
|
||||
"storj.io/storj/satellite/buckets"
|
||||
"storj.io/storj/satellite/console"
|
||||
@ -84,6 +85,7 @@ type Server struct {
|
||||
payments payments.Accounts
|
||||
buckets *buckets.Service
|
||||
restKeys *restkeys.Service
|
||||
analytics *analytics.Service
|
||||
freezeAccounts *console.AccountFreezeService
|
||||
|
||||
nowFn func() time.Time
|
||||
@ -100,6 +102,7 @@ func NewServer(
|
||||
buckets *buckets.Service,
|
||||
restKeys *restkeys.Service,
|
||||
freezeAccounts *console.AccountFreezeService,
|
||||
analyticsService *analytics.Service,
|
||||
accounts payments.Accounts,
|
||||
console consoleweb.Config,
|
||||
config Config,
|
||||
@ -113,6 +116,7 @@ func NewServer(
|
||||
payments: accounts,
|
||||
buckets: buckets,
|
||||
restKeys: restKeys,
|
||||
analytics: analyticsService,
|
||||
freezeAccounts: freezeAccounts,
|
||||
|
||||
nowFn: time.Now,
|
||||
@ -165,9 +169,11 @@ func NewServer(
|
||||
limitUpdateAPI.HandleFunc("/users/{useremail}", server.userInfo).Methods("GET")
|
||||
limitUpdateAPI.HandleFunc("/users/{useremail}/limits", server.userLimits).Methods("GET")
|
||||
limitUpdateAPI.HandleFunc("/users/{useremail}/limits", server.updateLimits).Methods("PUT")
|
||||
limitUpdateAPI.HandleFunc("/users/{useremail}/freeze", server.freezeUser).Methods("PUT")
|
||||
limitUpdateAPI.HandleFunc("/users/{useremail}/freeze", server.unfreezeUser).Methods("DELETE")
|
||||
limitUpdateAPI.HandleFunc("/users/{useremail}/warning", server.unWarnUser).Methods("DELETE")
|
||||
limitUpdateAPI.HandleFunc("/users/{useremail}/billing-freeze", server.billingFreezeUser).Methods("PUT")
|
||||
limitUpdateAPI.HandleFunc("/users/{useremail}/billing-freeze", server.billingUnfreezeUser).Methods("DELETE")
|
||||
limitUpdateAPI.HandleFunc("/users/{useremail}/billing-warning", server.billingUnWarnUser).Methods("DELETE")
|
||||
limitUpdateAPI.HandleFunc("/users/{useremail}/violation-freeze", server.violationFreezeUser).Methods("PUT")
|
||||
limitUpdateAPI.HandleFunc("/users/{useremail}/violation-freeze", server.violationUnfreezeUser).Methods("DELETE")
|
||||
limitUpdateAPI.HandleFunc("/projects/{project}/limit", server.getProjectLimit).Methods("GET")
|
||||
limitUpdateAPI.HandleFunc("/projects/{project}/limit", server.putProjectLimit).Methods("PUT", "POST")
|
||||
|
||||
|
@ -450,19 +450,35 @@ Blank fields will not be updated.`,
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'freeze user',
|
||||
name: 'billing freeze user',
|
||||
desc: "insert user into account_freeze_events and set user's limits to zero",
|
||||
params: [['email', new InputText('email', true)]],
|
||||
func: async (email: string): Promise<null> => {
|
||||
return this.fetch('PUT', `users/${email}/freeze`) as Promise<null>;
|
||||
return this.fetch('PUT', `users/${email}/billing-freeze`) as Promise<null>;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'unfreeze user',
|
||||
name: 'billing unfreeze user',
|
||||
desc: "remove user from account_freeze_events and reset user's limits to what is stored in account_freeze_events",
|
||||
params: [['email', new InputText('email', true)]],
|
||||
func: async (email: string): Promise<null> => {
|
||||
return this.fetch('DELETE', `users/${email}/freeze`) as Promise<null>;
|
||||
return this.fetch('DELETE', `users/${email}/billing-freeze`) as Promise<null>;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'violation freeze user',
|
||||
desc: 'freeze a user for ToS violation, set limits to zero and status to pending deletion',
|
||||
params: [['email', new InputText('email', true)]],
|
||||
func: async (email: string): Promise<null> => {
|
||||
return this.fetch('PUT', `users/${email}/violation-freeze`) as Promise<null>;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'violation unfreeze user',
|
||||
desc: "remove a user's violation freeze, reinstating their limits and status (Active)",
|
||||
params: [['email', new InputText('email', true)]],
|
||||
func: async (email: string): Promise<null> => {
|
||||
return this.fetch('DELETE', `users/${email}/violation-freeze`) as Promise<null>;
|
||||
}
|
||||
},
|
||||
{
|
||||
@ -470,7 +486,7 @@ Blank fields will not be updated.`,
|
||||
desc: "Remove a user's warning status",
|
||||
params: [['email', new InputText('email', true)]],
|
||||
func: async (email: string): Promise<null> => {
|
||||
return this.fetch('DELETE', `users/${email}/warning`) as Promise<null>;
|
||||
return this.fetch('DELETE', `users/${email}/billing-warning`) as Promise<null>;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
@ -16,12 +16,14 @@ import (
|
||||
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/zeebo/errs"
|
||||
"go.uber.org/zap"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
|
||||
"storj.io/common/memory"
|
||||
"storj.io/common/storj"
|
||||
"storj.io/common/uuid"
|
||||
"storj.io/storj/satellite/console"
|
||||
"storj.io/storj/satellite/payments"
|
||||
)
|
||||
|
||||
func (server *Server) addUser(w http.ResponseWriter, r *http.Request) {
|
||||
@ -575,7 +577,7 @@ func (server *Server) disableUserMFA(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) freezeUser(w http.ResponseWriter, r *http.Request) {
|
||||
func (server *Server) billingFreezeUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
@ -599,12 +601,12 @@ func (server *Server) freezeUser(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
err = server.freezeAccounts.BillingFreezeUser(ctx, u.ID)
|
||||
if err != nil {
|
||||
sendJSONError(w, "failed to freeze user",
|
||||
sendJSONError(w, "failed to billing freeze user",
|
||||
err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) unfreezeUser(w http.ResponseWriter, r *http.Request) {
|
||||
func (server *Server) billingUnfreezeUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
@ -626,14 +628,21 @@ func (server *Server) unfreezeUser(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if err = server.freezeAccounts.BillingUnfreezeUser(ctx, u.ID); err != nil {
|
||||
sendJSONError(w, "failed to unfreeze user",
|
||||
err.Error(), http.StatusInternalServerError)
|
||||
err = server.freezeAccounts.BillingUnfreezeUser(ctx, u.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, console.ErrFreezeUserStatusUpdate) {
|
||||
sendJSONError(w, "User unfrozen but failed to change user status to active. "+
|
||||
"Run the command again, but if the error persists, intervene manually.",
|
||||
err.Error(), http.StatusInternalServerError)
|
||||
} else {
|
||||
sendJSONError(w, "failed to violation unfreeze user",
|
||||
err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) unWarnUser(w http.ResponseWriter, r *http.Request) {
|
||||
func (server *Server) billingUnWarnUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
@ -656,12 +665,96 @@ func (server *Server) unWarnUser(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
|
||||
if err = server.freezeAccounts.BillingUnWarnUser(ctx, u.ID); err != nil {
|
||||
sendJSONError(w, "failed to unwarn user",
|
||||
sendJSONError(w, "failed to billing unwarn user",
|
||||
err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) violationFreezeUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
userEmail, ok := vars["useremail"]
|
||||
if !ok {
|
||||
sendJSONError(w, "user-email missing", "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
u, err := server.db.Console().Users().GetByEmail(ctx, userEmail)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
sendJSONError(w, fmt.Sprintf("user with email %q does not exist", userEmail),
|
||||
"", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
sendJSONError(w, "failed to get user details",
|
||||
err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
err = server.freezeAccounts.ViolationFreezeUser(ctx, u.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, console.ErrFreezeUserStatusUpdate) {
|
||||
sendJSONError(w, "User frozen but failed to change user status to Pending Deletion. "+
|
||||
"Run the command again, but if the error persists, intervene manually.",
|
||||
err.Error(), http.StatusInternalServerError)
|
||||
} else {
|
||||
sendJSONError(w, "failed to violation freeze user",
|
||||
err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
invoices, err := server.payments.Invoices().List(ctx, u.ID)
|
||||
if err != nil {
|
||||
server.log.Error("failed to get invoices for violation frozen user", zap.Error(err))
|
||||
return
|
||||
}
|
||||
|
||||
for _, invoice := range invoices {
|
||||
if invoice.Status == payments.InvoiceStatusOpen {
|
||||
server.analytics.TrackViolationFrozenUnpaidInvoice(invoice.ID, u.ID, u.Email)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) violationUnfreezeUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
vars := mux.Vars(r)
|
||||
userEmail, ok := vars["useremail"]
|
||||
if !ok {
|
||||
sendJSONError(w, "user-email missing", "", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
u, err := server.db.Console().Users().GetByEmail(ctx, userEmail)
|
||||
if err != nil {
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
sendJSONError(w, fmt.Sprintf("user with email %q does not exist", userEmail),
|
||||
"", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
sendJSONError(w, "failed to get user details",
|
||||
err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
err = server.freezeAccounts.ViolationUnfreezeUser(ctx, u.ID)
|
||||
if err != nil {
|
||||
if errors.Is(err, console.ErrFreezeUserStatusUpdate) {
|
||||
sendJSONError(w, "User unfrozen but failed to change user status to active. "+
|
||||
"Run the command again, but if the error persists, intervene manually.",
|
||||
err.Error(), http.StatusInternalServerError)
|
||||
} else {
|
||||
sendJSONError(w, "failed to violation unfreeze user",
|
||||
err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
func (server *Server) deleteUser(w http.ResponseWriter, r *http.Request) {
|
||||
ctx := r.Context()
|
||||
|
||||
|
@ -369,7 +369,7 @@ func TestDisableMFA(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestFreezeUnfreezeUser(t *testing.T) {
|
||||
func TestBillingFreezeUnfreezeUser(t *testing.T) {
|
||||
testplanet.Run(t, testplanet.Config{
|
||||
SatelliteCount: 1,
|
||||
StorageNodeCount: 0,
|
||||
@ -392,11 +392,11 @@ func TestFreezeUnfreezeUser(t *testing.T) {
|
||||
require.NotZero(t, projectPreFreeze.StorageLimit)
|
||||
|
||||
// freeze can be run multiple times. Test that doing so does not affect Unfreeze result.
|
||||
link := fmt.Sprintf("http://"+address.String()+"/api/users/%s/freeze", userPreFreeze.Email)
|
||||
link := fmt.Sprintf("http://"+address.String()+"/api/users/%s/billing-freeze", userPreFreeze.Email)
|
||||
body := assertReq(ctx, t, link, http.MethodPut, "", http.StatusOK, "", planet.Satellites[0].Config.Console.AuthToken)
|
||||
require.Len(t, body, 0)
|
||||
|
||||
link = fmt.Sprintf("http://"+address.String()+"/api/users/%s/freeze", userPreFreeze.Email)
|
||||
link = fmt.Sprintf("http://"+address.String()+"/api/users/%s/billing-freeze", userPreFreeze.Email)
|
||||
body = assertReq(ctx, t, link, http.MethodPut, "", http.StatusOK, "", planet.Satellites[0].Config.Console.AuthToken)
|
||||
require.Len(t, body, 0)
|
||||
|
||||
@ -410,7 +410,7 @@ func TestFreezeUnfreezeUser(t *testing.T) {
|
||||
require.Zero(t, projectPostFreeze.BandwidthLimit.Int64())
|
||||
require.Zero(t, projectPostFreeze.StorageLimit.Int64())
|
||||
|
||||
link = fmt.Sprintf("http://"+address.String()+"/api/users/%s/freeze", userPreFreeze.Email)
|
||||
link = fmt.Sprintf("http://"+address.String()+"/api/users/%s/billing-freeze", userPreFreeze.Email)
|
||||
body = assertReq(ctx, t, link, http.MethodDelete, "", http.StatusOK, "", planet.Satellites[0].Config.Console.AuthToken)
|
||||
require.Len(t, body, 0)
|
||||
|
||||
@ -429,7 +429,69 @@ func TestFreezeUnfreezeUser(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
func TestWarnUnwarnUser(t *testing.T) {
|
||||
func TestViolationFreezeUnfreezeUser(t *testing.T) {
|
||||
testplanet.Run(t, testplanet.Config{
|
||||
SatelliteCount: 1,
|
||||
StorageNodeCount: 0,
|
||||
UplinkCount: 1,
|
||||
Reconfigure: testplanet.Reconfigure{
|
||||
Satellite: func(_ *zap.Logger, _ int, config *satellite.Config) {
|
||||
config.Admin.Address = "127.0.0.1:0"
|
||||
},
|
||||
},
|
||||
}, func(t *testing.T, ctx *testcontext.Context, planet *testplanet.Planet) {
|
||||
address := planet.Satellites[0].Admin.Admin.Listener.Addr()
|
||||
userPreFreeze, err := planet.Satellites[0].DB.Console().Users().Get(ctx, planet.Uplinks[0].Projects[0].Owner.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, console.Active, userPreFreeze.Status)
|
||||
require.NotZero(t, userPreFreeze.ProjectStorageLimit)
|
||||
require.NotZero(t, userPreFreeze.ProjectBandwidthLimit)
|
||||
|
||||
projectPreFreeze, err := planet.Satellites[0].DB.Console().Projects().Get(ctx, planet.Uplinks[0].Projects[0].ID)
|
||||
require.NoError(t, err)
|
||||
require.NotZero(t, projectPreFreeze.BandwidthLimit)
|
||||
require.NotZero(t, projectPreFreeze.StorageLimit)
|
||||
|
||||
// freeze can be run multiple times. Test that doing so does not affect Unfreeze result.
|
||||
link := fmt.Sprintf("http://"+address.String()+"/api/users/%s/violation-freeze", userPreFreeze.Email)
|
||||
body := assertReq(ctx, t, link, http.MethodPut, "", http.StatusOK, "", planet.Satellites[0].Config.Console.AuthToken)
|
||||
require.Len(t, body, 0)
|
||||
|
||||
body = assertReq(ctx, t, link, http.MethodPut, "", http.StatusOK, "", planet.Satellites[0].Config.Console.AuthToken)
|
||||
require.Len(t, body, 0)
|
||||
|
||||
userPostFreeze, err := planet.Satellites[0].DB.Console().Users().Get(ctx, userPreFreeze.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, console.PendingDeletion, userPostFreeze.Status)
|
||||
require.Zero(t, userPostFreeze.ProjectStorageLimit)
|
||||
require.Zero(t, userPostFreeze.ProjectBandwidthLimit)
|
||||
|
||||
projectPostFreeze, err := planet.Satellites[0].DB.Console().Projects().Get(ctx, planet.Uplinks[0].Projects[0].ID)
|
||||
require.NoError(t, err)
|
||||
require.Zero(t, projectPostFreeze.BandwidthLimit.Int64())
|
||||
require.Zero(t, projectPostFreeze.StorageLimit.Int64())
|
||||
|
||||
link = fmt.Sprintf("http://"+address.String()+"/api/users/%s/violation-freeze", userPreFreeze.Email)
|
||||
body = assertReq(ctx, t, link, http.MethodDelete, "", http.StatusOK, "", planet.Satellites[0].Config.Console.AuthToken)
|
||||
require.Len(t, body, 0)
|
||||
|
||||
unfrozenUser, err := planet.Satellites[0].DB.Console().Users().Get(ctx, userPreFreeze.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, console.Active, unfrozenUser.Status)
|
||||
require.Equal(t, userPreFreeze.ProjectStorageLimit, unfrozenUser.ProjectStorageLimit)
|
||||
require.Equal(t, userPreFreeze.ProjectBandwidthLimit, unfrozenUser.ProjectBandwidthLimit)
|
||||
|
||||
unfrozenProject, err := planet.Satellites[0].DB.Console().Projects().Get(ctx, projectPreFreeze.ID)
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, projectPreFreeze.StorageLimit, unfrozenProject.StorageLimit)
|
||||
require.Equal(t, projectPreFreeze.BandwidthLimit, unfrozenProject.BandwidthLimit)
|
||||
|
||||
body = assertReq(ctx, t, link, http.MethodDelete, "", http.StatusInternalServerError, "", planet.Satellites[0].Config.Console.AuthToken)
|
||||
require.Contains(t, string(body), "not violation frozen")
|
||||
})
|
||||
}
|
||||
|
||||
func TestBillingWarnUnwarnUser(t *testing.T) {
|
||||
testplanet.Run(t, testplanet.Config{
|
||||
SatelliteCount: 1,
|
||||
StorageNodeCount: 0,
|
||||
@ -451,7 +513,7 @@ func TestWarnUnwarnUser(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, freezes.BillingWarning)
|
||||
|
||||
link := fmt.Sprintf("http://"+address.String()+"/api/users/%s/warning", user.Email)
|
||||
link := fmt.Sprintf("http://"+address.String()+"/api/users/%s/billing-warning", user.Email)
|
||||
body := assertReq(ctx, t, link, http.MethodDelete, "", http.StatusOK, "", planet.Satellites[0].Config.Console.AuthToken)
|
||||
require.Len(t, body, 0)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user