[MM-51201/MM-60406/MM-60404] CrossTeam Search posts and files (#28478)

* poc - wip

* add search files across teams

* eslint

* fix existing tests

* fix webapp style

* fix test

* add api doc

* change initial state in test

* add tests on API

* add tests on file info layer

* fix file search tags

* add rhs reducer test

* reset team selected when the RHS is suppressed

* change css to reflect UI

* fix style

* fix doc wording

* make getSearchTeam return currentTeamId when value is not set

* await is unnecessary

* revert boolean check and add test

* add comment to getSearchTeam to let dev knows it defaults to currentTeam

* remove redundant team check

* simplfy test

* fix style check

---------

Co-authored-by: Caleb Roseland <caleb@calebroseland.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Julien Tant
2024-11-21 13:40:46 -07:00
коммит произвёл GitHub
родитель f0280d6dd4
Коммит 3b1eb64e02
25 изменённых файлов: 573 добавлений и 150 удалений

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

@@ -198,6 +198,11 @@ var searchFileInfoStoreTests = []searchTest{
Fn: testFileInfoSearchShowChannelBookmarkFiles,
Tags: []string{EnginePostgres, EngineMySQL, EngineElasticSearch},
},
{
Name: "Should search files across teams",
Fn: testFileInfoSearchAcrossTeams,
Tags: []string{EngineAll},
},
}
func TestSearchFileInfoStore(t *testing.T, s store.Store, testEngine *SearchTestEngine) {
@@ -1727,3 +1732,73 @@ func testFileInfoSearchShowChannelBookmarkFiles(t *testing.T, th *SearchTestHelp
require.Len(t, results.FileInfos, 1)
require.Equal(t, "message test@test.com", results.FileInfos[file.Id].Name)
}
func testFileInfoSearchAcrossTeams(t *testing.T, th *SearchTestHelper) {
user1, err := th.createUser("user1", "user1", "user1", "user1")
require.NoError(t, err)
defer th.deleteUser(user1)
user2, err := th.createUser("user2", "user2", "user2", "user2")
require.NoError(t, err)
defer th.deleteUser(user2)
team1, err := th.createTeam("team1", "team1", model.TeamOpen)
require.NoError(t, err)
defer th.deleteTeam(team1)
team2, err := th.createTeam("team2", "team2", model.TeamOpen)
require.NoError(t, err)
defer th.deleteTeam(team2)
// user1 join both teams, user2 join team1
err = th.addUserToTeams(user1, []string{team1.Id, team2.Id})
require.NoError(t, err)
err = th.addUserToTeams(user2, []string{team1.Id})
require.NoError(t, err)
channel1, err := th.createChannel(team1.Id, "channel1", "channel1", "", model.ChannelTypeOpen, th.User, false)
require.NoError(t, err)
defer th.deleteChannel(channel1)
channel2, err := th.createChannel(team2.Id, "channel2", "channel2", "", model.ChannelTypeOpen, th.User, false)
require.NoError(t, err)
defer th.deleteChannel(channel2)
// user1 joins all channels, user2 joins channel1
err = th.addUserToChannels(user1, []string{channel1.Id, channel2.Id})
require.NoError(t, err)
err = th.addUserToChannels(user2, []string{channel1.Id})
require.NoError(t, err)
postInChannel1, err := th.createPost(user1.Id, channel1.Id, "message", "", model.PostTypeDefault, 0, false)
require.NoError(t, err)
defer th.deleteUserPosts(user1.Id)
postInChannel2, err := th.createPost(user1.Id, channel2.Id, "message", "", model.PostTypeDefault, 0, false)
require.NoError(t, err)
defer th.deleteUserPosts(user1.Id)
p1, err := th.createFileInfo(user1.Id, postInChannel1.Id, postInChannel1.ChannelId, "channel test filename", "channel contenttest filename", "jpg", "image/jpeg", 0, 0)
require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id)
p2, err := th.createFileInfo(user1.Id, postInChannel2.Id, postInChannel2.ChannelId, "channel test filename", "channel contenttest filename", "jpg", "image/jpeg", 0, 0)
require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id)
t.Run("user in all teams", func(t *testing.T) {
params := &model.SearchParams{Terms: "test"}
results, err := th.Store.FileInfo().Search(th.Context, []*model.SearchParams{params}, user1.Id, "", 0, 20)
require.NoError(t, err)
require.Len(t, results.FileInfos, 2)
th.checkFileInfoInSearchResults(t, p1.Id, results.FileInfos)
th.checkFileInfoInSearchResults(t, p2.Id, results.FileInfos)
})
t.Run("user in team1", func(t *testing.T) {
params := &model.SearchParams{Terms: "test"}
results, err := th.Store.FileInfo().Search(th.Context, []*model.SearchParams{params}, user2.Id, "", 0, 20)
require.NoError(t, err)
require.Len(t, results.FileInfos, 1)
th.checkFileInfoInSearchResults(t, p1.Id, results.FileInfos)
})
}

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

@@ -519,7 +519,6 @@ func (fs SqlFileInfoStore) Search(rctx request.CTX, paramsList []*model.SearchPa
From("FileInfo").
LeftJoin("Channels as C ON C.Id=FileInfo.ChannelId").
LeftJoin("ChannelMembers as CM ON C.Id=CM.ChannelId").
Where(sq.Or{sq.Eq{"C.TeamId": teamId}, sq.Eq{"C.TeamId": ""}}).
Where(sq.Eq{"FileInfo.DeleteAt": 0}).
Where(sq.Or{
sq.Eq{"FileInfo.CreatorId": model.BookmarkFileOwner},
@@ -528,6 +527,10 @@ func (fs SqlFileInfoStore) Search(rctx request.CTX, paramsList []*model.SearchPa
OrderBy("FileInfo.CreateAt DESC").
Limit(100)
if teamId != "" {
query = query.Where(sq.Or{sq.Eq{"C.TeamId": teamId}, sq.Eq{"C.TeamId": ""}})
}
for _, params := range paramsList {
params.Terms = removeNonAlphaNumericUnquotedTerms(params.Terms, " ")