Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

(BEDS-94) dashboard notifications: accept multiple chain ids #880

Merged
merged 2 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/pkg/api/data_access/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,7 +448,7 @@ func (d *DummyService) GetValidatorDashboardPublicIdCount(ctx context.Context, d
func (d *DummyService) GetNotificationOverview(ctx context.Context, userId uint64) (*t.NotificationOverviewData, error) {
return getDummyStruct[t.NotificationOverviewData]()
}
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) {
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) {
return getDummyWithPaging[t.NotificationDashboardsTableRow]()
}

Expand Down
6 changes: 3 additions & 3 deletions backend/pkg/api/data_access/notifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
type NotificationsRepository interface {
GetNotificationOverview(ctx context.Context, userId uint64) (*t.NotificationOverviewData, error)

GetDashboardNotifications(ctx context.Context, userId uint64, chainId uint64, cursor string, colSort t.Sort[enums.NotificationDashboardsColumn], search string, limit uint64) ([]t.NotificationDashboardsTableRow, *t.Paging, error)
GetDashboardNotifications(ctx context.Context, userId uint64, chainIds []uint64, cursor string, colSort t.Sort[enums.NotificationDashboardsColumn], search string, limit uint64) ([]t.NotificationDashboardsTableRow, *t.Paging, error)
// depending on how notifications are implemented, we may need to use something other than `notificationId` for identifying the notification
GetValidatorDashboardNotificationDetails(ctx context.Context, dashboardId t.VDBIdPrimary, groupId uint64, epoch uint64) (*t.NotificationValidatorDashboardDetail, error)
GetAccountDashboardNotificationDetails(ctx context.Context, dashboardId uint64, groupId uint64, epoch uint64) (*t.NotificationAccountDashboardDetail, error)
Expand All @@ -33,8 +33,8 @@ type NotificationsRepository interface {
func (d *DataAccessService) GetNotificationOverview(ctx context.Context, userId uint64) (*t.NotificationOverviewData, error) {
return d.dummy.GetNotificationOverview(ctx, userId)
}
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) {
return d.dummy.GetDashboardNotifications(ctx, userId, chainId, cursor, colSort, search, limit)
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) {
return d.dummy.GetDashboardNotifications(ctx, userId, chainIds, cursor, colSort, search, limit)
}

func (d *DataAccessService) GetValidatorDashboardNotificationDetails(ctx context.Context, dashboardId t.VDBIdPrimary, groupId uint64, epoch uint64) (*t.NotificationValidatorDashboardDetail, error) {
Expand Down
16 changes: 8 additions & 8 deletions backend/pkg/api/enums/notifications_enums.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ var _ EnumFactory[NotificationDashboardsColumn] = NotificationDashboardsColumn(0
const (
NotificationDashboardChainId NotificationDashboardsColumn = iota
NotificationDashboardTimestamp
NotificationDashboardDashboardId // sort by name
NotificationDashboardDashboardName // sort by name
)

func (c NotificationDashboardsColumn) Int() int {
Expand All @@ -23,8 +23,8 @@ func (NotificationDashboardsColumn) NewFromString(s string) NotificationDashboar
return NotificationDashboardChainId
case "timestamp":
return NotificationDashboardTimestamp
case "dashboard_id":
return NotificationDashboardDashboardId
case "dashboard_name", "dashboard_id": // accepting id for frontend
return NotificationDashboardDashboardName
default:
return NotificationDashboardsColumn(-1)
}
Expand All @@ -37,7 +37,7 @@ var NotificationsDashboardsColumns = struct {
}{
NotificationDashboardChainId,
NotificationDashboardTimestamp,
NotificationDashboardDashboardId,
NotificationDashboardDashboardName,
}

// ------------------------------------------------------------
Expand Down Expand Up @@ -203,7 +203,7 @@ type NotificationSettingsDashboardColumn int
var _ EnumFactory[NotificationSettingsDashboardColumn] = NotificationSettingsDashboardColumn(0)

const (
NotificationSettingsDashboardDashboardId NotificationSettingsDashboardColumn = iota
NotificationSettingsDashboardDashboardName NotificationSettingsDashboardColumn = iota
NotificationSettingsDashboardGroupName
)

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

func (NotificationSettingsDashboardColumn) NewFromString(s string) NotificationSettingsDashboardColumn {
switch s {
case "dashboard_id":
return NotificationSettingsDashboardDashboardId
case "dashboard_name", "dashboard_id":
return NotificationSettingsDashboardDashboardName
case "group_name":
return NotificationSettingsDashboardGroupName
default:
Expand All @@ -226,6 +226,6 @@ var NotificationSettingsDashboardColumns = struct {
DashboardId NotificationSettingsDashboardColumn
GroupName NotificationSettingsDashboardColumn
}{
NotificationSettingsDashboardDashboardId,
NotificationSettingsDashboardDashboardName,
NotificationSettingsDashboardGroupName,
}
8 changes: 8 additions & 0 deletions backend/pkg/api/handlers/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,14 @@ func (v *validationError) checkNetworkParameter(param string) uint64 {
return v.checkNetwork(intOrString{strValue: &param})
}

func (v *validationError) checkNetworksParameter(param string) []uint64 {
var chainIds []uint64
for _, network := range splitParameters(param, ',') {
chainIds = append(chainIds, v.checkNetworkParameter(network))
}
return chainIds
}

// isValidNetwork checks if the given network is a valid network.
// It returns the chain id of the network and true if it is valid, otherwise 0 and false.
func isValidNetwork(network intOrString) (uint64, bool) {
Expand Down
16 changes: 4 additions & 12 deletions backend/pkg/api/handlers/public.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
// @description - Setting the URL query parameter in the following format: `api_key={your_api_key}`.\
// @description Example: `https://beaconcha.in/api/v2/example?field=value&api_key={your_api_key}`

// @host beaconcha.in
// @BasePath /api/v2

// @securitydefinitions.apikey ApiKeyInHeader
Expand Down Expand Up @@ -1901,7 +1900,7 @@ func (h *HandlerService) PublicGetUserNotifications(w http.ResponseWriter, r *ht
// @Security ApiKeyInHeader || ApiKeyInQuery
// @Tags Notifications
// @Produce json
// @Param network query string false "If set, results will be filtered to only include networks given. Provide a comma separated list."
// @Param networks query string false "If set, results will be filtered to only include networks given. Provide a comma separated list."
// @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."
// @Param limit query string false "The maximum number of results that may be returned."
// @Param sort query string false "The field you want to sort by. Append with `:desc` for descending order." " Enums(chain_id, timestamp, dashboard_id)
Expand All @@ -1919,12 +1918,12 @@ func (h *HandlerService) PublicGetUserNotificationDashboards(w http.ResponseWrit
q := r.URL.Query()
pagingParams := v.checkPagingParams(q)
sort := checkSort[enums.NotificationDashboardsColumn](&v, q.Get("sort"))
chainId := v.checkNetworkParameter(q.Get("network"))
chainIds := v.checkNetworksParameter(q.Get("networks"))
if v.hasErrors() {
handleErr(w, r, v)
return
}
data, paging, err := h.dai.GetDashboardNotifications(r.Context(), userId, chainId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
data, paging, err := h.dai.GetDashboardNotifications(r.Context(), userId, chainIds, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
if err != nil {
handleErr(w, r, err)
return
Expand Down Expand Up @@ -2467,14 +2466,7 @@ func (h *HandlerService) PublicPutUserNotificationSettingsAccountDashboard(w htt
handleErr(w, r, err)
return
}
chainIdMap := v.checkNetworkSlice(req.SubscribedChainIds)
// convert to uint64[] slice
chainIds := make([]uint64, len(chainIdMap))
i := 0
for k := range chainIdMap {
chainIds[i] = k
i++
}
chainIds := v.checkNetworkSlice(req.SubscribedChainIds)
checkMinMax(&v, req.ERC20TokenTransfersValueThreshold, 0, math.MaxFloat64, "group_offline_threshold")
vars := mux.Vars(r)
dashboardId := v.checkPrimaryDashboardId(vars["dashboard_id"])
Expand Down
18 changes: 10 additions & 8 deletions backend/pkg/api/handlers/search_handlers.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@ import (
"encoding/hex"
"errors"
"fmt"
"maps"
"net/http"
"regexp"
"slices"
"strconv"
"strings"

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

// iterate over all combinations of search types and networks
for searchType := range searchTypeSet {
for _, searchType := range searchTypeSet {
// check if input matches the regex for the search type
if !searchTypeToRegex[searchType].MatchString(req.Input) {
continue
}
for chainId := range chainIdSet {
for _, chainId := range chainIdSet {
chainId := chainId
searchType := searchType
g.Go(func() error {
Expand Down Expand Up @@ -326,14 +328,14 @@ func (h *HandlerService) handleSearchValidatorsByGraffiti(ctx context.Context, i
// Input Validation

// if the passed slice is empty, return a set with all chain IDs; otherwise check if the passed networks are valid
func (v *validationError) checkNetworkSlice(networks []intOrString) map[uint64]struct{} {
func (v *validationError) checkNetworkSlice(networks []intOrString) []uint64 {
networkSet := map[uint64]struct{}{}
// if the list is empty, query all networks
if len(networks) == 0 {
for _, n := range allNetworks {
networkSet[n.ChainId] = struct{}{}
}
return networkSet
return slices.Collect(maps.Keys(networkSet))
}
// list not empty, check if networks are valid
for _, network := range networks {
Expand All @@ -344,18 +346,18 @@ func (v *validationError) checkNetworkSlice(networks []intOrString) map[uint64]s
}
networkSet[chainId] = struct{}{}
}
return networkSet
return slices.Collect(maps.Keys(networkSet))
}

// if the passed slice is empty, return a set with all search types; otherwise check if the passed types are valid
func (v *validationError) checkSearchTypes(types []searchTypeKey) map[searchTypeKey]struct{} {
func (v *validationError) checkSearchTypes(types []searchTypeKey) []searchTypeKey {
typeSet := map[searchTypeKey]struct{}{}
// if the list is empty, query all types
if len(types) == 0 {
for t := range searchTypeToRegex {
typeSet[t] = struct{}{}
}
return typeSet
return slices.Collect(maps.Keys(typeSet))
}
// list not empty, check if types are valid
for _, t := range types {
Expand All @@ -365,5 +367,5 @@ func (v *validationError) checkSearchTypes(types []searchTypeKey) map[searchType
}
typeSet[t] = struct{}{}
}
return typeSet
return slices.Collect(maps.Keys(typeSet))
}
Loading