[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>
Этот коммит содержится в:
Daniel Espino García
2022-03-02 12:15:58 +01:00
коммит произвёл GitHub
родитель 7e2ae93231
Коммит 32e3c2f0b8
7 изменённых файлов: 131 добавлений и 29 удалений

Просмотреть файл

@@ -183,6 +183,10 @@ func getSystemPing(c *Context, w http.ResponseWriter, r *http.Request) {
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 {
w.WriteHeader(http.StatusInternalServerError)
}

Просмотреть файл

@@ -96,6 +96,17 @@ func TestGetPing(t *testing.T) {
respString = string(respBytes)
require.Contains(t, respString, "testvalue")
}, "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) {

Просмотреть файл

@@ -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)
SendPasswordReset(email string, siteURL string) (bool, *model.AppError)
SendPaymentFailedEmail(failedPayment *model.FailedPayment) *model.AppError
SendTestPushNotification(deviceID string) string
ServeInterPluginRequest(w http.ResponseWriter, r *http.Request, sourcePluginId, destinationPluginId string)
SessionHasPermissionTo(session model.Session, permission *model.Permission) bool
SessionHasPermissionToAny(session model.Session, permissions []*model.Permission) bool

Просмотреть файл

@@ -379,6 +379,32 @@ func (s *Server) StopPushNotificationsHubWorkers() {
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 {
msg.ServerId = a.TelemetryId()
@@ -390,28 +416,11 @@ func (a *App) sendToPushProxy(msg *model.PushNotification, session *model.Sessio
mlog.String("status", model.PushSendPrepare),
)
msgJSON, jsonErr := json.Marshal(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))
pushResponse, err := a.rawSendToPushProxy(msg)
if err != nil {
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] {
case model.PushStatusRemove:
a.AttachDeviceId(session.Id, "", session.ExpiresAt)
@@ -568,6 +577,40 @@ func (a *App) BuildPushNotificationMessage(contentsConfig string, post *model.Po
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 {
userLocale := i18n.GetUserTranslations(user.Locale)
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
if _, ok := h.t.(*testing.B); ok {
resp := model.NewOkPushResponse()
jsonData, _ := json.Marshal(&resp)
fmt.Fprintln(w, jsonData)
h.printResponse(w, model.NewOkPushResponse())
return
}
@@ -1042,9 +1040,7 @@ func (h *testPushNotificationHandler) handleReq(w http.ResponseWriter, r *http.R
var err error
if r.URL.Path == "/api/v1/send_push" {
if err = json.NewDecoder(r.Body).Decode(&notification); err != nil {
resp := model.NewErrorPushResponse("fail")
jsonData, _ := json.Marshal(&resp)
fmt.Fprintln(w, jsonData)
h.printResponse(w, model.NewErrorPushResponse("fail"))
return
}
// 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 {
if err = json.NewDecoder(r.Body).Decode(&notificationAck); err != nil {
resp := model.NewErrorPushResponse("fail")
jsonData, _ := json.Marshal(&resp)
fmt.Fprintln(w, jsonData)
h.printResponse(w, model.NewErrorPushResponse("fail"))
return
}
}
@@ -1086,11 +1080,15 @@ func (h *testPushNotificationHandler) handleReq(w http.ResponseWriter, r *http.R
resp = model.NewRemovePushResponse()
}
}
jsonData, _ := json.Marshal(&resp)
fmt.Fprintln(w, jsonData)
h.printResponse(w, resp)
}
}
func (h *testPushNotificationHandler) printResponse(w http.ResponseWriter, resp model.PushResponse) {
jsonData, _ := json.Marshal(&resp)
fmt.Fprintln(w, string(jsonData))
}
func (h *testPushNotificationHandler) numReqs() int {
h.mut.RLock()
defer h.mut.RUnlock()
@@ -1239,6 +1237,33 @@ func TestUpdateMobileAppBadgeSync(t *testing.T) {
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) {
th := SetupWithStoreMock(t)
defer th.TearDown()

Просмотреть файл

@@ -14637,6 +14637,23 @@ func (a *OpenTracingAppLayer) SendPaymentFailedEmail(failedPayment *model.Failed
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) {
origCtx := a.ctx
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.ServeInterPluginRequest")

Просмотреть файл

@@ -17,6 +17,7 @@ const (
PushTypeClear = "clear"
PushTypeUpdateBadge = "update_badge"
PushTypeSession = "session"
PushTypeTest = "test"
PushMessageV2 = "v2"
PushSoundNone = "none"