storj/storagenode/console/consoleapi/notifications.go
Egon Elbre 961e841bd7 all: fix error naming
errs.Class should not contain "error" in the name, since that causes a
lot of stutter in the error logs. As an example a log line could end up
looking like:

    ERROR node stats service error: satellitedbs error: node stats database error: no rows

Whereas something like:

    ERROR nodestats service: satellitedbs: nodestatsdb: no rows

Would contain all the necessary information without the stutter.

Change-Id: I7b7cb7e592ebab4bcfadc1eef11122584d2b20e0
2021-04-29 15:38:21 +03:00

163 lines
4.5 KiB
Go

// Copyright (C) 2019 Storj Labs, Inc.
// See LICENSE for copying information.
package consoleapi
import (
"encoding/json"
"net/http"
"strconv"
"github.com/gorilla/mux"
"github.com/zeebo/errs"
"go.uber.org/zap"
"storj.io/common/uuid"
"storj.io/storj/storagenode/notifications"
)
// ErrNotificationsAPI - console notifications api error type.
var ErrNotificationsAPI = errs.Class("consoleapi notifications")
// Notifications is an api controller that exposes all notifications related api.
type Notifications struct {
service *notifications.Service
log *zap.Logger
}
// Page contains notifications and related information.
type Page struct {
Notifications []notifications.Notification `json:"notifications"`
Offset uint64 `json:"offset"`
Limit uint `json:"limit"`
CurrentPage uint `json:"currentPage"`
PageCount uint `json:"pageCount"`
}
// NewNotifications is a constructor for notifications controller.
func NewNotifications(log *zap.Logger, service *notifications.Service) *Notifications {
return &Notifications{
log: log,
service: service,
}
}
// ReadNotification updates specific notification in database as read.
func (notification *Notifications) ReadNotification(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
w.Header().Set(contentType, applicationJSON)
params := mux.Vars(r)
id, ok := params["id"]
if !ok {
notification.serveJSONError(w, http.StatusInternalServerError, ErrNotificationsAPI.Wrap(err))
return
}
notificationID, err := uuid.FromString(id)
if err != nil {
notification.serveJSONError(w, http.StatusInternalServerError, ErrNotificationsAPI.Wrap(err))
return
}
err = notification.service.Read(ctx, notificationID)
if err != nil {
notification.serveJSONError(w, http.StatusInternalServerError, ErrNotificationsAPI.Wrap(err))
return
}
}
// ReadAllNotifications updates all notifications in database as read.
func (notification *Notifications) ReadAllNotifications(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
w.Header().Set(contentType, applicationJSON)
err = notification.service.ReadAll(ctx)
if err != nil {
notification.serveJSONError(w, http.StatusInternalServerError, ErrNotificationsAPI.Wrap(err))
return
}
}
// ListNotifications returns listed page of notifications from database.
func (notification *Notifications) ListNotifications(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
var err error
defer mon.Task()(&ctx)(&err)
w.Header().Set(contentType, applicationJSON)
limit, err := strconv.ParseUint(r.URL.Query().Get("limit"), 10, 32)
if err != nil {
notification.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
return
}
page, err := strconv.ParseUint(r.URL.Query().Get("page"), 10, 32)
if err != nil {
notification.serveJSONError(w, http.StatusBadRequest, ErrNotificationsAPI.Wrap(err))
return
}
cursor := notifications.Cursor{
Limit: uint(limit),
Page: uint(page),
}
notificationList, err := notification.service.List(ctx, cursor)
if err != nil {
notification.serveJSONError(w, http.StatusInternalServerError, ErrNotificationsAPI.Wrap(err))
return
}
unreadCount, err := notification.service.UnreadAmount(ctx)
if err != nil {
notification.serveJSONError(w, http.StatusInternalServerError, ErrNotificationsAPI.Wrap(err))
return
}
var result struct {
Page Page `json:"page"`
UnreadCount int `json:"unreadCount"`
TotalCount int `json:"totalCount"`
}
result.Page.Notifications = notificationList.Notifications
result.Page.Limit = notificationList.Limit
result.Page.CurrentPage = notificationList.CurrentPage
result.Page.Offset = notificationList.Offset
result.Page.PageCount = notificationList.PageCount
result.UnreadCount = unreadCount
result.TotalCount = int(notificationList.TotalCount)
if err := json.NewEncoder(w).Encode(result); err != nil {
notification.log.Error("failed to encode json list notifications response", zap.Error(ErrNotificationsAPI.Wrap(err)))
return
}
}
// serveJSONError writes JSON error to response output stream.
func (notification *Notifications) serveJSONError(w http.ResponseWriter, status int, err error) {
w.WriteHeader(status)
var response struct {
Error string `json:"error"`
}
response.Error = err.Error()
err = json.NewEncoder(w).Encode(response)
if err != nil {
notification.log.Error("failed to write json error response", zap.Error(ErrNotificationsAPI.Wrap(err)))
return
}
}