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)
}()