Skip to content

Commit

Permalink
Merge pull request #511 from gobitfly/BIDS-3166/api-archived-dashboar…
Browse files Browse the repository at this point in the history
…ds-v2

(BIDS-3166) API: Indicate archived dashboards
  • Loading branch information
remoterami authored Aug 2, 2024
2 parents 9e18c47 + b0ac2c0 commit beeabb6
Show file tree
Hide file tree
Showing 12 changed files with 150 additions and 20 deletions.
17 changes: 16 additions & 1 deletion backend/pkg/api/data_access/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,15 @@ func (d *DummyService) GetValidatorDashboardInfoByPublicId(ctx context.Context,
return &r, err
}

func (d *DummyService) GetValidatorDashboard(ctx context.Context, dashboardId t.VDBId) (*t.ValidatorDashboard, error) {
r := t.ValidatorDashboard{}
// return semi-valid data to not break staging
//nolint:errcheck
commonFakeData(&r)
r.IsArchived = false
return &r, nil
}

func (d *DummyService) GetValidatorDashboardName(ctx context.Context, dashboardId t.VDBIdPrimary) (string, error) {
r := ""
err := commonFakeData(&r)
Expand Down Expand Up @@ -207,6 +216,12 @@ func (d *DummyService) RemoveValidatorDashboard(ctx context.Context, dashboardId
return nil
}

func (d *DummyService) UpdateValidatorDashboardArchiving(ctx context.Context, dashboardId t.VDBIdPrimary, archived bool) (*t.VDBPostArchivingReturnData, error) {
r := t.VDBPostArchivingReturnData{}
err := commonFakeData(&r)
return &r, err
}

func (d *DummyService) UpdateValidatorDashboardName(ctx context.Context, dashboardId t.VDBIdPrimary, name string) (*t.VDBPostReturnData, error) {
r := t.VDBPostReturnData{}
err := commonFakeData(&r)
Expand Down Expand Up @@ -523,7 +538,7 @@ func (d *DummyService) GetSearchValidatorsByGraffiti(ctx context.Context, chainI
return &r, err
}

func (d *DummyService) GetUserValidatorDashboardCount(ctx context.Context, userId uint64) (uint64, error) {
func (d *DummyService) GetUserValidatorDashboardCount(ctx context.Context, userId uint64, active bool) (uint64, error) {
r := uint64(0)
err := commonFakeData(&r)
return r, err
Expand Down
7 changes: 5 additions & 2 deletions backend/pkg/api/data_access/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ type UserRepository interface {
GetUserIdByConfirmationHash(hash string) (uint64, error)
GetUserInfo(ctx context.Context, id uint64) (*t.UserInfo, error)
GetUserDashboards(ctx context.Context, userId uint64) (*t.UserDashboardsData, error)
GetUserValidatorDashboardCount(ctx context.Context, userId uint64) (uint64, error)
GetUserValidatorDashboardCount(ctx context.Context, userId uint64, active bool) (uint64, error)
}

func (d *DataAccessService) GetUserByEmail(ctx context.Context, email string) (uint64, error) {
Expand Down Expand Up @@ -539,6 +539,7 @@ func (d *DataAccessService) GetFreeTierPerks(ctx context.Context) (*t.PremiumPer
}

func (d *DataAccessService) GetUserDashboards(ctx context.Context, userId uint64) (*t.UserDashboardsData, error) {
// TODO @DATA-ACCESS Adjust to api changes: return archival related fields
result := &t.UserDashboardsData{}

dbReturn := []struct {
Expand Down Expand Up @@ -603,7 +604,9 @@ func (d *DataAccessService) GetUserDashboards(ctx context.Context, userId uint64
return result, nil
}

func (d *DataAccessService) GetUserValidatorDashboardCount(ctx context.Context, userId uint64) (uint64, error) {
// return number of active / archived dashboards
func (d *DataAccessService) GetUserValidatorDashboardCount(ctx context.Context, userId uint64, active bool) (uint64, error) {
// @DATA-ACCESS return number of dashboards depending on archival status (see comment above)
var count uint64
err := d.alloyReader.GetContext(ctx, &count, `
SELECT COUNT(*) FROM users_val_dashboards
Expand Down
3 changes: 3 additions & 0 deletions backend/pkg/api/data_access/vdb_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,13 @@ import (
type ValidatorDashboardRepository interface {
GetValidatorDashboardInfo(ctx context.Context, dashboardId t.VDBIdPrimary) (*t.DashboardInfo, error)
GetValidatorDashboardInfoByPublicId(ctx context.Context, publicDashboardId t.VDBIdPublic) (*t.DashboardInfo, error)
GetValidatorDashboard(ctx context.Context, dashboardId t.VDBId) (*t.ValidatorDashboard, error)
GetValidatorDashboardName(ctx context.Context, dashboardId t.VDBIdPrimary) (string, error)
CreateValidatorDashboard(ctx context.Context, userId uint64, name string, network uint64) (*t.VDBPostReturnData, error)
RemoveValidatorDashboard(ctx context.Context, dashboardId t.VDBIdPrimary) error

UpdateValidatorDashboardArchiving(ctx context.Context, dashboardId t.VDBIdPrimary, archived bool) (*t.VDBPostArchivingReturnData, error)

UpdateValidatorDashboardName(ctx context.Context, dashboardId t.VDBIdPrimary, name string) (*t.VDBPostReturnData, error)

GetValidatorDashboardOverview(ctx context.Context, dashboardId t.VDBId, protocolModes t.VDBProtocolModes) (*t.VDBOverviewData, error)
Expand Down
10 changes: 10 additions & 0 deletions backend/pkg/api/data_access/vdb_management.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ func (d *DataAccessService) GetValidatorDashboardInfoByPublicId(ctx context.Cont
return result, err
}

func (d *DataAccessService) GetValidatorDashboard(ctx context.Context, dashboardId t.VDBId) (*t.ValidatorDashboard, error) {
// TODO @DATA-ACCESS
return d.dummy.GetValidatorDashboard(ctx, dashboardId)
}

func (d *DataAccessService) GetValidatorDashboardName(ctx context.Context, dashboardId t.VDBIdPrimary) (string, error) {
var name string
err := d.alloyReader.GetContext(ctx, &name, `
Expand Down Expand Up @@ -181,6 +186,11 @@ func (d *DataAccessService) RemoveValidatorDashboard(ctx context.Context, dashbo
return nil
}

func (d *DataAccessService) UpdateValidatorDashboardArchiving(ctx context.Context, dashboardId t.VDBIdPrimary, archived bool) (*t.VDBPostArchivingReturnData, error) {
// TODO @DATA-ACCESS
return d.dummy.UpdateValidatorDashboardArchiving(ctx, dashboardId, archived)
}

func (d *DataAccessService) UpdateValidatorDashboardName(ctx context.Context, dashboardId t.VDBIdPrimary, name string) (*t.VDBPostReturnData, error) {
result := &t.VDBPostReturnData{}

Expand Down
27 changes: 15 additions & 12 deletions backend/pkg/api/handlers/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,17 +69,18 @@ var (
)

const (
maxNameLength = 50
maxValidatorsInList = 20
maxQueryLimit uint64 = 100
defaultReturnLimit uint64 = 10
sortOrderAscending = "asc"
sortOrderDescending = "desc"
defaultSortOrder = sortOrderAscending
ethereum = "ethereum"
gnosis = "gnosis"
allowEmpty = true
forbidEmpty = false
maxNameLength = 50
maxValidatorsInList = 20
maxQueryLimit uint64 = 100
defaultReturnLimit uint64 = 10
sortOrderAscending = "asc"
sortOrderDescending = "desc"
defaultSortOrder = sortOrderAscending
ethereum = "ethereum"
gnosis = "gnosis"
allowEmpty = true
forbidEmpty = false
maxArchivedDashboardsCount = 10
)

var (
Expand Down Expand Up @@ -318,7 +319,8 @@ func (h *HandlerService) getDashboardId(ctx context.Context, dashboardIdParam in
}

// handleDashboardId is a helper function to both validate the dashboard id param and convert it to a VDBId.
// it should be used as the last validation step for all internal dashboard handlers.
// it should be used as the last validation step for all internal dashboard GET-handlers.
// Modifying handlers (POST, PUT, DELETE) should only accept primary dashboard ids and just use checkPrimaryDashboardId.
func (h *HandlerService) handleDashboardId(ctx context.Context, param string) (*types.VDBId, error) {
// validate dashboard id param
dashboardIdParam, err := parseDashboardId(param)
Expand All @@ -330,6 +332,7 @@ func (h *HandlerService) handleDashboardId(ctx context.Context, param string) (*
if err != nil {
return nil, err
}

return dashboardId, nil
}

Expand Down
77 changes: 75 additions & 2 deletions backend/pkg/api/handlers/internal.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,14 +340,13 @@ func (h *HandlerService) InternalPostValidatorDashboards(w http.ResponseWriter,
handleErr(w, err)
return
}
dashboardCount, err := h.dai.GetUserValidatorDashboardCount(r.Context(), userId)
dashboardCount, err := h.dai.GetUserValidatorDashboardCount(r.Context(), userId, true)
if err != nil {
handleErr(w, err)
return
}
if dashboardCount >= userInfo.PremiumPerks.ValidatorDasboards {
returnConflict(w, errors.New("maximum number of validator dashboards reached"))
return
}

data, err := h.dai.CreateValidatorDashboard(r.Context(), userId, name, chainId)
Expand Down Expand Up @@ -427,6 +426,80 @@ func (h *HandlerService) InternalDeleteValidatorDashboard(w http.ResponseWriter,
returnNoContent(w)
}

func (h *HandlerService) InternalPutValidatorDashboardArchiving(w http.ResponseWriter, r *http.Request) {
var v validationError
dashboardId := v.checkPrimaryDashboardId(mux.Vars(r)["dashboard_id"])
req := struct {
IsArchived bool `json:"is_archived"`
}{}
if err := v.checkBody(&req, r); err != nil {
handleErr(w, err)
return
}
if v.hasErrors() {
handleErr(w, v)
return
}

// check conditions for changing archival status
dashboardInfo, err := h.dai.GetValidatorDashboard(r.Context(), types.VDBId{Id: dashboardId})
if err != nil {
handleErr(w, err)
return
}
if dashboardInfo.IsArchived == req.IsArchived {
// nothing to do
returnOk(w, types.ApiDataResponse[types.VDBPostArchivingReturnData]{
Data: types.VDBPostArchivingReturnData{Id: uint64(dashboardId), IsArchived: req.IsArchived},
})
}

userId, ok := r.Context().Value(ctxUserIdKey).(uint64)
if !ok {
handleErr(w, errors.New("error getting user id from context"))
return
}
dashboardCount, err := h.dai.GetUserValidatorDashboardCount(r.Context(), userId, !req.IsArchived)
if err != nil {
handleErr(w, err)
return
}
if req.IsArchived {
if dashboardCount >= maxArchivedDashboardsCount {
returnConflict(w, errors.New("maximum number of archived validator dashboards reached"))
return
}
} else {
userInfo, err := h.dai.GetUserInfo(r.Context(), userId)
if err != nil {
handleErr(w, err)
return
}
if dashboardCount >= userInfo.PremiumPerks.ValidatorDasboards {
returnConflict(w, errors.New("maximum number of active validator dashboards reached"))
return
}
if dashboardInfo.GroupCount >= userInfo.PremiumPerks.ValidatorGroupsPerDashboard {
returnConflict(w, errors.New("maximum number of groups in dashboards reached"))
return
}
if dashboardInfo.ValidatorCount >= userInfo.PremiumPerks.ValidatorsPerDashboard {
returnConflict(w, errors.New("maximum number of validators in dashboards reached"))
return
}
}

data, err := h.dai.UpdateValidatorDashboardArchiving(r.Context(), dashboardId, req.IsArchived)
if err != nil {
handleErr(w, err)
return
}
response := types.ApiDataResponse[types.VDBPostArchivingReturnData]{
Data: *data,
}
returnOk(w, response)
}

func (h *HandlerService) InternalPutValidatorDashboardName(w http.ResponseWriter, r *http.Request) {
var v validationError
dashboardId := v.checkPrimaryDashboardId(mux.Vars(r)["dashboard_id"])
Expand Down
4 changes: 4 additions & 0 deletions backend/pkg/api/handlers/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,10 @@ func (h *HandlerService) PublicDeleteValidatorDashboard(w http.ResponseWriter, r
returnNoContent(w)
}

func (h *HandlerService) PublicPutValidatorDashboardArchiving(w http.ResponseWriter, r *http.Request) {
returnNoContent(w)
}

func (h *HandlerService) PublicPostValidatorDashboardGroups(w http.ResponseWriter, r *http.Request) {
returnCreated(w, nil)
}
Expand Down
1 change: 1 addition & 0 deletions backend/pkg/api/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ func addValidatorDashboardRoutes(hs *handlers.HandlerService, publicRouter, inte
endpoints := []endpoint{
{http.MethodGet, "/{dashboard_id}", hs.PublicGetValidatorDashboard, hs.InternalGetValidatorDashboard},
{http.MethodDelete, "/{dashboard_id}", hs.PublicDeleteValidatorDashboard, hs.InternalDeleteValidatorDashboard},
{http.MethodPut, "/{dashboard_id}/archiving", hs.PublicPutValidatorDashboardArchiving, hs.InternalPutValidatorDashboardArchiving},
{http.MethodPut, "/{dashboard_id}/name", nil, hs.InternalPutValidatorDashboardName},
{http.MethodPost, "/{dashboard_id}/groups", hs.PublicPostValidatorDashboardGroups, hs.InternalPostValidatorDashboardGroups},
{http.MethodPut, "/{dashboard_id}/groups/{group_id}", hs.PublicPutValidatorDashboardGroups, hs.InternalPutValidatorDashboardGroups},
Expand Down
11 changes: 8 additions & 3 deletions backend/pkg/api/types/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,15 @@ type AccountDashboard struct {
Name string `json:"name"`
}
type ValidatorDashboard struct {
Id uint64 `json:"id"`
Name string `json:"name"`
PublicIds []VDBPublicId `json:"public_ids,omitempty"`
Id uint64 `json:"id"`
Name string `json:"name"`
PublicIds []VDBPublicId `json:"public_ids,omitempty"`
IsArchived bool `json:"is_archived"`
ArchivedReason string `json:"archived_reason,omitempty" tstype:"'dashboard_limit' | 'validator_limit' | 'group_limit'"`
ValidatorCount uint64 `json:"validator_count"`
GroupCount uint64 `json:"group_count"`
}

type UserDashboardsData struct {
ValidatorDashboards []ValidatorDashboard `json:"validator_dashboards"`
AccountDashboards []AccountDashboard `json:"account_dashboards"`
Expand Down
5 changes: 5 additions & 0 deletions backend/pkg/api/types/validator_dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ type VDBOverviewData struct {

type InternalGetValidatorDashboardResponse ApiDataResponse[VDBOverviewData]

type VDBPostArchivingReturnData struct {
Id uint64 `json:"id"`
IsArchived bool `json:"is_archived"`
}

// ------------------------------------------------------------
// Summary Tab

Expand Down
4 changes: 4 additions & 0 deletions frontend/types/api/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ export interface ValidatorDashboard {
id: number /* uint64 */;
name: string;
public_ids?: VDBPublicId[];
is_archived: boolean;
archived_reason?: 'dashboard_limit' | 'validator_limit' | 'group_limit';
validator_count: number /* uint64 */;
group_count: number /* uint64 */;
}
export interface UserDashboardsData {
validator_dashboards: ValidatorDashboard[];
Expand Down
4 changes: 4 additions & 0 deletions frontend/types/api/validator_dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ export interface VDBOverviewData {
chart_history_seconds: ChartHistorySeconds;
}
export type InternalGetValidatorDashboardResponse = ApiDataResponse<VDBOverviewData>;
export interface VDBPostArchivingReturnData {
id: number /* uint64 */;
is_archived: boolean;
}
export interface VDBSummaryStatus {
next_sync_count: number /* uint64 */;
current_sync_count: number /* uint64 */;
Expand Down

0 comments on commit beeabb6

Please sign in to comment.