6ba8f6c8a9
Change-Id: I4aa5e99bffaa87d0a800a429a4c83aa498ad4b7b
263 lines
7.3 KiB
Go
263 lines
7.3 KiB
Go
// 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/payouts"
|
|
)
|
|
|
|
// ErrPayoutAPI - console payouts api error type.
|
|
var ErrPayoutAPI = errs.Class("payouts console web error")
|
|
|
|
// Payout is an api controller that exposes all payouts related api.
|
|
type Payout struct {
|
|
service *payouts.Service
|
|
|
|
log *zap.Logger
|
|
}
|
|
|
|
// NewPayout is a constructor for payouts controller.
|
|
func NewPayout(log *zap.Logger, service *payouts.Service) *Payout {
|
|
return &Payout{
|
|
log: log,
|
|
service: service,
|
|
}
|
|
}
|
|
|
|
// PayStubMonthly returns payouts, storage holding and prices data for specific month from all satellites or specified satellite by query parameter id.
|
|
func (payout *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 {
|
|
payout.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
id := queryParams.Get("id")
|
|
if id == "" {
|
|
payStubs, err := payout.service.AllPayStubsMonthly(ctx, period)
|
|
if err != nil {
|
|
payout.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
if err := json.NewEncoder(w).Encode(payStubs); err != nil {
|
|
payout.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
|
|
return
|
|
}
|
|
} else {
|
|
satelliteID, err := storj.NodeIDFromString(id)
|
|
if err != nil {
|
|
payout.serveJSONError(w, http.StatusBadRequest, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
payStub, err := payout.service.SatellitePayStubMonthly(ctx, satelliteID, period)
|
|
if err != nil {
|
|
if payouts.ErrNoPayStubForPeriod.Has(err) {
|
|
payout.serveJSONError(w, http.StatusNotFound, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
payout.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
if err := json.NewEncoder(w).Encode([]*payouts.PayStub{payStub}); err != nil {
|
|
payout.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 (payout *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 {
|
|
payout.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
end, ok := segmentParams["end"]
|
|
if !ok {
|
|
payout.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
id := queryParams.Get("id")
|
|
if id == "" {
|
|
payStubs, err := payout.service.AllPayStubsPeriod(ctx, start, end)
|
|
if err != nil {
|
|
if payouts.ErrBadPeriod.Has(err) {
|
|
payout.serveJSONError(w, http.StatusBadRequest, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
payout.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
if err := json.NewEncoder(w).Encode(payStubs); err != nil {
|
|
payout.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
|
|
return
|
|
}
|
|
} else {
|
|
satelliteID, err := storj.NodeIDFromString(id)
|
|
if err != nil {
|
|
payout.serveJSONError(w, http.StatusBadRequest, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
payStubs, err := payout.service.SatellitePayStubPeriod(ctx, satelliteID, start, end)
|
|
if err != nil {
|
|
if payouts.ErrBadPeriod.Has(err) {
|
|
payout.serveJSONError(w, http.StatusBadRequest, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
payout.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
if err := json.NewEncoder(w).Encode(payStubs); err != nil {
|
|
payout.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// HeldHistory returns held amount for each % period for all satellites.
|
|
func (payout *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 := payout.service.AllHeldbackHistory(ctx)
|
|
if err != nil {
|
|
payout.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
if err := json.NewEncoder(w).Encode(heldbackHistory); err != nil {
|
|
payout.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 (payout *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 {
|
|
payout.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
payoutHistory, err := payout.service.AllSatellitesPayoutPeriod(ctx, period)
|
|
if err != nil {
|
|
payout.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
if err := json.NewEncoder(w).Encode(payoutHistory); err != nil {
|
|
payout.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
|
|
return
|
|
}
|
|
}
|
|
|
|
// HeldAmountPeriods retrieves all periods in which we have some payouts data.
|
|
// Have optional parameter - satelliteID.
|
|
// If satelliteID specified - will retrieve periods only for concrete satellite.
|
|
func (payout *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 := payout.service.AllPeriods(ctx)
|
|
if err != nil {
|
|
payout.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
if err := json.NewEncoder(w).Encode(payStubs); err != nil {
|
|
payout.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
|
|
return
|
|
}
|
|
} else {
|
|
satelliteID, err := storj.NodeIDFromString(id)
|
|
if err != nil {
|
|
payout.serveJSONError(w, http.StatusBadRequest, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
payStubs, err := payout.service.SatellitePeriods(ctx, satelliteID)
|
|
if err != nil {
|
|
payout.serveJSONError(w, http.StatusInternalServerError, ErrPayoutAPI.Wrap(err))
|
|
return
|
|
}
|
|
|
|
if err := json.NewEncoder(w).Encode(payStubs); err != nil {
|
|
payout.log.Error("failed to encode json response", zap.Error(ErrPayoutAPI.Wrap(err)))
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// serveJSONError writes JSON error to response output stream.
|
|
func (payout *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 {
|
|
payout.log.Error("failed to write json error response", zap.Error(ErrPayoutAPI.Wrap(err)))
|
|
return
|
|
}
|
|
}
|