MM-30882: Fix read-after-write issue for demoting user (#16911)

* MM-30882: Fix read-after-write issue for demoting user

In (*App).DemoteUserToGuest, we would demote a user, and then immediately
read it back to do future operations from the user. This reading back
of the user had the effect of sticking the old value into the cache
after which it would never be updated.

There was another issue along with this, which was when the invalidation
message would broadcast across the cluster, it would hit the cache invalidation
problem where an unrelated store call would miss the cache because
it was invalidated, and then again read from replica and stick the old value.

To fix all these, we return the new value directly from the store method
to avoid having the app to read it again.

And we add a map in the localcache layer which tracks invalidations made,
and then switch to use master if it's true.

The core change is fairly limited, but due to changing the store method signatures,
a lot of code needed to be updated to pass "context.Background". Therefore the PR
just "appears" to be big, but the main changes are limited to app/user.go,
sqlstore/user_store.go and user_layer.go

https://mattermost.atlassian.net/browse/MM-30882

```release-note
Fix an issue where demoting a user to guest would not take effect in
an environment with read replicas.
```

* Fix concurrent map access

* Fixing mistakes

* fix tests
Этот коммит содержится в:
Agniva De Sarker
2021-02-12 19:04:05 +05:30
коммит произвёл GitHub
родитель 49907d3081
Коммит 021c90f29f
38 изменённых файлов: 410 добавлений и 288 удалений

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

@@ -4,6 +4,7 @@
package app
import (
"context"
"errors"
"fmt"
"io"
@@ -55,7 +56,7 @@ func (a *App) CreateBot(bot *model.Bot) (*model.Bot, *model.AppError) {
}
// Get the owner of the bot, if one exists. If not, don't send a message
ownerUser, err := a.Srv().Store.User().Get(bot.OwnerId)
ownerUser, err := a.Srv().Store.User().Get(context.Background(), bot.OwnerId)
var nfErr *store.ErrNotFound
if err != nil && !errors.As(err, &nfErr) {
return nil, model.NewAppError("CreateBot", "app.user.get.app_error", nil, err.Error(), http.StatusInternalServerError)
@@ -156,7 +157,7 @@ func (a *App) PatchBot(botUserId string, botPatch *model.BotPatch) (*model.Bot,
bot.Patch(botPatch)
user, nErr := a.Srv().Store.User().Get(botUserId)
user, nErr := a.Srv().Store.User().Get(context.Background(), botUserId)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {
@@ -233,7 +234,7 @@ func (a *App) GetBots(options *model.BotGetOptions) (model.BotList, *model.AppEr
// UpdateBotActive marks a bot as active or inactive, along with its corresponding user.
func (a *App) UpdateBotActive(botUserId string, active bool) (*model.Bot, *model.AppError) {
user, nErr := a.Srv().Store.User().Get(botUserId)
user, nErr := a.Srv().Store.User().Get(context.Background(), botUserId)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {

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

@@ -4,6 +4,7 @@
package app
import (
"context"
"errors"
"fmt"
"net/http"
@@ -67,7 +68,7 @@ func (a *App) JoinDefaultChannels(teamID string, user *model.User, shouldBeAdmin
var requestor *model.User
var nErr error
if userRequestorId != "" {
requestor, nErr = a.Srv().Store.User().Get(userRequestorId)
requestor, nErr = a.Srv().Store.User().Get(context.Background(), userRequestorId)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {
@@ -264,7 +265,7 @@ func (a *App) CreateChannel(channel *model.Channel, addMember bool) (*model.Chan
}
if addMember {
user, nErr := a.Srv().Store.User().Get(channel.CreatorId)
user, nErr := a.Srv().Store.User().Get(context.Background(), channel.CreatorId)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {
@@ -386,7 +387,7 @@ func (a *App) handleCreationEvent(userID, otherUserID string, channel *model.Cha
}
func (a *App) createDirectChannel(userID, otherUserID string) (*model.Channel, *model.AppError) {
users, err := a.Srv().Store.User().GetMany([]string{userID, otherUserID})
users, err := a.Srv().Store.User().GetMany(context.Background(), []string{userID, otherUserID})
if err != nil {
return nil, model.NewAppError("CreateDirectChannel", "api.channel.create_direct_channel.invalid_user.app_error", nil, err.Error(), http.StatusBadRequest)
}
@@ -520,7 +521,7 @@ func (a *App) createGroupChannel(userIDs []string) (*model.Channel, *model.AppEr
return nil, model.NewAppError("CreateGroupChannel", "api.channel.create_group.bad_size.app_error", nil, "", http.StatusBadRequest)
}
users, err := a.Srv().Store.User().GetProfileByIds(userIDs, nil, true)
users, err := a.Srv().Store.User().GetProfileByIds(context.Background(), userIDs, nil, true)
if err != nil {
return nil, model.NewAppError("createGroupChannel", "app.user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -599,7 +600,7 @@ func (a *App) GetGroupChannel(userIDs []string) (*model.Channel, *model.AppError
return nil, model.NewAppError("GetGroupChannel", "api.channel.create_group.bad_size.app_error", nil, "", http.StatusBadRequest)
}
users, err := a.Srv().Store.User().GetProfileByIds(userIDs, nil, true)
users, err := a.Srv().Store.User().GetProfileByIds(context.Background(), userIDs, nil, true)
if err != nil {
return nil, model.NewAppError("GetGroupChannel", "app.user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -745,7 +746,7 @@ func (a *App) RestoreChannel(channel *model.Channel, userID string) (*model.Chan
message.Add("channel_id", channel.Id)
a.Publish(message)
user, nErr := a.Srv().Store.User().Get(userID)
user, nErr := a.Srv().Store.User().Get(context.Background(), userID)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {
@@ -1236,7 +1237,7 @@ func (a *App) DeleteChannel(channel *model.Channel, userID string) *model.AppErr
var user *model.User
if userID != "" {
var nErr error
user, nErr = a.Srv().Store.User().Get(userID)
user, nErr = a.Srv().Store.User().Get(context.Background(), userID)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {
@@ -1492,7 +1493,7 @@ func (a *App) AddDirectChannels(teamID string, user *model.User) *model.AppError
}
func (a *App) PostUpdateChannelHeaderMessage(userID string, channel *model.Channel, oldChannelHeader, newChannelHeader string) *model.AppError {
user, err := a.Srv().Store.User().Get(userID)
user, err := a.Srv().Store.User().Get(context.Background(), userID)
if err != nil {
return model.NewAppError("PostUpdateChannelHeaderMessage", "api.channel.post_update_channel_header_message_and_forget.retrieve_user.error", nil, err.Error(), http.StatusBadRequest)
}
@@ -1526,7 +1527,7 @@ func (a *App) PostUpdateChannelHeaderMessage(userID string, channel *model.Chann
}
func (a *App) PostUpdateChannelPurposeMessage(userID string, channel *model.Channel, oldChannelPurpose string, newChannelPurpose string) *model.AppError {
user, err := a.Srv().Store.User().Get(userID)
user, err := a.Srv().Store.User().Get(context.Background(), userID)
if err != nil {
return model.NewAppError("PostUpdateChannelPurposeMessage", "app.channel.post_update_channel_purpose_message.retrieve_user.error", nil, err.Error(), http.StatusBadRequest)
}
@@ -1559,7 +1560,7 @@ func (a *App) PostUpdateChannelPurposeMessage(userID string, channel *model.Chan
}
func (a *App) PostUpdateChannelDisplayNameMessage(userID string, channel *model.Channel, oldChannelDisplayName, newChannelDisplayName string) *model.AppError {
user, err := a.Srv().Store.User().Get(userID)
user, err := a.Srv().Store.User().Get(context.Background(), userID)
if err != nil {
return model.NewAppError("PostUpdateChannelDisplayNameMessage", "api.channel.post_update_channel_displayname_message_and_forget.retrieve_user.error", nil, err.Error(), http.StatusBadRequest)
}
@@ -1905,7 +1906,7 @@ func (a *App) JoinChannel(channel *model.Channel, userID string) *model.AppError
userChan := make(chan store.StoreResult, 1)
memberChan := make(chan store.StoreResult, 1)
go func() {
user, err := a.Srv().Store.User().Get(userID)
user, err := a.Srv().Store.User().Get(context.Background(), userID)
userChan <- store.StoreResult{Data: user, NErr: err}
close(userChan)
}()
@@ -2014,7 +2015,7 @@ func (a *App) LeaveChannel(channelId string, userID string) *model.AppError {
uc := make(chan store.StoreResult, 1)
go func() {
user, err := a.Srv().Store.User().Get(userID)
user, err := a.Srv().Store.User().Get(context.Background(), userID)
uc <- store.StoreResult{Data: user, NErr: err}
close(uc)
}()
@@ -2176,7 +2177,7 @@ func (a *App) postRemoveFromChannelMessage(removerUserId string, removedUser *mo
}
func (a *App) removeUserFromChannel(userIDToRemove string, removerUserId string, channel *model.Channel) *model.AppError {
user, nErr := a.Srv().Store.User().Get(userIDToRemove)
user, nErr := a.Srv().Store.User().Get(context.Background(), userIDToRemove)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {

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

@@ -4,6 +4,7 @@
package app
import (
"context"
"fmt"
"net/http"
"sort"
@@ -1910,7 +1911,7 @@ func TestMarkChannelsAsViewedPanic(t *testing.T) {
mockStore := th.App.Srv().Store.(*mocks.Store)
mockUserStore := mocks.UserStore{}
mockUserStore.On("Get", "userID").Return(nil, model.NewAppError("SqlUserStore.Get", "app.user.get.app_error", nil, "user_id=userID", http.StatusInternalServerError))
mockUserStore.On("Get", context.Background(), "userID").Return(nil, model.NewAppError("SqlUserStore.Get", "app.user.get.app_error", nil, "user_id=userID", http.StatusInternalServerError))
mockChannelStore := mocks.ChannelStore{}
mockChannelStore.On("Get", "channelID", true).Return(&model.Channel{}, nil)
mockChannelStore.On("GetMember", "channelID", "userID").Return(&model.ChannelMember{

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

@@ -4,6 +4,7 @@
package app
import (
"context"
"errors"
"io"
"io/ioutil"
@@ -368,7 +369,7 @@ func (a *App) tryExecuteCustomCommand(args *model.CommandArgs, trigger string, m
userChan := make(chan store.StoreResult, 1)
go func() {
user, err := a.Srv().Store.User().Get(args.UserId)
user, err := a.Srv().Store.User().Get(context.Background(), args.UserId)
userChan <- store.StoreResult{Data: user, NErr: err}
close(userChan)
}()

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

@@ -4,6 +4,7 @@
package app
import (
"context"
"fmt"
"html/template"
"net/http"
@@ -194,7 +195,7 @@ func (job *EmailBatchingJob) checkPendingNotifications(now time.Time, handler fu
}
func (es *EmailService) sendBatchedEmailNotification(userID string, notifications []*batchedNotification) {
user, err := es.srv.Store.User().Get(userID)
user, err := es.srv.Store.User().Get(context.Background(), userID)
if err != nil {
mlog.Warn("Unable to find recipient for batched email notification")
return
@@ -205,7 +206,7 @@ func (es *EmailService) sendBatchedEmailNotification(userID string, notification
var contents string
for _, notification := range notifications {
sender, err := es.srv.Store.User().Get(notification.post.UserId)
sender, err := es.srv.Store.User().Get(context.Background(), notification.post.UserId)
if err != nil {
mlog.Warn("Unable to find sender of post for batched email notification")
continue

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

@@ -5,6 +5,7 @@ package app
import (
"archive/zip"
"context"
"encoding/json"
"io"
"net/http"
@@ -483,7 +484,7 @@ func (a *App) BuildPostReactions(postId string) (*[]ReactionImportData, *model.A
}
for _, reaction := range reactions {
user, err := a.Srv().Store.User().Get(reaction.UserId)
user, err := a.Srv().Store.User().Get(context.Background(), reaction.UserId)
if err != nil {
var nfErr *store.ErrNotFound
if errors.As(err, &nfErr) { // this is a valid case, the user that reacted might've been deleted by now

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

@@ -19,6 +19,7 @@ package app
import (
"bytes"
"context"
"encoding/json"
"errors"
"fmt"
@@ -84,7 +85,7 @@ func (a *App) DoPostActionWithCookie(postId, actionId, userID, selectedOption st
userChan := make(chan store.StoreResult, 1)
go func() {
user, err := a.Srv().Store.User().Get(upstreamRequest.UserId)
user, err := a.Srv().Store.User().Get(context.Background(), upstreamRequest.UserId)
userChan <- store.StoreResult{Data: user, NErr: err}
close(userChan)
}()

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

@@ -4,6 +4,7 @@
package app
import (
"context"
"net/http"
"sort"
"strconv"
@@ -28,7 +29,7 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
pchan := make(chan store.StoreResult, 1)
go func() {
props, err := a.Srv().Store.User().GetAllProfilesInChannel(channel.Id, true)
props, err := a.Srv().Store.User().GetAllProfilesInChannel(context.Background(), channel.Id, true)
pchan <- store.StoreResult{Data: props, NErr: err}
close(pchan)
}()

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

@@ -5,6 +5,7 @@ package app
import (
"bytes"
"context"
b64 "encoding/base64"
"errors"
"fmt"
@@ -288,7 +289,7 @@ func (a *App) GetOAuthAccessTokenForCodeFlow(clientId, grantType, redirectUri, c
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.redirect_uri.app_error", nil, "", http.StatusBadRequest)
}
user, nErr = a.Srv().Store.User().Get(authData.UserId)
user, nErr = a.Srv().Store.User().Get(context.Background(), authData.UserId)
if nErr != nil {
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.internal_user.app_error", nil, "", http.StatusNotFound)
}
@@ -347,7 +348,7 @@ func (a *App) GetOAuthAccessTokenForCodeFlow(clientId, grantType, redirectUri, c
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.refresh_token.app_error", nil, "", http.StatusNotFound)
}
user, nErr := a.Srv().Store.User().Get(accessData.UserId)
user, nErr := a.Srv().Store.User().Get(context.Background(), accessData.UserId)
if nErr != nil {
return nil, model.NewAppError("GetOAuthAccessToken", "api.oauth.get_access_token.internal_user.app_error", nil, "", http.StatusNotFound)
}

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

@@ -4,6 +4,7 @@
package app
import (
"context"
"encoding/json"
"errors"
"fmt"
@@ -53,7 +54,7 @@ func (a *App) CreatePostAsUser(post *model.Post, currentSessionId string, setOnl
}
if err.Id == "api.post.create_post.town_square_read_only" {
user, nErr := a.Srv().Store.User().Get(post.UserId)
user, nErr := a.Srv().Store.User().Get(context.Background(), post.UserId)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {
@@ -191,7 +192,7 @@ func (a *App) CreatePost(post *model.Post, channel *model.Channel, triggerWebhoo
}()
}
user, nErr := a.Srv().Store.User().Get(post.UserId)
user, nErr := a.Srv().Store.User().Get(context.Background(), post.UserId)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {

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

@@ -4,6 +4,7 @@
package app
import (
"context"
"errors"
"fmt"
"math"
@@ -427,7 +428,7 @@ func (a *App) SetSessionExpireInDays(session *model.Session, days int) {
func (a *App) CreateUserAccessToken(token *model.UserAccessToken) (*model.UserAccessToken, *model.AppError) {
user, nErr := a.Srv().Store.User().Get(token.UserId)
user, nErr := a.Srv().Store.User().Get(context.Background(), token.UserId)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {
@@ -476,7 +477,7 @@ func (a *App) createSessionForUserAccessToken(tokenString string) (*model.Sessio
return nil, model.NewAppError("createSessionForUserAccessToken", "app.user_access_token.invalid_or_missing", nil, "inactive_token", http.StatusUnauthorized)
}
user, nErr := a.Srv().Store.User().Get(token.UserId)
user, nErr := a.Srv().Store.User().Get(context.Background(), token.UserId)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {

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

@@ -5,6 +5,7 @@ package app
import (
"bytes"
"context"
"fmt"
"mime/multipart"
"regexp"
@@ -88,7 +89,7 @@ func replaceUserIds(userStore store.UserStore, text string) string {
userIDs = append(userIDs, match[1])
}
if users, err := userStore.GetProfileByIds(userIDs, nil, true); err == nil {
if users, err := userStore.GetProfileByIds(context.Background(), userIDs, nil, true); err == nil {
for _, user := range users {
text = strings.Replace(text, "<@"+user.Id+">", "@"+user.Username, -1)
}

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

@@ -489,7 +489,7 @@ func (a *App) AddUserToTeam(teamID string, userID string, userRequestorId string
uchan := make(chan store.StoreResult, 1)
go func() {
user, err := a.Srv().Store.User().Get(userID)
user, err := a.Srv().Store.User().Get(context.Background(), userID)
uchan <- store.StoreResult{Data: user, NErr: err}
close(uchan)
}()
@@ -566,7 +566,7 @@ func (a *App) AddUserToTeamByToken(userID string, tokenID string) (*model.Team,
uchan := make(chan store.StoreResult, 1)
go func() {
user, err := a.Srv().Store.User().Get(userID)
user, err := a.Srv().Store.User().Get(context.Background(), userID)
uchan <- store.StoreResult{Data: user, NErr: err}
close(uchan)
}()
@@ -641,7 +641,7 @@ func (a *App) AddUserToTeamByInviteId(inviteId string, userID string) (*model.Te
uchan := make(chan store.StoreResult, 1)
go func() {
user, err := a.Srv().Store.User().Get(userID)
user, err := a.Srv().Store.User().Get(context.Background(), userID)
uchan <- store.StoreResult{Data: user, NErr: err}
close(uchan)
}()
@@ -1163,7 +1163,7 @@ func (a *App) RemoveUserFromTeam(teamID string, userID string, requestorId strin
uchan := make(chan store.StoreResult, 1)
go func() {
user, err := a.Srv().Store.User().Get(userID)
user, err := a.Srv().Store.User().Get(context.Background(), userID)
uchan <- store.StoreResult{Data: user, NErr: err}
close(uchan)
}()
@@ -1206,7 +1206,7 @@ func (a *App) RemoveTeamMemberFromTeam(teamMember *model.TeamMember, requestorId
message.Add("team_id", teamMember.TeamId)
a.Publish(message)
user, nErr := a.Srv().Store.User().Get(teamMember.UserId)
user, nErr := a.Srv().Store.User().Get(context.Background(), teamMember.UserId)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {
@@ -1368,7 +1368,7 @@ func (a *App) prepareInviteNewUsersToTeam(teamID, senderId string) (*model.User,
uchan := make(chan store.StoreResult, 1)
go func() {
user, err := a.Srv().Store.User().Get(senderId)
user, err := a.Srv().Store.User().Get(context.Background(), senderId)
uchan <- store.StoreResult{Data: user, NErr: err}
close(uchan)
}()
@@ -1499,7 +1499,7 @@ func (a *App) prepareInviteGuestsToChannels(teamID string, guestsInvite *model.G
}()
uchan := make(chan store.StoreResult, 1)
go func() {
user, err := a.Srv().Store.User().Get(senderId)
user, err := a.Srv().Store.User().Get(context.Background(), senderId)
uchan <- store.StoreResult{Data: user, NErr: err}
close(uchan)
}()

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

@@ -5,6 +5,7 @@ package app
import (
"bytes"
"context"
b64 "encoding/base64"
"encoding/json"
"errors"
@@ -432,7 +433,7 @@ func (a *App) IsUsernameTaken(name string) bool {
}
func (a *App) GetUser(userID string) (*model.User, *model.AppError) {
user, err := a.Srv().Store.User().Get(userID)
user, err := a.Srv().Store.User().Get(context.Background(), userID)
if err != nil {
var nfErr *store.ErrNotFound
switch {
@@ -683,7 +684,7 @@ func (a *App) GetChannelGroupUsers(channelID string) ([]*model.User, *model.AppE
func (a *App) GetUsersByIds(userIDs []string, options *store.UserGetByIdsOpts) ([]*model.User, *model.AppError) {
allowFromCache := options.ViewRestrictions == nil
users, err := a.Srv().Store.User().GetProfileByIds(userIDs, options, allowFromCache)
users, err := a.Srv().Store.User().GetProfileByIds(context.Background(), userIDs, options, allowFromCache)
if err != nil {
return nil, model.NewAppError("GetUsersByIds", "app.user.get_profiles.app_error", nil, err.Error(), http.StatusInternalServerError)
}
@@ -739,7 +740,7 @@ func (a *App) GenerateMfaSecret(userID string) (*model.MfaSecret, *model.AppErro
}
func (a *App) ActivateMfa(userID, token string) *model.AppError {
user, err := a.Srv().Store.User().Get(userID)
user, err := a.Srv().Store.User().Get(context.Background(), userID)
if err != nil {
var nfErr *store.ErrNotFound
switch {
@@ -1212,7 +1213,7 @@ func (a *App) sendUpdatedUserEvent(user model.User) {
}
func (a *App) UpdateUser(user *model.User, sendNotifications bool) (*model.User, *model.AppError) {
prev, err := a.Srv().Store.User().Get(user.Id)
prev, err := a.Srv().Store.User().Get(context.Background(), user.Id)
if err != nil {
var nfErr *store.ErrNotFound
switch {
@@ -2058,7 +2059,7 @@ func (a *App) FilterNonGroupChannelMembers(userIDs []string, channel *model.Chan
// and returns the list of normal users present in userIDs but not in groupUsers.
func (a *App) filterNonGroupUsers(userIDs []string, groupUsers []*model.User) ([]string, error) {
nonMemberIds := []string{}
users, err := a.Srv().Store.User().GetProfileByIds(userIDs, nil, false)
users, err := a.Srv().Store.User().GetProfileByIds(context.Background(), userIDs, nil, false)
if err != nil {
return nil, err
}
@@ -2223,19 +2224,14 @@ func (a *App) PromoteGuestToUser(user *model.User, requestorId string) *model.Ap
// DemoteUserToGuest Convert user's roles and all his mermbership's roles from
// regular user roles to guest roles.
func (a *App) DemoteUserToGuest(user *model.User) *model.AppError {
nErr := a.Srv().Store.User().DemoteUserToGuest(user.Id)
demotedUser, nErr := a.Srv().Store.User().DemoteUserToGuest(user.Id)
a.InvalidateCacheForUser(user.Id)
if nErr != nil {
return model.NewAppError("DemoteUserToGuest", "app.user.demote_user_to_guest.user_update.app_error", nil, nErr.Error(), http.StatusInternalServerError)
}
demotedUser, err := a.GetUser(user.Id)
if err != nil {
mlog.Warn("Failed to get user on demote user to guest", mlog.Err(err))
} else {
a.sendUpdatedUserEvent(*demotedUser)
a.UpdateSessionsIsGuest(demotedUser.Id, demotedUser.IsGuest())
}
a.sendUpdatedUserEvent(*demotedUser)
a.UpdateSessionsIsGuest(demotedUser.Id, demotedUser.IsGuest())
teamMembers, err := a.GetTeamMembersForUser(user.Id)
if err != nil {
@@ -2248,6 +2244,7 @@ func (a *App) DemoteUserToGuest(user *model.User) *model.AppError {
channelMembers, err := a.GetChannelMembersForUser(member.TeamId, user.Id)
if err != nil {
mlog.Warn("Failed to get channel members for users on demote user to guest", mlog.Err(err))
continue
}
for _, member := range *channelMembers {
@@ -2260,7 +2257,6 @@ func (a *App) DemoteUserToGuest(user *model.User) *model.AppError {
}
a.ClearSessionCacheForUser(user.Id)
return nil
}
@@ -2308,7 +2304,7 @@ func (a *App) GetKnownUsers(userID string) ([]string, *model.AppError) {
// ConvertBotToUser converts a bot to user.
func (a *App) ConvertBotToUser(bot *model.Bot, userPatch *model.UserPatch, sysadmin bool) (*model.User, *model.AppError) {
user, nErr := a.Srv().Store.User().Get(bot.UserId)
user, nErr := a.Srv().Store.User().Get(context.Background(), bot.UserId)
if nErr != nil {
var nfErr *store.ErrNotFound
switch {

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

@@ -4,6 +4,7 @@
package app
import (
"context"
"errors"
"io"
"net/http"
@@ -674,7 +675,7 @@ func (a *App) HandleIncomingWebhook(hookID string, req *model.IncomingWebhookReq
uchan := make(chan store.StoreResult, 1)
go func() {
user, err := a.Srv().Store.User().Get(hook.UserId)
user, err := a.Srv().Store.User().Get(context.Background(), hook.UserId)
uchan <- store.StoreResult{Data: user, NErr: err}
close(uchan)
}()

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

@@ -4,6 +4,7 @@
package commands
import (
"context"
"testing"
"github.com/stretchr/testify/require"
@@ -115,7 +116,7 @@ func TestDeleteUserBotUser(t *testing.T) {
defer th.TearDown()
th.CheckCommand(t, "user", "delete", th.BasicUser.Username, "--confirm")
_, err := th.App.Srv().Store.User().Get(th.BasicUser.Id)
_, err := th.App.Srv().Store.User().Get(context.Background(), th.BasicUser.Id)
require.Error(t, err)
// Make a bot
@@ -131,7 +132,7 @@ func TestDeleteUserBotUser(t *testing.T) {
require.Nil(t, nErr)
th.CheckCommand(t, "user", "delete", bot.Username, "--confirm")
_, err = th.App.Srv().Store.User().Get(user.Id)
_, err = th.App.Srv().Store.User().Get(context.Background(), user.Id)
require.Error(t, err)
_, nErr = th.App.Srv().Store.Bot().Get(user.Id, true)
require.Error(t, nErr)
@@ -199,7 +200,7 @@ func TestConvertUser(t *testing.T) {
_, err = th.App.Srv().Store.Bot().Get(th.BasicUser2.Id, false)
require.NotNil(t, err)
user, appErr := th.App.Srv().Store.User().Get(th.BasicUser2.Id)
user, appErr := th.App.Srv().Store.User().Get(context.Background(), th.BasicUser2.Id)
require.Nil(t, appErr)
require.Equal(t, "newusername", user.Username)
require.Equal(t, "valid@email.com", user.Email)

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

@@ -4,6 +4,8 @@
package commands
import (
"context"
"github.com/mattermost/mattermost-server/v5/app"
"github.com/mattermost/mattermost-server/v5/model"
)
@@ -28,7 +30,7 @@ func getUserFromUserArg(a *app.App, userArg string) *model.User {
}
if user == nil {
user, _ = a.Srv().Store.User().Get(userArg)
user, _ = a.Srv().Store.User().Get(context.Background(), userArg)
}
return user

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

@@ -98,7 +98,7 @@ type LocalCacheStore struct {
postLastPostsCache cache.Cache
lastPostTimeCache cache.Cache
user LocalCacheUserStore
user *LocalCacheUserStore
userProfileByIdsCache cache.Cache
profilesInChannelCache cache.Cache
@@ -283,7 +283,12 @@ func NewLocalCacheLayer(baseStore store.Store, metrics einterfaces.MetricsInterf
}); err != nil {
return
}
localCacheStore.user = LocalCacheUserStore{UserStore: baseStore.User(), rootStore: &localCacheStore}
localCacheStore.user = &LocalCacheUserStore{
UserStore: baseStore.User(),
rootStore: &localCacheStore,
userProfileByIdsInvalidations: make(map[string]bool),
profilesInChannelInvalidations: make(map[string]bool),
}
// Teams
if localCacheStore.teamAllTeamIdsForUserCache, err = cacheProvider.NewCache(&cache.CacheOptions{

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

@@ -132,16 +132,16 @@ func getMockStore() *mocks.Store {
AuthService: "authService",
}}
mockUserStore := mocks.UserStore{}
mockUserStore.On("GetProfileByIds", []string{"123"}, &store.UserGetByIdsOpts{}, true).Return(fakeUser, nil)
mockUserStore.On("GetProfileByIds", []string{"123"}, &store.UserGetByIdsOpts{}, false).Return(fakeUser, nil)
mockUserStore.On("GetProfileByIds", mock.Anything, []string{"123"}, &store.UserGetByIdsOpts{}, true).Return(fakeUser, nil)
mockUserStore.On("GetProfileByIds", mock.Anything, []string{"123"}, &store.UserGetByIdsOpts{}, false).Return(fakeUser, nil)
fakeProfilesInChannelMap := map[string]*model.User{
"456": {Id: "456"},
}
mockUserStore.On("GetAllProfilesInChannel", "123", true).Return(fakeProfilesInChannelMap, nil)
mockUserStore.On("GetAllProfilesInChannel", "123", false).Return(fakeProfilesInChannelMap, nil)
mockUserStore.On("GetAllProfilesInChannel", mock.Anything, "123", true).Return(fakeProfilesInChannelMap, nil)
mockUserStore.On("GetAllProfilesInChannel", mock.Anything, "123", false).Return(fakeProfilesInChannelMap, nil)
mockUserStore.On("Get", "123").Return(fakeUser[0], nil)
mockUserStore.On("Get", mock.Anything, "123").Return(fakeUser[0], nil)
users := []*model.User{
fakeUser[0],
{
@@ -150,8 +150,8 @@ func getMockStore() *mocks.Store {
AuthService: "authService",
},
}
mockUserStore.On("GetMany", []string{"123", "456"}).Return(users, nil)
mockUserStore.On("GetMany", []string{"123"}).Return(users[0:1], nil)
mockUserStore.On("GetMany", mock.Anything, []string{"123", "456"}).Return(users, nil)
mockUserStore.On("GetMany", mock.Anything, []string{"123"}).Return(users[0:1], nil)
mockStore.On("User").Return(&mockUserStore)
fakeUserTeamIds := []string{"1", "2", "3"}

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

@@ -4,21 +4,31 @@
package localcachelayer
import (
"context"
"sort"
"sync"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/store"
"github.com/mattermost/mattermost-server/v5/store/sqlstore"
)
type LocalCacheUserStore struct {
store.UserStore
rootStore *LocalCacheStore
rootStore *LocalCacheStore
userProfileByIdsMut sync.Mutex
userProfileByIdsInvalidations map[string]bool
profilesInChannelMut sync.Mutex
profilesInChannelInvalidations map[string]bool
}
func (s *LocalCacheUserStore) handleClusterInvalidateScheme(msg *model.ClusterMessage) {
if msg.Data == ClearCacheMessageData {
s.rootStore.userProfileByIdsCache.Purge()
} else {
s.userProfileByIdsMut.Lock()
s.userProfileByIdsInvalidations[msg.Data] = true
s.userProfileByIdsMut.Unlock()
s.rootStore.userProfileByIdsCache.Remove(msg.Data)
}
}
@@ -27,11 +37,14 @@ func (s *LocalCacheUserStore) handleClusterInvalidateProfilesInChannel(msg *mode
if msg.Data == ClearCacheMessageData {
s.rootStore.profilesInChannelCache.Purge()
} else {
s.profilesInChannelMut.Lock()
s.profilesInChannelInvalidations[msg.Data] = true
s.profilesInChannelMut.Unlock()
s.rootStore.profilesInChannelCache.Remove(msg.Data)
}
}
func (s LocalCacheUserStore) ClearCaches() {
func (s *LocalCacheUserStore) ClearCaches() {
s.rootStore.userProfileByIdsCache.Purge()
s.rootStore.profilesInChannelCache.Purge()
@@ -41,7 +54,10 @@ func (s LocalCacheUserStore) ClearCaches() {
}
}
func (s LocalCacheUserStore) InvalidateProfileCacheForUser(userId string) {
func (s *LocalCacheUserStore) InvalidateProfileCacheForUser(userId string) {
s.userProfileByIdsMut.Lock()
s.userProfileByIdsInvalidations[userId] = true
s.userProfileByIdsMut.Unlock()
s.rootStore.doInvalidateCacheCluster(s.rootStore.userProfileByIdsCache, userId)
if s.rootStore.metrics != nil {
@@ -49,13 +65,16 @@ func (s LocalCacheUserStore) InvalidateProfileCacheForUser(userId string) {
}
}
func (s LocalCacheUserStore) InvalidateProfilesInChannelCacheByUser(userId string) {
func (s *LocalCacheUserStore) InvalidateProfilesInChannelCacheByUser(userId string) {
keys, err := s.rootStore.profilesInChannelCache.Keys()
if err == nil {
for _, key := range keys {
var userMap map[string]*model.User
if err = s.rootStore.profilesInChannelCache.Get(key, &userMap); err == nil {
if _, userInCache := userMap[userId]; userInCache {
s.profilesInChannelMut.Lock()
s.profilesInChannelInvalidations[key] = true
s.profilesInChannelMut.Unlock()
s.rootStore.doInvalidateCacheCluster(s.rootStore.profilesInChannelCache, key)
if s.rootStore.metrics != nil {
s.rootStore.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Remove by User")
@@ -66,14 +85,17 @@ func (s LocalCacheUserStore) InvalidateProfilesInChannelCacheByUser(userId strin
}
}
func (s LocalCacheUserStore) InvalidateProfilesInChannelCache(channelId string) {
s.rootStore.doInvalidateCacheCluster(s.rootStore.profilesInChannelCache, channelId)
func (s *LocalCacheUserStore) InvalidateProfilesInChannelCache(channelID string) {
s.profilesInChannelMut.Lock()
s.profilesInChannelInvalidations[channelID] = true
s.profilesInChannelMut.Unlock()
s.rootStore.doInvalidateCacheCluster(s.rootStore.profilesInChannelCache, channelID)
if s.rootStore.metrics != nil {
s.rootStore.metrics.IncrementMemCacheInvalidationCounter("Profiles in Channel - Remove by Channel")
}
}
func (s LocalCacheUserStore) GetAllProfilesInChannel(channelId string, allowFromCache bool) (map[string]*model.User, error) {
func (s *LocalCacheUserStore) GetAllProfilesInChannel(ctx context.Context, channelId string, allowFromCache bool) (map[string]*model.User, error) {
if allowFromCache {
var cachedMap map[string]*model.User
if err := s.rootStore.doStandardReadCache(s.rootStore.profilesInChannelCache, channelId, &cachedMap); err == nil {
@@ -81,7 +103,16 @@ func (s LocalCacheUserStore) GetAllProfilesInChannel(channelId string, allowFrom
}
}
userMap, err := s.UserStore.GetAllProfilesInChannel(channelId, allowFromCache)
// If it was invalidated, then we need to query master.
s.profilesInChannelMut.Lock()
if s.profilesInChannelInvalidations[channelId] {
ctx = sqlstore.WithMaster(ctx)
// And then remove the key from the map.
delete(s.profilesInChannelInvalidations, channelId)
}
s.profilesInChannelMut.Unlock()
userMap, err := s.UserStore.GetAllProfilesInChannel(ctx, channelId, allowFromCache)
if err != nil {
return nil, err
}
@@ -93,9 +124,9 @@ func (s LocalCacheUserStore) GetAllProfilesInChannel(channelId string, allowFrom
return userMap, nil
}
func (s LocalCacheUserStore) GetProfileByIds(userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error) {
func (s *LocalCacheUserStore) GetProfileByIds(ctx context.Context, userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error) {
if !allowFromCache {
return s.UserStore.GetProfileByIds(userIds, options, false)
return s.UserStore.GetProfileByIds(ctx, userIds, options, false)
}
if options == nil {
@@ -105,6 +136,7 @@ func (s LocalCacheUserStore) GetProfileByIds(userIds []string, options *store.Us
users := []*model.User{}
remainingUserIds := make([]string, 0)
fromMaster := false
for _, userId := range userIds {
var cacheItem *model.User
if err := s.rootStore.doStandardReadCache(s.rootStore.userProfileByIdsCache, userId, &cacheItem); err == nil {
@@ -112,6 +144,14 @@ func (s LocalCacheUserStore) GetProfileByIds(userIds []string, options *store.Us
users = append(users, cacheItem)
}
} else {
// If it was invalidated, then we need to query master.
s.userProfileByIdsMut.Lock()
if s.userProfileByIdsInvalidations[userId] {
fromMaster = true
// And then remove the key from the map.
delete(s.userProfileByIdsInvalidations, userId)
}
s.userProfileByIdsMut.Unlock()
remainingUserIds = append(remainingUserIds, userId)
}
}
@@ -122,7 +162,10 @@ func (s LocalCacheUserStore) GetProfileByIds(userIds []string, options *store.Us
}
if len(remainingUserIds) > 0 {
remainingUsers, err := s.UserStore.GetProfileByIds(remainingUserIds, options, false)
if fromMaster {
ctx = sqlstore.WithMaster(ctx)
}
remainingUsers, err := s.UserStore.GetProfileByIds(ctx, remainingUserIds, options, false)
if err != nil {
return nil, err
}
@@ -139,7 +182,7 @@ func (s LocalCacheUserStore) GetProfileByIds(userIds []string, options *store.Us
// It checks if the user entry is present in the cache, returning the entry from cache
// if it is present. Otherwise, it fetches the entry from the store and stores it in the
// cache.
func (s LocalCacheUserStore) Get(id string) (*model.User, error) {
func (s *LocalCacheUserStore) Get(ctx context.Context, id string) (*model.User, error) {
var cacheItem *model.User
if err := s.rootStore.doStandardReadCache(s.rootStore.userProfileByIdsCache, id, &cacheItem); err == nil {
if s.rootStore.metrics != nil {
@@ -150,7 +193,17 @@ func (s LocalCacheUserStore) Get(id string) (*model.User, error) {
if s.rootStore.metrics != nil {
s.rootStore.metrics.AddMemCacheMissCounter("Profile By Id", float64(1))
}
user, err := s.UserStore.Get(id)
// If it was invalidated, then we need to query master.
s.userProfileByIdsMut.Lock()
if s.userProfileByIdsInvalidations[id] {
ctx = sqlstore.WithMaster(ctx)
// And then remove the key from the map.
delete(s.userProfileByIdsInvalidations, id)
}
s.userProfileByIdsMut.Unlock()
user, err := s.UserStore.Get(ctx, id)
if err != nil {
return nil, err
}
@@ -162,13 +215,14 @@ func (s LocalCacheUserStore) Get(id string) (*model.User, error) {
// It checks if the user entries are present in the cache, returning the entries from cache
// if it is present. Otherwise, it fetches the entries from the store and stores it in the
// cache.
func (s LocalCacheUserStore) GetMany(ids []string) ([]*model.User, error) {
func (s *LocalCacheUserStore) GetMany(ctx context.Context, ids []string) ([]*model.User, error) {
// we are doing a loop instead of caching the full set in the cache because the number of permutations that we can have
// in this func is making caching of the total set not beneficial.
var cachedUsers []*model.User
var notCachedUserIds []string
uniqIDs := dedup(ids)
fromMaster := false
for _, id := range uniqIDs {
var cachedUser *model.User
if err := s.rootStore.doStandardReadCache(s.rootStore.userProfileByIdsCache, id, &cachedUser); err == nil {
@@ -180,13 +234,24 @@ func (s LocalCacheUserStore) GetMany(ids []string) ([]*model.User, error) {
if s.rootStore.metrics != nil {
s.rootStore.metrics.AddMemCacheMissCounter("Profile By Id", float64(1))
}
// If it was invalidated, then we need to query master.
s.userProfileByIdsMut.Lock()
if s.userProfileByIdsInvalidations[id] {
fromMaster = true
// And then remove the key from the map.
delete(s.userProfileByIdsInvalidations, id)
}
s.userProfileByIdsMut.Unlock()
notCachedUserIds = append(notCachedUserIds, id)
}
}
if len(notCachedUserIds) > 0 {
dbUsers, err := s.UserStore.GetMany(notCachedUserIds)
if fromMaster {
ctx = sqlstore.WithMaster(ctx)
}
dbUsers, err := s.UserStore.GetMany(ctx, notCachedUserIds)
if err != nil {
return nil, err
}

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

@@ -4,12 +4,14 @@
package localcachelayer
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/plugin/plugintest/mock"
"github.com/mattermost/mattermost-server/v5/store"
"github.com/mattermost/mattermost-server/v5/store/storetest"
"github.com/mattermost/mattermost-server/v5/store/storetest/mocks"
@@ -33,12 +35,12 @@ func TestUserStoreCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
gotUser, err := cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true)
gotUser, err := cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
require.NoError(t, err)
assert.Equal(t, fakeUser, gotUser)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetProfileByIds", 1)
_, _ = cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true)
_, _ = cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetProfileByIds", 1)
})
@@ -48,12 +50,12 @@ func TestUserStoreCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
gotUser, err := cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true)
gotUser, err := cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
require.NoError(t, err)
assert.Equal(t, fakeUser, gotUser)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetProfileByIds", 1)
_, _ = cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, false)
_, _ = cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, false)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetProfileByIds", 2)
})
@@ -63,13 +65,13 @@ func TestUserStoreCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
gotUser, err := cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true)
gotUser, err := cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
require.NoError(t, err)
assert.Equal(t, fakeUser, gotUser)
cachedStore.User().InvalidateProfileCacheForUser("123")
_, _ = cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true)
_, _ = cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetProfileByIds", 2)
})
@@ -79,7 +81,7 @@ func TestUserStoreCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
storedUsers, err := mockStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, false)
storedUsers, err := mockStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, false)
require.NoError(t, err)
originalProps := make([]model.StringMap, len(storedUsers))
@@ -90,14 +92,14 @@ func TestUserStoreCache(t *testing.T) {
storedUsers[i].NotifyProps["key"] = "somevalue"
}
cachedUsers, err := cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true)
cachedUsers, err := cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
require.NoError(t, err)
for i := 0; i < len(storedUsers); i++ {
assert.Equal(t, storedUsers[i].Id, cachedUsers[i].Id)
}
cachedUsers, err = cachedStore.User().GetProfileByIds(fakeUserIds, &store.UserGetByIdsOpts{}, true)
cachedUsers, err = cachedStore.User().GetProfileByIds(context.Background(), fakeUserIds, &store.UserGetByIdsOpts{}, true)
require.NoError(t, err)
for i := 0; i < len(storedUsers); i++ {
storedUsers[i].Props = model.StringMap{}
@@ -129,12 +131,12 @@ func TestUserStoreProfilesInChannelCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
gotMap, err := cachedStore.User().GetAllProfilesInChannel(fakeChannelId, true)
gotMap, err := cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
require.NoError(t, err)
assert.Equal(t, fakeMap, gotMap)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 1)
_, _ = cachedStore.User().GetAllProfilesInChannel(fakeChannelId, true)
_, _ = cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 1)
})
@@ -144,12 +146,12 @@ func TestUserStoreProfilesInChannelCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
gotMap, err := cachedStore.User().GetAllProfilesInChannel(fakeChannelId, true)
gotMap, err := cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
require.NoError(t, err)
assert.Equal(t, fakeMap, gotMap)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 1)
_, _ = cachedStore.User().GetAllProfilesInChannel(fakeChannelId, false)
_, _ = cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, false)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 2)
})
@@ -159,14 +161,14 @@ func TestUserStoreProfilesInChannelCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
gotMap, err := cachedStore.User().GetAllProfilesInChannel(fakeChannelId, true)
gotMap, err := cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
require.NoError(t, err)
assert.Equal(t, fakeMap, gotMap)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 1)
cachedStore.User().InvalidateProfilesInChannelCache("123")
_, _ = cachedStore.User().GetAllProfilesInChannel(fakeChannelId, true)
_, _ = cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 2)
})
@@ -176,14 +178,14 @@ func TestUserStoreProfilesInChannelCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
gotMap, err := cachedStore.User().GetAllProfilesInChannel(fakeChannelId, true)
gotMap, err := cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
require.NoError(t, err)
assert.Equal(t, fakeMap, gotMap)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 1)
cachedStore.User().InvalidateProfilesInChannelCacheByUser("456")
_, _ = cachedStore.User().GetAllProfilesInChannel(fakeChannelId, true)
_, _ = cachedStore.User().GetAllProfilesInChannel(context.Background(), fakeChannelId, true)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetAllProfilesInChannel", 2)
})
}
@@ -201,12 +203,12 @@ func TestUserStoreGetCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
gotUser, err := cachedStore.User().Get(fakeUserId)
gotUser, err := cachedStore.User().Get(context.Background(), fakeUserId)
require.NoError(t, err)
assert.Equal(t, fakeUser, gotUser)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "Get", 1)
_, _ = cachedStore.User().Get(fakeUserId)
_, _ = cachedStore.User().Get(context.Background(), fakeUserId)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "Get", 1)
})
@@ -216,14 +218,14 @@ func TestUserStoreGetCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
gotUser, err := cachedStore.User().Get(fakeUserId)
gotUser, err := cachedStore.User().Get(context.Background(), fakeUserId)
require.NoError(t, err)
assert.Equal(t, fakeUser, gotUser)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "Get", 1)
cachedStore.User().InvalidateProfileCacheForUser("123")
_, _ = cachedStore.User().Get(fakeUserId)
_, _ = cachedStore.User().Get(context.Background(), fakeUserId)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "Get", 2)
})
@@ -233,20 +235,20 @@ func TestUserStoreGetCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
storedUser, err := mockStore.User().Get(fakeUserId)
storedUser, err := mockStore.User().Get(context.Background(), fakeUserId)
require.NoError(t, err)
originalProps := storedUser.NotifyProps
storedUser.NotifyProps = map[string]string{}
storedUser.NotifyProps["key"] = "somevalue"
cachedUser, err := cachedStore.User().Get(fakeUserId)
cachedUser, err := cachedStore.User().Get(context.Background(), fakeUserId)
require.NoError(t, err)
assert.Equal(t, storedUser, cachedUser)
storedUser.Props = model.StringMap{}
storedUser.Timezone = model.StringMap{}
cachedUser, err = cachedStore.User().Get(fakeUserId)
cachedUser, err = cachedStore.User().Get(context.Background(), fakeUserId)
require.NoError(t, err)
assert.Equal(t, storedUser, cachedUser)
if storedUser == cachedUser {
@@ -276,13 +278,13 @@ func TestUserStoreGetManyCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
gotUsers, err := cachedStore.User().GetMany([]string{fakeUser.Id, otherFakeUser.Id})
gotUsers, err := cachedStore.User().GetMany(context.Background(), []string{fakeUser.Id, otherFakeUser.Id})
require.Nil(t, err)
assert.Len(t, gotUsers, 2)
assert.Contains(t, gotUsers, fakeUser)
assert.Contains(t, gotUsers, otherFakeUser)
gotUsers, err = cachedStore.User().GetMany([]string{fakeUser.Id, otherFakeUser.Id})
gotUsers, err = cachedStore.User().GetMany(context.Background(), []string{fakeUser.Id, otherFakeUser.Id})
require.Nil(t, err)
assert.Len(t, gotUsers, 2)
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetMany", 1)
@@ -294,7 +296,7 @@ func TestUserStoreGetManyCache(t *testing.T) {
cachedStore, err := NewLocalCacheLayer(mockStore, nil, nil, mockCacheProvider)
require.NoError(t, err)
gotUsers, err := cachedStore.User().GetMany([]string{fakeUser.Id, otherFakeUser.Id})
gotUsers, err := cachedStore.User().GetMany(context.Background(), []string{fakeUser.Id, otherFakeUser.Id})
require.Nil(t, err)
assert.Len(t, gotUsers, 2)
assert.Contains(t, gotUsers, fakeUser)
@@ -302,10 +304,10 @@ func TestUserStoreGetManyCache(t *testing.T) {
cachedStore.User().InvalidateProfileCacheForUser("123")
gotUsers, err = cachedStore.User().GetMany([]string{fakeUser.Id, otherFakeUser.Id})
gotUsers, err = cachedStore.User().GetMany(context.Background(), []string{fakeUser.Id, otherFakeUser.Id})
require.NoError(t, err)
assert.Len(t, gotUsers, 2)
mockStore.User().(*mocks.UserStore).AssertCalled(t, "GetMany", []string{"123"})
mockStore.User().(*mocks.UserStore).AssertCalled(t, "GetMany", mock.Anything, []string{"123"})
mockStore.User().(*mocks.UserStore).AssertNumberOfCalls(t, "GetMany", 2)
})
}

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

@@ -8394,7 +8394,7 @@ func (s *OpenTracingLayerUserStore) DeactivateGuests() ([]string, error) {
return result, err
}
func (s *OpenTracingLayerUserStore) DemoteUserToGuest(userID string) error {
func (s *OpenTracingLayerUserStore) DemoteUserToGuest(userID string) (*model.User, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.DemoteUserToGuest")
s.Root.Store.SetContext(newCtx)
@@ -8403,16 +8403,16 @@ func (s *OpenTracingLayerUserStore) DemoteUserToGuest(userID string) error {
}()
defer span.Finish()
err := s.UserStore.DemoteUserToGuest(userID)
result, err := s.UserStore.DemoteUserToGuest(userID)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
}
return err
return result, err
}
func (s *OpenTracingLayerUserStore) Get(id string) (*model.User, error) {
func (s *OpenTracingLayerUserStore) Get(ctx context.Context, id string) (*model.User, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.Get")
s.Root.Store.SetContext(newCtx)
@@ -8421,7 +8421,7 @@ func (s *OpenTracingLayerUserStore) Get(id string) (*model.User, error) {
}()
defer span.Finish()
result, err := s.UserStore.Get(id)
result, err := s.UserStore.Get(ctx, id)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
@@ -8502,7 +8502,7 @@ func (s *OpenTracingLayerUserStore) GetAllProfiles(options *model.UserGetOptions
return result, err
}
func (s *OpenTracingLayerUserStore) GetAllProfilesInChannel(channelId string, allowFromCache bool) (map[string]*model.User, error) {
func (s *OpenTracingLayerUserStore) GetAllProfilesInChannel(ctx context.Context, channelId string, allowFromCache bool) (map[string]*model.User, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.GetAllProfilesInChannel")
s.Root.Store.SetContext(newCtx)
@@ -8511,7 +8511,7 @@ func (s *OpenTracingLayerUserStore) GetAllProfilesInChannel(channelId string, al
}()
defer span.Finish()
result, err := s.UserStore.GetAllProfilesInChannel(channelId, allowFromCache)
result, err := s.UserStore.GetAllProfilesInChannel(ctx, channelId, allowFromCache)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
@@ -8703,7 +8703,7 @@ func (s *OpenTracingLayerUserStore) GetKnownUsers(userID string) ([]string, erro
return result, err
}
func (s *OpenTracingLayerUserStore) GetMany(ids []string) ([]*model.User, error) {
func (s *OpenTracingLayerUserStore) GetMany(ctx context.Context, ids []string) ([]*model.User, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.GetMany")
s.Root.Store.SetContext(newCtx)
@@ -8712,7 +8712,7 @@ func (s *OpenTracingLayerUserStore) GetMany(ids []string) ([]*model.User, error)
}()
defer span.Finish()
result, err := s.UserStore.GetMany(ids)
result, err := s.UserStore.GetMany(ctx, ids)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)
@@ -8757,7 +8757,7 @@ func (s *OpenTracingLayerUserStore) GetProfileByGroupChannelIdsForUser(userId st
return result, err
}
func (s *OpenTracingLayerUserStore) GetProfileByIds(userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error) {
func (s *OpenTracingLayerUserStore) GetProfileByIds(ctx context.Context, userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.GetProfileByIds")
s.Root.Store.SetContext(newCtx)
@@ -8766,7 +8766,7 @@ func (s *OpenTracingLayerUserStore) GetProfileByIds(userIds []string, options *s
}()
defer span.Finish()
result, err := s.UserStore.GetProfileByIds(userIds, options, allowFromCache)
result, err := s.UserStore.GetProfileByIds(ctx, userIds, options, allowFromCache)
if err != nil {
span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true)

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

@@ -9110,31 +9110,31 @@ func (s *RetryLayerUserStore) DeactivateGuests() ([]string, error) {
}
func (s *RetryLayerUserStore) DemoteUserToGuest(userID string) error {
func (s *RetryLayerUserStore) DemoteUserToGuest(userID string) (*model.User, error) {
tries := 0
for {
err := s.UserStore.DemoteUserToGuest(userID)
result, err := s.UserStore.DemoteUserToGuest(userID)
if err == nil {
return nil
return result, nil
}
if !isRepeatableError(err) {
return err
return result, err
}
tries++
if tries >= 3 {
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
return err
return result, err
}
}
}
func (s *RetryLayerUserStore) Get(id string) (*model.User, error) {
func (s *RetryLayerUserStore) Get(ctx context.Context, id string) (*model.User, error) {
tries := 0
for {
result, err := s.UserStore.Get(id)
result, err := s.UserStore.Get(ctx, id)
if err == nil {
return result, nil
}
@@ -9230,11 +9230,11 @@ func (s *RetryLayerUserStore) GetAllProfiles(options *model.UserGetOptions) ([]*
}
func (s *RetryLayerUserStore) GetAllProfilesInChannel(channelId string, allowFromCache bool) (map[string]*model.User, error) {
func (s *RetryLayerUserStore) GetAllProfilesInChannel(ctx context.Context, channelId string, allowFromCache bool) (map[string]*model.User, error) {
tries := 0
for {
result, err := s.UserStore.GetAllProfilesInChannel(channelId, allowFromCache)
result, err := s.UserStore.GetAllProfilesInChannel(ctx, channelId, allowFromCache)
if err == nil {
return result, nil
}
@@ -9428,11 +9428,11 @@ func (s *RetryLayerUserStore) GetKnownUsers(userID string) ([]string, error) {
}
func (s *RetryLayerUserStore) GetMany(ids []string) ([]*model.User, error) {
func (s *RetryLayerUserStore) GetMany(ctx context.Context, ids []string) ([]*model.User, error) {
tries := 0
for {
result, err := s.UserStore.GetMany(ids)
result, err := s.UserStore.GetMany(ctx, ids)
if err == nil {
return result, nil
}
@@ -9488,11 +9488,11 @@ func (s *RetryLayerUserStore) GetProfileByGroupChannelIdsForUser(userId string,
}
func (s *RetryLayerUserStore) GetProfileByIds(userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error) {
func (s *RetryLayerUserStore) GetProfileByIds(ctx context.Context, userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error) {
tries := 0
for {
result, err := s.UserStore.GetProfileByIds(userIds, options, allowFromCache)
result, err := s.UserStore.GetProfileByIds(ctx, userIds, options, allowFromCache)
if err == nil {
return result, nil
}

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

@@ -4,6 +4,8 @@
package searchlayer
import (
"context"
"github.com/pkg/errors"
"github.com/mattermost/mattermost-server/v5/mlog"
@@ -193,7 +195,7 @@ func (c *SearchChannelStore) PermanentDeleteMembersByUser(userId string) error {
}
func (c *SearchChannelStore) RemoveAllDeactivatedMembers(channelId string) error {
profiles, errProfiles := c.rootStore.User().GetAllProfilesInChannel(channelId, true)
profiles, errProfiles := c.rootStore.User().GetAllProfilesInChannel(context.Background(), channelId, true)
if errProfiles != nil {
mlog.Warn("Encountered error indexing users for channel", mlog.String("channel_id", channelId), mlog.Err(errProfiles))
}
@@ -210,7 +212,7 @@ func (c *SearchChannelStore) RemoveAllDeactivatedMembers(channelId string) error
}
func (c *SearchChannelStore) PermanentDeleteMembersByChannel(channelId string) error {
profiles, errProfiles := c.rootStore.User().GetAllProfilesInChannel(channelId, true)
profiles, errProfiles := c.rootStore.User().GetAllProfilesInChannel(context.Background(), channelId, true)
if errProfiles != nil {
mlog.Warn("Encountered error indexing users for channel", mlog.String("channel_id", channelId), mlog.Err(errProfiles))
}

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

@@ -4,6 +4,7 @@
package searchlayer
import (
"context"
"sync/atomic"
"github.com/mattermost/mattermost-server/v5/mlog"
@@ -67,7 +68,7 @@ func (s *SearchStore) User() store.UserStore {
}
func (s *SearchStore) indexUserFromID(userId string) {
user, err := s.User().Get(userId)
user, err := s.User().Get(context.Background(), userId)
if err != nil {
return
}

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

@@ -4,6 +4,7 @@
package searchlayer
import (
"context"
"strings"
"github.com/pkg/errors"
@@ -54,7 +55,7 @@ func (s *SearchUserStore) Search(teamId, term string, options *model.UserSearchO
continue
}
users, nErr := s.UserStore.GetProfileByIds(usersIds, nil, false)
users, nErr := s.UserStore.GetProfileByIds(context.Background(), usersIds, nil, false)
if nErr != nil {
mlog.Warn("Encountered error on Search", mlog.String("search_engine", engine.GetName()), mlog.Err(nErr))
continue
@@ -89,7 +90,7 @@ func (s *SearchUserStore) Save(user *model.User) (*model.User, error) {
}
func (s *SearchUserStore) PermanentDelete(userId string) error {
user, userErr := s.UserStore.Get(userId)
user, userErr := s.UserStore.Get(context.Background(), userId)
if userErr != nil {
mlog.Warn("Encountered error deleting user", mlog.String("user_id", userId), mlog.Err(userErr))
}
@@ -116,14 +117,14 @@ func (s *SearchUserStore) autocompleteUsersInChannelByEngine(engine searchengine
uchan := make(chan store.StoreResult, 1)
go func() {
users, nErr := s.UserStore.GetProfileByIds(uchanIds, nil, false)
users, nErr := s.UserStore.GetProfileByIds(context.Background(), uchanIds, nil, false)
uchan <- store.StoreResult{Data: users, NErr: nErr}
close(uchan)
}()
nuchan := make(chan store.StoreResult, 1)
go func() {
users, nErr := s.UserStore.GetProfileByIds(nuchanIds, nil, false)
users, nErr := s.UserStore.GetProfileByIds(context.Background(), nuchanIds, nil, false)
nuchan <- store.StoreResult{Data: users, NErr: nErr}
close(nuchan)
}()

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

@@ -18,8 +18,8 @@ const (
useMaster contextValue = "useMaster"
)
// withMaster adds the context value that master DB should be selected for this request.
func withMaster(ctx context.Context) context.Context {
// WithMaster adds the context value that master DB should be selected for this request.
func WithMaster(ctx context.Context) context.Context {
return context.WithValue(ctx, storeContextKey(useMaster), true)
}

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

@@ -13,6 +13,6 @@ import (
func TestContextMaster(t *testing.T) {
ctx := context.Background()
m := withMaster(ctx)
m := WithMaster(ctx)
assert.True(t, hasMaster(m))
}

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

@@ -4,6 +4,7 @@
package sqlstore
import (
"context"
"database/sql"
"fmt"
"regexp"
@@ -677,7 +678,7 @@ func (s *SqlPostStore) prepareThreadedResponse(posts []*postWithExtra, extended,
var users []*model.User
if extended {
var err error
users, err = s.User().GetProfileByIds(userIds, &store.UserGetByIdsOpts{}, true)
users, err = s.User().GetProfileByIds(context.Background(), userIds, &store.UserGetByIdsOpts{}, true)
if err != nil {
return nil, err
}

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

@@ -84,7 +84,7 @@ func (me SqlSessionStore) Get(sessionIdOrToken string) (*model.Session, error) {
session := sessions[0]
tempMembers, err := me.Team().GetTeamsForUser(
withMaster(context.Background()),
WithMaster(context.Background()),
session.UserId)
if err != nil {
return nil, errors.Wrapf(err, "failed to find TeamMembers for Session with userId=%s", session.UserId)

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

@@ -4,6 +4,7 @@
package sqlstore
import (
"context"
"database/sql"
"time"
@@ -288,7 +289,7 @@ func (s *SqlThreadStore) GetThreadsForUser(userId, teamId string, opts model.Get
var users []*model.User
if opts.Extended {
var err error
users, err = s.User().GetProfileByIds(userIds, &store.UserGetByIdsOpts{}, true)
users, err = s.User().GetProfileByIds(context.Background(), userIds, &store.UserGetByIdsOpts{}, true)
if err != nil {
return nil, errors.Wrapf(err, "failed to get threads for user id=%s", userId)
}
@@ -376,7 +377,7 @@ func (s *SqlThreadStore) GetThreadForUser(userId, teamId, threadId string, exten
var users []*model.User
if extended {
var err error
users, err = s.User().GetProfileByIds(thread.Participants, &store.UserGetByIdsOpts{}, true)
users, err = s.User().GetProfileByIds(context.Background(), thread.Participants, &store.UserGetByIdsOpts{}, true)
if err != nil {
return nil, errors.Wrapf(err, "failed to get threads for user id=%s", userId)
}

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

@@ -4,6 +4,7 @@
package sqlstore
import (
"context"
"database/sql"
"encoding/json"
"fmt"
@@ -38,7 +39,7 @@ type SqlUserStore struct {
usersQuery sq.SelectBuilder
}
func (us SqlUserStore) ClearCaches() {}
func (us *SqlUserStore) ClearCaches() {}
func (us SqlUserStore) InvalidateProfileCacheForUser(userId string) {}
@@ -326,28 +327,41 @@ func (us SqlUserStore) UpdateMfaActive(userId string, active bool) error {
}
// GetMany returns a list of users for the provided list of ids
func (us SqlUserStore) GetMany(ids []string) ([]*model.User, error) {
func (us SqlUserStore) GetMany(ctx context.Context, ids []string) ([]*model.User, error) {
query := us.usersQuery.Where(sq.Eq{"Id": ids})
queryString, args, err := query.ToSql()
if err != nil {
return nil, errors.Wrap(err, "users_get_many_tosql")
}
var db *gorp.DbMap
if hasMaster(ctx) {
db = us.GetMaster()
} else {
db = us.GetReplica()
}
var users []*model.User
if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil {
if _, err := db.Select(&users, queryString, args...); err != nil {
return nil, errors.Wrap(err, "users_get_many_select")
}
return users, nil
}
func (us SqlUserStore) Get(id string) (*model.User, error) {
func (us SqlUserStore) Get(ctx context.Context, id string) (*model.User, error) {
query := us.usersQuery.Where("Id = ?", id)
queryString, args, err := query.ToSql()
if err != nil {
return nil, errors.Wrap(err, "users_get_tosql")
}
row := us.GetReplica().Db.QueryRow(queryString, args...)
var db *gorp.DbMap
if hasMaster(ctx) {
db = us.GetMaster()
} else {
db = us.GetReplica()
}
row := db.Db.QueryRow(queryString, args...)
var user model.User
var props, notifyProps, timezone []byte
@@ -703,10 +717,10 @@ func (us SqlUserStore) GetProfilesInChannelByStatus(options *model.UserGetOption
return users, nil
}
func (us SqlUserStore) GetAllProfilesInChannel(channelId string, allowFromCache bool) (map[string]*model.User, error) {
func (us SqlUserStore) GetAllProfilesInChannel(ctx context.Context, channelID string, allowFromCache bool) (map[string]*model.User, error) {
query := us.usersQuery.
Join("ChannelMembers cm ON ( cm.UserId = u.Id )").
Where("cm.ChannelId = ?", channelId).
Where("cm.ChannelId = ?", channelID).
Where("u.DeleteAt = 0").
OrderBy("u.Username ASC")
@@ -714,8 +728,15 @@ func (us SqlUserStore) GetAllProfilesInChannel(channelId string, allowFromCache
if err != nil {
return nil, errors.Wrap(err, "get_all_profiles_in_channel_tosql")
}
var db *gorp.DbMap
if hasMaster(ctx) {
db = us.GetMaster()
} else {
db = us.GetReplica()
}
var users []*model.User
rows, err := us.GetReplica().Db.Query(queryString, args...)
rows, err := db.Db.Query(queryString, args...)
if err != nil {
return nil, errors.Wrap(err, "failed to find Users")
}
@@ -914,7 +935,7 @@ func (us SqlUserStore) GetNewUsersForTeam(teamId string, offset, limit int, view
return users, nil
}
func (us SqlUserStore) GetProfileByIds(userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error) {
func (us SqlUserStore) GetProfileByIds(ctx context.Context, userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error) {
if options == nil {
options = &store.UserGetByIdsOpts{}
}
@@ -939,7 +960,14 @@ func (us SqlUserStore) GetProfileByIds(userIds []string, options *store.UserGetB
return nil, errors.Wrap(err, "get_profile_by_ids_tosql")
}
if _, err := us.GetReplica().Select(&users, queryString, args...); err != nil {
var db *gorp.DbMap
if hasMaster(ctx) {
db = us.GetMaster()
} else {
db = us.GetReplica()
}
if _, err := db.Select(&users, queryString, args...); err != nil {
return nil, errors.Wrap(err, "failed to find Users")
}
@@ -1775,7 +1803,7 @@ func (us SqlUserStore) PromoteGuestToUser(userId string) error {
}
defer finalizeTransaction(transaction)
user, err := us.Get(userId)
user, err := us.Get(context.Background(), userId)
if err != nil {
return err
}
@@ -1837,76 +1865,80 @@ func (us SqlUserStore) PromoteGuestToUser(userId string) error {
return nil
}
func (us SqlUserStore) DemoteUserToGuest(userId string) error {
func (us SqlUserStore) DemoteUserToGuest(userID string) (*model.User, error) {
transaction, err := us.GetMaster().Begin()
if err != nil {
return errors.Wrap(err, "begin_transaction")
return nil, errors.Wrap(err, "begin_transaction")
}
defer finalizeTransaction(transaction)
user, err := us.Get(userId)
user, err := us.Get(context.Background(), userID)
if err != nil {
return err
return nil, err
}
roles := user.GetRoles()
newRoles := []string{}
for _, role := range roles {
if role == "system_user" {
newRoles = append(newRoles, "system_guest")
} else if role != "system_admin" {
if role == model.SYSTEM_USER_ROLE_ID {
newRoles = append(newRoles, model.SYSTEM_GUEST_ROLE_ID)
} else if role != model.SYSTEM_ADMIN_ROLE_ID {
newRoles = append(newRoles, role)
}
}
curTime := model.GetMillis()
newRolesDBStr := strings.Join(newRoles, " ")
query := us.getQueryBuilder().Update("Users").
Set("Roles", strings.Join(newRoles, " ")).
Set("Roles", newRolesDBStr).
Set("UpdateAt", curTime).
Where(sq.Eq{"Id": userId})
Where(sq.Eq{"Id": userID})
queryString, args, err := query.ToSql()
if err != nil {
return errors.Wrap(err, "demote_user_to_guest_tosql")
return nil, errors.Wrap(err, "demote_user_to_guest_tosql")
}
if _, err = transaction.Exec(queryString, args...); err != nil {
return errors.Wrapf(err, "failed to update User with userId=%s", userId)
return nil, errors.Wrapf(err, "failed to update User with userId=%s", userID)
}
user.Roles = newRolesDBStr
user.UpdateAt = curTime
query = us.getQueryBuilder().Update("ChannelMembers").
Set("SchemeUser", false).
Set("SchemeGuest", true).
Where(sq.Eq{"UserId": userId})
Where(sq.Eq{"UserId": userID})
queryString, args, err = query.ToSql()
if err != nil {
return errors.Wrap(err, "demote_user_to_guest_tosql")
return nil, errors.Wrap(err, "demote_user_to_guest_tosql")
}
if _, err = transaction.Exec(queryString, args...); err != nil {
return errors.Wrapf(err, "failed to update ChannelMembers with userId=%s", userId)
return nil, errors.Wrapf(err, "failed to update ChannelMembers with userId=%s", userID)
}
query = us.getQueryBuilder().Update("TeamMembers").
Set("SchemeUser", false).
Set("SchemeGuest", true).
Where(sq.Eq{"UserId": userId})
Where(sq.Eq{"UserId": userID})
queryString, args, err = query.ToSql()
if err != nil {
return errors.Wrap(err, "demote_user_to_guest_tosql")
return nil, errors.Wrap(err, "demote_user_to_guest_tosql")
}
if _, err := transaction.Exec(queryString, args...); err != nil {
return errors.Wrapf(err, "failed to update TeamMembers with userId=%s", userId)
return nil, errors.Wrapf(err, "failed to update TeamMembers with userId=%s", userID)
}
if err := transaction.Commit(); err != nil {
return errors.Wrap(err, "commit_transaction")
return nil, errors.Wrap(err, "commit_transaction")
}
return nil
return user, nil
}
func (us SqlUserStore) AutocompleteUsersInChannel(teamId, channelId, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, error) {

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

@@ -322,21 +322,21 @@ type UserStore interface {
UpdateAuthData(userId string, service string, authData *string, email string, resetMfa bool) (string, error)
UpdateMfaSecret(userId, secret string) error
UpdateMfaActive(userId string, active bool) error
Get(id string) (*model.User, error)
GetMany(ids []string) ([]*model.User, error)
Get(ctx context.Context, id string) (*model.User, error)
GetMany(ctx context.Context, ids []string) ([]*model.User, error)
GetAll() ([]*model.User, error)
ClearCaches()
InvalidateProfilesInChannelCacheByUser(userId string)
InvalidateProfilesInChannelCache(channelId string)
GetProfilesInChannel(options *model.UserGetOptions) ([]*model.User, error)
GetProfilesInChannelByStatus(options *model.UserGetOptions) ([]*model.User, error)
GetAllProfilesInChannel(channelId string, allowFromCache bool) (map[string]*model.User, error)
GetAllProfilesInChannel(ctx context.Context, channelId string, allowFromCache bool) (map[string]*model.User, error)
GetProfilesNotInChannel(teamId string, channelId string, groupConstrained bool, offset int, limit int, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, error)
GetProfilesWithoutTeam(options *model.UserGetOptions) ([]*model.User, error)
GetProfilesByUsernames(usernames []string, viewRestrictions *model.ViewUsersRestrictions) ([]*model.User, error)
GetAllProfiles(options *model.UserGetOptions) ([]*model.User, error)
GetProfiles(options *model.UserGetOptions) ([]*model.User, error)
GetProfileByIds(userIds []string, options *UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error)
GetProfileByIds(ctx context.Context, userIds []string, options *UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error)
GetProfileByGroupChannelIdsForUser(userId string, channelIds []string) (map[string][]*model.User, error)
InvalidateProfileCacheForUser(userId string)
GetByEmail(email string) (*model.User, error)
@@ -378,7 +378,7 @@ type UserStore interface {
GetTeamGroupUsers(teamID string) ([]*model.User, error)
GetChannelGroupUsers(channelID string) ([]*model.User, error)
PromoteGuestToUser(userID string) error
DemoteUserToGuest(userID string) error
DemoteUserToGuest(userID string) (*model.User, error)
DeactivateGuests() ([]string, error)
AutocompleteUsersInChannel(teamId, channelId, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, error)
GetKnownUsers(userID string) ([]string, error)

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

@@ -5,9 +5,12 @@
package mocks
import (
context "context"
model "github.com/mattermost/mattermost-server/v5/model"
store "github.com/mattermost/mattermost-server/v5/store"
mock "github.com/stretchr/testify/mock"
store "github.com/mattermost/mattermost-server/v5/store"
)
// UserStore is an autogenerated mock type for the UserStore type
@@ -228,26 +231,12 @@ func (_m *UserStore) DeactivateGuests() ([]string, error) {
}
// DemoteUserToGuest provides a mock function with given fields: userID
func (_m *UserStore) DemoteUserToGuest(userID string) error {
func (_m *UserStore) DemoteUserToGuest(userID string) (*model.User, error) {
ret := _m.Called(userID)
var r0 error
if rf, ok := ret.Get(0).(func(string) error); ok {
r0 = rf(userID)
} else {
r0 = ret.Error(0)
}
return r0
}
// Get provides a mock function with given fields: id
func (_m *UserStore) Get(id string) (*model.User, error) {
ret := _m.Called(id)
var r0 *model.User
if rf, ok := ret.Get(0).(func(string) *model.User); ok {
r0 = rf(id)
r0 = rf(userID)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.User)
@@ -256,7 +245,30 @@ func (_m *UserStore) Get(id string) (*model.User, error) {
var r1 error
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(id)
r1 = rf(userID)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// Get provides a mock function with given fields: ctx, id
func (_m *UserStore) Get(ctx context.Context, id string) (*model.User, error) {
ret := _m.Called(ctx, id)
var r0 *model.User
if rf, ok := ret.Get(0).(func(context.Context, string) *model.User); ok {
r0 = rf(ctx, id)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.User)
}
}
var r1 error
if rf, ok := ret.Get(1).(func(context.Context, string) error); ok {
r1 = rf(ctx, id)
} else {
r1 = ret.Error(1)
}
@@ -356,13 +368,13 @@ func (_m *UserStore) GetAllProfiles(options *model.UserGetOptions) ([]*model.Use
return r0, r1
}
// GetAllProfilesInChannel provides a mock function with given fields: channelId, allowFromCache
func (_m *UserStore) GetAllProfilesInChannel(channelId string, allowFromCache bool) (map[string]*model.User, error) {
ret := _m.Called(channelId, allowFromCache)
// GetAllProfilesInChannel provides a mock function with given fields: ctx, channelId, allowFromCache
func (_m *UserStore) GetAllProfilesInChannel(ctx context.Context, channelId string, allowFromCache bool) (map[string]*model.User, error) {
ret := _m.Called(ctx, channelId, allowFromCache)
var r0 map[string]*model.User
if rf, ok := ret.Get(0).(func(string, bool) map[string]*model.User); ok {
r0 = rf(channelId, allowFromCache)
if rf, ok := ret.Get(0).(func(context.Context, string, bool) map[string]*model.User); ok {
r0 = rf(ctx, channelId, allowFromCache)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(map[string]*model.User)
@@ -370,8 +382,8 @@ func (_m *UserStore) GetAllProfilesInChannel(channelId string, allowFromCache bo
}
var r1 error
if rf, ok := ret.Get(1).(func(string, bool) error); ok {
r1 = rf(channelId, allowFromCache)
if rf, ok := ret.Get(1).(func(context.Context, string, bool) error); ok {
r1 = rf(ctx, channelId, allowFromCache)
} else {
r1 = ret.Error(1)
}
@@ -603,13 +615,13 @@ func (_m *UserStore) GetKnownUsers(userID string) ([]string, error) {
return r0, r1
}
// GetMany provides a mock function with given fields: ids
func (_m *UserStore) GetMany(ids []string) ([]*model.User, error) {
ret := _m.Called(ids)
// GetMany provides a mock function with given fields: ctx, ids
func (_m *UserStore) GetMany(ctx context.Context, ids []string) ([]*model.User, error) {
ret := _m.Called(ctx, ids)
var r0 []*model.User
if rf, ok := ret.Get(0).(func([]string) []*model.User); ok {
r0 = rf(ids)
if rf, ok := ret.Get(0).(func(context.Context, []string) []*model.User); ok {
r0 = rf(ctx, ids)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.User)
@@ -617,8 +629,8 @@ func (_m *UserStore) GetMany(ids []string) ([]*model.User, error) {
}
var r1 error
if rf, ok := ret.Get(1).(func([]string) error); ok {
r1 = rf(ids)
if rf, ok := ret.Get(1).(func(context.Context, []string) error); ok {
r1 = rf(ctx, ids)
} else {
r1 = ret.Error(1)
}
@@ -672,13 +684,13 @@ func (_m *UserStore) GetProfileByGroupChannelIdsForUser(userId string, channelId
return r0, r1
}
// GetProfileByIds provides a mock function with given fields: userIds, options, allowFromCache
func (_m *UserStore) GetProfileByIds(userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error) {
ret := _m.Called(userIds, options, allowFromCache)
// GetProfileByIds provides a mock function with given fields: ctx, userIds, options, allowFromCache
func (_m *UserStore) GetProfileByIds(ctx context.Context, userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error) {
ret := _m.Called(ctx, userIds, options, allowFromCache)
var r0 []*model.User
if rf, ok := ret.Get(0).(func([]string, *store.UserGetByIdsOpts, bool) []*model.User); ok {
r0 = rf(userIds, options, allowFromCache)
if rf, ok := ret.Get(0).(func(context.Context, []string, *store.UserGetByIdsOpts, bool) []*model.User); ok {
r0 = rf(ctx, userIds, options, allowFromCache)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.User)
@@ -686,8 +698,8 @@ func (_m *UserStore) GetProfileByIds(userIds []string, options *store.UserGetByI
}
var r1 error
if rf, ok := ret.Get(1).(func([]string, *store.UserGetByIdsOpts, bool) error); ok {
r1 = rf(userIds, options, allowFromCache)
if rf, ok := ret.Get(1).(func(context.Context, []string, *store.UserGetByIdsOpts, bool) error); ok {
r1 = rf(ctx, userIds, options, allowFromCache)
} else {
r1 = ret.Error(1)
}

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

@@ -2829,7 +2829,7 @@ func testSaveTeamMemberMaxMembers(t *testing.T, ss store.Store) {
require.Equal(t, maxUsersPerTeam, int(totalMemberCount), "should have 5 team members again, had %v instead", totalMemberCount)
// Deactivating a user should make them stop counting against max members
user2, nErr := ss.User().Get(userIds[1])
user2, nErr := ss.User().Get(context.Background(), userIds[1])
require.NoError(t, nErr)
user2.DeleteAt = 1234
_, nErr = ss.User().Update(user2, true)

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

@@ -4,6 +4,7 @@
package storetest
import (
"context"
"errors"
"strings"
"testing"
@@ -226,7 +227,7 @@ func testUserStoreUpdateUpdateAt(t *testing.T, ss store.Store) {
_, err = ss.User().UpdateUpdateAt(u1.Id)
require.NoError(t, err)
user, err := ss.User().Get(u1.Id)
user, err := ss.User().Get(context.Background(), u1.Id)
require.NoError(t, err)
require.Less(t, u1.UpdateAt, user.UpdateAt, "UpdateAt not updated correctly")
}
@@ -243,7 +244,7 @@ func testUserStoreUpdateFailedPasswordAttempts(t *testing.T, ss store.Store) {
err = ss.User().UpdateFailedPasswordAttempts(u1.Id, 3)
require.NoError(t, err)
user, err := ss.User().Get(u1.Id)
user, err := ss.User().Get(context.Background(), u1.Id)
require.NoError(t, err)
require.Equal(t, 3, user.FailedAttempts, "FailedAttempts not updated correctly")
}
@@ -276,19 +277,19 @@ func testUserStoreGet(t *testing.T, ss store.Store) {
require.NoError(t, nErr)
t.Run("fetch empty id", func(t *testing.T) {
_, err := ss.User().Get("")
_, err := ss.User().Get(context.Background(), "")
require.Error(t, err)
})
t.Run("fetch user 1", func(t *testing.T) {
actual, err := ss.User().Get(u1.Id)
actual, err := ss.User().Get(context.Background(), u1.Id)
require.NoError(t, err)
require.Equal(t, u1, actual)
require.False(t, actual.IsBot)
})
t.Run("fetch user 2, also a bot", func(t *testing.T) {
actual, err := ss.User().Get(u2.Id)
actual, err := ss.User().Get(context.Background(), u2.Id)
require.NoError(t, err)
require.Equal(t, u2, actual)
require.True(t, actual.IsBot)
@@ -1272,7 +1273,7 @@ func testUserStoreGetAllProfilesInChannel(t *testing.T, ss store.Store) {
t.Run("all profiles in channel 1, no caching", func(t *testing.T) {
var profiles map[string]*model.User
profiles, err = ss.User().GetAllProfilesInChannel(c1.Id, false)
profiles, err = ss.User().GetAllProfilesInChannel(context.Background(), c1.Id, false)
require.NoError(t, err)
assert.Equal(t, map[string]*model.User{
u1.Id: sanitized(u1),
@@ -1283,7 +1284,7 @@ func testUserStoreGetAllProfilesInChannel(t *testing.T, ss store.Store) {
t.Run("all profiles in channel 2, no caching", func(t *testing.T) {
var profiles map[string]*model.User
profiles, err = ss.User().GetAllProfilesInChannel(c2.Id, false)
profiles, err = ss.User().GetAllProfilesInChannel(context.Background(), c2.Id, false)
require.NoError(t, err)
assert.Equal(t, map[string]*model.User{
u1.Id: sanitized(u1),
@@ -1292,7 +1293,7 @@ func testUserStoreGetAllProfilesInChannel(t *testing.T, ss store.Store) {
t.Run("all profiles in channel 2, caching", func(t *testing.T) {
var profiles map[string]*model.User
profiles, err = ss.User().GetAllProfilesInChannel(c2.Id, true)
profiles, err = ss.User().GetAllProfilesInChannel(context.Background(), c2.Id, true)
require.NoError(t, err)
assert.Equal(t, map[string]*model.User{
u1.Id: sanitized(u1),
@@ -1301,7 +1302,7 @@ func testUserStoreGetAllProfilesInChannel(t *testing.T, ss store.Store) {
t.Run("all profiles in channel 2, caching [repeated]", func(t *testing.T) {
var profiles map[string]*model.User
profiles, err = ss.User().GetAllProfilesInChannel(c2.Id, true)
profiles, err = ss.User().GetAllProfilesInChannel(context.Background(), c2.Id, true)
require.NoError(t, err)
assert.Equal(t, map[string]*model.User{
u1.Id: sanitized(u1),
@@ -1521,37 +1522,37 @@ func testUserStoreGetProfilesByIds(t *testing.T, ss store.Store) {
defer func() { require.NoError(t, ss.User().PermanentDelete(u4.Id)) }()
t.Run("get u1 by id, no caching", func(t *testing.T) {
users, err := ss.User().GetProfileByIds([]string{u1.Id}, nil, false)
users, err := ss.User().GetProfileByIds(context.Background(), []string{u1.Id}, nil, false)
require.NoError(t, err)
assert.Equal(t, []*model.User{u1}, users)
})
t.Run("get u1 by id, caching", func(t *testing.T) {
users, err := ss.User().GetProfileByIds([]string{u1.Id}, nil, true)
users, err := ss.User().GetProfileByIds(context.Background(), []string{u1.Id}, nil, true)
require.NoError(t, err)
assert.Equal(t, []*model.User{u1}, users)
})
t.Run("get u1, u2, u3 by id, no caching", func(t *testing.T) {
users, err := ss.User().GetProfileByIds([]string{u1.Id, u2.Id, u3.Id}, nil, false)
users, err := ss.User().GetProfileByIds(context.Background(), []string{u1.Id, u2.Id, u3.Id}, nil, false)
require.NoError(t, err)
assert.Equal(t, []*model.User{u1, u2, u3}, users)
})
t.Run("get u1, u2, u3 by id, caching", func(t *testing.T) {
users, err := ss.User().GetProfileByIds([]string{u1.Id, u2.Id, u3.Id}, nil, true)
users, err := ss.User().GetProfileByIds(context.Background(), []string{u1.Id, u2.Id, u3.Id}, nil, true)
require.NoError(t, err)
assert.Equal(t, []*model.User{u1, u2, u3}, users)
})
t.Run("get unknown id, caching", func(t *testing.T) {
users, err := ss.User().GetProfileByIds([]string{"123"}, nil, true)
users, err := ss.User().GetProfileByIds(context.Background(), []string{"123"}, nil, true)
require.NoError(t, err)
assert.Equal(t, []*model.User{}, users)
})
t.Run("should only return users with UpdateAt greater than the since time", func(t *testing.T) {
users, err := ss.User().GetProfileByIds([]string{u1.Id, u2.Id, u3.Id, u4.Id}, &store.UserGetByIdsOpts{
users, err := ss.User().GetProfileByIds(context.Background(), []string{u1.Id, u2.Id, u3.Id, u4.Id}, &store.UserGetByIdsOpts{
Since: u2.CreateAt,
}, true)
require.NoError(t, err)
@@ -4835,7 +4836,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
err = ss.User().PromoteGuestToUser(user.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user.Id)
updatedUser, err := ss.User().Get(context.Background(), user.Id)
require.NoError(t, err)
require.Equal(t, "system_user", updatedUser.Roles)
require.True(t, user.UpdateAt < updatedUser.UpdateAt)
@@ -4881,7 +4882,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
err = ss.User().PromoteGuestToUser(user.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user.Id)
updatedUser, err := ss.User().Get(context.Background(), user.Id)
require.NoError(t, err)
require.Equal(t, "system_user system_admin", updatedUser.Roles)
@@ -4912,7 +4913,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
err = ss.User().PromoteGuestToUser(user.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user.Id)
updatedUser, err := ss.User().Get(context.Background(), user.Id)
require.NoError(t, err)
require.Equal(t, "system_user", updatedUser.Roles)
})
@@ -4937,7 +4938,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
err = ss.User().PromoteGuestToUser(user.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user.Id)
updatedUser, err := ss.User().Get(context.Background(), user.Id)
require.NoError(t, err)
require.Equal(t, "system_user", updatedUser.Roles)
@@ -4977,7 +4978,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
err = ss.User().PromoteGuestToUser(user.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user.Id)
updatedUser, err := ss.User().Get(context.Background(), user.Id)
require.NoError(t, err)
require.Equal(t, "system_user", updatedUser.Roles)
@@ -5022,7 +5023,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
err = ss.User().PromoteGuestToUser(user.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user.Id)
updatedUser, err := ss.User().Get(context.Background(), user.Id)
require.NoError(t, err)
require.Equal(t, "system_user custom_role", updatedUser.Roles)
@@ -5088,7 +5089,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
err = ss.User().PromoteGuestToUser(user1.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user1.Id)
updatedUser, err := ss.User().Get(context.Background(), user1.Id)
require.NoError(t, err)
require.Equal(t, "system_user", updatedUser.Roles)
@@ -5102,7 +5103,7 @@ func testUserStorePromoteGuestToUser(t *testing.T, ss store.Store) {
require.False(t, updatedChannelMember.SchemeGuest)
require.True(t, updatedChannelMember.SchemeUser)
notUpdatedUser, err := ss.User().Get(user2.Id)
notUpdatedUser, err := ss.User().Get(context.Background(), user2.Id)
require.NoError(t, err)
require.Equal(t, "system_guest", notUpdatedUser.Roles)
@@ -5148,19 +5149,17 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
_, nErr = ss.Channel().SaveMember(&model.ChannelMember{ChannelId: channel.Id, UserId: user.Id, SchemeGuest: false, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()})
require.NoError(t, nErr)
err = ss.User().DemoteUserToGuest(user.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user.Id)
updatedUser, err := ss.User().DemoteUserToGuest(user.Id)
require.NoError(t, err)
require.Equal(t, "system_guest", updatedUser.Roles)
require.True(t, user.UpdateAt < updatedUser.UpdateAt)
updatedTeamMember, nErr := ss.Team().GetMember(teamId, user.Id)
updatedTeamMember, nErr := ss.Team().GetMember(teamId, updatedUser.Id)
require.NoError(t, nErr)
require.True(t, updatedTeamMember.SchemeGuest)
require.False(t, updatedTeamMember.SchemeUser)
updatedChannelMember, nErr := ss.Channel().GetMember(channel.Id, user.Id)
updatedChannelMember, nErr := ss.Channel().GetMember(channel.Id, updatedUser.Id)
require.NoError(t, nErr)
require.True(t, updatedChannelMember.SchemeGuest)
require.False(t, updatedChannelMember.SchemeUser)
@@ -5194,9 +5193,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
_, nErr = ss.Channel().SaveMember(&model.ChannelMember{ChannelId: channel.Id, UserId: user.Id, SchemeGuest: true, SchemeUser: false, NotifyProps: model.GetDefaultChannelNotifyProps()})
require.NoError(t, nErr)
err = ss.User().DemoteUserToGuest(user.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user.Id)
updatedUser, err := ss.User().DemoteUserToGuest(user.Id)
require.NoError(t, err)
require.Equal(t, "system_guest", updatedUser.Roles)
@@ -5225,9 +5222,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
require.NoError(t, err)
defer func() { require.NoError(t, ss.User().PermanentDelete(user.Id)) }()
err = ss.User().DemoteUserToGuest(user.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user.Id)
updatedUser, err := ss.User().DemoteUserToGuest(user.Id)
require.NoError(t, err)
require.Equal(t, "system_guest", updatedUser.Roles)
})
@@ -5250,9 +5245,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
_, nErr := ss.Team().SaveMember(&model.TeamMember{TeamId: teamId, UserId: user.Id, SchemeGuest: false, SchemeUser: true}, 999)
require.NoError(t, nErr)
err = ss.User().DemoteUserToGuest(user.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user.Id)
updatedUser, err := ss.User().DemoteUserToGuest(user.Id)
require.NoError(t, err)
require.Equal(t, "system_guest", updatedUser.Roles)
@@ -5290,9 +5283,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
_, nErr = ss.Channel().SaveMember(&model.ChannelMember{ChannelId: channel.Id, UserId: user.Id, SchemeGuest: false, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()})
require.NoError(t, nErr)
err = ss.User().DemoteUserToGuest(user.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user.Id)
updatedUser, err := ss.User().DemoteUserToGuest(user.Id)
require.NoError(t, err)
require.Equal(t, "system_guest", updatedUser.Roles)
@@ -5335,9 +5326,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
_, nErr = ss.Channel().SaveMember(&model.ChannelMember{ChannelId: channel.Id, UserId: user.Id, SchemeGuest: false, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()})
require.NoError(t, nErr)
err = ss.User().DemoteUserToGuest(user.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user.Id)
updatedUser, err := ss.User().DemoteUserToGuest(user.Id)
require.NoError(t, err)
require.Equal(t, "system_guest custom_role", updatedUser.Roles)
@@ -5401,9 +5390,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
_, nErr = ss.Channel().SaveMember(&model.ChannelMember{ChannelId: channel.Id, UserId: user2.Id, SchemeGuest: false, SchemeUser: true, NotifyProps: model.GetDefaultChannelNotifyProps()})
require.NoError(t, nErr)
err = ss.User().DemoteUserToGuest(user1.Id)
require.NoError(t, err)
updatedUser, err := ss.User().Get(user1.Id)
updatedUser, err := ss.User().DemoteUserToGuest(user1.Id)
require.NoError(t, err)
require.Equal(t, "system_guest", updatedUser.Roles)
@@ -5417,7 +5404,7 @@ func testUserStoreDemoteUserToGuest(t *testing.T, ss store.Store) {
require.True(t, updatedChannelMember.SchemeGuest)
require.False(t, updatedChannelMember.SchemeUser)
notUpdatedUser, err := ss.User().Get(user2.Id)
notUpdatedUser, err := ss.User().Get(context.Background(), user2.Id)
require.NoError(t, err)
require.Equal(t, "system_user", notUpdatedUser.Roles)
@@ -5493,19 +5480,19 @@ func testDeactivateGuests(t *testing.T, ss store.Store) {
require.NoError(t, err)
assert.ElementsMatch(t, []string{guest1.Id, guest2.Id}, ids)
u, err := ss.User().Get(guest1.Id)
u, err := ss.User().Get(context.Background(), guest1.Id)
require.NoError(t, err)
assert.NotEqual(t, u.DeleteAt, int64(0))
u, err = ss.User().Get(guest2.Id)
u, err = ss.User().Get(context.Background(), guest2.Id)
require.NoError(t, err)
assert.NotEqual(t, u.DeleteAt, int64(0))
u, err = ss.User().Get(guest3.Id)
u, err = ss.User().Get(context.Background(), guest3.Id)
require.NoError(t, err)
assert.Equal(t, u.DeleteAt, int64(10))
u, err = ss.User().Get(regularUser.Id)
u, err = ss.User().Get(context.Background(), regularUser.Id)
require.NoError(t, err)
assert.Equal(t, u.DeleteAt, int64(0))
})
@@ -5523,7 +5510,7 @@ func testUserStoreResetLastPictureUpdate(t *testing.T, ss store.Store) {
err = ss.User().UpdateLastPictureUpdate(u1.Id)
require.NoError(t, err)
user, err := ss.User().Get(u1.Id)
user, err := ss.User().Get(context.Background(), u1.Id)
require.NoError(t, err)
assert.NotZero(t, user.LastPictureUpdate)
@@ -5537,7 +5524,7 @@ func testUserStoreResetLastPictureUpdate(t *testing.T, ss store.Store) {
ss.User().InvalidateProfileCacheForUser(u1.Id)
user2, err := ss.User().Get(u1.Id)
user2, err := ss.User().Get(context.Background(), u1.Id)
require.NoError(t, err)
assert.True(t, user2.UpdateAt > user.UpdateAt)

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

@@ -7574,10 +7574,10 @@ func (s *TimerLayerUserStore) DeactivateGuests() ([]string, error) {
return result, err
}
func (s *TimerLayerUserStore) DemoteUserToGuest(userID string) error {
func (s *TimerLayerUserStore) DemoteUserToGuest(userID string) (*model.User, error) {
start := timemodule.Now()
err := s.UserStore.DemoteUserToGuest(userID)
result, err := s.UserStore.DemoteUserToGuest(userID)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
@@ -7587,13 +7587,13 @@ func (s *TimerLayerUserStore) DemoteUserToGuest(userID string) error {
}
s.Root.Metrics.ObserveStoreMethodDuration("UserStore.DemoteUserToGuest", success, elapsed)
}
return err
return result, err
}
func (s *TimerLayerUserStore) Get(id string) (*model.User, error) {
func (s *TimerLayerUserStore) Get(ctx context.Context, id string) (*model.User, error) {
start := timemodule.Now()
result, err := s.UserStore.Get(id)
result, err := s.UserStore.Get(ctx, id)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
@@ -7670,10 +7670,10 @@ func (s *TimerLayerUserStore) GetAllProfiles(options *model.UserGetOptions) ([]*
return result, err
}
func (s *TimerLayerUserStore) GetAllProfilesInChannel(channelId string, allowFromCache bool) (map[string]*model.User, error) {
func (s *TimerLayerUserStore) GetAllProfilesInChannel(ctx context.Context, channelId string, allowFromCache bool) (map[string]*model.User, error) {
start := timemodule.Now()
result, err := s.UserStore.GetAllProfilesInChannel(channelId, allowFromCache)
result, err := s.UserStore.GetAllProfilesInChannel(ctx, channelId, allowFromCache)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
@@ -7862,10 +7862,10 @@ func (s *TimerLayerUserStore) GetKnownUsers(userID string) ([]string, error) {
return result, err
}
func (s *TimerLayerUserStore) GetMany(ids []string) ([]*model.User, error) {
func (s *TimerLayerUserStore) GetMany(ctx context.Context, ids []string) ([]*model.User, error) {
start := timemodule.Now()
result, err := s.UserStore.GetMany(ids)
result, err := s.UserStore.GetMany(ctx, ids)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
@@ -7910,10 +7910,10 @@ func (s *TimerLayerUserStore) GetProfileByGroupChannelIdsForUser(userId string,
return result, err
}
func (s *TimerLayerUserStore) GetProfileByIds(userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error) {
func (s *TimerLayerUserStore) GetProfileByIds(ctx context.Context, userIds []string, options *store.UserGetByIdsOpts, allowFromCache bool) ([]*model.User, error) {
start := timemodule.Now()
result, err := s.UserStore.GetProfileByIds(userIds, options, allowFromCache)
result, err := s.UserStore.GetProfileByIds(ctx, userIds, options, allowFromCache)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {

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

@@ -4,6 +4,7 @@
package web
import (
"context"
"net/http"
"testing"
@@ -55,7 +56,7 @@ func TestMfaRequired(t *testing.T) {
mockStore := th.App.Srv().Store.(*mocks.Store)
mockUserStore := mocks.UserStore{}
mockUserStore.On("Count", mock.Anything).Return(int64(10), nil)
mockUserStore.On("Get", "userid").Return(nil, model.NewAppError("Userstore.Get", "storeerror", nil, "store error", http.StatusInternalServerError))
mockUserStore.On("Get", context.Background(), "userid").Return(nil, model.NewAppError("Userstore.Get", "storeerror", nil, "store error", http.StatusInternalServerError))
mockPostStore := mocks.PostStore{}
mockPostStore.On("GetMaxPostSize").Return(65535, nil)
mockSystemStore := mocks.SystemStore{}