Adding the new search engine abstraction (#13304)

* WIP

* Adding bleve to go modules

* WIP

* Adding missing files from searchengine implementation

* WIP

* WIP

* WIP

* WIP

* WIP

* WIP

* User and channel indexing and searches implemented

* Make bleve tests run with in-memory indexes

* Implement post index and deletion tests

* Initial commits for the search layer

* Removing unnecesary indexing

* WIP

* WIP

* More fixes for tests

* Adding the search layer

* Finishing the migration of searchers to the layer

* Removing unnecesary code

* Allowing multiple engines active at the same time

* WIP

* Add simple post search

* Print information when using bleve

* Adding some debugging to understand better how the searches are working

* Making more dynamic config of search engines

* Add post search basics

* Adding the Purge API endpoint

* Fixing bleve config updates

* Adding missed file

* Regenerating search engine mocks

* Adding missed v5 to modules imports

* fixing i18n

* Fixing some test around search engine

* Removing all bleve traces

* Cleaning up the vendors directory and go.mod/go.sum files

* Regenerating timer layer

* Adding properly the license

* Fixing govet shadow error

* Fixing some tests

* Fixing TestSearchPostsFromUser

* Fixing another test

* Fixing more tests

* Fixing more tests

* Removing SearchEngine redundant text from searchengine module code

* Fixing some reindexing problems in members updates

* Fixing tests

* Addressing PR comments

* Reverting go.mod and go.sum

* Addressing PR comments

* Fixing tests compilation

* Fixing govet

* Adding search engine stop method

* Being more explicit on where we use includeDeleted

* Adding GetSqlSupplier test helper method

* Mocking elasticsearch start function

* Fixing tests

Co-authored-by: Miguel de la Cruz <miguel@mcrx.me>
Co-authored-by: mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
Jesús Espino
2020-03-13 15:33:18 +01:00
коммит произвёл GitHub
родитель e2883bfe5f
Коммит c66e182b08
43 изменённых файлов: 1331 добавлений и 908 удалений

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

@@ -936,7 +936,7 @@ func (s *OpenTracingLayerChannelStore) GetChannelsBatchForIndexing(startTime int
return resultVar0, resultVar1
}
func (s *OpenTracingLayerChannelStore) GetChannelsByIds(channelIds []string) ([]*model.Channel, *model.AppError) {
func (s *OpenTracingLayerChannelStore) GetChannelsByIds(channelIds []string, includeDeleted bool) ([]*model.Channel, *model.AppError) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetChannelsByIds")
s.Root.Store.SetContext(newCtx)
@@ -945,7 +945,7 @@ func (s *OpenTracingLayerChannelStore) GetChannelsByIds(channelIds []string) ([]
}()
defer span.Finish()
resultVar0, resultVar1 := s.ChannelStore.GetChannelsByIds(channelIds)
resultVar0, resultVar1 := s.ChannelStore.GetChannelsByIds(channelIds, includeDeleted)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
@@ -4873,6 +4873,24 @@ func (s *OpenTracingLayerPostStore) Search(teamId string, userId string, params
return resultVar0, resultVar1
}
func (s *OpenTracingLayerPostStore) SearchPostsInTeamForUser(paramsList []*model.SearchParams, userId string, teamId string, isOrSearch bool, includeDeletedChannels bool, page int, perPage int) (*model.PostSearchResults, *model.AppError) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.SearchPostsInTeamForUser")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
resultVar0, resultVar1 := s.PostStore.SearchPostsInTeamForUser(paramsList, userId, teamId, isOrSearch, includeDeletedChannels, page, perPage)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (s *OpenTracingLayerPostStore) Update(newPost *model.Post, oldPost *model.Post) (*model.Post, *model.AppError) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "PostStore.Update")
@@ -6905,6 +6923,24 @@ func (s *OpenTracingLayerUserStore) AnalyticsGetSystemAdminCount() (int64, *mode
return resultVar0, resultVar1
}
func (s *OpenTracingLayerUserStore) AutocompleteUsersInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError) {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.AutocompleteUsersInChannel")
s.Root.Store.SetContext(newCtx)
defer func() {
s.Root.Store.SetContext(origCtx)
}()
defer span.Finish()
resultVar0, resultVar1 := s.UserStore.AutocompleteUsersInChannel(teamId, channelId, term, options)
if resultVar1 != nil {
span.LogFields(spanlog.Error(resultVar1))
ext.Error.Set(span, true)
}
return resultVar0, resultVar1
}
func (s *OpenTracingLayerUserStore) ClearAllCustomRoleAssignments() *model.AppError {
origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "UserStore.ClearAllCustomRoleAssignments")

207
store/searchlayer/channel_layer.go Обычный файл
Просмотреть файл

@@ -0,0 +1,207 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package searchlayer
import (
"github.com/mattermost/mattermost-server/v5/mlog"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/services/searchengine"
"github.com/mattermost/mattermost-server/v5/store"
)
type SearchChannelStore struct {
store.ChannelStore
rootStore *SearchStore
}
func (c *SearchChannelStore) deleteChannelIndex(channel *model.Channel) {
if channel.Type == model.CHANNEL_OPEN {
for _, engine := range c.rootStore.searchEngine.GetActiveEngines() {
if engine.IsIndexingEnabled() {
go (func(engineCopy searchengine.SearchEngineInterface) {
if err := engineCopy.DeleteChannel(channel); err != nil {
mlog.Error("Encountered error deleting channel", mlog.String("channel_id", channel.Id), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
}
mlog.Debug("Removed channel from index in search engine", mlog.String("search_engine", engineCopy.GetName()), mlog.String("channel_id", channel.Id))
})(engine)
}
}
}
}
func (c *SearchChannelStore) indexChannel(channel *model.Channel) {
if channel.Type == model.CHANNEL_OPEN {
for _, engine := range c.rootStore.searchEngine.GetActiveEngines() {
if engine.IsIndexingEnabled() {
go (func(engineCopy searchengine.SearchEngineInterface) {
if err := engineCopy.IndexChannel(channel); err != nil {
mlog.Error("Encountered error indexing channel", mlog.String("channel_id", channel.Id), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
}
mlog.Debug("Indexed channel in search engine", mlog.String("search_engine", engineCopy.GetName()), mlog.String("channel_id", channel.Id))
})(engine)
}
}
}
}
func (c *SearchChannelStore) Save(channel *model.Channel, maxChannels int64) (*model.Channel, *model.AppError) {
newChannel, err := c.ChannelStore.Save(channel, maxChannels)
if err == nil {
c.indexChannel(newChannel)
}
return newChannel, err
}
func (c *SearchChannelStore) Update(channel *model.Channel) (*model.Channel, *model.AppError) {
updatedChannel, err := c.ChannelStore.Update(channel)
if err == nil {
c.indexChannel(updatedChannel)
}
return updatedChannel, err
}
func (c *SearchChannelStore) UpdateMember(cm *model.ChannelMember) (*model.ChannelMember, *model.AppError) {
member, err := c.ChannelStore.UpdateMember(cm)
if err == nil {
c.rootStore.indexUserFromID(cm.UserId)
channel, channelErr := c.ChannelStore.Get(member.ChannelId, true)
if channelErr != nil {
mlog.Error("Encountered error indexing user in channel", mlog.String("channel_id", member.ChannelId), mlog.Err(err))
} else {
c.rootStore.indexUserFromID(channel.CreatorId)
}
}
return member, err
}
func (c *SearchChannelStore) SaveMember(cm *model.ChannelMember) (*model.ChannelMember, *model.AppError) {
member, err := c.ChannelStore.SaveMember(cm)
if err == nil {
c.rootStore.indexUserFromID(cm.UserId)
channel, channelErr := c.ChannelStore.Get(member.ChannelId, true)
if channelErr != nil {
mlog.Error("Encountered error indexing user in channel", mlog.String("channel_id", member.ChannelId), mlog.Err(err))
} else {
c.rootStore.indexUserFromID(channel.CreatorId)
}
}
return member, err
}
func (c *SearchChannelStore) RemoveMember(channelId, userIdToRemove string) *model.AppError {
err := c.ChannelStore.RemoveMember(channelId, userIdToRemove)
if err == nil {
c.rootStore.indexUserFromID(userIdToRemove)
}
return err
}
func (c *SearchChannelStore) CreateDirectChannel(user *model.User, otherUser *model.User) (*model.Channel, *model.AppError) {
channel, err := c.ChannelStore.CreateDirectChannel(user, otherUser)
if err == nil {
c.rootStore.indexUserFromID(user.Id)
c.rootStore.indexUserFromID(otherUser.Id)
}
return channel, err
}
func (c *SearchChannelStore) AutocompleteInTeam(teamId string, term string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
var channelList *model.ChannelList
var err *model.AppError
allFailed := true
for _, engine := range c.rootStore.searchEngine.GetActiveEngines() {
if engine.IsAutocompletionEnabled() {
channelList, err = c.searchAutocompleteChannels(engine, teamId, term, includeDeleted)
if err != nil {
mlog.Error("Encountered error on AutocompleteChannels through SearchEngine. Falling back to default autocompletion.", mlog.String("search_engine", engine.GetName()), mlog.Err(err))
continue
}
allFailed = false
mlog.Debug("Using the first available search engine", mlog.String("search_engine", engine.GetName()))
break
}
}
if allFailed {
mlog.Debug("Using database search because no other search engine is available")
channelList, err = c.ChannelStore.AutocompleteInTeam(teamId, term, includeDeleted)
if err != nil {
return nil, err
}
}
return channelList, err
}
func (c *SearchChannelStore) searchAutocompleteChannels(engine searchengine.SearchEngineInterface, teamId, term string, includeDeleted bool) (*model.ChannelList, *model.AppError) {
channelIds, err := engine.SearchChannels(teamId, term)
if err != nil {
return nil, err
}
channelList := model.ChannelList{}
if len(channelIds) > 0 {
channels, err := c.ChannelStore.GetChannelsByIds(channelIds, includeDeleted)
if err != nil {
return nil, err
}
for _, ch := range channels {
channelList = append(channelList, ch)
}
}
return &channelList, nil
}
func (c *SearchChannelStore) PermanentDeleteMembersByUser(userId string) *model.AppError {
err := c.ChannelStore.PermanentDeleteMembersByUser(userId)
if err == nil {
c.rootStore.indexUserFromID(userId)
}
return err
}
func (c *SearchChannelStore) RemoveAllDeactivatedMembers(channelId string) *model.AppError {
profiles, errProfiles := c.rootStore.User().GetAllProfilesInChannel(channelId, true)
if errProfiles != nil {
mlog.Error("Encountered error indexing users for channel", mlog.String("channel_id", channelId), mlog.Err(errProfiles))
}
err := c.ChannelStore.RemoveAllDeactivatedMembers(channelId)
if err == nil && errProfiles == nil {
for _, user := range profiles {
if user.DeleteAt != 0 {
c.rootStore.indexUser(user)
}
}
}
return err
}
func (c *SearchChannelStore) PermanentDeleteMembersByChannel(channelId string) *model.AppError {
profiles, errProfiles := c.rootStore.User().GetAllProfilesInChannel(channelId, true)
if errProfiles != nil {
mlog.Error("Encountered error indexing users for channel", mlog.String("channel_id", channelId), mlog.Err(errProfiles))
}
err := c.ChannelStore.PermanentDeleteMembersByChannel(channelId)
if err == nil && errProfiles == nil {
for _, user := range profiles {
c.rootStore.indexUser(user)
}
}
return err
}
func (c *SearchChannelStore) PermanentDelete(channelId string) *model.AppError {
channel, channelErr := c.ChannelStore.Get(channelId, true)
if channelErr != nil {
mlog.Error("Encountered error deleting channel", mlog.String("channel_id", channelId), mlog.Err(channelErr))
}
err := c.ChannelStore.PermanentDelete(channelId)
if err == nil && channelErr == nil {
c.deleteChannelIndex(channel)
}
return err
}

93
store/searchlayer/layer.go Обычный файл
Просмотреть файл

@@ -0,0 +1,93 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package searchlayer
import (
"github.com/mattermost/mattermost-server/v5/mlog"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/services/searchengine"
"github.com/mattermost/mattermost-server/v5/store"
)
type SearchStore struct {
store.Store
searchEngine *searchengine.Broker
user *SearchUserStore
team *SearchTeamStore
channel *SearchChannelStore
post *SearchPostStore
}
func NewSearchLayer(baseStore store.Store, searchEngine *searchengine.Broker) SearchStore {
searchStore := SearchStore{
Store: baseStore,
searchEngine: searchEngine,
}
searchStore.channel = &SearchChannelStore{ChannelStore: baseStore.Channel(), rootStore: &searchStore}
searchStore.post = &SearchPostStore{PostStore: baseStore.Post(), rootStore: &searchStore}
searchStore.team = &SearchTeamStore{TeamStore: baseStore.Team(), rootStore: &searchStore}
searchStore.user = &SearchUserStore{UserStore: baseStore.User(), rootStore: &searchStore}
return searchStore
}
func (s SearchStore) Channel() store.ChannelStore {
return s.channel
}
func (s SearchStore) Post() store.PostStore {
return s.post
}
func (s SearchStore) Team() store.TeamStore {
return s.team
}
func (s SearchStore) User() store.UserStore {
return s.user
}
func (s SearchStore) indexUserFromID(userId string) {
user, err := s.User().Get(userId)
if err != nil {
return
}
s.indexUser(user)
}
func (s SearchStore) indexUser(user *model.User) {
for _, engine := range s.searchEngine.GetActiveEngines() {
if engine.IsIndexingEnabled() {
go (func(engineCopy searchengine.SearchEngineInterface) {
userTeams, err := s.Team().GetTeamsByUserId(user.Id)
if err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", user.Id), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
return
}
userTeamsIds := []string{}
for _, team := range userTeams {
userTeamsIds = append(userTeamsIds, team.Id)
}
userChannelMembers, err := s.Channel().GetAllChannelMembersForUser(user.Id, false, true)
if err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", user.Id), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
return
}
userChannelsIds := []string{}
for channelId := range userChannelMembers {
userChannelsIds = append(userChannelsIds, channelId)
}
if err := engineCopy.IndexUser(user, userTeamsIds, userChannelsIds); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", user.Id), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
return
}
mlog.Debug("Indexed user in search engine", mlog.String("search_engine", engineCopy.GetName()), mlog.String("user_id", user.Id))
})(engine)
}
}
}

126
store/searchlayer/post_layer.go Обычный файл
Просмотреть файл

@@ -0,0 +1,126 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package searchlayer
import (
"github.com/mattermost/mattermost-server/v5/mlog"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/services/searchengine"
"github.com/mattermost/mattermost-server/v5/store"
)
type SearchPostStore struct {
store.PostStore
rootStore *SearchStore
}
func (s SearchPostStore) indexPost(post *model.Post) {
for _, engine := range s.rootStore.searchEngine.GetActiveEngines() {
if engine.IsIndexingEnabled() {
go (func(engineCopy searchengine.SearchEngineInterface) {
channel, chanErr := s.rootStore.Channel().GetForPost(post.Id)
if chanErr != nil {
mlog.Error("Couldn't get channel for post for SearchEngine indexing.", mlog.String("channel_id", post.ChannelId), mlog.String("search_engine", engineCopy.GetName()), mlog.String("post_id", post.Id))
return
}
if err := engineCopy.IndexPost(post, channel.TeamId); err != nil {
mlog.Error("Encountered error indexing post", mlog.String("post_id", post.Id), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
}
mlog.Debug("Indexed post in search engine", mlog.String("search_engine", engineCopy.GetName()), mlog.String("post_id", post.Id))
})(engine)
}
}
}
func (s SearchPostStore) deletePostIndex(post *model.Post) {
for _, engine := range s.rootStore.searchEngine.GetActiveEngines() {
if engine.IsIndexingEnabled() {
go (func(engineCopy searchengine.SearchEngineInterface) {
if err := engineCopy.DeletePost(post); err != nil {
mlog.Error("Encountered error deleting post", mlog.String("post_id", post.Id), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
}
mlog.Debug("Removed post from the index in search engine", mlog.String("search_engine", engineCopy.GetName()), mlog.String("post_id", post.Id))
})(engine)
}
}
}
func (s SearchPostStore) Update(newPost, oldPost *model.Post) (*model.Post, *model.AppError) {
post, err := s.PostStore.Update(newPost, oldPost)
if err == nil {
s.indexPost(post)
}
return post, err
}
func (s SearchPostStore) Save(post *model.Post) (*model.Post, *model.AppError) {
npost, err := s.PostStore.Save(post)
if err == nil {
s.indexPost(npost)
}
return npost, err
}
func (s SearchPostStore) Delete(postId string, date int64, deletedByID string) *model.AppError {
err := s.PostStore.Delete(postId, date, deletedByID)
if err == nil {
postList, err2 := s.PostStore.Get(postId, true)
if postList != nil && len(postList.Order) > 0 {
if err2 != nil {
s.deletePostIndex(postList.Posts[postList.Order[0]])
}
}
}
return err
}
func (s SearchPostStore) searchPostsInTeamForUserByEngine(engine searchengine.SearchEngineInterface, paramsList []*model.SearchParams, userId, teamId string, isOrSearch, includeDeletedChannels bool, page, perPage int) (*model.PostSearchResults, *model.AppError) {
// We only allow the user to search in channels they are a member of.
userChannels, err := s.rootStore.Channel().GetChannels(teamId, userId, includeDeletedChannels)
if err != nil {
mlog.Error("error getting channel for user", mlog.Err(err))
return nil, err
}
postIds, matches, err := engine.SearchPosts(userChannels, paramsList, page, perPage)
if err != nil {
return nil, err
}
// Get the posts
postList := model.NewPostList()
if len(postIds) > 0 {
posts, err := s.PostStore.GetPostsByIds(postIds)
if err != nil {
return nil, err
}
for _, p := range posts {
if p.DeleteAt == 0 {
postList.AddPost(p)
postList.AddOrder(p.Id)
}
}
}
return model.MakePostSearchResults(postList, matches), nil
}
func (s SearchPostStore) SearchPostsInTeamForUser(paramsList []*model.SearchParams, userId, teamId string, isOrSearch, includeDeletedChannels bool, page, perPage int) (*model.PostSearchResults, *model.AppError) {
for _, engine := range s.rootStore.searchEngine.GetActiveEngines() {
if engine.IsSearchEnabled() {
results, err := s.searchPostsInTeamForUserByEngine(engine, paramsList, userId, teamId, isOrSearch, includeDeletedChannels, page, perPage)
if err != nil {
mlog.Error("Encountered error on SearchPostsInTeamForUser.", mlog.String("search_engine", engine.GetName()), mlog.Err(err))
continue
}
mlog.Debug("Using the first available search engine", mlog.String("search_engine", engine.GetName()))
return results, err
}
}
mlog.Debug("Using database search because no other search engine is available")
return s.PostStore.SearchPostsInTeamForUser(paramsList, userId, teamId, isOrSearch, includeDeletedChannels, page, perPage)
}

46
store/searchlayer/team_layer.go Обычный файл
Просмотреть файл

@@ -0,0 +1,46 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package searchlayer
import (
model "github.com/mattermost/mattermost-server/v5/model"
store "github.com/mattermost/mattermost-server/v5/store"
)
type SearchTeamStore struct {
store.TeamStore
rootStore *SearchStore
}
func (s SearchTeamStore) SaveMember(teamMember *model.TeamMember, maxUsersPerTeam int) (*model.TeamMember, *model.AppError) {
member, err := s.TeamStore.SaveMember(teamMember, maxUsersPerTeam)
if err == nil {
s.rootStore.indexUserFromID(member.UserId)
}
return member, err
}
func (s SearchTeamStore) UpdateMember(teamMember *model.TeamMember) (*model.TeamMember, *model.AppError) {
member, err := s.TeamStore.UpdateMember(teamMember)
if err == nil {
s.rootStore.indexUserFromID(member.UserId)
}
return member, err
}
func (s SearchTeamStore) RemoveMember(teamId string, userId string) *model.AppError {
err := s.TeamStore.RemoveMember(teamId, userId)
if err == nil {
s.rootStore.indexUserFromID(userId)
}
return err
}
func (s SearchTeamStore) RemoveAllMembersByUser(userId string) *model.AppError {
err := s.TeamStore.RemoveAllMembersByUser(userId)
if err == nil {
s.rootStore.indexUserFromID(userId)
}
return err
}

192
store/searchlayer/user_layer.go Обычный файл
Просмотреть файл

@@ -0,0 +1,192 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package searchlayer
import (
"strings"
"github.com/mattermost/mattermost-server/v5/mlog"
"github.com/mattermost/mattermost-server/v5/model"
"github.com/mattermost/mattermost-server/v5/services/searchengine"
"github.com/mattermost/mattermost-server/v5/store"
)
type SearchUserStore struct {
store.UserStore
rootStore *SearchStore
}
func (s *SearchUserStore) deleteUserIndex(user *model.User) {
for _, engine := range s.rootStore.searchEngine.GetActiveEngines() {
if engine.IsIndexingEnabled() {
go (func(engineCopy searchengine.SearchEngineInterface) {
if err := engineCopy.DeleteUser(user); err != nil {
mlog.Error("Encountered error deleting user", mlog.String("user_id", user.Id), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
return
}
mlog.Debug("Removed user from the index in search engine", mlog.String("search_engine", engineCopy.GetName()), mlog.String("user_id", user.Id))
})(engine)
}
}
}
func (s *SearchUserStore) Search(teamId, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError) {
for _, engine := range s.rootStore.searchEngine.GetActiveEngines() {
if engine.IsSearchEnabled() {
listOfAllowedChannels, err := s.getListOfAllowedChannelsForTeam(teamId, options.ViewRestrictions)
if err != nil {
mlog.Error("Encountered error on Search.", mlog.String("search_engine", engine.GetName()), mlog.Err(err))
continue
}
if len(listOfAllowedChannels) == 0 {
return []*model.User{}, nil
}
usersIds, err := engine.SearchUsersInTeam(teamId, listOfAllowedChannels, term, options)
if err != nil {
continue
}
users, err := s.UserStore.GetProfileByIds(usersIds, nil, false)
if err != nil {
continue
}
mlog.Debug("Using the first available search engine", mlog.String("search_engine", engine.GetName()))
return users, nil
}
}
mlog.Debug("Using database search because no other search engine is available")
return s.UserStore.Search(teamId, term, options)
}
func (s *SearchUserStore) Update(user *model.User, trustedUpdateData bool) (*model.UserUpdate, *model.AppError) {
userUpdate, err := s.UserStore.Update(user, trustedUpdateData)
if err == nil {
s.rootStore.indexUser(userUpdate.New)
}
return userUpdate, err
}
func (s *SearchUserStore) Save(user *model.User) (*model.User, *model.AppError) {
nuser, err := s.UserStore.Save(user)
if err == nil {
s.rootStore.indexUser(nuser)
}
return nuser, err
}
func (s *SearchUserStore) PermanentDelete(userId string) *model.AppError {
user, userErr := s.UserStore.Get(userId)
if userErr != nil {
mlog.Error("Encountered error deleting user", mlog.String("user_id", userId), mlog.Err(userErr))
}
err := s.UserStore.PermanentDelete(userId)
if err == nil && userErr == nil {
s.deleteUserIndex(user)
}
return err
}
func (s *SearchUserStore) autocompleteUsersInChannelByEngine(engine searchengine.SearchEngineInterface, teamId, channelId, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError) {
var err *model.AppError
uchanIds := []string{}
nuchanIds := []string{}
if options.ListOfAllowedChannels != nil && !strings.Contains(strings.Join(options.ListOfAllowedChannels, "."), channelId) {
nuchanIds, err = engine.SearchUsersInTeam(teamId, options.ListOfAllowedChannels, term, options)
} else {
uchanIds, nuchanIds, err = engine.SearchUsersInChannel(teamId, channelId, options.ListOfAllowedChannels, term, options)
}
if err != nil {
return nil, err
}
uchan := make(chan store.StoreResult, 1)
go func() {
users, err := s.UserStore.GetProfileByIds(uchanIds, nil, false)
uchan <- store.StoreResult{Data: users, Err: err}
close(uchan)
}()
nuchan := make(chan store.StoreResult, 1)
go func() {
users, err := s.UserStore.GetProfileByIds(nuchanIds, nil, false)
nuchan <- store.StoreResult{Data: users, Err: err}
close(nuchan)
}()
autocomplete := &model.UserAutocompleteInChannel{}
result := <-uchan
if result.Err != nil {
return nil, result.Err
}
inUsers := result.Data.([]*model.User)
autocomplete.InChannel = inUsers
result = <-nuchan
if result.Err != nil {
return nil, result.Err
}
outUsers := result.Data.([]*model.User)
autocomplete.OutOfChannel = outUsers
return autocomplete, nil
}
func (s *SearchUserStore) getListOfAllowedChannelsForTeam(teamId string, viewRestrictions *model.ViewUsersRestrictions) ([]string, *model.AppError) {
var listOfAllowedChannels []string
if viewRestrictions == nil || strings.Contains(strings.Join(viewRestrictions.Teams, "."), teamId) {
channels, err := s.rootStore.Channel().GetTeamChannels(teamId)
if err != nil {
return nil, err
}
channelIds := []string{}
for _, channel := range *channels {
channelIds = append(channelIds, channel.Id)
}
return channelIds, nil
}
channels, err := s.rootStore.Channel().GetChannelsByIds(viewRestrictions.Channels, false)
if err != nil {
return nil, err
}
for _, c := range channels {
if c.TeamId == teamId {
listOfAllowedChannels = append(listOfAllowedChannels, c.Id)
}
}
return listOfAllowedChannels, nil
}
func (s *SearchUserStore) AutocompleteUsersInChannel(teamId, channelId, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError) {
for _, engine := range s.rootStore.searchEngine.GetActiveEngines() {
if engine.IsAutocompletionEnabled() {
listOfAllowedChannels, err := s.getListOfAllowedChannelsForTeam(teamId, options.ViewRestrictions)
if err != nil {
mlog.Error("Encountered error on AutocompleteUsersInChannel.", mlog.String("search_engine", engine.GetName()), mlog.Err(err))
continue
}
if len(listOfAllowedChannels) == 0 {
return &model.UserAutocompleteInChannel{}, nil
}
options.ListOfAllowedChannels = listOfAllowedChannels
autocomplete, err := s.autocompleteUsersInChannelByEngine(engine, teamId, channelId, term, options)
if err != nil {
mlog.Error("Encountered error on AutocompleteUsersInChannel.", mlog.String("search_engine", engine.GetName()), mlog.Err(err))
continue
}
mlog.Debug("Using the first available search engine", mlog.String("search_engine", engine.GetName()))
return autocomplete, err
}
}
mlog.Debug("Using database search because no other search engine is available")
return s.UserStore.AutocompleteUsersInChannel(teamId, channelId, term, options)
}

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

@@ -1865,9 +1865,12 @@ func (s SqlChannelStore) GetAll(teamId string) ([]*model.Channel, *model.AppErro
return data, nil
}
func (s SqlChannelStore) GetChannelsByIds(channelIds []string) ([]*model.Channel, *model.AppError) {
func (s SqlChannelStore) GetChannelsByIds(channelIds []string, includeDeleted bool) ([]*model.Channel, *model.AppError) {
keys, params := MapStringsToQueryParams(channelIds, "Channel")
query := `SELECT * FROM Channels WHERE Id IN ` + keys + ` ORDER BY Name`
if !includeDeleted {
query = `SELECT * FROM Channels WHERE DeleteAt=0 AND Id IN ` + keys + ` ORDER BY Name`
}
var channels []*model.Channel
_, err := s.GetReplica().Select(&channels, query, params)

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

@@ -999,7 +999,7 @@ func (s *SqlPostStore) buildCreateDateFilterClause(params *model.SearchParams, q
return searchQuery, queryParams
}
func (s *SqlPostStore) buildSearchChannelFilterClause(channels []string, paramPrefix string, exclusion bool, queryParams map[string]interface{}) (string, map[string]interface{}) {
func (s *SqlPostStore) buildSearchChannelFilterClause(channels []string, paramPrefix string, exclusion bool, queryParams map[string]interface{}, byName bool) (string, map[string]interface{}) {
if len(channels) == 0 {
return "", queryParams
}
@@ -1011,13 +1011,20 @@ func (s *SqlPostStore) buildSearchChannelFilterClause(channels []string, paramPr
queryParams[paramName] = channel
}
clause := strings.Join(clauseSlice, ", ")
if exclusion {
return "AND Name NOT IN (" + clause + ")", queryParams
if byName {
if exclusion {
return "AND Name NOT IN (" + clause + ")", queryParams
}
return "AND Name IN (" + clause + ")", queryParams
}
return "AND Name IN (" + clause + ")", queryParams
if exclusion {
return "AND Id NOT IN (" + clause + ")", queryParams
}
return "AND Id IN (" + clause + ")", queryParams
}
func (s *SqlPostStore) buildSearchUserFilterClause(users []string, paramPrefix string, exclusion bool, queryParams map[string]interface{}) (string, map[string]interface{}) {
func (s *SqlPostStore) buildSearchUserFilterClause(users []string, paramPrefix string, exclusion bool, queryParams map[string]interface{}, byUsername bool) (string, map[string]interface{}) {
if len(users) == 0 {
return "", queryParams
}
@@ -1028,13 +1035,19 @@ func (s *SqlPostStore) buildSearchUserFilterClause(users []string, paramPrefix s
queryParams[paramName] = user
}
clause := strings.Join(clauseSlice, ", ")
if exclusion {
return "AND Username NOT IN (" + clause + ")", queryParams
if byUsername {
if exclusion {
return "AND Username NOT IN (" + clause + ")", queryParams
}
return "AND Username IN (" + clause + ")", queryParams
}
return "AND Username IN (" + clause + ")", queryParams
if exclusion {
return "AND Id NOT IN (" + clause + ")", queryParams
}
return "AND Id IN (" + clause + ")", queryParams
}
func (s *SqlPostStore) buildSearchPostFilterClause(fromUsers []string, excludedUsers []string, queryParams map[string]interface{}) (string, map[string]interface{}) {
func (s *SqlPostStore) buildSearchPostFilterClause(fromUsers []string, excludedUsers []string, queryParams map[string]interface{}, userByUsername bool) (string, map[string]interface{}) {
if len(fromUsers) == 0 && len(excludedUsers) == 0 {
return "", queryParams
}
@@ -1052,16 +1065,20 @@ func (s *SqlPostStore) buildSearchPostFilterClause(fromUsers []string, excludedU
FROM_USER_FILTER
EXCLUDED_USER_FILTER)`
fromUserClause, queryParams := s.buildSearchUserFilterClause(fromUsers, "FromUser", false, queryParams)
fromUserClause, queryParams := s.buildSearchUserFilterClause(fromUsers, "FromUser", false, queryParams, userByUsername)
filterQuery = strings.Replace(filterQuery, "FROM_USER_FILTER", fromUserClause, 1)
excludedUserClause, queryParams := s.buildSearchUserFilterClause(excludedUsers, "ExcludedUser", true, queryParams)
excludedUserClause, queryParams := s.buildSearchUserFilterClause(excludedUsers, "ExcludedUser", true, queryParams, userByUsername)
filterQuery = strings.Replace(filterQuery, "EXCLUDED_USER_FILTER", excludedUserClause, 1)
return filterQuery, queryParams
}
func (s *SqlPostStore) Search(teamId string, userId string, params *model.SearchParams) (*model.PostList, *model.AppError) {
return s.search(teamId, userId, params, true, true)
}
func (s *SqlPostStore) search(teamId string, userId string, params *model.SearchParams, channelsByName bool, userByUsername bool) (*model.PostList, *model.AppError) {
queryParams := map[string]interface{}{
"TeamId": teamId,
"UserId": userId,
@@ -1114,13 +1131,13 @@ func (s *SqlPostStore) Search(teamId string, userId string, params *model.Search
ORDER BY CreateAt DESC
LIMIT 100`
inChannelClause, queryParams := s.buildSearchChannelFilterClause(params.InChannels, "InChannel", false, queryParams)
inChannelClause, queryParams := s.buildSearchChannelFilterClause(params.InChannels, "InChannel", false, queryParams, channelsByName)
searchQuery = strings.Replace(searchQuery, "IN_CHANNEL_FILTER", inChannelClause, 1)
excludedChannelClause, queryParams := s.buildSearchChannelFilterClause(params.ExcludedChannels, "ExcludedChannel", true, queryParams)
excludedChannelClause, queryParams := s.buildSearchChannelFilterClause(params.ExcludedChannels, "ExcludedChannel", true, queryParams, channelsByName)
searchQuery = strings.Replace(searchQuery, "EXCLUDED_CHANNEL_FILTER", excludedChannelClause, 1)
postFilterClause, queryParams := s.buildSearchPostFilterClause(params.FromUsers, params.ExcludedUsers, queryParams)
postFilterClause, queryParams := s.buildSearchPostFilterClause(params.FromUsers, params.ExcludedUsers, queryParams, userByUsername)
searchQuery = strings.Replace(searchQuery, "POST_FILTER", postFilterClause, 1)
createDateFilterClause, queryParams := s.buildCreateDateFilterClause(params, queryParams)
@@ -1666,3 +1683,49 @@ func (s *SqlPostStore) GetDirectPostParentsForExportAfter(limit int, afterId str
}
return posts, nil
}
func (s *SqlPostStore) SearchPostsInTeamForUser(paramsList []*model.SearchParams, userId, teamId string, isOrSearch, includeDeletedChannels bool, page, perPage int) (*model.PostSearchResults, *model.AppError) {
// Since we don't support paging for DB search, we just return nothing for later pages
if page > 0 {
return model.MakePostSearchResults(model.NewPostList(), nil), nil
}
var wg sync.WaitGroup
pchan := make(chan store.StoreResult, len(paramsList))
for _, params := range paramsList {
// Don't allow users to search for everything.
if params.Terms == "*" {
continue
}
params.IncludeDeletedChannels = includeDeletedChannels
params.OrTerms = isOrSearch
wg.Add(1)
go func(params *model.SearchParams) {
defer wg.Done()
postList, err := s.search(teamId, userId, params, false, false)
pchan <- store.StoreResult{Data: postList, Err: err}
}(params)
}
wg.Wait()
close(pchan)
posts := model.NewPostList()
for result := range pchan {
if result.Err != nil {
return nil, result.Err
}
data := result.Data.(*model.PostList)
posts.Extend(data)
}
posts.SortByCreateAt()
return model.MakePostSearchResults(posts, nil), nil
}

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

@@ -1716,3 +1716,35 @@ func (us SqlUserStore) DemoteUserToGuest(userId string) *model.AppError {
}
return nil
}
func (us SqlUserStore) AutocompleteUsersInChannel(teamId, channelId, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError) {
autocomplete := &model.UserAutocompleteInChannel{}
uchan := make(chan store.StoreResult, 1)
go func() {
users, err := us.SearchInChannel(channelId, term, options)
uchan <- store.StoreResult{Data: users, Err: err}
close(uchan)
}()
nuchan := make(chan store.StoreResult, 1)
go func() {
users, err := us.SearchNotInChannel(teamId, channelId, term, options)
nuchan <- store.StoreResult{Data: users, Err: err}
close(nuchan)
}()
result := <-uchan
if result.Err != nil {
return nil, result.Err
}
users := result.Data.([]*model.User)
autocomplete.InChannel = users
result = <-nuchan
if result.Err != nil {
return nil, result.Err
}
users = result.Data.([]*model.User)
autocomplete.OutOfChannel = users
return autocomplete, nil
}

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

@@ -148,7 +148,7 @@ type ChannelStore interface {
GetChannelCounts(teamId string, userId string) (*model.ChannelCounts, *model.AppError)
GetTeamChannels(teamId string) (*model.ChannelList, *model.AppError)
GetAll(teamId string) ([]*model.Channel, *model.AppError)
GetChannelsByIds(channelIds []string) ([]*model.Channel, *model.AppError)
GetChannelsByIds(channelIds []string, includeDeleted bool) ([]*model.Channel, *model.AppError)
GetForPost(postId string) (*model.Channel, *model.AppError)
SaveMember(member *model.ChannelMember) (*model.ChannelMember, *model.AppError)
UpdateMember(member *model.ChannelMember) (*model.ChannelMember, *model.AppError)
@@ -256,6 +256,7 @@ type PostStore interface {
GetParentsForExportAfter(limit int, afterId string) ([]*model.PostForExport, *model.AppError)
GetRepliesForExport(parentId string) ([]*model.ReplyForExport, *model.AppError)
GetDirectPostParentsForExportAfter(limit int, afterId string) ([]*model.DirectPostForExport, *model.AppError)
SearchPostsInTeamForUser(paramsList []*model.SearchParams, userId, teamId string, isOrSearch, includeDeletedChannels bool, page, perPage int) (*model.PostSearchResults, *model.AppError)
}
type UserStore interface {
@@ -320,6 +321,7 @@ type UserStore interface {
PromoteGuestToUser(userID string) *model.AppError
DemoteUserToGuest(userID string) *model.AppError
DeactivateGuests() ([]string, *model.AppError)
AutocompleteUsersInChannel(teamId, channelId, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError)
}
type BotStore interface {

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

@@ -447,6 +447,18 @@ func testChannelStoreGetChannelsByIds(t *testing.T, ss store.Store) {
o2.Name = "bb" + model.NewId() + "b"
o2.Type = model.CHANNEL_DIRECT
o3 := model.Channel{}
o3.TeamId = model.NewId()
o3.DisplayName = "Deleted channel"
o3.Name = "cc" + model.NewId() + "b"
o3.Type = model.CHANNEL_OPEN
_, err = ss.Channel().Save(&o3, -1)
require.Nil(t, err)
err = ss.Channel().Delete(o3.Id, 123)
require.Nil(t, err)
o3.DeleteAt = 123
o3.UpdateAt = 123
m1 := model.ChannelMember{}
m1.ChannelId = o2.Id
m1.UserId = u1.Id
@@ -460,17 +472,30 @@ func testChannelStoreGetChannelsByIds(t *testing.T, ss store.Store) {
_, err = ss.Channel().SaveDirectChannel(&o2, &m1, &m2)
require.Nil(t, err)
r1, err := ss.Channel().GetChannelsByIds([]string{o1.Id, o2.Id})
require.Nil(t, err, err)
require.Len(t, r1, 2, "invalid returned channels, exepected 2 and got "+strconv.Itoa(len(r1)))
require.Equal(t, o1.ToJson(), r1[0].ToJson())
require.Equal(t, o2.ToJson(), r1[1].ToJson())
t.Run("Get 2 existing channels", func(t *testing.T) {
r1, err := ss.Channel().GetChannelsByIds([]string{o1.Id, o2.Id}, false)
require.Nil(t, err, err)
require.Len(t, r1, 2, "invalid returned channels, exepected 2 and got "+strconv.Itoa(len(r1)))
require.Equal(t, o1.ToJson(), r1[0].ToJson())
require.Equal(t, o2.ToJson(), r1[1].ToJson())
})
nonexistentId := "abcd1234"
r2, err := ss.Channel().GetChannelsByIds([]string{o1.Id, nonexistentId})
require.Nil(t, err, err)
require.Len(t, r2, 1, "invalid returned channels, expected 1 and got "+strconv.Itoa(len(r2)))
require.Equal(t, o1.ToJson(), r2[0].ToJson(), "invalid returned channel")
t.Run("Get 1 existing and 1 not existing channel", func(t *testing.T) {
nonexistentId := "abcd1234"
r2, err := ss.Channel().GetChannelsByIds([]string{o1.Id, nonexistentId}, false)
require.Nil(t, err, err)
require.Len(t, r2, 1, "invalid returned channels, expected 1 and got "+strconv.Itoa(len(r2)))
require.Equal(t, o1.ToJson(), r2[0].ToJson(), "invalid returned channel")
})
t.Run("Get 2 existing and 1 deleted channel", func(t *testing.T) {
r1, err := ss.Channel().GetChannelsByIds([]string{o1.Id, o2.Id, o3.Id}, true)
require.Nil(t, err, err)
require.Len(t, r1, 3, "invalid returned channels, exepected 3 and got "+strconv.Itoa(len(r1)))
require.Equal(t, o1.ToJson(), r1[0].ToJson())
require.Equal(t, o2.ToJson(), r1[1].ToJson())
require.Equal(t, o3.ToJson(), r1[2].ToJson())
})
}
func testChannelStoreGetForPost(t *testing.T, ss store.Store) {

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

@@ -619,13 +619,13 @@ func (_m *ChannelStore) GetChannelsBatchForIndexing(startTime int64, endTime int
return r0, r1
}
// GetChannelsByIds provides a mock function with given fields: channelIds
func (_m *ChannelStore) GetChannelsByIds(channelIds []string) ([]*model.Channel, *model.AppError) {
ret := _m.Called(channelIds)
// GetChannelsByIds provides a mock function with given fields: channelIds, includeDeleted
func (_m *ChannelStore) GetChannelsByIds(channelIds []string, includeDeleted bool) ([]*model.Channel, *model.AppError) {
ret := _m.Called(channelIds, includeDeleted)
var r0 []*model.Channel
if rf, ok := ret.Get(0).(func([]string) []*model.Channel); ok {
r0 = rf(channelIds)
if rf, ok := ret.Get(0).(func([]string, bool) []*model.Channel); ok {
r0 = rf(channelIds, includeDeleted)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.Channel)
@@ -633,8 +633,8 @@ func (_m *ChannelStore) GetChannelsByIds(channelIds []string) ([]*model.Channel,
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func([]string) *model.AppError); ok {
r1 = rf(channelIds)
if rf, ok := ret.Get(1).(func([]string, bool) *model.AppError); ok {
r1 = rf(channelIds, includeDeleted)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)

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

@@ -792,6 +792,31 @@ func (_m *PostStore) Search(teamId string, userId string, params *model.SearchPa
return r0, r1
}
// SearchPostsInTeamForUser provides a mock function with given fields: paramsList, userId, teamId, isOrSearch, includeDeletedChannels, page, perPage
func (_m *PostStore) SearchPostsInTeamForUser(paramsList []*model.SearchParams, userId string, teamId string, isOrSearch bool, includeDeletedChannels bool, page int, perPage int) (*model.PostSearchResults, *model.AppError) {
ret := _m.Called(paramsList, userId, teamId, isOrSearch, includeDeletedChannels, page, perPage)
var r0 *model.PostSearchResults
if rf, ok := ret.Get(0).(func([]*model.SearchParams, string, string, bool, bool, int, int) *model.PostSearchResults); ok {
r0 = rf(paramsList, userId, teamId, isOrSearch, includeDeletedChannels, page, perPage)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.PostSearchResults)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func([]*model.SearchParams, string, string, bool, bool, int, int) *model.AppError); ok {
r1 = rf(paramsList, userId, teamId, isOrSearch, includeDeletedChannels, page, perPage)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// Update provides a mock function with given fields: newPost, oldPost
func (_m *PostStore) Update(newPost *model.Post, oldPost *model.Post) (*model.Post, *model.AppError) {
ret := _m.Called(newPost, oldPost)

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

@@ -84,6 +84,31 @@ func (_m *UserStore) AnalyticsGetSystemAdminCount() (int64, *model.AppError) {
return r0, r1
}
// AutocompleteUsersInChannel provides a mock function with given fields: teamId, channelId, term, options
func (_m *UserStore) AutocompleteUsersInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError) {
ret := _m.Called(teamId, channelId, term, options)
var r0 *model.UserAutocompleteInChannel
if rf, ok := ret.Get(0).(func(string, string, string, *model.UserSearchOptions) *model.UserAutocompleteInChannel); ok {
r0 = rf(teamId, channelId, term, options)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).(*model.UserAutocompleteInChannel)
}
}
var r1 *model.AppError
if rf, ok := ret.Get(1).(func(string, string, string, *model.UserSearchOptions) *model.AppError); ok {
r1 = rf(teamId, channelId, term, options)
} else {
if ret.Get(1) != nil {
r1 = ret.Get(1).(*model.AppError)
}
}
return r0, r1
}
// ClearAllCustomRoleAssignments provides a mock function with given fields:
func (_m *UserStore) ClearAllCustomRoleAssignments() *model.AppError {
ret := _m.Called()

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

@@ -872,10 +872,10 @@ func (s *TimerLayerChannelStore) GetChannelsBatchForIndexing(startTime int64, en
return resultVar0, resultVar1
}
func (s *TimerLayerChannelStore) GetChannelsByIds(channelIds []string) ([]*model.Channel, *model.AppError) {
func (s *TimerLayerChannelStore) GetChannelsByIds(channelIds []string, includeDeleted bool) ([]*model.Channel, *model.AppError) {
start := timemodule.Now()
resultVar0, resultVar1 := s.ChannelStore.GetChannelsByIds(channelIds)
resultVar0, resultVar1 := s.ChannelStore.GetChannelsByIds(channelIds, includeDeleted)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
@@ -4444,6 +4444,22 @@ func (s *TimerLayerPostStore) Search(teamId string, userId string, params *model
return resultVar0, resultVar1
}
func (s *TimerLayerPostStore) SearchPostsInTeamForUser(paramsList []*model.SearchParams, userId string, teamId string, isOrSearch bool, includeDeletedChannels bool, page int, perPage int) (*model.PostSearchResults, *model.AppError) {
start := timemodule.Now()
resultVar0, resultVar1 := s.PostStore.SearchPostsInTeamForUser(paramsList, userId, teamId, isOrSearch, includeDeletedChannels, page, perPage)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if resultVar1 == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("PostStore.SearchPostsInTeamForUser", success, elapsed)
}
return resultVar0, resultVar1
}
func (s *TimerLayerPostStore) Update(newPost *model.Post, oldPost *model.Post) (*model.Post, *model.AppError) {
start := timemodule.Now()
@@ -6264,6 +6280,22 @@ func (s *TimerLayerUserStore) AnalyticsGetSystemAdminCount() (int64, *model.AppE
return resultVar0, resultVar1
}
func (s *TimerLayerUserStore) AutocompleteUsersInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError) {
start := timemodule.Now()
resultVar0, resultVar1 := s.UserStore.AutocompleteUsersInChannel(teamId, channelId, term, options)
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
if s.Root.Metrics != nil {
success := "false"
if resultVar1 == nil {
success = "true"
}
s.Root.Metrics.ObserveStoreMethodDuration("UserStore.AutocompleteUsersInChannel", success, elapsed)
}
return resultVar0, resultVar1
}
func (s *TimerLayerUserStore) ClearAllCustomRoleAssignments() *model.AppError {
start := timemodule.Now()