[notification] add /notification/read, add message_type (#47)

[notification] add /notification/read, add message_type

Co-authored-by: Kassian Sun <kassiansun@outlook.com>
This commit is contained in:
sunjiacheng 2023-04-02 15:02:30 +08:00 committed by medcl
parent 55ac534b02
commit 8fddcdaf09
5 changed files with 155 additions and 86 deletions

View File

@ -7,9 +7,16 @@ import (
type NotificationType string type NotificationType string
const ( const (
NotificationTypeProductNews NotificationType = "PRODUCT_NEWS" NotificationTypeNotification NotificationType = "NOTIFICATION"
NotificationTypeAlertTriggered NotificationType = "ALERT_TRIGGERED" NotificationTypeTodo NotificationType = "TODO"
NotificationTypeDataMigration NotificationType = "DATA_MIGRATION" )
type MessageType string
const (
MessageTypeNews MessageType = "NEWS"
MessageTypeAlerting MessageType = "ALERTING"
MessageTypeMigration MessageType = "MIGRATION"
) )
type NotificationStatus string type NotificationStatus string
@ -24,6 +31,7 @@ type Notification struct {
UserId string `json:"user_id,omitempty" elastic_mapping:"user_id: { type: keyword }"` UserId string `json:"user_id,omitempty" elastic_mapping:"user_id: { type: keyword }"`
NotificationType NotificationType `json:"notification_type,omitempty" elastic_mapping:"notification_type:{type:keyword,fields:{text: {type: text}}}"` NotificationType NotificationType `json:"notification_type,omitempty" elastic_mapping:"notification_type:{type:keyword,fields:{text: {type: text}}}"`
MessageType MessageType `json:"message_type,omitempty" elastic_mapping:"message_type:{type:keyword,fields:{text: {type: text}}}"`
Status NotificationStatus `json:"status,omitempty" elastic_mapping:"status: { type: keyword }"` Status NotificationStatus `json:"status,omitempty" elastic_mapping:"status: { type: keyword }"`
Title string `json:"title,omitempty" elastic_mapping:"title: { type: keyword }"` Title string `json:"title,omitempty" elastic_mapping:"title: { type: keyword }"`
Body string `json:"body,omitempty" elastic_mapping:"body: { type: keyword }"` Body string `json:"body,omitempty" elastic_mapping:"body: { type: keyword }"`

View File

@ -11,4 +11,5 @@ type NotificationAPI struct {
func InitAPI() { func InitAPI() {
notification := NotificationAPI{} notification := NotificationAPI{}
api.HandleAPIMethod(api.GET, "/notification", notification.RequireLogin(notification.listNotifications)) api.HandleAPIMethod(api.GET, "/notification", notification.RequireLogin(notification.listNotifications))
api.HandleAPIMethod(api.POST, "/notification/read", notification.RequireLogin(notification.setNotificationsRead))
} }

View File

@ -5,6 +5,7 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"strconv" "strconv"
"time"
log "github.com/cihub/seelog" log "github.com/cihub/seelog"
"infini.sh/console/model" "infini.sh/console/model"
@ -17,7 +18,7 @@ import (
func (h *NotificationAPI) listNotifications(w http.ResponseWriter, req *http.Request, ps httprouter.Params) { func (h *NotificationAPI) listNotifications(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
user, err := rbac.FromUserContext(req.Context()) user, err := rbac.FromUserContext(req.Context())
if err != nil { if err != nil {
log.Error(err) log.Error("failed to get user from context, err: %v", err)
h.WriteError(w, err.Error(), http.StatusInternalServerError) h.WriteError(w, err.Error(), http.StatusInternalServerError)
return return
} }
@ -35,7 +36,8 @@ func (h *NotificationAPI) listNotifications(w http.ResponseWriter, req *http.Req
], ],
"query": { "query": {
"bool": { "must": [ "bool": { "must": [
{ "term": {"user_id": { "value": "%s" } } } { "term": {"user_id": { "value": "%s" } } },
{ "term": {"status": { "value": "%s" } } }
] } ] }
}, },
"size": %d, "from": %d "size": %d, "from": %d
@ -53,7 +55,7 @@ func (h *NotificationAPI) listNotifications(w http.ResponseWriter, req *http.Req
} }
q := orm.Query{} q := orm.Query{}
queryDSL = fmt.Sprintf(queryDSL, user.UserId, size, from) queryDSL = fmt.Sprintf(queryDSL, user.UserId, model.NotificationStatusNew, size, from)
q.RawQuery = util.UnsafeStringToBytes(queryDSL) q.RawQuery = util.UnsafeStringToBytes(queryDSL)
err, res := orm.Search(&model.Notification{}, &q) err, res := orm.Search(&model.Notification{}, &q)
@ -65,3 +67,64 @@ func (h *NotificationAPI) listNotifications(w http.ResponseWriter, req *http.Req
h.WriteJSONHeader(w) h.WriteJSONHeader(w)
h.Write(w, res.Raw) h.Write(w, res.Raw)
} }
type SetNotificationsReadRequest struct {
Ids []string `json:"ids"`
}
func (h *NotificationAPI) setNotificationsRead(w http.ResponseWriter, req *http.Request, ps httprouter.Params) {
user, err := rbac.FromUserContext(req.Context())
if err != nil {
log.Error("failed to get user from context, err: %v", err)
h.WriteError(w, err.Error(), http.StatusInternalServerError)
return
}
if user == nil {
log.Error(errors.New("no user info"))
h.WriteError(w, "no user info", http.StatusInternalServerError)
return
}
var reqData = SetNotificationsReadRequest{}
err = h.DecodeJSON(req, &reqData)
if err != nil {
log.Error("failed to parse request: ", err)
h.WriteError(w, err.Error(), http.StatusBadRequest)
return
}
now := time.Now().Format(time.RFC3339Nano)
queryDsl := util.MapStr{
"query": util.MapStr{
"bool": util.MapStr{
"must": []util.MapStr{
{
"terms": util.MapStr{
"_id": reqData.Ids,
},
},
{
"term": util.MapStr{
"status": util.MapStr{
"value": model.NotificationStatusNew,
},
},
},
},
},
},
"script": util.MapStr{
"source": fmt.Sprintf("ctx._source['status'] = '%s';ctx._source['updated'] = '%s'", model.NotificationStatusRead, now),
},
}
err = orm.UpdateBy(model.Notification{}, util.MustToJSONBytes(queryDsl))
if err != nil {
log.Errorf("failed to update notifications, err: %v", err)
h.WriteError(w, "update notifications failed", http.StatusInternalServerError)
return
}
h.WriteAckOKJSON(w)
}

View File

@ -7,6 +7,11 @@ package migration
import ( import (
"context" "context"
"fmt" "fmt"
"net/http"
"strconv"
"strings"
"time"
log "github.com/cihub/seelog" log "github.com/cihub/seelog"
"infini.sh/console/model" "infini.sh/console/model"
"infini.sh/framework/core/api" "infini.sh/framework/core/api"
@ -17,16 +22,10 @@ import (
"infini.sh/framework/core/orm" "infini.sh/framework/core/orm"
task2 "infini.sh/framework/core/task" task2 "infini.sh/framework/core/task"
"infini.sh/framework/core/util" "infini.sh/framework/core/util"
"net/http"
"strconv"
"strings"
"time"
) )
func InitAPI() { func InitAPI() {
handler := APIHandler{ handler := APIHandler{}
}
api.HandleAPIMethod(api.GET, "/migration/data/_search", handler.RequireLogin(handler.searchDataMigrationTask)) api.HandleAPIMethod(api.GET, "/migration/data/_search", handler.RequireLogin(handler.searchDataMigrationTask))
api.HandleAPIMethod(api.POST, "/migration/data", handler.RequireLogin(handler.createDataMigrationTask)) api.HandleAPIMethod(api.POST, "/migration/data", handler.RequireLogin(handler.createDataMigrationTask))
api.HandleAPIMethod(api.POST, "/migration/data/_validate", handler.RequireLogin(handler.validateDataMigration)) api.HandleAPIMethod(api.POST, "/migration/data/_validate", handler.RequireLogin(handler.validateDataMigration))
@ -591,7 +590,7 @@ func getMajorTaskInfoByIndex(taskID string) (map[string]IndexStateInfo, error){
return resBody, nil return resBody, nil
} }
func getIndexTaskDocCount(index *IndexConfig, targetESClient elastic.API) (int64, error) { func getIndexTaskDocCount(ctx context.Context, index *IndexConfig, targetESClient elastic.API) (int64, error) {
targetIndexName := index.Target.Name targetIndexName := index.Target.Name
if targetIndexName == "" { if targetIndexName == "" {
if v, ok := index.IndexRename[index.Source.Name].(string); ok { if v, ok := index.IndexRename[index.Source.Name].(string); ok {
@ -622,8 +621,6 @@ func getIndexTaskDocCount(index *IndexConfig, targetESClient elastic.API) (int64
body = util.MustToJSONBytes(query) body = util.MustToJSONBytes(query)
} }
ctx, cancel := context.WithTimeout(context.Background(), time.Second*3)
defer cancel()
countRes, err := targetESClient.Count(ctx, targetIndexName, body) countRes, err := targetESClient.Count(ctx, targetIndexName, body)
if err != nil { if err != nil {
return 0, err return 0, err
@ -893,8 +890,8 @@ func (h *APIHandler) countDocuments(w http.ResponseWriter, req *http.Request, ps
}) })
} }
ctx, cancel := context.WithTimeout(context.Background(), time.Second*5) ctx := req.Context()
defer cancel()
countRes, err := client.Count(ctx, index, query) countRes, err := client.Count(ctx, index, query)
if err != nil { if err != nil {
log.Error(err) log.Error(err)
@ -1125,7 +1122,6 @@ func getMajorTaskStatsFromInstances(majorTaskID string) (taskStats MajorTaskStat
}, },
}, },
}, },
}, },
}, },
}, },

View File

@ -1503,7 +1503,8 @@ func (p *DispatcherProcessor) sendMajorTaskNotification(taskItem *task2.Task) {
} }
notification := &model.Notification{ notification := &model.Notification{
UserId: util.ToString(creatorID), UserId: util.ToString(creatorID),
NotificationType: model.NotificationTypeDataMigration, NotificationType: model.NotificationTypeNotification,
MessageType: model.MessageTypeMigration,
Status: model.NotificationStatusNew, Status: model.NotificationStatusNew,
Title: title, Title: title,
Body: body, Body: body,