diff --git a/backend/pkg/api/data_access/dummy.go b/backend/pkg/api/data_access/dummy.go
index 4590a106b..1dc80125d 100644
--- a/backend/pkg/api/data_access/dummy.go
+++ b/backend/pkg/api/data_access/dummy.go
@@ -452,11 +452,11 @@ func (d *DummyService) GetDashboardNotifications(ctx context.Context, userId uin
return getDummyWithPaging[t.NotificationDashboardsTableRow]()
}
-func (d *DummyService) GetValidatorDashboardNotificationDetails(ctx context.Context, notificationId string) (*t.NotificationValidatorDashboardDetail, error) {
+func (d *DummyService) GetValidatorDashboardNotificationDetails(ctx context.Context, dashboardId t.VDBIdPrimary, groupId uint64, epoch uint64) (*t.NotificationValidatorDashboardDetail, error) {
return getDummyStruct[t.NotificationValidatorDashboardDetail]()
}
-func (d *DummyService) GetAccountDashboardNotificationDetails(ctx context.Context, notificationId string) (*t.NotificationAccountDashboardDetail, error) {
+func (d *DummyService) GetAccountDashboardNotificationDetails(ctx context.Context, dashboardId uint64, groupId uint64, epoch uint64) (*t.NotificationAccountDashboardDetail, error) {
return getDummyStruct[t.NotificationAccountDashboardDetail]()
}
diff --git a/backend/pkg/api/data_access/notifications.go b/backend/pkg/api/data_access/notifications.go
index 4859b770c..94530d441 100644
--- a/backend/pkg/api/data_access/notifications.go
+++ b/backend/pkg/api/data_access/notifications.go
@@ -12,8 +12,8 @@ type NotificationsRepository interface {
GetDashboardNotifications(ctx context.Context, userId uint64, chainId 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, notificationId string) (*t.NotificationValidatorDashboardDetail, error)
- GetAccountDashboardNotificationDetails(ctx context.Context, notificationId string) (*t.NotificationAccountDashboardDetail, error)
+ 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)
GetMachineNotifications(ctx context.Context, userId uint64, cursor string, colSort t.Sort[enums.NotificationMachinesColumn], search string, limit uint64) ([]t.NotificationMachinesTableRow, *t.Paging, error)
GetClientNotifications(ctx context.Context, userId uint64, cursor string, colSort t.Sort[enums.NotificationClientsColumn], search string, limit uint64) ([]t.NotificationClientsTableRow, *t.Paging, error)
@@ -37,12 +37,12 @@ func (d *DataAccessService) GetDashboardNotifications(ctx context.Context, userI
return d.dummy.GetDashboardNotifications(ctx, userId, chainId, cursor, colSort, search, limit)
}
-func (d *DataAccessService) GetValidatorDashboardNotificationDetails(ctx context.Context, notificationId string) (*t.NotificationValidatorDashboardDetail, error) {
- return d.dummy.GetValidatorDashboardNotificationDetails(ctx, notificationId)
+func (d *DataAccessService) GetValidatorDashboardNotificationDetails(ctx context.Context, dashboardId t.VDBIdPrimary, groupId uint64, epoch uint64) (*t.NotificationValidatorDashboardDetail, error) {
+ return d.dummy.GetValidatorDashboardNotificationDetails(ctx, dashboardId, groupId, epoch)
}
-func (d *DataAccessService) GetAccountDashboardNotificationDetails(ctx context.Context, notificationId string) (*t.NotificationAccountDashboardDetail, error) {
- return d.dummy.GetAccountDashboardNotificationDetails(ctx, notificationId)
+func (d *DataAccessService) GetAccountDashboardNotificationDetails(ctx context.Context, dashboardId uint64, groupId uint64, epoch uint64) (*t.NotificationAccountDashboardDetail, error) {
+ return d.dummy.GetAccountDashboardNotificationDetails(ctx, dashboardId, groupId, epoch)
}
func (d *DataAccessService) GetMachineNotifications(ctx context.Context, userId uint64, cursor string, colSort t.Sort[enums.NotificationMachinesColumn], search string, limit uint64) ([]t.NotificationMachinesTableRow, *t.Paging, error) {
diff --git a/backend/pkg/api/enums/validator_dashboard_enums.go b/backend/pkg/api/enums/validator_dashboard_enums.go
index 928d5742c..fcbfec71b 100644
--- a/backend/pkg/api/enums/validator_dashboard_enums.go
+++ b/backend/pkg/api/enums/validator_dashboard_enums.go
@@ -437,7 +437,7 @@ func (c VDBRocketPoolMinipoolsColumn) Int() int {
func (VDBRocketPoolMinipoolsColumn) NewFromString(s string) VDBRocketPoolMinipoolsColumn {
switch s {
- case "group":
+ case "group_id":
return VDBRocketPoolMinipoolsGroup
default:
return VDBRocketPoolMinipoolsColumn(-1)
diff --git a/backend/pkg/api/handlers/internal.go b/backend/pkg/api/handlers/internal.go
index be1d96ecb..0a0f5c006 100644
--- a/backend/pkg/api/handlers/internal.go
+++ b/backend/pkg/api/handlers/internal.go
@@ -2,7 +2,6 @@ package handlers
import (
"errors"
- "math"
"net/http"
"github.com/gobitfly/beaconchain/pkg/api/enums"
@@ -526,459 +525,79 @@ func (h *HandlerService) InternalPostMobileBundleDeliveries(w http.ResponseWrite
// Notifications
func (h *HandlerService) InternalGetUserNotifications(w http.ResponseWriter, r *http.Request) {
- userId, err := GetUserIdByContext(r)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- data, err := h.dai.GetNotificationOverview(r.Context(), userId)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalGetUserNotificationsResponse{
- Data: *data,
- }
- returnOk(w, r, response)
+ h.PublicGetUserNotifications(w, r)
}
func (h *HandlerService) InternalGetUserNotificationDashboards(w http.ResponseWriter, r *http.Request) {
- var v validationError
- userId, err := GetUserIdByContext(r)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- q := r.URL.Query()
- pagingParams := v.checkPagingParams(q)
- sort := checkSort[enums.NotificationDashboardsColumn](&v, q.Get("sort"))
- chainId := v.checkNetworkParameter(q.Get("network"))
- 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)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalGetUserNotificationDashboardsResponse{
- Data: data,
- Paging: *paging,
- }
- returnOk(w, r, response)
+ h.PublicGetUserNotificationDashboards(w, r)
}
func (h *HandlerService) InternalGetUserNotificationsValidatorDashboard(w http.ResponseWriter, r *http.Request) {
- var v validationError
- notificationId := v.checkRegex(reNonEmpty, mux.Vars(r)["notification_id"], "notification_id")
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- data, err := h.dai.GetValidatorDashboardNotificationDetails(r.Context(), notificationId)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalGetUserNotificationsValidatorDashboardResponse{
- Data: *data,
- }
- returnOk(w, r, response)
+ h.PublicGetUserNotificationsValidatorDashboard(w, r)
}
func (h *HandlerService) InternalGetUserNotificationsAccountDashboard(w http.ResponseWriter, r *http.Request) {
- var v validationError
- notificationId := v.checkRegex(reNonEmpty, mux.Vars(r)["notification_id"], "notification_id")
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- data, err := h.dai.GetAccountDashboardNotificationDetails(r.Context(), notificationId)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalGetUserNotificationsAccountDashboardResponse{
- Data: *data,
- }
- returnOk(w, r, response)
+ h.PublicGetUserNotificationsAccountDashboard(w, r)
}
func (h *HandlerService) InternalGetUserNotificationMachines(w http.ResponseWriter, r *http.Request) {
- var v validationError
- userId, err := GetUserIdByContext(r)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- q := r.URL.Query()
- pagingParams := v.checkPagingParams(q)
- sort := checkSort[enums.NotificationMachinesColumn](&v, q.Get("sort"))
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- data, paging, err := h.dai.GetMachineNotifications(r.Context(), userId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalGetUserNotificationMachinesResponse{
- Data: data,
- Paging: *paging,
- }
- returnOk(w, r, response)
+ h.PublicGetUserNotificationMachines(w, r)
}
func (h *HandlerService) InternalGetUserNotificationClients(w http.ResponseWriter, r *http.Request) {
- var v validationError
- userId, err := GetUserIdByContext(r)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- q := r.URL.Query()
- pagingParams := v.checkPagingParams(q)
- sort := checkSort[enums.NotificationClientsColumn](&v, q.Get("sort"))
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- data, paging, err := h.dai.GetClientNotifications(r.Context(), userId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalGetUserNotificationClientsResponse{
- Data: data,
- Paging: *paging,
- }
- returnOk(w, r, response)
+ h.PublicGetUserNotificationClients(w, r)
}
func (h *HandlerService) InternalGetUserNotificationRocketPool(w http.ResponseWriter, r *http.Request) {
- var v validationError
- userId, err := GetUserIdByContext(r)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- q := r.URL.Query()
- pagingParams := v.checkPagingParams(q)
- sort := checkSort[enums.NotificationRocketPoolColumn](&v, q.Get("sort"))
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- data, paging, err := h.dai.GetRocketPoolNotifications(r.Context(), userId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalGetUserNotificationRocketPoolResponse{
- Data: data,
- Paging: *paging,
- }
- returnOk(w, r, response)
+ h.PublicGetUserNotificationRocketPool(w, r)
}
func (h *HandlerService) InternalGetUserNotificationNetworks(w http.ResponseWriter, r *http.Request) {
- var v validationError
- userId, err := GetUserIdByContext(r)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- q := r.URL.Query()
- pagingParams := v.checkPagingParams(q)
- sort := checkSort[enums.NotificationNetworksColumn](&v, q.Get("sort"))
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- data, paging, err := h.dai.GetNetworkNotifications(r.Context(), userId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalGetUserNotificationNetworksResponse{
- Data: data,
- Paging: *paging,
- }
- returnOk(w, r, response)
+ h.PublicGetUserNotificationNetworks(w, r)
}
func (h *HandlerService) InternalGetUserNotificationSettings(w http.ResponseWriter, r *http.Request) {
- userId, err := GetUserIdByContext(r)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- data, err := h.dai.GetNotificationSettings(r.Context(), userId)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalGetUserNotificationSettingsResponse{
- Data: *data,
- }
- returnOk(w, r, response)
+ h.PublicGetUserNotificationSettings(w, r)
}
func (h *HandlerService) InternalPutUserNotificationSettingsGeneral(w http.ResponseWriter, r *http.Request) {
- var v validationError
- userId, err := GetUserIdByContext(r)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- var req types.NotificationSettingsGeneral
- if err := v.checkBody(&req, r); err != nil {
- handleErr(w, r, err)
- return
- }
- checkMinMax(&v, req.MachineStorageUsageThreshold, 0, 1, "machine_storage_usage_threshold")
- checkMinMax(&v, req.MachineCpuUsageThreshold, 0, 1, "machine_cpu_usage_threshold")
- checkMinMax(&v, req.MachineMemoryUsageThreshold, 0, 1, "machine_memory_usage_threshold")
- checkMinMax(&v, req.RocketPoolMaxCollateralThreshold, 0, 1, "rocket_pool_max_collateral_threshold")
- checkMinMax(&v, req.RocketPoolMinCollateralThreshold, 0, 1, "rocket_pool_min_collateral_threshold")
- // TODO: check validity of clients
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- err = h.dai.UpdateNotificationSettingsGeneral(r.Context(), userId, req)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalPutUserNotificationSettingsGeneralResponse{
- Data: req,
- }
- returnOk(w, r, response)
+ h.PublicPutUserNotificationSettingsGeneral(w, r)
}
func (h *HandlerService) InternalPutUserNotificationSettingsNetworks(w http.ResponseWriter, r *http.Request) {
- var v validationError
- userId, err := GetUserIdByContext(r)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- var req types.NotificationSettingsNetwork
- if err := v.checkBody(&req, r); err != nil {
- handleErr(w, r, err)
- return
- }
- checkMinMax(&v, req.ParticipationRateThreshold, 0, 1, "participation_rate_threshold")
-
- chainId := v.checkNetworkParameter(mux.Vars(r)["network"])
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- err = h.dai.UpdateNotificationSettingsNetworks(r.Context(), userId, chainId, req)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalPutUserNotificationSettingsNetworksResponse{
- Data: types.NotificationNetwork{
- ChainId: chainId,
- Settings: req,
- },
- }
- returnOk(w, r, response)
+ h.PublicPutUserNotificationSettingsNetworks(w, r)
}
func (h *HandlerService) InternalPutUserNotificationSettingsPairedDevices(w http.ResponseWriter, r *http.Request) {
- var v validationError
- req := struct {
- Name string `json:"name,omitempty"`
- IsNotificationsEnabled bool `json:"is_notifications_enabled"`
- }{}
- if err := v.checkBody(&req, r); err != nil {
- handleErr(w, r, err)
- return
- }
- // TODO use a better way to validate the paired device id
- pairedDeviceId := v.checkRegex(reNonEmpty, mux.Vars(r)["paired_device_id"], "paired_device_id")
- name := v.checkNameNotEmpty(req.Name)
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- err := h.dai.UpdateNotificationSettingsPairedDevice(r.Context(), pairedDeviceId, name, req.IsNotificationsEnabled)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- // TODO timestamp
- response := types.InternalPutUserNotificationSettingsPairedDevicesResponse{
- Data: types.NotificationPairedDevice{
- Id: pairedDeviceId,
- Name: req.Name,
- IsNotificationsEnabled: req.IsNotificationsEnabled,
- },
- }
-
- returnOk(w, r, response)
+ h.PublicPutUserNotificationSettingsPairedDevices(w, r)
}
func (h *HandlerService) InternalDeleteUserNotificationSettingsPairedDevices(w http.ResponseWriter, r *http.Request) {
- var v validationError
- // TODO use a better way to validate the paired device id
- pairedDeviceId := v.checkRegex(reNonEmpty, mux.Vars(r)["paired_device_id"], "paired_device_id")
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- err := h.dai.DeleteNotificationSettingsPairedDevice(r.Context(), pairedDeviceId)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- returnNoContent(w, r)
+ h.PublicDeleteUserNotificationSettingsPairedDevices(w, r)
}
func (h *HandlerService) InternalGetUserNotificationSettingsDashboards(w http.ResponseWriter, r *http.Request) {
- var v validationError
- userId, err := GetUserIdByContext(r)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- q := r.URL.Query()
- pagingParams := v.checkPagingParams(q)
- sort := checkSort[enums.NotificationSettingsDashboardColumn](&v, q.Get("sort"))
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- data, paging, err := h.dai.GetNotificationSettingsDashboards(r.Context(), userId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalGetUserNotificationSettingsDashboardsResponse{
- Data: data,
- Paging: *paging,
- }
- returnOk(w, r, response)
+ h.PublicGetUserNotificationSettingsDashboards(w, r)
}
func (h *HandlerService) InternalPutUserNotificationSettingsValidatorDashboard(w http.ResponseWriter, r *http.Request) {
- var v validationError
- var req types.NotificationSettingsValidatorDashboard
- if err := v.checkBody(&req, r); err != nil {
- handleErr(w, r, err)
- return
- }
- checkMinMax(&v, req.GroupOfflineThreshold, 0, 1, "group_offline_threshold")
- vars := mux.Vars(r)
- dashboardId := v.checkPrimaryDashboardId(vars["dashboard_id"])
- groupId := v.checkExistingGroupId(vars["group_id"])
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- err := h.dai.UpdateNotificationSettingsValidatorDashboard(r.Context(), dashboardId, groupId, req)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalPutUserNotificationSettingsValidatorDashboardResponse{
- Data: req,
- }
- returnOk(w, r, response)
+ h.PublicPutUserNotificationSettingsValidatorDashboard(w, r)
}
func (h *HandlerService) InternalPutUserNotificationSettingsAccountDashboard(w http.ResponseWriter, r *http.Request) {
- var v validationError
- req := struct {
- WebhookUrl string `json:"webhook_url"`
- IsWebhookDiscordEnabled bool `json:"is_webhook_discord_enabled"`
- IsIgnoreSpamTransactionsEnabled bool `json:"is_ignore_spam_transactions_enabled"`
- SubscribedChainIds []intOrString `json:"subscribed_chain_ids"`
-
- IsIncomingTransactionsSubscribed bool `json:"is_incoming_transactions_subscribed"`
- IsOutgoingTransactionsSubscribed bool `json:"is_outgoing_transactions_subscribed"`
- IsERC20TokenTransfersSubscribed bool `json:"is_erc20_token_transfers_subscribed"`
- ERC20TokenTransfersValueThreshold float64 `json:"erc20_token_transfers_value_threshold"` // 0 does not disable, is_erc20_token_transfers_subscribed determines if it's enabled
- IsERC721TokenTransfersSubscribed bool `json:"is_erc721_token_transfers_subscribed"`
- IsERC1155TokenTransfersSubscribed bool `json:"is_erc1155_token_transfers_subscribed"`
- }{}
- if err := v.checkBody(&req, r); err != nil {
- 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++
- }
- checkMinMax(&v, req.ERC20TokenTransfersValueThreshold, 0, math.MaxFloat64, "group_offline_threshold")
- vars := mux.Vars(r)
- dashboardId := v.checkPrimaryDashboardId(vars["dashboard_id"])
- groupId := v.checkExistingGroupId(vars["group_id"])
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- settings := types.NotificationSettingsAccountDashboard{
- WebhookUrl: req.WebhookUrl,
- IsWebhookDiscordEnabled: req.IsWebhookDiscordEnabled,
- IsIgnoreSpamTransactionsEnabled: req.IsIgnoreSpamTransactionsEnabled,
- SubscribedChainIds: chainIds,
-
- IsIncomingTransactionsSubscribed: req.IsIncomingTransactionsSubscribed,
- IsOutgoingTransactionsSubscribed: req.IsOutgoingTransactionsSubscribed,
- IsERC20TokenTransfersSubscribed: req.IsERC20TokenTransfersSubscribed,
- ERC20TokenTransfersValueThreshold: req.ERC20TokenTransfersValueThreshold,
- IsERC721TokenTransfersSubscribed: req.IsERC721TokenTransfersSubscribed,
- IsERC1155TokenTransfersSubscribed: req.IsERC1155TokenTransfersSubscribed,
- }
- err := h.dai.UpdateNotificationSettingsAccountDashboard(r.Context(), dashboardId, groupId, settings)
- if err != nil {
- handleErr(w, r, err)
- return
- }
- response := types.InternalPutUserNotificationSettingsAccountDashboardResponse{
- Data: settings,
- }
- returnOk(w, r, response)
+ h.PublicPutUserNotificationSettingsAccountDashboard(w, r)
}
func (h *HandlerService) InternalPostUserNotificationsTestEmail(w http.ResponseWriter, r *http.Request) {
- // TODO
- returnOk(w, r, nil)
+ h.PublicPostUserNotificationsTestEmail(w, r)
}
func (h *HandlerService) InternalPostUserNotificationsTestPush(w http.ResponseWriter, r *http.Request) {
- // TODO
- returnOk(w, r, nil)
+ h.PublicPostUserNotificationsTestPush(w, r)
}
func (h *HandlerService) InternalPostUserNotificationsTestWebhook(w http.ResponseWriter, r *http.Request) {
- var v validationError
- req := struct {
- WebhookUrl string `json:"webhook_url"`
- IsDiscordWebhookEnabled bool `json:"is_discord_webhook_enabled,omitempty"`
- }{}
- if err := v.checkBody(&req, r); err != nil {
- handleErr(w, r, err)
- return
- }
- if v.hasErrors() {
- handleErr(w, r, v)
- return
- }
- // TODO
- returnOk(w, r, nil)
+ h.PublicPostUserNotificationsTestWebhook(w, r)
}
// --------------------------------------
diff --git a/backend/pkg/api/handlers/public.go b/backend/pkg/api/handlers/public.go
index 95df23ea7..a31ad6bb2 100644
--- a/backend/pkg/api/handlers/public.go
+++ b/backend/pkg/api/handlers/public.go
@@ -4,6 +4,7 @@ import (
"context"
"errors"
"fmt"
+ "math"
"net/http"
"reflect"
"time"
@@ -36,6 +37,8 @@ import (
// @in query
// @name api_key
+// @Validator Dashboard Management.n
+
func (h *HandlerService) PublicGetHealthz(w http.ResponseWriter, r *http.Request) {
var v validationError
showAll := v.checkBool(r.URL.Query().Get("show_all"), "show_all")
@@ -135,7 +138,7 @@ func (h *HandlerService) PublicPutAccountDashboardTransactionsSettings(w http.Re
//
// @Description Create a new validator dashboard. **Note**: New dashboards will automatically have a default group created.
// @Security ApiKeyInHeader || ApiKeyInQuery
-// @Tags Validator Dashboard
+// @Tags Validator Dashboard Management
// @Accept json
// @Produce json
// @Param request body handlers.PublicPostValidatorDashboards.request true "`name`: Specify the name of the dashboard.
`network`: Specify the network for the dashboard. Possible options are:
"
@@ -621,7 +624,6 @@ func (h *HandlerService) PublicPostValidatorDashboardValidators(w http.ResponseW
// @Produce json
// @Param dashboard_id path string true "The ID of the dashboard."
// @Param group_id query string false "The ID of the group."
-// @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(index, public_key, balance, status, withdrawal_credentials)
// @Param search query string false "Search for Address, ENS."
@@ -662,8 +664,8 @@ func (h *HandlerService) PublicGetValidatorDashboardValidators(w http.ResponseWr
// @Tags Validator Dashboard Management
// @Accept json
// @Produce json
-// @Param dashboard_id path string true "The ID of the dashboard."
-// @Param request body handlers.PublicDeleteValidatorDashboardValidators.request true "`validators`: Provide an array of validator indices or public keys that should get removed from the dashboard."
+// @Param dashboard_id path string true "The ID of the dashboard."
+// @Param request body handlers.PublicDeleteValidatorDashboardValidators.request true "`validators`: Provide an array of validator indices or public keys that should get removed from the dashboard."
// @Success 204 "Validators removed successfully."
// @Failure 400 {object} types.ApiErrorResponse
// @Router /validator-dashboards/{dashboard_id}/validators/bulk-deletions [post]
@@ -857,7 +859,7 @@ func (h *HandlerService) PublicDeleteValidatorDashboardPublicId(w http.ResponseW
// @Param request body handlers.PublicPutValidatorDashboardArchiving.request true "request"
// @Success 200 {object} types.ApiDataResponse[types.VDBPostArchivingReturnData]
// @Failure 400 {object} types.ApiErrorResponse
-// @Conflict 409 {object} types.ApiErrorResponse "Conflict. The request could not be performed by the server because the authenticated user has already reached their subscription limit."
+// @Conflict 409 {object} types.ApiErrorResponse "Conflict. The request could not be performed by the server because the authenticated user has already reached their subscription limit."
// @Router /validator-dashboards/{dashboard_id}/archiving [put]
func (h *HandlerService) PublicPutValidatorDashboardArchiving(w http.ResponseWriter, r *http.Request) {
var v validationError
@@ -1821,7 +1823,7 @@ func (h *HandlerService) PublicGetValidatorDashboardNodeRocketPool(w http.Respon
// @Param node_address path string true "The address of the node."
// @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. Possible values are TODO."
+// @Param sort query string false "The field you want to sort by. Append with `:desc` for descending order." Enums(group_id)
// @Param search query string false "Search for Index, Node."
// @Success 200 {object} types.GetValidatorDashboardRocketPoolMinipoolsResponse
// @Failure 400 {object} types.ApiErrorResponse
@@ -1856,6 +1858,693 @@ func (h *HandlerService) PublicGetValidatorDashboardRocketPoolMinipools(w http.R
returnOk(w, r, response)
}
+// ----------------------------------------------
+// Notifications
+// ----------------------------------------------
+
+// PublicGetUserNotifications godoc
+//
+// @Description Get an overview of your recent notifications.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notifications
+// @Produce json
+// @Success 200 {object} types.InternalGetUserNotificationsResponse
+// @Router /users/me/notifications [get]
+func (h *HandlerService) PublicGetUserNotifications(w http.ResponseWriter, r *http.Request) {
+ userId, err := GetUserIdByContext(r)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ data, err := h.dai.GetNotificationOverview(r.Context(), userId)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalGetUserNotificationsResponse{
+ Data: *data,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicGetUserNotificationDashboards godoc
+//
+// @Description Get a list of triggered notifications related to your dashboards.
+// @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 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)
+// @Param search query string false "Search for Dashboard, Group"
+// @Success 200 {object} types.InternalGetUserNotificationDashboardsResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/dashboards [get]
+func (h *HandlerService) PublicGetUserNotificationDashboards(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ userId, err := GetUserIdByContext(r)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ q := r.URL.Query()
+ pagingParams := v.checkPagingParams(q)
+ sort := checkSort[enums.NotificationDashboardsColumn](&v, q.Get("sort"))
+ chainId := v.checkNetworkParameter(q.Get("network"))
+ 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)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalGetUserNotificationDashboardsResponse{
+ Data: data,
+ Paging: *paging,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicGetUserNotificationValidators godoc
+//
+// @Description Get a detailed view of a triggered notification related to a validator dashboard group at a specific epoch.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notifications
+// @Produce json
+// @Param dashboard_id path string true "The ID of the dashboard."
+// @Param group_id path string true "The ID of the group."
+// @Param epoch path string true "The epoch of the notification."
+// @Success 200 {object} types.InternalGetUserNotificationsValidatorDashboardResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/validator-dashboards/{dashboard_id}/groups/{group_id}/epochs/{epoch} [get]
+func (h *HandlerService) PublicGetUserNotificationsValidatorDashboard(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ vars := mux.Vars(r)
+ dashboardId := v.checkPrimaryDashboardId(vars["dashboard_id"])
+ groupId := v.checkExistingGroupId(vars["group_id"])
+ epoch := v.checkUint(vars["epoch"], "epoch")
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ data, err := h.dai.GetValidatorDashboardNotificationDetails(r.Context(), dashboardId, groupId, epoch)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalGetUserNotificationsValidatorDashboardResponse{
+ Data: *data,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicGetUserNotificationsAccountDashboard godoc
+//
+// @Description Get a detailed view of a triggered notification related to an account dashboard group at a specific epoch.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notifications
+// @Produce json
+// @Param dashboard_id path string true "The ID of the dashboard."
+// @Param group_id path string true "The ID of the group."
+// @Param epoch path string true "The epoch of the notification."
+// @Success 200 {object} types.InternalGetUserNotificationsAccountDashboardResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/account-dashboards/{dashboard_id}/groups/{group_id}/epochs/{epoch} [get]
+func (h *HandlerService) PublicGetUserNotificationsAccountDashboard(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ vars := mux.Vars(r)
+ dashboardId := v.checkUint(vars["dashboard_id"], "dashboard_id")
+ groupId := v.checkExistingGroupId(vars["group_id"])
+ epoch := v.checkUint(vars["epoch"], "epoch")
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ data, err := h.dai.GetAccountDashboardNotificationDetails(r.Context(), dashboardId, groupId, epoch)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalGetUserNotificationsAccountDashboardResponse{
+ Data: *data,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicGetUserNotificationMachines godoc
+//
+// @Description Get a list of triggered notifications related to your machines.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notifications
+// @Produce json
+// @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(machine_name, threshold, event_type, timestamp)
+// @Param search query string false "Search for Machine"
+// @Success 200 {object} types.InternalGetUserNotificationMachinesResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/machines [get]
+func (h *HandlerService) PublicGetUserNotificationMachines(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ userId, err := GetUserIdByContext(r)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ q := r.URL.Query()
+ pagingParams := v.checkPagingParams(q)
+ sort := checkSort[enums.NotificationMachinesColumn](&v, q.Get("sort"))
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ data, paging, err := h.dai.GetMachineNotifications(r.Context(), userId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalGetUserNotificationMachinesResponse{
+ Data: data,
+ Paging: *paging,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicGetUserNotificationClients godoc
+//
+// @Description Get a list of triggered notifications related to your clients.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notifications
+// @Produce json
+// @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(client_name, timestamp)
+// @Param search query string false "Search for Client"
+// @Success 200 {object} types.InternalGetUserNotificationClientsResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/clients [get]
+func (h *HandlerService) PublicGetUserNotificationClients(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ userId, err := GetUserIdByContext(r)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ q := r.URL.Query()
+ pagingParams := v.checkPagingParams(q)
+ sort := checkSort[enums.NotificationClientsColumn](&v, q.Get("sort"))
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ data, paging, err := h.dai.GetClientNotifications(r.Context(), userId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalGetUserNotificationClientsResponse{
+ Data: data,
+ Paging: *paging,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicGetUserNotificationRocketPool godoc
+//
+// @Description Get a list of triggered notifications related to Rocket Pool.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notifications
+// @Produce json
+// @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(timestamp, event_type, node_address)
+// @Param search query string false "Search for TODO"
+// @Success 200 {object} types.InternalGetUserNotificationRocketPoolResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/rocket-pool [get]
+func (h *HandlerService) PublicGetUserNotificationRocketPool(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ userId, err := GetUserIdByContext(r)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ q := r.URL.Query()
+ pagingParams := v.checkPagingParams(q)
+ sort := checkSort[enums.NotificationRocketPoolColumn](&v, q.Get("sort"))
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ data, paging, err := h.dai.GetRocketPoolNotifications(r.Context(), userId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalGetUserNotificationRocketPoolResponse{
+ Data: data,
+ Paging: *paging,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicGetUserNotificationNetworks godoc
+//
+// @Description Get a list of triggered notifications related to networks.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notifications
+// @Produce json
+// @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(timestamp, event_type)
+// @Param search query string false "Search for TODO"
+// @Success 200 {object} types.InternalGetUserNotificationNetworksResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/networks [get]
+func (h *HandlerService) PublicGetUserNotificationNetworks(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ userId, err := GetUserIdByContext(r)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ q := r.URL.Query()
+ pagingParams := v.checkPagingParams(q)
+ sort := checkSort[enums.NotificationNetworksColumn](&v, q.Get("sort"))
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ data, paging, err := h.dai.GetNetworkNotifications(r.Context(), userId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalGetUserNotificationNetworksResponse{
+ Data: data,
+ Paging: *paging,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicGetUserNotificationPairedDevices godoc
+//
+// @Description Get notification settings for the authenticated user. Excludes dashboard notification settings.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notification Settings
+// @Produce json
+// @Success 200 {object} types.InternalGetUserNotificationSettingsResponse
+// @Router /users/me/notifications/settings [get]
+func (h *HandlerService) PublicGetUserNotificationSettings(w http.ResponseWriter, r *http.Request) {
+ userId, err := GetUserIdByContext(r)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ data, err := h.dai.GetNotificationSettings(r.Context(), userId)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalGetUserNotificationSettingsResponse{
+ Data: *data,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicPutUserNotificationSettingsGeneral godoc
+//
+// @Description Update general notification settings for the authenticated user.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notification Settings
+// @Accept json
+// @Produce json
+// @Param request body types.NotificationSettingsGeneral true "Notification settings"
+// @Success 200 {object} types.InternalPutUserNotificationSettingsGeneralResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/settings/general [put]
+func (h *HandlerService) PublicPutUserNotificationSettingsGeneral(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ userId, err := GetUserIdByContext(r)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ var req types.NotificationSettingsGeneral
+ if err := v.checkBody(&req, r); err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ checkMinMax(&v, req.MachineStorageUsageThreshold, 0, 1, "machine_storage_usage_threshold")
+ checkMinMax(&v, req.MachineCpuUsageThreshold, 0, 1, "machine_cpu_usage_threshold")
+ checkMinMax(&v, req.MachineMemoryUsageThreshold, 0, 1, "machine_memory_usage_threshold")
+ checkMinMax(&v, req.RocketPoolMaxCollateralThreshold, 0, 1, "rocket_pool_max_collateral_threshold")
+ checkMinMax(&v, req.RocketPoolMinCollateralThreshold, 0, 1, "rocket_pool_min_collateral_threshold")
+ // TODO: check validity of clients
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ err = h.dai.UpdateNotificationSettingsGeneral(r.Context(), userId, req)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalPutUserNotificationSettingsGeneralResponse{
+ Data: req,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicPutUserNotificationSettingsNetworks godoc
+//
+// @Description Update network notification settings for the authenticated user.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notification Settings
+// @Accept json
+// @Produce json
+// @Param network path string true "The networks name or chain ID."
+// @Param request body types.NotificationSettingsNetwork true "Notification settings"
+// @Success 200 {object} types.InternalPutUserNotificationSettingsNetworksResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/settings/networks/{network} [put]
+func (h *HandlerService) PublicPutUserNotificationSettingsNetworks(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ userId, err := GetUserIdByContext(r)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ var req types.NotificationSettingsNetwork
+ if err := v.checkBody(&req, r); err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ checkMinMax(&v, req.ParticipationRateThreshold, 0, 1, "participation_rate_threshold")
+
+ chainId := v.checkNetworkParameter(mux.Vars(r)["network"])
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ err = h.dai.UpdateNotificationSettingsNetworks(r.Context(), userId, chainId, req)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalPutUserNotificationSettingsNetworksResponse{
+ Data: types.NotificationNetwork{
+ ChainId: chainId,
+ Settings: req,
+ },
+ }
+ returnOk(w, r, response)
+}
+
+// PublicPutUserNotificationSettingsPairedDevices godoc
+//
+// @Description Update paired device notification settings for the authenticated user.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notification Settings
+// @Accept json
+// @Produce json
+// @Param paired_device_id path string true "The paired device ID."
+// @Param request body handlers.PublicPutUserNotificationSettingsPairedDevices.request true "Notification settings"
+// @Success 200 {object} types.InternalPutUserNotificationSettingsPairedDevicesResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/settings/paired-devices/{paired_device_id} [put]
+func (h *HandlerService) PublicPutUserNotificationSettingsPairedDevices(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ type request struct {
+ Name string `json:"name,omitempty"`
+ IsNotificationsEnabled bool `json:"is_notifications_enabled"`
+ }
+ var req request
+ if err := v.checkBody(&req, r); err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ // TODO use a better way to validate the paired device id
+ pairedDeviceId := v.checkRegex(reNonEmpty, mux.Vars(r)["paired_device_id"], "paired_device_id")
+ name := v.checkNameNotEmpty(req.Name)
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ err := h.dai.UpdateNotificationSettingsPairedDevice(r.Context(), pairedDeviceId, name, req.IsNotificationsEnabled)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ // TODO timestamp
+ response := types.InternalPutUserNotificationSettingsPairedDevicesResponse{
+ Data: types.NotificationPairedDevice{
+ Id: pairedDeviceId,
+ Name: req.Name,
+ IsNotificationsEnabled: req.IsNotificationsEnabled,
+ },
+ }
+
+ returnOk(w, r, response)
+}
+
+// PublicDeleteUserNotificationSettingsPairedDevices godoc
+//
+// @Description Delete paired device notification settings for the authenticated user.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notification Settings
+// @Produce json
+// @Param paired_device_id path string true "The paired device ID."
+// @Success 204
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/settings/paired-devices/{paired_device_id} [delete]
+func (h *HandlerService) PublicDeleteUserNotificationSettingsPairedDevices(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ // TODO use a better way to validate the paired device id
+ pairedDeviceId := v.checkRegex(reNonEmpty, mux.Vars(r)["paired_device_id"], "paired_device_id")
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ err := h.dai.DeleteNotificationSettingsPairedDevice(r.Context(), pairedDeviceId)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ returnNoContent(w, r)
+}
+
+// PublicGetUserNotificationSettingsDashboards godoc
+//
+// @Description Get a list of notification settings for the dashboards of the authenticated user.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notification Settings
+// @Produce json
+// @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 (dashboard_id, group_name)
+// @Param search query string false "Search for Dashboard, Group"
+// @Success 200 {object} types.InternalGetUserNotificationSettingsDashboardsResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/settings/dashboards [get]
+func (h *HandlerService) PublicGetUserNotificationSettingsDashboards(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ userId, err := GetUserIdByContext(r)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ q := r.URL.Query()
+ pagingParams := v.checkPagingParams(q)
+ sort := checkSort[enums.NotificationSettingsDashboardColumn](&v, q.Get("sort"))
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ data, paging, err := h.dai.GetNotificationSettingsDashboards(r.Context(), userId, pagingParams.cursor, *sort, pagingParams.search, pagingParams.limit)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalGetUserNotificationSettingsDashboardsResponse{
+ Data: data,
+ Paging: *paging,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicPutUserNotificationSettingsValidatorDashboard godoc
+//
+// @Description Update the notification settings for a specific group of a validator dashboard for the authenticated user.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notification Settings
+// @Accept json
+// @Produce json
+// @Param dashboard_id path string true "The ID of the dashboard."
+// @Param group_id path string true "The ID of the group."
+// @Param request body types.NotificationSettingsValidatorDashboard true "Notification settings"
+// @Success 200 {object} types.InternalPutUserNotificationSettingsValidatorDashboardResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/settings/validator-dashboards/{dashboard_id}/groups/{group_id} [put]
+func (h *HandlerService) PublicPutUserNotificationSettingsValidatorDashboard(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ var req types.NotificationSettingsValidatorDashboard
+ if err := v.checkBody(&req, r); err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ checkMinMax(&v, req.GroupOfflineThreshold, 0, 1, "group_offline_threshold")
+ vars := mux.Vars(r)
+ dashboardId := v.checkPrimaryDashboardId(vars["dashboard_id"])
+ groupId := v.checkExistingGroupId(vars["group_id"])
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ err := h.dai.UpdateNotificationSettingsValidatorDashboard(r.Context(), dashboardId, groupId, req)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalPutUserNotificationSettingsValidatorDashboardResponse{
+ Data: req,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicPutUserNotificationSettingsAccountDashboard godoc
+//
+// @Description Update the notification settings for a specific group of an account dashboard for the authenticated user.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notification Settings
+// @Accept json
+// @Produce json
+// @Param dashboard_id path string true "The ID of the dashboard."
+// @Param group_id path string true "The ID of the group."
+// @Param request body handlers.PublicPutUserNotificationSettingsAccountDashboard.request true "Notification settings"
+// @Success 200 {object} types.InternalPutUserNotificationSettingsAccountDashboardResponse
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/settings/account-dashboards/{dashboard_id}/groups/{group_id} [put]
+func (h *HandlerService) PublicPutUserNotificationSettingsAccountDashboard(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ // uses a different struct due to `subscribed_chain_ids`, which is a slice of intOrString in the payload but a slice of uint64 in the response
+ type request struct {
+ WebhookUrl string `json:"webhook_url"`
+ IsWebhookDiscordEnabled bool `json:"is_webhook_discord_enabled"`
+ IsIgnoreSpamTransactionsEnabled bool `json:"is_ignore_spam_transactions_enabled"`
+ SubscribedChainIds []intOrString `json:"subscribed_chain_ids"`
+
+ IsIncomingTransactionsSubscribed bool `json:"is_incoming_transactions_subscribed"`
+ IsOutgoingTransactionsSubscribed bool `json:"is_outgoing_transactions_subscribed"`
+ IsERC20TokenTransfersSubscribed bool `json:"is_erc20_token_transfers_subscribed"`
+ ERC20TokenTransfersValueThreshold float64 `json:"erc20_token_transfers_value_threshold"` // 0 does not disable, is_erc20_token_transfers_subscribed determines if it's enabled
+ IsERC721TokenTransfersSubscribed bool `json:"is_erc721_token_transfers_subscribed"`
+ IsERC1155TokenTransfersSubscribed bool `json:"is_erc1155_token_transfers_subscribed"`
+ }
+ var req request
+ if err := v.checkBody(&req, r); err != nil {
+ 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++
+ }
+ checkMinMax(&v, req.ERC20TokenTransfersValueThreshold, 0, math.MaxFloat64, "group_offline_threshold")
+ vars := mux.Vars(r)
+ dashboardId := v.checkPrimaryDashboardId(vars["dashboard_id"])
+ groupId := v.checkExistingGroupId(vars["group_id"])
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ settings := types.NotificationSettingsAccountDashboard{
+ WebhookUrl: req.WebhookUrl,
+ IsWebhookDiscordEnabled: req.IsWebhookDiscordEnabled,
+ IsIgnoreSpamTransactionsEnabled: req.IsIgnoreSpamTransactionsEnabled,
+ SubscribedChainIds: chainIds,
+
+ IsIncomingTransactionsSubscribed: req.IsIncomingTransactionsSubscribed,
+ IsOutgoingTransactionsSubscribed: req.IsOutgoingTransactionsSubscribed,
+ IsERC20TokenTransfersSubscribed: req.IsERC20TokenTransfersSubscribed,
+ ERC20TokenTransfersValueThreshold: req.ERC20TokenTransfersValueThreshold,
+ IsERC721TokenTransfersSubscribed: req.IsERC721TokenTransfersSubscribed,
+ IsERC1155TokenTransfersSubscribed: req.IsERC1155TokenTransfersSubscribed,
+ }
+ err := h.dai.UpdateNotificationSettingsAccountDashboard(r.Context(), dashboardId, groupId, settings)
+ if err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ response := types.InternalPutUserNotificationSettingsAccountDashboardResponse{
+ Data: settings,
+ }
+ returnOk(w, r, response)
+}
+
+// PublicPostUserNotificationsTestEmail godoc
+//
+// @Description Send a test email notification to the authenticated user.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notification Settings
+// @Produce json
+// @Success 204
+// @Router /users/me/notifications/test-email [post]
+func (h *HandlerService) PublicPostUserNotificationsTestEmail(w http.ResponseWriter, r *http.Request) {
+ // TODO
+ returnNoContent(w, r)
+}
+
+// PublicPostUserNotificationsTestPush godoc
+//
+// @Description Send a test push notification to the authenticated user.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notification Settings
+// @Produce json
+// @Success 204
+// @Router /users/me/notifications/test-push [post]
+func (h *HandlerService) PublicPostUserNotificationsTestPush(w http.ResponseWriter, r *http.Request) {
+ // TODO
+ returnNoContent(w, r)
+}
+
+// PublicPostUserNotificationsTestWebhook godoc
+//
+// @Description Send a test webhook notification from the authenticated user to the given URL.
+// @Security ApiKeyInHeader || ApiKeyInQuery
+// @Tags Notification Settings
+// @Accept json
+// @Produce json
+// @Param request body handlers.PublicPostUserNotificationsTestWebhook.request true "Request"
+// @Success 204
+// @Failure 400 {object} types.ApiErrorResponse
+// @Router /users/me/notifications/test-webhook [post]
+func (h *HandlerService) PublicPostUserNotificationsTestWebhook(w http.ResponseWriter, r *http.Request) {
+ var v validationError
+ type request struct {
+ WebhookUrl string `json:"webhook_url"`
+ IsDiscordWebhookEnabled bool `json:"is_discord_webhook_enabled,omitempty"`
+ }
+ var req request
+ if err := v.checkBody(&req, r); err != nil {
+ handleErr(w, r, err)
+ return
+ }
+ if v.hasErrors() {
+ handleErr(w, r, v)
+ return
+ }
+ // TODO
+ returnNoContent(w, r)
+}
+
func (h *HandlerService) PublicGetNetworkValidators(w http.ResponseWriter, r *http.Request) {
returnOk(w, r, nil)
}
diff --git a/backend/pkg/api/router.go b/backend/pkg/api/router.go
index 5338b5ccd..3238257bd 100644
--- a/backend/pkg/api/router.go
+++ b/backend/pkg/api/router.go
@@ -317,35 +317,36 @@ func addNotificationRoutes(hs *handlers.HandlerService, publicRouter, internalRo
publicNotificationRouter.Use(hs.ManageViaApiCheckMiddleware)
}
endpoints := []endpoint{
- {http.MethodGet, "", nil, hs.InternalGetUserNotifications},
- {http.MethodGet, "/dashboards", nil, hs.InternalGetUserNotificationDashboards},
- {http.MethodGet, "/validator-dashboards/{notification_id}", nil, hs.InternalGetUserNotificationsValidatorDashboard},
- {http.MethodGet, "/account-dashboards/{notification_id}", nil, hs.InternalGetUserNotificationsAccountDashboard},
- {http.MethodGet, "/machines", nil, hs.InternalGetUserNotificationMachines},
- {http.MethodGet, "/clients", nil, hs.InternalGetUserNotificationClients},
- {http.MethodGet, "/rocket-pool", nil, hs.InternalGetUserNotificationRocketPool},
- {http.MethodGet, "/networks", nil, hs.InternalGetUserNotificationNetworks},
- {http.MethodGet, "/settings", nil, hs.InternalGetUserNotificationSettings},
- {http.MethodPut, "/settings/general", nil, hs.InternalPutUserNotificationSettingsGeneral},
- {http.MethodPut, "/settings/networks/{network}", nil, hs.InternalPutUserNotificationSettingsNetworks},
- {http.MethodPut, "/settings/paired-devices/{paired_device_id}", nil, hs.InternalPutUserNotificationSettingsPairedDevices},
- {http.MethodDelete, "/settings/paired-devices/{paired_device_id}", nil, hs.InternalDeleteUserNotificationSettingsPairedDevices},
- {http.MethodGet, "/settings/dashboards", nil, hs.InternalGetUserNotificationSettingsDashboards},
- {http.MethodPost, "/test-email", nil, hs.InternalPostUserNotificationsTestEmail},
- {http.MethodPost, "/test-push", nil, hs.InternalPostUserNotificationsTestPush},
- {http.MethodPost, "/test-webhook", nil, hs.InternalPostUserNotificationsTestWebhook},
+ {http.MethodGet, "", hs.PublicGetUserNotifications, hs.InternalGetUserNotifications},
+ {http.MethodGet, "/dashboards", hs.PublicGetUserNotificationDashboards, hs.InternalGetUserNotificationDashboards},
+ {http.MethodGet, "/machines", hs.PublicGetUserNotificationMachines, hs.InternalGetUserNotificationMachines},
+ {http.MethodGet, "/clients", hs.PublicGetUserNotificationClients, hs.InternalGetUserNotificationClients},
+ {http.MethodGet, "/rocket-pool", hs.PublicGetUserNotificationRocketPool, hs.InternalGetUserNotificationRocketPool},
+ {http.MethodGet, "/networks", hs.PublicGetUserNotificationNetworks, hs.InternalGetUserNotificationNetworks},
+ {http.MethodGet, "/settings", hs.PublicGetUserNotificationSettings, hs.InternalGetUserNotificationSettings},
+ {http.MethodPut, "/settings/general", hs.PublicPutUserNotificationSettingsGeneral, hs.InternalPutUserNotificationSettingsGeneral},
+ {http.MethodPut, "/settings/networks/{network}", hs.PublicPutUserNotificationSettingsNetworks, hs.InternalPutUserNotificationSettingsNetworks},
+ {http.MethodPut, "/settings/paired-devices/{paired_device_id}", hs.PublicPutUserNotificationSettingsPairedDevices, hs.InternalPutUserNotificationSettingsPairedDevices},
+ {http.MethodDelete, "/settings/paired-devices/{paired_device_id}", hs.PublicDeleteUserNotificationSettingsPairedDevices, hs.InternalDeleteUserNotificationSettingsPairedDevices},
+ {http.MethodGet, "/settings/dashboards", hs.PublicGetUserNotificationSettingsDashboards, hs.InternalGetUserNotificationSettingsDashboards},
+ {http.MethodPost, "/test-email", hs.PublicPostUserNotificationsTestEmail, hs.InternalPostUserNotificationsTestEmail},
+ {http.MethodPost, "/test-push", hs.PublicPostUserNotificationsTestPush, hs.InternalPostUserNotificationsTestPush},
+ {http.MethodPost, "/test-webhook", hs.PublicPostUserNotificationsTestWebhook, hs.InternalPostUserNotificationsTestWebhook},
}
addEndpointsToRouters(endpoints, publicNotificationRouter, internalNotificationRouter)
publicDashboardNotificationSettingsRouter := publicNotificationRouter.NewRoute().Subrouter()
internalDashboardNotificationSettingsRouter := internalNotificationRouter.NewRoute().Subrouter()
+ // TODO add adb auth middleware to account dashboard endpoints once they are implemented
if !debug {
publicDashboardNotificationSettingsRouter.Use(hs.VDBAuthMiddleware)
internalDashboardNotificationSettingsRouter.Use(hs.VDBAuthMiddleware)
}
dashboardSettingsEndpoints := []endpoint{
- {http.MethodPut, "/settings/validator-dashboards/{dashboard_id}/groups/{group_id}", nil, hs.InternalPutUserNotificationSettingsValidatorDashboard},
- {http.MethodPut, "/settings/account-dashboards/{dashboard_id}/groups/{group_id}", nil, hs.InternalPutUserNotificationSettingsAccountDashboard},
+ {http.MethodGet, "/validator-dashboards/{dashboard_id}/groups/{group_id}/epochs/{epoch}", hs.PublicGetUserNotificationsValidatorDashboard, hs.InternalGetUserNotificationsValidatorDashboard},
+ {http.MethodGet, "/account-dashboards/{dashboard_id}/groups/{group_id}/epochs/{epoch}", hs.PublicGetUserNotificationsAccountDashboard, hs.InternalGetUserNotificationsAccountDashboard},
+ {http.MethodPut, "/settings/validator-dashboards/{dashboard_id}/groups/{group_id}", hs.PublicPutUserNotificationSettingsValidatorDashboard, hs.InternalPutUserNotificationSettingsValidatorDashboard},
+ {http.MethodPut, "/settings/account-dashboards/{dashboard_id}/groups/{group_id}", hs.PublicPutUserNotificationSettingsAccountDashboard, hs.InternalPutUserNotificationSettingsAccountDashboard},
}
addEndpointsToRouters(dashboardSettingsEndpoints, publicDashboardNotificationSettingsRouter, internalDashboardNotificationSettingsRouter)
}