From f9aecaf7bdd9f5cd63f20c6bf096a92bac6326bd Mon Sep 17 00:00:00 2001 From: LUCCA DUKIC <109136188+LuccaBitfly@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:58:52 +0200 Subject: [PATCH 1/5] (BEDS-452) move clients in notification settings --- backend/pkg/api/types/notifications.go | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/backend/pkg/api/types/notifications.go b/backend/pkg/api/types/notifications.go index 27bf585be..5d80efc89 100644 --- a/backend/pkg/api/types/notifications.go +++ b/backend/pkg/api/types/notifications.go @@ -162,6 +162,12 @@ type NotificationPairedDevice struct { } type InternalPutUserNotificationSettingsPairedDevicesResponse ApiDataResponse[NotificationPairedDevice] +type NotificationSettingsClients struct { + Id uint64 `json:"id"` + Name string `json:"name"` + Category string `json:"category"` + IsSubscribed bool `json:"is_subscribed"` +} type NotificationSettingsGeneral struct { DoNotDisturbTimestamp int64 `json:"do_not_disturb_timestamp"` // notifications are disabled until this timestamp IsEmailNotificationsEnabled bool `json:"is_email_notifications_enabled"` @@ -175,18 +181,18 @@ type NotificationSettingsGeneral struct { IsMachineMemoryUsageSubscribed bool `json:"is_machine_memory_usage_subscribed"` MachineMemoryUsageThreshold float64 `json:"machine_memory_usage_threshold" faker:"boundary_start=0, boundary_end=1"` - SubscribedClients []string `json:"subscribed_clients"` - IsRocketPoolNewRewardRoundSubscribed bool `json:"is_rocket_pool_new_reward_round_subscribed"` - IsRocketPoolMaxCollateralSubscribed bool `json:"is_rocket_pool_max_collateral_subscribed"` - RocketPoolMaxCollateralThreshold float64 `json:"rocket_pool_max_collateral_threshold" faker:"boundary_start=0, boundary_end=1"` - IsRocketPoolMinCollateralSubscribed bool `json:"is_rocket_pool_min_collateral_subscribed"` - RocketPoolMinCollateralThreshold float64 `json:"rocket_pool_min_collateral_threshold" faker:"boundary_start=0, boundary_end=1"` + IsRocketPoolNewRewardRoundSubscribed bool `json:"is_rocket_pool_new_reward_round_subscribed"` + IsRocketPoolMaxCollateralSubscribed bool `json:"is_rocket_pool_max_collateral_subscribed"` + RocketPoolMaxCollateralThreshold float64 `json:"rocket_pool_max_collateral_threshold" faker:"boundary_start=0, boundary_end=1"` + IsRocketPoolMinCollateralSubscribed bool `json:"is_rocket_pool_min_collateral_subscribed"` + RocketPoolMinCollateralThreshold float64 `json:"rocket_pool_min_collateral_threshold" faker:"boundary_start=0, boundary_end=1"` } type InternalPutUserNotificationSettingsGeneralResponse ApiDataResponse[NotificationSettingsGeneral] type NotificationSettings struct { - GeneralSettings NotificationSettingsGeneral `json:"general_settings"` - Networks []NotificationNetwork `json:"networks"` - PairedDevices []NotificationPairedDevice `json:"paired_devices"` + GeneralSettings NotificationSettingsGeneral `json:"general_settings"` + Networks []NotificationNetwork `json:"networks"` + PairedDevices []NotificationPairedDevice `json:"paired_devices"` + Clients []NotificationSettingsClients `json:"clients"` } type InternalGetUserNotificationSettingsResponse ApiDataResponse[NotificationSettings] From d0a011c6dc740ce3673464078e94cfc3afedb0dc Mon Sep 17 00:00:00 2001 From: LUCCA DUKIC <109136188+LuccaBitfly@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:29:45 +0200 Subject: [PATCH 2/5] (BEDS-452) add new client notification settings endpoint --- backend/pkg/api/data_access/dummy.go | 5 + backend/pkg/api/data_access/notifications.go | 4 + backend/pkg/api/handlers/internal.go | 4 + backend/pkg/api/handlers/public.go | 122 +++++++++++++------ backend/pkg/api/router.go | 1 + backend/pkg/api/types/notifications.go | 13 +- 6 files changed, 104 insertions(+), 45 deletions(-) diff --git a/backend/pkg/api/data_access/dummy.go b/backend/pkg/api/data_access/dummy.go index 7bee9a38c..38fb693ab 100644 --- a/backend/pkg/api/data_access/dummy.go +++ b/backend/pkg/api/data_access/dummy.go @@ -488,6 +488,11 @@ func (d *DummyService) UpdateNotificationSettingsPairedDevice(ctx context.Contex func (d *DummyService) DeleteNotificationSettingsPairedDevice(ctx context.Context, userId uint64, pairedDeviceId string) error { return nil } + +func (d *DummyService) UpdateNotificationSettingsClients(ctx context.Context, userId uint64, clientId uint64, IsSubscribed bool) (*t.NotificationSettingsClient, error) { + return getDummyStruct[t.NotificationSettingsClient]() +} + func (d *DummyService) GetNotificationSettingsDashboards(ctx context.Context, userId uint64, cursor string, colSort t.Sort[enums.NotificationSettingsDashboardColumn], search string, limit uint64) ([]t.NotificationSettingsDashboardsTableRow, *t.Paging, error) { r, p, err := getDummyWithPaging[t.NotificationSettingsDashboardsTableRow]() for i, n := range r { diff --git a/backend/pkg/api/data_access/notifications.go b/backend/pkg/api/data_access/notifications.go index 5389847db..44f7ca4a5 100644 --- a/backend/pkg/api/data_access/notifications.go +++ b/backend/pkg/api/data_access/notifications.go @@ -25,6 +25,7 @@ type NotificationsRepository interface { UpdateNotificationSettingsNetworks(ctx context.Context, userId uint64, chainId uint64, settings t.NotificationSettingsNetwork) error UpdateNotificationSettingsPairedDevice(ctx context.Context, userId uint64, pairedDeviceId string, name string, IsNotificationsEnabled bool) error DeleteNotificationSettingsPairedDevice(ctx context.Context, userId uint64, pairedDeviceId string) error + UpdateNotificationSettingsClients(ctx context.Context, userId uint64, clientId uint64, IsSubscribed bool) (*t.NotificationSettingsClient, error) GetNotificationSettingsDashboards(ctx context.Context, userId uint64, cursor string, colSort t.Sort[enums.NotificationSettingsDashboardColumn], search string, limit uint64) ([]t.NotificationSettingsDashboardsTableRow, *t.Paging, error) UpdateNotificationSettingsValidatorDashboard(ctx context.Context, dashboardId t.VDBIdPrimary, groupId uint64, settings t.NotificationSettingsValidatorDashboard) error UpdateNotificationSettingsAccountDashboard(ctx context.Context, dashboardId t.VDBIdPrimary, groupId uint64, settings t.NotificationSettingsAccountDashboard) error @@ -72,6 +73,9 @@ func (d *DataAccessService) UpdateNotificationSettingsPairedDevice(ctx context.C func (d *DataAccessService) DeleteNotificationSettingsPairedDevice(ctx context.Context, userId uint64, pairedDeviceId string) error { return d.dummy.DeleteNotificationSettingsPairedDevice(ctx, userId, pairedDeviceId) } +func (d *DataAccessService) UpdateNotificationSettingsClients(ctx context.Context, userId uint64, clientId uint64, IsSubscribed bool) (*t.NotificationSettingsClient, error) { + return d.dummy.UpdateNotificationSettingsClients(ctx, userId, clientId, IsSubscribed) +} func (d *DataAccessService) GetNotificationSettingsDashboards(ctx context.Context, userId uint64, cursor string, colSort t.Sort[enums.NotificationSettingsDashboardColumn], search string, limit uint64) ([]t.NotificationSettingsDashboardsTableRow, *t.Paging, error) { return d.dummy.GetNotificationSettingsDashboards(ctx, userId, cursor, colSort, search, limit) } diff --git a/backend/pkg/api/handlers/internal.go b/backend/pkg/api/handlers/internal.go index 78d998856..bf3e347fe 100644 --- a/backend/pkg/api/handlers/internal.go +++ b/backend/pkg/api/handlers/internal.go @@ -609,6 +609,10 @@ func (h *HandlerService) InternalDeleteUserNotificationSettingsPairedDevices(w h h.PublicDeleteUserNotificationSettingsPairedDevices(w, r) } +func (h *HandlerService) InternalPutUserNotificationSettingsClient(w http.ResponseWriter, r *http.Request) { + h.PublicPutUserNotificationSettingsClient(w, r) +} + func (h *HandlerService) InternalGetUserNotificationSettingsDashboards(w http.ResponseWriter, r *http.Request) { h.PublicGetUserNotificationSettingsDashboards(w, r) } diff --git a/backend/pkg/api/handlers/public.go b/backend/pkg/api/handlers/public.go index e0e560b8c..d160582df 100644 --- a/backend/pkg/api/handlers/public.go +++ b/backend/pkg/api/handlers/public.go @@ -271,7 +271,7 @@ func (h *HandlerService) PublicGetValidatorDashboard(w http.ResponseWriter, r *h // @Security ApiKeyInHeader || ApiKeyInQuery // @Tags Validator Dashboard Management // @Produce json -// @Param dashboard_id path string true "The ID of the dashboard." +// @Param dashboard_id path integer true "The ID of the dashboard." // @Success 204 "Dashboard deleted successfully." // @Failure 400 {object} types.ApiErrorResponse "Bad Request" // @Router /validator-dashboards/{dashboard_id} [delete] @@ -297,7 +297,7 @@ func (h *HandlerService) PublicDeleteValidatorDashboard(w http.ResponseWriter, r // @Tags Validator Dashboard Management // @Accept json // @Produce json -// @Param dashboard_id path string true "The ID of the dashboard." +// @Param dashboard_id path integer true "The ID of the dashboard." // @Param request body handlers.PublicPutValidatorDashboardName.request true "request" // @Success 200 {object} types.ApiDataResponse[types.VDBPostReturnData] // @Failure 400 {object} types.ApiErrorResponse @@ -336,7 +336,7 @@ func (h *HandlerService) PublicPutValidatorDashboardName(w http.ResponseWriter, // @Tags Validator Dashboard Management // @Accept json // @Produce json -// @Param dashboard_id path string true "The ID of the dashboard." +// @Param dashboard_id path integer true "The ID of the dashboard." // @Param request body handlers.PublicPostValidatorDashboardGroups.request true "request" // @Success 201 {object} types.ApiDataResponse[types.VDBPostCreateGroupData] // @Failure 400 {object} types.ApiErrorResponse @@ -400,8 +400,8 @@ func (h *HandlerService) PublicPostValidatorDashboardGroups(w http.ResponseWrite // @Tags Validator Dashboard Management // @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 dashboard_id path integer true "The ID of the dashboard." +// @Param group_id path integer true "The ID of the group." // @Param request body handlers.PublicPutValidatorDashboardGroups.request true "request" // @Success 200 {object} types.ApiDataResponse[types.VDBPostCreateGroupData] // @Failure 400 {object} types.ApiErrorResponse @@ -453,8 +453,8 @@ func (h *HandlerService) PublicPutValidatorDashboardGroups(w http.ResponseWriter // @Security ApiKeyInHeader || ApiKeyInQuery // @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 dashboard_id path integer true "The ID of the dashboard." +// @Param group_id path integer true "The ID of the group." // @Success 204 "Group deleted successfully." // @Failure 400 {object} types.ApiErrorResponse // @Router /validator-dashboards/{dashboard_id}/groups/{group_id} [delete] @@ -496,7 +496,7 @@ func (h *HandlerService) PublicDeleteValidatorDashboardGroup(w http.ResponseWrit // @Tags Validator Dashboard Management // @Accept json // @Produce json -// @Param dashboard_id path string true "The ID of the dashboard." +// @Param dashboard_id path integer true "The ID of the dashboard." // @Param request body handlers.PublicPostValidatorDashboardValidators.request true "`group_id`: (optional) Provide a single group id, to which all validators get added to. If omitted, the default group will be used.

To add validators, only one of the following fields can be set:" // @Success 201 {object} types.ApiDataResponse[[]types.VDBPostValidatorsData] "Returns a list of added validators." // @Failure 400 {object} types.ApiErrorResponse @@ -631,7 +631,7 @@ func (h *HandlerService) PublicPostValidatorDashboardValidators(w http.ResponseW // @Tags Validator Dashboard // @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 group_id query integer false "The ID of the group." // @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." @@ -672,7 +672,7 @@ 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 dashboard_id path integer 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 @@ -714,7 +714,7 @@ func (h *HandlerService) PublicDeleteValidatorDashboardValidators(w http.Respons // @Tags Validator Dashboard Management // @Accept json // @Produce json -// @Param dashboard_id path string true "The ID of the dashboard." +// @Param dashboard_id path integer true "The ID of the dashboard." // @Param request body handlers.PublicPostValidatorDashboardPublicIds.request true "`name`: Provide a public name for the dashboard
`share_settings`:" // @Success 201 {object} types.ApiDataResponse[types.VDBPublicId] // @Failure 400 {object} types.ApiErrorResponse @@ -768,7 +768,7 @@ func (h *HandlerService) PublicPostValidatorDashboardPublicIds(w http.ResponseWr // @Tags Validator Dashboard Management // @Accept json // @Produce json -// @Param dashboard_id path string true "The ID of the dashboard." +// @Param dashboard_id path integer true "The ID of the dashboard." // @Param public_id path string true "The ID of the public ID." // @Param request body handlers.PublicPutValidatorDashboardPublicId.request true "`name`: Provide a public name for the dashboard
`share_settings`:" // @Success 200 {object} types.ApiDataResponse[types.VDBPublicId] @@ -823,7 +823,7 @@ func (h *HandlerService) PublicPutValidatorDashboardPublicId(w http.ResponseWrit // @Security ApiKeyInHeader || ApiKeyInQuery // @Tags Validator Dashboard Management // @Produce json -// @Param dashboard_id path string true "The ID of the dashboard." +// @Param dashboard_id path integer true "The ID of the dashboard." // @Param public_id path string true "The ID of the public ID." // @Success 204 "Public ID deleted successfully." // @Failure 400 {object} types.ApiErrorResponse @@ -863,8 +863,8 @@ func (h *HandlerService) PublicDeleteValidatorDashboardPublicId(w http.ResponseW // @Tags Validator Dashboard Management // @Accept json // @Produce json -// @Param dashboard_id path string true "The ID of the dashboard." -// @Param request body handlers.PublicPutValidatorDashboardArchiving.request true "request" +// @Param dashboard_id path integer true "The ID of the dashboard." +// @Param request body handlers.PublicPutValidatorDashboardArchiving.request true "`is_archived`: Set to `true` to archive the dashboard, or `false` to unarchive it." // @Success 200 {object} types.ApiDataResponse[types.VDBPostArchivingReturnData] // @Failure 400 {object} types.ApiErrorResponse // @Failure 409 {object} types.ApiErrorResponse "Conflict. The request could not be performed by the server because the authenticated user has already reached their subscription limit." @@ -1043,7 +1043,7 @@ func (h *HandlerService) PublicGetValidatorDashboardSummary(w http.ResponseWrite // @Tags Validator Dashboard // @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 group_id path integer true "The ID of the group." // @Param period query string true "Time period to get data for." Enums(all_time, last_30d, last_7d, last_24h, last_1h) // @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." // @Success 200 {object} types.GetValidatorDashboardGroupSummaryResponse @@ -1142,7 +1142,7 @@ func (h *HandlerService) PublicGetValidatorDashboardSummaryChart(w http.Response // @Tags Validator Dashboard // @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 group_id query integer false "The ID of the group." // @Param duty query string false "Validator duty to get data for." Enums(none, sync, slashed, proposal) Default(none) // @Param period query string true "Time period to get data for." Enums(all_time, last_30d, last_7d, last_24h, last_1h) // @Success 200 {object} types.GetValidatorDashboardSummaryValidatorsResponse @@ -1246,8 +1246,8 @@ func (h *HandlerService) PublicGetValidatorDashboardRewards(w http.ResponseWrite // @Tags Validator Dashboard // @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 to get data for." +// @Param group_id path integer true "The ID of the group." +// @Param epoch path integer true "The epoch to get data for." // @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." // @Success 200 {object} types.GetValidatorDashboardGroupRewardsResponse // @Failure 400 {object} types.ApiErrorResponse @@ -1322,8 +1322,8 @@ func (h *HandlerService) PublicGetValidatorDashboardRewardsChart(w http.Response // @Tags Validator Dashboard // @Produce json // @Param dashboard_id path string true "The ID of the dashboard." -// @Param epoch path string true "The epoch to get data for." -// @Param group_id query string false "The ID of the group." +// @Param epoch path integer true "The epoch to get data for." +// @Param group_id query integer 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(validator, reward) @@ -1460,8 +1460,8 @@ func (h *HandlerService) PublicGetValidatorDashboardHeatmap(w http.ResponseWrite // @Tags Validator Dashboard // @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 timestamp path string true "The timestamp to get data for." +// @Param group_id path integer true "The ID of the group." +// @Param timestamp path integer true "The timestamp to get data for." // @Param modes query string false "Provide a comma separated list of protocol modes which should be respected for validator calculations. Possible values are `rocket_pool``." // @Param aggregation query string false "Aggregation type to get data for." Enums(epoch, hourly, daily, weekly) Default(hourly) // @Success 200 {object} types.GetValidatorDashboardGroupHeatmapResponse @@ -1903,7 +1903,7 @@ func (h *HandlerService) PublicGetUserNotifications(w http.ResponseWriter, r *ht // @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 limit query integer 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 @@ -1931,7 +1931,7 @@ func (h *HandlerService) PublicGetUserNotificationDashboards(w http.ResponseWrit } response := types.InternalGetUserNotificationDashboardsResponse{ Data: data, - Paging: *paging, + Paging: *paging, // @Param epoch path strings } returnOk(w, r, response) } @@ -1943,8 +1943,8 @@ func (h *HandlerService) PublicGetUserNotificationDashboards(w http.ResponseWrit // @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." +// @Param group_id path integer true "The ID of the group." +// @Param epoch path integer 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] @@ -1976,8 +1976,8 @@ func (h *HandlerService) PublicGetUserNotificationsValidatorDashboard(w http.Res // @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." +// @Param group_id path integer true "The ID of the group." +// @Param epoch path integer 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] @@ -2009,7 +2009,7 @@ func (h *HandlerService) PublicGetUserNotificationsAccountDashboard(w http.Respo // @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 limit query integer 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 @@ -2048,7 +2048,7 @@ func (h *HandlerService) PublicGetUserNotificationMachines(w http.ResponseWriter // @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 limit query integer 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 @@ -2087,7 +2087,7 @@ func (h *HandlerService) PublicGetUserNotificationClients(w http.ResponseWriter, // @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 limit query integer 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 @@ -2126,7 +2126,7 @@ func (h *HandlerService) PublicGetUserNotificationRocketPool(w http.ResponseWrit // @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 limit query integer 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 @@ -2190,7 +2190,7 @@ func (h *HandlerService) PublicGetUserNotificationSettings(w http.ResponseWriter // @Tags Notification Settings // @Accept json // @Produce json -// @Param request body types.NotificationSettingsGeneral true "Notification settings" +// @Param request body types.NotificationSettingsGeneral true "Description TODO" // @Success 200 {object} types.InternalPutUserNotificationSettingsGeneralResponse // @Failure 400 {object} types.ApiErrorResponse // @Router /users/me/notifications/settings/general [put] @@ -2211,7 +2211,6 @@ func (h *HandlerService) PublicPutUserNotificationSettingsGeneral(w http.Respons 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 @@ -2235,7 +2234,7 @@ func (h *HandlerService) PublicPutUserNotificationSettingsGeneral(w http.Respons // @Accept json // @Produce json // @Param network path string true "The networks name or chain ID." -// @Param request body types.NotificationSettingsNetwork true "Notification settings" +// @Param request body types.NotificationSettingsNetwork true "Description Todo" // @Success 200 {object} types.InternalPutUserNotificationSettingsNetworksResponse // @Failure 400 {object} types.ApiErrorResponse // @Router /users/me/notifications/settings/networks/{network} [put] @@ -2280,7 +2279,7 @@ func (h *HandlerService) PublicPutUserNotificationSettingsNetworks(w http.Respon // @Accept json // @Produce json // @Param paired_device_id path string true "The paired device ID." -// @Param request body handlers.PublicPutUserNotificationSettingsPairedDevices.request true "Notification settings" +// @Param request body handlers.PublicPutUserNotificationSettingsPairedDevices.request true "Description TODO" // @Success 200 {object} types.InternalPutUserNotificationSettingsPairedDevicesResponse // @Failure 400 {object} types.ApiErrorResponse // @Router /users/me/notifications/settings/paired-devices/{paired_device_id} [put] @@ -2355,6 +2354,49 @@ func (h *HandlerService) PublicDeleteUserNotificationSettingsPairedDevices(w htt returnNoContent(w, r) } +// PublicPutUserNotificationSettingsClient godoc +// +// @Description Update client notification settings for the authenticated user. When a client is subscribed, notifications will be sent when a new version is available. +// @Security ApiKeyInHeader || ApiKeyInQuery +// @Tags Notification Settings +// @Accept json +// @Produce json +// @Param client_id path integer true "The ID of the client." +// @Param request body handlers.PublicPutUserNotificationSettingsClient.request true "`is_subscribed`: Set to `true` to subscribe to notifications; set to `false` to unsubscribe." +// @Success 200 {object} types.InternalPutUserNotificationSettingsClientResponse +// @Failure 400 {object} types.ApiErrorResponse +// @Router /users/me/notifications/settings/clients/{client_id} [put] +func (h *HandlerService) PublicPutUserNotificationSettingsClient(w http.ResponseWriter, r *http.Request) { + var v validationError + userId, err := GetUserIdByContext(r) + if err != nil { + handleErr(w, r, err) + return + } + type request struct { + IsSubscribed bool `json:"is_subscribed"` + } + var req request + if err := v.checkBody(&req, r); err != nil { + handleErr(w, r, err) + return + } + clientId := v.checkUint(mux.Vars(r)["client_id"], "client_id") + if v.hasErrors() { + handleErr(w, r, v) + return + } + data, err := h.dai.UpdateNotificationSettingsClients(r.Context(), userId, clientId, req.IsSubscribed) + if err != nil { + handleErr(w, r, err) + return + } + response := types.InternalPutUserNotificationSettingsClientResponse{ + Data: *data, + } + returnOk(w, r, response) +} + // PublicGetUserNotificationSettingsDashboards godoc // // @Description Get a list of notification settings for the dashboards of the authenticated user. @@ -2362,7 +2404,7 @@ func (h *HandlerService) PublicDeleteUserNotificationSettingsPairedDevices(w htt // @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 limit query integer 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 @@ -2402,7 +2444,7 @@ func (h *HandlerService) PublicGetUserNotificationSettingsDashboards(w http.Resp // @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 group_id path integer true "The ID of the group." // @Param request body types.NotificationSettingsValidatorDashboard true "Notification settings" // @Success 200 {object} types.InternalPutUserNotificationSettingsValidatorDashboardResponse // @Failure 400 {object} types.ApiErrorResponse @@ -2441,7 +2483,7 @@ func (h *HandlerService) PublicPutUserNotificationSettingsValidatorDashboard(w h // @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 group_id path integer 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 diff --git a/backend/pkg/api/router.go b/backend/pkg/api/router.go index 16ab4c0b2..864cb69d8 100644 --- a/backend/pkg/api/router.go +++ b/backend/pkg/api/router.go @@ -329,6 +329,7 @@ func addNotificationRoutes(hs *handlers.HandlerService, publicRouter, internalRo {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.MethodPut, "/settings/clients/{client_id}", hs.PublicPutUserNotificationSettingsClient, hs.InternalPutUserNotificationSettingsClient}, {http.MethodGet, "/settings/dashboards", hs.PublicGetUserNotificationSettingsDashboards, hs.InternalGetUserNotificationSettingsDashboards}, {http.MethodPost, "/test-email", hs.PublicPostUserNotificationsTestEmail, hs.InternalPostUserNotificationsTestEmail}, {http.MethodPost, "/test-push", hs.PublicPostUserNotificationsTestPush, hs.InternalPostUserNotificationsTestPush}, diff --git a/backend/pkg/api/types/notifications.go b/backend/pkg/api/types/notifications.go index 5d80efc89..4d512ff5a 100644 --- a/backend/pkg/api/types/notifications.go +++ b/backend/pkg/api/types/notifications.go @@ -162,12 +162,15 @@ type NotificationPairedDevice struct { } type InternalPutUserNotificationSettingsPairedDevicesResponse ApiDataResponse[NotificationPairedDevice] -type NotificationSettingsClients struct { +type NotificationSettingsClient struct { Id uint64 `json:"id"` Name string `json:"name"` Category string `json:"category"` IsSubscribed bool `json:"is_subscribed"` } + +type InternalPutUserNotificationSettingsClientResponse ApiDataResponse[NotificationSettingsClient] + type NotificationSettingsGeneral struct { DoNotDisturbTimestamp int64 `json:"do_not_disturb_timestamp"` // notifications are disabled until this timestamp IsEmailNotificationsEnabled bool `json:"is_email_notifications_enabled"` @@ -189,10 +192,10 @@ type NotificationSettingsGeneral struct { } type InternalPutUserNotificationSettingsGeneralResponse ApiDataResponse[NotificationSettingsGeneral] type NotificationSettings struct { - GeneralSettings NotificationSettingsGeneral `json:"general_settings"` - Networks []NotificationNetwork `json:"networks"` - PairedDevices []NotificationPairedDevice `json:"paired_devices"` - Clients []NotificationSettingsClients `json:"clients"` + GeneralSettings NotificationSettingsGeneral `json:"general_settings"` + Networks []NotificationNetwork `json:"networks"` + PairedDevices []NotificationPairedDevice `json:"paired_devices"` + Clients []NotificationSettingsClient `json:"clients"` } type InternalGetUserNotificationSettingsResponse ApiDataResponse[NotificationSettings] From 1b7d591b99887e569067d4080006ffb59ed28022 Mon Sep 17 00:00:00 2001 From: LUCCA DUKIC <109136188+LuccaBitfly@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:30:19 +0200 Subject: [PATCH 3/5] (BEDS-452) typescript conversion --- frontend/types/api/notifications.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/frontend/types/api/notifications.ts b/frontend/types/api/notifications.ts index 0d9f53898..57a2900d4 100644 --- a/frontend/types/api/notifications.ts +++ b/frontend/types/api/notifications.ts @@ -156,6 +156,13 @@ export interface NotificationPairedDevice { is_notifications_enabled: boolean; } export type InternalPutUserNotificationSettingsPairedDevicesResponse = ApiDataResponse; +export interface NotificationSettingsClient { + id: number /* uint64 */; + name: string; + category: string; + is_subscribed: boolean; +} +export type InternalPutUserNotificationSettingsClientResponse = ApiDataResponse; export interface NotificationSettingsGeneral { do_not_disturb_timestamp: number /* int64 */; // notifications are disabled until this timestamp is_email_notifications_enabled: boolean; @@ -167,7 +174,6 @@ export interface NotificationSettingsGeneral { machine_cpu_usage_threshold: number /* float64 */; is_machine_memory_usage_subscribed: boolean; machine_memory_usage_threshold: number /* float64 */; - subscribed_clients: string[]; is_rocket_pool_new_reward_round_subscribed: boolean; is_rocket_pool_max_collateral_subscribed: boolean; rocket_pool_max_collateral_threshold: number /* float64 */; @@ -179,6 +185,7 @@ export interface NotificationSettings { general_settings: NotificationSettingsGeneral; networks: NotificationNetwork[]; paired_devices: NotificationPairedDevice[]; + clients: NotificationSettingsClient[]; } export type InternalGetUserNotificationSettingsResponse = ApiDataResponse; export interface NotificationSettingsValidatorDashboard { From f29cd091cd21b671a4ba63d7b94b83e10e5322ad Mon Sep 17 00:00:00 2001 From: LUCCA DUKIC <109136188+LuccaBitfly@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:48:14 +0200 Subject: [PATCH 4/5] (BEDS-452) defeat frontend typecheck --- frontend/utils/mock.ts | 27 ++++++++++++++++++++++++++- 1 file changed, 26 insertions(+), 1 deletion(-) diff --git a/frontend/utils/mock.ts b/frontend/utils/mock.ts index f942d8fbb..0f5e8bc6e 100644 --- a/frontend/utils/mock.ts +++ b/frontend/utils/mock.ts @@ -443,6 +443,32 @@ export function simulateAPIresponseAboutNetworkList(): ApiDataResponse< export function mockManageNotificationsGeneral(): InternalGetUserNotificationSettingsResponse { return { data: { + clients: [ + { + category: 'EL', + id: 1, + is_subscribed: true, + name: 'EL Client 1', + }, + { + category: 'CL', + id: 2, + is_subscribed: false, + name: 'CL Client 1', + }, + { + category: 'other', + id: 3, + is_subscribed: true, + name: 'Other Clien 1', + }, + { + category: 'other', + id: 4, + is_subscribed: false, + name: 'Other Clien 2', + }, + ], general_settings: { do_not_disturb_timestamp: 9000, is_email_notifications_enabled: false, @@ -459,7 +485,6 @@ export function mockManageNotificationsGeneral(): InternalGetUserNotificationSet machine_storage_usage_threshold: 80, rocket_pool_max_collateral_threshold: 29823, rocket_pool_min_collateral_threshold: 123, - subscribed_clients: [], }, networks: [], paired_devices: [ From 434ccfc33e98c2e1075fe7d08d4a9c27cc943e61 Mon Sep 17 00:00:00 2001 From: marcel-bitfly <174338434+marcel-bitfly@users.noreply.github.com> Date: Fri, 27 Sep 2024 11:09:32 +0200 Subject: [PATCH 5/5] refactor: resolve `type errors` --- .../useNotificationsManagementStore.ts | 2 +- frontend/utils/mock.ts | 65 ------------------- 2 files changed, 1 insertion(+), 66 deletions(-) diff --git a/frontend/stores/notifications/useNotificationsManagementStore.ts b/frontend/stores/notifications/useNotificationsManagementStore.ts index ad08472d8..2b7c060b7 100644 --- a/frontend/stores/notifications/useNotificationsManagementStore.ts +++ b/frontend/stores/notifications/useNotificationsManagementStore.ts @@ -10,6 +10,7 @@ export const useNotificationsManagementStore = defineStore('notifications-manage const { fetch } = useCustomFetch() const settings = ref( { + clients: [], general_settings: { do_not_disturb_timestamp: 0, is_email_notifications_enabled: false, @@ -26,7 +27,6 @@ export const useNotificationsManagementStore = defineStore('notifications-manage machine_storage_usage_threshold: 0.0, rocket_pool_max_collateral_threshold: 0, rocket_pool_min_collateral_threshold: 0, - subscribed_clients: [], }, networks: [ { chain_id: 0, diff --git a/frontend/utils/mock.ts b/frontend/utils/mock.ts index bc1f3d08a..23a2b3184 100644 --- a/frontend/utils/mock.ts +++ b/frontend/utils/mock.ts @@ -438,68 +438,3 @@ export function simulateAPIresponseAboutNetworkList(): ApiDataResponse< } return result } - -export function mockManageNotificationsGeneral(): InternalGetUserNotificationSettingsResponse { - return { - data: { - clients: [ - { - category: 'EL', - id: 1, - is_subscribed: true, - name: 'EL Client 1', - }, - { - category: 'CL', - id: 2, - is_subscribed: false, - name: 'CL Client 1', - }, - { - category: 'other', - id: 3, - is_subscribed: true, - name: 'Other Clien 1', - }, - { - category: 'other', - id: 4, - is_subscribed: false, - name: 'Other Clien 2', - }, - ], - general_settings: { - do_not_disturb_timestamp: 9000, - is_email_notifications_enabled: false, - is_machine_cpu_usage_subscribed: true, - is_machine_memory_usage_subscribed: true, - is_machine_offline_subscribed: true, - is_machine_storage_usage_subscribed: true, - is_push_notifications_enabled: true, - is_rocket_pool_max_collateral_subscribed: true, - is_rocket_pool_min_collateral_subscribed: true, - is_rocket_pool_new_reward_round_subscribed: true, - machine_cpu_usage_threshold: 40, - machine_memory_usage_threshold: 50, - machine_storage_usage_threshold: 80, - rocket_pool_max_collateral_threshold: 29823, - rocket_pool_min_collateral_threshold: 123, - }, - networks: [], - paired_devices: [ - { - id: 'ABC-test', - is_notifications_enabled: true, - name: 'My device', - paired_timestamp: 1620000000, - }, - { - id: 'DEF-test', - is_notifications_enabled: false, - name: 'My other device', - paired_timestamp: 1700000000, - }, - ], - }, - } -}