From 9799fe9be6a12bf405dc4ccf17b3ec84f7a3ad61 Mon Sep 17 00:00:00 2001 From: Doug Lauder Date: Wed, 14 Apr 2021 14:59:26 -0400 Subject: [PATCH] MM-34549 shared channels; add users to channel that were already sync'd (#17361) Fixes a bug and adds a feature for shared channels: - The Bug: when creating new shared channels, users that had already been sync'd via another channel were not added to the new channel's member list, since the users were not sync'd again. This PR sync's users per channel. - The Feature: support custom statuses --- app/app_iface.go | 1 + app/opentracing/opentracing_layer.go | 15 +++++++++++ app/shared_channel.go | 6 +++++ app/slashcommands/command_remote.go | 8 ++++++ model/shared_channel.go | 5 ++++ services/sharedchannel/mock_AppIface_test.go | 10 ++++++++ services/sharedchannel/msg.go | 27 +++++++++++--------- services/sharedchannel/service.go | 2 ++ services/sharedchannel/sync_recv.go | 23 +++++++++++++---- services/sharedchannel/sync_send.go | 10 +++++--- store/opentracinglayer/opentracinglayer.go | 4 +-- store/retrylayer/retrylayer.go | 4 +-- store/sqlstore/shared_channel_store.go | 14 +++++----- store/sqlstore/upgrade.go | 1 + store/store.go | 2 +- store/storetest/mocks/SharedChannelStore.go | 14 +++++----- store/storetest/remote_cluster_store.go | 4 +-- store/storetest/shared_channel_store.go | 21 ++++++++------- store/timerlayer/timerlayer.go | 4 +-- 19 files changed, 123 insertions(+), 52 deletions(-) diff --git a/app/app_iface.go b/app/app_iface.go index 91bf8e0925..44a4e5643e 100644 --- a/app/app_iface.go +++ b/app/app_iface.go @@ -832,6 +832,7 @@ type AppIface interface { Notification() einterfaces.NotificationInterface NotificationsLog() *mlog.Logger NotifyAndSetWarnMetricAck(warnMetricId string, sender *model.User, forceAck bool, isBot bool) *model.AppError + NotifySharedChannelUserUpdate(user *model.User) OpenInteractiveDialog(request model.OpenDialogRequest) *model.AppError OriginChecker() func(*http.Request) bool PatchChannel(channel *model.Channel, patch *model.ChannelPatch, userID string) (*model.Channel, *model.AppError) diff --git a/app/opentracing/opentracing_layer.go b/app/opentracing/opentracing_layer.go index 97ce222537..cff0d70601 100644 --- a/app/opentracing/opentracing_layer.go +++ b/app/opentracing/opentracing_layer.go @@ -11401,6 +11401,21 @@ func (a *OpenTracingAppLayer) NotifySessionsExpired() *model.AppError { return resultVar0 } +func (a *OpenTracingAppLayer) NotifySharedChannelUserUpdate(user *model.User) { + origCtx := a.ctx + span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.NotifySharedChannelUserUpdate") + + a.ctx = newCtx + a.app.Srv().Store.SetContext(newCtx) + defer func() { + a.app.Srv().Store.SetContext(origCtx) + a.ctx = origCtx + }() + + defer span.Finish() + a.app.NotifySharedChannelUserUpdate(user) +} + func (a *OpenTracingAppLayer) OpenInteractiveDialog(request model.OpenDialogRequest) *model.AppError { origCtx := a.ctx span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.OpenInteractiveDialog") diff --git a/app/shared_channel.go b/app/shared_channel.go index 7c5a75d3a3..5fdd64eeb4 100644 --- a/app/shared_channel.go +++ b/app/shared_channel.go @@ -147,3 +147,9 @@ func (a *App) GetSharedChannelRemotesStatus(channelID string) ([]*model.SharedCh } return a.Srv().Store.SharedChannel().GetRemotesStatus(channelID) } + +// SharedChannelUsers + +func (a *App) NotifySharedChannelUserUpdate(user *model.User) { + a.sendUpdatedUserEvent(*user) +} diff --git a/app/slashcommands/command_remote.go b/app/slashcommands/command_remote.go index a8d375708d..43a32e69ab 100644 --- a/app/slashcommands/command_remote.go +++ b/app/slashcommands/command_remote.go @@ -116,7 +116,11 @@ func (rp *RemoteProvider) doInvite(a *app.App, args *model.CommandArgs, margs ma if name == "" { return responsef(args.T("api.command_remote.missing_empty", map[string]interface{}{"Arg": "name"})) } + displayname := margs["displayname"] + if displayname == "" { + displayname = name + } url := a.GetSiteURL() if url == "" { @@ -163,7 +167,11 @@ func (rp *RemoteProvider) doAccept(a *app.App, args *model.CommandArgs, margs ma if name == "" { return responsef(args.T("api.command_remote.missing_empty", map[string]interface{}{"Arg": "name"})) } + displayname := margs["displayname"] + if displayname == "" { + displayname = name + } blob := margs["invite"] if blob == "" { diff --git a/model/shared_channel.go b/model/shared_channel.go index f2278e66d0..3387db1cea 100644 --- a/model/shared_channel.go +++ b/model/shared_channel.go @@ -183,6 +183,7 @@ type SharedChannelRemoteStatus struct { type SharedChannelUser struct { Id string `json:"id"` UserId string `json:"user_id"` + ChannelId string `json:"channel_id"` RemoteId string `json:"remote_id"` CreateAt int64 `json:"create_at"` LastSyncAt int64 `json:"last_sync_at"` @@ -202,6 +203,10 @@ func (scu *SharedChannelUser) IsValid() *AppError { return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.id.app_error", nil, "UserId="+scu.UserId, http.StatusBadRequest) } + if !IsValidId(scu.ChannelId) { + return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.id.app_error", nil, "ChannelId="+scu.ChannelId, http.StatusBadRequest) + } + if !IsValidId(scu.RemoteId) { return NewAppError("SharedChannelUser.IsValid", "model.channel.is_valid.id.app_error", nil, "RemoteId="+scu.RemoteId, http.StatusBadRequest) } diff --git a/services/sharedchannel/mock_AppIface_test.go b/services/sharedchannel/mock_AppIface_test.go index 00d98242a5..565a9c6833 100644 --- a/services/sharedchannel/mock_AppIface_test.go +++ b/services/sharedchannel/mock_AppIface_test.go @@ -230,6 +230,11 @@ func (_m *MockAppIface) GetOrCreateDirectChannel(userId string, otherUserId stri return r0, r1 } +// InvalidateCacheForUser provides a mock function with given fields: userID +func (_m *MockAppIface) InvalidateCacheForUser(userID string) { + _m.Called(userID) +} + // MentionsToTeamMembers provides a mock function with given fields: message, teamID func (_m *MockAppIface) MentionsToTeamMembers(message string, teamID string) model.UserMentionMap { ret := _m.Called(message, teamID) @@ -246,6 +251,11 @@ func (_m *MockAppIface) MentionsToTeamMembers(message string, teamID string) mod return r0 } +// NotifySharedChannelUserUpdate provides a mock function with given fields: user +func (_m *MockAppIface) NotifySharedChannelUserUpdate(user *model.User) { + _m.Called(user) +} + // PatchChannelModerationsForChannel provides a mock function with given fields: channel, channelModerationsPatch func (_m *MockAppIface) PatchChannelModerationsForChannel(channel *model.Channel, channelModerationsPatch []*model.ChannelModerationPatch) ([]*model.ChannelModeration, *model.AppError) { ret := _m.Called(channel, channelModerationsPatch) diff --git a/services/sharedchannel/msg.go b/services/sharedchannel/msg.go index 7e59e5bbf8..ce7f8319f6 100644 --- a/services/sharedchannel/msg.go +++ b/services/sharedchannel/msg.go @@ -52,10 +52,10 @@ func (u userCache) Add(id string) { // postsToSyncMessages takes a slice of posts and converts to a `RemoteClusterMsg` which can be // sent to a remote cluster. -func (scs *Service) postsToSyncMessages(posts []*model.Post, rc *model.RemoteCluster, nextSyncAt int64) ([]syncMsg, error) { +func (scs *Service) postsToSyncMessages(posts []*model.Post, channelID string, rc *model.RemoteCluster, nextSyncAt int64) ([]syncMsg, error) { syncMessages := make([]syncMsg, 0, len(posts)) - var teamId string + var teamID string uCache := make(userCache) for _, p := range posts { @@ -64,7 +64,7 @@ func (scs *Service) postsToSyncMessages(posts []*model.Post, rc *model.RemoteClu } // lookup team id once - if teamId == "" { + if teamID == "" { sc, err := scs.server.GetStore().SharedChannel().Get(p.ChannelId) if err != nil { scs.server.GetLogger().Log(mlog.LvlSharedChannelServiceError, "Could not get shared channel for post", @@ -73,7 +73,7 @@ func (scs *Service) postsToSyncMessages(posts []*model.Post, rc *model.RemoteClu ) continue } - teamId = sc.TeamId + teamID = sc.TeamId } // any reactions originating from the remote cluster are filtered out @@ -119,7 +119,7 @@ func (scs *Service) postsToSyncMessages(posts []*model.Post, rc *model.RemoteClu } // any users originating from the remote cluster are filtered out - users := scs.usersForPost(postSync, reactions, teamId, rc, uCache) + users := scs.usersForPost(postSync, reactions, channelID, teamID, rc, uCache) // if everything was filtered out then don't send an empty message. if postSync == nil && len(reactions) == 0 && len(users) == 0 { @@ -142,7 +142,7 @@ func (scs *Service) postsToSyncMessages(posts []*model.Post, rc *model.RemoteClu // usersForPost provides a list of Users associated with the post that need to be synchronized. // The user cache ensures the same user is not synchronized redundantly if they appear in multiple // posts for this sync batch. -func (scs *Service) usersForPost(post *model.Post, reactions []*model.Reaction, teamID string, rc *model.RemoteCluster, uCache userCache) []*model.User { +func (scs *Service) usersForPost(post *model.Post, reactions []*model.Reaction, channelID string, teamID string, rc *model.RemoteCluster, uCache userCache) []*model.User { userIds := make([]string, 0) var mentionMap model.UserMentionMap @@ -178,7 +178,7 @@ func (scs *Service) usersForPost(post *model.Post, reactions []*model.Reaction, for _, id := range userIds { user, err := scs.server.GetStore().User().Get(context.Background(), id) if err == nil { - if sync, err2 := scs.shouldUserSync(user, rc); err2 != nil { + if sync, err2 := scs.shouldUserSync(user, channelID, rc); err2 != nil { scs.server.GetLogger().Log(mlog.LvlSharedChannelServiceError, "Could not find user for post", mlog.String("user_id", id), mlog.Err(err2), @@ -238,15 +238,15 @@ func sanitizeUserForSync(user *model.User) *model.User { } // shouldUserSync determines if a user needs to be synchronized. -// User should be synchronized if it has no entry in the SharedChannelUsers table, +// User should be synchronized if it has no entry in the SharedChannelUsers table for the specified channel, // or there is an entry but the LastSyncAt is less than user.UpdateAt -func (scs *Service) shouldUserSync(user *model.User, rc *model.RemoteCluster) (bool, error) { +func (scs *Service) shouldUserSync(user *model.User, channelID string, rc *model.RemoteCluster) (bool, error) { // don't sync users with the remote they originated from. if user.RemoteId != nil && *user.RemoteId == rc.RemoteId { return false, nil } - scu, err := scs.server.GetStore().SharedChannel().GetUser(user.Id, rc.RemoteId) + scu, err := scs.server.GetStore().SharedChannel().GetUser(user.Id, channelID, rc.RemoteId) if err != nil { if _, ok := err.(errNotFound); !ok { return false, err @@ -254,13 +254,16 @@ func (scs *Service) shouldUserSync(user *model.User, rc *model.RemoteCluster) (b // user not in the SharedChannelUsers table, so we must add them. scu = &model.SharedChannelUser{ - UserId: user.Id, - RemoteId: rc.RemoteId, + UserId: user.Id, + RemoteId: rc.RemoteId, + ChannelId: channelID, } if _, err = scs.server.GetStore().SharedChannel().SaveUser(scu); err != nil { scs.server.GetLogger().Log(mlog.LvlSharedChannelServiceError, "Error adding user to shared channel users", mlog.String("remote_id", rc.RemoteId), mlog.String("user_id", user.Id), + mlog.String("channel_id", user.Id), + mlog.Err(err), ) } } else if scu.LastSyncAt >= user.UpdateAt { diff --git a/services/sharedchannel/service.go b/services/sharedchannel/service.go index cc5ea8b5e7..f5314bf519 100644 --- a/services/sharedchannel/service.go +++ b/services/sharedchannel/service.go @@ -57,6 +57,8 @@ type AppIface interface { CreateUploadSession(us *model.UploadSession) (*model.UploadSession, *model.AppError) FileReader(path string) (filestore.ReadCloseSeeker, *model.AppError) MentionsToTeamMembers(message, teamID string) model.UserMentionMap + InvalidateCacheForUser(userID string) + NotifySharedChannelUserUpdate(user *model.User) } // errNotFound allows checking against Store.ErrNotFound errors without making Store a dependency. diff --git a/services/sharedchannel/sync_recv.go b/services/sharedchannel/sync_recv.go index ff25a15a99..ffc5f41608 100644 --- a/services/sharedchannel/sync_recv.go +++ b/services/sharedchannel/sync_recv.go @@ -9,6 +9,7 @@ import ( "errors" "fmt" "strconv" + "strings" "github.com/mattermost/mattermost-server/v5/model" "github.com/mattermost/mattermost-server/v5/services/remotecluster" @@ -194,6 +195,7 @@ func (scs *Service) upsertSyncUser(user *model.User, channel *model.Channel, rc FirstName: &user.FirstName, LastName: &user.LastName, Email: &user.Email, + Props: user.Props, Position: &user.Position, Locale: &user.Locale, Timezone: user.Timezone, @@ -226,7 +228,7 @@ func (scs *Service) insertSyncUser(user *model.User, channel *model.Channel, rc var userSaved *model.User var suffix string - // save the originals in props (if not already done by another remote) + // save the original username and email in props (if not already done by another remote) if _, ok := user.GetProp(KeyRemoteUsername); !ok { user.SetProp(KeyRemoteUsername, user.Username) } @@ -262,6 +264,7 @@ func (scs *Service) insertSyncUser(user *model.User, channel *model.Channel, rc ) } } else { + scs.app.NotifySharedChannelUserUpdate(userSaved) return userSaved, nil } } @@ -273,14 +276,22 @@ func (scs *Service) updateSyncUser(patch *model.UserPatch, user *model.User, cha var update *model.UserUpdate var suffix string - if patch.Username != nil { - user.SetProp(KeyRemoteUsername, *patch.Username) + // preserve existing real username/email since Patch will over-write them; + // the real username/email in props can be updated if they don't contain colons, + // meaning the update is coming from the user's origin server (not munged). + realUsername, _ := user.GetProp(KeyRemoteUsername) + realEmail, _ := user.GetProp(KeyRemoteEmail) + + if patch.Username != nil && !strings.Contains(*patch.Username, ":") { + realUsername = *patch.Username } - if patch.Email != nil { - user.SetProp(KeyRemoteEmail, *patch.Email) + if patch.Email != nil && !strings.Contains(*patch.Email, ":") { + realEmail = *patch.Email } user.Patch(patch) + user.SetProp(KeyRemoteUsername, realUsername) + user.SetProp(KeyRemoteEmail, realEmail) // Apply a suffix to the username until it is unique. for i := 1; i <= MaxUpsertRetries; i++ { @@ -306,6 +317,8 @@ func (scs *Service) updateSyncUser(patch *model.UserPatch, user *model.User, cha ) } } else { + scs.app.InvalidateCacheForUser(update.New.Id) + scs.app.NotifySharedChannelUserUpdate(update.New) return update.New, nil } } diff --git a/services/sharedchannel/sync_send.go b/services/sharedchannel/sync_send.go index 075f45b4b6..c4c7b7e621 100644 --- a/services/sharedchannel/sync_send.go +++ b/services/sharedchannel/sync_send.go @@ -300,7 +300,7 @@ func (scs *Service) updateForRemote(task syncTask, rc *model.RemoteCluster) erro return nil } - syncMessages, err := scs.postsToSyncMessages(posts, rc, scr.NextSyncAt) + syncMessages, err := scs.postsToSyncMessages(posts, task.channelId, rc, scr.NextSyncAt) if err != nil { return err } @@ -365,7 +365,7 @@ func (scs *Service) updateForRemote(task syncTask, rc *model.RemoteCluster) erro } // update NextSyncAt for all the users that were synchronized - scs.updateSyncUsers(syncResp.UsersSyncd, rc, nextSince) + scs.updateSyncUsers(syncResp.UsersSyncd, task.channelId, rc, nextSince) }) wg.Wait() @@ -470,9 +470,9 @@ func (scs *Service) updateNextSyncForRemote(scrId string, rc *model.RemoteCluste ) } -func (scs *Service) updateSyncUsers(userIds []string, rc *model.RemoteCluster, lastSyncAt int64) { +func (scs *Service) updateSyncUsers(userIds []string, channelID string, rc *model.RemoteCluster, lastSyncAt int64) { for _, uid := range userIds { - scu, err := scs.server.GetStore().SharedChannel().GetUser(uid, rc.RemoteId) + scu, err := scs.server.GetStore().SharedChannel().GetUser(uid, channelID, rc.RemoteId) if err != nil { scs.server.GetLogger().Log(mlog.LvlSharedChannelServiceError, "error getting user for lastSyncAt update", mlog.String("remote", rc.DisplayName), @@ -486,12 +486,14 @@ func (scs *Service) updateSyncUsers(userIds []string, rc *model.RemoteCluster, l scs.server.GetLogger().Log(mlog.LvlSharedChannelServiceError, "error updating lastSyncAt for user", mlog.String("remote", rc.DisplayName), mlog.String("user_id", uid), + mlog.String("channel_id", channelID), mlog.Err(err), ) } else { scs.server.GetLogger().Log(mlog.LvlSharedChannelServiceDebug, "updated lastSyncAt for user", mlog.String("remote", rc.DisplayName), mlog.String("user_id", scu.UserId), + mlog.String("channel_id", channelID), mlog.Int64("last_update_at", lastSyncAt), ) } diff --git a/store/opentracinglayer/opentracinglayer.go b/store/opentracinglayer/opentracinglayer.go index 59794ab75a..22ce6f027f 100644 --- a/store/opentracinglayer/opentracinglayer.go +++ b/store/opentracinglayer/opentracinglayer.go @@ -6904,7 +6904,7 @@ func (s *OpenTracingLayerSharedChannelStore) GetRemotesStatus(channelId string) return result, err } -func (s *OpenTracingLayerSharedChannelStore) GetUser(userId string, remoteId string) (*model.SharedChannelUser, error) { +func (s *OpenTracingLayerSharedChannelStore) GetUser(userID string, channelID string, remoteID string) (*model.SharedChannelUser, error) { origCtx := s.Root.Store.Context() span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "SharedChannelStore.GetUser") s.Root.Store.SetContext(newCtx) @@ -6913,7 +6913,7 @@ func (s *OpenTracingLayerSharedChannelStore) GetUser(userId string, remoteId str }() defer span.Finish() - result, err := s.SharedChannelStore.GetUser(userId, remoteId) + result, err := s.SharedChannelStore.GetUser(userID, channelID, remoteID) if err != nil { span.LogFields(spanlog.Error(err)) ext.Error.Set(span, true) diff --git a/store/retrylayer/retrylayer.go b/store/retrylayer/retrylayer.go index 49402206af..af2ac756d1 100644 --- a/store/retrylayer/retrylayer.go +++ b/store/retrylayer/retrylayer.go @@ -7486,11 +7486,11 @@ func (s *RetryLayerSharedChannelStore) GetRemotesStatus(channelId string) ([]*mo } -func (s *RetryLayerSharedChannelStore) GetUser(userId string, remoteId string) (*model.SharedChannelUser, error) { +func (s *RetryLayerSharedChannelStore) GetUser(userID string, channelID string, remoteID string) (*model.SharedChannelUser, error) { tries := 0 for { - result, err := s.SharedChannelStore.GetUser(userId, remoteId) + result, err := s.SharedChannelStore.GetUser(userID, channelID, remoteID) if err == nil { return result, nil } diff --git a/store/sqlstore/shared_channel_store.go b/store/sqlstore/shared_channel_store.go index 3d93c80a8f..d2135ef56a 100644 --- a/store/sqlstore/shared_channel_store.go +++ b/store/sqlstore/shared_channel_store.go @@ -47,7 +47,8 @@ func newSqlSharedChannelStore(sqlStore *SqlStore) store.SharedChannelStore { tableSharedChannelUsers.ColMap("Id").SetMaxSize(26) tableSharedChannelUsers.ColMap("UserId").SetMaxSize(26) tableSharedChannelUsers.ColMap("RemoteId").SetMaxSize(26) - tableSharedChannelUsers.SetUniqueTogether("UserId", "RemoteId") + tableSharedChannelUsers.ColMap("ChannelId").SetMaxSize(26) + tableSharedChannelUsers.SetUniqueTogether("UserId", "ChannelId", "RemoteId") tableSharedChannelFiles := db.AddTableWithName(model.SharedChannelAttachment{}, "SharedChannelAttachments").SetKeys(false, "Id") tableSharedChannelFiles.ColMap("Id").SetMaxSize(26) @@ -557,14 +558,15 @@ func (s SqlSharedChannelStore) SaveUser(scUser *model.SharedChannelUser) (*model } // GetUser fetches a shared channel user based on user_id and remoteId. -func (s SqlSharedChannelStore) GetUser(userId string, remoteId string) (*model.SharedChannelUser, error) { +func (s SqlSharedChannelStore) GetUser(userID string, channelID string, remoteID string) (*model.SharedChannelUser, error) { var scu model.SharedChannelUser squery, args, err := s.getQueryBuilder(). Select("*"). From("SharedChannelUsers"). - Where(sq.Eq{"SharedChannelUsers.UserId": userId}). - Where(sq.Eq{"SharedChannelUsers.RemoteId": remoteId}). + Where(sq.Eq{"SharedChannelUsers.UserId": userID}). + Where(sq.Eq{"SharedChannelUsers.RemoteId": remoteID}). + Where(sq.Eq{"SharedChannelUsers.ChannelId": channelID}). ToSql() if err != nil { @@ -573,9 +575,9 @@ func (s SqlSharedChannelStore) GetUser(userId string, remoteId string) (*model.S if err := s.GetReplica().SelectOne(&scu, squery, args...); err != nil { if err == sql.ErrNoRows { - return nil, store.NewErrNotFound("SharedChannelUser", userId) + return nil, store.NewErrNotFound("SharedChannelUser", userID) } - return nil, errors.Wrapf(err, "failed to find shared channel user with UserId=%s, RemoteId=%s", userId, remoteId) + return nil, errors.Wrapf(err, "failed to find shared channel user with UserId=%s, ChannelId=%s, RemoteId=%s", userID, channelID, remoteID) } return &scu, nil } diff --git a/store/sqlstore/upgrade.go b/store/sqlstore/upgrade.go index c0e829d702..565705e033 100644 --- a/store/sqlstore/upgrade.go +++ b/store/sqlstore/upgrade.go @@ -1030,6 +1030,7 @@ func upgradeDatabaseToVersion535(sqlStore *SqlStore) { uniquenessColumns = []string{"RemoteTeamId", "SiteUrl(168)"} } sqlStore.CreateUniqueCompositeIndexIfNotExists(RemoteClusterSiteURLUniqueIndex, "RemoteClusters", uniquenessColumns) + sqlStore.CreateColumnIfNotExists("SharedChannelUsers", "ChannelId", "VARCHAR(26)", "VARCHAR(26)", "") // 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") diff --git a/store/store.go b/store/store.go index 85f411f1c1..adcf1022e6 100644 --- a/store/store.go +++ b/store/store.go @@ -828,7 +828,7 @@ type SharedChannelStore interface { GetRemotesStatus(channelId string) ([]*model.SharedChannelRemoteStatus, error) SaveUser(remote *model.SharedChannelUser) (*model.SharedChannelUser, error) - GetUser(userId string, remoteId string) (*model.SharedChannelUser, error) + GetUser(userID string, channelID string, remoteID string) (*model.SharedChannelUser, error) UpdateUserLastSyncAt(id string, syncTime int64) error SaveAttachment(remote *model.SharedChannelAttachment) (*model.SharedChannelAttachment, error) diff --git a/store/storetest/mocks/SharedChannelStore.go b/store/storetest/mocks/SharedChannelStore.go index 7aa6a4ba42..505c6190fd 100644 --- a/store/storetest/mocks/SharedChannelStore.go +++ b/store/storetest/mocks/SharedChannelStore.go @@ -261,13 +261,13 @@ func (_m *SharedChannelStore) GetRemotesStatus(channelId string) ([]*model.Share return r0, r1 } -// GetUser provides a mock function with given fields: userId, remoteId -func (_m *SharedChannelStore) GetUser(userId string, remoteId string) (*model.SharedChannelUser, error) { - ret := _m.Called(userId, remoteId) +// GetUser provides a mock function with given fields: userID, channelID, remoteID +func (_m *SharedChannelStore) GetUser(userID string, channelID string, remoteID string) (*model.SharedChannelUser, error) { + ret := _m.Called(userID, channelID, remoteID) var r0 *model.SharedChannelUser - if rf, ok := ret.Get(0).(func(string, string) *model.SharedChannelUser); ok { - r0 = rf(userId, remoteId) + if rf, ok := ret.Get(0).(func(string, string, string) *model.SharedChannelUser); ok { + r0 = rf(userID, channelID, remoteID) } else { if ret.Get(0) != nil { r0 = ret.Get(0).(*model.SharedChannelUser) @@ -275,8 +275,8 @@ func (_m *SharedChannelStore) GetUser(userId string, remoteId string) (*model.Sh } var r1 error - if rf, ok := ret.Get(1).(func(string, string) error); ok { - r1 = rf(userId, remoteId) + if rf, ok := ret.Get(1).(func(string, string, string) error); ok { + r1 = rf(userID, channelID, remoteID) } else { r1 = ret.Error(1) } diff --git a/store/storetest/remote_cluster_store.go b/store/storetest/remote_cluster_store.go index 8d1cd3b946..95955dc9a5 100644 --- a/store/storetest/remote_cluster_store.go +++ b/store/storetest/remote_cluster_store.go @@ -36,7 +36,7 @@ func testRemoteClusterSave(t *testing.T, ss store.Store) { rcSaved, err := ss.RemoteCluster().Save(rc) require.NoError(t, err) - require.Equal(t, rc.DisplayName, rcSaved.DisplayName) + require.Equal(t, rc.Name, rcSaved.Name) require.Equal(t, rc.SiteURL, rcSaved.SiteURL) require.Greater(t, rc.CreateAt, int64(0)) require.Equal(t, rc.LastPingAt, int64(0)) @@ -53,7 +53,7 @@ func testRemoteClusterSave(t *testing.T, ss store.Store) { t.Run("Save missing creator id", func(t *testing.T) { rc := &model.RemoteCluster{ - Name: "some_remote 2", + Name: "some_remote_2", SiteURL: "somewhere.com", } _, err := ss.RemoteCluster().Save(rc) diff --git a/store/storetest/shared_channel_store.go b/store/storetest/shared_channel_store.go index 898cc2475b..2a74acbf7d 100644 --- a/store/storetest/shared_channel_store.go +++ b/store/storetest/shared_channel_store.go @@ -843,8 +843,9 @@ func clearSharedChannels(ss store.Store) error { func testSaveSharedChannelUser(t *testing.T, ss store.Store) { t.Run("Save shared channel user", func(t *testing.T) { scUser := &model.SharedChannelUser{ - UserId: model.NewId(), - RemoteId: model.NewId(), + UserId: model.NewId(), + RemoteId: model.NewId(), + ChannelId: model.NewId(), } userSaved, err := ss.SharedChannel().SaveUser(scUser) @@ -877,15 +878,16 @@ func testSaveSharedChannelUser(t *testing.T, ss store.Store) { func testGetSharedChannelUser(t *testing.T, ss store.Store) { scUser := &model.SharedChannelUser{ - UserId: model.NewId(), - RemoteId: model.NewId(), + UserId: model.NewId(), + RemoteId: model.NewId(), + ChannelId: model.NewId(), } userSaved, err := ss.SharedChannel().SaveUser(scUser) require.NoError(t, err, "could not save user", err) t.Run("Get existing shared channel user", func(t *testing.T) { - r, err := ss.SharedChannel().GetUser(userSaved.UserId, userSaved.RemoteId) + r, err := ss.SharedChannel().GetUser(userSaved.UserId, userSaved.ChannelId, userSaved.RemoteId) require.NoError(t, err, "couldn't get shared channel user", err) require.Equal(t, userSaved.Id, r.Id) @@ -895,7 +897,7 @@ func testGetSharedChannelUser(t *testing.T, ss store.Store) { }) t.Run("Get non-existent shared channel user", func(t *testing.T) { - u, err := ss.SharedChannel().GetUser(model.NewId(), model.NewId()) + u, err := ss.SharedChannel().GetUser(model.NewId(), model.NewId(), model.NewId()) require.Error(t, err) require.Nil(t, u) }) @@ -903,8 +905,9 @@ func testGetSharedChannelUser(t *testing.T, ss store.Store) { func testUpdateSharedChannelUserLastSyncAt(t *testing.T, ss store.Store) { scUser := &model.SharedChannelUser{ - UserId: model.NewId(), - RemoteId: model.NewId(), + UserId: model.NewId(), + RemoteId: model.NewId(), + ChannelId: model.NewId(), } userSaved, err := ss.SharedChannel().SaveUser(scUser) @@ -916,7 +919,7 @@ func testUpdateSharedChannelUserLastSyncAt(t *testing.T, ss store.Store) { err := ss.SharedChannel().UpdateUserLastSyncAt(userSaved.Id, future) require.NoError(t, err, "updateLastSyncAt should not error", err) - u, err := ss.SharedChannel().GetUser(userSaved.UserId, userSaved.RemoteId) + u, err := ss.SharedChannel().GetUser(userSaved.UserId, userSaved.ChannelId, userSaved.RemoteId) require.NoError(t, err) require.Equal(t, future, u.LastSyncAt) }) diff --git a/store/timerlayer/timerlayer.go b/store/timerlayer/timerlayer.go index 946e3bd350..7590aee0be 100644 --- a/store/timerlayer/timerlayer.go +++ b/store/timerlayer/timerlayer.go @@ -6238,10 +6238,10 @@ func (s *TimerLayerSharedChannelStore) GetRemotesStatus(channelId string) ([]*mo return result, err } -func (s *TimerLayerSharedChannelStore) GetUser(userId string, remoteId string) (*model.SharedChannelUser, error) { +func (s *TimerLayerSharedChannelStore) GetUser(userID string, channelID string, remoteID string) (*model.SharedChannelUser, error) { start := timemodule.Now() - result, err := s.SharedChannelStore.GetUser(userId, remoteId) + result, err := s.SharedChannelStore.GetUser(userID, channelID, remoteID) elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second) if s.Root.Metrics != nil {