[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
@@ -94,6 +94,15 @@ type channelMemberWithSchemeRoles struct {
|
||||
MsgCountRoot int64
|
||||
}
|
||||
|
||||
type channelMemberWithTeamWithSchemeRoles struct {
|
||||
channelMemberWithSchemeRoles
|
||||
TeamDisplayName string
|
||||
TeamName string
|
||||
TeamUpdateAt int64
|
||||
}
|
||||
|
||||
type channelMemberWithTeamWithSchemeRolesList []channelMemberWithTeamWithSchemeRoles
|
||||
|
||||
func channelMemberSliceColumns() []string {
|
||||
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 {
|
||||
cms := model.ChannelMembers{}
|
||||
|
||||
@@ -260,6 +336,16 @@ func (db channelMemberWithSchemeRolesList) ToModel() model.ChannelMembers {
|
||||
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 {
|
||||
ChannelId string
|
||||
Roles string
|
||||
@@ -999,6 +1085,73 @@ func (s SqlChannelStore) GetChannels(teamId string, userId string, includeDelete
|
||||
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) {
|
||||
query := s.getAllChannelsQuery(opts, false)
|
||||
|
||||
@@ -1397,7 +1550,7 @@ func (s SqlChannelStore) GetDeleted(teamId string, offset int, limit int, userId
|
||||
return channels, nil
|
||||
}
|
||||
|
||||
var ChannelMembersWithSchemeSelectQuery = `
|
||||
var channelMembersForTeamWithSchemeSelectQuery = `
|
||||
SELECT
|
||||
ChannelMembers.*,
|
||||
TeamScheme.DefaultChannelGuestRole TeamSchemeDefaultGuestRole,
|
||||
@@ -1418,6 +1571,30 @@ var ChannelMembersWithSchemeSelectQuery = `
|
||||
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) {
|
||||
for _, member := range members {
|
||||
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
|
||||
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 {
|
||||
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
|
||||
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 {
|
||||
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) {
|
||||
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 {
|
||||
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) {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
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) {
|
||||
channel := &model.Channel{}
|
||||
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) {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) GetMembersForUserWithPagination(teamId, userId string, page, perPage int) (model.ChannelMembers, error) {
|
||||
var dbMembers channelMemberWithSchemeRolesList
|
||||
func (s SqlChannelStore) GetMembersForUserWithPagination(userId string, page, perPage int) (model.ChannelMembersWithTeamData, error) {
|
||||
var dbMembers channelMemberWithTeamWithSchemeRolesList
|
||||
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 {
|
||||
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
|
||||
}
|
||||
|
||||
func (s SqlChannelStore) AutocompleteInTeam(teamId string, term string, includeDeleted bool) (model.ChannelList, error) {
|
||||
deleteFilter := "AND Channels.DeleteAt = 0"
|
||||
func (s SqlChannelStore) GetTeamMembersForChannel(channelID string) ([]string, error) {
|
||||
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 {
|
||||
deleteFilter = ""
|
||||
}
|
||||
|
||||
queryFormat := `
|
||||
SELECT
|
||||
Channels.*
|
||||
FROM
|
||||
Channels
|
||||
JOIN
|
||||
PublicChannels c ON (c.Id = Channels.Id)
|
||||
WHERE
|
||||
Channels.TeamId = :TeamId
|
||||
` + deleteFilter + `
|
||||
%v
|
||||
LIMIT ` + strconv.Itoa(model.ChannelSearchDefaultLimit)
|
||||
return s.performGlobalSearch(`
|
||||
SELECT
|
||||
c.*, t.DisplayName AS TeamDisplayName, t.Name AS TeamName, t.UpdateAt AS TeamUpdateAt
|
||||
FROM
|
||||
Channels c, Teams t, TeamMembers tm
|
||||
WHERE
|
||||
c.TeamId=t.Id
|
||||
AND
|
||||
t.Id=tm.TeamId
|
||||
AND
|
||||
tm.UserId = :UserId
|
||||
`+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
|
||||
|
||||
if likeClause, likeTerm := s.buildLIKEClause(term, "c.Name, c.DisplayName, c.Purpose"); likeClause == "" {
|
||||
if _, err := s.GetReplica().Select(&channels, fmt.Sprintf(queryFormat, ""), map[string]interface{}{"TeamId": teamId}); err != nil {
|
||||
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)
|
||||
}
|
||||
func (s SqlChannelStore) AutocompleteInTeam(teamID, userID, term string, includeDeleted bool) (model.ChannelList, error) {
|
||||
deleteFilter := "AND c.DeleteAt = 0"
|
||||
if includeDeleted {
|
||||
deleteFilter = ""
|
||||
}
|
||||
|
||||
sort.Slice(channels, func(a, b int) bool {
|
||||
return strings.ToLower(channels[a].DisplayName) < strings.ToLower(channels[b].DisplayName)
|
||||
return s.performSearch(`
|
||||
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) {
|
||||
@@ -2959,6 +3200,27 @@ func (s SqlChannelStore) performSearch(searchQuery string, term string, paramete
|
||||
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{}) {
|
||||
var query, baseLikeClause string
|
||||
if isPostgreSQL {
|
||||
@@ -3064,7 +3326,7 @@ func (s SqlChannelStore) GetMembersByIds(channelId string, userIds []string) (mo
|
||||
keys, props := MapStringsToQueryParams(userIds, "User")
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -3077,7 +3339,7 @@ func (s SqlChannelStore) GetMembersByChannelIds(channelIds []string, userId stri
|
||||
keys, props := MapStringsToQueryParams(channelIds, "Channel")
|
||||
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)
|
||||
}
|
||||
|
||||
@@ -3367,8 +3629,6 @@ func (s SqlChannelStore) GetChannelsBatchForIndexing(startTime, endTime int64, l
|
||||
FROM
|
||||
Channels
|
||||
WHERE
|
||||
Type = 'O'
|
||||
AND
|
||||
CreateAt >= :StartTime
|
||||
AND
|
||||
CreateAt < :EndTime
|
||||
|
||||
Ссылка в новой задаче
Block a user