storj/satellite/console/consoleweb/consoleapi/payments.go
2019-10-17 17:42:18 +03:00

144 lines
3.3 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package consoleapi
import (
"context"
"encoding/json"
"net/http"
"strings"
"go.uber.org/zap"
monkit "gopkg.in/spacemonkeygo/monkit.v2"
"storj.io/storj/pkg/auth"
"storj.io/storj/satellite/console"
)
var mon = monkit.Package()
// Payments is an api controller that exposes all payment related functionality
type Payments struct {
log *zap.Logger
service *console.Service
}
// NewPayments is a constructor for api payments controller.
func NewPayments(log *zap.Logger, service *console.Service) *Payments {
return &Payments{
log: log,
service: service,
}
}
// SetupAccount creates a payment account for the user.
func (p *Payments) SetupAccount(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusNotFound)
return
}
ctx = p.authorize(ctx, r)
err = p.service.Payments().SetupAccount(ctx)
if err != nil {
p.serveJSONError(w, http.StatusInternalServerError, err)
}
}
// AccountBalance returns an integer amount in cents that represents the current balance of payment account.
func (p *Payments) AccountBalance(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
if r.Method != http.MethodGet {
w.WriteHeader(http.StatusNotFound)
return
}
ctx = p.authorize(ctx, r)
balance, err := p.service.Payments().AccountBalance(ctx)
if err != nil {
p.serveJSONError(w, http.StatusInternalServerError, err)
return
}
var balanceResponse struct {
Balance int64 `json:"balance"`
}
balanceResponse.Balance = balance
err = json.NewEncoder(w).Encode(balanceResponse)
if err != nil {
p.log.Error("failed to write json balance response", zap.Error(err))
}
}
// AddCreditCard is used to save new credit card and attach it to payment account.
func (p *Payments) AddCreditCard(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
if r.Method != http.MethodPost {
w.WriteHeader(http.StatusNotFound)
return
}
ctx = p.authorize(ctx, r)
var requestBody struct {
Token string `json:"token"`
}
decoder := json.NewDecoder(r.Body)
err = decoder.Decode(&requestBody)
if err != nil {
p.serveJSONError(w, http.StatusBadRequest, err)
return
}
err = p.service.Payments().AddCreditCard(ctx, requestBody.Token)
if err != nil {
p.serveJSONError(w, http.StatusInternalServerError, err)
}
}
// serveJSONError writes JSON error to response output stream.
func (p *Payments) serveJSONError(w http.ResponseWriter, status int, err error) {
w.WriteHeader(status)
var response struct {
Error string `json:"error"`
}
response.Error = err.Error()
err = json.NewEncoder(w).Encode(response)
if err != nil {
p.log.Error("failed to write json error response", zap.Error(err))
}
}
// authorize checks request for authorization token, validates it and updates context with auth data.
func (p *Payments) authorize(ctx context.Context, r *http.Request) context.Context {
authHeaderValue := r.Header.Get("Authorization")
token := strings.TrimPrefix(authHeaderValue, "Bearer ")
auth, err := p.service.Authorize(auth.WithAPIKey(ctx, []byte(token)))
if err != nil {
return console.WithAuthFailure(ctx, err)
}
return console.WithAuth(ctx, auth)
}