[Gekidou] Add push notification check to ping (#19610)
* Add push notification check to ping * Add test type and missing details * Address feedback * Fix function name * Address feedback Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
7e2ae93231
Коммит
32e3c2f0b8
@@ -183,6 +183,10 @@ func getSystemPing(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Header().Set(filestoreStatusKey, s[filestoreStatusKey])
|
w.Header().Set(filestoreStatusKey, s[filestoreStatusKey])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if deviceID := r.FormValue("device_id"); deviceID != "" {
|
||||||
|
s["CanReceiveNotifications"] = c.App.SendTestPushNotification(deviceID)
|
||||||
|
}
|
||||||
|
|
||||||
if s[model.STATUS] != model.StatusOk {
|
if s[model.STATUS] != model.StatusOk {
|
||||||
w.WriteHeader(http.StatusInternalServerError)
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -96,6 +96,17 @@ func TestGetPing(t *testing.T) {
|
|||||||
respString = string(respBytes)
|
respString = string(respBytes)
|
||||||
require.Contains(t, respString, "testvalue")
|
require.Contains(t, respString, "testvalue")
|
||||||
}, "ping feature flag test")
|
}, "ping feature flag test")
|
||||||
|
|
||||||
|
th.TestForAllClients(t, func(t *testing.T, client *model.Client4) {
|
||||||
|
th.App.ReloadConfig()
|
||||||
|
resp, err := client.DoAPIGet("/system/ping?device_id=platform:id", "")
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, http.StatusOK, resp.StatusCode)
|
||||||
|
var respMap map[string]string
|
||||||
|
err = json.NewDecoder(resp.Body).Decode(&respMap)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, "unknown", respMap["CanReceiveNotifications"]) // Unrecognized platform
|
||||||
|
}, "ping and test push notification")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestGetAudits(t *testing.T) {
|
func TestGetAudits(t *testing.T) {
|
||||||
|
|||||||
@@ -977,6 +977,7 @@ type AppIface interface {
|
|||||||
SendNotifications(post *model.Post, team *model.Team, channel *model.Channel, sender *model.User, parentPostList *model.PostList, setOnline bool) ([]string, error)
|
SendNotifications(post *model.Post, team *model.Team, channel *model.Channel, sender *model.User, parentPostList *model.PostList, setOnline bool) ([]string, error)
|
||||||
SendPasswordReset(email string, siteURL string) (bool, *model.AppError)
|
SendPasswordReset(email string, siteURL string) (bool, *model.AppError)
|
||||||
SendPaymentFailedEmail(failedPayment *model.FailedPayment) *model.AppError
|
SendPaymentFailedEmail(failedPayment *model.FailedPayment) *model.AppError
|
||||||
|
SendTestPushNotification(deviceID string) string
|
||||||
ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId, destinationPluginId string)
|
ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId, destinationPluginId string)
|
||||||
SessionHasPermissionTo(session model.Session, permission *model.Permission) bool
|
SessionHasPermissionTo(session model.Session, permission *model.Permission) bool
|
||||||
SessionHasPermissionToAny(session model.Session, permissions []*model.Permission) bool
|
SessionHasPermissionToAny(session model.Session, permissions []*model.Permission) bool
|
||||||
|
|||||||
@@ -379,6 +379,32 @@ func (s *Server) StopPushNotificationsHubWorkers() {
|
|||||||
s.PushNotificationsHub.stop()
|
s.PushNotificationsHub.stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) rawSendToPushProxy(msg *model.PushNotification) (model.PushResponse, error) {
|
||||||
|
msgJSON, jsonErr := json.Marshal(msg)
|
||||||
|
if jsonErr != nil {
|
||||||
|
return nil, errors.Wrap(jsonErr, "failed to encode to JSON")
|
||||||
|
}
|
||||||
|
|
||||||
|
url := strings.TrimRight(*a.Config().EmailSettings.PushNotificationServer, "/") + model.APIURLSuffixV1 + "/send_push"
|
||||||
|
request, err := http.NewRequest("POST", url, bytes.NewReader(msgJSON))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := a.Srv().pushNotificationClient.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
var pushResponse model.PushResponse
|
||||||
|
if jsonErr := json.NewDecoder(resp.Body).Decode(&pushResponse); jsonErr != nil {
|
||||||
|
return nil, errors.Wrap(jsonErr, "failed to decode from JSON")
|
||||||
|
}
|
||||||
|
|
||||||
|
return pushResponse, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) sendToPushProxy(msg *model.PushNotification, session *model.Session) error {
|
func (a *App) sendToPushProxy(msg *model.PushNotification, session *model.Session) error {
|
||||||
msg.ServerId = a.TelemetryId()
|
msg.ServerId = a.TelemetryId()
|
||||||
|
|
||||||
@@ -390,28 +416,11 @@ func (a *App) sendToPushProxy(msg *model.PushNotification, session *model.Sessio
|
|||||||
mlog.String("status", model.PushSendPrepare),
|
mlog.String("status", model.PushSendPrepare),
|
||||||
)
|
)
|
||||||
|
|
||||||
msgJSON, jsonErr := json.Marshal(msg)
|
pushResponse, err := a.rawSendToPushProxy(msg)
|
||||||
if jsonErr != nil {
|
|
||||||
return errors.Wrap(jsonErr, "failed to encode to JSON")
|
|
||||||
}
|
|
||||||
|
|
||||||
url := strings.TrimRight(*a.Config().EmailSettings.PushNotificationServer, "/") + model.APIURLSuffixV1 + "/send_push"
|
|
||||||
request, err := http.NewRequest("POST", url, bytes.NewReader(msgJSON))
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := a.Srv().pushNotificationClient.Do(request)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
var pushResponse model.PushResponse
|
|
||||||
if jsonErr := json.NewDecoder(resp.Body).Decode(&pushResponse); jsonErr != nil {
|
|
||||||
return errors.Wrap(jsonErr, "failed to decode from JSON")
|
|
||||||
}
|
|
||||||
|
|
||||||
switch pushResponse[model.PushStatus] {
|
switch pushResponse[model.PushStatus] {
|
||||||
case model.PushStatusRemove:
|
case model.PushStatusRemove:
|
||||||
a.AttachDeviceId(session.Id, "", session.ExpiresAt)
|
a.AttachDeviceId(session.Id, "", session.ExpiresAt)
|
||||||
@@ -568,6 +577,40 @@ func (a *App) BuildPushNotificationMessage(contentsConfig string, post *model.Po
|
|||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) SendTestPushNotification(deviceID string) string {
|
||||||
|
msg := &model.PushNotification{
|
||||||
|
Version: "2",
|
||||||
|
Type: model.PushTypeTest,
|
||||||
|
ServerId: a.TelemetryId(),
|
||||||
|
Badge: -1,
|
||||||
|
}
|
||||||
|
msg.SetDeviceIdAndPlatform(deviceID)
|
||||||
|
|
||||||
|
pushResponse, err := a.rawSendToPushProxy(msg)
|
||||||
|
if err != nil {
|
||||||
|
a.NotificationsLog().Error("Notification error",
|
||||||
|
mlog.String("type", msg.Type),
|
||||||
|
mlog.String("deviceId", msg.DeviceId),
|
||||||
|
mlog.String("status", err.Error()),
|
||||||
|
)
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
switch pushResponse[model.PushStatus] {
|
||||||
|
case model.PushStatusRemove:
|
||||||
|
return "false"
|
||||||
|
case model.PushStatusFail:
|
||||||
|
a.NotificationsLog().Error("Notification error",
|
||||||
|
mlog.String("type", msg.Type),
|
||||||
|
mlog.String("deviceId", msg.DeviceId),
|
||||||
|
mlog.String("status", pushResponse[model.PushStatusErrorMsg]),
|
||||||
|
)
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
|
||||||
|
return "true"
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) buildIdLoadedPushNotificationMessage(channel *model.Channel, post *model.Post, user *model.User) *model.PushNotification {
|
func (a *App) buildIdLoadedPushNotificationMessage(channel *model.Channel, post *model.Post, user *model.User) *model.PushNotification {
|
||||||
userLocale := i18n.GetUserTranslations(user.Locale)
|
userLocale := i18n.GetUserTranslations(user.Locale)
|
||||||
msg := &model.PushNotification{
|
msg := &model.PushNotification{
|
||||||
|
|||||||
@@ -1031,9 +1031,7 @@ func (h *testPushNotificationHandler) handleReq(w http.ResponseWriter, r *http.R
|
|||||||
|
|
||||||
// Don't do any checking if it's a benchmark
|
// Don't do any checking if it's a benchmark
|
||||||
if _, ok := h.t.(*testing.B); ok {
|
if _, ok := h.t.(*testing.B); ok {
|
||||||
resp := model.NewOkPushResponse()
|
h.printResponse(w, model.NewOkPushResponse())
|
||||||
jsonData, _ := json.Marshal(&resp)
|
|
||||||
fmt.Fprintln(w, jsonData)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1042,9 +1040,7 @@ func (h *testPushNotificationHandler) handleReq(w http.ResponseWriter, r *http.R
|
|||||||
var err error
|
var err error
|
||||||
if r.URL.Path == "/api/v1/send_push" {
|
if r.URL.Path == "/api/v1/send_push" {
|
||||||
if err = json.NewDecoder(r.Body).Decode(¬ification); err != nil {
|
if err = json.NewDecoder(r.Body).Decode(¬ification); err != nil {
|
||||||
resp := model.NewErrorPushResponse("fail")
|
h.printResponse(w, model.NewErrorPushResponse("fail"))
|
||||||
jsonData, _ := json.Marshal(&resp)
|
|
||||||
fmt.Fprintln(w, jsonData)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
// We verify that messages are being sent in order per-device.
|
// We verify that messages are being sent in order per-device.
|
||||||
@@ -1057,9 +1053,7 @@ func (h *testPushNotificationHandler) handleReq(w http.ResponseWriter, r *http.R
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if err = json.NewDecoder(r.Body).Decode(¬ificationAck); err != nil {
|
if err = json.NewDecoder(r.Body).Decode(¬ificationAck); err != nil {
|
||||||
resp := model.NewErrorPushResponse("fail")
|
h.printResponse(w, model.NewErrorPushResponse("fail"))
|
||||||
jsonData, _ := json.Marshal(&resp)
|
|
||||||
fmt.Fprintln(w, jsonData)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1086,11 +1080,15 @@ func (h *testPushNotificationHandler) handleReq(w http.ResponseWriter, r *http.R
|
|||||||
resp = model.NewRemovePushResponse()
|
resp = model.NewRemovePushResponse()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
jsonData, _ := json.Marshal(&resp)
|
h.printResponse(w, resp)
|
||||||
fmt.Fprintln(w, jsonData)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h *testPushNotificationHandler) printResponse(w http.ResponseWriter, resp model.PushResponse) {
|
||||||
|
jsonData, _ := json.Marshal(&resp)
|
||||||
|
fmt.Fprintln(w, string(jsonData))
|
||||||
|
}
|
||||||
|
|
||||||
func (h *testPushNotificationHandler) numReqs() int {
|
func (h *testPushNotificationHandler) numReqs() int {
|
||||||
h.mut.RLock()
|
h.mut.RLock()
|
||||||
defer h.mut.RUnlock()
|
defer h.mut.RUnlock()
|
||||||
@@ -1239,6 +1237,33 @@ func TestUpdateMobileAppBadgeSync(t *testing.T) {
|
|||||||
assert.Equal(t, model.PushTypeUpdateBadge, handler.notifications()[1].Type)
|
assert.Equal(t, model.PushTypeUpdateBadge, handler.notifications()[1].Type)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSendTestPushNotification(t *testing.T) {
|
||||||
|
th := Setup(t)
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
handler := &testPushNotificationHandler{t: t}
|
||||||
|
pushServer := httptest.NewServer(
|
||||||
|
http.HandlerFunc(handler.handleReq),
|
||||||
|
)
|
||||||
|
defer pushServer.Close()
|
||||||
|
|
||||||
|
th.App.UpdateConfig(func(cfg *model.Config) {
|
||||||
|
*cfg.EmailSettings.PushNotificationServer = pushServer.URL
|
||||||
|
})
|
||||||
|
|
||||||
|
// Per mock definition, first time will send remove, second time will send OK
|
||||||
|
result := th.App.SendTestPushNotification("platform:id")
|
||||||
|
assert.Equal(t, "false", result)
|
||||||
|
result = th.App.SendTestPushNotification("platform:id")
|
||||||
|
assert.Equal(t, "true", result)
|
||||||
|
|
||||||
|
// Server side verification.
|
||||||
|
// We verify that 2 requests have been sent, and also check the message contents.
|
||||||
|
require.Equal(t, 2, handler.numReqs())
|
||||||
|
assert.Equal(t, model.PushTypeTest, handler.notifications()[0].Type)
|
||||||
|
assert.Equal(t, model.PushTypeTest, handler.notifications()[1].Type)
|
||||||
|
}
|
||||||
|
|
||||||
func TestSendAckToPushProxy(t *testing.T) {
|
func TestSendAckToPushProxy(t *testing.T) {
|
||||||
th := SetupWithStoreMock(t)
|
th := SetupWithStoreMock(t)
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|||||||
@@ -14637,6 +14637,23 @@ func (a *OpenTracingAppLayer) SendPaymentFailedEmail(failedPayment *model.Failed
|
|||||||
return resultVar0
|
return resultVar0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *OpenTracingAppLayer) SendTestPushNotification(deviceID string) string {
|
||||||
|
origCtx := a.ctx
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.SendTestPushNotification")
|
||||||
|
|
||||||
|
a.ctx = newCtx
|
||||||
|
a.app.Srv().Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
a.app.Srv().Store.SetContext(origCtx)
|
||||||
|
a.ctx = origCtx
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
resultVar0 := a.app.SendTestPushNotification(deviceID)
|
||||||
|
|
||||||
|
return resultVar0
|
||||||
|
}
|
||||||
|
|
||||||
func (a *OpenTracingAppLayer) ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId string, destinationPluginId string) {
|
func (a *OpenTracingAppLayer) ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId string, destinationPluginId string) {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ServeInterPluginRequest")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ServeInterPluginRequest")
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ const (
|
|||||||
PushTypeClear = "clear"
|
PushTypeClear = "clear"
|
||||||
PushTypeUpdateBadge = "update_badge"
|
PushTypeUpdateBadge = "update_badge"
|
||||||
PushTypeSession = "session"
|
PushTypeSession = "session"
|
||||||
|
PushTypeTest = "test"
|
||||||
PushMessageV2 = "v2"
|
PushMessageV2 = "v2"
|
||||||
|
|
||||||
PushSoundNone = "none"
|
PushSoundNone = "none"
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user