Skip to content

Commit 4e76b22

Browse files
(BEDS-94) dashboard notifications: accept multiple chain ids (#880)
Co-authored-by: remoterami <142154971+remoterami@users.noreply.github.com>
1 parent ac5358a commit 4e76b22

File tree

6 files changed

+34
-32
lines changed

6 files changed

+34
-32
lines changed

backend/pkg/api/data_access/dummy.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -448,7 +448,7 @@ func (d *DummyService) GetValidatorDashboardPublicIdCount(ctx context.Context, d
448448
func (d *DummyService) GetNotificationOverview(ctx context.Context, userId uint64) (*t.NotificationOverviewData, error) {
449449
return getDummyStruct[t.NotificationOverviewData]()
450450
}
451-
func (d *DummyService) GetDashboardNotifications(ctx context.Context, userId uint64, chainId uint64, cursor string, colSort t.Sort[enums.NotificationDashboardsColumn], search string, limit uint64) ([]t.NotificationDashboardsTableRow, *t.Paging, error) {
451+
func (d *DummyService) GetDashboardNotifications(ctx context.Context, userId uint64, chainIds []uint64, cursor string, colSort t.Sort[enums.NotificationDashboardsColumn], search string, limit uint64) ([]t.NotificationDashboardsTableRow, *t.Paging, error) {
452452
return getDummyWithPaging[t.NotificationDashboardsTableRow]()
453453
}
454454

backend/pkg/api/data_access/notifications.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import (
1010
type NotificationsRepository interface {
1111
GetNotificationOverview(ctx context.Context, userId uint64) (*t.NotificationOverviewData, error)
1212

13-
GetDashboardNotifications(ctx context.Context, userId uint64, chainId uint64, cursor string, colSort t.Sort[enums.NotificationDashboardsColumn], search string, limit uint64) ([]t.NotificationDashboardsTableRow, *t.Paging, error)
13+
GetDashboardNotifications(ctx context.Context, userId uint64, chainIds []uint64, cursor string, colSort t.Sort[enums.NotificationDashboardsColumn], search string, limit uint64) ([]t.NotificationDashboardsTableRow, *t.Paging, error)
1414
// depending on how notifications are implemented, we may need to use something other than `notificationId` for identifying the notification
1515
GetValidatorDashboardNotificationDetails(ctx context.Context, dashboardId t.VDBIdPrimary, groupId uint64, epoch uint64) (*t.NotificationValidatorDashboardDetail, error)
1616
GetAccountDashboardNotificationDetails(ctx context.Context, dashboardId uint64, groupId uint64, epoch uint64) (*t.NotificationAccountDashboardDetail, error)
@@ -33,8 +33,8 @@ type NotificationsRepository interface {
3333
func (d *DataAccessService) GetNotificationOverview(ctx context.Context, userId uint64) (*t.NotificationOverviewData, error) {
3434
return d.dummy.GetNotificationOverview(ctx, userId)
3535
}
36-
func (d *DataAccessService) GetDashboardNotifications(ctx context.Context, userId uint64, chainId uint64, cursor string, colSort t.Sort[enums.NotificationDashboardsColumn], search string, limit uint64) ([]t.NotificationDashboardsTableRow, *t.Paging, error) {
37-
return d.dummy.GetDashboardNotifications(ctx, userId, chainId, cursor, colSort, search, limit)
36+
func (d *DataAccessService) GetDashboardNotifications(ctx context.Context, userId uint64, chainIds []uint64, cursor string, colSort t.Sort[enums.NotificationDashboardsColumn], search string, limit uint64) ([]t.NotificationDashboardsTableRow, *t.Paging, error) {
37+
return d.dummy.GetDashboardNotifications(ctx, userId, chainIds, cursor, colSort, search, limit)
3838
}
3939

4040
func (d *DataAccessService) GetValidatorDashboardNotificationDetails(ctx context.Context, dashboardId t.VDBIdPrimary, groupId uint64, epoch uint64) (*t.NotificationValidatorDashboardDetail, error) {

backend/pkg/api/enums/notifications_enums.go

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ var _ EnumFactory[NotificationDashboardsColumn] = NotificationDashboardsColumn(0
1010
const (
1111
NotificationDashboardChainId NotificationDashboardsColumn = iota
1212
NotificationDashboardTimestamp
13-
NotificationDashboardDashboardId // sort by name
13+
NotificationDashboardDashboardName // sort by name
1414
)
1515

1616
func (c NotificationDashboardsColumn) Int() int {
@@ -23,8 +23,8 @@ func (NotificationDashboardsColumn) NewFromString(s string) NotificationDashboar
2323
return NotificationDashboardChainId
2424
case "timestamp":
2525
return NotificationDashboardTimestamp
26-
case "dashboard_id":
27-
return NotificationDashboardDashboardId
26+
case "dashboard_name", "dashboard_id": // accepting id for frontend
27+
return NotificationDashboardDashboardName
2828
default:
2929
return NotificationDashboardsColumn(-1)
3030
}
@@ -37,7 +37,7 @@ var NotificationsDashboardsColumns = struct {
3737
}{
3838
NotificationDashboardChainId,
3939
NotificationDashboardTimestamp,
40-
NotificationDashboardDashboardId,
40+
NotificationDashboardDashboardName,
4141
}
4242

4343
// ------------------------------------------------------------
@@ -203,7 +203,7 @@ type NotificationSettingsDashboardColumn int
203203
var _ EnumFactory[NotificationSettingsDashboardColumn] = NotificationSettingsDashboardColumn(0)
204204

205205
const (
206-
NotificationSettingsDashboardDashboardId NotificationSettingsDashboardColumn = iota
206+
NotificationSettingsDashboardDashboardName NotificationSettingsDashboardColumn = iota
207207
NotificationSettingsDashboardGroupName
208208
)
209209

@@ -213,8 +213,8 @@ func (c NotificationSettingsDashboardColumn) Int() int {
213213

214214
func (NotificationSettingsDashboardColumn) NewFromString(s string) NotificationSettingsDashboardColumn {
215215
switch s {
216-
case "dashboard_id":
217-
return NotificationSettingsDashboardDashboardId
216+
case "dashboard_name", "dashboard_id":
217+
return NotificationSettingsDashboardDashboardName
218218
case "group_name":
219219
return NotificationSettingsDashboardGroupName
220220
default:
@@ -226,6 +226,6 @@ var NotificationSettingsDashboardColumns = struct {
226226
DashboardId NotificationSettingsDashboardColumn
227227
GroupName NotificationSettingsDashboardColumn
228228
}{
229-
NotificationSettingsDashboardDashboardId,
229+
NotificationSettingsDashboardDashboardName,
230230
NotificationSettingsDashboardGroupName,
231231
}

backend/pkg/api/handlers/common.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -658,6 +658,14 @@ func (v *validationError) checkNetworkParameter(param string) uint64 {
658658
return v.checkNetwork(intOrString{strValue: &param})
659659
}
660660

661+
func (v *validationError) checkNetworksParameter(param string) []uint64 {
662+
var chainIds []uint64
663+
for _, network := range splitParameters(param, ',') {
664+
chainIds = append(chainIds, v.checkNetworkParameter(network))
665+
}
666+
return chainIds
667+
}
668+
661669
// isValidNetwork checks if the given network is a valid network.
662670
// It returns the chain id of the network and true if it is valid, otherwise 0 and false.
663671
func isValidNetwork(network intOrString) (uint64, bool) {

backend/pkg/api/handlers/public.go

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
// @description - Setting the URL query parameter in the following format: `api_key={your_api_key}`.\
2626
// @description Example: `https://beaconcha.in/api/v2/example?field=value&api_key={your_api_key}`
2727

28-
// @host beaconcha.in
2928
// @BasePath /api/v2
3029

3130
// @securitydefinitions.apikey ApiKeyInHeader
@@ -1901,7 +1900,7 @@ func (h *HandlerService) PublicGetUserNotifications(w http.ResponseWriter, r *ht
19011900
// @Security ApiKeyInHeader || ApiKeyInQuery
19021901
// @Tags Notifications
19031902
// @Produce json
1904-
// @Param network query string false "If set, results will be filtered to only include networks given. Provide a comma separated list."
1903+
// @Param networks query string false "If set, results will be filtered to only include networks given. Provide a comma separated list."
19051904
// @Param cursor query string false "Return data for the given cursor value. Pass the `paging.next_cursor`` value of the previous response to navigate to forward, or pass the `paging.prev_cursor`` value of the previous response to navigate to backward."
19061905
// @Param limit query string false "The maximum number of results that may be returned."
19071906
// @Param sort query string false "The field you want to sort by. Append with `:desc` for descending order." " Enums(chain_id, timestamp, dashboard_id)
@@ -1919,12 +1918,12 @@ func (h *HandlerService) PublicGetUserNotificationDashboards(w http.ResponseWrit
19191918
q := r.URL.Query()
19201919
pagingParams := v.checkPagingParams(q)
19211920
sort := checkSort[enums.NotificationDashboardsColumn](&v, q.Get("sort"))
1922-
chainId := v.checkNetworkParameter(q.Get("network"))
1921+
chainIds := v.checkNetworksParameter(q.Get("networks"))
19231922
if v.hasErrors() {
19241923
handleErr(w, r, v)
19251924
return
19261925
}
1927-
data, paging, err := h.dai.GetDashboardNotifications(r.Context(), userId, chainId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
1926+
data, paging, err := h.dai.GetDashboardNotifications(r.Context(), userId, chainIds, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
19281927
if err != nil {
19291928
handleErr(w, r, err)
19301929
return
@@ -2467,14 +2466,7 @@ func (h *HandlerService) PublicPutUserNotificationSettingsAccountDashboard(w htt
24672466
handleErr(w, r, err)
24682467
return
24692468
}
2470-
chainIdMap := v.checkNetworkSlice(req.SubscribedChainIds)
2471-
// convert to uint64[] slice
2472-
chainIds := make([]uint64, len(chainIdMap))
2473-
i := 0
2474-
for k := range chainIdMap {
2475-
chainIds[i] = k
2476-
i++
2477-
}
2469+
chainIds := v.checkNetworkSlice(req.SubscribedChainIds)
24782470
checkMinMax(&v, req.ERC20TokenTransfersValueThreshold, 0, math.MaxFloat64, "group_offline_threshold")
24792471
vars := mux.Vars(r)
24802472
dashboardId := v.checkPrimaryDashboardId(vars["dashboard_id"])

backend/pkg/api/handlers/search_handlers.go

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ import (
55
"encoding/hex"
66
"errors"
77
"fmt"
8+
"maps"
89
"net/http"
910
"regexp"
11+
"slices"
1012
"strconv"
1113
"strings"
1214

@@ -68,12 +70,12 @@ func (h *HandlerService) InternalPostSearch(w http.ResponseWriter, r *http.Reque
6870
searchResultChan := make(chan types.SearchResult)
6971

7072
// iterate over all combinations of search types and networks
71-
for searchType := range searchTypeSet {
73+
for _, searchType := range searchTypeSet {
7274
// check if input matches the regex for the search type
7375
if !searchTypeToRegex[searchType].MatchString(req.Input) {
7476
continue
7577
}
76-
for chainId := range chainIdSet {
78+
for _, chainId := range chainIdSet {
7779
chainId := chainId
7880
searchType := searchType
7981
g.Go(func() error {
@@ -326,14 +328,14 @@ func (h *HandlerService) handleSearchValidatorsByGraffiti(ctx context.Context, i
326328
// Input Validation
327329

328330
// if the passed slice is empty, return a set with all chain IDs; otherwise check if the passed networks are valid
329-
func (v *validationError) checkNetworkSlice(networks []intOrString) map[uint64]struct{} {
331+
func (v *validationError) checkNetworkSlice(networks []intOrString) []uint64 {
330332
networkSet := map[uint64]struct{}{}
331333
// if the list is empty, query all networks
332334
if len(networks) == 0 {
333335
for _, n := range allNetworks {
334336
networkSet[n.ChainId] = struct{}{}
335337
}
336-
return networkSet
338+
return slices.Collect(maps.Keys(networkSet))
337339
}
338340
// list not empty, check if networks are valid
339341
for _, network := range networks {
@@ -344,18 +346,18 @@ func (v *validationError) checkNetworkSlice(networks []intOrString) map[uint64]s
344346
}
345347
networkSet[chainId] = struct{}{}
346348
}
347-
return networkSet
349+
return slices.Collect(maps.Keys(networkSet))
348350
}
349351

350352
// if the passed slice is empty, return a set with all search types; otherwise check if the passed types are valid
351-
func (v *validationError) checkSearchTypes(types []searchTypeKey) map[searchTypeKey]struct{} {
353+
func (v *validationError) checkSearchTypes(types []searchTypeKey) []searchTypeKey {
352354
typeSet := map[searchTypeKey]struct{}{}
353355
// if the list is empty, query all types
354356
if len(types) == 0 {
355357
for t := range searchTypeToRegex {
356358
typeSet[t] = struct{}{}
357359
}
358-
return typeSet
360+
return slices.Collect(maps.Keys(typeSet))
359361
}
360362
// list not empty, check if types are valid
361363
for _, t := range types {
@@ -365,5 +367,5 @@ func (v *validationError) checkSearchTypes(types []searchTypeKey) map[searchType
365367
}
366368
typeSet[t] = struct{}{}
367369
}
368-
return typeSet
370+
return slices.Collect(maps.Keys(typeSet))
369371
}

0 commit comments

Comments
 (0)