github.com/mattermost/mattermost-server/v5@v5.39.3/store/searchlayer/post_layer.go (about)

     1  // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
     2  // See LICENSE.txt for license information.
     3  
     4  package searchlayer
     5  
     6  import (
     7  	"context"
     8  
     9  	"github.com/pkg/errors"
    10  
    11  	"github.com/mattermost/mattermost-server/v5/model"
    12  	"github.com/mattermost/mattermost-server/v5/services/searchengine"
    13  	"github.com/mattermost/mattermost-server/v5/shared/mlog"
    14  	"github.com/mattermost/mattermost-server/v5/store"
    15  )
    16  
    17  type SearchPostStore struct {
    18  	store.PostStore
    19  	rootStore *SearchStore
    20  }
    21  
    22  func (s SearchPostStore) indexPost(post *model.Post) {
    23  	for _, engine := range s.rootStore.searchEngine.GetActiveEngines() {
    24  		if engine.IsIndexingEnabled() {
    25  			runIndexFn(engine, func(engineCopy searchengine.SearchEngineInterface) {
    26  				channel, chanErr := s.rootStore.Channel().Get(post.ChannelId, true)
    27  				if chanErr != nil {
    28  					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), mlog.Err(chanErr))
    29  					return
    30  				}
    31  				if err := engineCopy.IndexPost(post, channel.TeamId); err != nil {
    32  					mlog.Warn("Encountered error indexing post", mlog.String("post_id", post.Id), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
    33  					return
    34  				}
    35  				mlog.Debug("Indexed post in search engine", mlog.String("search_engine", engineCopy.GetName()), mlog.String("post_id", post.Id))
    36  			})
    37  		}
    38  	}
    39  }
    40  
    41  func (s SearchPostStore) deletePostIndex(post *model.Post) {
    42  	for _, engine := range s.rootStore.searchEngine.GetActiveEngines() {
    43  		if engine.IsIndexingEnabled() {
    44  			runIndexFn(engine, func(engineCopy searchengine.SearchEngineInterface) {
    45  				if err := engineCopy.DeletePost(post); err != nil {
    46  					mlog.Warn("Encountered error deleting post", mlog.String("post_id", post.Id), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
    47  					return
    48  				}
    49  				mlog.Debug("Removed post from the index in search engine", mlog.String("search_engine", engineCopy.GetName()), mlog.String("post_id", post.Id))
    50  			})
    51  		}
    52  	}
    53  }
    54  
    55  func (s SearchPostStore) deleteChannelPostsIndex(channelID string) {
    56  	for _, engine := range s.rootStore.searchEngine.GetActiveEngines() {
    57  		if engine.IsIndexingEnabled() {
    58  			runIndexFn(engine, func(engineCopy searchengine.SearchEngineInterface) {
    59  				if err := engineCopy.DeleteChannelPosts(channelID); err != nil {
    60  					mlog.Warn("Encountered error deleting channel posts", mlog.String("channel_id", channelID), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
    61  					return
    62  				}
    63  				mlog.Debug("Removed all channel posts from the index in search engine", mlog.String("channel_id", channelID), mlog.String("search_engine", engineCopy.GetName()))
    64  			})
    65  		}
    66  	}
    67  }
    68  
    69  func (s SearchPostStore) deleteUserPostsIndex(userID string) {
    70  	for _, engine := range s.rootStore.searchEngine.GetActiveEngines() {
    71  		if engine.IsIndexingEnabled() {
    72  			runIndexFn(engine, func(engineCopy searchengine.SearchEngineInterface) {
    73  				if err := engineCopy.DeleteUserPosts(userID); err != nil {
    74  					mlog.Warn("Encountered error deleting user posts", mlog.String("user_id", userID), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
    75  					return
    76  				}
    77  				mlog.Debug("Removed all user posts from the index in search engine", mlog.String("user_id", userID), mlog.String("search_engine", engineCopy.GetName()))
    78  			})
    79  		}
    80  	}
    81  }
    82  
    83  func (s SearchPostStore) Update(newPost, oldPost *model.Post) (*model.Post, error) {
    84  	post, err := s.PostStore.Update(newPost, oldPost)
    85  
    86  	if err == nil {
    87  		s.indexPost(post)
    88  	}
    89  	return post, err
    90  }
    91  
    92  func (s *SearchPostStore) Overwrite(post *model.Post) (*model.Post, error) {
    93  	post, err := s.PostStore.Overwrite(post)
    94  	if err == nil {
    95  		s.indexPost(post)
    96  	}
    97  	return post, err
    98  }
    99  
   100  func (s SearchPostStore) Save(post *model.Post) (*model.Post, error) {
   101  	npost, err := s.PostStore.Save(post)
   102  
   103  	if err == nil {
   104  		s.indexPost(npost)
   105  	}
   106  	return npost, err
   107  }
   108  
   109  func (s SearchPostStore) Delete(postId string, date int64, deletedByID string) error {
   110  	err := s.PostStore.Delete(postId, date, deletedByID)
   111  
   112  	if err == nil {
   113  		postList, err2 := s.PostStore.Get(context.Background(), postId, true, false, false, "")
   114  		if postList != nil && len(postList.Order) > 0 {
   115  			if err2 != nil {
   116  				s.deletePostIndex(postList.Posts[postList.Order[0]])
   117  			}
   118  		}
   119  	}
   120  	return err
   121  }
   122  
   123  func (s SearchPostStore) PermanentDeleteByUser(userID string) error {
   124  	err := s.PostStore.PermanentDeleteByUser(userID)
   125  	if err == nil {
   126  		s.deleteUserPostsIndex(userID)
   127  	}
   128  	return err
   129  }
   130  
   131  func (s SearchPostStore) PermanentDeleteByChannel(channelID string) error {
   132  	err := s.PostStore.PermanentDeleteByChannel(channelID)
   133  	if err == nil {
   134  		s.deleteChannelPostsIndex(channelID)
   135  	}
   136  	return err
   137  }
   138  
   139  func (s SearchPostStore) searchPostsInTeamForUserByEngine(engine searchengine.SearchEngineInterface, paramsList []*model.SearchParams, userId, teamId string, page, perPage int) (*model.PostSearchResults, error) {
   140  	if err := model.IsSearchParamsListValid(paramsList); err != nil {
   141  		return nil, err
   142  	}
   143  
   144  	// We only allow the user to search in channels they are a member of.
   145  	userChannels, err2 := s.rootStore.Channel().GetChannels(teamId, userId, paramsList[0].IncludeDeletedChannels, 0)
   146  	if err2 != nil {
   147  		return nil, errors.Wrap(err2, "error getting channel for user")
   148  	}
   149  
   150  	postIds, matches, err := engine.SearchPosts(userChannels, paramsList, page, perPage)
   151  	if err != nil {
   152  		return nil, err
   153  	}
   154  
   155  	// Get the posts
   156  	postList := model.NewPostList()
   157  	if len(postIds) > 0 {
   158  		posts, err := s.PostStore.GetPostsByIds(postIds)
   159  		if err != nil {
   160  			return nil, err
   161  		}
   162  		for _, p := range posts {
   163  			if p.DeleteAt == 0 {
   164  				postList.AddPost(p)
   165  				postList.AddOrder(p.Id)
   166  			}
   167  		}
   168  	}
   169  
   170  	return model.MakePostSearchResults(postList, matches), nil
   171  }
   172  
   173  func (s SearchPostStore) SearchPostsInTeamForUser(paramsList []*model.SearchParams, userId, teamId string, page, perPage int) (*model.PostSearchResults, error) {
   174  	for _, engine := range s.rootStore.searchEngine.GetActiveEngines() {
   175  		if engine.IsSearchEnabled() {
   176  			results, err := s.searchPostsInTeamForUserByEngine(engine, paramsList, userId, teamId, page, perPage)
   177  			if err != nil {
   178  				mlog.Warn("Encountered error on SearchPostsInTeamForUser.", mlog.String("search_engine", engine.GetName()), mlog.Err(err))
   179  				continue
   180  			}
   181  			mlog.Debug("Using the first available search engine", mlog.String("search_engine", engine.GetName()))
   182  			return results, err
   183  		}
   184  	}
   185  
   186  	if *s.rootStore.getConfig().SqlSettings.DisableDatabaseSearch {
   187  		mlog.Debug("Returning empty results for post SearchPostsInTeam as the database search is disabled")
   188  		return &model.PostSearchResults{PostList: model.NewPostList(), Matches: model.PostSearchMatches{}}, nil
   189  	}
   190  
   191  	mlog.Debug("Using database search because no other search engine is available")
   192  	return s.PostStore.SearchPostsInTeamForUser(paramsList, userId, teamId, page, perPage)
   193  }