MM-33708 - Add MentionCountRoot column to ChannelMembers (#17099)

* added new column for root-only mentions

Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Eli Yukelzon
2021-04-01 14:43:09 +03:00
коммит произвёл GitHub
родитель 3c21eef110
Коммит 480796a1df
35 изменённых файлов: 288 добавлений и 346 удалений

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

@@ -39,34 +39,36 @@ type SqlChannelStore struct {
}
type channelMember struct {
ChannelId string
UserId string
Roles string
LastViewedAt int64
MsgCount int64
MentionCount int64
NotifyProps model.StringMap
LastUpdateAt int64
SchemeUser sql.NullBool
SchemeAdmin sql.NullBool
SchemeGuest sql.NullBool
MsgCountRoot int64
ChannelId string
UserId string
Roles string
LastViewedAt int64
MsgCount int64
MentionCount int64
NotifyProps model.StringMap
LastUpdateAt int64
SchemeUser sql.NullBool
SchemeAdmin sql.NullBool
SchemeGuest sql.NullBool
MentionCountRoot int64
MsgCountRoot int64
}
func NewChannelMemberFromModel(cm *model.ChannelMember) *channelMember {
return &channelMember{
ChannelId: cm.ChannelId,
UserId: cm.UserId,
Roles: cm.ExplicitRoles,
LastViewedAt: cm.LastViewedAt,
MsgCount: cm.MsgCount,
MsgCountRoot: cm.MsgCountRoot,
MentionCount: cm.MentionCount,
NotifyProps: cm.NotifyProps,
LastUpdateAt: cm.LastUpdateAt,
SchemeGuest: sql.NullBool{Valid: true, Bool: cm.SchemeGuest},
SchemeUser: sql.NullBool{Valid: true, Bool: cm.SchemeUser},
SchemeAdmin: sql.NullBool{Valid: true, Bool: cm.SchemeAdmin},
ChannelId: cm.ChannelId,
UserId: cm.UserId,
Roles: cm.ExplicitRoles,
LastViewedAt: cm.LastViewedAt,
MsgCount: cm.MsgCount,
MentionCount: cm.MentionCount,
MentionCountRoot: cm.MentionCountRoot,
MsgCountRoot: cm.MsgCountRoot,
NotifyProps: cm.NotifyProps,
LastUpdateAt: cm.LastUpdateAt,
SchemeGuest: sql.NullBool{Valid: true, Bool: cm.SchemeGuest},
SchemeUser: sql.NullBool{Valid: true, Bool: cm.SchemeUser},
SchemeAdmin: sql.NullBool{Valid: true, Bool: cm.SchemeAdmin},
}
}
@@ -77,6 +79,7 @@ type channelMemberWithSchemeRoles struct {
LastViewedAt int64
MsgCount int64
MentionCount int64
MentionCountRoot int64
NotifyProps model.StringMap
LastUpdateAt int64
SchemeGuest sql.NullBool
@@ -92,7 +95,7 @@ type channelMemberWithSchemeRoles struct {
}
func channelMemberSliceColumns() []string {
return []string{"ChannelId", "UserId", "Roles", "LastViewedAt", "MsgCount", "MsgCountRoot", "MentionCount", "NotifyProps", "LastUpdateAt", "SchemeUser", "SchemeAdmin", "SchemeGuest"}
return []string{"ChannelId", "UserId", "Roles", "LastViewedAt", "MsgCount", "MsgCountRoot", "MentionCount", "MentionCountRoot", "NotifyProps", "LastUpdateAt", "SchemeUser", "SchemeAdmin", "SchemeGuest"}
}
func channelMemberToSlice(member *model.ChannelMember) []interface{} {
@@ -104,6 +107,7 @@ func channelMemberToSlice(member *model.ChannelMember) []interface{} {
resultSlice = append(resultSlice, member.MsgCount)
resultSlice = append(resultSlice, member.MsgCountRoot)
resultSlice = append(resultSlice, member.MentionCount)
resultSlice = append(resultSlice, member.MentionCountRoot)
resultSlice = append(resultSlice, model.MapToJson(member.NotifyProps))
resultSlice = append(resultSlice, member.LastUpdateAt)
resultSlice = append(resultSlice, member.SchemeUser)
@@ -229,19 +233,20 @@ func (db channelMemberWithSchemeRoles) ToModel() *model.ChannelMember {
strings.Fields(db.Roles),
)
return &model.ChannelMember{
ChannelId: db.ChannelId,
UserId: db.UserId,
Roles: strings.Join(rolesResult.roles, " "),
LastViewedAt: db.LastViewedAt,
MsgCount: db.MsgCount,
MsgCountRoot: db.MsgCountRoot,
MentionCount: db.MentionCount,
NotifyProps: db.NotifyProps,
LastUpdateAt: db.LastUpdateAt,
SchemeAdmin: rolesResult.schemeAdmin,
SchemeUser: rolesResult.schemeUser,
SchemeGuest: rolesResult.schemeGuest,
ExplicitRoles: strings.Join(rolesResult.explicitRoles, " "),
ChannelId: db.ChannelId,
UserId: db.UserId,
Roles: strings.Join(rolesResult.roles, " "),
LastViewedAt: db.LastViewedAt,
MsgCount: db.MsgCount,
MsgCountRoot: db.MsgCountRoot,
MentionCount: db.MentionCount,
MentionCountRoot: db.MentionCountRoot,
NotifyProps: db.NotifyProps,
LastUpdateAt: db.LastUpdateAt,
SchemeAdmin: rolesResult.schemeAdmin,
SchemeUser: rolesResult.schemeUser,
SchemeGuest: rolesResult.schemeGuest,
ExplicitRoles: strings.Join(rolesResult.explicitRoles, " "),
}
}
@@ -717,10 +722,7 @@ func (s SqlChannelStore) GetChannelUnread(channelId, userId string) (*model.Chan
var unreadChannel model.ChannelUnread
err := s.GetReplica().SelectOne(&unreadChannel,
`SELECT
Channels.TeamId TeamId, Channels.Id ChannelId,
(Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount,
(Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot,
ChannelMembers.MentionCount MentionCount, ChannelMembers.NotifyProps NotifyProps
Channels.TeamId TeamId, Channels.Id ChannelId, (Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount, (Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot, ChannelMembers.MentionCount MentionCount, ChannelMembers.MentionCountRoot MentionCountRoot, ChannelMembers.NotifyProps NotifyProps
FROM
Channels, ChannelMembers
WHERE
@@ -2086,6 +2088,7 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string,
ChannelMembers cm
SET
MentionCount = 0,
MentionCountRoot = 0,
MsgCount = greatest(cm.MsgCount, c.TotalMsgCount),
MsgCountRoot = greatest(cm.MsgCountRoot, c.TotalMsgCountRoot),
LastViewedAt = greatest(cm.LastViewedAt, c.LastPostAt),
@@ -2140,6 +2143,7 @@ func (s SqlChannelStore) UpdateLastViewedAt(channelIds []string, userId string,
ChannelMembers
SET
MentionCount = 0,
MentionCountRoot = 0,
MsgCount = CASE ChannelId ` + msgCountQuery + ` END,
MsgCountRoot = CASE ChannelId ` + msgCountQueryRoot + ` END,
LastViewedAt = CASE ChannelId ` + lastViewedQuery + ` END,
@@ -2196,7 +2200,7 @@ func (s SqlChannelStore) CountPostsAfter(channelId string, timestamp int64, user
// UpdateLastViewedAtPost updates a ChannelMember as if the user last read the channel at the time of the given post.
// If the provided mentionCount is -1, the given post and all posts after it are considered to be mentions. Returns
// an updated model.ChannelUnreadAt that can be returned to the client.
func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount int, updateThreads bool) (*model.ChannelUnreadAt, error) {
func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID string, mentionCount, mentionCountRoot int, updateThreads bool) (*model.ChannelUnreadAt, error) {
var threadsToUpdate []string
unreadDate := unreadPost.CreateAt - 1
if updateThreads {
@@ -2214,6 +2218,7 @@ func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID s
params := map[string]interface{}{
"mentions": mentionCount,
"mentionsRoot": mentionCountRoot,
"unreadCount": unread,
"unreadCountRoot": unreadRoot,
"lastViewedAt": unreadDate,
@@ -2229,6 +2234,7 @@ func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID s
ChannelMembers
SET
MentionCount = :mentions,
MentionCountRoot = :mentionsRoot,
MsgCount = (SELECT TotalMsgCount FROM Channels WHERE ID = :channelId) - :unreadCount,
MsgCountRoot = (SELECT TotalMsgCountRoot FROM Channels WHERE ID = :channelId) - :unreadCountRoot,
LastViewedAt = :lastViewedAt,
@@ -2250,6 +2256,7 @@ func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID s
cm.MsgCount MsgCount,
cm.MsgCountRoot MsgCountRoot,
cm.MentionCount MentionCount,
cm.MentionCountRoot MentionCountRoot,
cm.LastViewedAt LastViewedAt,
cm.NotifyProps NotifyProps
FROM
@@ -2271,7 +2278,7 @@ func (s SqlChannelStore) UpdateLastViewedAtPost(unreadPost *model.Post, userID s
return result, nil
}
func (s SqlChannelStore) IncrementMentionCount(channelId string, userId string, updateThreads bool) error {
func (s SqlChannelStore) IncrementMentionCount(channelId string, userId string, updateThreads, isRoot bool) error {
now := model.GetMillis()
var threadsToUpdate []string
if updateThreads {
@@ -2281,17 +2288,21 @@ func (s SqlChannelStore) IncrementMentionCount(channelId string, userId string,
return err
}
}
rootInc := 0
if isRoot {
rootInc = 1
}
_, err := s.GetMaster().Exec(
`UPDATE
ChannelMembers
SET
MentionCount = MentionCount + 1,
MentionCountRoot = MentionCountRoot + :RootInc,
LastUpdateAt = :LastUpdateAt
WHERE
UserId = :UserId
AND ChannelId = :ChannelId`,
map[string]interface{}{"ChannelId": channelId, "UserId": userId, "LastUpdateAt": now})
AND ChannelId = :ChannelId`,
map[string]interface{}{"ChannelId": channelId, "UserId": userId, "LastUpdateAt": now, "RootInc": rootInc})
if err != nil {
return errors.Wrapf(err, "failed to Update ChannelMembers with channelId=%s and userId=%s", channelId, userId)
}
@@ -3186,6 +3197,7 @@ func (s SqlChannelStore) GetChannelMembersForExport(userId string, teamId string
ChannelMembers.LastViewedAt,
ChannelMembers.MsgCount,
ChannelMembers.MentionCount,
ChannelMembers.MentionCountRoot,
ChannelMembers.NotifyProps,
ChannelMembers.LastUpdateAt,
ChannelMembers.SchemeUser,
@@ -3236,7 +3248,7 @@ func (s SqlChannelStore) GetAllDirectChannelsForExportAfter(limit int, afterId s
channelIds = append(channelIds, channel.Id)
}
query = s.getQueryBuilder().
Select("u.Username as Username, ChannelId, UserId, cm.Roles as Roles, LastViewedAt, MsgCount, MentionCount, cm.NotifyProps as NotifyProps, LastUpdateAt, SchemeUser, SchemeAdmin, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest").
Select("u.Username as Username, ChannelId, UserId, cm.Roles as Roles, LastViewedAt, MsgCount, MentionCount, MentionCountRoot, cm.NotifyProps as NotifyProps, LastUpdateAt, SchemeUser, SchemeAdmin, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest").
From("ChannelMembers cm").
Join("Users u ON ( u.Id = cm.UserId )").
Where(sq.And{

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

@@ -69,6 +69,7 @@ func testNewChannelMemberFromModel(t *testing.T) {
assert.Equal(t, m.LastViewedAt, db.LastViewedAt)
assert.Equal(t, m.MsgCount, db.MsgCount)
assert.Equal(t, m.MentionCount, db.MentionCount)
assert.Equal(t, int64(0), m.MentionCountRoot)
assert.Equal(t, m.NotifyProps, db.NotifyProps)
assert.Equal(t, m.LastUpdateAt, db.LastUpdateAt)
assert.Equal(t, true, db.SchemeGuest.Valid)
@@ -111,6 +112,7 @@ func testChannelMemberWithSchemeRolesToModel(t *testing.T) {
assert.Equal(t, db.LastViewedAt, m.LastViewedAt)
assert.Equal(t, db.MsgCount, m.MsgCount)
assert.Equal(t, db.MentionCount, m.MentionCount)
assert.Equal(t, db.MentionCountRoot, m.MentionCountRoot)
assert.Equal(t, db.NotifyProps, m.NotifyProps)
assert.Equal(t, db.LastUpdateAt, m.LastUpdateAt)
assert.Equal(t, db.SchemeGuest.Bool, m.SchemeGuest)

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

@@ -919,6 +919,7 @@ func (s *SqlGroupStore) ChannelMembersToRemove(channelID *string) ([]*model.Chan
"ChannelMembers.MsgCount",
"ChannelMembers.MsgCountRoot",
"ChannelMembers.MentionCount",
"ChannelMembers.MentionCountRoot",
"ChannelMembers.NotifyProps",
"ChannelMembers.LastUpdateAt",
"ChannelMembers.LastUpdateAt",

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

@@ -2030,7 +2030,7 @@ func (s *SqlPostStore) GetDirectPostParentsForExportAfter(limit int, afterId str
channelIds = append(channelIds, post.ChannelId)
}
query = s.getQueryBuilder().
Select("u.Username as Username, ChannelId, UserId, cm.Roles as Roles, LastViewedAt, MsgCount, MentionCount, cm.NotifyProps as NotifyProps, LastUpdateAt, SchemeUser, SchemeAdmin, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest").
Select("u.Username as Username, ChannelId, UserId, cm.Roles as Roles, LastViewedAt, MsgCount, MentionCount, MentionCountRoot, cm.NotifyProps as NotifyProps, LastUpdateAt, SchemeUser, SchemeAdmin, (SchemeGuest IS NOT NULL AND SchemeGuest) as SchemeGuest").
From("ChannelMembers cm").
Join("Users u ON ( u.Id = cm.UserId )").
Where(sq.Eq{

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

@@ -1177,7 +1177,7 @@ func (s SqlTeamStore) GetTeamsForUserWithPagination(userId string, page, perPage
// for all the channels in all the teams except the excluded ones.
func (s SqlTeamStore) GetChannelUnreadsForAllTeams(excludeTeamId, userId string) ([]*model.ChannelUnread, error) {
query, args, err := s.getQueryBuilder().
Select("Channels.TeamId TeamId", "Channels.Id ChannelId", "(Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount", "(Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot", "ChannelMembers.MentionCount MentionCount", "ChannelMembers.NotifyProps NotifyProps").
Select("Channels.TeamId TeamId", "Channels.Id ChannelId", "(Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount", "(Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot", "ChannelMembers.MentionCount MentionCount", "ChannelMembers.MentionCountRoot MentionCountRoot", "ChannelMembers.NotifyProps NotifyProps").
From("Channels").
Join("ChannelMembers ON Id = ChannelId").
Where(sq.Eq{"UserId": userId, "DeleteAt": 0}).
@@ -1199,7 +1199,7 @@ func (s SqlTeamStore) GetChannelUnreadsForAllTeams(excludeTeamId, userId string)
// GetChannelUnreadsForTeam returns unreads msg count, mention counts and notifyProps for all the channels in a single team.
func (s SqlTeamStore) GetChannelUnreadsForTeam(teamId, userId string) ([]*model.ChannelUnread, error) {
query, args, err := s.getQueryBuilder().
Select("Channels.TeamId TeamId", "Channels.Id ChannelId", "(Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount", "(Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot", "ChannelMembers.MentionCount MentionCount", "ChannelMembers.NotifyProps NotifyProps").
Select("Channels.TeamId TeamId", "Channels.Id ChannelId", "(Channels.TotalMsgCount - ChannelMembers.MsgCount) MsgCount", "(Channels.TotalMsgCountRoot - ChannelMembers.MsgCountRoot) MsgCountRoot", "ChannelMembers.MentionCount MentionCount", "ChannelMembers.MentionCountRoot MentionCountRoot", "ChannelMembers.NotifyProps NotifyProps").
From("Channels").
Join("ChannelMembers ON Id = ChannelId").
Where(sq.Eq{"UserId": userId, "TeamId": teamId, "DeleteAt": 0}).ToSql()

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

@@ -109,35 +109,6 @@ func (s *SqlThreadStore) Get(id string) (*model.Thread, error) {
return &thread, nil
}
func (s *SqlThreadStore) GetThreadMentionsForUserPerChannel(userId, teamId string) (map[string]int64, error) {
type Count struct {
UnreadMentions int64
ChannelId string
}
var counts []Count
sql, args, _ := s.getQueryBuilder().
Select("SUM(UnreadMentions) as UnreadMentions", "ChannelId").
From("ThreadMemberships").
LeftJoin("Threads ON Threads.PostId = ThreadMemberships.PostId").
LeftJoin("Channels ON Threads.ChannelId = Channels.Id").
Where(sq.And{
sq.Or{sq.Eq{"Channels.TeamId": teamId}, sq.Eq{"Channels.TeamId": ""}},
sq.Eq{"ThreadMemberships.UserId": userId},
sq.Eq{"ThreadMemberships.Following": true},
}).
GroupBy("Threads.ChannelId").ToSql()
if _, err := s.GetMaster().Select(&counts, sql, args...); err != nil {
return nil, err
}
result := map[string]int64{}
for _, count := range counts {
result[count.ChannelId] = count.UnreadMentions
}
return result, nil
}
func (s *SqlThreadStore) GetThreadsForUser(userId, teamId string, opts model.GetUserThreadsOpts) (*model.Threads, error) {
type JoinedThread struct {
PostId string

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

@@ -1011,6 +1011,38 @@ func upgradeDatabaseToVersion535(sqlStore *SqlStore) {
sqlStore.CreateColumnIfNotExists("SidebarCategories", "Collapsed", "tinyint(1)", "boolean", "0")
// note: setting default 0 on pre-5.0 tables causes test-db-migration script to fail, so this column will be added to ignore list
sqlStore.CreateColumnIfNotExists("ChannelMembers", "MentionCountRoot", "bigint", "bigint", "0")
sqlStore.AlterColumnDefaultIfExists("ChannelMembers", "MentionCountRoot", model.NewString("0"), model.NewString("0"))
mentionCountRootCTE := `
SELECT ChannelId, COALESCE(SUM(UnreadMentions), 0) AS UnreadMentions, UserId
FROM ThreadMemberships
LEFT JOIN Threads ON ThreadMemberships.PostId = Threads.PostId
GROUP BY Threads.ChannelId, ThreadMemberships.UserId
`
updateMentionCountRootQuery := `
UPDATE ChannelMembers INNER JOIN (` + mentionCountRootCTE + `) AS q ON
q.ChannelId = ChannelMembers.ChannelId AND
q.UserId=ChannelMembers.UserId AND
ChannelMembers.MentionCount > 0
SET MentionCountRoot = ChannelMembers.MentionCount - q.UnreadMentions
`
if sqlStore.DriverName() == model.DATABASE_DRIVER_POSTGRES {
updateMentionCountRootQuery = `
WITH q AS (` + mentionCountRootCTE + `)
UPDATE channelmembers
SET MentionCountRoot = ChannelMembers.MentionCount - q.UnreadMentions
FROM q
WHERE
q.ChannelId = ChannelMembers.ChannelId AND
q.UserId = ChannelMembers.UserId AND
ChannelMembers.MentionCount > 0
`
}
if _, err := sqlStore.GetMaster().Exec(updateMentionCountRootQuery); err != nil {
mlog.Error("Error updating ChannelId in Threads table", mlog.Err(err))
}
sqlStore.CreateColumnIfNotExists("Channels", "TotalMsgCountRoot", "bigint", "bigint", "0")
sqlStore.CreateColumnIfNotExistsNoDefault("Channels", "LastRootPostAt", "bigint", "bigint")
defer sqlStore.RemoveColumnIfExists("Channels", "LastRootPostAt")

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

@@ -1634,6 +1634,7 @@ func (us SqlUserStore) GetUsersBatchForIndexing(startTime, endTime int64, limit
cm.LastViewedAt,
cm.MsgCount,
cm.MentionCount,
cm.MentionCountRoot,
cm.NotifyProps,
cm.LastUpdateAt,
cm.SchemeUser,