satellite/admin: change returned data to be json encoded

Change-Id: I239779fe54328fe854fcbdd71f7906875cd76635
This commit is contained in:
stefanbenten 2020-08-05 15:13:11 +02:00
parent f804f03b1f
commit d654ab5fa0
5 changed files with 219 additions and 100 deletions

View File

@ -3,7 +3,30 @@
package admin
import "github.com/zeebo/errs"
import (
"encoding/json"
"net/http"
"github.com/zeebo/errs"
)
// Error is default error class for admin package.
var Error = errs.Class("admin")
func httpJSONError(w http.ResponseWriter, error, detail string, statusCode int) {
errStr := struct {
Error string `json:"error"`
Detail string `json:"detail"`
}{
Error: error,
Detail: detail,
}
byt, err := json.Marshal(errStr)
if err != nil {
return
}
w.WriteHeader(statusCode)
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write(byt) // any error here entitles a client side disconnect or similar, which we do not care about.
}

View File

@ -22,7 +22,8 @@ func (server *Server) addCoupon(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("failed to read body: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to read body",
err.Error(), http.StatusInternalServerError)
return
}
@ -35,21 +36,26 @@ func (server *Server) addCoupon(w http.ResponseWriter, r *http.Request) {
err = json.Unmarshal(body, &input)
if err != nil {
http.Error(w, fmt.Sprintf("failed to unmarshal request: %v", err), http.StatusBadRequest)
httpJSONError(w, "failed to unmarshal request",
err.Error(), http.StatusBadRequest)
return
}
switch {
case input.Duration == 0:
http.Error(w, "Duration is not set", http.StatusBadRequest)
httpJSONError(w, "Duration is not set",
"", http.StatusBadRequest)
return
case input.Amount == 0:
http.Error(w, "Amount is not set", http.StatusBadRequest)
httpJSONError(w, "Amount is not set",
"", http.StatusBadRequest)
return
case input.Description == "":
http.Error(w, "Description is not set", http.StatusBadRequest)
httpJSONError(w, "Description is not set",
"", http.StatusBadRequest)
return
case input.UserID.IsZero():
http.Error(w, "UserID is not set", http.StatusBadRequest)
httpJSONError(w, "UserID is not set",
"", http.StatusBadRequest)
return
}
@ -60,13 +66,15 @@ func (server *Server) addCoupon(w http.ResponseWriter, r *http.Request) {
Description: input.Description,
})
if err != nil {
http.Error(w, fmt.Sprintf("failed to insert coupon: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to insert coupon",
err.Error(), http.StatusInternalServerError)
return
}
data, err := json.Marshal(coupon.ID)
if err != nil {
http.Error(w, fmt.Sprintf("json encoding failed: %v", err), http.StatusInternalServerError)
httpJSONError(w, "json encoding failed",
err.Error(), http.StatusInternalServerError)
return
}
@ -80,28 +88,33 @@ func (server *Server) couponInfo(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id, ok := vars["couponid"]
if !ok {
http.Error(w, "couponId missing", http.StatusBadRequest)
httpJSONError(w, "couponId missing",
"", http.StatusBadRequest)
return
}
couponID, err := uuid.FromString(id)
if err != nil {
http.Error(w, "invalid couponId", http.StatusBadRequest)
httpJSONError(w, "invalid couponId",
"", http.StatusBadRequest)
}
coupon, err := server.db.StripeCoinPayments().Coupons().Get(ctx, couponID)
if errors.Is(err, sql.ErrNoRows) {
http.Error(w, fmt.Sprintf("coupon with id %q not found", couponID), http.StatusNotFound)
httpJSONError(w, fmt.Sprintf("coupon with id %q not found", couponID),
"", http.StatusNotFound)
return
}
if err != nil {
http.Error(w, fmt.Sprintf("failed to get coupon %q: %v", couponID, err), http.StatusInternalServerError)
httpJSONError(w, "failed to get coupon",
err.Error(), http.StatusInternalServerError)
return
}
data, err := json.Marshal(coupon)
if err != nil {
http.Error(w, fmt.Sprintf("json encoding failed: %v", err), http.StatusInternalServerError)
httpJSONError(w, "json encoding failed",
err.Error(), http.StatusInternalServerError)
return
}
@ -115,19 +128,22 @@ func (server *Server) deleteCoupon(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
UUIDString, ok := vars["couponid"]
if !ok {
http.Error(w, "couponid missing", http.StatusBadRequest)
httpJSONError(w, "couponid missing",
"", http.StatusBadRequest)
return
}
couponID, err := uuid.FromString(UUIDString)
if err != nil {
http.Error(w, fmt.Sprintf("invalid couponid: %v", err), http.StatusBadRequest)
httpJSONError(w, "invalid couponid",
err.Error(), http.StatusBadRequest)
return
}
err = server.db.StripeCoinPayments().Coupons().Delete(ctx, couponID)
if err != nil {
http.Error(w, fmt.Sprintf("unable to delete coupon: %v", err), http.StatusInternalServerError)
httpJSONError(w, "unable to delete coupon",
err.Error(), http.StatusInternalServerError)
return
}
}

View File

@ -29,31 +29,36 @@ func (server *Server) getProjectLimit(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
projectUUIDString, ok := vars["project"]
if !ok {
http.Error(w, "project-uuid missing", http.StatusBadRequest)
httpJSONError(w, "project-uuid missing",
"", http.StatusBadRequest)
return
}
projectUUID, err := uuid.FromString(projectUUIDString)
if err != nil {
http.Error(w, fmt.Sprintf("invalid project-uuid: %v", err), http.StatusBadRequest)
httpJSONError(w, "invalid project-uuid",
err.Error(), http.StatusBadRequest)
return
}
usagelimit, err := server.db.ProjectAccounting().GetProjectStorageLimit(ctx, projectUUID)
if err != nil {
http.Error(w, fmt.Sprintf("failed to get usage limit: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to get usage limit",
err.Error(), http.StatusInternalServerError)
return
}
bandwidthlimit, err := server.db.ProjectAccounting().GetProjectBandwidthLimit(ctx, projectUUID)
if err != nil {
http.Error(w, fmt.Sprintf("failed to get bandwidth limit: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to get bandwidth limit",
err.Error(), http.StatusInternalServerError)
return
}
project, err := server.db.Console().Projects().Get(ctx, projectUUID)
if err != nil {
http.Error(w, fmt.Sprintf("failed to get project: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to get project",
err.Error(), http.StatusInternalServerError)
return
}
@ -82,7 +87,8 @@ func (server *Server) getProjectLimit(w http.ResponseWriter, r *http.Request) {
data, err := json.Marshal(output)
if err != nil {
http.Error(w, fmt.Sprintf("json encoding failed: %v", err), http.StatusInternalServerError)
httpJSONError(w, "json encoding failed",
err.Error(), http.StatusInternalServerError)
return
}
@ -96,13 +102,15 @@ func (server *Server) putProjectLimit(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
projectUUIDString, ok := vars["project"]
if !ok {
http.Error(w, "project-uuid missing", http.StatusBadRequest)
httpJSONError(w, "project-uuid missing",
"", http.StatusBadRequest)
return
}
projectUUID, err := uuid.FromString(projectUUIDString)
if err != nil {
http.Error(w, fmt.Sprintf("invalid project-uuid: %v", err), http.StatusBadRequest)
httpJSONError(w, "invalid project-uuid",
err.Error(), http.StatusBadRequest)
return
}
@ -114,65 +122,75 @@ func (server *Server) putProjectLimit(w http.ResponseWriter, r *http.Request) {
}
if err := r.ParseForm(); err != nil {
http.Error(w, fmt.Sprintf("invalid form: %v", err), http.StatusBadRequest)
httpJSONError(w, "invalid form",
err.Error(), http.StatusBadRequest)
return
}
decoder := schema.NewDecoder()
err = decoder.Decode(&arguments, r.Form)
if err != nil {
http.Error(w, fmt.Sprintf("invalid arguments: %v", err), http.StatusBadRequest)
httpJSONError(w, "invalid arguments",
err.Error(), http.StatusBadRequest)
return
}
if arguments.Usage != nil {
if *arguments.Usage < 0 {
http.Error(w, fmt.Sprintf("negative usage: %v", arguments.Usage), http.StatusBadRequest)
httpJSONError(w, "negative usage",
fmt.Sprintf("%v", arguments.Usage), http.StatusBadRequest)
return
}
err = server.db.ProjectAccounting().UpdateProjectUsageLimit(ctx, projectUUID, *arguments.Usage)
if err != nil {
http.Error(w, fmt.Sprintf("failed to update usage: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to update usage",
err.Error(), http.StatusInternalServerError)
return
}
}
if arguments.Bandwidth != nil {
if *arguments.Bandwidth < 0 {
http.Error(w, fmt.Sprintf("negative bandwidth: %v", arguments.Usage), http.StatusBadRequest)
httpJSONError(w, "negative bandwidth",
fmt.Sprintf("%v", arguments.Usage), http.StatusBadRequest)
return
}
err = server.db.ProjectAccounting().UpdateProjectBandwidthLimit(ctx, projectUUID, *arguments.Bandwidth)
if err != nil {
http.Error(w, fmt.Sprintf("failed to update bandwidth: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to update bandwidth",
err.Error(), http.StatusInternalServerError)
return
}
}
if arguments.Rate != nil {
if *arguments.Rate < 0 {
http.Error(w, fmt.Sprintf("negative rate: %v", arguments.Rate), http.StatusBadRequest)
httpJSONError(w, "negative rate",
fmt.Sprintf("%v", arguments.Rate), http.StatusBadRequest)
return
}
err = server.db.Console().Projects().UpdateRateLimit(ctx, projectUUID, *arguments.Rate)
if err != nil {
http.Error(w, fmt.Sprintf("failed to update rate: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to update rate",
err.Error(), http.StatusInternalServerError)
return
}
}
if arguments.Buckets != nil {
if *arguments.Buckets < 0 {
http.Error(w, fmt.Sprintf("negative bucket count: %v", arguments.Buckets), http.StatusBadRequest)
httpJSONError(w, "negative bucket coun",
fmt.Sprintf("t: %v", arguments.Buckets), http.StatusBadRequest)
return
}
err = server.db.Console().Projects().UpdateBucketLimit(ctx, projectUUID, *arguments.Buckets)
if err != nil {
http.Error(w, fmt.Sprintf("failed to update bucket limit: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to update bucket limit",
err.Error(), http.StatusInternalServerError)
return
}
}
@ -183,7 +201,8 @@ func (server *Server) addProject(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("failed to read body: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to read body",
err.Error(), http.StatusInternalServerError)
return
}
@ -198,17 +217,20 @@ func (server *Server) addProject(w http.ResponseWriter, r *http.Request) {
err = json.Unmarshal(body, &input)
if err != nil {
http.Error(w, fmt.Sprintf("failed to unmarshal request: %v", err), http.StatusBadRequest)
httpJSONError(w, "failed to unmarshal request",
err.Error(), http.StatusBadRequest)
return
}
if input.OwnerID.IsZero() {
http.Error(w, "OwnerID is not set", http.StatusBadRequest)
httpJSONError(w, "OwnerID is not set",
"", http.StatusBadRequest)
return
}
if input.ProjectName == "" {
http.Error(w, "ProjectName is not set", http.StatusBadRequest)
httpJSONError(w, "ProjectName is not set",
"", http.StatusBadRequest)
return
}
@ -217,20 +239,23 @@ func (server *Server) addProject(w http.ResponseWriter, r *http.Request) {
OwnerID: input.OwnerID,
})
if err != nil {
http.Error(w, fmt.Sprintf("failed to insert project: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to insert project",
err.Error(), http.StatusInternalServerError)
return
}
_, err = server.db.Console().ProjectMembers().Insert(ctx, project.OwnerID, project.ID)
if err != nil {
http.Error(w, fmt.Sprintf("failed to insert project member: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to insert project member",
err.Error(), http.StatusInternalServerError)
return
}
output.ProjectID = project.ID
data, err := json.Marshal(output)
if err != nil {
http.Error(w, fmt.Sprintf("json encoding failed: %v", err), http.StatusInternalServerError)
httpJSONError(w, "json encoding failed",
err.Error(), http.StatusInternalServerError)
return
}
@ -244,29 +269,34 @@ func (server *Server) renameProject(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
projectUUIDString, ok := vars["project"]
if !ok {
http.Error(w, "project-uuid missing", http.StatusBadRequest)
httpJSONError(w, "project-uuid missing",
"", http.StatusBadRequest)
return
}
projectUUID, err := uuid.FromString(projectUUIDString)
if err != nil {
http.Error(w, fmt.Sprintf("invalid project-uuid: %v", err), http.StatusBadRequest)
httpJSONError(w, "invalid project-uuid",
err.Error(), http.StatusBadRequest)
return
}
project, err := server.db.Console().Projects().Get(ctx, projectUUID)
if errors.Is(err, sql.ErrNoRows) {
http.Error(w, "project with specified uuid does not exist", http.StatusBadRequest)
httpJSONError(w, "project with specified uuid does not exist",
"", http.StatusBadRequest)
return
}
if err != nil {
http.Error(w, fmt.Sprintf("error getting project: %v", err), http.StatusInternalServerError)
httpJSONError(w, "error getting project",
err.Error(), http.StatusInternalServerError)
return
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("failed to read body: %v", err), http.StatusInternalServerError)
httpJSONError(w, "ailed to read body",
err.Error(), http.StatusInternalServerError)
return
}
@ -277,12 +307,14 @@ func (server *Server) renameProject(w http.ResponseWriter, r *http.Request) {
err = json.Unmarshal(body, &input)
if err != nil {
http.Error(w, fmt.Sprintf("failed to unmarshal request: %v", err), http.StatusBadRequest)
httpJSONError(w, "failed to unmarshal request",
err.Error(), http.StatusBadRequest)
return
}
if input.ProjectName == "" {
http.Error(w, "ProjectName is not set", http.StatusBadRequest)
httpJSONError(w, "ProjectName is not set",
"", http.StatusBadRequest)
return
}
@ -291,7 +323,8 @@ func (server *Server) renameProject(w http.ResponseWriter, r *http.Request) {
err = server.db.Console().Projects().Update(ctx, project)
if err != nil {
http.Error(w, fmt.Sprintf("error renaming project: %v", err), http.StatusInternalServerError)
httpJSONError(w, "error renaming project",
err.Error(), http.StatusInternalServerError)
return
}
}
@ -302,38 +335,46 @@ func (server *Server) deleteProject(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
projectUUIDString, ok := vars["project"]
if !ok {
http.Error(w, "project-uuid missing", http.StatusBadRequest)
httpJSONError(w, "project-uuid missing",
"", http.StatusBadRequest)
return
}
projectUUID, err := uuid.FromString(projectUUIDString)
if err != nil {
http.Error(w, fmt.Sprintf("invalid project-uuid: %v", err), http.StatusBadRequest)
httpJSONError(w, "invalid project-uuid",
err.Error(), http.StatusBadRequest)
return
}
if err := r.ParseForm(); err != nil {
http.Error(w, fmt.Sprintf("invalid form: %v", err), http.StatusBadRequest)
httpJSONError(w, "invalid form",
err.Error(), http.StatusBadRequest)
return
}
buckets, err := server.db.Buckets().ListBuckets(ctx, projectUUID, storj.BucketListOptions{Limit: 1, Direction: storj.Forward}, macaroon.AllowedBuckets{All: true})
options := storj.BucketListOptions{Limit: 1, Direction: storj.Forward}
buckets, err := server.db.Buckets().ListBuckets(ctx, projectUUID, options, macaroon.AllowedBuckets{All: true})
if err != nil {
http.Error(w, fmt.Sprintf("unable to list buckets: %v", err), http.StatusInternalServerError)
httpJSONError(w, "unable to list buckets",
err.Error(), http.StatusInternalServerError)
return
}
if len(buckets.Items) > 0 {
http.Error(w, fmt.Sprintf("buckets still exist: %v", bucketNames(buckets.Items)), http.StatusConflict)
httpJSONError(w, "buckets still exist",
fmt.Sprintf("%v", bucketNames(buckets.Items)), http.StatusConflict)
return
}
keys, err := server.db.Console().APIKeys().GetPagedByProjectID(ctx, projectUUID, console.APIKeyCursor{Limit: 1, Page: 1})
if err != nil {
http.Error(w, fmt.Sprintf("unable to list api-keys: %v", err), http.StatusInternalServerError)
httpJSONError(w, "unable to list api-keys",
err.Error(), http.StatusInternalServerError)
return
}
if keys.TotalCount > 0 {
http.Error(w, fmt.Sprintf("api-keys still exist: count %v", keys.TotalCount), http.StatusConflict)
httpJSONError(w, "api-keys still exist",
fmt.Sprintf("count %d", keys.TotalCount), http.StatusConflict)
return
}
@ -343,18 +384,21 @@ func (server *Server) deleteProject(w http.ResponseWriter, r *http.Request) {
currentUsage, err := server.db.ProjectAccounting().GetProjectTotal(ctx, projectUUID, firstOfMonth, time.Now())
if err != nil {
http.Error(w, fmt.Sprintf("unable to list project usage: %v", err), http.StatusInternalServerError)
httpJSONError(w, "unable to list project usage",
err.Error(), http.StatusInternalServerError)
return
}
if currentUsage.Storage > 0 || currentUsage.Egress > 0 || currentUsage.ObjectCount > 0 {
http.Error(w, "usage for current month exists", http.StatusConflict)
httpJSONError(w, "usage for current month exists",
"", http.StatusConflict)
return
}
// if usage of last month exist, make sure to look for billing records
lastMonthUsage, err := server.db.ProjectAccounting().GetProjectTotal(ctx, projectUUID, firstOfMonth.AddDate(0, -1, 0), firstOfMonth.AddDate(0, 0, -1))
if err != nil {
http.Error(w, "error getting project totals", http.StatusInternalServerError)
httpJSONError(w, "error getting project totals",
"", http.StatusInternalServerError)
return
}
@ -364,26 +408,31 @@ func (server *Server) deleteProject(w http.ResponseWriter, r *http.Request) {
case stripecoinpayments.ErrProjectRecordExists:
record, err := server.db.StripeCoinPayments().ProjectRecords().Get(ctx, projectUUID, firstOfMonth.AddDate(0, -1, 0), firstOfMonth.Add(-time.Hour))
if err != nil {
http.Error(w, fmt.Sprintf("unable to get project records: %v", err), http.StatusInternalServerError)
httpJSONError(w, "unable to get project records",
err.Error(), http.StatusInternalServerError)
return
}
// state = 0 means unapplied and not invoiced yet.
if record.State == 0 {
http.Error(w, "unapplied project invoice record exist", http.StatusConflict)
httpJSONError(w, "unapplied project invoice record exist",
"", http.StatusConflict)
return
}
case nil:
http.Error(w, "usage for last month exist, but is not billed yet", http.StatusConflict)
httpJSONError(w, "usage for last month exist, but is not billed yet",
"", http.StatusConflict)
return
default:
http.Error(w, fmt.Sprintf("unable to get project records: %v", err), http.StatusInternalServerError)
httpJSONError(w, "unable to get project records",
err.Error(), http.StatusInternalServerError)
return
}
}
err = server.db.Console().Projects().Delete(ctx, projectUUID)
if err != nil {
http.Error(w, fmt.Sprintf("unable to delete project: %v", err), http.StatusInternalServerError)
httpJSONError(w, "unable to delete project",
err.Error(), http.StatusInternalServerError)
return
}
}

View File

@ -317,7 +317,7 @@ func TestDeleteProjectWithUsageCurrentMonth(t *testing.T) {
require.NoError(t, err)
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.Equal(t, "usage for current month exists\n", string(responseBody))
require.Equal(t, "{\"error\":\"usage for current month exists\",\"detail\":\"\"}", string(responseBody))
require.NoError(t, response.Body.Close())
require.Equal(t, http.StatusConflict, response.StatusCode)
})
@ -401,7 +401,7 @@ func TestDeleteProjectWithUsagePreviousMonth(t *testing.T) {
require.NoError(t, err)
responseBody, err := ioutil.ReadAll(response.Body)
require.NoError(t, err)
require.Equal(t, "usage for last month exist, but is not billed yet\n", string(responseBody))
require.Equal(t, "{\"error\":\"usage for last month exist, but is not billed yet\",\"detail\":\"\"}", string(responseBody))
require.NoError(t, response.Body.Close())
require.Equal(t, http.StatusConflict, response.StatusCode)
})

View File

@ -24,7 +24,8 @@ func (server *Server) addUser(w http.ResponseWriter, r *http.Request) {
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("failed to read body: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to read body",
err.Error(), http.StatusInternalServerError)
return
}
@ -32,7 +33,8 @@ func (server *Server) addUser(w http.ResponseWriter, r *http.Request) {
err = json.Unmarshal(body, &input)
if err != nil {
http.Error(w, fmt.Sprintf("failed to unmarshal request: %v", err), http.StatusBadRequest)
httpJSONError(w, "failed to unmarshal request",
err.Error(), http.StatusBadRequest)
return
}
@ -47,23 +49,27 @@ func (server *Server) addUser(w http.ResponseWriter, r *http.Request) {
existingUser, err := server.db.Console().Users().GetByEmail(ctx, input.Email)
if err != nil && !errors.Is(sql.ErrNoRows, err) {
http.Error(w, fmt.Sprintf("failed to check for user email %q: %v", input.Email, err), http.StatusInternalServerError)
httpJSONError(w, "failed to check for user email",
err.Error(), http.StatusInternalServerError)
return
}
if existingUser != nil {
http.Error(w, fmt.Sprintf("user with email already exists %s", input.Email), http.StatusConflict)
httpJSONError(w, fmt.Sprintf("user with email already exists %s", input.Email),
"", http.StatusConflict)
return
}
hash, err := bcrypt.GenerateFromPassword([]byte(input.Password), 0)
if err != nil {
http.Error(w, "Unable to save password hash", http.StatusInternalServerError)
httpJSONError(w, "unable to save password hash",
"", http.StatusInternalServerError)
return
}
userID, err := uuid.New()
if err != nil {
http.Error(w, "Unable to create UUID", http.StatusInternalServerError)
httpJSONError(w, "unable to create UUID",
"", http.StatusInternalServerError)
return
}
@ -75,7 +81,8 @@ func (server *Server) addUser(w http.ResponseWriter, r *http.Request) {
err = user.IsValid()
if err != nil {
http.Error(w, "User data is not valid", http.StatusBadRequest)
httpJSONError(w, "user data is not valid",
err.Error(), http.StatusBadRequest)
return
}
@ -87,13 +94,15 @@ func (server *Server) addUser(w http.ResponseWriter, r *http.Request) {
PasswordHash: hash,
})
if err != nil {
http.Error(w, fmt.Sprintf("failed to insert user: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to insert user",
err.Error(), http.StatusInternalServerError)
return
}
err = server.payments.Setup(ctx, newuser.ID, newuser.Email)
if err != nil {
http.Error(w, fmt.Sprintf("failed to create payment account for user: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to create payment account for user",
err.Error(), http.StatusInternalServerError)
return
}
@ -102,13 +111,15 @@ func (server *Server) addUser(w http.ResponseWriter, r *http.Request) {
newuser.PasswordHash = nil
err = server.db.Console().Users().Update(ctx, newuser)
if err != nil {
http.Error(w, fmt.Sprintf("failed to activate user: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to activate user",
err.Error(), http.StatusInternalServerError)
return
}
data, err := json.Marshal(newuser)
if err != nil {
http.Error(w, fmt.Sprintf("json encoding failed: %v", err), http.StatusInternalServerError)
httpJSONError(w, "json encoding failed",
err.Error(), http.StatusInternalServerError)
return
}
@ -122,30 +133,35 @@ func (server *Server) userInfo(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
userEmail, ok := vars["useremail"]
if !ok {
http.Error(w, "user-email missing", http.StatusBadRequest)
httpJSONError(w, "user-email missing",
"", http.StatusBadRequest)
return
}
user, err := server.db.Console().Users().GetByEmail(ctx, userEmail)
if errors.Is(err, sql.ErrNoRows) {
http.Error(w, fmt.Sprintf("user with email %q not found", userEmail), http.StatusNotFound)
httpJSONError(w, fmt.Sprintf("user with email %q not found", userEmail),
"", http.StatusNotFound)
return
}
if err != nil {
http.Error(w, fmt.Sprintf("failed to get user %q: %v", userEmail, err), http.StatusInternalServerError)
httpJSONError(w, "failed to get user",
err.Error(), http.StatusInternalServerError)
return
}
user.PasswordHash = nil
projects, err := server.db.Console().Projects().GetByUserID(ctx, user.ID)
if err != nil {
http.Error(w, fmt.Sprintf("failed to get user projects %q: %v", userEmail, err), http.StatusInternalServerError)
httpJSONError(w, "failed to get user projects",
err.Error(), http.StatusInternalServerError)
return
}
coupons, err := server.db.StripeCoinPayments().Coupons().ListByUserID(ctx, user.ID)
if err != nil {
http.Error(w, fmt.Sprintf("failed to get user coupons %q: %v", userEmail, err), http.StatusInternalServerError)
httpJSONError(w, "failed to get user coupons",
err.Error(), http.StatusInternalServerError)
return
}
@ -184,7 +200,8 @@ func (server *Server) userInfo(w http.ResponseWriter, r *http.Request) {
data, err := json.Marshal(output)
if err != nil {
http.Error(w, fmt.Sprintf("json encoding failed: %v", err), http.StatusInternalServerError)
httpJSONError(w, "json encoding failed",
err.Error(), http.StatusInternalServerError)
return
}
@ -198,23 +215,27 @@ func (server *Server) updateUser(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
userEmail, ok := vars["useremail"]
if !ok {
http.Error(w, "user-email missing", http.StatusBadRequest)
httpJSONError(w, "user-email missing",
"", http.StatusBadRequest)
return
}
user, err := server.db.Console().Users().GetByEmail(ctx, userEmail)
if errors.Is(err, sql.ErrNoRows) {
http.Error(w, fmt.Sprintf("user with email %q not found", userEmail), http.StatusNotFound)
httpJSONError(w, fmt.Sprintf("user with email %q not found", userEmail),
"", http.StatusNotFound)
return
}
if err != nil {
http.Error(w, fmt.Sprintf("failed to get user %q: %v", userEmail, err), http.StatusInternalServerError)
httpJSONError(w, "failed to get user",
err.Error(), http.StatusInternalServerError)
return
}
body, err := ioutil.ReadAll(r.Body)
if err != nil {
http.Error(w, fmt.Sprintf("failed to read body: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to read body",
err.Error(), http.StatusInternalServerError)
return
}
@ -222,7 +243,8 @@ func (server *Server) updateUser(w http.ResponseWriter, r *http.Request) {
err = json.Unmarshal(body, &input)
if err != nil {
http.Error(w, fmt.Sprintf("failed to unmarshal request: %v", err), http.StatusBadRequest)
httpJSONError(w, "failed to unmarshal request",
err.Error(), http.StatusBadRequest)
return
}
@ -244,7 +266,8 @@ func (server *Server) updateUser(w http.ResponseWriter, r *http.Request) {
err = server.db.Console().Users().Update(ctx, user)
if err != nil {
http.Error(w, fmt.Sprintf("failed to update user: %v", err), http.StatusInternalServerError)
httpJSONError(w, "failed to update user",
err.Error(), http.StatusInternalServerError)
return
}
}
@ -255,24 +278,27 @@ func (server *Server) deleteUser(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
userEmail, ok := vars["useremail"]
if !ok {
http.Error(w, "user-email missing", http.StatusBadRequest)
httpJSONError(w, "user-email missing", "", http.StatusBadRequest)
return
}
user, err := server.db.Console().Users().GetByEmail(ctx, userEmail)
if errors.Is(err, sql.ErrNoRows) {
http.Error(w, fmt.Sprintf("user with email %q not found", userEmail), http.StatusNotFound)
httpJSONError(w, fmt.Sprintf("user with email %q not found", userEmail),
"", http.StatusNotFound)
return
}
if err != nil {
http.Error(w, fmt.Sprintf("failed to get user %q: %v", userEmail, err), http.StatusInternalServerError)
httpJSONError(w, "failed to get user details",
err.Error(), http.StatusInternalServerError)
return
}
// Ensure user has no own projects any longer
projects, err := server.db.Console().Projects().GetByUserID(ctx, user.ID)
if err != nil {
http.Error(w, fmt.Sprintf("unable to list buckets: %v", err), http.StatusInternalServerError)
httpJSONError(w, "unable to list buckets",
err.Error(), http.StatusInternalServerError)
return
}
if len(projects) > 0 {
@ -283,7 +309,8 @@ func (server *Server) deleteUser(w http.ResponseWriter, r *http.Request) {
// Delete memberships in foreign projects
members, err := server.db.Console().ProjectMembers().GetByMemberID(ctx, user.ID)
if err != nil {
http.Error(w, fmt.Sprintf("unable to search for user project memberships: %v", err), http.StatusInternalServerError)
httpJSONError(w, "unable to search for user project memberships",
err.Error(), http.StatusInternalServerError)
return
}
if len(members) > 0 {
@ -299,7 +326,8 @@ func (server *Server) deleteUser(w http.ResponseWriter, r *http.Request) {
// ensure no unpaid invoices exist.
invoices, err := server.payments.Invoices().List(ctx, user.ID)
if err != nil {
http.Error(w, fmt.Sprintf("unable to list user invoices: %v", err), http.StatusInternalServerError)
httpJSONError(w, "unable to list user invoices",
err.Error(), http.StatusInternalServerError)
return
}
if len(invoices) > 0 {
@ -313,11 +341,13 @@ func (server *Server) deleteUser(w http.ResponseWriter, r *http.Request) {
hasItems, err := server.payments.Invoices().CheckPendingItems(ctx, user.ID)
if err != nil {
http.Error(w, fmt.Sprintf("unable to list pending invoice items: %v", err), http.StatusInternalServerError)
httpJSONError(w, "unable to list pending invoice items",
err.Error(), http.StatusInternalServerError)
return
}
if hasItems {
http.Error(w, "user has pending invoice items", http.StatusConflict)
httpJSONError(w, "user has pending invoice items",
"", http.StatusConflict)
return
}
@ -331,7 +361,8 @@ func (server *Server) deleteUser(w http.ResponseWriter, r *http.Request) {
err = server.db.Console().Users().Update(ctx, userInfo)
if err != nil {
http.Error(w, fmt.Sprintf("unable to delete user: %v", err), http.StatusInternalServerError)
httpJSONError(w, "unable to delete user",
err.Error(), http.StatusInternalServerError)
return
}
}