[MM-18946] [MM-26721] [MM-6842] Cross team search+private channel autocomplete (#18468)
* Show private channels in autocomplete This is supported in all Engines: MySQL, Postgres, Bleve, Elasticsearch. https://mattermost.atlassian.net/browse/MM-18496 ```release-note Private channels will now appear in channel autocomplete. If you are using Bleve or ElasticSearch, you will have to reindex the channels again to populate them with the new attributes. ``` A large chunk of this work has been based on the earlier effort at https://github.com/mattermost/mattermost-server/pull/17804. Full credit goes to https://github.com/arvinDarmawan. * Add comment ```release-note NONE ``` * Adding more tests ```release-note NONE ``` * fix more tests ```release-note NONE ``` * tmp ```release-note NONE ``` * more fixes ```release-note NONE ``` * add tests ```release-note NONE ``` * Add review comments from previous PR ```release-note NONE ``` * Add API to return all channels from all team ```release-note NONE ``` * Added support for bleve and ES ```release-note NONE ``` * Streaming response for GetAllChannels ```release-note NONE ``` * Fix tests ```release-note NONE ``` * Trigger CI ```release-note NONE ``` * fix tests ```release-note NONE ``` * Addressing review comments ```release-note NONE ``` * Fix lint ```release-note NONE ``` * Removing flaky test ```release-note NONE ``` * Address comments ```release-note NONE ``` * Trigger CI ```release-note NONE ``` * Added /users/<userid>/channel_members endpoint ```release-note NONE ``` * Minor edit ```release-note NONE ``` * Improve embedding ```release-note NONE ``` * Fix lint error ```release-note NONE ``` Co-authored-by: Mattermod <mattermod@users.noreply.github.com>
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
971af6935c
Коммит
e24f22745e
@@ -402,8 +402,9 @@ type AppIface interface {
|
||||
AttachSessionCookies(c *request.Context, w http.ResponseWriter, r *http.Request)
|
||||
AuthenticateUserForLogin(c *request.Context, id, loginId, password, mfaToken, cwsToken string, ldapOnly bool) (user *model.User, err *model.AppError)
|
||||
AuthorizeOAuthUser(w http.ResponseWriter, r *http.Request, service, code, state, redirectURI string) (io.ReadCloser, string, map[string]string, *model.User, *model.AppError)
|
||||
AutocompleteChannels(teamID string, term string) (model.ChannelList, *model.AppError)
|
||||
AutocompleteChannels(userID, term string) (model.ChannelListWithTeamData, *model.AppError)
|
||||
AutocompleteChannelsForSearch(teamID string, userID string, term string) (model.ChannelList, *model.AppError)
|
||||
AutocompleteChannelsForTeam(teamID, userID, term string) (model.ChannelList, *model.AppError)
|
||||
AutocompleteUsersInChannel(teamID string, channelID string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError)
|
||||
AutocompleteUsersInTeam(teamID string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInTeam, *model.AppError)
|
||||
BroadcastStatus(status *model.Status)
|
||||
@@ -564,9 +565,10 @@ type AppIface interface {
|
||||
GetChannelMemberCount(channelID string) (int64, *model.AppError)
|
||||
GetChannelMembersByIds(channelID string, userIDs []string) (model.ChannelMembers, *model.AppError)
|
||||
GetChannelMembersForUser(teamID string, userID string) (model.ChannelMembers, *model.AppError)
|
||||
GetChannelMembersForUserWithPagination(teamID, userID string, page, perPage int) ([]*model.ChannelMember, *model.AppError)
|
||||
GetChannelMembersForUserWithPagination(userID string, page, perPage int) ([]*model.ChannelMember, *model.AppError)
|
||||
GetChannelMembersPage(channelID string, page, perPage int) (model.ChannelMembers, *model.AppError)
|
||||
GetChannelMembersTimezones(channelID string) ([]string, *model.AppError)
|
||||
GetChannelMembersWithTeamDataForUserWithPagination(userID string, page, perPage int) (model.ChannelMembersWithTeamData, *model.AppError)
|
||||
GetChannelPinnedPostCount(channelID string) (int64, *model.AppError)
|
||||
GetChannelPoliciesForUser(userID string, offset, limit int) (*model.RetentionPolicyForChannelList, *model.AppError)
|
||||
GetChannelUnread(channelID, userID string) (*model.ChannelUnread, *model.AppError)
|
||||
@@ -574,7 +576,8 @@ type AppIface interface {
|
||||
GetChannelsForRetentionPolicy(policyID string, offset, limit int) (*model.ChannelsWithCount, *model.AppError)
|
||||
GetChannelsForScheme(scheme *model.Scheme, offset int, limit int) (model.ChannelList, *model.AppError)
|
||||
GetChannelsForSchemePage(scheme *model.Scheme, page int, perPage int) (model.ChannelList, *model.AppError)
|
||||
GetChannelsForUser(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, *model.AppError)
|
||||
GetChannelsForTeamForUser(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, *model.AppError)
|
||||
GetChannelsForUser(userID string, includeDeleted bool, lastDeleteAt, pageSize int, fromChannelID string) (model.ChannelList, *model.AppError)
|
||||
GetChannelsUserNotIn(teamID string, userID string, offset int, limit int) (model.ChannelList, *model.AppError)
|
||||
GetCloudSession(token string) (*model.Session, *model.AppError)
|
||||
GetClusterId() string
|
||||
|
||||
@@ -1759,7 +1759,7 @@ func (a *App) GetChannelByNameForTeamName(channelName, teamName string, includeD
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (a *App) GetChannelsForUser(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, *model.AppError) {
|
||||
func (a *App) GetChannelsForTeamForUser(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, *model.AppError) {
|
||||
list, err := a.Srv().Store.Channel().GetChannels(teamID, userID, includeDeleted, lastDeleteAt)
|
||||
if err != nil {
|
||||
var nfErr *store.ErrNotFound
|
||||
@@ -1774,6 +1774,21 @@ func (a *App) GetChannelsForUser(teamID string, userID string, includeDeleted bo
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (a *App) GetChannelsForUser(userID string, includeDeleted bool, lastDeleteAt, pageSize int, fromChannelID string) (model.ChannelList, *model.AppError) {
|
||||
list, err := a.Srv().Store.Channel().GetChannelsByUser(userID, includeDeleted, lastDeleteAt, pageSize, fromChannelID)
|
||||
if err != nil {
|
||||
var nfErr *store.ErrNotFound
|
||||
switch {
|
||||
case errors.As(err, &nfErr):
|
||||
return nil, model.NewAppError("GetChannelsForUser", "app.channel.get_channels.not_found.app_error", nil, nfErr.Error(), http.StatusNotFound)
|
||||
default:
|
||||
return nil, model.NewAppError("GetChannelsForUser", "app.channel.get_channels.get.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
|
||||
return list, nil
|
||||
}
|
||||
|
||||
func (a *App) GetAllChannels(page, perPage int, opts model.ChannelSearchOpts) (model.ChannelListWithTeamData, *model.AppError) {
|
||||
if opts.ExcludeDefaultChannels {
|
||||
opts.ExcludeChannelNames = a.DefaultChannelNames()
|
||||
@@ -1925,20 +1940,29 @@ func (a *App) GetChannelMembersForUser(teamID string, userID string) (model.Chan
|
||||
return channelMembers, nil
|
||||
}
|
||||
|
||||
func (a *App) GetChannelMembersForUserWithPagination(teamID, userID string, page, perPage int) ([]*model.ChannelMember, *model.AppError) {
|
||||
m, err := a.Srv().Store.Channel().GetMembersForUserWithPagination(teamID, userID, page, perPage)
|
||||
func (a *App) GetChannelMembersForUserWithPagination(userID string, page, perPage int) ([]*model.ChannelMember, *model.AppError) {
|
||||
m, err := a.Srv().Store.Channel().GetMembersForUserWithPagination(userID, page, perPage)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetChannelMembersForUserWithPagination", "app.channel.get_members.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
members := make([]*model.ChannelMember, 0)
|
||||
members := make([]*model.ChannelMember, 0, len(m))
|
||||
for _, member := range m {
|
||||
member := member
|
||||
members = append(members, &member)
|
||||
members = append(members, &member.ChannelMember)
|
||||
}
|
||||
return members, nil
|
||||
}
|
||||
|
||||
func (a *App) GetChannelMembersWithTeamDataForUserWithPagination(userID string, page, perPage int) (model.ChannelMembersWithTeamData, *model.AppError) {
|
||||
m, err := a.Srv().Store.Channel().GetMembersForUserWithPagination(userID, page, perPage)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("GetChannelMembersForUserWithPagination", "app.channel.get_members.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (a *App) GetChannelMemberCount(channelID string) (int64, *model.AppError) {
|
||||
count, err := a.Srv().Store.Channel().GetMemberCount(channelID, true)
|
||||
if err != nil {
|
||||
@@ -2689,11 +2713,23 @@ func (a *App) sendWebSocketPostUnreadEvent(channelUnread *model.ChannelUnreadAt,
|
||||
a.Publish(message)
|
||||
}
|
||||
|
||||
func (a *App) AutocompleteChannels(teamID string, term string) (model.ChannelList, *model.AppError) {
|
||||
func (a *App) AutocompleteChannels(userID, term string) (model.ChannelListWithTeamData, *model.AppError) {
|
||||
includeDeleted := *a.Config().TeamSettings.ExperimentalViewArchivedChannels
|
||||
term = strings.TrimSpace(term)
|
||||
|
||||
channelList, err := a.Srv().Store.Channel().AutocompleteInTeam(teamID, term, includeDeleted)
|
||||
channelList, err := a.Srv().Store.Channel().Autocomplete(userID, term, includeDeleted)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("AutocompleteChannels", "app.channel.search.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
return channelList, nil
|
||||
}
|
||||
|
||||
func (a *App) AutocompleteChannelsForTeam(teamID, userID, term string) (model.ChannelList, *model.AppError) {
|
||||
includeDeleted := *a.Config().TeamSettings.ExperimentalViewArchivedChannels
|
||||
term = strings.TrimSpace(term)
|
||||
|
||||
channelList, err := a.Srv().Store.Channel().AutocompleteInTeam(teamID, userID, term, includeDeleted)
|
||||
if err != nil {
|
||||
return nil, model.NewAppError("AutocompleteChannels", "app.channel.search.app_error", nil, err.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
@@ -996,19 +996,19 @@ func TestGetChannelsForUser(t *testing.T) {
|
||||
defer th.App.PermanentDeleteChannel(channel)
|
||||
defer th.TearDown()
|
||||
|
||||
channelList, err := th.App.GetChannelsForUser(th.BasicTeam.Id, th.BasicUser.Id, false, 0)
|
||||
channelList, err := th.App.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, false, 0)
|
||||
require.Nil(t, err)
|
||||
require.Len(t, channelList, 4)
|
||||
|
||||
th.App.DeleteChannel(th.Context, channel, th.BasicUser.Id)
|
||||
|
||||
// Now we get all the non-archived channels for the user
|
||||
channelList, err = th.App.GetChannelsForUser(th.BasicTeam.Id, th.BasicUser.Id, false, 0)
|
||||
channelList, err = th.App.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, false, 0)
|
||||
require.Nil(t, err)
|
||||
require.Len(t, channelList, 3)
|
||||
|
||||
// Now we get all the channels, even though are archived, for the user
|
||||
channelList, err = th.App.GetChannelsForUser(th.BasicTeam.Id, th.BasicUser.Id, true, 0)
|
||||
channelList, err = th.App.GetChannelsForTeamForUser(th.BasicTeam.Id, th.BasicUser.Id, true, 0)
|
||||
require.Nil(t, err)
|
||||
require.Len(t, channelList, 4)
|
||||
}
|
||||
|
||||
@@ -767,7 +767,7 @@ func (a *OpenTracingAppLayer) AuthorizeOAuthUser(w http.ResponseWriter, r *http.
|
||||
return resultVar0, resultVar1, resultVar2, resultVar3, resultVar4
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) AutocompleteChannels(teamID string, term string) (model.ChannelList, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) AutocompleteChannels(userID string, term string) (model.ChannelListWithTeamData, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AutocompleteChannels")
|
||||
|
||||
@@ -779,7 +779,7 @@ func (a *OpenTracingAppLayer) AutocompleteChannels(teamID string, term string) (
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.AutocompleteChannels(teamID, term)
|
||||
resultVar0, resultVar1 := a.app.AutocompleteChannels(userID, term)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
@@ -811,6 +811,28 @@ func (a *OpenTracingAppLayer) AutocompleteChannelsForSearch(teamID string, userI
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) AutocompleteChannelsForTeam(teamID string, userID string, term string) (model.ChannelList, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AutocompleteChannelsForTeam")
|
||||
|
||||
a.ctx = newCtx
|
||||
a.app.Srv().Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
a.app.Srv().Store.SetContext(origCtx)
|
||||
a.ctx = origCtx
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.AutocompleteChannelsForTeam(teamID, userID, term)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) AutocompleteUsersInChannel(teamID string, channelID string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AutocompleteUsersInChannel")
|
||||
@@ -4848,7 +4870,7 @@ func (a *OpenTracingAppLayer) GetChannelMembersForUser(teamID string, userID str
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetChannelMembersForUserWithPagination(teamID string, userID string, page int, perPage int) ([]*model.ChannelMember, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) GetChannelMembersForUserWithPagination(userID string, page int, perPage int) ([]*model.ChannelMember, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelMembersForUserWithPagination")
|
||||
|
||||
@@ -4860,7 +4882,7 @@ func (a *OpenTracingAppLayer) GetChannelMembersForUserWithPagination(teamID stri
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.GetChannelMembersForUserWithPagination(teamID, userID, page, perPage)
|
||||
resultVar0, resultVar1 := a.app.GetChannelMembersForUserWithPagination(userID, page, perPage)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
@@ -4914,6 +4936,28 @@ func (a *OpenTracingAppLayer) GetChannelMembersTimezones(channelID string) ([]st
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetChannelMembersWithTeamDataForUserWithPagination(userID string, page int, perPage int) (model.ChannelMembersWithTeamData, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelMembersWithTeamDataForUserWithPagination")
|
||||
|
||||
a.ctx = newCtx
|
||||
a.app.Srv().Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
a.app.Srv().Store.SetContext(origCtx)
|
||||
a.ctx = origCtx
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.GetChannelMembersWithTeamDataForUserWithPagination(userID, page, perPage)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetChannelModerationsForChannel(channel *model.Channel) ([]*model.ChannelModeration, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelModerationsForChannel")
|
||||
@@ -5090,7 +5134,29 @@ func (a *OpenTracingAppLayer) GetChannelsForSchemePage(scheme *model.Scheme, pag
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetChannelsForUser(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, *model.AppError) {
|
||||
func (a *OpenTracingAppLayer) GetChannelsForTeamForUser(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelsForTeamForUser")
|
||||
|
||||
a.ctx = newCtx
|
||||
a.app.Srv().Store.SetContext(newCtx)
|
||||
defer func() {
|
||||
a.app.Srv().Store.SetContext(origCtx)
|
||||
a.ctx = origCtx
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.GetChannelsForTeamForUser(teamID, userID, includeDeleted, lastDeleteAt)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
ext.Error.Set(span, true)
|
||||
}
|
||||
|
||||
return resultVar0, resultVar1
|
||||
}
|
||||
|
||||
func (a *OpenTracingAppLayer) GetChannelsForUser(userID string, includeDeleted bool, lastDeleteAt int, pageSize int, fromChannelID string) (model.ChannelList, *model.AppError) {
|
||||
origCtx := a.ctx
|
||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelsForUser")
|
||||
|
||||
@@ -5102,7 +5168,7 @@ func (a *OpenTracingAppLayer) GetChannelsForUser(teamID string, userID string, i
|
||||
}()
|
||||
|
||||
defer span.Finish()
|
||||
resultVar0, resultVar1 := a.app.GetChannelsForUser(teamID, userID, includeDeleted, lastDeleteAt)
|
||||
resultVar0, resultVar1 := a.app.GetChannelsForUser(userID, includeDeleted, lastDeleteAt, pageSize, fromChannelID)
|
||||
|
||||
if resultVar1 != nil {
|
||||
span.LogFields(spanlog.Error(resultVar1))
|
||||
|
||||
@@ -419,7 +419,7 @@ func (api *PluginAPI) GetChannelByNameForTeamName(teamName, channelName string,
|
||||
}
|
||||
|
||||
func (api *PluginAPI) GetChannelsForTeamForUser(teamID, userID string, includeDeleted bool) ([]*model.Channel, *model.AppError) {
|
||||
channels, err := api.app.GetChannelsForUser(teamID, userID, includeDeleted, 0)
|
||||
channels, err := api.app.GetChannelsForTeamForUser(teamID, userID, includeDeleted, 0)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -557,8 +557,10 @@ func (api *PluginAPI) GetChannelMembersByIds(channelID string, userIDs []string)
|
||||
return api.app.GetChannelMembersByIds(channelID, userIDs)
|
||||
}
|
||||
|
||||
func (api *PluginAPI) GetChannelMembersForUser(teamID, userID string, page, perPage int) ([]*model.ChannelMember, *model.AppError) {
|
||||
return api.app.GetChannelMembersForUserWithPagination(teamID, userID, page, perPage)
|
||||
func (api *PluginAPI) GetChannelMembersForUser(_, userID string, page, perPage int) ([]*model.ChannelMember, *model.AppError) {
|
||||
// The team ID parameter was never used in the SQL query.
|
||||
// But we keep this to maintain compatibility.
|
||||
return api.app.GetChannelMembersForUserWithPagination(userID, page, perPage)
|
||||
}
|
||||
|
||||
func (api *PluginAPI) UpdateChannelMemberRoles(channelID, userID, newRoles string) (*model.ChannelMember, *model.AppError) {
|
||||
|
||||
@@ -868,7 +868,7 @@ func (a *App) invalidateUserChannelMembersCaches(userID string) *model.AppError
|
||||
}
|
||||
|
||||
for _, team := range teamsForUser {
|
||||
channelsForUser, err := a.GetChannelsForUser(team.Id, userID, false, 0)
|
||||
channelsForUser, err := a.GetChannelsForTeamForUser(team.Id, userID, false, 0)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
Ссылка в новой задаче
Block a user