PLT-7444: If there is activity in Mattermost before the email batch is sent, do not send the email (#7342)

* Changed email batching short-circuit logic to look at last viewed at timestamp in channel member struct instead of in user's status struct, since the latter is only updated if the user's status is set to online

* Fixed unit tests

* Reduced right-hand drift

* Reduced total number of store calls by loading all channel member objects for user exactly once per team that the user received notifications for
Этот коммит содержится в:
Jonathan
2017-09-05 16:39:07 -04:00
коммит произвёл Joram Wilander
родитель 2977b31a39
Коммит 016b5daa1c
3 изменённых файлов: 74 добавлений и 57 удалений

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

@@ -122,24 +122,42 @@ func (job *EmailBatchingJob) handleNewNotifications() {
}
func (job *EmailBatchingJob) checkPendingNotifications(now time.Time, handler func(string, []*batchedNotification)) {
// look for users who've acted since pending posts were received
for userId, notifications := range job.pendingNotifications {
schan := Srv.Store.Status().Get(userId)
pchan := Srv.Store.Preference().Get(userId, model.PREFERENCE_CATEGORY_NOTIFICATIONS, model.PREFERENCE_NAME_EMAIL_INTERVAL)
batchStartTime := notifications[0].post.CreateAt
inspectedTeamNames := make(map[string]string)
for _, notification := range notifications {
// at most, we'll do one check for each team that notifications were sent for
if inspectedTeamNames[notification.teamName] != "" {
continue
}
tchan := Srv.Store.Team().GetByName(notifications[0].teamName)
if result := <-tchan; result.Err != nil {
l4g.Error("Unable to find Team id for notification", result.Err)
continue
} else if team, ok := result.Data.(*model.Team); ok {
inspectedTeamNames[notification.teamName] = team.Id
}
// check if the user has been active and would've seen any new posts
if result := <-schan; result.Err != nil {
l4g.Error(utils.T("api.email_batching.check_pending_emails.status.app_error"), result.Err)
delete(job.pendingNotifications, userId)
continue
} else if status := result.Data.(*model.Status); status.LastActivityAt >= batchStartTime {
delete(job.pendingNotifications, userId)
continue
// if the user has viewed any channels in this team since the notification was queued, delete
// all queued notifications
mchan := Srv.Store.Channel().GetMembersForUser(inspectedTeamNames[notification.teamName], userId)
if result := <-mchan; result.Err != nil {
l4g.Error("Unable to find ChannelMembers for user", result.Err)
continue
} else if channelMembers, ok := result.Data.(*model.ChannelMembers); ok {
for _, channelMember := range *channelMembers {
if channelMember.LastViewedAt >= batchStartTime {
l4g.Info("Deleted notifications for user %s", userId)
delete(job.pendingNotifications, userId)
break
}
}
}
}
// get how long we need to wait to send notifications to the user
var interval int64
pchan := Srv.Store.Preference().Get(userId, model.PREFERENCE_CATEGORY_NOTIFICATIONS, model.PREFERENCE_NAME_EMAIL_INTERVAL)
if result := <-pchan; result.Err != nil {
// use the default batching interval if an error ocurrs while fetching user preferences
interval, _ = strconv.ParseInt(model.PREFERENCE_EMAIL_INTERVAL_BATCHING_SECONDS, 10, 64)