Adds elasticsearch to the user and channel autocompletion functions (#10354)

* Adds elasticsearch to the user and channel autocompletion functions

* Implement channel store GetChannelsByIds test

* Style changes and govet fixes

* Add gofmt fixes

* Extract default channel search limit to a const

* Add StringSliceDiff function to the utils package

* Honor USER_SEARCH_MAX_LIMIT on the user autocomplete api handler

* Change the elasticsearch development image
Этот коммит содержится в:
Miguel de la Cruz
2019-03-15 17:53:53 +00:00
коммит произвёл GitHub
родитель 5dae08761c
Коммит 44887a0272
17 изменённых файлов: 461 добавлений и 13 удалений

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

@@ -91,6 +91,15 @@ func (a *App) JoinDefaultChannels(teamId string, user *model.User, shouldBeAdmin
}
}
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
if err = a.indexUser(user); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", user.Id), mlog.Err(err))
}
})
}
return err
}
@@ -160,6 +169,15 @@ func (a *App) CreateChannelWithUser(channel *model.Channel, userId string) (*mod
message.Add("team_id", channel.TeamId)
a.Publish(message)
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
if err := a.indexUser(user); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", user.Id), mlog.Err(err))
}
})
}
return rchannel, nil
}
@@ -223,6 +241,24 @@ func (a *App) CreateChannel(channel *model.Channel, addMember bool) (*model.Chan
})
}
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
if sc.Type == "O" {
a.Srv.Go(func() {
if err := esInterface.IndexChannel(sc); err != nil {
mlog.Error("Encountered error indexing channel", mlog.String("channel_id", sc.Id), mlog.Err(err))
}
})
}
if addMember {
a.Srv.Go(func() {
if err := a.indexUserFromId(channel.CreatorId); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", channel.CreatorId), mlog.Err(err))
}
})
}
}
return sc, nil
}
@@ -253,6 +289,17 @@ func (a *App) GetOrCreateDirectChannel(userId, otherUserId string) (*model.Chann
})
}
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
for _, id := range []string{userId, otherUserId} {
if err := a.indexUserFromId(id); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", id), mlog.Err(err))
}
}
})
}
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_DIRECT_ADDED, "", channel.Id, "", nil)
message.Add("teammate_id", otherUserId)
a.Publish(message)
@@ -344,6 +391,17 @@ func (a *App) CreateGroupChannel(userIds []string, creatorId string) (*model.Cha
message.Add("teammate_ids", model.ArrayToJson(userIds))
a.Publish(message)
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
for _, id := range userIds {
if err := a.indexUserFromId(id); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", id), mlog.Err(err))
}
}
})
}
return channel, nil
}
@@ -431,6 +489,15 @@ func (a *App) UpdateChannel(channel *model.Channel) (*model.Channel, *model.AppE
messageWs.Add("channel", channel.ToJson())
a.Publish(messageWs)
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing && channel.Type == "O" {
a.Srv.Go(func() {
if err := esInterface.IndexChannel(channel); err != nil {
mlog.Error("Encountered error indexing channel", mlog.String("channel_id", channel.Id), mlog.Err(err))
}
})
}
return channel, nil
}
@@ -874,6 +941,15 @@ func (a *App) AddChannelMember(userId string, channel *model.Channel, userReques
})
}
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
if err := a.indexUser(user); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", user.Id), mlog.Err(err))
}
})
}
if userRequestorId == "" || userId == userRequestorId {
a.postJoinChannelMessage(user, channel)
} else {
@@ -1289,6 +1365,15 @@ func (a *App) JoinChannel(channel *model.Channel, userId string) *model.AppError
})
}
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
if err := a.indexUser(user); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", user.Id), mlog.Err(err))
}
})
}
if err := a.postJoinChannelMessage(user, channel); err != nil {
return err
}
@@ -1495,6 +1580,15 @@ func (a *App) removeUserFromChannel(userIdToRemove string, removerUserId string,
})
}
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
if err := a.indexUserFromId(userIdToRemove); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", userIdToRemove), mlog.Err(err))
}
})
}
message := model.NewWebSocketEvent(model.WEBSOCKET_EVENT_USER_REMOVED, "", channel.Id, "", nil)
message.Add("user_id", userIdToRemove)
message.Add("remover_id", removerUserId)
@@ -1585,6 +1679,31 @@ func (a *App) UpdateChannelLastViewedAt(channelIds []string, userId string) *mod
func (a *App) AutocompleteChannels(teamId string, term string) (*model.ChannelList, *model.AppError) {
includeDeleted := *a.Config().TeamSettings.ExperimentalViewArchivedChannels
esInterface := a.Elasticsearch
license := a.License()
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableAutocomplete && license != nil && *license.Features.Elasticsearch {
channelIds, err := a.Elasticsearch.SearchChannels(teamId, term)
if err != nil {
return nil, err
}
channelList := model.ChannelList{}
if len(channelIds) > 0 {
cresult := <-a.Srv.Store.Channel().GetChannelsByIds(channelIds)
if cresult.Err != nil {
return nil, cresult.Err
}
for _, c := range cresult.Data.([]*model.Channel) {
if c.DeleteAt > 0 && !includeDeleted {
continue
}
channelList = append(channelList, c)
}
}
return &channelList, nil
}
result := <-a.Srv.Store.Channel().AutocompleteInTeam(teamId, term, includeDeleted)
if result.Err != nil {
return nil, result.Err
@@ -1710,6 +1829,11 @@ func (a *App) ViewChannel(view *model.ChannelView, userId string, clearPushNotif
}
func (a *App) PermanentDeleteChannel(channel *model.Channel) *model.AppError {
channelUsers := <-a.Srv.Store.User().GetAllProfilesInChannel(channel.Id, false)
if channelUsers.Err != nil {
return channelUsers.Err
}
if result := <-a.Srv.Store.Post().PermanentDeleteByChannel(channel.Id); result.Err != nil {
return result.Err
}
@@ -1730,6 +1854,24 @@ func (a *App) PermanentDeleteChannel(channel *model.Channel) *model.AppError {
return result.Err
}
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
for _, user := range channelUsers.Data.(map[string]*model.User) {
if err := a.indexUser(user); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", user.Id), mlog.Err(err))
}
}
})
if channel.Type == "O" {
a.Srv.Go(func() {
if err := esInterface.DeleteChannel(channel); err != nil {
mlog.Error("Encountered error deleting channel", mlog.String("channel_id", channel.Id), mlog.Err(err))
}
})
}
}
return nil
}

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

@@ -548,9 +548,14 @@ func (a *App) trackConfig() {
"isdefault_password": isDefault(*cfg.ElasticsearchSettings.Password, model.ELASTICSEARCH_SETTINGS_DEFAULT_PASSWORD),
"enable_indexing": *cfg.ElasticsearchSettings.EnableIndexing,
"enable_searching": *cfg.ElasticsearchSettings.EnableSearching,
"enable_autocomplete": *cfg.ElasticsearchSettings.EnableAutocomplete,
"sniff": *cfg.ElasticsearchSettings.Sniff,
"post_index_replicas": *cfg.ElasticsearchSettings.PostIndexReplicas,
"post_index_shards": *cfg.ElasticsearchSettings.PostIndexShards,
"channel_index_replicas": *cfg.ElasticsearchSettings.ChannelIndexReplicas,
"channel_index_shards": *cfg.ElasticsearchSettings.ChannelIndexShards,
"user_index_replicas": *cfg.ElasticsearchSettings.UserIndexReplicas,
"user_index_shards": *cfg.ElasticsearchSettings.UserIndexShards,
"isdefault_index_prefix": isDefault(*cfg.ElasticsearchSettings.IndexPrefix, model.ELASTICSEARCH_SETTINGS_DEFAULT_INDEX_PREFIX),
"live_indexing_batch_size": *cfg.ElasticsearchSettings.LiveIndexingBatchSize,
"bulk_indexing_time_window_seconds": *cfg.ElasticsearchSettings.BulkIndexingTimeWindowSeconds,

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

@@ -830,6 +830,15 @@ func (a *App) LeaveTeam(team *model.Team, user *model.User, requestorId string)
})
}
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
if err := a.indexUser(user); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", user.Id), mlog.Err(err))
}
})
}
if uua := <-a.Srv.Store.User().UpdateUpdateAt(user.Id); uua.Err != nil {
return uua.Err
}

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

@@ -31,6 +31,7 @@ import (
"github.com/mattermost/mattermost-server/model"
"github.com/mattermost/mattermost-server/plugin"
"github.com/mattermost/mattermost-server/services/mfa"
"github.com/mattermost/mattermost-server/store"
"github.com/mattermost/mattermost-server/utils"
"github.com/mattermost/mattermost-server/utils/fileutils"
)
@@ -186,6 +187,40 @@ func (a *App) IsFirstUserAccount() bool {
return false
}
// indexUser fetches the required information to index a user from the database and
// calls the elasticsearch interface method
func (a *App) indexUser(user *model.User) *model.AppError {
userTeams := <-a.Srv.Store.Team().GetTeamsByUserId(user.Id)
if userTeams.Err != nil {
return userTeams.Err
}
userTeamsIds := []string{}
for _, team := range userTeams.Data.([]*model.Team) {
userTeamsIds = append(userTeamsIds, team.Id)
}
userChannelMembers := <-a.Srv.Store.Channel().GetAllChannelMembersForUser(user.Id, false, true)
if userChannelMembers.Err != nil {
return userChannelMembers.Err
}
userChannelsIds := []string{}
for channelId := range userChannelMembers.Data.(map[string]string) {
userChannelsIds = append(userChannelsIds, channelId)
}
return a.Elasticsearch.IndexUser(user, userTeamsIds, userChannelsIds)
}
func (a *App) indexUserFromId(userId string) *model.AppError {
user, err := a.GetUser(userId)
if err != nil {
return err
}
return a.indexUser(user)
}
// CreateUser creates a user and sets several fields of the returned User struct to
// their zero values.
func (a *App) CreateUser(user *model.User) (*model.User, *model.AppError) {
@@ -230,6 +265,15 @@ func (a *App) CreateUser(user *model.User) (*model.User, *model.AppError) {
})
}
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
if err := a.indexUser(user); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", user.Id), mlog.Err(err))
}
})
}
return ruser, nil
}
@@ -1076,6 +1120,15 @@ func (a *App) UpdateUser(user *model.User, sendNotifications bool) (*model.User,
a.InvalidateCacheForUser(user.Id)
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
if err := a.indexUser(user); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", user.Id), mlog.Err(err))
}
})
}
return rusers[0], nil
}
@@ -1413,6 +1466,15 @@ func (a *App) PermanentDeleteUser(user *model.User) *model.AppError {
mlog.Warn(fmt.Sprintf("Permanently deleted account %v id=%v", user.Email, user.Id), mlog.String("user_id", user.Id))
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
if err := a.Elasticsearch.DeleteUser(user); err != nil {
mlog.Error("Encountered error deleting user", mlog.String("user_id", user.Id), mlog.Err(err))
}
})
}
return nil
}
@@ -1596,7 +1658,21 @@ func (a *App) SearchUsersNotInChannel(teamId string, channelId string, term stri
}
func (a *App) SearchUsersInTeam(teamId string, term string, options *model.UserSearchOptions) ([]*model.User, *model.AppError) {
result := <-a.Srv.Store.User().Search(teamId, term, options)
var result store.StoreResult
esInterface := a.Elasticsearch
license := a.License()
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableAutocomplete && license != nil && *license.Features.Elasticsearch {
usersIds, err := a.Elasticsearch.SearchUsersInTeam(teamId, term, options)
if err != nil {
return nil, err
}
result = <-a.Srv.Store.User().GetProfileByIds(usersIds, false)
} else {
result = <-a.Srv.Store.User().Search(teamId, term, options)
}
if result.Err != nil {
return nil, result.Err
}
@@ -1638,8 +1714,21 @@ func (a *App) SearchUsersWithoutTeam(term string, options *model.UserSearchOptio
}
func (a *App) AutocompleteUsersInChannel(teamId string, channelId string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError) {
uchan := a.Srv.Store.User().SearchInChannel(channelId, term, options)
nuchan := a.Srv.Store.User().SearchNotInChannel(teamId, channelId, term, options)
var uchan, nuchan store.StoreChannel
esInterface := a.Elasticsearch
license := a.License()
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableAutocomplete && license != nil && *license.Features.Elasticsearch {
uchanIds, nuchanIds, err := a.Elasticsearch.SearchUsersInChannel(teamId, channelId, term, options)
if err != nil {
return nil, err
}
uchan = a.Srv.Store.User().GetProfileByIds(uchanIds, false)
nuchan = a.Srv.Store.User().GetProfileByIds(nuchanIds, false)
} else {
uchan = a.Srv.Store.User().SearchInChannel(channelId, term, options)
nuchan = a.Srv.Store.User().SearchNotInChannel(teamId, channelId, term, options)
}
autocomplete := &model.UserAutocompleteInChannel{}
@@ -1672,8 +1761,21 @@ func (a *App) AutocompleteUsersInChannel(teamId string, channelId string, term s
func (a *App) AutocompleteUsersInTeam(teamId string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInTeam, *model.AppError) {
autocomplete := &model.UserAutocompleteInTeam{}
var result store.StoreResult
esInterface := a.Elasticsearch
license := a.License()
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableAutocomplete && license != nil && *license.Features.Elasticsearch {
usersIds, err := a.Elasticsearch.SearchUsersInTeam(teamId, term, options)
if err != nil {
return nil, err
}
result = <-a.Srv.Store.User().GetProfileByIds(usersIds, false)
} else {
result = <-a.Srv.Store.User().Search(teamId, term, options)
}
result := <-a.Srv.Store.User().Search(teamId, term, options)
if result.Err != nil {
return nil, result.Err
}
@@ -1730,6 +1832,15 @@ func (a *App) UpdateOAuthUserAttrs(userData io.Reader, user *model.User, provide
user = result.Data.([2]*model.User)[0]
a.InvalidateCacheForUser(user.Id)
esInterface := a.Elasticsearch
if esInterface != nil && *a.Config().ElasticsearchSettings.EnableIndexing {
a.Srv.Go(func() {
if err := a.indexUser(user); err != nil {
mlog.Error("Encountered error indexing user", mlog.String("user_id", user.Id), mlog.Err(err))
}
})
}
}
return nil