storj/storagenode/console/consoleapi/payout.go

263 lines
7.3 KiB
Go
Raw Normal View History

// Copyright (C) 2020 Storj Labs, Inc.
// See LICENSE for copying information.
package consoleapi
import (
"encoding/json"
"net/http"
"github.com/gorilla/mux"
"github.com/zeebo/errs"
"go.uber.org/zap"
"storj.io/common/storj"
"storj.io/storj/storagenode/payout"
)
// ErrPayoutAPI - console payout api error type.
var ErrPayoutAPI = errs.Class("payout console web error")
// Payout is an api controller that exposes all payout related api.
type Payout struct {
service *payout.Service
log *zap.Logger
}
// NewPayout is a constructor for payout controller.
func NewPayout(log *zap.Logger, service *payout.Service) *Payout {
return &Payout{
log: log,
service: service,
}
}
// PayStubMonthly returns payout, storage holding and prices data for specific month from all satellites or specified satellite by query parameter id.
func (payouts *Payout) PayStubMonthly(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
w.Header().Set(contentType, applicationJSON)
segmentParams := mux.Vars(r)
queryParams := r.URL.Query()
period, ok := segmentParams["period"]
if !ok {
payouts.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
return
}
id := queryParams.Get("id")
if id == "" {
payStubs, err := payouts.service.AllPayStubsMonthly(ctx, period)
if err != nil {
payouts.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
return
}
if err := json.NewEncoder(w).Encode(payStubs); err != nil {
payouts.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
return
}
} else {
satelliteID, err := storj.NodeIDFromString(id)
if err != nil {
payouts.serveJSONError(w, http.StatusBadRequest, ErrPayoutAPI.Wrap(err))
return
}
payStub, err := payouts.service.SatellitePayStubMonthly(ctx, satelliteID, period)
if err != nil {
if payout.ErrNoPayStubForPeriod.Has(err) {
payouts.serveJSONError(w, http.StatusNotFound, ErrPayoutAPI.Wrap(err))
return
}
payouts.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
return
}
if err := json.NewEncoder(w).Encode([]*payout.PayStub{payStub}); err != nil {
payouts.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
return
}
}
}
// PayStubPeriod retrieves paystubs for selected range of months from storagenode database for all satellites or specified satellite by query parameter id.
func (payouts *Payout) PayStubPeriod(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
w.Header().Set(contentType, applicationJSON)
segmentParams := mux.Vars(r)
queryParams := r.URL.Query()
start, ok := segmentParams["start"]
if !ok {
payouts.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
return
}
end, ok := segmentParams["end"]
if !ok {
payouts.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
return
}
id := queryParams.Get("id")
if id == "" {
payStubs, err := payouts.service.AllPayStubsPeriod(ctx, start, end)
if err != nil {
if payout.ErrBadPeriod.Has(err) {
payouts.serveJSONError(w, http.StatusBadRequest, ErrPayoutAPI.Wrap(err))
return
}
payouts.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
return
}
if err := json.NewEncoder(w).Encode(payStubs); err != nil {
payouts.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
return
}
} else {
satelliteID, err := storj.NodeIDFromString(id)
if err != nil {
payouts.serveJSONError(w, http.StatusBadRequest, ErrPayoutAPI.Wrap(err))
return
}
payStubs, err := payouts.service.SatellitePayStubPeriod(ctx, satelliteID, start, end)
if err != nil {
if payout.ErrBadPeriod.Has(err) {
payouts.serveJSONError(w, http.StatusBadRequest, ErrPayoutAPI.Wrap(err))
return
}
payouts.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
return
}
if err := json.NewEncoder(w).Encode(payStubs); err != nil {
payouts.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
return
}
}
}
// HeldHistory returns held amount for each % period for all satellites.
func (payouts *Payout) HeldHistory(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
w.Header().Set(contentType, applicationJSON)
heldbackHistory, err := payouts.service.AllHeldbackHistory(ctx)
if err != nil {
payouts.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
return
}
if err := json.NewEncoder(w).Encode(heldbackHistory); err != nil {
payouts.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
return
}
}
// PayoutHistory retrieves paystubs for specific period from all satellites and transaction receipts if exists.
func (payouts *Payout) PayoutHistory(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
w.Header().Set(contentType, applicationJSON)
segmentParams := mux.Vars(r)
period, ok := segmentParams["period"]
if !ok {
payouts.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
return
}
payoutHistory, err := payouts.service.AllSatellitesPayoutPeriod(ctx, period)
if err != nil {
payouts.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
return
}
if err := json.NewEncoder(w).Encode(payoutHistory); err != nil {
payouts.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
return
}
}
// HeldAmountPeriods retrieves all periods in which we have some payout data.
// Have optional parameter - satelliteID.
// If satelliteID specified - will retrieve periods only for concrete satellite.
func (payouts *Payout) HeldAmountPeriods(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
w.Header().Set(contentType, applicationJSON)
queryParams := r.URL.Query()
id := queryParams.Get("id")
if id == "" {
payStubs, err := payouts.service.AllPeriods(ctx)
if err != nil {
payouts.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
return
}
if err := json.NewEncoder(w).Encode(payStubs); err != nil {
payouts.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
return
}
} else {
satelliteID, err := storj.NodeIDFromString(id)
if err != nil {
payouts.serveJSONError(w, http.StatusBadRequest, ErrPayoutAPI.Wrap(err))
return
}
payStubs, err := payouts.service.SatellitePeriods(ctx, satelliteID)
if err != nil {
payouts.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
return
}
if err := json.NewEncoder(w).Encode(payStubs); err != nil {
payouts.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
return
}
}
}
// serveJSONError writes JSON error to response output stream.
func (payouts *Payout) 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 {
payouts.log.Error("failed to write json error response", zap.Error(ErrPayoutAPI.Wrap(err)))
return
}
}