storagenode/console/api period payment api extended

Change-Id: I18ec331c6a684e3a9351e3c917bacdb8b8f18c28
This commit is contained in:
Qweder93 2020-03-18 13:27:42 +02:00
parent 0df586c3a8
commit 8597e6b512
5 changed files with 242 additions and 18 deletions

View File

@ -179,8 +179,8 @@ func (heldAmount *HeldAmount) AllPayStubsPeriod(w http.ResponseWriter, r *http.R
}
}
// GetMonthlyPayment returns payment data from satellite for specific month.
func (heldAmount *HeldAmount) GetMonthlyPayment(w http.ResponseWriter, r *http.Request) {
// SatellitePaymentMonthly returns payment data from satellite for specific month.
func (heldAmount *HeldAmount) SatellitePaymentMonthly(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
@ -206,7 +206,7 @@ func (heldAmount *HeldAmount) GetMonthlyPayment(w http.ResponseWriter, r *http.R
return
}
paymentData, err := heldAmount.service.GetPayment(ctx, satelliteID, period)
paymentData, err := heldAmount.service.SatellitePaymentMonthlyCached(ctx, satelliteID, period)
if err != nil {
heldAmount.serveJSONError(w, http.StatusInternalServerError, ErrHeldAmountPI.Wrap(err))
return
@ -218,6 +218,113 @@ func (heldAmount *HeldAmount) GetMonthlyPayment(w http.ResponseWriter, r *http.R
}
}
// AllPaymentsMonthly returns payments for specific month from all satellites.
func (heldAmount *HeldAmount) AllPaymentsMonthly(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
w.Header().Set(contentType, applicationJSON)
params := mux.Vars(r)
period, ok := params["period"]
if !ok {
heldAmount.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
return
}
payStubs, err := heldAmount.service.AllPaymentsMonthlyCached(ctx, period)
if err != nil {
heldAmount.serveJSONError(w, http.StatusInternalServerError, ErrHeldAmountPI.Wrap(err))
return
}
if err := json.NewEncoder(w).Encode(payStubs); err != nil {
heldAmount.log.Error("failed to encode json response", zap.Error(ErrHeldAmountPI.Wrap(err)))
return
}
}
// SatellitePaymentPeriod retrieves payment for selected satellite for selected period from storagenode database.
func (heldAmount *HeldAmount) SatellitePaymentPeriod(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
w.Header().Set(contentType, applicationJSON)
params := mux.Vars(r)
id, ok := params["satelliteID"]
if !ok {
heldAmount.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
return
}
satelliteID, err := storj.NodeIDFromString(id)
if err != nil {
heldAmount.serveJSONError(w, http.StatusBadRequest, ErrHeldAmountPI.Wrap(err))
return
}
start, ok := params["start"]
if !ok {
heldAmount.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
return
}
end, ok := params["end"]
if !ok {
heldAmount.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
return
}
payments, err := heldAmount.service.SatellitePaymentPeriodCached(ctx, satelliteID, start, end)
if err != nil {
heldAmount.serveJSONError(w, http.StatusInternalServerError, ErrHeldAmountPI.Wrap(err))
return
}
if err := json.NewEncoder(w).Encode(payments); err != nil {
heldAmount.log.Error("failed to encode json response", zap.Error(ErrHeldAmountPI.Wrap(err)))
return
}
}
// AllPaymentsPeriod retrieves payment for all satellites for selected range of months from storagenode database.
func (heldAmount *HeldAmount) AllPaymentsPeriod(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
w.Header().Set(contentType, applicationJSON)
params := mux.Vars(r)
start, ok := params["start"]
if !ok {
heldAmount.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
return
}
end, ok := params["end"]
if !ok {
heldAmount.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
return
}
payStubs, err := heldAmount.service.AllPaymentsPeriodCached(ctx, start, end)
if err != nil {
heldAmount.serveJSONError(w, http.StatusInternalServerError, ErrHeldAmountPI.Wrap(err))
return
}
if err := json.NewEncoder(w).Encode(payStubs); err != nil {
heldAmount.log.Error("failed to encode json response", zap.Error(ErrHeldAmountPI.Wrap(err)))
return
}
}
// serveJSONError writes JSON error to response output stream.
func (heldAmount *HeldAmount) serveJSONError(w http.ResponseWriter, status int, err error) {
w.WriteHeader(status)

View File

@ -81,7 +81,10 @@ func NewServer(logger *zap.Logger, assets http.FileSystem, notifications *notifi
heldAmountRouter.HandleFunc("/paystub/{period}", heldAmountController.AllPayStubsMonthly).Methods(http.MethodGet)
heldAmountRouter.HandleFunc("/paystub/{start}/{end}/{satelliteID}", heldAmountController.SatellitePayStubPeriod).Methods(http.MethodGet)
heldAmountRouter.HandleFunc("/paystub/{start}/{end}", heldAmountController.AllPayStubsPeriod).Methods(http.MethodGet)
heldAmountRouter.HandleFunc("/payment/{period}/{satelliteID}", heldAmountController.GetMonthlyPayment).Methods(http.MethodGet)
heldAmountRouter.HandleFunc("/payment/{period}/{satelliteID}", heldAmountController.SatellitePaymentMonthly).Methods(http.MethodGet)
heldAmountRouter.HandleFunc("/payment/{period}", heldAmountController.AllPaymentsMonthly).Methods(http.MethodGet)
heldAmountRouter.HandleFunc("/payment/{start}/{end}/{satelliteID}", heldAmountController.SatellitePaymentPeriod).Methods(http.MethodGet)
heldAmountRouter.HandleFunc("/payment/{start}/{end}", heldAmountController.AllPaymentsPeriod).Methods(http.MethodGet)
if assets != nil {
fs := http.FileServer(assets)

View File

@ -149,10 +149,12 @@ func TestHeldAmountDB(t *testing.T) {
paym, err = heldAmount.GetPayment(ctx, satelliteID, "")
assert.Error(t, err)
assert.Equal(t, true, heldamount.ErrNoPayStubForPeriod.Has(err))
assert.Nil(t, paym)
paym, err = heldAmount.GetPayment(ctx, storj.NodeID{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1}, period)
assert.Error(t, err)
assert.Equal(t, true, heldamount.ErrNoPayStubForPeriod.Has(err))
assert.Nil(t, paym)
})
@ -174,6 +176,81 @@ func TestHeldAmountDB(t *testing.T) {
})
})
}
func TestSatellitePaymentPeriodCached(t *testing.T) {
storagenodedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db storagenode.DB) {
heldAmountDB := db.HeldAmount()
service := heldamount.NewService(nil, heldAmountDB, rpc.Dialer{}, nil)
payment := heldamount.Payment{
Created: time.Now().UTC(),
SatelliteID: storj.NodeID{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
Amount: 228,
Receipt: "receipt_test",
Notes: "notes_test",
}
for i := 1; i < 4; i++ {
payment.Period = fmt.Sprintf("2020-0%d", i)
payment.ID = int64(i)
err := heldAmountDB.StorePayment(ctx, payment)
require.NoError(t, err)
}
payments, err := service.SatellitePaymentPeriodCached(ctx, payment.SatelliteID, "2020-01", "2020-03")
require.NoError(t, err)
require.Equal(t, 3, len(payments))
payments, err = service.SatellitePaymentPeriodCached(ctx, payment.SatelliteID, "2019-01", "2021-03")
require.NoError(t, err)
require.Equal(t, 3, len(payments))
payments, err = service.SatellitePaymentPeriodCached(ctx, payment.SatelliteID, "2019-01", "2020-01")
require.NoError(t, err)
require.Equal(t, 1, len(payments))
})
}
func TestAllPaymentPeriodCached(t *testing.T) {
storagenodedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db storagenode.DB) {
heldAmountDB := db.HeldAmount()
service := heldamount.NewService(nil, heldAmountDB, rpc.Dialer{}, nil)
payment := heldamount.Payment{
ID: 1,
Created: time.Now().UTC(),
SatelliteID: storj.NodeID{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
Amount: 228,
Receipt: "receipt_test",
Notes: "notes_test",
}
for i := 1; i < 4; i++ {
payment.SatelliteID[0] += byte(i)
for j := 1; j < 4; j++ {
payment.Period = fmt.Sprintf("2020-0%d", j)
payment.ID = int64(12*i + 2*j + 1)
err := heldAmountDB.StorePayment(ctx, payment)
require.NoError(t, err)
}
}
payments, err := service.AllPaymentsPeriodCached(ctx, "2020-01", "2020-03")
require.NoError(t, err)
require.Equal(t, 9, len(payments))
payments, err = service.AllPaymentsPeriodCached(ctx, "2019-01", "2021-03")
require.NoError(t, err)
require.Equal(t, 9, len(payments))
payments, err = service.AllPaymentsPeriodCached(ctx, "2019-01", "2020-01")
require.NoError(t, err)
require.Equal(t, 3, len(payments))
payments, err = service.AllPaymentsPeriodCached(ctx, "2019-01", "2019-01")
require.NoError(t, err)
require.Equal(t, 0, len(payments))
})
}
func TestSatellitePayStubPeriodCached(t *testing.T) {
storagenodedbtest.Run(t, func(ctx *testcontext.Context, t *testing.T, db storagenode.DB) {

View File

@ -8,7 +8,6 @@ import (
"fmt"
"strconv"
"strings"
"time"
"github.com/spacemonkeygo/monkit/v3"
"github.com/zeebo/errs"
@ -17,6 +16,7 @@ import (
"storj.io/common/pb"
"storj.io/common/rpc"
"storj.io/storj/pkg/storj"
"storj.io/storj/private/date"
"storj.io/storj/storagenode/trust"
)
@ -74,7 +74,7 @@ func (service *Service) GetPaystubStats(ctx context.Context, satelliteID storj.N
}
defer func() { err = errs.Combine(err, client.Close()) }()
requestedPeriod, err := stringToTime(period)
requestedPeriod, err := date.PeriodToTime(period)
if err != nil {
service.log.Error("stringToTime", zap.Error(err))
return nil, ErrHeldAmountService.Wrap(err)
@ -121,7 +121,7 @@ func (service *Service) GetPayment(ctx context.Context, satelliteID storj.NodeID
}
defer func() { err = errs.Combine(err, client.Close()) }()
requestedPeriod, err := stringToTime(period)
requestedPeriod, err := date.PeriodToTime(period)
if err != nil {
return nil, ErrHeldAmountService.Wrap(err)
}
@ -235,6 +235,51 @@ func (service *Service) AllPaymentsMonthlyCached(ctx context.Context, period str
return payments, nil
}
// SatellitePaymentPeriodCached retrieves payment for all satellites for selected months from storagenode database.
func (service *Service) SatellitePaymentPeriodCached(ctx context.Context, satelliteID storj.NodeID, periodStart, periodEnd string) (payments []*Payment, err error) {
defer mon.Task()(&ctx, &satelliteID, &periodStart, &periodEnd)(&err)
periods, err := parsePeriodRange(periodStart, periodEnd)
if err != nil {
return nil, err
}
for _, period := range periods {
payment, err := service.db.GetPayment(ctx, satelliteID, period)
if err != nil {
if ErrNoPayStubForPeriod.Has(err) {
continue
}
return nil, ErrHeldAmountService.Wrap(err)
}
payments = append(payments, payment)
}
return payments, nil
}
// AllPaymentsPeriodCached retrieves payment for all satellites for selected range of months from storagenode database.
func (service *Service) AllPaymentsPeriodCached(ctx context.Context, periodStart, periodEnd string) (payments []Payment, err error) {
defer mon.Task()(&ctx, &periodStart, &periodEnd)(&err)
periods, err := parsePeriodRange(periodStart, periodEnd)
if err != nil {
return nil, err
}
for _, period := range periods {
payment, err := service.db.AllPayments(ctx, period)
if err != nil {
return nil, ErrHeldAmountService.Wrap(err)
}
payments = append(payments, payment...)
}
return payments, nil
}
// dial dials the HeldAmount client for the satellite by id
func (service *Service) dial(ctx context.Context, satelliteID storj.NodeID) (_ *Client, err error) {
defer mon.Task()(&ctx)(&err)
@ -255,17 +300,6 @@ func (service *Service) dial(ctx context.Context, satelliteID storj.NodeID) (_ *
}, nil
}
func stringToTime(period string) (_ time.Time, err error) {
layout := "2006-01"
per := period[0:7]
result, err := time.Parse(layout, per)
if err != nil {
return time.Time{}, err
}
return result, nil
}
// TODO: improve it.
func parsePeriodRange(periodStart, periodEnd string) (periods []string, err error) {
var yearStart, yearEnd, monthStart, monthEnd int

View File

@ -273,6 +273,9 @@ func (db *heldamountDB) GetPayment(ctx context.Context, satelliteID storj.NodeID
&result.Notes,
)
if err != nil {
if sql.ErrNoRows == err {
return nil, heldamount.ErrNoPayStubForPeriod.Wrap(err)
}
return nil, ErrHeldAmount.Wrap(err)
}