MM-14532 Send "clear" notification to every other session (#10459)
Этот коммит содержится в:
коммит произвёл
Jesús Espino
родитель
078e678a34
Коммит
4cc75fc062
@@ -975,7 +975,7 @@ func viewChannel(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
times, err := c.App.ViewChannel(view, c.Params.UserId, !c.App.Session.IsMobileApp())
|
||||
times, err := c.App.ViewChannel(view, c.Params.UserId, c.App.Session.Id)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
@@ -1137,7 +1137,7 @@ func addChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
cm, err := c.App.AddChannelMember(member.UserId, channel, c.App.Session.UserId, postRootId, !c.App.Session.IsMobileApp())
|
||||
cm, err := c.App.AddChannelMember(member.UserId, channel, c.App.Session.UserId, postRootId, c.App.Session.Id)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
|
||||
@@ -57,7 +57,7 @@ func createPost(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||
post.CreateAt = 0
|
||||
}
|
||||
|
||||
rp, err := c.App.CreatePostAsUser(c.App.PostWithProxyRemovedFromImageURLs(post), !c.App.Session.IsMobileApp())
|
||||
rp, err := c.App.CreatePostAsUser(c.App.PostWithProxyRemovedFromImageURLs(post), c.App.Session.Id)
|
||||
if err != nil {
|
||||
c.Err = err
|
||||
return
|
||||
|
||||
@@ -903,7 +903,7 @@ func (a *App) AddUserToChannel(user *model.User, channel *model.Channel) (*model
|
||||
return newMember, nil
|
||||
}
|
||||
|
||||
func (a *App) AddChannelMember(userId string, channel *model.Channel, userRequestorId string, postRootId string, clearPushNotifications bool) (*model.ChannelMember, *model.AppError) {
|
||||
func (a *App) AddChannelMember(userId string, channel *model.Channel, userRequestorId string, postRootId string, currentSessionId string) (*model.ChannelMember, *model.AppError) {
|
||||
if result := <-a.Srv.Store.Channel().GetMember(channel.Id, userId); result.Err != nil {
|
||||
if result.Err.Id != store.MISSING_CHANNEL_MEMBER_ERROR {
|
||||
return nil, result.Err
|
||||
@@ -959,7 +959,7 @@ func (a *App) AddChannelMember(userId string, channel *model.Channel, userReques
|
||||
}
|
||||
|
||||
if userRequestor != nil {
|
||||
a.MarkChannelsAsViewed([]string{channel.Id}, userRequestor.Id, clearPushNotifications)
|
||||
a.MarkChannelsAsViewed([]string{channel.Id}, userRequestor.Id, currentSessionId)
|
||||
}
|
||||
|
||||
return cm, nil
|
||||
@@ -1747,10 +1747,10 @@ func (a *App) SearchChannelsUserNotIn(teamId string, userId string, term string)
|
||||
return result.Data.(*model.ChannelList), nil
|
||||
}
|
||||
|
||||
func (a *App) MarkChannelsAsViewed(channelIds []string, userId string, clearPushNotifications bool) (map[string]int64, *model.AppError) {
|
||||
func (a *App) MarkChannelsAsViewed(channelIds []string, userId string, currentSessionId string) (map[string]int64, *model.AppError) {
|
||||
// I start looking for channels with notifications before I mark it as read, to clear the push notifications if needed
|
||||
channelsToClearPushNotifications := []string{}
|
||||
if *a.Config().EmailSettings.SendPushNotifications && clearPushNotifications {
|
||||
if *a.Config().EmailSettings.SendPushNotifications {
|
||||
for _, channelId := range channelIds {
|
||||
chanResult := <-a.Srv.Store.Channel().Get(channelId, true)
|
||||
if chanResult.Err != nil {
|
||||
@@ -1801,12 +1801,12 @@ func (a *App) MarkChannelsAsViewed(channelIds []string, userId string, clearPush
|
||||
}
|
||||
}
|
||||
for _, channelId := range channelsToClearPushNotifications {
|
||||
a.ClearPushNotification(userId, channelId)
|
||||
a.ClearPushNotification(currentSessionId, userId, channelId)
|
||||
}
|
||||
return times, nil
|
||||
}
|
||||
|
||||
func (a *App) ViewChannel(view *model.ChannelView, userId string, clearPushNotifications bool) (map[string]int64, *model.AppError) {
|
||||
func (a *App) ViewChannel(view *model.ChannelView, userId string, currentSessionId string) (map[string]int64, *model.AppError) {
|
||||
if err := a.SetActiveChannel(userId, view.ChannelId); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -1825,7 +1825,7 @@ func (a *App) ViewChannel(view *model.ChannelView, userId string, clearPushNotif
|
||||
return map[string]int64{}, nil
|
||||
}
|
||||
|
||||
return a.MarkChannelsAsViewed(channelIds, userId, clearPushNotifications)
|
||||
return a.MarkChannelsAsViewed(channelIds, userId, currentSessionId)
|
||||
}
|
||||
|
||||
func (a *App) PermanentDeleteChannel(channel *model.Channel) *model.AppError {
|
||||
|
||||
@@ -438,7 +438,7 @@ func TestAddChannelMemberNoUserRequestor(t *testing.T) {
|
||||
channel := th.createChannel(th.BasicTeam, model.CHANNEL_OPEN)
|
||||
userRequestorId := ""
|
||||
postRootId := ""
|
||||
if _, err := th.App.AddChannelMember(user.Id, channel, userRequestorId, postRootId, false); err != nil {
|
||||
if _, err := th.App.AddChannelMember(user.Id, channel, userRequestorId, postRootId, ""); err != nil {
|
||||
t.Fatal("Failed to add user to channel. Error: " + err.Message)
|
||||
}
|
||||
|
||||
@@ -738,7 +738,7 @@ func TestGetChannelMembersTimezones(t *testing.T) {
|
||||
|
||||
userRequestorId := ""
|
||||
postRootId := ""
|
||||
if _, err := th.App.AddChannelMember(th.BasicUser2.Id, th.BasicChannel, userRequestorId, postRootId, false); err != nil {
|
||||
if _, err := th.App.AddChannelMember(th.BasicUser2.Id, th.BasicChannel, userRequestorId, postRootId, ""); err != nil {
|
||||
t.Fatal("Failed to add user to channel. Error: " + err.Message)
|
||||
}
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@ func (me *InviteProvider) DoCommand(a *App, args *model.CommandArgs, message str
|
||||
}
|
||||
}
|
||||
|
||||
if _, err := a.AddChannelMember(userProfile.Id, channelToJoin, args.Session.UserId, "", !args.Session.IsMobileApp()); err != nil {
|
||||
if _, err := a.AddChannelMember(userProfile.Id, channelToJoin, args.Session.UserId, "", args.Session.Id); err != nil {
|
||||
return &model.CommandResponse{
|
||||
Text: args.T("api.command_invite.fail.app_error"),
|
||||
ResponseType: model.COMMAND_RESPONSE_TYPE_EPHEMERAL,
|
||||
|
||||
@@ -55,7 +55,7 @@ func TestPostActionInvalidURL(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
post, err := th.App.CreatePostAsUser(&interactivePost, false)
|
||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||
require.Nil(t, err)
|
||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
||||
require.True(t, ok)
|
||||
@@ -122,7 +122,7 @@ func TestPostAction(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
post, err := th.App.CreatePostAsUser(&interactivePost, false)
|
||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||
require.Nil(t, err)
|
||||
|
||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
||||
@@ -159,7 +159,7 @@ func TestPostAction(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
post2, err := th.App.CreatePostAsUser(&menuPost, false)
|
||||
post2, err := th.App.CreatePostAsUser(&menuPost, "")
|
||||
require.Nil(t, err)
|
||||
|
||||
attachments2, ok := post2.Props["attachments"].([]*model.SlackAttachment)
|
||||
@@ -217,7 +217,7 @@ func TestPostAction(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
postplugin, err := th.App.CreatePostAsUser(&interactivePostPlugin, false)
|
||||
postplugin, err := th.App.CreatePostAsUser(&interactivePostPlugin, "")
|
||||
require.Nil(t, err)
|
||||
|
||||
attachmentsPlugin, ok := postplugin.Props["attachments"].([]*model.SlackAttachment)
|
||||
@@ -258,7 +258,7 @@ func TestPostAction(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
postSiteURL, err := th.App.CreatePostAsUser(&interactivePostSiteURL, false)
|
||||
postSiteURL, err := th.App.CreatePostAsUser(&interactivePostSiteURL, "")
|
||||
require.Nil(t, err)
|
||||
|
||||
attachmentsSiteURL, ok := postSiteURL.Props["attachments"].([]*model.SlackAttachment)
|
||||
@@ -300,7 +300,7 @@ func TestPostAction(t *testing.T) {
|
||||
},
|
||||
}
|
||||
|
||||
postSubpath, err := th.App.CreatePostAsUser(&interactivePostSubpath, false)
|
||||
postSubpath, err := th.App.CreatePostAsUser(&interactivePostSubpath, "")
|
||||
require.Nil(t, err)
|
||||
|
||||
attachmentsSubpath, ok := postSubpath.Props["attachments"].([]*model.SlackAttachment)
|
||||
|
||||
@@ -29,6 +29,7 @@ type PushNotificationsHub struct {
|
||||
|
||||
type PushNotification struct {
|
||||
notificationType NotificationType
|
||||
currentSessionId string
|
||||
userId string
|
||||
channelId string
|
||||
post *model.Post
|
||||
@@ -189,7 +190,7 @@ func (a *App) getPushNotificationMessage(postMessage string, explicitMention, ch
|
||||
return "@" + senderName + userLocale("api.post.send_notifications_and_forget.push_general_message")
|
||||
}
|
||||
|
||||
func (a *App) ClearPushNotificationSync(userId string, channelId string) {
|
||||
func (a *App) ClearPushNotificationSync(currentSessionId, userId, channelId string) {
|
||||
sessions, err := a.getMobileAppSessions(userId)
|
||||
if err != nil {
|
||||
mlog.Error(err.Error())
|
||||
@@ -207,19 +208,21 @@ func (a *App) ClearPushNotificationSync(userId string, channelId string) {
|
||||
msg.Badge = int(badge.Data.(int64))
|
||||
}
|
||||
|
||||
mlog.Debug(fmt.Sprintf("Clearing push notification to %v with channel_id %v", msg.DeviceId, msg.ChannelId))
|
||||
|
||||
for _, session := range sessions {
|
||||
tmpMessage := *model.PushNotificationFromJson(strings.NewReader(msg.ToJson()))
|
||||
tmpMessage.SetDeviceIdAndPlatform(session.DeviceId)
|
||||
a.sendToPushProxy(tmpMessage, session)
|
||||
if currentSessionId != session.Id {
|
||||
tmpMessage := *model.PushNotificationFromJson(strings.NewReader(msg.ToJson()))
|
||||
tmpMessage.SetDeviceIdAndPlatform(session.DeviceId)
|
||||
mlog.Debug(fmt.Sprintf("Clearing push notification to %v with channel_id %v", session.DeviceId, msg.ChannelId))
|
||||
a.sendToPushProxy(tmpMessage, session)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (a *App) ClearPushNotification(userId string, channelId string) {
|
||||
func (a *App) ClearPushNotification(currentSessionId, userId, channelId string) {
|
||||
channel := a.Srv.PushNotificationsHub.GetGoChannelFromUserId(userId)
|
||||
channel <- PushNotification{
|
||||
notificationType: NOTIFICATION_TYPE_CLEAR,
|
||||
currentSessionId: currentSessionId,
|
||||
userId: userId,
|
||||
channelId: channelId,
|
||||
}
|
||||
@@ -239,7 +242,7 @@ func (a *App) pushNotificationWorker(notifications chan PushNotification) {
|
||||
for notification := range notifications {
|
||||
switch notification.notificationType {
|
||||
case NOTIFICATION_TYPE_CLEAR:
|
||||
a.ClearPushNotificationSync(notification.userId, notification.channelId)
|
||||
a.ClearPushNotificationSync(notification.currentSessionId, notification.userId, notification.channelId)
|
||||
case NOTIFICATION_TYPE_MESSAGE:
|
||||
a.sendPushNotificationSync(
|
||||
notification.post,
|
||||
|
||||
@@ -376,7 +376,7 @@ func (api *PluginAPI) AddChannelMember(channelId, userId string) (*model.Channel
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return api.app.AddChannelMember(userId, channel, userRequestorId, postRootId, false)
|
||||
return api.app.AddChannelMember(userId, channel, userRequestorId, postRootId, "")
|
||||
}
|
||||
|
||||
func (api *PluginAPI) GetChannelMember(channelId, userId string) (*model.ChannelMember, *model.AppError) {
|
||||
|
||||
@@ -22,7 +22,7 @@ const (
|
||||
PENDING_POST_IDS_CACHE_TTL = 30 * time.Second
|
||||
)
|
||||
|
||||
func (a *App) CreatePostAsUser(post *model.Post, clearPushNotifications bool) (*model.Post, *model.AppError) {
|
||||
func (a *App) CreatePostAsUser(post *model.Post, currentSessionId string) (*model.Post, *model.AppError) {
|
||||
// Check that channel has not been deleted
|
||||
result := <-a.Srv.Store.Channel().Get(post.ChannelId, true)
|
||||
if result.Err != nil {
|
||||
@@ -74,7 +74,7 @@ func (a *App) CreatePostAsUser(post *model.Post, clearPushNotifications bool) (*
|
||||
|
||||
// Update the LastViewAt only if the post does not have from_webhook prop set (eg. Zapier app)
|
||||
if _, ok := post.Props["from_webhook"]; !ok {
|
||||
if _, err := a.MarkChannelsAsViewed([]string{post.ChannelId}, post.UserId, clearPushNotifications); err != nil {
|
||||
if _, err := a.MarkChannelsAsViewed([]string{post.ChannelId}, post.UserId, currentSessionId); err != nil {
|
||||
mlog.Error(fmt.Sprintf("Encountered error updating last viewed, channel_id=%s, user_id=%s, err=%v", post.ChannelId, post.UserId, err))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ func TestCreatePostDeduplicate(t *testing.T) {
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
Message: "message",
|
||||
PendingPostId: pendingPostId,
|
||||
}, false)
|
||||
}, "")
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, "message", post.Message)
|
||||
|
||||
@@ -38,7 +38,7 @@ func TestCreatePostDeduplicate(t *testing.T) {
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
Message: "message",
|
||||
PendingPostId: pendingPostId,
|
||||
}, false)
|
||||
}, "")
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, post.Id, duplicatePost.Id, "should have returned previously created post id")
|
||||
require.Equal(t, "message", duplicatePost.Message)
|
||||
@@ -78,7 +78,7 @@ func TestCreatePostDeduplicate(t *testing.T) {
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
Message: "message",
|
||||
PendingPostId: pendingPostId,
|
||||
}, false)
|
||||
}, "")
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, "Post rejected by plugin. rejected", err.Id)
|
||||
require.Nil(t, post)
|
||||
@@ -88,7 +88,7 @@ func TestCreatePostDeduplicate(t *testing.T) {
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
Message: "message",
|
||||
PendingPostId: pendingPostId,
|
||||
}, false)
|
||||
}, "")
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, "message", duplicatePost.Message)
|
||||
})
|
||||
@@ -138,7 +138,7 @@ func TestCreatePostDeduplicate(t *testing.T) {
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
Message: "plugin delayed",
|
||||
PendingPostId: pendingPostId,
|
||||
}, false)
|
||||
}, "")
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, post.Message, "plugin delayed")
|
||||
}()
|
||||
@@ -152,7 +152,7 @@ func TestCreatePostDeduplicate(t *testing.T) {
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
Message: "plugin delayed",
|
||||
PendingPostId: pendingPostId,
|
||||
}, false)
|
||||
}, "")
|
||||
require.NotNil(t, err)
|
||||
require.Equal(t, "api.post.deduplicate_create_post.pending", err.Id)
|
||||
require.Nil(t, duplicatePost)
|
||||
@@ -168,7 +168,7 @@ func TestCreatePostDeduplicate(t *testing.T) {
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
Message: "message",
|
||||
PendingPostId: pendingPostId,
|
||||
}, false)
|
||||
}, "")
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, "message", post.Message)
|
||||
|
||||
@@ -179,7 +179,7 @@ func TestCreatePostDeduplicate(t *testing.T) {
|
||||
ChannelId: th.BasicChannel.Id,
|
||||
Message: "message",
|
||||
PendingPostId: pendingPostId,
|
||||
}, false)
|
||||
}, "")
|
||||
require.Nil(t, err)
|
||||
require.NotEqual(t, post.Id, duplicatePost.Id, "should have created new post id")
|
||||
require.Equal(t, "message", duplicatePost.Message)
|
||||
@@ -350,7 +350,7 @@ func TestPostReplyToPostWhereRootPosterLeftChannel(t *testing.T) {
|
||||
CreateAt: 0,
|
||||
}
|
||||
|
||||
if _, err := th.App.CreatePostAsUser(&replyPost, false); err != nil {
|
||||
if _, err := th.App.CreatePostAsUser(&replyPost, ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -373,7 +373,7 @@ func TestPostAttachPostToChildPost(t *testing.T) {
|
||||
CreateAt: 0,
|
||||
}
|
||||
|
||||
res1, err := th.App.CreatePostAsUser(&replyPost1, false)
|
||||
res1, err := th.App.CreatePostAsUser(&replyPost1, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
@@ -388,7 +388,7 @@ func TestPostAttachPostToChildPost(t *testing.T) {
|
||||
CreateAt: 0,
|
||||
}
|
||||
|
||||
_, err = th.App.CreatePostAsUser(&replyPost2, false)
|
||||
_, err = th.App.CreatePostAsUser(&replyPost2, "")
|
||||
if err.StatusCode != http.StatusBadRequest {
|
||||
t.Fatal(fmt.Sprintf("Expected BadRequest error, got %v", err))
|
||||
}
|
||||
@@ -403,7 +403,7 @@ func TestPostAttachPostToChildPost(t *testing.T) {
|
||||
CreateAt: 0,
|
||||
}
|
||||
|
||||
if _, err := th.App.CreatePostAsUser(&replyPost3, false); err != nil {
|
||||
if _, err := th.App.CreatePostAsUser(&replyPost3, ""); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
@@ -437,7 +437,7 @@ func TestPostChannelMentions(t *testing.T) {
|
||||
CreateAt: 0,
|
||||
}
|
||||
|
||||
result, err := th.App.CreatePostAsUser(post, false)
|
||||
result, err := th.App.CreatePostAsUser(post, "")
|
||||
require.Nil(t, err)
|
||||
assert.Equal(t, map[string]interface{}{
|
||||
"mention-test": map[string]interface{}{
|
||||
|
||||
@@ -48,7 +48,7 @@ func (a *App) PopulateSyncablesSince(groupMembersCreatedAfter int64) error {
|
||||
mlog.String("team_id", channel.TeamId),
|
||||
)
|
||||
|
||||
_, err = a.AddChannelMember(userChannel.UserID, channel, "", "", false)
|
||||
_, err = a.AddChannelMember(userChannel.UserID, channel, "", "", "")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -271,7 +271,7 @@ func TestPopulateSyncablesSince(t *testing.T) {
|
||||
}
|
||||
|
||||
// Ensure members are in channel
|
||||
_, err = th.App.AddChannelMember(scientist1.Id, experimentsChannel, "", "", false)
|
||||
_, err = th.App.AddChannelMember(scientist1.Id, experimentsChannel, "", "", "")
|
||||
if err != nil {
|
||||
t.Errorf("unable to add user to channel: %s", err.Error())
|
||||
}
|
||||
@@ -281,7 +281,7 @@ func TestPopulateSyncablesSince(t *testing.T) {
|
||||
if err != nil {
|
||||
t.Errorf("unable to add user to team: %s", err.Error())
|
||||
}
|
||||
_, err = th.App.AddChannelMember(singer1.Id, experimentsChannel, "", "", false)
|
||||
_, err = th.App.AddChannelMember(singer1.Id, experimentsChannel, "", "", "")
|
||||
if err != nil {
|
||||
t.Errorf("unable to add user to channel: %s", err.Error())
|
||||
}
|
||||
|
||||
@@ -1117,7 +1117,7 @@ func (us SqlUserStore) GetUnreadCount(userId string) store.StoreChannel {
|
||||
|
||||
func (us SqlUserStore) GetUnreadCountForChannel(userId string, channelId string) store.StoreChannel {
|
||||
return store.Do(func(result *store.StoreResult) {
|
||||
if count, err := us.GetReplica().SelectInt("SELECT SUM(CASE WHEN c.Type = 'D' THEN (c.TotalMsgCount - cm.MsgCount) ELSE cm.MentionCount END) FROM Channels c INNER JOIN ChannelMembers cm ON c.Id = :ChannelId AND cm.ChannelId = :ChannelId AND cm.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil {
|
||||
if count, err := us.GetReplica().SelectInt("SELECT SUM(CASE WHEN c.Type = 'D' THEN (c.TotalMsgCount - cm.MsgCount) ELSE cm.MentionCount END) FROM Channels c INNER JOIN ChannelMembers cm ON c.Id = cm.ChannelId AND cm.ChannelId = :ChannelId AND cm.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.GetMentionCountForChannel", "store.sql_user.get_unread_count_for_channel.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
} else {
|
||||
result.Data = count
|
||||
@@ -1127,7 +1127,7 @@ func (us SqlUserStore) GetUnreadCountForChannel(userId string, channelId string)
|
||||
|
||||
func (us SqlUserStore) GetAnyUnreadPostCountForChannel(userId string, channelId string) store.StoreChannel {
|
||||
return store.Do(func(result *store.StoreResult) {
|
||||
if count, err := us.GetReplica().SelectInt("SELECT SUM(c.TotalMsgCount - cm.MsgCount) FROM Channels c INNER JOIN ChannelMembers cm ON c.Id = :ChannelId AND cm.ChannelId = :ChannelId AND cm.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil {
|
||||
if count, err := us.GetReplica().SelectInt("SELECT SUM(c.TotalMsgCount - cm.MsgCount) FROM Channels c INNER JOIN ChannelMembers cm ON c.Id = cm.ChannelId AND cm.ChannelId = :ChannelId AND cm.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil {
|
||||
result.Err = model.NewAppError("SqlUserStore.GetMentionCountForChannel", "store.sql_user.get_unread_count_for_channel.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
} else {
|
||||
result.Data = count
|
||||
|
||||
Ссылка в новой задаче
Block a user