[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
108
api4/channel.go
108
api4/channel.go
@@ -35,6 +35,7 @@ func (api *API) InitChannel() {
|
|||||||
api.BaseRoutes.ChannelsForTeam.Handle("/autocomplete", api.APISessionRequired(autocompleteChannelsForTeam)).Methods("GET")
|
api.BaseRoutes.ChannelsForTeam.Handle("/autocomplete", api.APISessionRequired(autocompleteChannelsForTeam)).Methods("GET")
|
||||||
api.BaseRoutes.ChannelsForTeam.Handle("/search_autocomplete", api.APISessionRequired(autocompleteChannelsForTeamForSearch)).Methods("GET")
|
api.BaseRoutes.ChannelsForTeam.Handle("/search_autocomplete", api.APISessionRequired(autocompleteChannelsForTeamForSearch)).Methods("GET")
|
||||||
api.BaseRoutes.User.Handle("/teams/{team_id:[A-Za-z0-9]+}/channels", api.APISessionRequired(getChannelsForTeamForUser)).Methods("GET")
|
api.BaseRoutes.User.Handle("/teams/{team_id:[A-Za-z0-9]+}/channels", api.APISessionRequired(getChannelsForTeamForUser)).Methods("GET")
|
||||||
|
api.BaseRoutes.User.Handle("/channels", api.APISessionRequired(getChannelsForUser)).Methods("GET")
|
||||||
|
|
||||||
api.BaseRoutes.ChannelCategories.Handle("", api.APISessionRequired(getCategoriesForTeamForUser)).Methods("GET")
|
api.BaseRoutes.ChannelCategories.Handle("", api.APISessionRequired(getCategoriesForTeamForUser)).Methods("GET")
|
||||||
api.BaseRoutes.ChannelCategories.Handle("", api.APISessionRequired(createCategoryForTeamForUser)).Methods("POST")
|
api.BaseRoutes.ChannelCategories.Handle("", api.APISessionRequired(createCategoryForTeamForUser)).Methods("POST")
|
||||||
@@ -66,7 +67,7 @@ func (api *API) InitChannel() {
|
|||||||
api.BaseRoutes.ChannelMembers.Handle("", api.APISessionRequired(getChannelMembers)).Methods("GET")
|
api.BaseRoutes.ChannelMembers.Handle("", api.APISessionRequired(getChannelMembers)).Methods("GET")
|
||||||
api.BaseRoutes.ChannelMembers.Handle("/ids", api.APISessionRequired(getChannelMembersByIds)).Methods("POST")
|
api.BaseRoutes.ChannelMembers.Handle("/ids", api.APISessionRequired(getChannelMembersByIds)).Methods("POST")
|
||||||
api.BaseRoutes.ChannelMembers.Handle("", api.APISessionRequired(addChannelMember)).Methods("POST")
|
api.BaseRoutes.ChannelMembers.Handle("", api.APISessionRequired(addChannelMember)).Methods("POST")
|
||||||
api.BaseRoutes.ChannelMembersForUser.Handle("", api.APISessionRequired(getChannelMembersForUser)).Methods("GET")
|
api.BaseRoutes.ChannelMembersForUser.Handle("", api.APISessionRequired(getChannelMembersForTeamForUser)).Methods("GET")
|
||||||
api.BaseRoutes.ChannelMember.Handle("", api.APISessionRequired(getChannelMember)).Methods("GET")
|
api.BaseRoutes.ChannelMember.Handle("", api.APISessionRequired(getChannelMember)).Methods("GET")
|
||||||
api.BaseRoutes.ChannelMember.Handle("", api.APISessionRequired(removeChannelMember)).Methods("DELETE")
|
api.BaseRoutes.ChannelMember.Handle("", api.APISessionRequired(removeChannelMember)).Methods("DELETE")
|
||||||
api.BaseRoutes.ChannelMember.Handle("/roles", api.APISessionRequired(updateChannelMemberRoles)).Methods("PUT")
|
api.BaseRoutes.ChannelMember.Handle("/roles", api.APISessionRequired(updateChannelMemberRoles)).Methods("PUT")
|
||||||
@@ -877,7 +878,7 @@ func getChannelsForTeamForUser(c *Context, w http.ResponseWriter, r *http.Reques
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
channels, err := c.App.GetChannelsForUser(c.Params.TeamId, c.Params.UserId, c.Params.IncludeDeleted, lastDeleteAt)
|
channels, err := c.App.GetChannelsForTeamForUser(c.Params.TeamId, c.Params.UserId, c.Params.IncludeDeleted, lastDeleteAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
return
|
return
|
||||||
@@ -899,6 +900,79 @@ func getChannelsForTeamForUser(c *Context, w http.ResponseWriter, r *http.Reques
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getChannelsForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireUserId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionToUser(*c.AppContext.Session(), c.Params.UserId) {
|
||||||
|
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
query := r.URL.Query()
|
||||||
|
lastDeleteAt, nErr := strconv.Atoi(query.Get("last_delete_at"))
|
||||||
|
if nErr != nil {
|
||||||
|
lastDeleteAt = 0
|
||||||
|
}
|
||||||
|
if lastDeleteAt < 0 {
|
||||||
|
c.SetInvalidURLParam("last_delete_at")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
pageSize := 100
|
||||||
|
fromChannelID := ""
|
||||||
|
// We have to write `[` and `]` separately because we want to stream the response.
|
||||||
|
// The internal API is paginated, but the client always needs to get the full data.
|
||||||
|
// Therefore, to avoid forcing the client to go through all the pages,
|
||||||
|
// we stream the full data from server side itself.
|
||||||
|
//
|
||||||
|
// Note that this means if an error occurs in mid-stream, the response won't be
|
||||||
|
// fully JSON.
|
||||||
|
w.Write([]byte(`[`))
|
||||||
|
enc := json.NewEncoder(w)
|
||||||
|
for {
|
||||||
|
channels, err := c.App.GetChannelsForUser(c.Params.UserId, c.Params.IncludeDeleted, lastDeleteAt, pageSize, fromChannelID)
|
||||||
|
if err != nil {
|
||||||
|
// If the page size was a perfect multiple of the total number of results,
|
||||||
|
// then the last query will always return zero results.
|
||||||
|
if fromChannelID != "" && err.Id == "app.channel.get_channels.not_found.app_error" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = c.App.FillInChannelsProps(channels)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
// intermediary comma between sets
|
||||||
|
if fromChannelID != "" {
|
||||||
|
w.Write([]byte(`,`))
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, ch := range channels {
|
||||||
|
if err := enc.Encode(ch); err != nil {
|
||||||
|
mlog.Warn("Error while writing response", mlog.Err(err))
|
||||||
|
}
|
||||||
|
if i < len(channels)-1 {
|
||||||
|
w.Write([]byte(`,`))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(channels) < pageSize {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
fromChannelID = channels[len(channels)-1].Id
|
||||||
|
}
|
||||||
|
w.Write([]byte(`]`))
|
||||||
|
}
|
||||||
|
|
||||||
func autocompleteChannelsForTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
func autocompleteChannelsForTeam(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
c.RequireTeamId()
|
c.RequireTeamId()
|
||||||
if c.Err != nil {
|
if c.Err != nil {
|
||||||
@@ -912,7 +986,7 @@ func autocompleteChannelsForTeam(c *Context, w http.ResponseWriter, r *http.Requ
|
|||||||
|
|
||||||
name := r.URL.Query().Get("name")
|
name := r.URL.Query().Get("name")
|
||||||
|
|
||||||
channels, err := c.App.AutocompleteChannels(c.Params.TeamId, name)
|
channels, err := c.App.AutocompleteChannelsForTeam(c.Params.TeamId, c.AppContext.Session().UserId, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
c.Err = err
|
c.Err = err
|
||||||
return
|
return
|
||||||
@@ -1029,6 +1103,31 @@ func searchAllChannels(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
c.SetInvalidParam("channel_search")
|
c.SetInvalidParam("channel_search")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fromSysConsole := true
|
||||||
|
if val := r.URL.Query().Get("system_console"); val != "" {
|
||||||
|
fromSysConsole, err = strconv.ParseBool(val)
|
||||||
|
if err != nil {
|
||||||
|
c.SetInvalidParam("system_console")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if !fromSysConsole {
|
||||||
|
// If the request is not coming from system_console, only show the user level channels
|
||||||
|
// from all teams.
|
||||||
|
channels, err := c.App.AutocompleteChannels(c.AppContext.Session().UserId, props.Term)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewEncoder(w).Encode(channels); err != nil {
|
||||||
|
mlog.Warn("Error while writing response", mlog.Err(err))
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
// Only system managers may use the ExcludePolicyConstrained field
|
// Only system managers may use the ExcludePolicyConstrained field
|
||||||
if props.ExcludePolicyConstrained && !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleReadComplianceDataRetentionPolicy) {
|
if props.ExcludePolicyConstrained && !c.App.SessionHasPermissionTo(*c.AppContext.Session(), model.PermissionSysconsoleReadComplianceDataRetentionPolicy) {
|
||||||
c.SetPermissionError(model.PermissionSysconsoleReadComplianceDataRetentionPolicy)
|
c.SetPermissionError(model.PermissionSysconsoleReadComplianceDataRetentionPolicy)
|
||||||
@@ -1039,6 +1138,7 @@ func searchAllChannels(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
c.SetPermissionError(model.PermissionSysconsoleReadUserManagementChannels)
|
c.SetPermissionError(model.PermissionSysconsoleReadUserManagementChannels)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
includeDeleted, _ := strconv.ParseBool(r.URL.Query().Get("include_deleted"))
|
includeDeleted, _ := strconv.ParseBool(r.URL.Query().Get("include_deleted"))
|
||||||
includeDeleted = includeDeleted || props.IncludeDeleted
|
includeDeleted = includeDeleted || props.IncludeDeleted
|
||||||
|
|
||||||
@@ -1297,7 +1397,7 @@ func getChannelMember(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getChannelMembersForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
func getChannelMembersForTeamForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
c.RequireUserId().RequireTeamId()
|
c.RequireUserId().RequireTeamId()
|
||||||
if c.Err != nil {
|
if c.Err != nil {
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ func updateCategoriesForTeamForUser(c *Context, w http.ResponseWriter, r *http.R
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validateSidebarCategory(c *Context, teamId, userId string, category *model.SidebarCategoryWithChannels) *model.AppError {
|
func validateSidebarCategory(c *Context, teamId, userId string, category *model.SidebarCategoryWithChannels) *model.AppError {
|
||||||
channels, err := c.App.GetChannelsForUser(teamId, userId, true, 0)
|
channels, err := c.App.GetChannelsForTeamForUser(teamId, userId, true, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.NewAppError("validateSidebarCategory", "api.invalid_channel", nil, err.Error(), http.StatusBadRequest)
|
return model.NewAppError("validateSidebarCategory", "api.invalid_channel", nil, err.Error(), http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
@@ -221,7 +221,7 @@ func validateSidebarCategory(c *Context, teamId, userId string, category *model.
|
|||||||
}
|
}
|
||||||
|
|
||||||
func validateSidebarCategories(c *Context, teamId, userId string, categories []*model.SidebarCategoryWithChannels) *model.AppError {
|
func validateSidebarCategories(c *Context, teamId, userId string, categories []*model.SidebarCategoryWithChannels) *model.AppError {
|
||||||
channels, err := c.App.GetChannelsForUser(teamId, userId, true, 0)
|
channels, err := c.App.GetChannelsForTeamForUser(teamId, userId, true, 0)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return model.NewAppError("validateSidebarCategory", "api.invalid_channel", nil, err.Error(), http.StatusBadRequest)
|
return model.NewAppError("validateSidebarCategory", "api.invalid_channel", nil, err.Error(), http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1034,6 +1034,58 @@ func TestGetChannelsForTeamForUser(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetChannelsForUser(t *testing.T) {
|
||||||
|
th := Setup(t).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
client := th.Client
|
||||||
|
|
||||||
|
// Adding another team with more channels (public and private)
|
||||||
|
myTeam := th.CreateTeam()
|
||||||
|
ch1 := th.CreateChannelWithClientAndTeam(client, model.ChannelTypeOpen, myTeam.Id)
|
||||||
|
ch2 := th.CreateChannelWithClientAndTeam(client, model.ChannelTypePrivate, myTeam.Id)
|
||||||
|
th.LinkUserToTeam(th.BasicUser, myTeam)
|
||||||
|
th.App.AddUserToChannel(th.BasicUser, ch1, false)
|
||||||
|
th.App.AddUserToChannel(th.BasicUser, ch2, false)
|
||||||
|
|
||||||
|
channels, _, err := client.GetChannelsForUserWithLastDeleteAt(th.BasicUser.Id, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
numPrivate := 0
|
||||||
|
numPublic := 0
|
||||||
|
numOffTopic := 0
|
||||||
|
numTownSquare := 0
|
||||||
|
for _, ch := range channels {
|
||||||
|
if ch.Type == model.ChannelTypeOpen {
|
||||||
|
numPublic++
|
||||||
|
} else if ch.Type == model.ChannelTypePrivate {
|
||||||
|
numPrivate++
|
||||||
|
}
|
||||||
|
|
||||||
|
if ch.DisplayName == "Off-Topic" {
|
||||||
|
numOffTopic++
|
||||||
|
} else if ch.DisplayName == "Town Square" {
|
||||||
|
numTownSquare++
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert.Len(t, channels, 9)
|
||||||
|
assert.Equal(t, 2, numPrivate)
|
||||||
|
assert.Equal(t, 7, numPublic)
|
||||||
|
assert.Equal(t, 2, numOffTopic)
|
||||||
|
assert.Equal(t, 2, numTownSquare)
|
||||||
|
|
||||||
|
// Creating some more channels to be exactly 100 to test page size boundaries.
|
||||||
|
for i := 0; i < 91; i++ {
|
||||||
|
ch1 = th.CreateChannelWithClientAndTeam(client, model.ChannelTypeOpen, myTeam.Id)
|
||||||
|
th.App.AddUserToChannel(th.BasicUser, ch1, false)
|
||||||
|
}
|
||||||
|
|
||||||
|
channels, _, err = client.GetChannelsForUserWithLastDeleteAt(th.BasicUser.Id, 0)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, channels, 100)
|
||||||
|
}
|
||||||
|
|
||||||
func TestGetAllChannels(t *testing.T) {
|
func TestGetAllChannels(t *testing.T) {
|
||||||
th := Setup(t).InitBasic()
|
th := Setup(t).InitBasic()
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
@@ -1383,6 +1435,16 @@ func TestSearchAllChannels(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
team := th.CreateTeam()
|
team := th.CreateTeam()
|
||||||
|
privateChannel2, _, err := th.SystemAdminClient.CreateChannel(&model.Channel{
|
||||||
|
DisplayName: "dn_private2",
|
||||||
|
Name: "private2",
|
||||||
|
Type: model.ChannelTypePrivate,
|
||||||
|
TeamId: team.Id,
|
||||||
|
})
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.LinkUserToTeam(th.SystemAdminUser, team)
|
||||||
|
th.LinkUserToTeam(th.SystemAdminUser, th.BasicTeam)
|
||||||
|
|
||||||
groupConstrainedChannel, _, err := th.SystemAdminClient.CreateChannel(&model.Channel{
|
groupConstrainedChannel, _, err := th.SystemAdminClient.CreateChannel(&model.Channel{
|
||||||
DisplayName: "SearchAllChannels-groupConstrained-1",
|
DisplayName: "SearchAllChannels-groupConstrained-1",
|
||||||
Name: "groupconstrained1",
|
Name: "groupconstrained1",
|
||||||
@@ -1450,7 +1512,7 @@ func TestSearchAllChannels(t *testing.T) {
|
|||||||
{
|
{
|
||||||
"Search with private channel filter",
|
"Search with private channel filter",
|
||||||
&model.ChannelSearch{Private: true},
|
&model.ChannelSearch{Private: true},
|
||||||
[]string{th.BasicPrivateChannel.Id, th.BasicPrivateChannel2.Id, privateChannel.Id, groupConstrainedChannel.Id},
|
[]string{th.BasicPrivateChannel.Id, privateChannel2.Id, th.BasicPrivateChannel2.Id, privateChannel.Id, groupConstrainedChannel.Id},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Search with public channel filter",
|
"Search with public channel filter",
|
||||||
@@ -1517,6 +1579,14 @@ func TestSearchAllChannels(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
userChannels, _, err := th.SystemAdminClient.SearchAllChannelsForUser("private")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, userChannels, 2)
|
||||||
|
|
||||||
|
userChannels, _, err = th.SystemAdminClient.SearchAllChannelsForUser("FOOBARDISPLAYNAME")
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Len(t, userChannels, 1)
|
||||||
|
|
||||||
// Searching with no terms returns all default channels
|
// Searching with no terms returns all default channels
|
||||||
allChannels, _, err := th.SystemAdminClient.SearchAllChannels(&model.ChannelSearch{Term: ""})
|
allChannels, _, err := th.SystemAdminClient.SearchAllChannels(&model.ChannelSearch{Term: ""})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@@ -3238,7 +3308,7 @@ func TestAutocompleteChannels(t *testing.T) {
|
|||||||
th := Setup(t).InitBasic()
|
th := Setup(t).InitBasic()
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|
||||||
// A private channel to make sure private channels are not used
|
// A private channel to make sure private channels are used.
|
||||||
ptown, _, _ := th.Client.CreateChannel(&model.Channel{
|
ptown, _, _ := th.Client.CreateChannel(&model.Channel{
|
||||||
DisplayName: "Town",
|
DisplayName: "Town",
|
||||||
Name: "town",
|
Name: "town",
|
||||||
@@ -3267,8 +3337,8 @@ func TestAutocompleteChannels(t *testing.T) {
|
|||||||
"Basic town-square",
|
"Basic town-square",
|
||||||
th.BasicTeam.Id,
|
th.BasicTeam.Id,
|
||||||
"town",
|
"town",
|
||||||
[]string{"town-square"},
|
[]string{"town-square", "town"},
|
||||||
[]string{"off-topic", "town", "tower"},
|
[]string{"off-topic", "tower"},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Basic off-topic",
|
"Basic off-topic",
|
||||||
@@ -3281,8 +3351,8 @@ func TestAutocompleteChannels(t *testing.T) {
|
|||||||
"Basic town square and off topic",
|
"Basic town square and off topic",
|
||||||
th.BasicTeam.Id,
|
th.BasicTeam.Id,
|
||||||
"tow",
|
"tow",
|
||||||
[]string{"town-square", "tower"},
|
[]string{"town-square", "tower", "town"},
|
||||||
[]string{"off-topic", "town"},
|
[]string{"off-topic"},
|
||||||
},
|
},
|
||||||
} {
|
} {
|
||||||
t.Run(tc.description, func(t *testing.T) {
|
t.Run(tc.description, func(t *testing.T) {
|
||||||
|
|||||||
23
api4/user.go
23
api4/user.go
@@ -90,6 +90,7 @@ func (api *API) InitUser() {
|
|||||||
api.BaseRoutes.Users.Handle("/migrate_auth/saml", api.APISessionRequired(migrateAuthToSaml)).Methods("POST")
|
api.BaseRoutes.Users.Handle("/migrate_auth/saml", api.APISessionRequired(migrateAuthToSaml)).Methods("POST")
|
||||||
|
|
||||||
api.BaseRoutes.User.Handle("/uploads", api.APISessionRequired(getUploadsForUser)).Methods("GET")
|
api.BaseRoutes.User.Handle("/uploads", api.APISessionRequired(getUploadsForUser)).Methods("GET")
|
||||||
|
api.BaseRoutes.User.Handle("/channel_members", api.APISessionRequired(getChannelMembersForUser)).Methods("GET")
|
||||||
|
|
||||||
api.BaseRoutes.UserThreads.Handle("", api.APISessionRequired(getThreadsForUser)).Methods("GET")
|
api.BaseRoutes.UserThreads.Handle("", api.APISessionRequired(getThreadsForUser)).Methods("GET")
|
||||||
api.BaseRoutes.UserThreads.Handle("/read", api.APISessionRequired(updateReadStateAllThreadsByUser)).Methods("PUT")
|
api.BaseRoutes.UserThreads.Handle("/read", api.APISessionRequired(updateReadStateAllThreadsByUser)).Methods("PUT")
|
||||||
@@ -2800,6 +2801,28 @@ func getUploadsForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Write(js)
|
w.Write(js)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getChannelMembersForUser(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
|
c.RequireUserId()
|
||||||
|
if c.Err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if !c.App.SessionHasPermissionToUser(*c.AppContext.Session(), c.Params.UserId) {
|
||||||
|
c.SetPermissionError(model.PermissionEditOtherUsers)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
members, err := c.App.GetChannelMembersWithTeamDataForUserWithPagination(c.Params.UserId, c.Params.Page, c.Params.PerPage)
|
||||||
|
if err != nil {
|
||||||
|
c.Err = err
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewEncoder(w).Encode(members); err != nil {
|
||||||
|
mlog.Warn("Error while writing response", mlog.Err(err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func migrateAuthToLDAP(c *Context, w http.ResponseWriter, r *http.Request) {
|
func migrateAuthToLDAP(c *Context, w http.ResponseWriter, r *http.Request) {
|
||||||
props := model.StringInterfaceFromJSON(r.Body)
|
props := model.StringInterfaceFromJSON(r.Body)
|
||||||
from, ok := props["from"].(string)
|
from, ok := props["from"].(string)
|
||||||
|
|||||||
@@ -5443,6 +5443,19 @@ func TestConvertUserToBot(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetChannelMembersWithTeamData(t *testing.T) {
|
||||||
|
th := Setup(t).InitBasic()
|
||||||
|
defer th.TearDown()
|
||||||
|
|
||||||
|
channels, resp, err := th.Client.GetChannelMembersWithTeamData(th.BasicUser.Id, 0, 5)
|
||||||
|
require.NoError(t, err)
|
||||||
|
CheckOKStatus(t, resp)
|
||||||
|
assert.Len(t, channels, 5)
|
||||||
|
for _, ch := range channels {
|
||||||
|
assert.Equal(t, th.BasicTeam.DisplayName, ch.TeamDisplayName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMigrateAuthToLDAP(t *testing.T) {
|
func TestMigrateAuthToLDAP(t *testing.T) {
|
||||||
th := Setup(t).InitBasic()
|
th := Setup(t).InitBasic()
|
||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|||||||
@@ -402,8 +402,9 @@ type AppIface interface {
|
|||||||
AttachSessionCookies(c *request.Context, w http.ResponseWriter, r *http.Request)
|
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)
|
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)
|
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)
|
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)
|
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)
|
AutocompleteUsersInTeam(teamID string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInTeam, *model.AppError)
|
||||||
BroadcastStatus(status *model.Status)
|
BroadcastStatus(status *model.Status)
|
||||||
@@ -564,9 +565,10 @@ type AppIface interface {
|
|||||||
GetChannelMemberCount(channelID string) (int64, *model.AppError)
|
GetChannelMemberCount(channelID string) (int64, *model.AppError)
|
||||||
GetChannelMembersByIds(channelID string, userIDs []string) (model.ChannelMembers, *model.AppError)
|
GetChannelMembersByIds(channelID string, userIDs []string) (model.ChannelMembers, *model.AppError)
|
||||||
GetChannelMembersForUser(teamID string, userID 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)
|
GetChannelMembersPage(channelID string, page, perPage int) (model.ChannelMembers, *model.AppError)
|
||||||
GetChannelMembersTimezones(channelID string) ([]string, *model.AppError)
|
GetChannelMembersTimezones(channelID string) ([]string, *model.AppError)
|
||||||
|
GetChannelMembersWithTeamDataForUserWithPagination(userID string, page, perPage int) (model.ChannelMembersWithTeamData, *model.AppError)
|
||||||
GetChannelPinnedPostCount(channelID string) (int64, *model.AppError)
|
GetChannelPinnedPostCount(channelID string) (int64, *model.AppError)
|
||||||
GetChannelPoliciesForUser(userID string, offset, limit int) (*model.RetentionPolicyForChannelList, *model.AppError)
|
GetChannelPoliciesForUser(userID string, offset, limit int) (*model.RetentionPolicyForChannelList, *model.AppError)
|
||||||
GetChannelUnread(channelID, userID string) (*model.ChannelUnread, *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)
|
GetChannelsForRetentionPolicy(policyID string, offset, limit int) (*model.ChannelsWithCount, *model.AppError)
|
||||||
GetChannelsForScheme(scheme *model.Scheme, offset int, limit int) (model.ChannelList, *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)
|
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)
|
GetChannelsUserNotIn(teamID string, userID string, offset int, limit int) (model.ChannelList, *model.AppError)
|
||||||
GetCloudSession(token string) (*model.Session, *model.AppError)
|
GetCloudSession(token string) (*model.Session, *model.AppError)
|
||||||
GetClusterId() string
|
GetClusterId() string
|
||||||
|
|||||||
@@ -1759,7 +1759,7 @@ func (a *App) GetChannelByNameForTeamName(channelName, teamName string, includeD
|
|||||||
return result, nil
|
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)
|
list, err := a.Srv().Store.Channel().GetChannels(teamID, userID, includeDeleted, lastDeleteAt)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var nfErr *store.ErrNotFound
|
var nfErr *store.ErrNotFound
|
||||||
@@ -1774,6 +1774,21 @@ func (a *App) GetChannelsForUser(teamID string, userID string, includeDeleted bo
|
|||||||
return list, nil
|
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) {
|
func (a *App) GetAllChannels(page, perPage int, opts model.ChannelSearchOpts) (model.ChannelListWithTeamData, *model.AppError) {
|
||||||
if opts.ExcludeDefaultChannels {
|
if opts.ExcludeDefaultChannels {
|
||||||
opts.ExcludeChannelNames = a.DefaultChannelNames()
|
opts.ExcludeChannelNames = a.DefaultChannelNames()
|
||||||
@@ -1925,20 +1940,29 @@ func (a *App) GetChannelMembersForUser(teamID string, userID string) (model.Chan
|
|||||||
return channelMembers, nil
|
return channelMembers, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) GetChannelMembersForUserWithPagination(teamID, userID string, page, perPage int) ([]*model.ChannelMember, *model.AppError) {
|
func (a *App) GetChannelMembersForUserWithPagination(userID string, page, perPage int) ([]*model.ChannelMember, *model.AppError) {
|
||||||
m, err := a.Srv().Store.Channel().GetMembersForUserWithPagination(teamID, userID, page, perPage)
|
m, err := a.Srv().Store.Channel().GetMembersForUserWithPagination(userID, page, perPage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, model.NewAppError("GetChannelMembersForUserWithPagination", "app.channel.get_members.app_error", nil, err.Error(), http.StatusInternalServerError)
|
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 {
|
for _, member := range m {
|
||||||
member := member
|
member := member
|
||||||
members = append(members, &member)
|
members = append(members, &member.ChannelMember)
|
||||||
}
|
}
|
||||||
return members, nil
|
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) {
|
func (a *App) GetChannelMemberCount(channelID string) (int64, *model.AppError) {
|
||||||
count, err := a.Srv().Store.Channel().GetMemberCount(channelID, true)
|
count, err := a.Srv().Store.Channel().GetMemberCount(channelID, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -2689,11 +2713,23 @@ func (a *App) sendWebSocketPostUnreadEvent(channelUnread *model.ChannelUnreadAt,
|
|||||||
a.Publish(message)
|
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
|
includeDeleted := *a.Config().TeamSettings.ExperimentalViewArchivedChannels
|
||||||
term = strings.TrimSpace(term)
|
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 {
|
if err != nil {
|
||||||
return nil, model.NewAppError("AutocompleteChannels", "app.channel.search.app_error", nil, err.Error(), http.StatusInternalServerError)
|
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.App.PermanentDeleteChannel(channel)
|
||||||
defer th.TearDown()
|
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.Nil(t, err)
|
||||||
require.Len(t, channelList, 4)
|
require.Len(t, channelList, 4)
|
||||||
|
|
||||||
th.App.DeleteChannel(th.Context, channel, th.BasicUser.Id)
|
th.App.DeleteChannel(th.Context, channel, th.BasicUser.Id)
|
||||||
|
|
||||||
// Now we get all the non-archived channels for the user
|
// 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.Nil(t, err)
|
||||||
require.Len(t, channelList, 3)
|
require.Len(t, channelList, 3)
|
||||||
|
|
||||||
// Now we get all the channels, even though are archived, for the user
|
// 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.Nil(t, err)
|
||||||
require.Len(t, channelList, 4)
|
require.Len(t, channelList, 4)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -767,7 +767,7 @@ func (a *OpenTracingAppLayer) AuthorizeOAuthUser(w http.ResponseWriter, r *http.
|
|||||||
return resultVar0, resultVar1, resultVar2, resultVar3, resultVar4
|
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
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AutocompleteChannels")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AutocompleteChannels")
|
||||||
|
|
||||||
@@ -779,7 +779,7 @@ func (a *OpenTracingAppLayer) AutocompleteChannels(teamID string, term string) (
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
resultVar0, resultVar1 := a.app.AutocompleteChannels(teamID, term)
|
resultVar0, resultVar1 := a.app.AutocompleteChannels(userID, term)
|
||||||
|
|
||||||
if resultVar1 != nil {
|
if resultVar1 != nil {
|
||||||
span.LogFields(spanlog.Error(resultVar1))
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
@@ -811,6 +811,28 @@ func (a *OpenTracingAppLayer) AutocompleteChannelsForSearch(teamID string, userI
|
|||||||
return resultVar0, resultVar1
|
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) {
|
func (a *OpenTracingAppLayer) AutocompleteUsersInChannel(teamID string, channelID string, term string, options *model.UserSearchOptions) (*model.UserAutocompleteInChannel, *model.AppError) {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AutocompleteUsersInChannel")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.AutocompleteUsersInChannel")
|
||||||
@@ -4848,7 +4870,7 @@ func (a *OpenTracingAppLayer) GetChannelMembersForUser(teamID string, userID str
|
|||||||
return resultVar0, resultVar1
|
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
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelMembersForUserWithPagination")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelMembersForUserWithPagination")
|
||||||
|
|
||||||
@@ -4860,7 +4882,7 @@ func (a *OpenTracingAppLayer) GetChannelMembersForUserWithPagination(teamID stri
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
resultVar0, resultVar1 := a.app.GetChannelMembersForUserWithPagination(teamID, userID, page, perPage)
|
resultVar0, resultVar1 := a.app.GetChannelMembersForUserWithPagination(userID, page, perPage)
|
||||||
|
|
||||||
if resultVar1 != nil {
|
if resultVar1 != nil {
|
||||||
span.LogFields(spanlog.Error(resultVar1))
|
span.LogFields(spanlog.Error(resultVar1))
|
||||||
@@ -4914,6 +4936,28 @@ func (a *OpenTracingAppLayer) GetChannelMembersTimezones(channelID string) ([]st
|
|||||||
return resultVar0, resultVar1
|
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) {
|
func (a *OpenTracingAppLayer) GetChannelModerationsForChannel(channel *model.Channel) ([]*model.ChannelModeration, *model.AppError) {
|
||||||
origCtx := a.ctx
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelModerationsForChannel")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelModerationsForChannel")
|
||||||
@@ -5090,7 +5134,29 @@ func (a *OpenTracingAppLayer) GetChannelsForSchemePage(scheme *model.Scheme, pag
|
|||||||
return resultVar0, resultVar1
|
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
|
origCtx := a.ctx
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelsForUser")
|
span, newCtx := tracing.StartSpanWithParentByContext(a.ctx, "app.GetChannelsForUser")
|
||||||
|
|
||||||
@@ -5102,7 +5168,7 @@ func (a *OpenTracingAppLayer) GetChannelsForUser(teamID string, userID string, i
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
defer span.Finish()
|
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 {
|
if resultVar1 != nil {
|
||||||
span.LogFields(spanlog.Error(resultVar1))
|
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) {
|
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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -557,8 +557,10 @@ func (api *PluginAPI) GetChannelMembersByIds(channelID string, userIDs []string)
|
|||||||
return api.app.GetChannelMembersByIds(channelID, userIDs)
|
return api.app.GetChannelMembersByIds(channelID, userIDs)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (api *PluginAPI) GetChannelMembersForUser(teamID, userID string, page, perPage int) ([]*model.ChannelMember, *model.AppError) {
|
func (api *PluginAPI) GetChannelMembersForUser(_, userID string, page, perPage int) ([]*model.ChannelMember, *model.AppError) {
|
||||||
return api.app.GetChannelMembersForUserWithPagination(teamID, userID, page, perPage)
|
// 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) {
|
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 {
|
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 {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7019,6 +7019,14 @@
|
|||||||
"id": "ent.elasticsearch.generic.disabled",
|
"id": "ent.elasticsearch.generic.disabled",
|
||||||
"translation": "Elasticsearch search is not enabled on this server"
|
"translation": "Elasticsearch search is not enabled on this server"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.elasticsearch.getAllChannelMembers.error",
|
||||||
|
"translation": "Failed to get all channel members"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": "ent.elasticsearch.getAllTeamMembers.error",
|
||||||
|
"translation": "Failed to get all team members"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"id": "ent.elasticsearch.index_channel.error",
|
"id": "ent.elasticsearch.index_channel.error",
|
||||||
"translation": "Failed to index the channel"
|
"translation": "Failed to index the channel"
|
||||||
|
|||||||
@@ -60,8 +60,19 @@ type ChannelMember struct {
|
|||||||
ExplicitRoles string `json:"explicit_roles"`
|
ExplicitRoles string `json:"explicit_roles"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ChannelMemberWithTeamData contains ChannelMember appended with extra team information
|
||||||
|
// as well.
|
||||||
|
type ChannelMemberWithTeamData struct {
|
||||||
|
ChannelMember
|
||||||
|
TeamDisplayName string `json:"team_display_name"`
|
||||||
|
TeamName string `json:"team_name"`
|
||||||
|
TeamUpdateAt int64 `json:"team_update_at"`
|
||||||
|
}
|
||||||
|
|
||||||
type ChannelMembers []ChannelMember
|
type ChannelMembers []ChannelMember
|
||||||
|
|
||||||
|
type ChannelMembersWithTeamData []ChannelMemberWithTeamData
|
||||||
|
|
||||||
type ChannelMemberForExport struct {
|
type ChannelMemberForExport struct {
|
||||||
ChannelMember
|
ChannelMember
|
||||||
ChannelName string
|
ChannelName string
|
||||||
|
|||||||
@@ -3100,6 +3100,24 @@ func (c *Client4) GetChannelsForTeamAndUserWithLastDeleteAt(teamId, userId strin
|
|||||||
return ch, BuildResponse(r), nil
|
return ch, BuildResponse(r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetChannelsForUserWithLastDeleteAt returns a list channels for a user, additionally filtered with lastDeleteAt.
|
||||||
|
func (c *Client4) GetChannelsForUserWithLastDeleteAt(userID string, lastDeleteAt int) ([]*Channel, *Response, error) {
|
||||||
|
route := fmt.Sprintf(c.userRoute(userID) + "/channels")
|
||||||
|
route += fmt.Sprintf("?last_delete_at=%d", lastDeleteAt)
|
||||||
|
r, err := c.DoAPIGet(route, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildResponse(r), err
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
|
||||||
|
var ch []*Channel
|
||||||
|
err = json.NewDecoder(r.Body).Decode(&ch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildResponse(r), NewAppError("GetChannelsForUserWithLastDeleteAt", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return ch, BuildResponse(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
// SearchChannels returns the channels on a team matching the provided search term.
|
// SearchChannels returns the channels on a team matching the provided search term.
|
||||||
func (c *Client4) SearchChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response, error) {
|
func (c *Client4) SearchChannels(teamId string, search *ChannelSearch) ([]*Channel, *Response, error) {
|
||||||
searchJSON, jsonErr := json.Marshal(search)
|
searchJSON, jsonErr := json.Marshal(search)
|
||||||
@@ -3160,6 +3178,29 @@ func (c *Client4) SearchAllChannels(search *ChannelSearch) (ChannelListWithTeamD
|
|||||||
return ch, BuildResponse(r), nil
|
return ch, BuildResponse(r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SearchAllChannelsForUser search in all the channels for a regular user.
|
||||||
|
func (c *Client4) SearchAllChannelsForUser(term string) (ChannelListWithTeamData, *Response, error) {
|
||||||
|
search := &ChannelSearch{
|
||||||
|
Term: term,
|
||||||
|
}
|
||||||
|
searchJSON, jsonErr := json.Marshal(search)
|
||||||
|
if jsonErr != nil {
|
||||||
|
return nil, nil, NewAppError("SearchAllChannelsForUser", "api.marshal_error", nil, jsonErr.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
r, err := c.DoAPIPost(c.channelsRoute()+"/search?system_console=false", string(searchJSON))
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildResponse(r), err
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
|
||||||
|
var ch ChannelListWithTeamData
|
||||||
|
err = json.NewDecoder(r.Body).Decode(&ch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildResponse(r), NewAppError("SearchAllChannelsForUser", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return ch, BuildResponse(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
// SearchAllChannelsPaged searches all the channels and returns the results paged with the total count.
|
// SearchAllChannelsPaged searches all the channels and returns the results paged with the total count.
|
||||||
func (c *Client4) SearchAllChannelsPaged(search *ChannelSearch) (*ChannelsWithCount, *Response, error) {
|
func (c *Client4) SearchAllChannelsPaged(search *ChannelSearch) (*ChannelsWithCount, *Response, error) {
|
||||||
searchJSON, jsonErr := json.Marshal(search)
|
searchJSON, jsonErr := json.Marshal(search)
|
||||||
@@ -3304,7 +3345,7 @@ func (c *Client4) GetChannelByNameForTeamNameIncludeDeleted(channelName, teamNam
|
|||||||
return ch, BuildResponse(r), nil
|
return ch, BuildResponse(r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetChannelMembers gets a page of channel members.
|
// GetChannelMembers gets a page of channel members specific to a channel.
|
||||||
func (c *Client4) GetChannelMembers(channelId string, page, perPage int, etag string) (ChannelMembers, *Response, error) {
|
func (c *Client4) GetChannelMembers(channelId string, page, perPage int, etag string) (ChannelMembers, *Response, error) {
|
||||||
query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
|
query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
|
||||||
r, err := c.DoAPIGet(c.channelMembersRoute(channelId)+query, etag)
|
r, err := c.DoAPIGet(c.channelMembersRoute(channelId)+query, etag)
|
||||||
@@ -3321,6 +3362,23 @@ func (c *Client4) GetChannelMembers(channelId string, page, perPage int, etag st
|
|||||||
return ch, BuildResponse(r), nil
|
return ch, BuildResponse(r), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetChannelMembersWithTeamData gets a page of all channel members for a user.
|
||||||
|
func (c *Client4) GetChannelMembersWithTeamData(userID string, page, perPage int) (ChannelMembersWithTeamData, *Response, error) {
|
||||||
|
query := fmt.Sprintf("?page=%v&per_page=%v", page, perPage)
|
||||||
|
r, err := c.DoAPIGet(c.userRoute(userID)+"/channel_members"+query, "")
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildResponse(r), err
|
||||||
|
}
|
||||||
|
defer closeBody(r)
|
||||||
|
|
||||||
|
var ch ChannelMembersWithTeamData
|
||||||
|
err = json.NewDecoder(r.Body).Decode(&ch)
|
||||||
|
if err != nil {
|
||||||
|
return nil, BuildResponse(r), NewAppError("GetChannelMembersWithTeamData", "api.marshal_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
return ch, BuildResponse(r), nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetChannelMembersByIds gets the channel members in a channel for a list of user ids.
|
// GetChannelMembersByIds gets the channel members in a channel for a list of user ids.
|
||||||
func (c *Client4) GetChannelMembersByIds(channelId string, userIds []string) (ChannelMembers, *Response, error) {
|
func (c *Client4) GetChannelMembersByIds(channelId string, userIds []string) (ChannelMembers, *Response, error) {
|
||||||
r, err := c.DoAPIPost(c.channelMembersRoute(channelId)+"/ids", ArrayToJSON(userIds))
|
r, err := c.DoAPIPost(c.channelMembersRoute(channelId)+"/ids", ArrayToJSON(userIds))
|
||||||
|
|||||||
@@ -59,8 +59,11 @@ func init() {
|
|||||||
func getChannelIndexMapping() *mapping.IndexMappingImpl {
|
func getChannelIndexMapping() *mapping.IndexMappingImpl {
|
||||||
channelMapping := bleve.NewDocumentMapping()
|
channelMapping := bleve.NewDocumentMapping()
|
||||||
channelMapping.AddFieldMappingsAt("Id", keywordMapping)
|
channelMapping.AddFieldMappingsAt("Id", keywordMapping)
|
||||||
|
channelMapping.AddFieldMappingsAt("Type", keywordMapping)
|
||||||
channelMapping.AddFieldMappingsAt("TeamId", keywordMapping)
|
channelMapping.AddFieldMappingsAt("TeamId", keywordMapping)
|
||||||
channelMapping.AddFieldMappingsAt("NameSuggest", keywordMapping)
|
channelMapping.AddFieldMappingsAt("NameSuggest", keywordMapping)
|
||||||
|
channelMapping.AddFieldMappingsAt("UserIDs", keywordMapping)
|
||||||
|
channelMapping.AddFieldMappingsAt("TeamMemberIDs", keywordMapping)
|
||||||
|
|
||||||
indexMapping := bleve.NewIndexMapping()
|
indexMapping := bleve.NewIndexMapping()
|
||||||
indexMapping.AddDocumentMapping("_default", channelMapping)
|
indexMapping.AddDocumentMapping("_default", channelMapping)
|
||||||
|
|||||||
@@ -11,9 +11,12 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type BLVChannel struct {
|
type BLVChannel struct {
|
||||||
Id string
|
Id string
|
||||||
TeamId []string
|
Type model.ChannelType
|
||||||
NameSuggest []string
|
UserIDs []string
|
||||||
|
TeamId []string
|
||||||
|
TeamMemberIDs []string
|
||||||
|
NameSuggest []string
|
||||||
}
|
}
|
||||||
|
|
||||||
type BLVUser struct {
|
type BLVUser struct {
|
||||||
@@ -46,14 +49,17 @@ type BLVFile struct {
|
|||||||
Extension string
|
Extension string
|
||||||
}
|
}
|
||||||
|
|
||||||
func BLVChannelFromChannel(channel *model.Channel) *BLVChannel {
|
func BLVChannelFromChannel(channel *model.Channel, userIDs, teamMemberIDs []string) *BLVChannel {
|
||||||
displayNameInputs := searchengine.GetSuggestionInputsSplitBy(channel.DisplayName, " ")
|
displayNameInputs := searchengine.GetSuggestionInputsSplitBy(channel.DisplayName, " ")
|
||||||
nameInputs := searchengine.GetSuggestionInputsSplitByMultiple(channel.Name, []string{"-", "_"})
|
nameInputs := searchengine.GetSuggestionInputsSplitByMultiple(channel.Name, []string{"-", "_"})
|
||||||
|
|
||||||
return &BLVChannel{
|
return &BLVChannel{
|
||||||
Id: channel.Id,
|
Id: channel.Id,
|
||||||
TeamId: []string{channel.TeamId},
|
Type: channel.Type,
|
||||||
NameSuggest: append(displayNameInputs, nameInputs...),
|
TeamId: []string{channel.TeamId},
|
||||||
|
NameSuggest: append(displayNameInputs, nameInputs...),
|
||||||
|
UserIDs: userIDs,
|
||||||
|
TeamMemberIDs: teamMemberIDs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -510,7 +510,22 @@ func (worker *BleveIndexerWorker) BulkIndexChannels(channels []*model.Channel, p
|
|||||||
|
|
||||||
for _, channel := range channels {
|
for _, channel := range channels {
|
||||||
if channel.DeleteAt == 0 {
|
if channel.DeleteAt == 0 {
|
||||||
searchChannel := bleveengine.BLVChannelFromChannel(channel)
|
var userIDs []string
|
||||||
|
var err error
|
||||||
|
if channel.Type == model.ChannelTypePrivate {
|
||||||
|
userIDs, err = worker.jobServer.Store.Channel().GetAllChannelMembersById(channel.Id)
|
||||||
|
if err != nil {
|
||||||
|
return 0, model.NewAppError("BleveIndexerWorker.BulkIndexChannels", "bleveengine.indexer.do_job.bulk_index_channels.batch_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get teamMember ids from channelid
|
||||||
|
teamMemberIDs, err := worker.jobServer.Store.Channel().GetTeamMembersForChannel(channel.Id)
|
||||||
|
if err != nil {
|
||||||
|
return 0, model.NewAppError("BleveIndexerWorker.BulkIndexChannels", "bleveengine.indexer.do_job.bulk_index_channels.batch_error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
searchChannel := bleveengine.BLVChannelFromChannel(channel, userIDs, teamMemberIDs)
|
||||||
batch.Index(searchChannel.Id, searchChannel)
|
batch.Index(searchChannel.Id, searchChannel)
|
||||||
} else {
|
} else {
|
||||||
batch.Delete(channel.Id)
|
batch.Delete(channel.Id)
|
||||||
|
|||||||
@@ -303,21 +303,59 @@ func (b *BleveEngine) DeletePost(post *model.Post) *model.AppError {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BleveEngine) IndexChannel(channel *model.Channel) *model.AppError {
|
func (b *BleveEngine) IndexChannel(channel *model.Channel, userIDs, teamMemberIDs []string) *model.AppError {
|
||||||
b.Mutex.RLock()
|
b.Mutex.RLock()
|
||||||
defer b.Mutex.RUnlock()
|
defer b.Mutex.RUnlock()
|
||||||
|
|
||||||
blvChannel := BLVChannelFromChannel(channel)
|
blvChannel := BLVChannelFromChannel(channel, userIDs, teamMemberIDs)
|
||||||
if err := b.ChannelIndex.Index(blvChannel.Id, blvChannel); err != nil {
|
if err := b.ChannelIndex.Index(blvChannel.Id, blvChannel); err != nil {
|
||||||
return model.NewAppError("Bleveengine.IndexChannel", "bleveengine.index_channel.error", nil, err.Error(), http.StatusInternalServerError)
|
return model.NewAppError("Bleveengine.IndexChannel", "bleveengine.index_channel.error", nil, err.Error(), http.StatusInternalServerError)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b *BleveEngine) SearchChannels(teamId, term string) ([]string, *model.AppError) {
|
func (b *BleveEngine) SearchChannels(teamId, userID, term string) ([]string, *model.AppError) {
|
||||||
teamIdQ := bleve.NewTermQuery(teamId)
|
// This query essentially boils down to (if teamID is passed):
|
||||||
teamIdQ.SetField("TeamId")
|
// match teamID == <>
|
||||||
queries := []query.Query{teamIdQ}
|
// AND
|
||||||
|
// match term == <>
|
||||||
|
// AND
|
||||||
|
// match (channelType != 'P' || (<> in userIDs && channelType == 'P'))
|
||||||
|
|
||||||
|
// (or if teamID is not passed)
|
||||||
|
// <> in teamMemberIds
|
||||||
|
// AND
|
||||||
|
// match term == <>
|
||||||
|
// AND
|
||||||
|
// match (channelType != 'P' || (<> in userIDs && channelType == 'P'))
|
||||||
|
|
||||||
|
queries := []query.Query{}
|
||||||
|
if teamId != "" {
|
||||||
|
teamIdQ := bleve.NewTermQuery(teamId)
|
||||||
|
teamIdQ.SetField("TeamId")
|
||||||
|
queries = append(queries, teamIdQ)
|
||||||
|
} else {
|
||||||
|
teamMemberQ := bleve.NewTermQuery(userID)
|
||||||
|
teamMemberQ.SetField("TeamMemberIDs")
|
||||||
|
queries = append(queries, teamMemberQ)
|
||||||
|
}
|
||||||
|
|
||||||
|
boolNotPrivate := bleve.NewBooleanQuery()
|
||||||
|
privateQ := bleve.NewTermQuery(string(model.ChannelTypePrivate))
|
||||||
|
privateQ.SetField("Type")
|
||||||
|
boolNotPrivate.AddMustNot(privateQ)
|
||||||
|
|
||||||
|
userQ := bleve.NewBooleanQuery()
|
||||||
|
userIDQ := bleve.NewTermQuery(userID)
|
||||||
|
userIDQ.SetField("UserIDs")
|
||||||
|
userQ.AddMust(userIDQ)
|
||||||
|
userQ.AddMust(privateQ)
|
||||||
|
|
||||||
|
channelTypeQ := bleve.NewDisjunctionQuery()
|
||||||
|
channelTypeQ.AddQuery(boolNotPrivate)
|
||||||
|
channelTypeQ.AddQuery(userQ) // userID && 'p'
|
||||||
|
|
||||||
|
queries = append(queries, channelTypeQ)
|
||||||
|
|
||||||
if term != "" {
|
if term != "" {
|
||||||
nameSuggestQ := bleve.NewPrefixQuery(strings.ToLower(term))
|
nameSuggestQ := bleve.NewPrefixQuery(strings.ToLower(term))
|
||||||
|
|||||||
@@ -27,8 +27,10 @@ type SearchEngineInterface interface {
|
|||||||
DeletePost(post *model.Post) *model.AppError
|
DeletePost(post *model.Post) *model.AppError
|
||||||
DeleteChannelPosts(channelID string) *model.AppError
|
DeleteChannelPosts(channelID string) *model.AppError
|
||||||
DeleteUserPosts(userID string) *model.AppError
|
DeleteUserPosts(userID string) *model.AppError
|
||||||
IndexChannel(channel *model.Channel) *model.AppError
|
// IndexChannel indexes a given channel. The userIDs are only populated
|
||||||
SearchChannels(teamId, term string) ([]string, *model.AppError)
|
// for private channels.
|
||||||
|
IndexChannel(channel *model.Channel, userIDs, teamMemberIDs []string) *model.AppError
|
||||||
|
SearchChannels(teamId, userID, term string) ([]string, *model.AppError)
|
||||||
DeleteChannel(channel *model.Channel) *model.AppError
|
DeleteChannel(channel *model.Channel) *model.AppError
|
||||||
IndexUser(user *model.User, teamsIds, channelsIds []string) *model.AppError
|
IndexUser(user *model.User, teamsIds, channelsIds []string) *model.AppError
|
||||||
SearchUsersInChannel(teamId, channelId string, restrictedToChannels []string, term string, options *model.UserSearchOptions) ([]string, []string, *model.AppError)
|
SearchUsersInChannel(teamId, channelId string, restrictedToChannels []string, term string, options *model.UserSearchOptions) ([]string, []string, *model.AppError)
|
||||||
|
|||||||
@@ -234,13 +234,13 @@ func (_m *SearchEngineInterface) GetVersion() int {
|
|||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
// IndexChannel provides a mock function with given fields: channel
|
// IndexChannel provides a mock function with given fields: channel, userIDs, teamMemberIDs
|
||||||
func (_m *SearchEngineInterface) IndexChannel(channel *model.Channel) *model.AppError {
|
func (_m *SearchEngineInterface) IndexChannel(channel *model.Channel, userIDs []string, teamMemberIDs []string) *model.AppError {
|
||||||
ret := _m.Called(channel)
|
ret := _m.Called(channel, userIDs, teamMemberIDs)
|
||||||
|
|
||||||
var r0 *model.AppError
|
var r0 *model.AppError
|
||||||
if rf, ok := ret.Get(0).(func(*model.Channel) *model.AppError); ok {
|
if rf, ok := ret.Get(0).(func(*model.Channel, []string, []string) *model.AppError); ok {
|
||||||
r0 = rf(channel)
|
r0 = rf(channel, userIDs, teamMemberIDs)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
if ret.Get(0) != nil {
|
||||||
r0 = ret.Get(0).(*model.AppError)
|
r0 = ret.Get(0).(*model.AppError)
|
||||||
@@ -400,13 +400,13 @@ func (_m *SearchEngineInterface) RefreshIndexes() *model.AppError {
|
|||||||
return r0
|
return r0
|
||||||
}
|
}
|
||||||
|
|
||||||
// SearchChannels provides a mock function with given fields: teamId, term
|
// SearchChannels provides a mock function with given fields: teamId, userID, term
|
||||||
func (_m *SearchEngineInterface) SearchChannels(teamId string, term string) ([]string, *model.AppError) {
|
func (_m *SearchEngineInterface) SearchChannels(teamId string, userID string, term string) ([]string, *model.AppError) {
|
||||||
ret := _m.Called(teamId, term)
|
ret := _m.Called(teamId, userID, term)
|
||||||
|
|
||||||
var r0 []string
|
var r0 []string
|
||||||
if rf, ok := ret.Get(0).(func(string, string) []string); ok {
|
if rf, ok := ret.Get(0).(func(string, string, string) []string); ok {
|
||||||
r0 = rf(teamId, term)
|
r0 = rf(teamId, userID, term)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
if ret.Get(0) != nil {
|
||||||
r0 = ret.Get(0).([]string)
|
r0 = ret.Get(0).([]string)
|
||||||
@@ -414,8 +414,8 @@ func (_m *SearchEngineInterface) SearchChannels(teamId string, term string) ([]s
|
|||||||
}
|
}
|
||||||
|
|
||||||
var r1 *model.AppError
|
var r1 *model.AppError
|
||||||
if rf, ok := ret.Get(1).(func(string, string) *model.AppError); ok {
|
if rf, ok := ret.Get(1).(func(string, string, string) *model.AppError); ok {
|
||||||
r1 = rf(teamId, term)
|
r1 = rf(teamId, userID, term)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(1) != nil {
|
if ret.Get(1) != nil {
|
||||||
r1 = ret.Get(1).(*model.AppError)
|
r1 = ret.Get(1).(*model.AppError)
|
||||||
|
|||||||
@@ -570,7 +570,25 @@ func (s *OpenTracingLayerChannelStore) AnalyticsTypeCount(teamID string, channel
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) AutocompleteInTeam(teamID string, term string, includeDeleted bool) (model.ChannelList, error) {
|
func (s *OpenTracingLayerChannelStore) Autocomplete(userID string, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.Autocomplete")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
result, err := s.ChannelStore.Autocomplete(userID, term, includeDeleted)
|
||||||
|
if err != nil {
|
||||||
|
span.LogFields(spanlog.Error(err))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) AutocompleteInTeam(teamID string, userID string, term string, includeDeleted bool) (model.ChannelList, error) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.AutocompleteInTeam")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.AutocompleteInTeam")
|
||||||
s.Root.Store.SetContext(newCtx)
|
s.Root.Store.SetContext(newCtx)
|
||||||
@@ -579,7 +597,7 @@ func (s *OpenTracingLayerChannelStore) AutocompleteInTeam(teamID string, term st
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
result, err := s.ChannelStore.AutocompleteInTeam(teamID, term, includeDeleted)
|
result, err := s.ChannelStore.AutocompleteInTeam(teamID, userID, term, includeDeleted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
span.LogFields(spanlog.Error(err))
|
span.LogFields(spanlog.Error(err))
|
||||||
ext.Error.Set(span, true)
|
ext.Error.Set(span, true)
|
||||||
@@ -817,6 +835,24 @@ func (s *OpenTracingLayerChannelStore) GetAll(teamID string) ([]*model.Channel,
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) GetAllChannelMembersById(id string) ([]string, error) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetAllChannelMembersById")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
result, err := s.ChannelStore.GetAllChannelMembersById(id)
|
||||||
|
if err != nil {
|
||||||
|
span.LogFields(spanlog.Error(err))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) GetAllChannelMembersForUser(userID string, allowFromCache bool, includeDeleted bool) (map[string]string, error) {
|
func (s *OpenTracingLayerChannelStore) GetAllChannelMembersForUser(userID string, allowFromCache bool, includeDeleted bool) (map[string]string, error) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetAllChannelMembersForUser")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetAllChannelMembersForUser")
|
||||||
@@ -1123,6 +1159,42 @@ func (s *OpenTracingLayerChannelStore) GetChannelsByScheme(schemeID string, offs
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) GetChannelsByUser(userID string, includeDeleted bool, lastDeleteAt int, pageSize int, fromChannelID string) (model.ChannelList, error) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetChannelsByUser")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
result, err := s.ChannelStore.GetChannelsByUser(userID, includeDeleted, lastDeleteAt, pageSize, fromChannelID)
|
||||||
|
if err != nil {
|
||||||
|
span.LogFields(spanlog.Error(err))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) GetChannelsWithTeamDataByIds(channelIds []string, includeDeleted bool) ([]*model.ChannelWithTeamData, error) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetChannelsWithTeamDataByIds")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
result, err := s.ChannelStore.GetChannelsWithTeamDataByIds(channelIds, includeDeleted)
|
||||||
|
if err != nil {
|
||||||
|
span.LogFields(spanlog.Error(err))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error) {
|
func (s *OpenTracingLayerChannelStore) GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetDeleted")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetDeleted")
|
||||||
@@ -1370,7 +1442,7 @@ func (s *OpenTracingLayerChannelStore) GetMembersForUser(teamID string, userID s
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) GetMembersForUserWithPagination(teamID string, userID string, page int, perPage int) (model.ChannelMembers, error) {
|
func (s *OpenTracingLayerChannelStore) GetMembersForUserWithPagination(userID string, page int, perPage int) (model.ChannelMembersWithTeamData, error) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetMembersForUserWithPagination")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetMembersForUserWithPagination")
|
||||||
s.Root.Store.SetContext(newCtx)
|
s.Root.Store.SetContext(newCtx)
|
||||||
@@ -1379,7 +1451,7 @@ func (s *OpenTracingLayerChannelStore) GetMembersForUserWithPagination(teamID st
|
|||||||
}()
|
}()
|
||||||
|
|
||||||
defer span.Finish()
|
defer span.Finish()
|
||||||
result, err := s.ChannelStore.GetMembersForUserWithPagination(teamID, userID, page, perPage)
|
result, err := s.ChannelStore.GetMembersForUserWithPagination(userID, page, perPage)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
span.LogFields(spanlog.Error(err))
|
span.LogFields(spanlog.Error(err))
|
||||||
ext.Error.Set(span, true)
|
ext.Error.Set(span, true)
|
||||||
@@ -1586,6 +1658,24 @@ func (s *OpenTracingLayerChannelStore) GetTeamForChannel(channelID string) (*mod
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *OpenTracingLayerChannelStore) GetTeamMembersForChannel(channelID string) ([]string, error) {
|
||||||
|
origCtx := s.Root.Store.Context()
|
||||||
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GetTeamMembersForChannel")
|
||||||
|
s.Root.Store.SetContext(newCtx)
|
||||||
|
defer func() {
|
||||||
|
s.Root.Store.SetContext(origCtx)
|
||||||
|
}()
|
||||||
|
|
||||||
|
defer span.Finish()
|
||||||
|
result, err := s.ChannelStore.GetTeamMembersForChannel(channelID)
|
||||||
|
if err != nil {
|
||||||
|
span.LogFields(spanlog.Error(err))
|
||||||
|
ext.Error.Set(span, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *OpenTracingLayerChannelStore) GroupSyncedChannelCount() (int64, error) {
|
func (s *OpenTracingLayerChannelStore) GroupSyncedChannelCount() (int64, error) {
|
||||||
origCtx := s.Root.Store.Context()
|
origCtx := s.Root.Store.Context()
|
||||||
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GroupSyncedChannelCount")
|
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "ChannelStore.GroupSyncedChannelCount")
|
||||||
|
|||||||
@@ -608,11 +608,31 @@ func (s *RetryLayerChannelStore) AnalyticsTypeCount(teamID string, channelType m
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *RetryLayerChannelStore) AutocompleteInTeam(teamID string, term string, includeDeleted bool) (model.ChannelList, error) {
|
func (s *RetryLayerChannelStore) Autocomplete(userID string, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
|
||||||
|
|
||||||
tries := 0
|
tries := 0
|
||||||
for {
|
for {
|
||||||
result, err := s.ChannelStore.AutocompleteInTeam(teamID, term, includeDeleted)
|
result, err := s.ChannelStore.Autocomplete(userID, term, includeDeleted)
|
||||||
|
if err == nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
if !isRepeatableError(err) {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
tries++
|
||||||
|
if tries >= 3 {
|
||||||
|
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *RetryLayerChannelStore) AutocompleteInTeam(teamID string, userID string, term string, includeDeleted bool) (model.ChannelList, error) {
|
||||||
|
|
||||||
|
tries := 0
|
||||||
|
for {
|
||||||
|
result, err := s.ChannelStore.AutocompleteInTeam(teamID, userID, term, includeDeleted)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
@@ -874,6 +894,26 @@ func (s *RetryLayerChannelStore) GetAll(teamID string) ([]*model.Channel, error)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *RetryLayerChannelStore) GetAllChannelMembersById(id string) ([]string, error) {
|
||||||
|
|
||||||
|
tries := 0
|
||||||
|
for {
|
||||||
|
result, err := s.ChannelStore.GetAllChannelMembersById(id)
|
||||||
|
if err == nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
if !isRepeatableError(err) {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
tries++
|
||||||
|
if tries >= 3 {
|
||||||
|
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (s *RetryLayerChannelStore) GetAllChannelMembersForUser(userID string, allowFromCache bool, includeDeleted bool) (map[string]string, error) {
|
func (s *RetryLayerChannelStore) GetAllChannelMembersForUser(userID string, allowFromCache bool, includeDeleted bool) (map[string]string, error) {
|
||||||
|
|
||||||
tries := 0
|
tries := 0
|
||||||
@@ -1214,6 +1254,46 @@ func (s *RetryLayerChannelStore) GetChannelsByScheme(schemeID string, offset int
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *RetryLayerChannelStore) GetChannelsByUser(userID string, includeDeleted bool, lastDeleteAt int, pageSize int, fromChannelID string) (model.ChannelList, error) {
|
||||||
|
|
||||||
|
tries := 0
|
||||||
|
for {
|
||||||
|
result, err := s.ChannelStore.GetChannelsByUser(userID, includeDeleted, lastDeleteAt, pageSize, fromChannelID)
|
||||||
|
if err == nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
if !isRepeatableError(err) {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
tries++
|
||||||
|
if tries >= 3 {
|
||||||
|
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *RetryLayerChannelStore) GetChannelsWithTeamDataByIds(channelIds []string, includeDeleted bool) ([]*model.ChannelWithTeamData, error) {
|
||||||
|
|
||||||
|
tries := 0
|
||||||
|
for {
|
||||||
|
result, err := s.ChannelStore.GetChannelsWithTeamDataByIds(channelIds, includeDeleted)
|
||||||
|
if err == nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
if !isRepeatableError(err) {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
tries++
|
||||||
|
if tries >= 3 {
|
||||||
|
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (s *RetryLayerChannelStore) GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error) {
|
func (s *RetryLayerChannelStore) GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error) {
|
||||||
|
|
||||||
tries := 0
|
tries := 0
|
||||||
@@ -1480,11 +1560,11 @@ func (s *RetryLayerChannelStore) GetMembersForUser(teamID string, userID string)
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *RetryLayerChannelStore) GetMembersForUserWithPagination(teamID string, userID string, page int, perPage int) (model.ChannelMembers, error) {
|
func (s *RetryLayerChannelStore) GetMembersForUserWithPagination(userID string, page int, perPage int) (model.ChannelMembersWithTeamData, error) {
|
||||||
|
|
||||||
tries := 0
|
tries := 0
|
||||||
for {
|
for {
|
||||||
result, err := s.ChannelStore.GetMembersForUserWithPagination(teamID, userID, page, perPage)
|
result, err := s.ChannelStore.GetMembersForUserWithPagination(userID, page, perPage)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
@@ -1720,6 +1800,26 @@ func (s *RetryLayerChannelStore) GetTeamForChannel(channelID string) (*model.Tea
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *RetryLayerChannelStore) GetTeamMembersForChannel(channelID string) ([]string, error) {
|
||||||
|
|
||||||
|
tries := 0
|
||||||
|
for {
|
||||||
|
result, err := s.ChannelStore.GetTeamMembersForChannel(channelID)
|
||||||
|
if err == nil {
|
||||||
|
return result, nil
|
||||||
|
}
|
||||||
|
if !isRepeatableError(err) {
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
tries++
|
||||||
|
if tries >= 3 {
|
||||||
|
err = errors.Wrap(err, "giving up after 3 consecutive repeatable transaction failures")
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
func (s *RetryLayerChannelStore) GroupSyncedChannelCount() (int64, error) {
|
func (s *RetryLayerChannelStore) GroupSyncedChannelCount() (int64, error) {
|
||||||
|
|
||||||
tries := 0
|
tries := 0
|
||||||
|
|||||||
@@ -36,17 +36,31 @@ func (c *SearchChannelStore) deleteChannelIndex(channel *model.Channel) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *SearchChannelStore) indexChannel(channel *model.Channel) {
|
func (c *SearchChannelStore) indexChannel(channel *model.Channel) {
|
||||||
if channel.Type == model.ChannelTypeOpen {
|
var userIDs, teamMemberIDs []string
|
||||||
for _, engine := range c.rootStore.searchEngine.GetActiveEngines() {
|
var err error
|
||||||
if engine.IsIndexingEnabled() {
|
if channel.Type == model.ChannelTypePrivate {
|
||||||
runIndexFn(engine, func(engineCopy searchengine.SearchEngineInterface) {
|
userIDs, err = c.GetAllChannelMembersById(channel.Id)
|
||||||
if err := engineCopy.IndexChannel(channel); err != nil {
|
if err != nil {
|
||||||
mlog.Warn("Encountered error indexing channel", mlog.String("channel_id", channel.Id), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
|
mlog.Warn("Encountered error while indexing channel", mlog.String("channel_id", channel.Id), mlog.Err(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
mlog.Debug("Indexed channel in search engine", mlog.String("search_engine", engineCopy.GetName()), mlog.String("channel_id", channel.Id))
|
}
|
||||||
})
|
|
||||||
}
|
teamMemberIDs, err = c.GetTeamMembersForChannel(channel.Id)
|
||||||
|
if err != nil {
|
||||||
|
mlog.Warn("Encountered error while indexing channel", mlog.String("channel_id", channel.Id), mlog.Err(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, engine := range c.rootStore.searchEngine.GetActiveEngines() {
|
||||||
|
if engine.IsIndexingEnabled() {
|
||||||
|
runIndexFn(engine, func(engineCopy searchengine.SearchEngineInterface) {
|
||||||
|
if err := engineCopy.IndexChannel(channel, userIDs, teamMemberIDs); err != nil {
|
||||||
|
mlog.Warn("Encountered error indexing channel", mlog.String("channel_id", channel.Id), mlog.String("search_engine", engineCopy.GetName()), mlog.Err(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
mlog.Debug("Indexed channel in search engine", mlog.String("search_engine", engineCopy.GetName()), mlog.String("channel_id", channel.Id))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,6 +89,7 @@ func (c *SearchChannelStore) UpdateMember(cm *model.ChannelMember) (*model.Chann
|
|||||||
if channelErr != nil {
|
if channelErr != nil {
|
||||||
mlog.Warn("Encountered error indexing user in channel", mlog.String("channel_id", member.ChannelId), mlog.Err(channelErr))
|
mlog.Warn("Encountered error indexing user in channel", mlog.String("channel_id", member.ChannelId), mlog.Err(channelErr))
|
||||||
} else {
|
} else {
|
||||||
|
c.indexChannel(channel)
|
||||||
c.rootStore.indexUserFromID(channel.CreatorId)
|
c.rootStore.indexUserFromID(channel.CreatorId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -89,25 +104,37 @@ func (c *SearchChannelStore) SaveMember(cm *model.ChannelMember) (*model.Channel
|
|||||||
if channelErr != nil {
|
if channelErr != nil {
|
||||||
mlog.Warn("Encountered error indexing user in channel", mlog.String("channel_id", member.ChannelId), mlog.Err(channelErr))
|
mlog.Warn("Encountered error indexing user in channel", mlog.String("channel_id", member.ChannelId), mlog.Err(channelErr))
|
||||||
} else {
|
} else {
|
||||||
|
c.indexChannel(channel)
|
||||||
c.rootStore.indexUserFromID(channel.CreatorId)
|
c.rootStore.indexUserFromID(channel.CreatorId)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return member, err
|
return member, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SearchChannelStore) RemoveMember(channelId, userIdToRemove string) error {
|
func (c *SearchChannelStore) RemoveMember(channelID, userIdToRemove string) error {
|
||||||
err := c.ChannelStore.RemoveMember(channelId, userIdToRemove)
|
err := c.ChannelStore.RemoveMember(channelID, userIdToRemove)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.rootStore.indexUserFromID(userIdToRemove)
|
c.rootStore.indexUserFromID(userIdToRemove)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel, err := c.ChannelStore.Get(channelID, true)
|
||||||
|
if err == nil {
|
||||||
|
c.indexChannel(channel)
|
||||||
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SearchChannelStore) RemoveMembers(channelId string, userIds []string) error {
|
func (c *SearchChannelStore) RemoveMembers(channelID string, userIds []string) error {
|
||||||
if err := c.ChannelStore.RemoveMembers(channelId, userIds); err != nil {
|
if err := c.ChannelStore.RemoveMembers(channelID, userIds); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
channel, err := c.ChannelStore.Get(channelID, true)
|
||||||
|
if err == nil {
|
||||||
|
c.indexChannel(channel)
|
||||||
|
}
|
||||||
|
|
||||||
for _, uid := range userIds {
|
for _, uid := range userIds {
|
||||||
c.rootStore.indexUserFromID(uid)
|
c.rootStore.indexUserFromID(uid)
|
||||||
}
|
}
|
||||||
@@ -119,27 +146,29 @@ func (c *SearchChannelStore) CreateDirectChannel(user *model.User, otherUser *mo
|
|||||||
if err == nil {
|
if err == nil {
|
||||||
c.rootStore.indexUserFromID(user.Id)
|
c.rootStore.indexUserFromID(user.Id)
|
||||||
c.rootStore.indexUserFromID(otherUser.Id)
|
c.rootStore.indexUserFromID(otherUser.Id)
|
||||||
|
c.indexChannel(channel)
|
||||||
}
|
}
|
||||||
return channel, err
|
return channel, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SearchChannelStore) SaveDirectChannel(directchannel *model.Channel, member1 *model.ChannelMember, member2 *model.ChannelMember) (*model.Channel, error) {
|
func (c *SearchChannelStore) SaveDirectChannel(directchannel *model.Channel, member1 *model.ChannelMember, member2 *model.ChannelMember) (*model.Channel, error) {
|
||||||
channel, err := c.ChannelStore.SaveDirectChannel(directchannel, member1, member2)
|
channel, err := c.ChannelStore.SaveDirectChannel(directchannel, member1, member2)
|
||||||
if err != nil {
|
if err == nil {
|
||||||
c.rootStore.indexUserFromID(member1.UserId)
|
c.rootStore.indexUserFromID(member1.UserId)
|
||||||
c.rootStore.indexUserFromID(member2.UserId)
|
c.rootStore.indexUserFromID(member2.UserId)
|
||||||
|
c.indexChannel(channel)
|
||||||
}
|
}
|
||||||
return channel, err
|
return channel, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SearchChannelStore) AutocompleteInTeam(teamId string, term string, includeDeleted bool) (model.ChannelList, error) {
|
func (c *SearchChannelStore) Autocomplete(userID, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
|
||||||
var channelList model.ChannelList
|
var channelList model.ChannelListWithTeamData
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
allFailed := true
|
allFailed := true
|
||||||
for _, engine := range c.rootStore.searchEngine.GetActiveEngines() {
|
for _, engine := range c.rootStore.searchEngine.GetActiveEngines() {
|
||||||
if engine.IsAutocompletionEnabled() {
|
if engine.IsAutocompletionEnabled() {
|
||||||
channelList, err = c.searchAutocompleteChannels(engine, teamId, term, includeDeleted)
|
channelList, err = c.searchAutocompleteChannelsAllTeams(engine, userID, term, includeDeleted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mlog.Warn("Encountered error on AutocompleteChannels through SearchEngine. Falling back to default autocompletion.", mlog.String("search_engine", engine.GetName()), mlog.Err(err))
|
mlog.Warn("Encountered error on AutocompleteChannels through SearchEngine. Falling back to default autocompletion.", mlog.String("search_engine", engine.GetName()), mlog.Err(err))
|
||||||
continue
|
continue
|
||||||
@@ -152,7 +181,7 @@ func (c *SearchChannelStore) AutocompleteInTeam(teamId string, term string, incl
|
|||||||
|
|
||||||
if allFailed {
|
if allFailed {
|
||||||
mlog.Debug("Using database search because no other search engine is available")
|
mlog.Debug("Using database search because no other search engine is available")
|
||||||
channelList, err = c.ChannelStore.AutocompleteInTeam(teamId, term, includeDeleted)
|
channelList, err = c.ChannelStore.Autocomplete(userID, term, includeDeleted)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrap(err, "Failed to autocomplete channels in team")
|
return nil, errors.Wrap(err, "Failed to autocomplete channels in team")
|
||||||
}
|
}
|
||||||
@@ -165,21 +194,69 @@ func (c *SearchChannelStore) AutocompleteInTeam(teamId string, term string, incl
|
|||||||
return channelList, nil
|
return channelList, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *SearchChannelStore) searchAutocompleteChannels(engine searchengine.SearchEngineInterface, teamId, term string, includeDeleted bool) (model.ChannelList, error) {
|
func (c *SearchChannelStore) AutocompleteInTeam(teamID, userID, term string, includeDeleted bool) (model.ChannelList, error) {
|
||||||
channelIds, err := engine.SearchChannels(teamId, term)
|
var channelList model.ChannelList
|
||||||
|
var err error
|
||||||
|
|
||||||
|
allFailed := true
|
||||||
|
for _, engine := range c.rootStore.searchEngine.GetActiveEngines() {
|
||||||
|
if engine.IsAutocompletionEnabled() {
|
||||||
|
channelList, err = c.searchAutocompleteChannels(engine, teamID, userID, term, includeDeleted)
|
||||||
|
if err != nil {
|
||||||
|
mlog.Warn("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, userID, term, includeDeleted)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "Failed to autocomplete channels in team")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return channelList, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return channelList, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *SearchChannelStore) searchAutocompleteChannels(engine searchengine.SearchEngineInterface, teamId, userID, term string, includeDeleted bool) (model.ChannelList, error) {
|
||||||
|
channelIds, err := engine.SearchChannels(teamId, userID, term)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
channelList := model.ChannelList{}
|
channelList := model.ChannelList{}
|
||||||
|
var nErr error
|
||||||
if len(channelIds) > 0 {
|
if len(channelIds) > 0 {
|
||||||
channels, err := c.ChannelStore.GetChannelsByIds(channelIds, includeDeleted)
|
channelList, nErr = c.ChannelStore.GetChannelsByIds(channelIds, includeDeleted)
|
||||||
if err != nil {
|
if nErr != nil {
|
||||||
return nil, errors.Wrap(err, "Failed to get channels by ids")
|
return nil, errors.Wrap(nErr, "Failed to get channels by ids")
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for _, ch := range channels {
|
return channelList, nil
|
||||||
channelList = append(channelList, ch)
|
}
|
||||||
|
|
||||||
|
func (c *SearchChannelStore) searchAutocompleteChannelsAllTeams(engine searchengine.SearchEngineInterface, userID, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
|
||||||
|
channelIds, err := engine.SearchChannels("", userID, term)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
channelList := model.ChannelListWithTeamData{}
|
||||||
|
var nErr error
|
||||||
|
if len(channelIds) > 0 {
|
||||||
|
channelList, nErr = c.ChannelStore.GetChannelsWithTeamDataByIds(channelIds, includeDeleted)
|
||||||
|
if nErr != nil {
|
||||||
|
return nil, errors.Wrap(nErr, "Failed to get channels by ids")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -187,10 +264,21 @@ func (c *SearchChannelStore) searchAutocompleteChannels(engine searchengine.Sear
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (c *SearchChannelStore) PermanentDeleteMembersByUser(userId string) error {
|
func (c *SearchChannelStore) PermanentDeleteMembersByUser(userId string) error {
|
||||||
|
channels, errGetChannels := c.ChannelStore.GetChannelsByUser(userId, false, 0, -1, "")
|
||||||
|
if errGetChannels != nil {
|
||||||
|
mlog.Warn("Encountered error indexing channel after removing user", mlog.String("user_id", userId), mlog.Err(errGetChannels))
|
||||||
|
}
|
||||||
|
|
||||||
err := c.ChannelStore.PermanentDeleteMembersByUser(userId)
|
err := c.ChannelStore.PermanentDeleteMembersByUser(userId)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
c.rootStore.indexUserFromID(userId)
|
c.rootStore.indexUserFromID(userId)
|
||||||
|
if errGetChannels == nil {
|
||||||
|
for _, ch := range channels {
|
||||||
|
c.indexChannel(ch)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,12 @@ var searchChannelStoreTests = []searchTest{
|
|||||||
{
|
{
|
||||||
Name: "Should be able to autocomplete a channel by name",
|
Name: "Should be able to autocomplete a channel by name",
|
||||||
Fn: testAutocompleteChannelByName,
|
Fn: testAutocompleteChannelByName,
|
||||||
Tags: []string{EngineAll},
|
Tags: []string{EngineMySql, EngineElasticSearch, EngineBleve},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Should be able to autocomplete a channel by name (Postgres)",
|
||||||
|
Fn: testAutocompleteChannelByNamePostgres,
|
||||||
|
Tags: []string{EnginePostgres},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should be able to autocomplete a channel by display name",
|
Name: "Should be able to autocomplete a channel by display name",
|
||||||
@@ -26,7 +31,12 @@ var searchChannelStoreTests = []searchTest{
|
|||||||
{
|
{
|
||||||
Name: "Should be able to autocomplete a channel by a part of its name when has parts splitted by - character",
|
Name: "Should be able to autocomplete a channel by a part of its name when has parts splitted by - character",
|
||||||
Fn: testAutocompleteChannelByNameSplittedWithDashChar,
|
Fn: testAutocompleteChannelByNameSplittedWithDashChar,
|
||||||
Tags: []string{EngineAll},
|
Tags: []string{EngineMySql, EngineElasticSearch, EngineBleve},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Name: "Should be able to autocomplete a channel by a part of its name when has parts splitted by - character (Postgres)",
|
||||||
|
Fn: testAutocompleteChannelByNameSplittedWithDashCharPostgres,
|
||||||
|
Tags: []string{EnginePostgres},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should be able to autocomplete a channel by a part of its name when has parts splitted by _ character",
|
Name: "Should be able to autocomplete a channel by a part of its name when has parts splitted by _ character",
|
||||||
@@ -46,12 +56,12 @@ var searchChannelStoreTests = []searchTest{
|
|||||||
{
|
{
|
||||||
Name: "Should be able to autocomplete channels in a case insensitive manner",
|
Name: "Should be able to autocomplete channels in a case insensitive manner",
|
||||||
Fn: testSearchChannelsInCaseInsensitiveManner,
|
Fn: testSearchChannelsInCaseInsensitiveManner,
|
||||||
Tags: []string{EngineAll},
|
Tags: []string{EngineMySql, EngineElasticSearch, EngineBleve},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should autocomplete only returning public channels",
|
Name: "Should be able to autocomplete channels in a case insensitive manner (Postgres)",
|
||||||
Fn: testSearchOnlyPublicChannels,
|
Fn: testSearchChannelsInCaseInsensitiveMannerPostgres,
|
||||||
Tags: []string{EngineAll},
|
Tags: []string{EnginePostgres},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
Name: "Should support to autocomplete having a hyphen as the last character",
|
Name: "Should support to autocomplete having a hyphen as the last character",
|
||||||
@@ -76,94 +86,148 @@ func TestSearchChannelStore(t *testing.T, s store.Store, testEngine *SearchTestE
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testAutocompleteChannelByName(t *testing.T, th *SearchTestHelper) {
|
func testAutocompleteChannelByName(t *testing.T, th *SearchTestHelper) {
|
||||||
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "Channel Alternate", "Channel Alternate", model.ChannelTypeOpen, false)
|
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "Channel Alternate", "Channel Alternate", model.ChannelTypeOpen, th.User, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer th.deleteChannel(alternate)
|
defer th.deleteChannel(alternate)
|
||||||
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, "channel-a", false)
|
|
||||||
|
private, err := th.createChannel(th.Team.Id, "channel-altprivate", "Channel AltPrivate", "Channel Private", model.ChannelTypePrivate, th.User, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
|
defer th.deleteChannel(private)
|
||||||
|
|
||||||
|
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-a", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id, private.Id}, res)
|
||||||
|
|
||||||
|
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "channel-a", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.checkChannelIdsMatchWithTeamData(t, []string{th.ChannelBasic.Id, alternate.Id, private.Id, th.ChannelAnotherTeam.Id}, res2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAutocompleteChannelByNamePostgres(t *testing.T, th *SearchTestHelper) {
|
||||||
|
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "Channel Alternate", "Channel Alternate", model.ChannelTypeOpen, th.User, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer th.deleteChannel(alternate)
|
||||||
|
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-a", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelPrivate.Id, alternate.Id}, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAutocompleteChannelByDisplayName(t *testing.T, th *SearchTestHelper) {
|
func testAutocompleteChannelByDisplayName(t *testing.T, th *SearchTestHelper) {
|
||||||
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, false)
|
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer th.deleteChannel(alternate)
|
defer th.deleteChannel(alternate)
|
||||||
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, "ChannelA", false)
|
|
||||||
|
private, err := th.createChannel(th.Team.Id, "channel-altprivate", "ChannelAltPrivate", "Channel Private", model.ChannelTypePrivate, th.User, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
|
defer th.deleteChannel(private)
|
||||||
|
|
||||||
|
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "ChannelA", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id, private.Id}, res)
|
||||||
|
|
||||||
|
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "ChannelA", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.checkChannelIdsMatchWithTeamData(t, []string{th.ChannelBasic.Id, alternate.Id, private.Id, th.ChannelAnotherTeam.Id}, res2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAutocompleteChannelByNameSplittedWithDashChar(t *testing.T, th *SearchTestHelper) {
|
func testAutocompleteChannelByNameSplittedWithDashChar(t *testing.T, th *SearchTestHelper) {
|
||||||
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, false)
|
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer th.deleteChannel(alternate)
|
defer th.deleteChannel(alternate)
|
||||||
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, "channel-a", false)
|
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-a", false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
|
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAutocompleteChannelByNameSplittedWithUnderscoreChar(t *testing.T, th *SearchTestHelper) {
|
func testAutocompleteChannelByNameSplittedWithDashCharPostgres(t *testing.T, th *SearchTestHelper) {
|
||||||
alternate, err := th.createChannel(th.Team.Id, "channel_alternate", "ChannelAlternate", "", model.ChannelTypeOpen, false)
|
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer th.deleteChannel(alternate)
|
defer th.deleteChannel(alternate)
|
||||||
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, "channel_a", false)
|
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-a", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelPrivate.Id, alternate.Id}, res)
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAutocompleteChannelByNameSplittedWithUnderscoreChar(t *testing.T, th *SearchTestHelper) {
|
||||||
|
alternate, err := th.createChannel(th.Team.Id, "channel_alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
defer th.deleteChannel(alternate)
|
||||||
|
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel_a", false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
th.checkChannelIdsMatch(t, []string{alternate.Id}, res)
|
th.checkChannelIdsMatch(t, []string{alternate.Id}, res)
|
||||||
|
|
||||||
|
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "channel_a", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.checkChannelIdsMatchWithTeamData(t, []string{alternate.Id}, res2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testAutocompleteChannelByDisplayNameSplittedByWhitespaces(t *testing.T, th *SearchTestHelper) {
|
func testAutocompleteChannelByDisplayNameSplittedByWhitespaces(t *testing.T, th *SearchTestHelper) {
|
||||||
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "Channel Alternate", "", model.ChannelTypeOpen, false)
|
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "Channel Alternate", "", model.ChannelTypeOpen, th.User, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
defer th.deleteChannel(alternate)
|
defer th.deleteChannel(alternate)
|
||||||
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, "Channel A", false)
|
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "Channel A", false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
th.checkChannelIdsMatch(t, []string{alternate.Id}, res)
|
th.checkChannelIdsMatch(t, []string{alternate.Id}, res)
|
||||||
}
|
}
|
||||||
func testAutocompleteAllChannelsIfTermIsEmpty(t *testing.T, th *SearchTestHelper) {
|
func testAutocompleteAllChannelsIfTermIsEmpty(t *testing.T, th *SearchTestHelper) {
|
||||||
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "Channel Alternate", "", model.ChannelTypeOpen, false)
|
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "Channel Alternate", "", model.ChannelTypeOpen, th.User, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
other, err := th.createChannel(th.Team.Id, "other-channel", "Other Channel", "", model.ChannelTypeOpen, false)
|
other, err := th.createChannel(th.Team.Id, "other-channel", "Other Channel", "", model.ChannelTypeOpen, th.User, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer th.deleteChannel(alternate)
|
defer th.deleteChannel(alternate)
|
||||||
defer th.deleteChannel(other)
|
defer th.deleteChannel(other)
|
||||||
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, "", false)
|
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "", false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id, other.Id}, res)
|
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelPrivate.Id, alternate.Id, other.Id}, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSearchChannelsInCaseInsensitiveManner(t *testing.T, th *SearchTestHelper) {
|
func testSearchChannelsInCaseInsensitiveManner(t *testing.T, th *SearchTestHelper) {
|
||||||
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, false)
|
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer th.deleteChannel(alternate)
|
defer th.deleteChannel(alternate)
|
||||||
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, "channela", false)
|
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channela", false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
|
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
|
||||||
res, err = th.Store.Channel().AutocompleteInTeam(th.Team.Id, "ChAnNeL-a", false)
|
res, err = th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "ChAnNeL-a", false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
|
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
|
||||||
|
|
||||||
|
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "channela", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.checkChannelIdsMatchWithTeamData(t, []string{th.ChannelAnotherTeam.Id, th.ChannelBasic.Id, alternate.Id}, res2)
|
||||||
|
res2, err = th.Store.Channel().Autocomplete(th.User.Id, "ChAnNeL-a", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.checkChannelIdsMatchWithTeamData(t, []string{th.ChannelAnotherTeam.Id, th.ChannelBasic.Id, alternate.Id}, res2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSearchOnlyPublicChannels(t *testing.T, th *SearchTestHelper) {
|
func testSearchChannelsInCaseInsensitiveMannerPostgres(t *testing.T, th *SearchTestHelper) {
|
||||||
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypePrivate, false)
|
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer th.deleteChannel(alternate)
|
defer th.deleteChannel(alternate)
|
||||||
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, "channel-a", false)
|
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channela", false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id}, res)
|
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
|
||||||
|
res, err = th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "ChAnNeL-a", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelPrivate.Id, alternate.Id}, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSearchShouldSupportHavingHyphenAsLastCharacter(t *testing.T, th *SearchTestHelper) {
|
func testSearchShouldSupportHavingHyphenAsLastCharacter(t *testing.T, th *SearchTestHelper) {
|
||||||
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, false)
|
alternate, err := th.createChannel(th.Team.Id, "channel-alternate", "ChannelAlternate", "", model.ChannelTypeOpen, th.User, false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
defer th.deleteChannel(alternate)
|
defer th.deleteChannel(alternate)
|
||||||
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, "channel-", false)
|
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-", false)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, alternate.Id}, res)
|
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelPrivate.Id, alternate.Id}, res)
|
||||||
|
|
||||||
|
res2, err := th.Store.Channel().Autocomplete(th.User.Id, "channel-", false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
th.checkChannelIdsMatchWithTeamData(t, []string{th.ChannelAnotherTeam.Id, th.ChannelBasic.Id, th.ChannelPrivate.Id, alternate.Id}, res2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func testSearchShouldSupportAutocompleteWithArchivedChannels(t *testing.T, th *SearchTestHelper) {
|
func testSearchShouldSupportAutocompleteWithArchivedChannels(t *testing.T, th *SearchTestHelper) {
|
||||||
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, "channel-", true)
|
res, err := th.Store.Channel().AutocompleteInTeam(th.Team.Id, th.User.Id, "channel-", true)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelDeleted.Id}, res)
|
th.checkChannelIdsMatch(t, []string{th.ChannelBasic.Id, th.ChannelPrivate.Id, th.ChannelDeleted.Id}, res)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -60,19 +60,19 @@ func (th *SearchTestHelper) SetupBasicFixtures() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create channels
|
// Create channels
|
||||||
channelBasic, err := th.createChannel(team.Id, "channel-a", "ChannelA", "", model.ChannelTypeOpen, false)
|
channelBasic, err := th.createChannel(team.Id, "channel-a", "ChannelA", "", model.ChannelTypeOpen, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
channelPrivate, err := th.createChannel(team.Id, "channel-private", "ChannelPrivate", "", model.ChannelTypePrivate, false)
|
channelPrivate, err := th.createChannel(team.Id, "channel-private", "ChannelPrivate", "", model.ChannelTypePrivate, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
channelDeleted, err := th.createChannel(team.Id, "channel-deleted", "ChannelA (deleted)", "", model.ChannelTypeOpen, true)
|
channelDeleted, err := th.createChannel(team.Id, "channel-deleted", "ChannelA (deleted)", "", model.ChannelTypeOpen, nil, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
channelAnotherTeam, err := th.createChannel(anotherTeam.Id, "channel-a", "ChannelA", "", model.ChannelTypeOpen, false)
|
channelAnotherTeam, err := th.createChannel(anotherTeam.Id, "channel-a", "ChannelA", "", model.ChannelTypeOpen, nil, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -239,7 +239,7 @@ func (th *SearchTestHelper) deleteBot(botID string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (th *SearchTestHelper) createChannel(teamID, name, displayName, purpose string, channelType model.ChannelType, deleted bool) (*model.Channel, error) {
|
func (th *SearchTestHelper) createChannel(teamID, name, displayName, purpose string, channelType model.ChannelType, user *model.User, deleted bool) (*model.Channel, error) {
|
||||||
channel, err := th.Store.Channel().Save(&model.Channel{
|
channel, err := th.Store.Channel().Save(&model.Channel{
|
||||||
TeamId: teamID,
|
TeamId: teamID,
|
||||||
DisplayName: displayName,
|
DisplayName: displayName,
|
||||||
@@ -251,6 +251,13 @@ func (th *SearchTestHelper) createChannel(teamID, name, displayName, purpose str
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if user != nil {
|
||||||
|
err = th.addUserToChannels(user, []string{channel.Id})
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if deleted {
|
if deleted {
|
||||||
err := th.Store.Channel().Delete(channel.Id, model.GetMillis())
|
err := th.Store.Channel().Delete(channel.Id, model.GetMillis())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -474,6 +481,15 @@ func (th *SearchTestHelper) checkChannelIdsMatch(t *testing.T, expected []string
|
|||||||
require.ElementsMatch(t, expected, channelIds)
|
require.ElementsMatch(t, expected, channelIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (th *SearchTestHelper) checkChannelIdsMatchWithTeamData(t *testing.T, expected []string, results model.ChannelListWithTeamData) {
|
||||||
|
t.Helper()
|
||||||
|
channelIds := make([]string, len(results))
|
||||||
|
for i, channel := range results {
|
||||||
|
channelIds[i] = channel.Id
|
||||||
|
}
|
||||||
|
require.ElementsMatch(t, expected, channelIds)
|
||||||
|
}
|
||||||
|
|
||||||
type ByChannelDisplayName model.ChannelList
|
type ByChannelDisplayName model.ChannelList
|
||||||
|
|
||||||
func (s ByChannelDisplayName) Len() int { return len(s) }
|
func (s ByChannelDisplayName) Len() int { return len(s) }
|
||||||
|
|||||||
@@ -94,6 +94,15 @@ type channelMemberWithSchemeRoles struct {
|
|||||||
MsgCountRoot int64
|
MsgCountRoot int64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type channelMemberWithTeamWithSchemeRoles struct {
|
||||||
|
channelMemberWithSchemeRoles
|
||||||
|
TeamDisplayName string
|
||||||
|
TeamName string
|
||||||
|
TeamUpdateAt int64
|
||||||
|
}
|
||||||
|
|
||||||
|
type channelMemberWithTeamWithSchemeRolesList []channelMemberWithTeamWithSchemeRoles
|
||||||
|
|
||||||
func channelMemberSliceColumns() []string {
|
func channelMemberSliceColumns() []string {
|
||||||
return []string{"ChannelId", "UserId", "Roles", "LastViewedAt", "MsgCount", "MsgCountRoot", "MentionCount", "MentionCountRoot", "NotifyProps", "LastUpdateAt", "SchemeUser", "SchemeAdmin", "SchemeGuest"}
|
return []string{"ChannelId", "UserId", "Roles", "LastViewedAt", "MsgCount", "MsgCountRoot", "MentionCount", "MentionCountRoot", "NotifyProps", "LastUpdateAt", "SchemeUser", "SchemeAdmin", "SchemeGuest"}
|
||||||
}
|
}
|
||||||
@@ -250,6 +259,73 @@ func (db channelMemberWithSchemeRoles) ToModel() *model.ChannelMember {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is almost an entire copy of the above method with team information added.
|
||||||
|
func (db channelMemberWithTeamWithSchemeRoles) ToModel() *model.ChannelMemberWithTeamData {
|
||||||
|
// Identify any system-wide scheme derived roles that are in "Roles" field due to not yet being migrated,
|
||||||
|
// and exclude them from ExplicitRoles field.
|
||||||
|
schemeGuest := db.SchemeGuest.Valid && db.SchemeGuest.Bool
|
||||||
|
schemeUser := db.SchemeUser.Valid && db.SchemeUser.Bool
|
||||||
|
schemeAdmin := db.SchemeAdmin.Valid && db.SchemeAdmin.Bool
|
||||||
|
|
||||||
|
defaultTeamGuestRole := ""
|
||||||
|
if db.TeamSchemeDefaultGuestRole.Valid {
|
||||||
|
defaultTeamGuestRole = db.TeamSchemeDefaultGuestRole.String
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultTeamUserRole := ""
|
||||||
|
if db.TeamSchemeDefaultUserRole.Valid {
|
||||||
|
defaultTeamUserRole = db.TeamSchemeDefaultUserRole.String
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultTeamAdminRole := ""
|
||||||
|
if db.TeamSchemeDefaultAdminRole.Valid {
|
||||||
|
defaultTeamAdminRole = db.TeamSchemeDefaultAdminRole.String
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultChannelGuestRole := ""
|
||||||
|
if db.ChannelSchemeDefaultGuestRole.Valid {
|
||||||
|
defaultChannelGuestRole = db.ChannelSchemeDefaultGuestRole.String
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultChannelUserRole := ""
|
||||||
|
if db.ChannelSchemeDefaultUserRole.Valid {
|
||||||
|
defaultChannelUserRole = db.ChannelSchemeDefaultUserRole.String
|
||||||
|
}
|
||||||
|
|
||||||
|
defaultChannelAdminRole := ""
|
||||||
|
if db.ChannelSchemeDefaultAdminRole.Valid {
|
||||||
|
defaultChannelAdminRole = db.ChannelSchemeDefaultAdminRole.String
|
||||||
|
}
|
||||||
|
|
||||||
|
rolesResult := getChannelRoles(
|
||||||
|
schemeGuest, schemeUser, schemeAdmin,
|
||||||
|
defaultTeamGuestRole, defaultTeamUserRole, defaultTeamAdminRole,
|
||||||
|
defaultChannelGuestRole, defaultChannelUserRole, defaultChannelAdminRole,
|
||||||
|
strings.Fields(db.Roles),
|
||||||
|
)
|
||||||
|
return &model.ChannelMemberWithTeamData{
|
||||||
|
ChannelMember: model.ChannelMember{
|
||||||
|
ChannelId: db.ChannelId,
|
||||||
|
UserId: db.UserId,
|
||||||
|
Roles: strings.Join(rolesResult.roles, " "),
|
||||||
|
LastViewedAt: db.LastViewedAt,
|
||||||
|
MsgCount: db.MsgCount,
|
||||||
|
MsgCountRoot: db.MsgCountRoot,
|
||||||
|
MentionCount: db.MentionCount,
|
||||||
|
MentionCountRoot: db.MentionCountRoot,
|
||||||
|
NotifyProps: db.NotifyProps,
|
||||||
|
LastUpdateAt: db.LastUpdateAt,
|
||||||
|
SchemeAdmin: rolesResult.schemeAdmin,
|
||||||
|
SchemeUser: rolesResult.schemeUser,
|
||||||
|
SchemeGuest: rolesResult.schemeGuest,
|
||||||
|
ExplicitRoles: strings.Join(rolesResult.explicitRoles, " "),
|
||||||
|
},
|
||||||
|
TeamName: db.TeamName,
|
||||||
|
TeamDisplayName: db.TeamDisplayName,
|
||||||
|
TeamUpdateAt: db.TeamUpdateAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (db channelMemberWithSchemeRolesList) ToModel() model.ChannelMembers {
|
func (db channelMemberWithSchemeRolesList) ToModel() model.ChannelMembers {
|
||||||
cms := model.ChannelMembers{}
|
cms := model.ChannelMembers{}
|
||||||
|
|
||||||
@@ -260,6 +336,16 @@ func (db channelMemberWithSchemeRolesList) ToModel() model.ChannelMembers {
|
|||||||
return cms
|
return cms
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (db channelMemberWithTeamWithSchemeRolesList) ToModel() model.ChannelMembersWithTeamData {
|
||||||
|
cms := model.ChannelMembersWithTeamData{}
|
||||||
|
|
||||||
|
for _, cm := range db {
|
||||||
|
cms = append(cms, *cm.ToModel())
|
||||||
|
}
|
||||||
|
|
||||||
|
return cms
|
||||||
|
}
|
||||||
|
|
||||||
type allChannelMember struct {
|
type allChannelMember struct {
|
||||||
ChannelId string
|
ChannelId string
|
||||||
Roles string
|
Roles string
|
||||||
@@ -999,6 +1085,73 @@ func (s SqlChannelStore) GetChannels(teamId string, userId string, includeDelete
|
|||||||
return channels, nil
|
return channels, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) GetChannelsByUser(userId string, includeDeleted bool, lastDeleteAt, pageSize int, fromChannelID string) (model.ChannelList, error) {
|
||||||
|
query := s.getQueryBuilder().
|
||||||
|
Select("Channels.*").
|
||||||
|
From("Channels, ChannelMembers").
|
||||||
|
Where(
|
||||||
|
sq.And{
|
||||||
|
sq.Expr("Id = ChannelId"),
|
||||||
|
sq.Eq{"UserId": userId},
|
||||||
|
},
|
||||||
|
).
|
||||||
|
OrderBy("Id ASC")
|
||||||
|
|
||||||
|
if fromChannelID != "" {
|
||||||
|
query = query.Where(sq.Gt{"Id": fromChannelID})
|
||||||
|
}
|
||||||
|
|
||||||
|
if pageSize != -1 {
|
||||||
|
query = query.Limit(uint64(pageSize))
|
||||||
|
}
|
||||||
|
|
||||||
|
if includeDeleted {
|
||||||
|
if lastDeleteAt != 0 {
|
||||||
|
// We filter by non-archived, and archived >= a timestamp.
|
||||||
|
query = query.Where(sq.Or{
|
||||||
|
sq.Eq{"DeleteAt": 0},
|
||||||
|
sq.GtOrEq{"DeleteAt": lastDeleteAt},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// If lastDeleteAt is not set, we include everything. That means no filter is needed.
|
||||||
|
} else {
|
||||||
|
// Don't include archived channels.
|
||||||
|
query = query.Where(sq.Eq{"DeleteAt": 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
sql, args, err := query.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "getchannels_tosql")
|
||||||
|
}
|
||||||
|
|
||||||
|
var channels model.ChannelList
|
||||||
|
_, err = s.GetReplica().Select(&channels, sql, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to get channels with UserId=%s", userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(channels) == 0 {
|
||||||
|
return nil, store.NewErrNotFound("Channel", "userId="+userId)
|
||||||
|
}
|
||||||
|
|
||||||
|
return channels, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) GetAllChannelMembersById(channelID string) ([]string, error) {
|
||||||
|
var dbMembers channelMemberWithSchemeRolesList
|
||||||
|
_, err := s.GetReplica().Select(&dbMembers, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelId = :ChannelId", map[string]interface{}{"ChannelId": channelID})
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to get ChannelMembers with channelID=%s", channelID)
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([]string, 0, len(dbMembers))
|
||||||
|
for _, member := range dbMembers.ToModel() {
|
||||||
|
res = append(res, member.UserId)
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s SqlChannelStore) GetAllChannels(offset, limit int, opts store.ChannelSearchOpts) (model.ChannelListWithTeamData, error) {
|
func (s SqlChannelStore) GetAllChannels(offset, limit int, opts store.ChannelSearchOpts) (model.ChannelListWithTeamData, error) {
|
||||||
query := s.getAllChannelsQuery(opts, false)
|
query := s.getAllChannelsQuery(opts, false)
|
||||||
|
|
||||||
@@ -1397,7 +1550,7 @@ func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int, userId
|
|||||||
return channels, nil
|
return channels, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var ChannelMembersWithSchemeSelectQuery = `
|
var channelMembersForTeamWithSchemeSelectQuery = `
|
||||||
SELECT
|
SELECT
|
||||||
ChannelMembers.*,
|
ChannelMembers.*,
|
||||||
TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole,
|
TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole,
|
||||||
@@ -1418,6 +1571,30 @@ var ChannelMembersWithSchemeSelectQuery = `
|
|||||||
Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id
|
Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id
|
||||||
`
|
`
|
||||||
|
|
||||||
|
var channelMembersWithSchemeSelectQuery = `
|
||||||
|
SELECT
|
||||||
|
ChannelMembers.*,
|
||||||
|
COALESCE(Teams.DisplayName, '') TeamDisplayName,
|
||||||
|
COALESCE(Teams.Name, '') TeamName,
|
||||||
|
COALESCE(Teams.UpdateAt, 0) TeamUpdateAt,
|
||||||
|
TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole,
|
||||||
|
TeamScheme.DefaultChannelUserRole TeamSchemeDefaultUserRole,
|
||||||
|
TeamScheme.DefaultChannelAdminRole TeamSchemeDefaultAdminRole,
|
||||||
|
ChannelScheme.DefaultChannelGuestRole ChannelSchemeDefaultGuestRole,
|
||||||
|
ChannelScheme.DefaultChannelUserRole ChannelSchemeDefaultUserRole,
|
||||||
|
ChannelScheme.DefaultChannelAdminRole ChannelSchemeDefaultAdminRole
|
||||||
|
FROM
|
||||||
|
ChannelMembers
|
||||||
|
INNER JOIN
|
||||||
|
Channels ON ChannelMembers.ChannelId = Channels.Id
|
||||||
|
LEFT JOIN
|
||||||
|
Schemes ChannelScheme ON Channels.SchemeId = ChannelScheme.Id
|
||||||
|
LEFT JOIN
|
||||||
|
Teams ON Channels.TeamId = Teams.Id
|
||||||
|
LEFT JOIN
|
||||||
|
Schemes TeamScheme ON Teams.SchemeId = TeamScheme.Id
|
||||||
|
`
|
||||||
|
|
||||||
func (s SqlChannelStore) SaveMultipleMembers(members []*model.ChannelMember) ([]*model.ChannelMember, error) {
|
func (s SqlChannelStore) SaveMultipleMembers(members []*model.ChannelMember) ([]*model.ChannelMember, error) {
|
||||||
for _, member := range members {
|
for _, member := range members {
|
||||||
defer s.InvalidateAllChannelMembersForUser(member.UserId)
|
defer s.InvalidateAllChannelMembersForUser(member.UserId)
|
||||||
@@ -1613,7 +1790,7 @@ func (s SqlChannelStore) UpdateMultipleMembers(members []*model.ChannelMember) (
|
|||||||
|
|
||||||
// TODO: Get this out of the transaction when is possible
|
// TODO: Get this out of the transaction when is possible
|
||||||
var dbMember channelMemberWithSchemeRoles
|
var dbMember channelMemberWithSchemeRoles
|
||||||
if err := transaction.SelectOne(&dbMember, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId", map[string]interface{}{"ChannelId": member.ChannelId, "UserId": member.UserId}); err != nil {
|
if err := transaction.SelectOne(&dbMember, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId", map[string]interface{}{"ChannelId": member.ChannelId, "UserId": member.UserId}); err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", member.ChannelId, member.UserId))
|
return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", member.ChannelId, member.UserId))
|
||||||
}
|
}
|
||||||
@@ -1668,7 +1845,7 @@ func (s SqlChannelStore) UpdateMemberNotifyProps(channelID, userID string, props
|
|||||||
}
|
}
|
||||||
|
|
||||||
var dbMember channelMemberWithSchemeRoles
|
var dbMember channelMemberWithSchemeRoles
|
||||||
if err2 := tx.SelectOne(&dbMember, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId", map[string]interface{}{"ChannelId": channelID, "UserId": userID}); err2 != nil {
|
if err2 := tx.SelectOne(&dbMember, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId", map[string]interface{}{"ChannelId": channelID, "UserId": userID}); err2 != nil {
|
||||||
if err2 == sql.ErrNoRows {
|
if err2 == sql.ErrNoRows {
|
||||||
return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", channelID, userID))
|
return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", channelID, userID))
|
||||||
}
|
}
|
||||||
@@ -1684,7 +1861,7 @@ func (s SqlChannelStore) UpdateMemberNotifyProps(channelID, userID string, props
|
|||||||
|
|
||||||
func (s SqlChannelStore) GetMembers(channelId string, offset, limit int) (model.ChannelMembers, error) {
|
func (s SqlChannelStore) GetMembers(channelId string, offset, limit int) (model.ChannelMembers, error) {
|
||||||
var dbMembers channelMemberWithSchemeRolesList
|
var dbMembers channelMemberWithSchemeRolesList
|
||||||
_, err := s.GetReplica().Select(&dbMembers, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelId = :ChannelId LIMIT :Limit OFFSET :Offset", map[string]interface{}{"ChannelId": channelId, "Limit": limit, "Offset": offset})
|
_, err := s.GetReplica().Select(&dbMembers, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelId = :ChannelId LIMIT :Limit OFFSET :Offset", map[string]interface{}{"ChannelId": channelId, "Limit": limit, "Offset": offset})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to get ChannelMembers with channelId=%s", channelId)
|
return nil, errors.Wrapf(err, "failed to get ChannelMembers with channelId=%s", channelId)
|
||||||
}
|
}
|
||||||
@@ -1714,7 +1891,7 @@ func (s SqlChannelStore) GetChannelMembersTimezones(channelId string) ([]model.S
|
|||||||
func (s SqlChannelStore) GetMember(ctx context.Context, channelId string, userId string) (*model.ChannelMember, error) {
|
func (s SqlChannelStore) GetMember(ctx context.Context, channelId string, userId string) (*model.ChannelMember, error) {
|
||||||
var dbMember channelMemberWithSchemeRoles
|
var dbMember channelMemberWithSchemeRoles
|
||||||
|
|
||||||
if err := s.DBFromContext(ctx).SelectOne(&dbMember, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil {
|
if err := s.DBFromContext(ctx).SelectOne(&dbMember, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId = :UserId", map[string]interface{}{"ChannelId": channelId, "UserId": userId}); err != nil {
|
||||||
if err == sql.ErrNoRows {
|
if err == sql.ErrNoRows {
|
||||||
return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", channelId, userId))
|
return nil, store.NewErrNotFound("ChannelMember", fmt.Sprintf("channelId=%s, userId=%s", channelId, userId))
|
||||||
}
|
}
|
||||||
@@ -2397,6 +2574,34 @@ func (s SqlChannelStore) GetChannelsByIds(channelIds []string, includeDeleted bo
|
|||||||
return channels, nil
|
return channels, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) GetChannelsWithTeamDataByIds(channelIDs []string, includeDeleted bool) ([]*model.ChannelWithTeamData, error) {
|
||||||
|
query := s.getQueryBuilder().
|
||||||
|
Select("c.*",
|
||||||
|
"COALESCE(t.DisplayName, '') As TeamDisplayName",
|
||||||
|
"COALESCE(t.Name, '') AS TeamName",
|
||||||
|
"COALESCE(t.UpdateAt, 0) AS TeamUpdateAt").
|
||||||
|
From("Channels c").
|
||||||
|
LeftJoin("Teams t ON c.TeamId = t.Id").
|
||||||
|
Where(sq.Eq{"c.Id": channelIDs}).
|
||||||
|
OrderBy("c.Name")
|
||||||
|
|
||||||
|
if !includeDeleted {
|
||||||
|
query = query.Where(sq.Eq{"c.DeleteAt": 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
sql, args, err := query.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "getChannelsWithTeamData_tosql")
|
||||||
|
}
|
||||||
|
|
||||||
|
var channels []*model.ChannelWithTeamData
|
||||||
|
_, err = s.GetReplica().Select(&channels, sql, args...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, errors.Wrap(err, "failed to find Channels")
|
||||||
|
}
|
||||||
|
return channels, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s SqlChannelStore) GetForPost(postId string) (*model.Channel, error) {
|
func (s SqlChannelStore) GetForPost(postId string) (*model.Channel, error) {
|
||||||
channel := &model.Channel{}
|
channel := &model.Channel{}
|
||||||
if err := s.GetReplica().SelectOne(
|
if err := s.GetReplica().SelectOne(
|
||||||
@@ -2446,7 +2651,7 @@ func (s SqlChannelStore) AnalyticsDeletedTypeCount(teamId string, channelType st
|
|||||||
|
|
||||||
func (s SqlChannelStore) GetMembersForUser(teamId string, userId string) (model.ChannelMembers, error) {
|
func (s SqlChannelStore) GetMembersForUser(teamId string, userId string) (model.ChannelMembers, error) {
|
||||||
var dbMembers channelMemberWithSchemeRolesList
|
var dbMembers channelMemberWithSchemeRolesList
|
||||||
_, err := s.GetReplica().Select(&dbMembers, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.UserId = :UserId AND (Teams.Id = :TeamId OR Teams.Id = '' OR Teams.Id IS NULL)", map[string]interface{}{"TeamId": teamId, "UserId": userId})
|
_, err := s.GetReplica().Select(&dbMembers, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelMembers.UserId = :UserId AND (Teams.Id = :TeamId OR Teams.Id = '' OR Teams.Id IS NULL)", map[string]interface{}{"TeamId": teamId, "UserId": userId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to find ChannelMembers data with teamId=%s and userId=%s", teamId, userId)
|
return nil, errors.Wrapf(err, "failed to find ChannelMembers data with teamId=%s and userId=%s", teamId, userId)
|
||||||
}
|
}
|
||||||
@@ -2454,60 +2659,96 @@ func (s SqlChannelStore) GetMembersForUser(teamId string, userId string) (model.
|
|||||||
return dbMembers.ToModel(), nil
|
return dbMembers.ToModel(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SqlChannelStore) GetMembersForUserWithPagination(teamId, userId string, page, perPage int) (model.ChannelMembers, error) {
|
func (s SqlChannelStore) GetMembersForUserWithPagination(userId string, page, perPage int) (model.ChannelMembersWithTeamData, error) {
|
||||||
var dbMembers channelMemberWithSchemeRolesList
|
var dbMembers channelMemberWithTeamWithSchemeRolesList
|
||||||
offset := page * perPage
|
offset := page * perPage
|
||||||
_, err := s.GetReplica().Select(&dbMembers, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.UserId = :UserId Limit :Limit Offset :Offset", map[string]interface{}{"TeamId": teamId, "UserId": userId, "Limit": perPage, "Offset": offset})
|
_, err := s.GetReplica().Select(&dbMembers, channelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.UserId = :UserId ORDER BY ChannelId ASC Limit :Limit Offset :Offset", map[string]interface{}{"UserId": userId, "Limit": perPage, "Offset": offset})
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to find ChannelMembers data with teamId=%s and userId=%s", teamId, userId)
|
return nil, errors.Wrapf(err, "failed to find ChannelMembers data with and userId=%s", userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
return dbMembers.ToModel(), nil
|
return dbMembers.ToModel(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SqlChannelStore) AutocompleteInTeam(teamId string, term string, includeDeleted bool) (model.ChannelList, error) {
|
func (s SqlChannelStore) GetTeamMembersForChannel(channelID string) ([]string, error) {
|
||||||
deleteFilter := "AND Channels.DeleteAt = 0"
|
teamMemberIDs := []string{}
|
||||||
|
if err := s.GetReplicaX().Select(&teamMemberIDs, `SELECT tm.UserId
|
||||||
|
FROM Channels c, Teams t, TeamMembers tm
|
||||||
|
WHERE
|
||||||
|
c.TeamId=t.Id
|
||||||
|
AND
|
||||||
|
t.Id=tm.TeamId
|
||||||
|
AND
|
||||||
|
c.Id = ?`,
|
||||||
|
channelID); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "error while getting team members for a channel")
|
||||||
|
}
|
||||||
|
|
||||||
|
return teamMemberIDs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) Autocomplete(userID, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
|
||||||
|
deleteFilter := "AND c.DeleteAt = 0"
|
||||||
if includeDeleted {
|
if includeDeleted {
|
||||||
deleteFilter = ""
|
deleteFilter = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
queryFormat := `
|
return s.performGlobalSearch(`
|
||||||
SELECT
|
SELECT
|
||||||
Channels.*
|
c.*, t.DisplayName AS TeamDisplayName, t.Name AS TeamName, t.UpdateAt AS TeamUpdateAt
|
||||||
FROM
|
FROM
|
||||||
Channels
|
Channels c, Teams t, TeamMembers tm
|
||||||
JOIN
|
WHERE
|
||||||
PublicChannels c ON (c.Id = Channels.Id)
|
c.TeamId=t.Id
|
||||||
WHERE
|
AND
|
||||||
Channels.TeamId = :TeamId
|
t.Id=tm.TeamId
|
||||||
` + deleteFilter + `
|
AND
|
||||||
%v
|
tm.UserId = :UserId
|
||||||
LIMIT ` + strconv.Itoa(model.ChannelSearchDefaultLimit)
|
`+deleteFilter+`
|
||||||
|
SEARCH_CLAUSE
|
||||||
|
AND (
|
||||||
|
c.Type != 'P'
|
||||||
|
OR (
|
||||||
|
c.Type = 'P'
|
||||||
|
AND c.Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ORDER BY c.DisplayName
|
||||||
|
`, term, map[string]interface{}{
|
||||||
|
"UserId": userID,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
var channels model.ChannelList
|
func (s SqlChannelStore) AutocompleteInTeam(teamID, userID, term string, includeDeleted bool) (model.ChannelList, error) {
|
||||||
|
deleteFilter := "AND c.DeleteAt = 0"
|
||||||
if likeClause, likeTerm := s.buildLIKEClause(term, "c.Name, c.DisplayName, c.Purpose"); likeClause == "" {
|
if includeDeleted {
|
||||||
if _, err := s.GetReplica().Select(&channels, fmt.Sprintf(queryFormat, ""), map[string]interface{}{"TeamId": teamId}); err != nil {
|
deleteFilter = ""
|
||||||
return nil, errors.Wrapf(err, "failed to find Channels with term='%s'", term)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Using a UNION results in index_merge and fulltext queries and is much faster than the ref
|
|
||||||
// query you would get using an OR of the LIKE and full-text clauses.
|
|
||||||
fulltextClause, fulltextTerm := s.buildFulltextClause(term, "c.Name, c.DisplayName, c.Purpose")
|
|
||||||
likeQuery := fmt.Sprintf(queryFormat, "AND "+likeClause)
|
|
||||||
fulltextQuery := fmt.Sprintf(queryFormat, "AND "+fulltextClause)
|
|
||||||
query := fmt.Sprintf("(%v) UNION (%v) LIMIT 50", likeQuery, fulltextQuery)
|
|
||||||
|
|
||||||
if _, err := s.GetReplica().Select(&channels, query, map[string]interface{}{"TeamId": teamId, "LikeTerm": likeTerm, "FulltextTerm": fulltextTerm}); err != nil {
|
|
||||||
return nil, errors.Wrapf(err, "failed to find Channels with term='%s'", term)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(channels, func(a, b int) bool {
|
return s.performSearch(`
|
||||||
return strings.ToLower(channels[a].DisplayName) < strings.ToLower(channels[b].DisplayName)
|
SELECT
|
||||||
|
*
|
||||||
|
FROM
|
||||||
|
Channels c
|
||||||
|
WHERE
|
||||||
|
c.TeamId = :TeamId
|
||||||
|
`+deleteFilter+`
|
||||||
|
SEARCH_CLAUSE
|
||||||
|
AND (
|
||||||
|
c.Type != 'P'
|
||||||
|
OR (
|
||||||
|
c.Type = 'P'
|
||||||
|
AND c.Id IN (SELECT ChannelId FROM ChannelMembers WHERE UserId = :UserId)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
ORDER BY c.DisplayName
|
||||||
|
LIMIT :Limit
|
||||||
|
`, term, map[string]interface{}{
|
||||||
|
"TeamId": teamID,
|
||||||
|
"UserId": userID,
|
||||||
|
"Limit": model.ChannelSearchDefaultLimit,
|
||||||
})
|
})
|
||||||
return channels, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s SqlChannelStore) AutocompleteInTeamForSearch(teamId string, userId string, term string, includeDeleted bool) (model.ChannelList, error) {
|
func (s SqlChannelStore) AutocompleteInTeamForSearch(teamId string, userId string, term string, includeDeleted bool) (model.ChannelList, error) {
|
||||||
@@ -2959,6 +3200,27 @@ func (s SqlChannelStore) performSearch(searchQuery string, term string, paramete
|
|||||||
return channels, nil
|
return channels, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s SqlChannelStore) performGlobalSearch(searchQuery string, term string, parameters map[string]interface{}) (model.ChannelListWithTeamData, error) {
|
||||||
|
likeClause, likeTerm := s.buildLIKEClause(term, "c.Name, c.DisplayName, c.Purpose")
|
||||||
|
if likeTerm == "" {
|
||||||
|
// If the likeTerm is empty after preparing, then don't bother searching.
|
||||||
|
searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "", 1)
|
||||||
|
} else {
|
||||||
|
parameters["LikeTerm"] = likeTerm
|
||||||
|
fulltextClause, fulltextTerm := s.buildFulltextClause(term, "c.Name, c.DisplayName, c.Purpose")
|
||||||
|
parameters["FulltextTerm"] = fulltextTerm
|
||||||
|
searchQuery = strings.Replace(searchQuery, "SEARCH_CLAUSE", "AND ("+likeClause+" OR "+fulltextClause+")", 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
var channels model.ChannelListWithTeamData
|
||||||
|
|
||||||
|
if _, err := s.GetReplica().Select(&channels, searchQuery, parameters); err != nil {
|
||||||
|
return nil, errors.Wrapf(err, "failed to find Channels with term='%s'", term)
|
||||||
|
}
|
||||||
|
|
||||||
|
return channels, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (s SqlChannelStore) getSearchGroupChannelsQuery(userId, term string, isPostgreSQL bool) (string, map[string]interface{}) {
|
func (s SqlChannelStore) getSearchGroupChannelsQuery(userId, term string, isPostgreSQL bool) (string, map[string]interface{}) {
|
||||||
var query, baseLikeClause string
|
var query, baseLikeClause string
|
||||||
if isPostgreSQL {
|
if isPostgreSQL {
|
||||||
@@ -3064,7 +3326,7 @@ func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) (mo
|
|||||||
keys, props := MapStringsToQueryParams(userIds, "User")
|
keys, props := MapStringsToQueryParams(userIds, "User")
|
||||||
props["ChannelId"] = channelId
|
props["ChannelId"] = channelId
|
||||||
|
|
||||||
if _, err := s.GetReplica().Select(&dbMembers, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId IN "+keys, props); err != nil {
|
if _, err := s.GetReplica().Select(&dbMembers, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelMembers.ChannelId = :ChannelId AND ChannelMembers.UserId IN "+keys, props); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to find ChannelMembers with channelId=%s and userId in %v", channelId, userIds)
|
return nil, errors.Wrapf(err, "failed to find ChannelMembers with channelId=%s and userId in %v", channelId, userIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3077,7 +3339,7 @@ func (s SqlChannelStore) GetMembersByChannelIds(channelIds []string, userId stri
|
|||||||
keys, props := MapStringsToQueryParams(channelIds, "Channel")
|
keys, props := MapStringsToQueryParams(channelIds, "Channel")
|
||||||
props["UserId"] = userId
|
props["UserId"] = userId
|
||||||
|
|
||||||
if _, err := s.GetReplica().Select(&dbMembers, ChannelMembersWithSchemeSelectQuery+"WHERE ChannelMembers.UserId = :UserId AND ChannelMembers.ChannelId IN "+keys, props); err != nil {
|
if _, err := s.GetReplica().Select(&dbMembers, channelMembersForTeamWithSchemeSelectQuery+"WHERE ChannelMembers.UserId = :UserId AND ChannelMembers.ChannelId IN "+keys, props); err != nil {
|
||||||
return nil, errors.Wrapf(err, "failed to find ChannelMembers with userId=%s and channelId in %v", userId, channelIds)
|
return nil, errors.Wrapf(err, "failed to find ChannelMembers with userId=%s and channelId in %v", userId, channelIds)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3367,8 +3629,6 @@ func (s SqlChannelStore) GetChannelsBatchForIndexing(startTime, endTime int64, l
|
|||||||
FROM
|
FROM
|
||||||
Channels
|
Channels
|
||||||
WHERE
|
WHERE
|
||||||
Type = 'O'
|
|
||||||
AND
|
|
||||||
CreateAt >= :StartTime
|
CreateAt >= :StartTime
|
||||||
AND
|
AND
|
||||||
CreateAt < :EndTime
|
CreateAt < :EndTime
|
||||||
|
|||||||
@@ -179,6 +179,8 @@ type ChannelStore interface {
|
|||||||
GetDeletedByName(team_id string, name string) (*model.Channel, error)
|
GetDeletedByName(team_id string, name string) (*model.Channel, error)
|
||||||
GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error)
|
GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error)
|
||||||
GetChannels(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, error)
|
GetChannels(teamID string, userID string, includeDeleted bool, lastDeleteAt int) (model.ChannelList, error)
|
||||||
|
GetChannelsByUser(userID string, includeDeleted bool, lastDeleteAt, pageSize int, fromChannelID string) (model.ChannelList, error)
|
||||||
|
GetAllChannelMembersById(id string) ([]string, error)
|
||||||
GetAllChannels(page, perPage int, opts ChannelSearchOpts) (model.ChannelListWithTeamData, error)
|
GetAllChannels(page, perPage int, opts ChannelSearchOpts) (model.ChannelListWithTeamData, error)
|
||||||
GetAllChannelsCount(opts ChannelSearchOpts) (int64, error)
|
GetAllChannelsCount(opts ChannelSearchOpts) (int64, error)
|
||||||
GetMoreChannels(teamID string, userID string, offset int, limit int) (model.ChannelList, error)
|
GetMoreChannels(teamID string, userID string, offset int, limit int) (model.ChannelList, error)
|
||||||
@@ -189,6 +191,7 @@ type ChannelStore interface {
|
|||||||
GetTeamChannels(teamID string) (model.ChannelList, error)
|
GetTeamChannels(teamID string) (model.ChannelList, error)
|
||||||
GetAll(teamID string) ([]*model.Channel, error)
|
GetAll(teamID string) ([]*model.Channel, error)
|
||||||
GetChannelsByIds(channelIds []string, includeDeleted bool) ([]*model.Channel, error)
|
GetChannelsByIds(channelIds []string, includeDeleted bool) ([]*model.Channel, error)
|
||||||
|
GetChannelsWithTeamDataByIds(channelIds []string, includeDeleted bool) ([]*model.ChannelWithTeamData, error)
|
||||||
GetForPost(postID string) (*model.Channel, error)
|
GetForPost(postID string) (*model.Channel, error)
|
||||||
SaveMultipleMembers(members []*model.ChannelMember) ([]*model.ChannelMember, error)
|
SaveMultipleMembers(members []*model.ChannelMember) ([]*model.ChannelMember, error)
|
||||||
SaveMember(member *model.ChannelMember) (*model.ChannelMember, error)
|
SaveMember(member *model.ChannelMember) (*model.ChannelMember, error)
|
||||||
@@ -225,8 +228,10 @@ type ChannelStore interface {
|
|||||||
IncrementMentionCount(channelID string, userID string, updateThreads, isRoot bool) error
|
IncrementMentionCount(channelID string, userID string, updateThreads, isRoot bool) error
|
||||||
AnalyticsTypeCount(teamID string, channelType model.ChannelType) (int64, error)
|
AnalyticsTypeCount(teamID string, channelType model.ChannelType) (int64, error)
|
||||||
GetMembersForUser(teamID string, userID string) (model.ChannelMembers, error)
|
GetMembersForUser(teamID string, userID string) (model.ChannelMembers, error)
|
||||||
GetMembersForUserWithPagination(teamID, userID string, page, perPage int) (model.ChannelMembers, error)
|
GetTeamMembersForChannel(channelID string) ([]string, error)
|
||||||
AutocompleteInTeam(teamID string, term string, includeDeleted bool) (model.ChannelList, error)
|
GetMembersForUserWithPagination(userID string, page, perPage int) (model.ChannelMembersWithTeamData, error)
|
||||||
|
Autocomplete(userID, term string, includeDeleted bool) (model.ChannelListWithTeamData, error)
|
||||||
|
AutocompleteInTeam(teamID, userID, term string, includeDeleted bool) (model.ChannelList, error)
|
||||||
AutocompleteInTeamForSearch(teamID string, userID string, term string, includeDeleted bool) (model.ChannelList, error)
|
AutocompleteInTeamForSearch(teamID string, userID string, term string, includeDeleted bool) (model.ChannelList, error)
|
||||||
SearchAllChannels(term string, opts ChannelSearchOpts) (model.ChannelListWithTeamData, int64, error)
|
SearchAllChannels(term string, opts ChannelSearchOpts) (model.ChannelListWithTeamData, int64, error)
|
||||||
SearchInTeam(teamID string, term string, includeDeleted bool) (model.ChannelList, error)
|
SearchInTeam(teamID string, term string, includeDeleted bool) (model.ChannelList, error)
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlStore) {
|
|||||||
t.Run("GetChannelUnread", func(t *testing.T) { testGetChannelUnread(t, ss) })
|
t.Run("GetChannelUnread", func(t *testing.T) { testGetChannelUnread(t, ss) })
|
||||||
t.Run("Get", func(t *testing.T) { testChannelStoreGet(t, ss, s) })
|
t.Run("Get", func(t *testing.T) { testChannelStoreGet(t, ss, s) })
|
||||||
t.Run("GetChannelsByIds", func(t *testing.T) { testChannelStoreGetChannelsByIds(t, ss) })
|
t.Run("GetChannelsByIds", func(t *testing.T) { testChannelStoreGetChannelsByIds(t, ss) })
|
||||||
|
t.Run("GetChannelsWithTeamDataByIds", func(t *testing.T) { testGetChannelsWithTeamDataByIds(t, ss) })
|
||||||
t.Run("GetForPost", func(t *testing.T) { testChannelStoreGetForPost(t, ss) })
|
t.Run("GetForPost", func(t *testing.T) { testChannelStoreGetForPost(t, ss) })
|
||||||
t.Run("Restore", func(t *testing.T) { testChannelStoreRestore(t, ss) })
|
t.Run("Restore", func(t *testing.T) { testChannelStoreRestore(t, ss) })
|
||||||
t.Run("Delete", func(t *testing.T) { testChannelStoreDelete(t, ss) })
|
t.Run("Delete", func(t *testing.T) { testChannelStoreDelete(t, ss) })
|
||||||
@@ -78,6 +79,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlStore) {
|
|||||||
t.Run("RemoveMembers", func(t *testing.T) { testChannelRemoveMembers(t, ss) })
|
t.Run("RemoveMembers", func(t *testing.T) { testChannelRemoveMembers(t, ss) })
|
||||||
t.Run("ChannelDeleteMemberStore", func(t *testing.T) { testChannelDeleteMemberStore(t, ss) })
|
t.Run("ChannelDeleteMemberStore", func(t *testing.T) { testChannelDeleteMemberStore(t, ss) })
|
||||||
t.Run("GetChannels", func(t *testing.T) { testChannelStoreGetChannels(t, ss) })
|
t.Run("GetChannels", func(t *testing.T) { testChannelStoreGetChannels(t, ss) })
|
||||||
|
t.Run("GetChannelsByUser", func(t *testing.T) { testChannelStoreGetChannelsByUser(t, ss) })
|
||||||
t.Run("GetAllChannels", func(t *testing.T) { testChannelStoreGetAllChannels(t, ss, s) })
|
t.Run("GetAllChannels", func(t *testing.T) { testChannelStoreGetAllChannels(t, ss, s) })
|
||||||
t.Run("GetMoreChannels", func(t *testing.T) { testChannelStoreGetMoreChannels(t, ss) })
|
t.Run("GetMoreChannels", func(t *testing.T) { testChannelStoreGetMoreChannels(t, ss) })
|
||||||
t.Run("GetPrivateChannelsForTeam", func(t *testing.T) { testChannelStoreGetPrivateChannelsForTeam(t, ss) })
|
t.Run("GetPrivateChannelsForTeam", func(t *testing.T) { testChannelStoreGetPrivateChannelsForTeam(t, ss) })
|
||||||
@@ -97,6 +99,7 @@ func TestChannelStore(t *testing.T, ss store.Store, s SqlStore) {
|
|||||||
t.Run("GetGuestCount", func(t *testing.T) { testGetGuestCount(t, ss) })
|
t.Run("GetGuestCount", func(t *testing.T) { testGetGuestCount(t, ss) })
|
||||||
t.Run("SearchMore", func(t *testing.T) { testChannelStoreSearchMore(t, ss) })
|
t.Run("SearchMore", func(t *testing.T) { testChannelStoreSearchMore(t, ss) })
|
||||||
t.Run("SearchInTeam", func(t *testing.T) { testChannelStoreSearchInTeam(t, ss) })
|
t.Run("SearchInTeam", func(t *testing.T) { testChannelStoreSearchInTeam(t, ss) })
|
||||||
|
t.Run("Autocomplete", func(t *testing.T) { testAutocomplete(t, ss) })
|
||||||
t.Run("SearchArchivedInTeam", func(t *testing.T) { testChannelStoreSearchArchivedInTeam(t, ss, s) })
|
t.Run("SearchArchivedInTeam", func(t *testing.T) { testChannelStoreSearchArchivedInTeam(t, ss, s) })
|
||||||
t.Run("SearchForUserInTeam", func(t *testing.T) { testChannelStoreSearchForUserInTeam(t, ss) })
|
t.Run("SearchForUserInTeam", func(t *testing.T) { testChannelStoreSearchForUserInTeam(t, ss) })
|
||||||
t.Run("SearchAllChannels", func(t *testing.T) { testChannelStoreSearchAllChannels(t, ss) })
|
t.Run("SearchAllChannels", func(t *testing.T) { testChannelStoreSearchAllChannels(t, ss) })
|
||||||
@@ -536,6 +539,81 @@ func testChannelStoreGetChannelsByIds(t *testing.T, ss store.Store) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testGetChannelsWithTeamDataByIds(t *testing.T, ss store.Store) {
|
||||||
|
t1 := &model.Team{
|
||||||
|
DisplayName: "DisplayName",
|
||||||
|
Name: NewTestId(),
|
||||||
|
Email: MakeEmail(),
|
||||||
|
Type: model.TeamOpen,
|
||||||
|
}
|
||||||
|
|
||||||
|
t1, err := ss.Team().Save(t1)
|
||||||
|
require.NoError(t, err, "couldn't save item")
|
||||||
|
|
||||||
|
c1 := model.Channel{}
|
||||||
|
c1.TeamId = t1.Id
|
||||||
|
c1.DisplayName = "Name"
|
||||||
|
c1.Name = "aa" + model.NewId()
|
||||||
|
c1.Type = model.ChannelTypeOpen
|
||||||
|
_, nErr := ss.Channel().Save(&c1, -1)
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
|
u1 := &model.User{}
|
||||||
|
u1.Email = MakeEmail()
|
||||||
|
u1.Nickname = model.NewId()
|
||||||
|
_, err = ss.User().Save(u1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, nErr = ss.Team().SaveMember(&model.TeamMember{TeamId: t1.Id, UserId: u1.Id}, -1)
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
|
u2 := model.User{}
|
||||||
|
u2.Email = MakeEmail()
|
||||||
|
u2.Nickname = model.NewId()
|
||||||
|
_, err = ss.User().Save(&u2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
_, nErr = ss.Team().SaveMember(&model.TeamMember{TeamId: t1.Id, UserId: u2.Id}, -1)
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
|
c2 := model.Channel{}
|
||||||
|
c2.TeamId = t1.Id
|
||||||
|
c2.DisplayName = "Direct Name"
|
||||||
|
c2.Name = "bb" + model.NewId()
|
||||||
|
c2.Type = model.ChannelTypeDirect
|
||||||
|
|
||||||
|
c3 := model.Channel{}
|
||||||
|
c3.TeamId = t1.Id
|
||||||
|
c3.DisplayName = "Deleted channel"
|
||||||
|
c3.Name = "cc" + model.NewId()
|
||||||
|
c3.Type = model.ChannelTypeOpen
|
||||||
|
_, nErr = ss.Channel().Save(&c3, -1)
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
nErr = ss.Channel().Delete(c3.Id, 123)
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
c3.DeleteAt = 123
|
||||||
|
c3.UpdateAt = 123
|
||||||
|
|
||||||
|
m1 := model.ChannelMember{}
|
||||||
|
m1.ChannelId = c2.Id
|
||||||
|
m1.UserId = u1.Id
|
||||||
|
m1.NotifyProps = model.GetDefaultChannelNotifyProps()
|
||||||
|
|
||||||
|
m2 := model.ChannelMember{}
|
||||||
|
m2.ChannelId = c2.Id
|
||||||
|
m2.UserId = u2.Id
|
||||||
|
m2.NotifyProps = model.GetDefaultChannelNotifyProps()
|
||||||
|
|
||||||
|
_, nErr = ss.Channel().SaveDirectChannel(&c2, &m1, &m2)
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
|
res, err := ss.Channel().GetChannelsWithTeamDataByIds([]string{c1.Id, c2.Id}, false)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Len(t, res, 2)
|
||||||
|
assert.Equal(t, res[0].Id, c1.Id)
|
||||||
|
assert.Equal(t, res[0].TeamName, t1.Name)
|
||||||
|
assert.Equal(t, res[1].Id, c2.Id)
|
||||||
|
assert.Equal(t, res[1].TeamName, "")
|
||||||
|
}
|
||||||
|
|
||||||
func testChannelStoreGetForPost(t *testing.T, ss store.Store) {
|
func testChannelStoreGetForPost(t *testing.T, ss store.Store) {
|
||||||
|
|
||||||
ch := &model.Channel{
|
ch := &model.Channel{
|
||||||
@@ -3317,6 +3395,97 @@ func testChannelStoreGetChannels(t *testing.T, ss store.Store) {
|
|||||||
ss.Channel().InvalidateAllChannelMembersForUser(m1.UserId)
|
ss.Channel().InvalidateAllChannelMembersForUser(m1.UserId)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func testChannelStoreGetChannelsByUser(t *testing.T, ss store.Store) {
|
||||||
|
team := model.NewId()
|
||||||
|
team2 := model.NewId()
|
||||||
|
o1 := model.Channel{}
|
||||||
|
o1.TeamId = team
|
||||||
|
o1.DisplayName = "Channel1"
|
||||||
|
o1.Name = NewTestId()
|
||||||
|
o1.Type = model.ChannelTypeOpen
|
||||||
|
_, nErr := ss.Channel().Save(&o1, -1)
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
|
o2 := model.Channel{}
|
||||||
|
o2.TeamId = team
|
||||||
|
o2.DisplayName = "Channel2"
|
||||||
|
o2.Name = NewTestId()
|
||||||
|
o2.Type = model.ChannelTypeOpen
|
||||||
|
_, nErr = ss.Channel().Save(&o2, -1)
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
|
o3 := model.Channel{}
|
||||||
|
o3.TeamId = team2
|
||||||
|
o3.DisplayName = "Channel3"
|
||||||
|
o3.Name = NewTestId()
|
||||||
|
o3.Type = model.ChannelTypeOpen
|
||||||
|
_, nErr = ss.Channel().Save(&o3, -1)
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
|
m1 := model.ChannelMember{}
|
||||||
|
m1.ChannelId = o1.Id
|
||||||
|
m1.UserId = model.NewId()
|
||||||
|
m1.NotifyProps = model.GetDefaultChannelNotifyProps()
|
||||||
|
_, err := ss.Channel().SaveMember(&m1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m2 := model.ChannelMember{}
|
||||||
|
m2.ChannelId = o1.Id
|
||||||
|
m2.UserId = model.NewId()
|
||||||
|
m2.NotifyProps = model.GetDefaultChannelNotifyProps()
|
||||||
|
_, err = ss.Channel().SaveMember(&m2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m3 := model.ChannelMember{}
|
||||||
|
m3.ChannelId = o2.Id
|
||||||
|
m3.UserId = m1.UserId
|
||||||
|
m3.NotifyProps = model.GetDefaultChannelNotifyProps()
|
||||||
|
_, err = ss.Channel().SaveMember(&m3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m4 := model.ChannelMember{}
|
||||||
|
m4.ChannelId = o3.Id
|
||||||
|
m4.UserId = m1.UserId
|
||||||
|
m4.NotifyProps = model.GetDefaultChannelNotifyProps()
|
||||||
|
_, err = ss.Channel().SaveMember(&m4)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
list, nErr := ss.Channel().GetChannelsByUser(m1.UserId, false, 0, -1, "")
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
require.Len(t, list, 3)
|
||||||
|
require.ElementsMatch(t, []string{o1.Id, o2.Id, o3.Id}, []string{list[0].Id, list[1].Id, list[2].Id}, "channels did not match")
|
||||||
|
|
||||||
|
nErr = ss.Channel().Delete(o2.Id, 10)
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
|
nErr = ss.Channel().Delete(o3.Id, 20)
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
|
// should return 1
|
||||||
|
list, nErr = ss.Channel().GetChannelsByUser(m1.UserId, false, 0, -1, "")
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
require.Len(t, list, 1)
|
||||||
|
require.Equal(t, o1.Id, list[0].Id, "missing channel")
|
||||||
|
|
||||||
|
// Should return all
|
||||||
|
list, nErr = ss.Channel().GetChannelsByUser(m1.UserId, true, 0, -1, "")
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
require.Len(t, list, 3)
|
||||||
|
require.ElementsMatch(t, []string{o1.Id, o2.Id, o3.Id}, []string{list[0].Id, list[1].Id, list[2].Id}, "channels did not match")
|
||||||
|
|
||||||
|
// Should still return all
|
||||||
|
list, nErr = ss.Channel().GetChannelsByUser(m1.UserId, true, 10, -1, "")
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
require.Len(t, list, 3)
|
||||||
|
require.ElementsMatch(t, []string{o1.Id, o2.Id, o3.Id}, []string{list[0].Id, list[1].Id, list[2].Id}, "channels did not match")
|
||||||
|
|
||||||
|
// Should return 2
|
||||||
|
list, nErr = ss.Channel().GetChannelsByUser(m1.UserId, true, 20, -1, "")
|
||||||
|
require.NoError(t, nErr)
|
||||||
|
require.Len(t, list, 2)
|
||||||
|
require.ElementsMatch(t, []string{o1.Id, o3.Id}, []string{list[0].Id, list[1].Id}, "channels did not match")
|
||||||
|
}
|
||||||
|
|
||||||
func testChannelStoreGetAllChannels(t *testing.T, ss store.Store, s SqlStore) {
|
func testChannelStoreGetAllChannels(t *testing.T, ss store.Store, s SqlStore) {
|
||||||
cleanupChannels(t, ss)
|
cleanupChannels(t, ss)
|
||||||
|
|
||||||
@@ -4019,29 +4188,41 @@ func testChannelStoreGetMembersForUser(t *testing.T, ss store.Store) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testChannelStoreGetMembersForUserWithPagination(t *testing.T, ss store.Store) {
|
func testChannelStoreGetMembersForUserWithPagination(t *testing.T, ss store.Store) {
|
||||||
t1 := model.Team{}
|
t1 := model.Team{
|
||||||
t1.DisplayName = "Name"
|
DisplayName: "team1",
|
||||||
t1.Name = NewTestId()
|
Name: NewTestId(),
|
||||||
t1.Email = MakeEmail()
|
Email: MakeEmail(),
|
||||||
t1.Type = model.TeamOpen
|
Type: model.TeamOpen,
|
||||||
|
}
|
||||||
_, err := ss.Team().Save(&t1)
|
_, err := ss.Team().Save(&t1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
o1 := model.Channel{}
|
o1 := model.Channel{
|
||||||
o1.TeamId = t1.Id
|
TeamId: t1.Id,
|
||||||
o1.DisplayName = "Channel1"
|
DisplayName: "Channel1",
|
||||||
o1.Name = NewTestId()
|
Name: NewTestId(),
|
||||||
o1.Type = model.ChannelTypeOpen
|
Type: model.ChannelTypeOpen,
|
||||||
_, nErr := ss.Channel().Save(&o1, -1)
|
}
|
||||||
require.NoError(t, nErr)
|
_, err = ss.Channel().Save(&o1, -1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
o2 := model.Channel{}
|
t2 := model.Team{
|
||||||
o2.TeamId = o1.TeamId
|
DisplayName: "team2",
|
||||||
o2.DisplayName = "Channel2"
|
Name: NewTestId(),
|
||||||
o2.Name = NewTestId()
|
Email: MakeEmail(),
|
||||||
o2.Type = model.ChannelTypeOpen
|
Type: model.TeamOpen,
|
||||||
_, nErr = ss.Channel().Save(&o2, -1)
|
}
|
||||||
require.NoError(t, nErr)
|
_, err = ss.Team().Save(&t2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
o2 := model.Channel{
|
||||||
|
TeamId: t2.Id,
|
||||||
|
DisplayName: "Channel2",
|
||||||
|
Name: NewTestId(),
|
||||||
|
Type: model.ChannelTypeOpen,
|
||||||
|
}
|
||||||
|
_, err = ss.Channel().Save(&o2, -1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
m1 := model.ChannelMember{}
|
m1 := model.ChannelMember{}
|
||||||
m1.ChannelId = o1.Id
|
m1.ChannelId = o1.Id
|
||||||
@@ -4057,11 +4238,16 @@ func testChannelStoreGetMembersForUserWithPagination(t *testing.T, ss store.Stor
|
|||||||
_, err = ss.Channel().SaveMember(&m2)
|
_, err = ss.Channel().SaveMember(&m2)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
members, err := ss.Channel().GetMembersForUserWithPagination(o1.TeamId, m1.UserId, 0, 1)
|
members, err := ss.Channel().GetMembersForUserWithPagination(m1.UserId, 0, 2)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, members, 1)
|
assert.Len(t, members, 2)
|
||||||
|
teamNames := make([]string, 0, 2)
|
||||||
|
for _, member := range members {
|
||||||
|
teamNames = append(teamNames, member.TeamDisplayName)
|
||||||
|
}
|
||||||
|
assert.ElementsMatch(t, teamNames, []string{t1.DisplayName, t2.DisplayName})
|
||||||
|
|
||||||
members, err = ss.Channel().GetMembersForUserWithPagination(o1.TeamId, m1.UserId, 1, 1)
|
members, err = ss.Channel().GetMembersForUserWithPagination(m1.UserId, 1, 1)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Len(t, members, 1)
|
assert.Len(t, members, 1)
|
||||||
}
|
}
|
||||||
@@ -5065,11 +5251,11 @@ func testChannelStoreSearchArchivedInTeam(t *testing.T, ss store.Store, s SqlSto
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
||||||
teamId := model.NewId()
|
teamID := model.NewId()
|
||||||
otherTeamId := model.NewId()
|
otherTeamID := model.NewId()
|
||||||
|
|
||||||
o1 := model.Channel{
|
o1 := model.Channel{
|
||||||
TeamId: teamId,
|
TeamId: teamID,
|
||||||
DisplayName: "ChannelA",
|
DisplayName: "ChannelA",
|
||||||
Name: NewTestId(),
|
Name: NewTestId(),
|
||||||
Type: model.ChannelTypeOpen,
|
Type: model.ChannelTypeOpen,
|
||||||
@@ -5078,7 +5264,7 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
o2 := model.Channel{
|
o2 := model.Channel{
|
||||||
TeamId: otherTeamId,
|
TeamId: otherTeamID,
|
||||||
DisplayName: "ChannelA",
|
DisplayName: "ChannelA",
|
||||||
Name: NewTestId(),
|
Name: NewTestId(),
|
||||||
Type: model.ChannelTypeOpen,
|
Type: model.ChannelTypeOpen,
|
||||||
@@ -5111,7 +5297,7 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
o3 := model.Channel{
|
o3 := model.Channel{
|
||||||
TeamId: teamId,
|
TeamId: teamID,
|
||||||
DisplayName: "ChannelA (alternate)",
|
DisplayName: "ChannelA (alternate)",
|
||||||
Name: NewTestId(),
|
Name: NewTestId(),
|
||||||
Type: model.ChannelTypeOpen,
|
Type: model.ChannelTypeOpen,
|
||||||
@@ -5120,7 +5306,7 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
o4 := model.Channel{
|
o4 := model.Channel{
|
||||||
TeamId: teamId,
|
TeamId: teamID,
|
||||||
DisplayName: "Channel B",
|
DisplayName: "Channel B",
|
||||||
Name: NewTestId(),
|
Name: NewTestId(),
|
||||||
Type: model.ChannelTypePrivate,
|
Type: model.ChannelTypePrivate,
|
||||||
@@ -5128,8 +5314,16 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
_, nErr = ss.Channel().Save(&o4, -1)
|
_, nErr = ss.Channel().Save(&o4, -1)
|
||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
|
m4 := &model.ChannelMember{
|
||||||
|
ChannelId: o4.Id,
|
||||||
|
UserId: m3.UserId,
|
||||||
|
NotifyProps: model.GetDefaultChannelNotifyProps(),
|
||||||
|
}
|
||||||
|
_, err = ss.Channel().SaveMember(m4)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
o5 := model.Channel{
|
o5 := model.Channel{
|
||||||
TeamId: teamId,
|
TeamId: teamID,
|
||||||
DisplayName: "Channel C",
|
DisplayName: "Channel C",
|
||||||
Name: NewTestId(),
|
Name: NewTestId(),
|
||||||
Type: model.ChannelTypePrivate,
|
Type: model.ChannelTypePrivate,
|
||||||
@@ -5138,7 +5332,7 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
o6 := model.Channel{
|
o6 := model.Channel{
|
||||||
TeamId: teamId,
|
TeamId: teamID,
|
||||||
DisplayName: "Off-Topic",
|
DisplayName: "Off-Topic",
|
||||||
Name: "off-topic",
|
Name: "off-topic",
|
||||||
Type: model.ChannelTypeOpen,
|
Type: model.ChannelTypeOpen,
|
||||||
@@ -5147,7 +5341,7 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
o7 := model.Channel{
|
o7 := model.Channel{
|
||||||
TeamId: teamId,
|
TeamId: teamID,
|
||||||
DisplayName: "Off-Set",
|
DisplayName: "Off-Set",
|
||||||
Name: "off-set",
|
Name: "off-set",
|
||||||
Type: model.ChannelTypeOpen,
|
Type: model.ChannelTypeOpen,
|
||||||
@@ -5156,7 +5350,7 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
o8 := model.Channel{
|
o8 := model.Channel{
|
||||||
TeamId: teamId,
|
TeamId: teamID,
|
||||||
DisplayName: "Off-Limit",
|
DisplayName: "Off-Limit",
|
||||||
Name: "off-limit",
|
Name: "off-limit",
|
||||||
Type: model.ChannelTypePrivate,
|
Type: model.ChannelTypePrivate,
|
||||||
@@ -5164,8 +5358,16 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
_, nErr = ss.Channel().Save(&o8, -1)
|
_, nErr = ss.Channel().Save(&o8, -1)
|
||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
|
m5 := &model.ChannelMember{
|
||||||
|
ChannelId: o8.Id,
|
||||||
|
UserId: model.NewId(),
|
||||||
|
NotifyProps: model.GetDefaultChannelNotifyProps(),
|
||||||
|
}
|
||||||
|
_, err = ss.Channel().SaveMember(m5)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
o9 := model.Channel{
|
o9 := model.Channel{
|
||||||
TeamId: teamId,
|
TeamId: teamID,
|
||||||
DisplayName: "Town Square",
|
DisplayName: "Town Square",
|
||||||
Name: "town-square",
|
Name: "town-square",
|
||||||
Type: model.ChannelTypeOpen,
|
Type: model.ChannelTypeOpen,
|
||||||
@@ -5174,7 +5376,7 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
o10 := model.Channel{
|
o10 := model.Channel{
|
||||||
TeamId: teamId,
|
TeamId: teamID,
|
||||||
DisplayName: "The",
|
DisplayName: "The",
|
||||||
Name: "thename",
|
Name: "thename",
|
||||||
Type: model.ChannelTypeOpen,
|
Type: model.ChannelTypeOpen,
|
||||||
@@ -5183,7 +5385,7 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
o11 := model.Channel{
|
o11 := model.Channel{
|
||||||
TeamId: teamId,
|
TeamId: teamID,
|
||||||
DisplayName: "Native Mobile Apps",
|
DisplayName: "Native Mobile Apps",
|
||||||
Name: "native-mobile-apps",
|
Name: "native-mobile-apps",
|
||||||
Type: model.ChannelTypeOpen,
|
Type: model.ChannelTypeOpen,
|
||||||
@@ -5192,7 +5394,7 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
o12 := model.Channel{
|
o12 := model.Channel{
|
||||||
TeamId: teamId,
|
TeamId: teamID,
|
||||||
DisplayName: "ChannelZ",
|
DisplayName: "ChannelZ",
|
||||||
Purpose: "This can now be searchable!",
|
Purpose: "This can now be searchable!",
|
||||||
Name: "with-purpose",
|
Name: "with-purpose",
|
||||||
@@ -5202,7 +5404,7 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
require.NoError(t, nErr)
|
require.NoError(t, nErr)
|
||||||
|
|
||||||
o13 := model.Channel{
|
o13 := model.Channel{
|
||||||
TeamId: teamId,
|
TeamId: teamID,
|
||||||
DisplayName: "ChannelA (deleted)",
|
DisplayName: "ChannelA (deleted)",
|
||||||
Name: model.NewId(),
|
Name: model.NewId(),
|
||||||
Type: model.ChannelTypeOpen,
|
Type: model.ChannelTypeOpen,
|
||||||
@@ -5216,42 +5418,199 @@ func testChannelStoreSearchInTeam(t *testing.T, ss store.Store) {
|
|||||||
|
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Description string
|
Description string
|
||||||
TeamId string
|
TeamID string
|
||||||
|
UserID string
|
||||||
Term string
|
Term string
|
||||||
IncludeDeleted bool
|
IncludeDeleted bool
|
||||||
ExpectedResults model.ChannelList
|
ExpectedResults model.ChannelList
|
||||||
}{
|
}{
|
||||||
{"ChannelA", teamId, "ChannelA", false, model.ChannelList{&o1, &o3}},
|
{"ChannelA", teamID, m1.UserId, "ChannelA", false, model.ChannelList{&o1, &o3}},
|
||||||
{"ChannelA, include deleted", teamId, "ChannelA", true, model.ChannelList{&o1, &o3, &o13}},
|
{"ChannelA, include deleted", teamID, m1.UserId, "ChannelA", true, model.ChannelList{&o1, &o3, &o13}},
|
||||||
{"ChannelA, other team", otherTeamId, "ChannelA", false, model.ChannelList{&o2}},
|
{"ChannelA, other team", otherTeamID, m3.UserId, "ChannelA", false, model.ChannelList{&o2}},
|
||||||
{"empty string", teamId, "", false, model.ChannelList{&o1, &o3, &o12, &o11, &o7, &o6, &o10, &o9}},
|
{"empty string", teamID, m1.UserId, "", false, model.ChannelList{&o1, &o3, &o12, &o11, &o7, &o6, &o10, &o9}},
|
||||||
{"no matches", teamId, "blargh", false, model.ChannelList{}},
|
{"no matches", teamID, m1.UserId, "blargh", false, model.ChannelList{}},
|
||||||
{"prefix", teamId, "off-", false, model.ChannelList{&o7, &o6}},
|
{"prefix", teamID, m1.UserId, "off-", false, model.ChannelList{&o7, &o6}},
|
||||||
{"full match with dash", teamId, "off-topic", false, model.ChannelList{&o6}},
|
{"full match with dash", teamID, m1.UserId, "off-topic", false, model.ChannelList{&o6}},
|
||||||
{"town square", teamId, "town square", false, model.ChannelList{&o9}},
|
{"town square", teamID, m1.UserId, "town square", false, model.ChannelList{&o9}},
|
||||||
{"the in name", teamId, "thename", false, model.ChannelList{&o10}},
|
{"the in name", teamID, m1.UserId, "thename", false, model.ChannelList{&o10}},
|
||||||
{"Mobile", teamId, "Mobile", false, model.ChannelList{&o11}},
|
{"Mobile", teamID, m1.UserId, "Mobile", false, model.ChannelList{&o11}},
|
||||||
{"search purpose", teamId, "now searchable", false, model.ChannelList{&o12}},
|
{"search purpose", teamID, m1.UserId, "now searchable", false, model.ChannelList{&o12}},
|
||||||
{"pipe ignored", teamId, "town square |", false, model.ChannelList{&o9}},
|
{"pipe ignored", teamID, m1.UserId, "town square |", false, model.ChannelList{&o9}},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, search := range map[string]func(teamId string, term string, includeDeleted bool) (model.ChannelList, error){
|
for _, testCase := range testCases {
|
||||||
"AutocompleteInTeam": ss.Channel().AutocompleteInTeam,
|
t.Run("SearchInTeam/"+testCase.Description, func(t *testing.T) {
|
||||||
"SearchInTeam": ss.Channel().SearchInTeam,
|
channels, err := ss.Channel().SearchInTeam(testCase.TeamID, testCase.Term, testCase.IncludeDeleted)
|
||||||
} {
|
require.NoError(t, err)
|
||||||
for _, testCase := range testCases {
|
require.Equal(t, testCase.ExpectedResults, channels)
|
||||||
t.Run(name+"/"+testCase.Description, func(t *testing.T) {
|
})
|
||||||
channels, err := search(testCase.TeamId, testCase.Term, testCase.IncludeDeleted)
|
}
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
// AutoCompleteInTeam doesn't currently sort its output results.
|
testCases = append(testCases, []struct {
|
||||||
if name == "AutocompleteInTeam" {
|
Description string
|
||||||
sort.Sort(ByChannelDisplayName(channels))
|
TeamID string
|
||||||
}
|
UserID string
|
||||||
|
Term string
|
||||||
|
IncludeDeleted bool
|
||||||
|
ExpectedResults model.ChannelList
|
||||||
|
}{
|
||||||
|
{"Channel A", teamID, m4.UserId, "Channel ", false, model.ChannelList{&o4, &o1, &o3, &o12}},
|
||||||
|
{"off limit (private)", teamID, m5.UserId, "off limit", false, model.ChannelList{&o8}},
|
||||||
|
}...,
|
||||||
|
)
|
||||||
|
|
||||||
require.Equal(t, testCase.ExpectedResults, channels)
|
for _, testCase := range testCases {
|
||||||
})
|
t.Run("AutoCompleteInTeam/"+testCase.Description, func(t *testing.T) {
|
||||||
}
|
channels, err := ss.Channel().AutocompleteInTeam(testCase.TeamID, testCase.UserID, testCase.Term, testCase.IncludeDeleted)
|
||||||
|
require.NoError(t, err)
|
||||||
|
sort.Sort(ByChannelDisplayName(channels))
|
||||||
|
require.Equal(t, testCase.ExpectedResults, channels)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func testAutocomplete(t *testing.T, ss store.Store) {
|
||||||
|
t1 := &model.Team{
|
||||||
|
DisplayName: "t1",
|
||||||
|
Name: NewTestId(),
|
||||||
|
Email: MakeEmail(),
|
||||||
|
Type: model.TeamOpen,
|
||||||
|
}
|
||||||
|
t1, err := ss.Team().Save(t1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
teamID := t1.Id
|
||||||
|
|
||||||
|
t2 := &model.Team{
|
||||||
|
DisplayName: "t2",
|
||||||
|
Name: NewTestId(),
|
||||||
|
Email: MakeEmail(),
|
||||||
|
Type: model.TeamOpen,
|
||||||
|
}
|
||||||
|
t2, err = ss.Team().Save(t2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
otherTeamID := t2.Id
|
||||||
|
|
||||||
|
o1 := model.Channel{
|
||||||
|
TeamId: teamID,
|
||||||
|
DisplayName: "ChannelA1",
|
||||||
|
Name: NewTestId(),
|
||||||
|
Type: model.ChannelTypeOpen,
|
||||||
|
}
|
||||||
|
_, err = ss.Channel().Save(&o1, -1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
o2 := model.Channel{
|
||||||
|
TeamId: otherTeamID,
|
||||||
|
DisplayName: "ChannelA2",
|
||||||
|
Name: NewTestId(),
|
||||||
|
Type: model.ChannelTypeOpen,
|
||||||
|
}
|
||||||
|
_, err = ss.Channel().Save(&o2, -1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m1 := model.ChannelMember{
|
||||||
|
ChannelId: o1.Id,
|
||||||
|
UserId: model.NewId(),
|
||||||
|
NotifyProps: model.GetDefaultChannelNotifyProps(),
|
||||||
|
}
|
||||||
|
_, err = ss.Channel().SaveMember(&m1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m2 := model.ChannelMember{
|
||||||
|
ChannelId: o2.Id,
|
||||||
|
UserId: m1.UserId,
|
||||||
|
NotifyProps: model.GetDefaultChannelNotifyProps(),
|
||||||
|
}
|
||||||
|
_, err = ss.Channel().SaveMember(&m2)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tm1 := &model.TeamMember{TeamId: teamID, UserId: m1.UserId}
|
||||||
|
_, err = ss.Team().SaveMember(tm1, -1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tm2 := &model.TeamMember{TeamId: otherTeamID, UserId: m1.UserId}
|
||||||
|
_, err = ss.Team().SaveMember(tm2, -1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m3 := model.ChannelMember{
|
||||||
|
ChannelId: o2.Id,
|
||||||
|
UserId: model.NewId(),
|
||||||
|
NotifyProps: model.GetDefaultChannelNotifyProps(),
|
||||||
|
}
|
||||||
|
_, err = ss.Channel().SaveMember(&m3)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tm3 := &model.TeamMember{TeamId: otherTeamID, UserId: m3.UserId}
|
||||||
|
_, err = ss.Team().SaveMember(tm3, -1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tm4 := &model.TeamMember{TeamId: teamID, UserId: m3.UserId}
|
||||||
|
_, err = ss.Team().SaveMember(tm4, -1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
o3 := model.Channel{
|
||||||
|
TeamId: teamID,
|
||||||
|
DisplayName: "ChannelA private",
|
||||||
|
Name: NewTestId(),
|
||||||
|
Type: model.ChannelTypePrivate,
|
||||||
|
}
|
||||||
|
_, err = ss.Channel().Save(&o3, -1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
o4 := model.Channel{
|
||||||
|
TeamId: otherTeamID,
|
||||||
|
DisplayName: "ChannelB",
|
||||||
|
Name: NewTestId(),
|
||||||
|
Type: model.ChannelTypePrivate,
|
||||||
|
}
|
||||||
|
_, err = ss.Channel().Save(&o4, -1)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m4 := &model.ChannelMember{
|
||||||
|
ChannelId: o3.Id,
|
||||||
|
UserId: m3.UserId,
|
||||||
|
NotifyProps: model.GetDefaultChannelNotifyProps(),
|
||||||
|
}
|
||||||
|
_, err = ss.Channel().SaveMember(m4)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
m5 := &model.ChannelMember{
|
||||||
|
ChannelId: o4.Id,
|
||||||
|
UserId: m1.UserId,
|
||||||
|
NotifyProps: model.GetDefaultChannelNotifyProps(),
|
||||||
|
}
|
||||||
|
_, err = ss.Channel().SaveMember(m5)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
Description string
|
||||||
|
UserID string
|
||||||
|
Term string
|
||||||
|
IncludeDeleted bool
|
||||||
|
ExpectedChannelIds []string
|
||||||
|
ExpectedTeamNames []string
|
||||||
|
}{
|
||||||
|
{"user 1, Channel A", m1.UserId, "ChannelA", false, []string{o1.Id, o2.Id}, []string{t1.Name, t2.Name}},
|
||||||
|
{"user 1, Channel B", m1.UserId, "ChannelB", false, []string{o4.Id}, []string{t2.Name}},
|
||||||
|
{"user 2, Channel A", m3.UserId, "ChannelA", false, []string{o3.Id, o1.Id, o2.Id}, []string{t2.Name, t1.Name, t1.Name}},
|
||||||
|
{"user 2, Channel B", m3.UserId, "ChannelB", false, nil, nil},
|
||||||
|
{"user 1, empty string", m1.UserId, "", false, []string{o1.Id, o2.Id, o4.Id}, []string{t1.Name, t2.Name, t2.Name}},
|
||||||
|
{"user 2, empty string", m3.UserId, "", false, []string{o1.Id, o2.Id, o3.Id}, []string{t1.Name, t2.Name, t1.Name}},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, testCase := range testCases {
|
||||||
|
t.Run("Autocomplete/"+testCase.Description, func(t *testing.T) {
|
||||||
|
channels, err := ss.Channel().Autocomplete(testCase.UserID, testCase.Term, testCase.IncludeDeleted)
|
||||||
|
require.NoError(t, err)
|
||||||
|
var gotChannelIds []string
|
||||||
|
var gotTeamNames []string
|
||||||
|
for _, ch := range channels {
|
||||||
|
gotChannelIds = append(gotChannelIds, ch.Id)
|
||||||
|
gotTeamNames = append(gotTeamNames, ch.TeamName)
|
||||||
|
}
|
||||||
|
require.ElementsMatch(t, testCase.ExpectedChannelIds, gotChannelIds)
|
||||||
|
require.ElementsMatch(t, testCase.ExpectedTeamNames, gotTeamNames)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -6903,13 +7262,13 @@ func testChannelStoreGetChannelsBatchForIndexing(t *testing.T, ss store.Store) {
|
|||||||
// First and last channel should be outside the range
|
// First and last channel should be outside the range
|
||||||
channels, err := ss.Channel().GetChannelsBatchForIndexing(startTime, endTime, 1000)
|
channels, err := ss.Channel().GetChannelsBatchForIndexing(startTime, endTime, 1000)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.ElementsMatch(t, []*model.Channel{c2, c3, c5}, channels)
|
assert.ElementsMatch(t, []*model.Channel{c2, c3, c4, c5}, channels)
|
||||||
|
|
||||||
// Update the endTime, last channel should be in
|
// Update the endTime, last channel should be in
|
||||||
endTime = model.GetMillis()
|
endTime = model.GetMillis()
|
||||||
channels, err = ss.Channel().GetChannelsBatchForIndexing(startTime, endTime, 1000)
|
channels, err = ss.Channel().GetChannelsBatchForIndexing(startTime, endTime, 1000)
|
||||||
assert.NoError(t, err)
|
assert.NoError(t, err)
|
||||||
assert.ElementsMatch(t, []*model.Channel{c2, c3, c5, c6}, channels)
|
assert.ElementsMatch(t, []*model.Channel{c2, c3, c4, c5, c6}, channels)
|
||||||
|
|
||||||
// Testing the limit
|
// Testing the limit
|
||||||
channels, err = ss.Channel().GetChannelsBatchForIndexing(startTime, endTime, 2)
|
channels, err = ss.Channel().GetChannelsBatchForIndexing(startTime, endTime, 2)
|
||||||
|
|||||||
@@ -60,13 +60,36 @@ func (_m *ChannelStore) AnalyticsTypeCount(teamID string, channelType model.Chan
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
// AutocompleteInTeam provides a mock function with given fields: teamID, term, includeDeleted
|
// Autocomplete provides a mock function with given fields: userID, term, includeDeleted
|
||||||
func (_m *ChannelStore) AutocompleteInTeam(teamID string, term string, includeDeleted bool) (model.ChannelList, error) {
|
func (_m *ChannelStore) Autocomplete(userID string, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
|
||||||
ret := _m.Called(teamID, term, includeDeleted)
|
ret := _m.Called(userID, term, includeDeleted)
|
||||||
|
|
||||||
|
var r0 model.ChannelListWithTeamData
|
||||||
|
if rf, ok := ret.Get(0).(func(string, string, bool) model.ChannelListWithTeamData); ok {
|
||||||
|
r0 = rf(userID, term, includeDeleted)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(model.ChannelListWithTeamData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(string, string, bool) error); ok {
|
||||||
|
r1 = rf(userID, term, includeDeleted)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// AutocompleteInTeam provides a mock function with given fields: teamID, userID, term, includeDeleted
|
||||||
|
func (_m *ChannelStore) AutocompleteInTeam(teamID string, userID string, term string, includeDeleted bool) (model.ChannelList, error) {
|
||||||
|
ret := _m.Called(teamID, userID, term, includeDeleted)
|
||||||
|
|
||||||
var r0 model.ChannelList
|
var r0 model.ChannelList
|
||||||
if rf, ok := ret.Get(0).(func(string, string, bool) model.ChannelList); ok {
|
if rf, ok := ret.Get(0).(func(string, string, string, bool) model.ChannelList); ok {
|
||||||
r0 = rf(teamID, term, includeDeleted)
|
r0 = rf(teamID, userID, term, includeDeleted)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
if ret.Get(0) != nil {
|
||||||
r0 = ret.Get(0).(model.ChannelList)
|
r0 = ret.Get(0).(model.ChannelList)
|
||||||
@@ -74,8 +97,8 @@ func (_m *ChannelStore) AutocompleteInTeam(teamID string, term string, includeDe
|
|||||||
}
|
}
|
||||||
|
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(1).(func(string, string, bool) error); ok {
|
if rf, ok := ret.Get(1).(func(string, string, string, bool) error); ok {
|
||||||
r1 = rf(teamID, term, includeDeleted)
|
r1 = rf(teamID, userID, term, includeDeleted)
|
||||||
} else {
|
} else {
|
||||||
r1 = ret.Error(1)
|
r1 = ret.Error(1)
|
||||||
}
|
}
|
||||||
@@ -331,6 +354,29 @@ func (_m *ChannelStore) GetAll(teamID string) ([]*model.Channel, error) {
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetAllChannelMembersById provides a mock function with given fields: id
|
||||||
|
func (_m *ChannelStore) GetAllChannelMembersById(id string) ([]string, error) {
|
||||||
|
ret := _m.Called(id)
|
||||||
|
|
||||||
|
var r0 []string
|
||||||
|
if rf, ok := ret.Get(0).(func(string) []string); ok {
|
||||||
|
r0 = rf(id)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||||
|
r1 = rf(id)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// GetAllChannelMembersForUser provides a mock function with given fields: userID, allowFromCache, includeDeleted
|
// GetAllChannelMembersForUser provides a mock function with given fields: userID, allowFromCache, includeDeleted
|
||||||
func (_m *ChannelStore) GetAllChannelMembersForUser(userID string, allowFromCache bool, includeDeleted bool) (map[string]string, error) {
|
func (_m *ChannelStore) GetAllChannelMembersForUser(userID string, allowFromCache bool, includeDeleted bool) (map[string]string, error) {
|
||||||
ret := _m.Called(userID, allowFromCache, includeDeleted)
|
ret := _m.Called(userID, allowFromCache, includeDeleted)
|
||||||
@@ -720,6 +766,52 @@ func (_m *ChannelStore) GetChannelsByScheme(schemeID string, offset int, limit i
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetChannelsByUser provides a mock function with given fields: userID, includeDeleted, lastDeleteAt, pageSize, fromChannelID
|
||||||
|
func (_m *ChannelStore) GetChannelsByUser(userID string, includeDeleted bool, lastDeleteAt int, pageSize int, fromChannelID string) (model.ChannelList, error) {
|
||||||
|
ret := _m.Called(userID, includeDeleted, lastDeleteAt, pageSize, fromChannelID)
|
||||||
|
|
||||||
|
var r0 model.ChannelList
|
||||||
|
if rf, ok := ret.Get(0).(func(string, bool, int, int, string) model.ChannelList); ok {
|
||||||
|
r0 = rf(userID, includeDeleted, lastDeleteAt, pageSize, fromChannelID)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).(model.ChannelList)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(string, bool, int, int, string) error); ok {
|
||||||
|
r1 = rf(userID, includeDeleted, lastDeleteAt, pageSize, fromChannelID)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetChannelsWithTeamDataByIds provides a mock function with given fields: channelIds, includeDeleted
|
||||||
|
func (_m *ChannelStore) GetChannelsWithTeamDataByIds(channelIds []string, includeDeleted bool) ([]*model.ChannelWithTeamData, error) {
|
||||||
|
ret := _m.Called(channelIds, includeDeleted)
|
||||||
|
|
||||||
|
var r0 []*model.ChannelWithTeamData
|
||||||
|
if rf, ok := ret.Get(0).(func([]string, bool) []*model.ChannelWithTeamData); ok {
|
||||||
|
r0 = rf(channelIds, includeDeleted)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]*model.ChannelWithTeamData)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func([]string, bool) error); ok {
|
||||||
|
r1 = rf(channelIds, includeDeleted)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// GetDeleted provides a mock function with given fields: team_id, offset, limit, userID
|
// GetDeleted provides a mock function with given fields: team_id, offset, limit, userID
|
||||||
func (_m *ChannelStore) GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error) {
|
func (_m *ChannelStore) GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error) {
|
||||||
ret := _m.Called(team_id, offset, limit, userID)
|
ret := _m.Called(team_id, offset, limit, userID)
|
||||||
@@ -1029,22 +1121,22 @@ func (_m *ChannelStore) GetMembersForUser(teamID string, userID string) (model.C
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetMembersForUserWithPagination provides a mock function with given fields: teamID, userID, page, perPage
|
// GetMembersForUserWithPagination provides a mock function with given fields: userID, page, perPage
|
||||||
func (_m *ChannelStore) GetMembersForUserWithPagination(teamID string, userID string, page int, perPage int) (model.ChannelMembers, error) {
|
func (_m *ChannelStore) GetMembersForUserWithPagination(userID string, page int, perPage int) (model.ChannelMembersWithTeamData, error) {
|
||||||
ret := _m.Called(teamID, userID, page, perPage)
|
ret := _m.Called(userID, page, perPage)
|
||||||
|
|
||||||
var r0 model.ChannelMembers
|
var r0 model.ChannelMembersWithTeamData
|
||||||
if rf, ok := ret.Get(0).(func(string, string, int, int) model.ChannelMembers); ok {
|
if rf, ok := ret.Get(0).(func(string, int, int) model.ChannelMembersWithTeamData); ok {
|
||||||
r0 = rf(teamID, userID, page, perPage)
|
r0 = rf(userID, page, perPage)
|
||||||
} else {
|
} else {
|
||||||
if ret.Get(0) != nil {
|
if ret.Get(0) != nil {
|
||||||
r0 = ret.Get(0).(model.ChannelMembers)
|
r0 = ret.Get(0).(model.ChannelMembersWithTeamData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var r1 error
|
var r1 error
|
||||||
if rf, ok := ret.Get(1).(func(string, string, int, int) error); ok {
|
if rf, ok := ret.Get(1).(func(string, int, int) error); ok {
|
||||||
r1 = rf(teamID, userID, page, perPage)
|
r1 = rf(userID, page, perPage)
|
||||||
} else {
|
} else {
|
||||||
r1 = ret.Error(1)
|
r1 = ret.Error(1)
|
||||||
}
|
}
|
||||||
@@ -1303,6 +1395,29 @@ func (_m *ChannelStore) GetTeamForChannel(channelID string) (*model.Team, error)
|
|||||||
return r0, r1
|
return r0, r1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetTeamMembersForChannel provides a mock function with given fields: channelID
|
||||||
|
func (_m *ChannelStore) GetTeamMembersForChannel(channelID string) ([]string, error) {
|
||||||
|
ret := _m.Called(channelID)
|
||||||
|
|
||||||
|
var r0 []string
|
||||||
|
if rf, ok := ret.Get(0).(func(string) []string); ok {
|
||||||
|
r0 = rf(channelID)
|
||||||
|
} else {
|
||||||
|
if ret.Get(0) != nil {
|
||||||
|
r0 = ret.Get(0).([]string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var r1 error
|
||||||
|
if rf, ok := ret.Get(1).(func(string) error); ok {
|
||||||
|
r1 = rf(channelID)
|
||||||
|
} else {
|
||||||
|
r1 = ret.Error(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
return r0, r1
|
||||||
|
}
|
||||||
|
|
||||||
// GroupSyncedChannelCount provides a mock function with given fields:
|
// GroupSyncedChannelCount provides a mock function with given fields:
|
||||||
func (_m *ChannelStore) GroupSyncedChannelCount() (int64, error) {
|
func (_m *ChannelStore) GroupSyncedChannelCount() (int64, error) {
|
||||||
ret := _m.Called()
|
ret := _m.Called()
|
||||||
|
|||||||
@@ -550,10 +550,26 @@ func (s *TimerLayerChannelStore) AnalyticsTypeCount(teamID string, channelType m
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) AutocompleteInTeam(teamID string, term string, includeDeleted bool) (model.ChannelList, error) {
|
func (s *TimerLayerChannelStore) Autocomplete(userID string, term string, includeDeleted bool) (model.ChannelListWithTeamData, error) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
result, err := s.ChannelStore.AutocompleteInTeam(teamID, term, includeDeleted)
|
result, err := s.ChannelStore.Autocomplete(userID, term, includeDeleted)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if err == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.Autocomplete", success, elapsed)
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) AutocompleteInTeam(teamID string, userID string, term string, includeDeleted bool) (model.ChannelList, error) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
result, err := s.ChannelStore.AutocompleteInTeam(teamID, userID, term, includeDeleted)
|
||||||
|
|
||||||
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
if s.Root.Metrics != nil {
|
if s.Root.Metrics != nil {
|
||||||
@@ -773,6 +789,22 @@ func (s *TimerLayerChannelStore) GetAll(teamID string) ([]*model.Channel, error)
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) GetAllChannelMembersById(id string) ([]string, error) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
result, err := s.ChannelStore.GetAllChannelMembersById(id)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if err == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetAllChannelMembersById", success, elapsed)
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) GetAllChannelMembersForUser(userID string, allowFromCache bool, includeDeleted bool) (map[string]string, error) {
|
func (s *TimerLayerChannelStore) GetAllChannelMembersForUser(userID string, allowFromCache bool, includeDeleted bool) (map[string]string, error) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
@@ -1045,6 +1077,38 @@ func (s *TimerLayerChannelStore) GetChannelsByScheme(schemeID string, offset int
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) GetChannelsByUser(userID string, includeDeleted bool, lastDeleteAt int, pageSize int, fromChannelID string) (model.ChannelList, error) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
result, err := s.ChannelStore.GetChannelsByUser(userID, includeDeleted, lastDeleteAt, pageSize, fromChannelID)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if err == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetChannelsByUser", success, elapsed)
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) GetChannelsWithTeamDataByIds(channelIds []string, includeDeleted bool) ([]*model.ChannelWithTeamData, error) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
result, err := s.ChannelStore.GetChannelsWithTeamDataByIds(channelIds, includeDeleted)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if err == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetChannelsWithTeamDataByIds", success, elapsed)
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error) {
|
func (s *TimerLayerChannelStore) GetDeleted(team_id string, offset int, limit int, userID string) (model.ChannelList, error) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
@@ -1269,10 +1333,10 @@ func (s *TimerLayerChannelStore) GetMembersForUser(teamID string, userID string)
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) GetMembersForUserWithPagination(teamID string, userID string, page int, perPage int) (model.ChannelMembers, error) {
|
func (s *TimerLayerChannelStore) GetMembersForUserWithPagination(userID string, page int, perPage int) (model.ChannelMembersWithTeamData, error) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
result, err := s.ChannelStore.GetMembersForUserWithPagination(teamID, userID, page, perPage)
|
result, err := s.ChannelStore.GetMembersForUserWithPagination(userID, page, perPage)
|
||||||
|
|
||||||
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
if s.Root.Metrics != nil {
|
if s.Root.Metrics != nil {
|
||||||
@@ -1461,6 +1525,22 @@ func (s *TimerLayerChannelStore) GetTeamForChannel(channelID string) (*model.Tea
|
|||||||
return result, err
|
return result, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *TimerLayerChannelStore) GetTeamMembersForChannel(channelID string) ([]string, error) {
|
||||||
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
result, err := s.ChannelStore.GetTeamMembersForChannel(channelID)
|
||||||
|
|
||||||
|
elapsed := float64(timemodule.Since(start)) / float64(timemodule.Second)
|
||||||
|
if s.Root.Metrics != nil {
|
||||||
|
success := "false"
|
||||||
|
if err == nil {
|
||||||
|
success = "true"
|
||||||
|
}
|
||||||
|
s.Root.Metrics.ObserveStoreMethodDuration("ChannelStore.GetTeamMembersForChannel", success, elapsed)
|
||||||
|
}
|
||||||
|
return result, err
|
||||||
|
}
|
||||||
|
|
||||||
func (s *TimerLayerChannelStore) GroupSyncedChannelCount() (int64, error) {
|
func (s *TimerLayerChannelStore) GroupSyncedChannelCount() (int64, error) {
|
||||||
start := timemodule.Now()
|
start := timemodule.Now()
|
||||||
|
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user