Mark category as read (#24003)
* Mark category as read * Fix lint and test * Fix tests * Fix test and remove wrong aria * Address server issues and add mark as read for unreads * Missing changes * Fix tests * fix tests * Add confirmation popup to mark as read category * Always use viewMultipleChannels and other fixes * Remove unneeded code * Fix test * Address feedback * Address feedback * Fix tests * Fix test * Fix tests * Update aria-haspopup depending on the number of channels to mark as viewed --------- Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
c1c07ba1bb
Коммит
e9b3afecc2
@@ -8,6 +8,7 @@ import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
@@ -149,6 +150,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlStore) {
|
||||
t.Run("UpdateSidebarChannelsByPreferences", func(t *testing.T) { testUpdateSidebarChannelsByPreferences(t, ss) })
|
||||
t.Run("SetShared", func(t *testing.T) { testSetShared(t, ss) })
|
||||
t.Run("GetTeamForChannel", func(t *testing.T) { testGetTeamForChannel(t, ss) })
|
||||
t.Run("GetChannelsWithUnreadsAndWithMentions", func(t *testing.T) { testGetChannelsWithUnreadsAndWithMentions(t, ss) })
|
||||
}
|
||||
|
||||
func testChannelStoreSave(t *testing.T, ss store.Store) {
|
||||
@@ -8065,3 +8067,166 @@ func testGetTeamForChannel(t *testing.T, ss store.Store) {
|
||||
var nfErr *store.ErrNotFound
|
||||
require.True(t, errors.As(err, &nfErr))
|
||||
}
|
||||
|
||||
func testGetChannelsWithUnreadsAndWithMentions(t *testing.T, ss store.Store) {
|
||||
setupMembership := func(
|
||||
pushProp string,
|
||||
withUnreads bool,
|
||||
withMentions bool,
|
||||
isDirect bool,
|
||||
userId string,
|
||||
) (model.Channel, model.ChannelMember) {
|
||||
if !isDirect {
|
||||
o1 := model.Channel{}
|
||||
o1.TeamId = model.NewId()
|
||||
o1.DisplayName = "Channel1"
|
||||
o1.Name = NewTestId()
|
||||
o1.Type = model.ChannelTypeOpen
|
||||
o1.TotalMsgCount = 25
|
||||
o1.LastPostAt = 12345
|
||||
o1.LastRootPostAt = 12345
|
||||
_, nErr := ss.Channel().Save(&o1, -1)
|
||||
require.NoError(t, nErr)
|
||||
|
||||
m1 := model.ChannelMember{}
|
||||
m1.ChannelId = o1.Id
|
||||
m1.UserId = userId
|
||||
m1.NotifyProps = model.GetDefaultChannelNotifyProps()
|
||||
m1.NotifyProps[model.PushNotifyProp] = pushProp
|
||||
if !withUnreads {
|
||||
m1.MsgCount = o1.TotalMsgCount
|
||||
m1.LastViewedAt = o1.LastPostAt
|
||||
}
|
||||
if withMentions {
|
||||
m1.MentionCount = 5
|
||||
}
|
||||
_, err := ss.Channel().SaveMember(&m1)
|
||||
require.NoError(t, err)
|
||||
|
||||
return o1, m1
|
||||
}
|
||||
|
||||
o1, err := ss.Channel().CreateDirectChannel(&model.User{Id: userId}, &model.User{Id: model.NewId()}, func(channel *model.Channel) {
|
||||
channel.TotalMsgCount = 25
|
||||
channel.LastPostAt = 12345
|
||||
channel.LastRootPostAt = 12345
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
m1, err := ss.Channel().GetMember(context.Background(), o1.Id, userId)
|
||||
require.NoError(t, err)
|
||||
|
||||
if !withUnreads {
|
||||
m1.MsgCount = o1.TotalMsgCount
|
||||
m1.LastViewedAt = o1.LastPostAt
|
||||
}
|
||||
if withMentions {
|
||||
m1.MentionCount = 5
|
||||
}
|
||||
|
||||
m1, err = ss.Channel().UpdateMember(m1)
|
||||
require.NoError(t, err)
|
||||
|
||||
return *o1, *m1
|
||||
}
|
||||
|
||||
type TestCase struct {
|
||||
name string
|
||||
pushProp string
|
||||
userNotifyProp string
|
||||
isDirect bool
|
||||
withUnreads bool
|
||||
withMentions bool
|
||||
}
|
||||
ttcc := []TestCase{}
|
||||
|
||||
channelNotifyProps := []string{model.ChannelNotifyDefault, model.ChannelNotifyAll, model.ChannelNotifyMention, model.ChannelNotifyNone}
|
||||
userNotifyProps := []string{model.UserNotifyAll, model.UserNotifyMention, model.UserNotifyHere, model.UserNotifyNone}
|
||||
boolRange := []bool{true, false}
|
||||
|
||||
nameTemplate := "pushProp: %s, userPushProp: %s, direct: %t, unreads: %t, mentions: %t"
|
||||
for _, pushProp := range channelNotifyProps {
|
||||
for _, userNotifyProp := range userNotifyProps {
|
||||
for _, isDirect := range boolRange {
|
||||
for _, withUnreads := range boolRange {
|
||||
ttcc = append(ttcc, TestCase{
|
||||
name: fmt.Sprintf(nameTemplate, pushProp, userNotifyProp, isDirect, withUnreads, false),
|
||||
pushProp: pushProp,
|
||||
userNotifyProp: userNotifyProp,
|
||||
isDirect: isDirect,
|
||||
withUnreads: withUnreads,
|
||||
withMentions: false,
|
||||
})
|
||||
if withUnreads {
|
||||
ttcc = append(ttcc, TestCase{
|
||||
name: fmt.Sprintf(nameTemplate, pushProp, userNotifyProp, isDirect, withUnreads, true),
|
||||
pushProp: pushProp,
|
||||
userNotifyProp: userNotifyProp,
|
||||
isDirect: isDirect,
|
||||
withUnreads: withUnreads,
|
||||
withMentions: true,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for _, tc := range ttcc {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
o1, m1 := setupMembership(tc.pushProp, tc.withUnreads, tc.withMentions, tc.isDirect, model.NewId())
|
||||
userNotifyProps := model.GetDefaultChannelNotifyProps()
|
||||
userNotifyProps[model.PushNotifyProp] = tc.userNotifyProp
|
||||
unreads, mentions, times, err := ss.Channel().GetChannelsWithUnreadsAndWithMentions(context.Background(), []string{o1.Id}, m1.UserId, userNotifyProps)
|
||||
require.NoError(t, err)
|
||||
|
||||
expectedUnreadsLength := 0
|
||||
if tc.withUnreads {
|
||||
expectedUnreadsLength = 1
|
||||
}
|
||||
require.Len(t, unreads, expectedUnreadsLength)
|
||||
|
||||
propToUse := tc.pushProp
|
||||
if tc.pushProp == model.ChannelNotifyDefault {
|
||||
propToUse = tc.userNotifyProp
|
||||
}
|
||||
expectedMentionsLength := 0
|
||||
if (tc.isDirect && tc.withUnreads) || (propToUse == model.UserNotifyAll && tc.withUnreads) || (propToUse == model.UserNotifyMention && tc.withMentions) {
|
||||
expectedMentionsLength = 1
|
||||
}
|
||||
|
||||
require.Len(t, mentions, expectedMentionsLength)
|
||||
require.Equal(t, o1.LastPostAt, times[o1.Id])
|
||||
})
|
||||
}
|
||||
|
||||
t.Run("multiple channels", func(t *testing.T) {
|
||||
userId := model.NewId()
|
||||
o1, _ := setupMembership(model.ChannelNotifyDefault, true, true, false, userId)
|
||||
o2, _ := setupMembership(model.ChannelNotifyDefault, true, true, false, userId)
|
||||
|
||||
userNotifyProps := model.GetDefaultChannelNotifyProps()
|
||||
userNotifyProps[model.PushNotifyProp] = model.UserNotifyMention
|
||||
|
||||
unreads, mentions, times, err := ss.Channel().GetChannelsWithUnreadsAndWithMentions(context.Background(), []string{o1.Id, o2.Id}, userId, userNotifyProps)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Contains(t, unreads, o1.Id)
|
||||
require.Contains(t, unreads, o2.Id)
|
||||
require.Contains(t, mentions, o1.Id)
|
||||
require.Contains(t, mentions, o2.Id)
|
||||
require.Equal(t, o1.LastPostAt, times[o1.Id])
|
||||
require.Equal(t, o2.LastPostAt, times[o2.Id])
|
||||
})
|
||||
|
||||
t.Run("non existing channel", func(t *testing.T) {
|
||||
userNotifyProps := model.GetDefaultChannelNotifyProps()
|
||||
userNotifyProps[model.PushNotifyProp] = model.UserNotifyMention
|
||||
unreads, mentions, times, err := ss.Channel().GetChannelsWithUnreadsAndWithMentions(context.Background(), []string{"foo"}, "foo", userNotifyProps)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, unreads, 0)
|
||||
require.Len(t, mentions, 0)
|
||||
require.Len(t, times, 0)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -986,6 +986,50 @@ func (_m *ChannelStore) GetChannelsWithTeamDataByIds(channelIds []string, includ
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetChannelsWithUnreadsAndWithMentions provides a mock function with given fields: ctx, channelIDs, userID, userNotifyProps
|
||||
func (_m *ChannelStore) GetChannelsWithUnreadsAndWithMentions(ctx context.Context, channelIDs []string, userID string, userNotifyProps model.StringMap) ([]string, []string, map[string]int64, error) {
|
||||
ret := _m.Called(ctx, channelIDs, userID, userNotifyProps)
|
||||
|
||||
var r0 []string
|
||||
var r1 []string
|
||||
var r2 map[string]int64
|
||||
var r3 error
|
||||
if rf, ok := ret.Get(0).(func(context.Context, []string, string, model.StringMap) ([]string, []string, map[string]int64, error)); ok {
|
||||
return rf(ctx, channelIDs, userID, userNotifyProps)
|
||||
}
|
||||
if rf, ok := ret.Get(0).(func(context.Context, []string, string, model.StringMap) []string); ok {
|
||||
r0 = rf(ctx, channelIDs, userID, userNotifyProps)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]string)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(1).(func(context.Context, []string, string, model.StringMap) []string); ok {
|
||||
r1 = rf(ctx, channelIDs, userID, userNotifyProps)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).([]string)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(2).(func(context.Context, []string, string, model.StringMap) map[string]int64); ok {
|
||||
r2 = rf(ctx, channelIDs, userID, userNotifyProps)
|
||||
} else {
|
||||
if ret.Get(2) != nil {
|
||||
r2 = ret.Get(2).(map[string]int64)
|
||||
}
|
||||
}
|
||||
|
||||
if rf, ok := ret.Get(3).(func(context.Context, []string, string, model.StringMap) error); ok {
|
||||
r3 = rf(ctx, channelIDs, userID, userNotifyProps)
|
||||
} else {
|
||||
r3 = ret.Error(3)
|
||||
}
|
||||
|
||||
return r0, r1, r2, r3
|
||||
}
|
||||
|
||||
// GetDeleted provides a mock function with given fields: team_id, offset, limit, userID
|
||||
func (_m *ChannelStore) GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error) {
|
||||
ret := _m.Called(team_id, offset, limit, userID)
|
||||
|
||||
Ссылка в новой задаче
Block a user