Skip to content

Commit f1f285e

Browse files
committed
refactor: split PostValidatorDashboardGroups and GetValidatorDashboardGroupSummary logics
1 parent 3cb6800 commit f1f285e

File tree

5 files changed

+147
-120
lines changed

5 files changed

+147
-120
lines changed

backend/pkg/api/handlers/input_validation.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package handlers
22

33
import (
44
"cmp"
5+
"encoding/base64"
56
"encoding/json"
67
"fmt"
78
"io"
@@ -94,6 +95,13 @@ func (v *validationError) hasErrors() bool {
9495
return v != nil && len(*v) > 0
9596
}
9697

98+
func (v *validationError) AsError() error {
99+
if v.hasErrors() {
100+
return newBadRequestErr("%s", v.Error())
101+
}
102+
return nil
103+
}
104+
97105
// --------------------------------------
98106

99107
func (v *validationError) checkRegex(regex *regexp.Regexp, param, paramName string) string {
@@ -553,3 +561,28 @@ func (v *validationError) checkTimestamps(r *http.Request, chartLimits ChartTime
553561
return afterTs, beforeTs
554562
}
555563
}
564+
565+
func (v *validationError) checkDashboardId(id string) interface{} {
566+
if reInteger.MatchString(id) {
567+
// given id is a normal id
568+
id := v.checkUint(id, "dashboard_id")
569+
return types.VDBIdPrimary(id)
570+
}
571+
if reValidatorDashboardPublicId.MatchString(id) {
572+
// given id is a public id
573+
return types.VDBIdPublic(id)
574+
}
575+
// given id must be an encoded set of validators
576+
decodedId, err := base64.RawURLEncoding.DecodeString(id)
577+
if err != nil {
578+
v.add("dashboard_id", fmt.Sprintf("given value '%s' is not a valid dashboard id", id))
579+
return nil
580+
}
581+
var validatorListError validationError
582+
indexes, publicKeys := validatorListError.checkValidatorList(string(decodedId), forbidEmpty)
583+
if validatorListError.hasErrors() {
584+
v.add("dashboard_id", fmt.Sprintf("given value '%s' is not a valid dashboard id", id))
585+
return nil
586+
}
587+
return validatorSet{Indexes: indexes, PublicKeys: publicKeys}
588+
}

backend/pkg/api/handlers/internal.go

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -348,10 +348,6 @@ func (h *HandlerService) InternalPutValidatorDashboardName(w http.ResponseWriter
348348
h.PublicPutValidatorDashboardName(w, r)
349349
}
350350

351-
func (h *HandlerService) InternalPostValidatorDashboardGroups(w http.ResponseWriter, r *http.Request) {
352-
h.PublicPostValidatorDashboardGroups(w, r)
353-
}
354-
355351
func (h *HandlerService) InternalPutValidatorDashboardGroups(w http.ResponseWriter, r *http.Request) {
356352
h.PublicPutValidatorDashboardGroups(w, r)
357353
}
@@ -431,11 +427,6 @@ func (h *HandlerService) InternalGetValidatorDashboardSlotViz(w http.ResponseWri
431427
func (h *HandlerService) InternalGetValidatorDashboardSummary(w http.ResponseWriter, r *http.Request) {
432428
h.PublicGetValidatorDashboardSummary(w, r)
433429
}
434-
435-
func (h *HandlerService) InternalGetValidatorDashboardGroupSummary(w http.ResponseWriter, r *http.Request) {
436-
h.PublicGetValidatorDashboardGroupSummary(w, r)
437-
}
438-
439430
func (h *HandlerService) InternalGetValidatorDashboardSummaryChart(w http.ResponseWriter, r *http.Request) {
440431
h.PublicGetValidatorDashboardSummaryChart(w, r)
441432
}

backend/pkg/api/handlers/public.go

Lines changed: 0 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -333,70 +333,6 @@ func (h *HandlerService) PublicPutValidatorDashboardName(w http.ResponseWriter,
333333
returnOk(w, r, response)
334334
}
335335

336-
// PublicPostValidatorDashboardGroups godoc
337-
//
338-
// @Description Create a new group in a specified validator dashboard.
339-
// @Security ApiKeyInHeader || ApiKeyInQuery
340-
// @Tags Validator Dashboard Management
341-
// @Accept json
342-
// @Produce json
343-
// @Param dashboard_id path integer true "The ID of the dashboard."
344-
// @Param request body handlers.PublicPostValidatorDashboardGroups.request true "request"
345-
// @Success 201 {object} types.ApiDataResponse[types.VDBPostCreateGroupData]
346-
// @Failure 400 {object} types.ApiErrorResponse
347-
// @Failure 409 {object} types.ApiErrorResponse "Conflict. The request could not be performed by the server because the authenticated user has already reached their group limit."
348-
// @Router /validator-dashboards/{dashboard_id}/groups [post]
349-
func (h *HandlerService) PublicPostValidatorDashboardGroups(w http.ResponseWriter, r *http.Request) {
350-
var v validationError
351-
dashboardId := v.checkPrimaryDashboardId(mux.Vars(r)["dashboard_id"])
352-
type request struct {
353-
Name string `json:"name"`
354-
}
355-
var req request
356-
if err := v.checkBody(&req, r.Body); err != nil {
357-
handleErr(w, r, err)
358-
return
359-
}
360-
name := v.checkNameNotEmpty(req.Name)
361-
if v.hasErrors() {
362-
handleErr(w, r, v)
363-
return
364-
}
365-
ctx := r.Context()
366-
// check if user has reached the maximum number of groups
367-
userId, err := GetUserIdByContext(ctx)
368-
if err != nil {
369-
handleErr(w, r, err)
370-
return
371-
}
372-
userInfo, err := h.getDataAccessor(ctx).GetUserInfo(ctx, userId)
373-
if err != nil {
374-
handleErr(w, r, err)
375-
return
376-
}
377-
groupCount, err := h.getDataAccessor(ctx).GetValidatorDashboardGroupCount(ctx, dashboardId)
378-
if err != nil {
379-
handleErr(w, r, err)
380-
return
381-
}
382-
if groupCount >= userInfo.PremiumPerks.ValidatorGroupsPerDashboard {
383-
returnConflict(w, r, errors.New("maximum number of validator dashboard groups reached"))
384-
return
385-
}
386-
387-
data, err := h.getDataAccessor(ctx).CreateValidatorDashboardGroup(ctx, dashboardId, name)
388-
if err != nil {
389-
handleErr(w, r, err)
390-
return
391-
}
392-
393-
response := types.ApiDataResponse[types.VDBPostCreateGroupData]{
394-
Data: *data,
395-
}
396-
397-
returnCreated(w, r, response)
398-
}
399-
400336
// PublicGetValidatorDashboardGroups godoc
401337
//
402338
// @Description Update a groups name in a specified validator dashboard.
@@ -1119,51 +1055,6 @@ func (h *HandlerService) PublicGetValidatorDashboardSummary(w http.ResponseWrite
11191055
returnOk(w, r, response)
11201056
}
11211057

1122-
// PublicGetValidatorDashboardGroupSummary godoc
1123-
//
1124-
// @Description Get summary information for a specified group in a specified dashboard
1125-
// @Tags Validator Dashboard
1126-
// @Produce json
1127-
// @Param dashboard_id path string true "The ID of the dashboard."
1128-
// @Param group_id path integer true "The ID of the group."
1129-
// @Param period query string true "Time period to get data for." Enums(all_time, last_30d, last_7d, last_24h, last_1h)
1130-
// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``."
1131-
// @Success 200 {object} types.GetValidatorDashboardGroupSummaryResponse
1132-
// @Failure 400 {object} types.ApiErrorResponse
1133-
// @Router /validator-dashboards/{dashboard_id}/groups/{group_id}/summary [get]
1134-
func (h *HandlerService) PublicGetValidatorDashboardGroupSummary(w http.ResponseWriter, r *http.Request) {
1135-
var v validationError
1136-
vars := mux.Vars(r)
1137-
ctx := r.Context()
1138-
dashboardId, err := h.handleDashboardId(ctx, vars["dashboard_id"])
1139-
q := r.URL.Query()
1140-
protocolModes := v.checkProtocolModes(q.Get("modes"))
1141-
if v.hasErrors() {
1142-
handleErr(w, r, v)
1143-
return
1144-
}
1145-
if err != nil {
1146-
handleErr(w, r, err)
1147-
return
1148-
}
1149-
groupId := v.checkGroupId(vars["group_id"], forbidEmpty)
1150-
period := checkEnum[enums.TimePeriod](&v, r.URL.Query().Get("period"), "period")
1151-
if v.hasErrors() {
1152-
handleErr(w, r, v)
1153-
return
1154-
}
1155-
1156-
data, err := h.getDataAccessor(ctx).GetValidatorDashboardGroupSummary(ctx, *dashboardId, groupId, period, protocolModes)
1157-
if err != nil {
1158-
handleErr(w, r, err)
1159-
return
1160-
}
1161-
response := types.GetValidatorDashboardGroupSummaryResponse{
1162-
Data: *data,
1163-
}
1164-
returnOk(w, r, response)
1165-
}
1166-
11671058
// PublicGetValidatorDashboardSummaryChart godoc
11681059
//
11691060
// @Description Get summary chart data for a specified dashboard
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
package handlers
2+
3+
import (
4+
"context"
5+
"io"
6+
7+
"github.com/gobitfly/beaconchain/pkg/api/enums"
8+
"github.com/gobitfly/beaconchain/pkg/api/types"
9+
)
10+
11+
// PublicPostValidatorDashboardGroups godoc
12+
//
13+
// @Description Create a new group in a specified validator dashboard.
14+
// @Security ApiKeyInHeader || ApiKeyInQuery
15+
// @Tags Validator Dashboard Management
16+
// @Accept json
17+
// @Produce json
18+
// @Param dashboard_id path integer true "The ID of the dashboard."
19+
// @Param request body handlers.PublicPostValidatorDashboardGroups.request true "request"
20+
// @Success 201 {object} types.ApiDataResponse[types.VDBPostCreateGroupData]
21+
// @Failure 400 {object} types.ApiErrorResponse
22+
// @Failure 409 {object} types.ApiErrorResponse "Conflict. The request could not be performed by the server because the authenticated user has already reached their group limit."
23+
// @Router /validator-dashboards/{dashboard_id}/groups [post]
24+
type inputPostValidatorDashboardGroups struct {
25+
dashboardId types.VDBIdPrimary
26+
name string
27+
}
28+
29+
func (i inputPostValidatorDashboardGroups) Check(params map[string]string, body io.ReadCloser) (inputPostValidatorDashboardGroups, error) {
30+
var v validationError
31+
type request struct {
32+
Name string `json:"name"`
33+
}
34+
var req request
35+
if err := v.checkBody(&req, body); err != nil {
36+
return i, err
37+
}
38+
i.dashboardId = v.checkPrimaryDashboardId(params["dashboard_id"])
39+
i.name = v.checkNameNotEmpty(req.Name)
40+
return i, v.AsError()
41+
}
42+
43+
func (h *HandlerService) PostValidatorDashboardGroups(ctx context.Context, input inputPostValidatorDashboardGroups) (*types.ApiDataResponse[types.VDBPostCreateGroupData], error) {
44+
dataAccessor := h.getDataAccessor(ctx)
45+
userId, err := GetUserIdByContext(ctx)
46+
if err != nil {
47+
return nil, err
48+
}
49+
userInfo, err := dataAccessor.GetUserInfo(ctx, userId)
50+
if err != nil {
51+
return nil, err
52+
}
53+
groupCount, err := dataAccessor.GetValidatorDashboardGroupCount(ctx, input.dashboardId)
54+
if err != nil {
55+
return nil, err
56+
}
57+
if groupCount >= userInfo.PremiumPerks.ValidatorGroupsPerDashboard {
58+
return nil, newConflictErr("maximum number of validator dashboard groups reached")
59+
}
60+
61+
data, err := dataAccessor.CreateValidatorDashboardGroup(ctx, input.dashboardId, input.name)
62+
if err != nil {
63+
return nil, err
64+
}
65+
response := types.ApiDataResponse[types.VDBPostCreateGroupData]{
66+
Data: *data,
67+
}
68+
return &response, nil
69+
}
70+
71+
// GetValidatorDashboardGroupSummary godoc
72+
//
73+
// @Description Get summary information for a specified group in a specified dashboard
74+
// @Tags Validator Dashboard
75+
// @Produce json
76+
// @Param dashboard_id path string true "The ID of the dashboard."
77+
// @Param group_id path integer true "The ID of the group."
78+
// @Param period query string true "Time period to get data for." Enums(all_time, last_30d, last_7d, last_24h, last_1h)
79+
// @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``."
80+
// @Success 200 {object} types.GetValidatorDashboardGroupSummaryResponse
81+
// @Failure 400 {object} types.ApiErrorResponse
82+
// @Router /validator-dashboards/{dashboard_id}/groups/{group_id}/summary [get]
83+
84+
type inputGetValidatorDashboardGroupSummary struct {
85+
dashboardIdParam interface{}
86+
groupId int64
87+
protocolModes types.VDBProtocolModes
88+
period enums.TimePeriod
89+
}
90+
91+
func (i inputGetValidatorDashboardGroupSummary) Check(params map[string]string, _ io.ReadCloser) (inputGetValidatorDashboardGroupSummary, error) {
92+
var v validationError
93+
i.dashboardIdParam = v.checkDashboardId(params["dashboard_id"])
94+
i.groupId = v.checkGroupId(params["group_id"], forbidEmpty)
95+
i.period = checkEnum[enums.TimePeriod](&v, params["period"], "period")
96+
i.protocolModes = v.checkProtocolModes(params["modes"])
97+
return i, v.AsError()
98+
}
99+
100+
func (h *HandlerService) GetValidatorDashboardGroupSummary(ctx context.Context, input inputGetValidatorDashboardGroupSummary) (*types.GetValidatorDashboardGroupSummaryResponse, error) {
101+
dashboardId, err := h.getDashboardId(ctx, input.dashboardIdParam)
102+
if err != nil {
103+
return nil, err
104+
}
105+
data, err := h.getDataAccessor(ctx).GetValidatorDashboardGroupSummary(ctx, *dashboardId, input.groupId, input.period, input.protocolModes)
106+
if err != nil {
107+
return nil, err
108+
}
109+
return &types.GetValidatorDashboardGroupSummaryResponse{
110+
Data: *data,
111+
}, nil
112+
}

backend/pkg/api/router.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -287,7 +287,7 @@ func addValidatorDashboardRoutes(hs *handlers.HandlerService, publicRouter, inte
287287
endpoints := []endpoint{
288288
{http.MethodGet, "/{dashboard_id}", hs.PublicGetValidatorDashboard, hs.InternalGetValidatorDashboard},
289289
{http.MethodPut, "/{dashboard_id}/name", hs.PublicPutValidatorDashboardName, hs.InternalPutValidatorDashboardName},
290-
{http.MethodPost, "/{dashboard_id}/groups", hs.PublicPostValidatorDashboardGroups, hs.InternalPostValidatorDashboardGroups},
290+
{http.MethodPost, "/{dashboard_id}/groups", handlers.Handle(http.StatusCreated, hs.PostValidatorDashboardGroups), handlers.Handle(http.StatusCreated, hs.PostValidatorDashboardGroups)},
291291
{http.MethodPut, "/{dashboard_id}/groups/{group_id}", hs.PublicPutValidatorDashboardGroups, hs.InternalPutValidatorDashboardGroups},
292292
{http.MethodDelete, "/{dashboard_id}/groups/{group_id}", hs.PublicDeleteValidatorDashboardGroup, hs.InternalDeleteValidatorDashboardGroup},
293293
{http.MethodDelete, "/{dashboard_id}/groups/{group_id}/validators", hs.PublicDeleteValidatorDashboardGroupValidators, hs.InternalDeleteValidatorDashboardGroupValidators},
@@ -301,7 +301,7 @@ func addValidatorDashboardRoutes(hs *handlers.HandlerService, publicRouter, inte
301301
{http.MethodGet, "/{dashboard_id}/slot-viz", hs.PublicGetValidatorDashboardSlotViz, hs.InternalGetValidatorDashboardSlotViz},
302302
{http.MethodGet, "/{dashboard_id}/summary", hs.PublicGetValidatorDashboardSummary, hs.InternalGetValidatorDashboardSummary},
303303
{http.MethodGet, "/{dashboard_id}/summary/validators", hs.PublicGetValidatorDashboardSummaryValidators, hs.InternalGetValidatorDashboardSummaryValidators},
304-
{http.MethodGet, "/{dashboard_id}/groups/{group_id}/summary", hs.PublicGetValidatorDashboardGroupSummary, hs.InternalGetValidatorDashboardGroupSummary},
304+
{http.MethodGet, "/{dashboard_id}/groups/{group_id}/summary", handlers.Handle(http.StatusOK, hs.GetValidatorDashboardGroupSummary), handlers.Handle(http.StatusOK, hs.GetValidatorDashboardGroupSummary)},
305305
{http.MethodGet, "/{dashboard_id}/summary-chart", hs.PublicGetValidatorDashboardSummaryChart, hs.InternalGetValidatorDashboardSummaryChart},
306306
{http.MethodGet, "/{dashboard_id}/rewards", hs.PublicGetValidatorDashboardRewards, hs.InternalGetValidatorDashboardRewards},
307307
{http.MethodGet, "/{dashboard_id}/groups/{group_id}/rewards/{epoch}", hs.PublicGetValidatorDashboardGroupRewards, hs.InternalGetValidatorDashboardGroupRewards},

0 commit comments

Comments
 (0)