From 56b18ca7bfcf1bc513fe8bbf45dc1c0b010bc4de Mon Sep 17 00:00:00 2001 From: Agniva De Sarker Date: Thu, 23 Mar 2023 22:14:04 +0530 Subject: [PATCH] MM-45956: Optimize FileInfo stats query (#22603) * MM-45956: Optimize FileInfo stats query We Denormalize Post.ChannelId on FileInfo.ChannelId ```release-note The file info stats query is now optimized by denormalizing the channelID column into the table itself. This will speed up the query to get the file count for a channel on clicking the RHS. Migration times: On a MySQL 8.0.31 DB with 1405 rows in FileInfo and 11M posts, it took around 0.3s On a Postgres 12.14 DB with 1731 rows in FileInfo and 11M posts, it took around 0.27s ``` https://mattermost.atlassian.net/browse/MM-45956 --- model/file_info.go | 12 +- server/channels/api4/file_test.go | 14 +- server/channels/app/file.go | 2 + server/channels/app/file_test.go | 1 + server/channels/app/import_functions.go | 2 +- server/channels/app/post.go | 2 +- server/channels/db/migrations/migrations.list | 4 + .../mysql/000106_fileinfo_channelid.down.sql | 29 +++ .../mysql/000106_fileinfo_channelid.up.sql | 34 ++++ .../000106_fileinfo_channelid.down.sql | 2 + .../postgres/000106_fileinfo_channelid.up.sql | 3 + .../opentracinglayer/opentracinglayer.go | 4 +- .../channels/store/retrylayer/retrylayer.go | 4 +- .../store/searchlayer/file_info_layer.go | 4 +- .../store/searchtest/file_info_layer.go | 170 +++++++++--------- server/channels/store/searchtest/helper.go | 7 +- .../channels/store/sqlstore/channel_store.go | 2 +- .../store/sqlstore/file_info_store.go | 24 +-- server/channels/store/sqlstore/integrity.go | 10 ++ .../channels/store/sqlstore/integrity_test.go | 6 +- server/channels/store/store.go | 2 +- .../store/storetest/file_info_store.go | 50 +++++- .../store/storetest/mocks/FileInfoStore.go | 10 +- .../channels/store/timerlayer/timerlayer.go | 4 +- .../services/slackimport/slackimport.go | 2 +- 25 files changed, 266 insertions(+), 138 deletions(-) create mode 100644 server/channels/db/migrations/mysql/000106_fileinfo_channelid.down.sql create mode 100644 server/channels/db/migrations/mysql/000106_fileinfo_channelid.up.sql create mode 100644 server/channels/db/migrations/postgres/000106_fileinfo_channelid.down.sql create mode 100644 server/channels/db/migrations/postgres/000106_fileinfo_channelid.up.sql diff --git a/model/file_info.go b/model/file_info.go index eb1bcb3524..554ad2e588 100644 --- a/model/file_info.go +++ b/model/file_info.go @@ -36,10 +36,14 @@ type GetFileInfosOptions struct { } type FileInfo struct { - Id string `json:"id"` - CreatorId string `json:"user_id"` - PostId string `json:"post_id,omitempty"` - ChannelId string `db:"-" json:"channel_id"` + Id string `json:"id"` + CreatorId string `json:"user_id"` + PostId string `json:"post_id,omitempty"` + // ChannelId is the denormalized value from the corresponding post. Note that this value is + // potentially distinct from the ChannelId provided when the file is first uploaded and + // used to organize the directories in the file store, since in theory that same file + // could be attached to a post from a different channel (or not attached to a post at all). + ChannelId string `json:"channel_id"` CreateAt int64 `json:"create_at"` UpdateAt int64 `json:"update_at"` DeleteAt int64 `json:"delete_at"` diff --git a/server/channels/api4/file_test.go b/server/channels/api4/file_test.go index 9e432fcb1a..05005e015e 100644 --- a/server/channels/api4/file_test.go +++ b/server/channels/api4/file_test.go @@ -916,7 +916,7 @@ func TestGetFileLink(t *testing.T) { CheckBadRequestStatus(t, resp) // Hacky way to assign file to a post (usually would be done by CreatePost call) - err = th.App.Srv().Store().FileInfo().AttachToPost(fileId, th.BasicPost.Id, th.BasicUser.Id) + err = th.App.Srv().Store().FileInfo().AttachToPost(fileId, th.BasicPost.Id, th.BasicPost.ChannelId, th.BasicUser.Id) require.NoError(t, err) th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.EnablePublicLink = false }) @@ -1074,7 +1074,7 @@ func TestGetPublicFile(t *testing.T) { fileId := fileResp.FileInfos[0].Id // Hacky way to assign file to a post (usually would be done by CreatePost call) - err = th.App.Srv().Store().FileInfo().AttachToPost(fileId, th.BasicPost.Id, th.BasicUser.Id) + err = th.App.Srv().Store().FileInfo().AttachToPost(fileId, th.BasicPost.Id, th.BasicPost.ChannelId, th.BasicUser.Id) require.NoError(t, err) info, err := th.App.Srv().Store().FileInfo().Get(fileId) @@ -1139,25 +1139,25 @@ func TestSearchFiles(t *testing.T) { filename := "search for fileInfo1" fileInfo1, appErr := th.App.UploadFile(th.Context, data, th.BasicChannel.Id, filename) require.Nil(t, appErr) - err = th.App.Srv().Store().FileInfo().AttachToPost(fileInfo1.Id, th.BasicPost.Id, th.BasicUser.Id) + err = th.App.Srv().Store().FileInfo().AttachToPost(fileInfo1.Id, th.BasicPost.Id, th.BasicPost.ChannelId, th.BasicUser.Id) require.NoError(t, err) filename = "search for fileInfo2" fileInfo2, appErr := th.App.UploadFile(th.Context, data, th.BasicChannel.Id, filename) require.Nil(t, appErr) - err = th.App.Srv().Store().FileInfo().AttachToPost(fileInfo2.Id, th.BasicPost.Id, th.BasicUser.Id) + err = th.App.Srv().Store().FileInfo().AttachToPost(fileInfo2.Id, th.BasicPost.Id, th.BasicPost.ChannelId, th.BasicUser.Id) require.NoError(t, err) filename = "tagged search for fileInfo3" fileInfo3, appErr := th.App.UploadFile(th.Context, data, th.BasicChannel.Id, filename) require.Nil(t, appErr) - err = th.App.Srv().Store().FileInfo().AttachToPost(fileInfo3.Id, th.BasicPost.Id, th.BasicUser.Id) + err = th.App.Srv().Store().FileInfo().AttachToPost(fileInfo3.Id, th.BasicPost.Id, th.BasicPost.ChannelId, th.BasicUser.Id) require.NoError(t, err) filename = "tagged for fileInfo4" fileInfo4, appErr := th.App.UploadFile(th.Context, data, th.BasicChannel.Id, filename) require.Nil(t, appErr) - err = th.App.Srv().Store().FileInfo().AttachToPost(fileInfo4.Id, th.BasicPost.Id, th.BasicUser.Id) + err = th.App.Srv().Store().FileInfo().AttachToPost(fileInfo4.Id, th.BasicPost.Id, th.BasicPost.ChannelId, th.BasicUser.Id) require.NoError(t, err) archivedChannel := th.CreatePublicChannel() @@ -1166,7 +1166,7 @@ func TestSearchFiles(t *testing.T) { post := &model.Post{ChannelId: archivedChannel.Id, Message: model.NewId() + "a"} rpost, _, err := client.CreatePost(post) require.NoError(t, err) - err = th.App.Srv().Store().FileInfo().AttachToPost(fileInfo5.Id, rpost.Id, th.BasicUser.Id) + err = th.App.Srv().Store().FileInfo().AttachToPost(fileInfo5.Id, rpost.Id, rpost.ChannelId, th.BasicUser.Id) require.NoError(t, err) th.Client.DeleteChannel(archivedChannel.Id) diff --git a/server/channels/app/file.go b/server/channels/app/file.go index 0bcf31e12e..826f224dc8 100644 --- a/server/channels/app/file.go +++ b/server/channels/app/file.go @@ -274,6 +274,7 @@ func (a *App) getInfoForFilename(post *model.Post, teamID, channelID, userID, ol info.Id = model.NewId() info.CreatorId = post.UserId info.PostId = post.Id + info.ChannelId = post.ChannelId info.CreateAt = post.CreateAt info.UpdateAt = post.UpdateAt info.Path = path @@ -1214,6 +1215,7 @@ func (a *App) CopyFileInfos(userID string, fileIDs []string) ([]string, *model.A fileInfo.CreateAt = now fileInfo.UpdateAt = now fileInfo.PostId = "" + fileInfo.ChannelId = "" if _, err := a.Srv().Store().FileInfo().Save(fileInfo); err != nil { var appErr *model.AppError diff --git a/server/channels/app/file_test.go b/server/channels/app/file_test.go index 6c7143cae6..842e69fb55 100644 --- a/server/channels/app/file_test.go +++ b/server/channels/app/file_test.go @@ -368,6 +368,7 @@ func TestSearchFilesInTeamForUser(t *testing.T) { fileInfo, err := th.App.Srv().Store().FileInfo().Save(&model.FileInfo{ CreatorId: th.BasicUser.Id, PostId: th.BasicPost.Id, + ChannelId: th.BasicPost.ChannelId, Name: searchTerm, Path: searchTerm, Extension: "jpg", diff --git a/server/channels/app/import_functions.go b/server/channels/app/import_functions.go index 3d7956d1e4..f266d2e30e 100644 --- a/server/channels/app/import_functions.go +++ b/server/channels/app/import_functions.go @@ -1638,7 +1638,7 @@ func (a *App) uploadAttachments(c request.CTX, attachments *[]imports.Attachment func (a *App) updateFileInfoWithPostId(post *model.Post) { for _, fileID := range post.FileIds { - if err := a.Srv().Store().FileInfo().AttachToPost(fileID, post.Id, post.UserId); err != nil { + if err := a.Srv().Store().FileInfo().AttachToPost(fileID, post.Id, post.ChannelId, post.UserId); err != nil { mlog.Error("Error attaching files to post.", mlog.String("post_id", post.Id), mlog.Any("post_file_ids", post.FileIds), mlog.Err(err)) } } diff --git a/server/channels/app/post.go b/server/channels/app/post.go index 0a58666b08..3e360bc863 100644 --- a/server/channels/app/post.go +++ b/server/channels/app/post.go @@ -416,7 +416,7 @@ func (a *App) addPostPreviewProp(post *model.Post) (*model.Post, error) { func (a *App) attachFilesToPost(post *model.Post) *model.AppError { var attachedIds []string for _, fileID := range post.FileIds { - err := a.Srv().Store().FileInfo().AttachToPost(fileID, post.Id, post.UserId) + err := a.Srv().Store().FileInfo().AttachToPost(fileID, post.Id, post.ChannelId, post.UserId) if err != nil { mlog.Warn("Failed to attach file to post", mlog.String("file_id", fileID), mlog.String("post_id", post.Id), mlog.Err(err)) continue diff --git a/server/channels/db/migrations/migrations.list b/server/channels/db/migrations/migrations.list index b5fe2b6b1a..6a7d33d5c6 100644 --- a/server/channels/db/migrations/migrations.list +++ b/server/channels/db/migrations/migrations.list @@ -210,6 +210,8 @@ channels/db/migrations/mysql/000104_upgrade_notifyadmin.down.sql channels/db/migrations/mysql/000104_upgrade_notifyadmin.up.sql channels/db/migrations/mysql/000105_remove_tokens.down.sql channels/db/migrations/mysql/000105_remove_tokens.up.sql +channels/db/migrations/mysql/000106_fileinfo_channelid.down.sql +channels/db/migrations/mysql/000106_fileinfo_channelid.up.sql channels/db/migrations/postgres/000001_create_teams.down.sql channels/db/migrations/postgres/000001_create_teams.up.sql channels/db/migrations/postgres/000002_create_team_members.down.sql @@ -420,3 +422,5 @@ channels/db/migrations/postgres/000104_upgrade_notifyadmin.down.sql channels/db/migrations/postgres/000104_upgrade_notifyadmin.up.sql channels/db/migrations/postgres/000105_remove_tokens.down.sql channels/db/migrations/postgres/000105_remove_tokens.up.sql +channels/db/migrations/postgres/000106_fileinfo_channelid.down.sql +channels/db/migrations/postgres/000106_fileinfo_channelid.up.sql diff --git a/server/channels/db/migrations/mysql/000106_fileinfo_channelid.down.sql b/server/channels/db/migrations/mysql/000106_fileinfo_channelid.down.sql new file mode 100644 index 0000000000..8892ce5a58 --- /dev/null +++ b/server/channels/db/migrations/mysql/000106_fileinfo_channelid.down.sql @@ -0,0 +1,29 @@ +SET @preparedStatement = (SELECT IF( + EXISTS( + SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS + WHERE table_name = 'FileInfo' + AND table_schema = DATABASE() + AND index_name = 'idx_fileinfo_channel_id_create_at' + ) > 0, + 'DROP INDEX idx_fileinfo_channel_id_create_at ON FileInfo;', + 'SELECT 1' +)); + +PREPARE removeIndexIfExists FROM @preparedStatement; +EXECUTE removeIndexIfExists; +DEALLOCATE PREPARE removeIndexIfExists; + +SET @preparedStatement = (SELECT IF( + EXISTS( + SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS + WHERE table_name = 'FileInfo' + AND table_schema = DATABASE() + AND column_name = 'ChannelId' + ) > 0, + 'ALTER TABLE FileInfo DROP COLUMN ChannelId;', + 'SELECT 1;' +)); + +PREPARE removeColumnIfExists FROM @preparedStatement; +EXECUTE removeColumnIfExists; +DEALLOCATE PREPARE removeColumnIfExists; diff --git a/server/channels/db/migrations/mysql/000106_fileinfo_channelid.up.sql b/server/channels/db/migrations/mysql/000106_fileinfo_channelid.up.sql new file mode 100644 index 0000000000..04ad46de04 --- /dev/null +++ b/server/channels/db/migrations/mysql/000106_fileinfo_channelid.up.sql @@ -0,0 +1,34 @@ +SET @preparedStatement = (SELECT IF( + NOT EXISTS( + SELECT 1 FROM INFORMATION_SCHEMA.COLUMNS + WHERE table_name = 'FileInfo' + AND table_schema = DATABASE() + AND column_name = 'ChannelId' + ), + 'ALTER TABLE FileInfo ADD COLUMN ChannelId varchar(26);', + 'SELECT 1;' +)); + +PREPARE addColumnIfNotExists FROM @preparedStatement; +EXECUTE addColumnIfNotExists; +DEALLOCATE PREPARE addColumnIfNotExists; + +UPDATE FileInfo, Posts +SET FileInfo.ChannelId = Posts.ChannelId +WHERE FileInfo.PostId = Posts.Id +AND FileInfo.ChannelId IS NULL; + +SET @preparedStatement = (SELECT IF( + NOT EXISTS( + SELECT 1 FROM INFORMATION_SCHEMA.STATISTICS + WHERE table_name = 'FileInfo' + AND table_schema = DATABASE() + AND index_name = 'idx_fileinfo_channel_id_create_at' + ), + 'CREATE INDEX idx_fileinfo_channel_id_create_at ON FileInfo(ChannelId, CreateAt);', + 'SELECT 1' +)); + +PREPARE createIndexIfNotExists FROM @preparedStatement; +EXECUTE createIndexIfNotExists; +DEALLOCATE PREPARE createIndexIfNotExists; diff --git a/server/channels/db/migrations/postgres/000106_fileinfo_channelid.down.sql b/server/channels/db/migrations/postgres/000106_fileinfo_channelid.down.sql new file mode 100644 index 0000000000..c5539c108e --- /dev/null +++ b/server/channels/db/migrations/postgres/000106_fileinfo_channelid.down.sql @@ -0,0 +1,2 @@ +DROP INDEX IF EXISTS idx_fileinfo_channel_id_create_at; +ALTER TABLE fileinfo DROP COLUMN IF EXISTS channelid; diff --git a/server/channels/db/migrations/postgres/000106_fileinfo_channelid.up.sql b/server/channels/db/migrations/postgres/000106_fileinfo_channelid.up.sql new file mode 100644 index 0000000000..bff45b2f07 --- /dev/null +++ b/server/channels/db/migrations/postgres/000106_fileinfo_channelid.up.sql @@ -0,0 +1,3 @@ +ALTER TABLE fileinfo ADD COLUMN IF NOT EXISTS channelid varchar(26); +UPDATE fileinfo SET channelid = posts.channelid FROM posts WHERE fileinfo.channelid IS NULL AND fileinfo.postid = posts.id; +CREATE INDEX IF NOT EXISTS idx_fileinfo_channel_id_create_at ON fileinfo(channelid, createat); diff --git a/server/channels/store/opentracinglayer/opentracinglayer.go b/server/channels/store/opentracinglayer/opentracinglayer.go index f0c29d4402..1f7d408365 100644 --- a/server/channels/store/opentracinglayer/opentracinglayer.go +++ b/server/channels/store/opentracinglayer/opentracinglayer.go @@ -3477,7 +3477,7 @@ func (s *OpenTracingLayerEmojiStore) Search(name string, prefixOnly bool, limit return result, err } -func (s *OpenTracingLayerFileInfoStore) AttachToPost(fileID string, postID string, creatorID string) error { +func (s *OpenTracingLayerFileInfoStore) AttachToPost(fileID string, postID string, channelID string, creatorID string) error { origCtx := s.Root.Store.Context() span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "FileInfoStore.AttachToPost") s.Root.Store.SetContext(newCtx) @@ -3486,7 +3486,7 @@ func (s *OpenTracingLayerFileInfoStore) AttachToPost(fileID string, postID strin }() defer span.Finish() - err := s.FileInfoStore.AttachToPost(fileID, postID, creatorID) + err := s.FileInfoStore.AttachToPost(fileID, postID, channelID, creatorID) if err != nil { span.LogFields(spanlog.Error(err)) ext.Error.Set(span, true) diff --git a/server/channels/store/retrylayer/retrylayer.go b/server/channels/store/retrylayer/retrylayer.go index 196ddcf914..121a769248 100644 --- a/server/channels/store/retrylayer/retrylayer.go +++ b/server/channels/store/retrylayer/retrylayer.go @@ -3892,11 +3892,11 @@ func (s *RetryLayerEmojiStore) Search(name string, prefixOnly bool, limit int) ( } -func (s *RetryLayerFileInfoStore) AttachToPost(fileID string, postID string, creatorID string) error { +func (s *RetryLayerFileInfoStore) AttachToPost(fileID string, postID string, channelID string, creatorID string) error { tries := 0 for { - err := s.FileInfoStore.AttachToPost(fileID, postID, creatorID) + err := s.FileInfoStore.AttachToPost(fileID, postID, channelID, creatorID) if err == nil { return nil } diff --git a/server/channels/store/searchlayer/file_info_layer.go b/server/channels/store/searchlayer/file_info_layer.go index c9b0188639..85253841aa 100644 --- a/server/channels/store/searchlayer/file_info_layer.go +++ b/server/channels/store/searchlayer/file_info_layer.go @@ -112,8 +112,8 @@ func (s SearchFileInfoStore) SetContent(fileID, content string) error { return err } -func (s SearchFileInfoStore) AttachToPost(fileId, postId, creatorId string) error { - err := s.FileInfoStore.AttachToPost(fileId, postId, creatorId) +func (s SearchFileInfoStore) AttachToPost(fileId, postId, channelId, creatorId string) error { + err := s.FileInfoStore.AttachToPost(fileId, postId, channelId, creatorId) if err == nil { nFileInfo, err2 := s.FileInfoStore.GetFromMaster(fileId) if err2 == nil { diff --git a/server/channels/store/searchtest/file_info_layer.go b/server/channels/store/searchtest/file_info_layer.go index ecb2966833..ff68961da2 100644 --- a/server/channels/store/searchtest/file_info_layer.go +++ b/server/channels/store/searchtest/file_info_layer.go @@ -207,11 +207,11 @@ func testFileInfoSearchFileInfosIncludingDMs(t *testing.T, th *SearchTestHelper) post2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "dm test", "", model.PostTypeDefault, 0, false) require.NoError(t, err) - p1, err := th.createFileInfo(th.User.Id, post.Id, "dm test filename", "dm contenttest filename", "jpg", "image/jpeg", 0, 1) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "dm test filename", "dm contenttest filename", "jpg", "image/jpeg", 0, 1) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "dm other filename", "dm other filename", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "dm other filename", "dm other filename", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post2.Id, "channel test filename", "channel contenttest filename", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post2.Id, post2.ChannelId, "channel test filename", "channel contenttest filename", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -248,11 +248,11 @@ func testFileInfoSearchFileInfosWithPagination(t *testing.T, th *SearchTestHelpe post2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "dm test", "", model.PostTypeDefault, 20000, false) require.NoError(t, err) - p1, err := th.createFileInfo(th.User.Id, post.Id, "dm test filename", "dm contenttest filename", "jpg", "image/jpeg", 10000, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "dm test filename", "dm contenttest filename", "jpg", "image/jpeg", 10000, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "dm other filename", "dm other filename", "jpg", "image/jpeg", 20000, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "dm other filename", "dm other filename", "jpg", "image/jpeg", 20000, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post2.Id, "channel test filename", "channel contenttest filename", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post2.Id, post2.ChannelId, "channel test filename", "channel contenttest filename", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -292,9 +292,9 @@ func testFileInfoSearchExactPhraseInQuotes(t *testing.T, th *SearchTestHelper) { require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "channel test 1 2 3 filename", "channel content test 1 2 3 filename", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "channel test 1 2 3 filename", "channel content test 1 2 3 filename", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "channel test 123 filename", "channel content test 123 filename", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "channel test 123 filename", "channel content test 123 filename", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -322,9 +322,9 @@ func testFileInfoSearchEmailAddresses(t *testing.T, th *SearchTestHelper) { require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "test email test@test.com", "test email test@content.com", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "test email test@test.com", "test email test@content.com", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "test email test2@test.com", "test email test2@content.com", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "test email test2@test.com", "test email test2@content.com", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -373,7 +373,7 @@ func testFileInfoSearchMarkdownUnderscores(t *testing.T, th *SearchTestHelper) { require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "_start middle end_ _another_", "_start middle end_ _another_", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "_start middle end_ _another_", "_start middle end_ _another_", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -420,9 +420,9 @@ func testFileInfoSearchNonLatinWords(t *testing.T, th *SearchTestHelper) { defer th.deleteUserPosts(th.User.Id) t.Run("Should be able to search chinese words", func(t *testing.T) { - p1, err := th.createFileInfo(th.User.Id, post.Id, "你好", "你好", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "你好", "你好", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "你", "你", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "你", "你", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -453,7 +453,7 @@ func testFileInfoSearchNonLatinWords(t *testing.T, th *SearchTestHelper) { }) }) t.Run("Should be able to search cyrillic words", func(t *testing.T) { - p1, err := th.createFileInfo(th.User.Id, post.Id, "слово test", "слово test", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "слово test", "слово test", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -476,9 +476,9 @@ func testFileInfoSearchNonLatinWords(t *testing.T, th *SearchTestHelper) { }) t.Run("Should be able to search japanese words", func(t *testing.T) { - p1, err := th.createFileInfo(th.User.Id, post.Id, "本", "本", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "本", "本", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "本木", "本木", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "本木", "本木", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -511,9 +511,9 @@ func testFileInfoSearchNonLatinWords(t *testing.T, th *SearchTestHelper) { }) t.Run("Should be able to search korean words", func(t *testing.T) { - p1, err := th.createFileInfo(th.User.Id, post.Id, "불", "불", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "불", "불", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "불다", "불다", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "불다", "불다", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -550,9 +550,9 @@ func testFileInfoSearchAlternativeSpellings(t *testing.T, th *SearchTestHelper) require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "Straße test", "Straße test", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "Straße test", "Straße test", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "Strasse test", "Strasse test", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "Strasse test", "Strasse test", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -578,9 +578,9 @@ func testFileInfoSearchAlternativeSpellingsAccents(t *testing.T, th *SearchTestH require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "café", "café", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "café", "café", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "café", "café", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "café", "café", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -612,9 +612,9 @@ func testFileInfoSearchOrExcludeFileInfosBySpecificUser(t *testing.T, th *Search require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "test fromuser filename", "test fromuser filename", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "test fromuser filename", "test fromuser filename", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User2.Id, post.Id, "test fromuser filename", "test fromuser filename", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User2.Id, post.Id, post.ChannelId, "test fromuser filename", "test fromuser filename", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User2.Id) @@ -635,9 +635,9 @@ func testFileInfoSearchOrExcludeFileInfosInChannel(t *testing.T, th *SearchTestH require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "test fromuser filename", "test fromuser filename", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "test fromuser filename", "test fromuser filename", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post2.Id, "test fromuser filename", "test fromuser filename", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post2.Id, post2.ChannelId, "test fromuser filename", "test fromuser filename", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User2.Id) @@ -666,9 +666,9 @@ func testFileInfoSearchOrExcludeFileInfosInDMGM(t *testing.T, th *SearchTestHelp defer th.deleteUserPosts(th.User.Id) defer th.deleteUserPosts(th.User2.Id) - p1, err := th.createFileInfo(th.User.Id, post1.Id, "test fromuser", "test fromuser", "jpg", "image/jpg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "test fromuser", "test fromuser", "jpg", "image/jpg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User2.Id, post2.Id, "test fromuser 2", "test fromuser 2", "jpg", "image/jpg", 0, 0) + p2, err := th.createFileInfo(th.User2.Id, post2.Id, post2.ChannelId, "test fromuser 2", "test fromuser 2", "jpg", "image/jpg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User2.Id) @@ -716,11 +716,11 @@ func testFileInfoSearchOrExcludeByExtensions(t *testing.T, th *SearchTestHelper) require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "test", "test", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "test", "test", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "test", "test", "png", "image/png", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "test", "test", "png", "image/png", 0, 0) require.NoError(t, err) - p3, err := th.createFileInfo(th.User.Id, post.Id, "test", "test", "bmp", "image/bmp", 0, 0) + p3, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "test", "test", "bmp", "image/bmp", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -787,13 +787,13 @@ func testFileInfoFilterFilesInSpecificDate(t *testing.T, th *SearchTestHelper) { defer th.deleteUserPosts(th.User.Id) creationDate := model.GetMillisForTime(time.Date(2020, 03, 22, 12, 0, 0, 0, time.UTC)) - p1, err := th.createFileInfo(th.User.Id, post1.Id, "test in specific date", "test in specific date", "jpg", "image/jpeg", creationDate, 0) + p1, err := th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "test in specific date", "test in specific date", "jpg", "image/jpeg", creationDate, 0) require.NoError(t, err) creationDate2 := model.GetMillisForTime(time.Date(2020, 03, 23, 0, 0, 0, 0, time.UTC)) - p2, err := th.createFileInfo(th.User.Id, post2.Id, "test in the present", "test in the present", "jpg", "image/jpeg", creationDate2, 0) + p2, err := th.createFileInfo(th.User.Id, post2.Id, post2.ChannelId, "test in the present", "test in the present", "jpg", "image/jpeg", creationDate2, 0) require.NoError(t, err) creationDate3 := model.GetMillisForTime(time.Date(2020, 03, 21, 23, 59, 59, 0, time.UTC)) - p3, err := th.createFileInfo(th.User.Id, post1.Id, "test in the present", "test in the present", "jpg", "image/jpeg", creationDate3, 0) + p3, err := th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "test in the present", "test in the present", "jpg", "image/jpeg", creationDate3, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -830,13 +830,13 @@ func testFileInfoFilterFilesBeforeSpecificDate(t *testing.T, th *SearchTestHelpe defer th.deleteUserPosts(th.User.Id) creationDate := model.GetMillisForTime(time.Date(2020, 03, 01, 12, 0, 0, 0, time.UTC)) - p1, err := th.createFileInfo(th.User.Id, post1.Id, "test in specific date", "test in specific date", "jpg", "image/jpeg", creationDate, 0) + p1, err := th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "test in specific date", "test in specific date", "jpg", "image/jpeg", creationDate, 0) require.NoError(t, err) creationDate2 := model.GetMillisForTime(time.Date(2020, 03, 22, 23, 59, 59, 0, time.UTC)) - p2, err := th.createFileInfo(th.User.Id, post2.Id, "test in specific date 2", "test in specific date 2", "jpg", "image/jpeg", creationDate2, 0) + p2, err := th.createFileInfo(th.User.Id, post2.Id, post2.ChannelId, "test in specific date 2", "test in specific date 2", "jpg", "image/jpeg", creationDate2, 0) require.NoError(t, err) creationDate3 := model.GetMillisForTime(time.Date(2020, 03, 26, 16, 55, 0, 0, time.UTC)) - p3, err := th.createFileInfo(th.User.Id, post1.Id, "test in the present", "test in the present", "jpg", "image/jpeg", creationDate3, 0) + p3, err := th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "test in the present", "test in the present", "jpg", "image/jpeg", creationDate3, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -874,13 +874,13 @@ func testFileInfoFilterFilesAfterSpecificDate(t *testing.T, th *SearchTestHelper defer th.deleteUserPosts(th.User.Id) creationDate := model.GetMillisForTime(time.Date(2020, 03, 01, 12, 0, 0, 0, time.UTC)) - p1, err := th.createFileInfo(th.User.Id, post1.Id, "test in specific date", "test in specific date", "jpg", "image/jpeg", creationDate, 0) + p1, err := th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "test in specific date", "test in specific date", "jpg", "image/jpeg", creationDate, 0) require.NoError(t, err) creationDate2 := model.GetMillisForTime(time.Date(2020, 03, 22, 23, 59, 59, 0, time.UTC)) - p2, err := th.createFileInfo(th.User.Id, post2.Id, "test in specific date 2", "test in specific date 2", "jpg", "image/jpeg", creationDate2, 0) + p2, err := th.createFileInfo(th.User.Id, post2.Id, post2.ChannelId, "test in specific date 2", "test in specific date 2", "jpg", "image/jpeg", creationDate2, 0) require.NoError(t, err) creationDate3 := model.GetMillisForTime(time.Date(2020, 03, 26, 16, 55, 0, 0, time.UTC)) - p3, err := th.createFileInfo(th.User.Id, post1.Id, "test in the present", "test in the present", "jpg", "image/jpeg", creationDate3, 0) + p3, err := th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "test in the present", "test in the present", "jpg", "image/jpeg", creationDate3, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -917,11 +917,11 @@ func testFileInfoFilterFilesWithATerm(t *testing.T, th *SearchTestHelper) { require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post1.Id, "one two three", "one two three", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "one two three", "one two three", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post2.Id, "one four five six", "one four five six", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post2.Id, post2.ChannelId, "one four five six", "one four five six", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post1.Id, "one seven eight nine", "one seven eight nine", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "one seven eight nine", "one seven eight nine", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -956,11 +956,11 @@ func testFileInfoSearchUsingBooleanOperators(t *testing.T, th *SearchTestHelper) require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "one two three message", "one two three message", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "one two three message", "one two three message", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "two messages", "two messages", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "two messages", "two messages", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "another message", "another message", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "another message", "another message", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -998,13 +998,13 @@ func testFileInfoSearchUsingCombinedFilters(t *testing.T, th *SearchTestHelper) defer th.deleteUserPosts(th.User.Id) creationDate := model.GetMillisForTime(time.Date(2020, 03, 01, 12, 0, 0, 0, time.UTC)) - p1, err := th.createFileInfo(th.User.Id, post2.Id, "one two three message", "one two three message", "jpg", "image/jpeg", creationDate, 0) + p1, err := th.createFileInfo(th.User.Id, post2.Id, post2.ChannelId, "one two three message", "one two three message", "jpg", "image/jpeg", creationDate, 0) require.NoError(t, err) creationDate2 := model.GetMillisForTime(time.Date(2020, 03, 10, 12, 0, 0, 0, time.UTC)) - p2, err := th.createFileInfo(th.User2.Id, post2.Id, "two messages", "two messages", "jpg", "image/jpeg", creationDate2, 0) + p2, err := th.createFileInfo(th.User2.Id, post2.Id, post2.ChannelId, "two messages", "two messages", "jpg", "image/jpeg", creationDate2, 0) require.NoError(t, err) creationDate3 := model.GetMillisForTime(time.Date(2020, 03, 20, 12, 0, 0, 0, time.UTC)) - p3, err := th.createFileInfo(th.User.Id, post1.Id, "two another message", "two another message", "jpg", "image/jpeg", creationDate3, 0) + p3, err := th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "two another message", "two another message", "jpg", "image/jpeg", creationDate3, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User2.Id) @@ -1067,13 +1067,13 @@ func testFileInfoSearchIgnoringStopWords(t *testing.T, th *SearchTestHelper) { require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "the search for a bunch of stop words", "the search for a bunch of stop words", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "the search for a bunch of stop words", "the search for a bunch of stop words", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "the objective is to avoid a bunch of stop words", "the objective is to avoid a bunch of stop words", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "the objective is to avoid a bunch of stop words", "the objective is to avoid a bunch of stop words", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p3, err := th.createFileInfo(th.User.Id, post.Id, "in the a on to where you", "in the a on to where you", "jpg", "image/jpeg", 0, 0) + p3, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "in the a on to where you", "in the a on to where you", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p4, err := th.createFileInfo(th.User.Id, post.Id, "where is the car?", "where is the car?", "jpg", "image/jpeg", 0, 0) + p4, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "where is the car?", "where is the car?", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1129,11 +1129,11 @@ func testFileInfoSupportStemming(t *testing.T, th *SearchTestHelper) { require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "search post", "search post", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "search post", "search post", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "searching post", "searching post", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "searching post", "searching post", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "another post", "another post", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "another post", "another post", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1153,11 +1153,11 @@ func testFileInfoSupportWildcards(t *testing.T, th *SearchTestHelper) { require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "search post", "search post", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "search post", "search post", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "searching", "searching", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "searching", "searching", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "another post", "another post", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "another post", "another post", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1190,11 +1190,11 @@ func testFileInfoNotSupportPrecedingWildcards(t *testing.T, th *SearchTestHelper require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - _, err = th.createFileInfo(th.User.Id, post.Id, "search post", "search post", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "search post", "search post", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "searching post", "searching post", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "searching post", "searching post", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "another post", "another post", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "another post", "another post", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1212,9 +1212,9 @@ func testFileInfoSearchDiscardWildcardAlone(t *testing.T, th *SearchTestHelper) require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "qwerty", "qwerty", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "qwerty", "qwerty", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "qwertyjkl", "qwertyjkl", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "qwertyjkl", "qwertyjkl", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1233,9 +1233,9 @@ func testFileInfoSupportTermsWithDash(t *testing.T, th *SearchTestHelper) { require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "search term-with-dash", "search term-with-dash", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "search term-with-dash", "search term-with-dash", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "searching term with dash", "searching term with dash", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "searching term with dash", "searching term with dash", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1267,9 +1267,9 @@ func testFileInfoSupportTermsWithUnderscore(t *testing.T, th *SearchTestHelper) require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "search term_with_underscore", "search term_with_underscore", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "search term_with_underscore", "search term_with_underscore", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "searching term with underscore", "searching term with underscore", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "searching term with underscore", "searching term with underscore", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1307,11 +1307,11 @@ func testFileInfoSearchInDeletedOrArchivedChannels(t *testing.T, th *SearchTestH require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post1.Id, "message in deleted channel", "message in deleted channel", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "message in deleted channel", "message in deleted channel", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post2.Id, "message in regular channel", "message in regular channel", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post2.Id, post2.ChannelId, "message in regular channel", "message in regular channel", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p3, err := th.createFileInfo(th.User.Id, post3.Id, "message in private channel", "message in private channel", "jpg", "image/jpeg", 0, 0) + p3, err := th.createFileInfo(th.User.Id, post3.Id, post3.ChannelId, "message in private channel", "message in private channel", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1382,9 +1382,9 @@ func testFileInfoSearchTermsWithDashes(t *testing.T, th *SearchTestHelper) { require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "message with-dash-term", "message with-dash-term", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "message with-dash-term", "message with-dash-term", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "message with dash term", "message with dash term", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "message with dash term", "message with dash term", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1431,9 +1431,9 @@ func testFileInfoSearchTermsWithDots(t *testing.T, th *SearchTestHelper) { require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "message with.dots.term", "message with.dots.term", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "message with.dots.term", "message with.dots.term", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "message with dots term", "message with dots term", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "message with dots term", "message with dots term", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1480,9 +1480,9 @@ func testFileInfoSearchTermsWithUnderscores(t *testing.T, th *SearchTestHelper) require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "message with_underscores_term", "message with_underscores_term", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "message with_underscores_term", "message with_underscores_term", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post.Id, "message with underscores term", "message with underscores term", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "message with underscores term", "message with underscores term", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1532,11 +1532,11 @@ func testFileInfoSupportStemmingAndWildcards(t *testing.T, th *SearchTestHelper) require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post1.Id, "approve", "approve", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "approve", "approve", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post2.Id, "approved", "approved", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post2.Id, post2.ChannelId, "approved", "approved", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p3, err := th.createFileInfo(th.User.Id, post2.Id, "approvedz", "approvedz", "jpg", "image/jpeg", 0, 0) + p3, err := th.createFileInfo(th.User.Id, post2.Id, post2.ChannelId, "approvedz", "approvedz", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1568,9 +1568,9 @@ func testFileInfoSupportWildcardOutsideQuotes(t *testing.T, th *SearchTestHelper post2, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "testmessage", "", model.PostTypeDefault, 0, false) require.NoError(t, err) - p1, err := th.createFileInfo(th.User.Id, post1.Id, "hello world", "hello world", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post1.Id, post1.ChannelId, "hello world", "hello world", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - p2, err := th.createFileInfo(th.User.Id, post2.Id, "hell or heaven", "hell or heaven", "jpg", "image/jpeg", 0, 0) + p2, err := th.createFileInfo(th.User.Id, post2.Id, post2.ChannelId, "hell or heaven", "hell or heaven", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1600,7 +1600,7 @@ func testFileInfoSlashShouldNotBeCharSeparator(t *testing.T, th *SearchTestHelpe require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "alpha/beta gamma, theta", "alpha/beta gamma, theta", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "alpha/beta gamma, theta", "alpha/beta gamma, theta", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) @@ -1631,9 +1631,9 @@ func testFileInfoSearchEmailsWithoutQuotes(t *testing.T, th *SearchTestHelper) { require.NoError(t, err) defer th.deleteUserPosts(th.User.Id) - p1, err := th.createFileInfo(th.User.Id, post.Id, "message test@test.com", "message test@test.com", "jpg", "image/jpeg", 0, 0) + p1, err := th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "message test@test.com", "message test@test.com", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) - _, err = th.createFileInfo(th.User.Id, post.Id, "message test2@test.com", "message test2@test.com", "jpg", "image/jpeg", 0, 0) + _, err = th.createFileInfo(th.User.Id, post.Id, post.ChannelId, "message test2@test.com", "message test2@test.com", "jpg", "image/jpeg", 0, 0) require.NoError(t, err) defer th.deleteUserFileInfos(th.User.Id) diff --git a/server/channels/store/searchtest/helper.go b/server/channels/store/searchtest/helper.go index 14f327dbe9..c43aaf8cfa 100644 --- a/server/channels/store/searchtest/helper.go +++ b/server/channels/store/searchtest/helper.go @@ -371,10 +371,11 @@ func (th *SearchTestHelper) createPost(userID, channelID, message, hashtags, pos return th.Store.Post().Save(postModel) } -func (th *SearchTestHelper) createFileInfoModel(creatorID, postID, name, content, extension, mimeType string, createAt, size int64) *model.FileInfo { +func (th *SearchTestHelper) createFileInfoModel(creatorID, postID, channelID, name, content, extension, mimeType string, createAt, size int64) *model.FileInfo { return &model.FileInfo{ CreatorId: creatorID, PostId: postID, + ChannelId: channelID, CreateAt: createAt, UpdateAt: createAt, DeleteAt: 0, @@ -387,12 +388,12 @@ func (th *SearchTestHelper) createFileInfoModel(creatorID, postID, name, content } } -func (th *SearchTestHelper) createFileInfo(creatorID, postID, name, content, extension, mimeType string, createAt, size int64) (*model.FileInfo, error) { +func (th *SearchTestHelper) createFileInfo(creatorID, postID, channelID, name, content, extension, mimeType string, createAt, size int64) (*model.FileInfo, error) { var creationTime int64 = 1000000 if createAt > 0 { creationTime = createAt } - fileInfoModel := th.createFileInfoModel(creatorID, postID, name, content, extension, mimeType, creationTime, size) + fileInfoModel := th.createFileInfoModel(creatorID, postID, channelID, name, content, extension, mimeType, creationTime, size) return th.Store.FileInfo().Save(fileInfoModel) } diff --git a/server/channels/store/sqlstore/channel_store.go b/server/channels/store/sqlstore/channel_store.go index 27bfa5d56a..76bd520457 100644 --- a/server/channels/store/sqlstore/channel_store.go +++ b/server/channels/store/sqlstore/channel_store.go @@ -2265,7 +2265,7 @@ func (s SqlChannelStore) GetFileCount(channelId string) (int64, error) { FileInfo WHERE FileInfo.DeleteAt = 0 - AND FileInfo.PostId IN (SELECT id FROM Posts WHERE ChannelId = ?)`, + AND FileInfo.ChannelId = ?`, channelId) if err != nil { return 0, errors.Wrapf(err, "failed to count files with channelId=%s", channelId) diff --git a/server/channels/store/sqlstore/file_info_store.go b/server/channels/store/sqlstore/file_info_store.go index da661f686a..b54efbe66e 100644 --- a/server/channels/store/sqlstore/file_info_store.go +++ b/server/channels/store/sqlstore/file_info_store.go @@ -88,6 +88,7 @@ func newSqlFileInfoStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterfac "FileInfo.Id", "FileInfo.CreatorId", "FileInfo.PostId", + "COALESCE(FileInfo.ChannelId, '') AS ChannelId", "FileInfo.CreateAt", "FileInfo.UpdateAt", "FileInfo.DeleteAt", @@ -118,10 +119,10 @@ func (fs SqlFileInfoStore) Save(info *model.FileInfo) (*model.FileInfo, error) { query := ` INSERT INTO FileInfo - (Id, CreatorId, PostId, CreateAt, UpdateAt, DeleteAt, Path, ThumbnailPath, PreviewPath, + (Id, CreatorId, PostId, ChannelId, CreateAt, UpdateAt, DeleteAt, Path, ThumbnailPath, PreviewPath, Name, Extension, Size, MimeType, Width, Height, HasPreviewImage, MiniPreview, Content, RemoteId) VALUES - (:Id, :CreatorId, :PostId, :CreateAt, :UpdateAt, :DeleteAt, :Path, :ThumbnailPath, :PreviewPath, + (:Id, :CreatorId, :PostId, :ChannelId, :CreateAt, :UpdateAt, :DeleteAt, :Path, :ThumbnailPath, :PreviewPath, :Name, :Extension, :Size, :MimeType, :Width, :Height, :HasPreviewImage, :MiniPreview, :Content, :RemoteId) ` @@ -133,9 +134,8 @@ func (fs SqlFileInfoStore) Save(info *model.FileInfo) (*model.FileInfo, error) { func (fs SqlFileInfoStore) GetByIds(ids []string) ([]*model.FileInfo, error) { query := fs.getQueryBuilder(). - Select(append(fs.queryFields, "COALESCE(P.ChannelId, '') as ChannelId")...). + Select(fs.queryFields...). From("FileInfo"). - LeftJoin("Posts as P ON FileInfo.PostId=P.Id"). Where(sq.Eq{"FileInfo.Id": ids}). Where(sq.Eq{"FileInfo.DeleteAt": 0}). OrderBy("FileInfo.CreateAt DESC") @@ -166,6 +166,8 @@ func (fs SqlFileInfoStore) Upsert(info *model.FileInfo) (*model.FileInfo, error) return nil, err } + // PostID and ChannelID are deliberately ignored + // from the list of fields to keep those two immutable. queryString, args, err := fs.getQueryBuilder(). Update("FileInfo"). SetMap(map[string]any{ @@ -261,8 +263,7 @@ func (fs SqlFileInfoStore) GetWithOptions(page, perPage int, opt *model.GetFileI From("FileInfo") if len(opt.ChannelIds) > 0 { - query = query.Join("Posts ON FileInfo.PostId = Posts.Id"). - Where(sq.Eq{"Posts.ChannelId": opt.ChannelIds}) + query = query.Where(sq.Eq{"FileInfo.ChannelId": opt.ChannelIds}) } if len(opt.UserIds) > 0 { @@ -388,10 +389,11 @@ func (fs SqlFileInfoStore) GetForUser(userId string) ([]*model.FileInfo, error) return infos, nil } -func (fs SqlFileInfoStore) AttachToPost(fileId, postId, creatorId string) error { +func (fs SqlFileInfoStore) AttachToPost(fileId, postId, channelId, creatorId string) error { query := fs.getQueryBuilder(). Update("FileInfo"). Set("PostId", postId). + Set("ChannelId", channelId). Where(sq.And{ sq.Eq{"Id": fileId}, sq.Eq{"PostId": ""}, @@ -506,10 +508,9 @@ func (fs SqlFileInfoStore) Search(paramsList []*model.SearchParams, userId, team return nil, err } query := fs.getQueryBuilder(). - Select(append(fs.queryFields, "Coalesce(P.ChannelId, '') AS ChannelId")...). + Select(fs.queryFields...). From("FileInfo"). - LeftJoin("Posts as P ON FileInfo.PostId=P.Id"). - LeftJoin("Channels as C ON C.Id=P.ChannelId"). + LeftJoin("Channels as C ON C.Id=FileInfo.ChannelId"). LeftJoin("ChannelMembers as CM ON C.Id=CM.ChannelId"). Where(sq.Eq{"FileInfo.DeleteAt": 0}). OrderBy("FileInfo.CreateAt DESC"). @@ -715,9 +716,8 @@ func (fs SqlFileInfoStore) CountAll() (int64, error) { func (fs SqlFileInfoStore) GetFilesBatchForIndexing(startTime int64, startFileID string, limit int) ([]*model.FileForIndexing, error) { files := []*model.FileForIndexing{} sql, args, _ := fs.getQueryBuilder(). - Select(append(fs.queryFields, "Coalesce(p.ChannelId, '') AS ChannelId")...). + Select(fs.queryFields...). From("FileInfo"). - LeftJoin("Posts AS p ON FileInfo.PostId = p.Id"). Where(sq.Or{ sq.Gt{"FileInfo.CreateAt": startTime}, sq.And{ diff --git a/server/channels/store/sqlstore/integrity.go b/server/channels/store/sqlstore/integrity.go index dd55de983f..7c9758b915 100644 --- a/server/channels/store/sqlstore/integrity.go +++ b/server/channels/store/sqlstore/integrity.go @@ -134,6 +134,15 @@ func checkChannelsPostsIntegrity(ss *SqlStore) model.IntegrityCheckResult { }) } +func checkChannelsFileInfoIntegrity(ss *SqlStore) model.IntegrityCheckResult { + return checkParentChildIntegrity(ss, relationalCheckConfig{ + parentName: "Channels", + parentIdAttr: "ChannelId", + childName: "FileInfo", + childIdAttr: "Id", + }) +} + func checkCommandsCommandWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult { return checkParentChildIntegrity(ss, relationalCheckConfig{ parentName: "Commands", @@ -458,6 +467,7 @@ func checkChannelsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckRes results <- checkChannelsIncomingWebhooksIntegrity(ss) results <- checkChannelsOutgoingWebhooksIntegrity(ss) results <- checkChannelsPostsIntegrity(ss) + results <- checkChannelsFileInfoIntegrity(ss) } func checkCommandsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) { diff --git a/server/channels/store/sqlstore/integrity_test.go b/server/channels/store/sqlstore/integrity_test.go index d6b11ff70c..b61d325231 100644 --- a/server/channels/store/sqlstore/integrity_test.go +++ b/server/channels/store/sqlstore/integrity_test.go @@ -115,7 +115,7 @@ func createEmoji(ss store.Store, userId string) *model.Emoji { return emoji } -func createFileInfo(ss store.Store, postId, userId string) *model.FileInfo { +func createFileInfo(ss store.Store, postId, channelId, userId string) *model.FileInfo { m := model.FileInfo{} m.PostId = postId m.CreatorId = userId @@ -623,7 +623,7 @@ func TestCheckPostsFileInfoIntegrity(t *testing.T) { t.Run("should generate a report with one record", func(t *testing.T) { postId := model.NewId() - info := createFileInfo(ss, postId, model.NewId()) + info := createFileInfo(ss, postId, model.NewId(), model.NewId()) result := checkPostsFileInfoIntegrity(store) require.NoError(t, result.Err) data := result.Data.(model.RelationalIntegrityCheckData) @@ -1226,7 +1226,7 @@ func TestCheckUsersFileInfoIntegrity(t *testing.T) { t.Run("should generate a report with one record", func(t *testing.T) { user := createUser(ss) userId := user.Id - info := createFileInfo(ss, model.NewId(), userId) + info := createFileInfo(ss, model.NewId(), model.NewId(), userId) dbmap.Exec(`DELETE FROM Users WHERE Id=?`, user.Id) result := checkUsersFileInfoIntegrity(store) require.NoError(t, result.Err) diff --git a/server/channels/store/store.go b/server/channels/store/store.go index 11f92fef14..1ac231cb06 100644 --- a/server/channels/store/store.go +++ b/server/channels/store/store.go @@ -699,7 +699,7 @@ type FileInfoStore interface { GetForUser(userID string) ([]*model.FileInfo, error) GetWithOptions(page, perPage int, opt *model.GetFileInfosOptions) ([]*model.FileInfo, error) InvalidateFileInfosForPostCache(postID string, deleted bool) - AttachToPost(fileID string, postID string, creatorID string) error + AttachToPost(fileID string, postID string, channelID, creatorID string) error DeleteForPost(postID string) (string, error) PermanentDelete(fileID string) error PermanentDeleteBatch(endTime int64, limit int64) (int64, error) diff --git a/server/channels/store/storetest/file_info_store.go b/server/channels/store/storetest/file_info_store.go index 4ca7f450ee..21d65f649d 100644 --- a/server/channels/store/storetest/file_info_store.go +++ b/server/channels/store/storetest/file_info_store.go @@ -106,26 +106,31 @@ func testFileInfoSaveGetByPath(t *testing.T, ss store.Store) { func testFileInfoGetForPost(t *testing.T, ss store.Store) { userId := model.NewId() postId := model.NewId() + channelId := model.NewId() infos := []*model.FileInfo{ { PostId: postId, + ChannelId: channelId, CreatorId: userId, Path: "file.txt", }, { PostId: postId, + ChannelId: channelId, CreatorId: userId, Path: "file.txt", }, { PostId: postId, + ChannelId: channelId, CreatorId: userId, Path: "file.txt", DeleteAt: 123, }, { PostId: model.NewId(), + ChannelId: channelId, CreatorId: userId, Path: "file.txt", }, @@ -225,25 +230,30 @@ func testFileInfoGetForUser(t *testing.T, ss store.Store) { userId := model.NewId() userId2 := model.NewId() postId := model.NewId() + channelId := model.NewId() infos := []*model.FileInfo{ { PostId: postId, + ChannelId: channelId, CreatorId: userId, Path: "file.txt", }, { PostId: postId, + ChannelId: channelId, CreatorId: userId, Path: "file.txt", }, { PostId: postId, + ChannelId: channelId, CreatorId: userId, Path: "file.txt", }, { PostId: model.NewId(), + ChannelId: channelId, CreatorId: userId2, Path: "file.txt", }, @@ -289,6 +299,9 @@ func testFileInfoGetWithOptions(t *testing.T, ss store.Store) { if post.Id != "" { fileInfo.PostId = post.Id } + if post.ChannelId != "" { + fileInfo.ChannelId = post.ChannelId + } _, err := ss.FileInfo().Save(&fileInfo) require.NoError(t, err) return fileInfo @@ -414,6 +427,7 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) { t.Run("should attach files", func(t *testing.T) { userId := model.NewId() postId := model.NewId() + channelId := model.NewId() info1, err := ss.FileInfo().Save(&model.FileInfo{ CreatorId: userId, @@ -429,13 +443,15 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) { require.Equal(t, "", info1.PostId) require.Equal(t, "", info2.PostId) - err = ss.FileInfo().AttachToPost(info1.Id, postId, userId) + err = ss.FileInfo().AttachToPost(info1.Id, postId, channelId, userId) assert.NoError(t, err) info1.PostId = postId + info1.ChannelId = channelId - err = ss.FileInfo().AttachToPost(info2.Id, postId, userId) + err = ss.FileInfo().AttachToPost(info2.Id, postId, channelId, userId) assert.NoError(t, err) info2.PostId = postId + info2.ChannelId = channelId data, err := ss.FileInfo().GetForPost(postId, true, false, false) require.NoError(t, err) @@ -449,6 +465,7 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) { t.Run("should not attach files to multiple posts", func(t *testing.T) { userId := model.NewId() postId := model.NewId() + channelId := model.NewId() info, err := ss.FileInfo().Save(&model.FileInfo{ CreatorId: userId, @@ -458,16 +475,17 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) { require.Equal(t, "", info.PostId) - err = ss.FileInfo().AttachToPost(info.Id, model.NewId(), userId) + err = ss.FileInfo().AttachToPost(info.Id, model.NewId(), channelId, userId) require.NoError(t, err) - err = ss.FileInfo().AttachToPost(info.Id, postId, userId) + err = ss.FileInfo().AttachToPost(info.Id, postId, channelId, userId) require.Error(t, err) }) t.Run("should not attach files owned from a different user", func(t *testing.T) { userId := model.NewId() postId := model.NewId() + channelId := model.NewId() info, err := ss.FileInfo().Save(&model.FileInfo{ CreatorId: model.NewId(), @@ -477,12 +495,13 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) { require.Equal(t, "", info.PostId) - err = ss.FileInfo().AttachToPost(info.Id, postId, userId) + err = ss.FileInfo().AttachToPost(info.Id, postId, channelId, userId) assert.Error(t, err) }) t.Run("should attach files uploaded by nouser", func(t *testing.T) { postId := model.NewId() + channelId := model.NewId() info, err := ss.FileInfo().Save(&model.FileInfo{ CreatorId: "nouser", @@ -491,12 +510,13 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) { require.NoError(t, err) assert.Equal(t, "", info.PostId) - err = ss.FileInfo().AttachToPost(info.Id, postId, model.NewId()) + err = ss.FileInfo().AttachToPost(info.Id, postId, channelId, model.NewId()) require.NoError(t, err) data, err := ss.FileInfo().GetForPost(postId, true, false, false) require.NoError(t, err) info.PostId = postId + info.ChannelId = channelId assert.EqualValues(t, []*model.FileInfo{info}, data) }) } @@ -504,26 +524,31 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) { func testFileInfoDeleteForPost(t *testing.T, ss store.Store) { userId := model.NewId() postId := model.NewId() + channelId := model.NewId() infos := []*model.FileInfo{ { PostId: postId, + ChannelId: channelId, CreatorId: userId, Path: "file.txt", }, { PostId: postId, + ChannelId: channelId, CreatorId: userId, Path: "file.txt", }, { PostId: postId, + ChannelId: channelId, CreatorId: userId, Path: "file.txt", DeleteAt: 123, }, { PostId: model.NewId(), + ChannelId: channelId, CreatorId: userId, Path: "file.txt", }, @@ -549,6 +574,7 @@ func testFileInfoDeleteForPost(t *testing.T, ss store.Store) { func testFileInfoPermanentDelete(t *testing.T, ss store.Store) { info, err := ss.FileInfo().Save(&model.FileInfo{ PostId: model.NewId(), + ChannelId: model.NewId(), CreatorId: model.NewId(), Path: "file.txt", }) @@ -560,9 +586,11 @@ func testFileInfoPermanentDelete(t *testing.T, ss store.Store) { func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) { postId := model.NewId() + channelId := model.NewId() _, err := ss.FileInfo().Save(&model.FileInfo{ PostId: postId, + ChannelId: channelId, CreatorId: model.NewId(), Path: "file.txt", CreateAt: 1000, @@ -571,6 +599,7 @@ func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) { _, err = ss.FileInfo().Save(&model.FileInfo{ PostId: postId, + ChannelId: channelId, CreatorId: model.NewId(), Path: "file.txt", CreateAt: 1200, @@ -579,6 +608,7 @@ func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) { _, err = ss.FileInfo().Save(&model.FileInfo{ PostId: postId, + ChannelId: channelId, CreatorId: model.NewId(), Path: "file.txt", CreateAt: 2000, @@ -600,9 +630,11 @@ func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) { func testFileInfoPermanentDeleteByUser(t *testing.T, ss store.Store) { userId := model.NewId() postId := model.NewId() + channelId := model.NewId() _, err := ss.FileInfo().Save(&model.FileInfo{ PostId: postId, + ChannelId: channelId, CreatorId: userId, Path: "file.txt", }) @@ -668,6 +700,7 @@ func testFileInfoStoreGetFilesBatchForIndexing(t *testing.T, ss store.Store) { require.NoError(t, err) f1, err := ss.FileInfo().Save(&model.FileInfo{ PostId: o1.Id, + ChannelId: o1.ChannelId, CreatorId: model.NewId(), Path: "file1.txt", }) @@ -686,6 +719,7 @@ func testFileInfoStoreGetFilesBatchForIndexing(t *testing.T, ss store.Store) { f2, err := ss.FileInfo().Save(&model.FileInfo{ PostId: o2.Id, + ChannelId: o2.ChannelId, CreatorId: model.NewId(), Path: "file2.txt", }) @@ -705,6 +739,7 @@ func testFileInfoStoreGetFilesBatchForIndexing(t *testing.T, ss store.Store) { f3, err := ss.FileInfo().Save(&model.FileInfo{ PostId: o3.Id, + ChannelId: o3.ChannelId, CreatorId: model.NewId(), Path: "file3.txt", }) @@ -737,6 +772,7 @@ func testFileInfoStoreCountAll(t *testing.T, ss store.Store) { require.NoError(t, err) f1, err := ss.FileInfo().Save(&model.FileInfo{ PostId: model.NewId(), + ChannelId: model.NewId(), CreatorId: model.NewId(), Path: "file1.txt", }) @@ -744,12 +780,14 @@ func testFileInfoStoreCountAll(t *testing.T, ss store.Store) { _, err = ss.FileInfo().Save(&model.FileInfo{ PostId: model.NewId(), + ChannelId: model.NewId(), CreatorId: model.NewId(), Path: "file2.txt", }) require.NoError(t, err) _, err = ss.FileInfo().Save(&model.FileInfo{ PostId: model.NewId(), + ChannelId: model.NewId(), CreatorId: model.NewId(), Path: "file3.txt", }) diff --git a/server/channels/store/storetest/mocks/FileInfoStore.go b/server/channels/store/storetest/mocks/FileInfoStore.go index c9627a84ad..5ea9700707 100644 --- a/server/channels/store/storetest/mocks/FileInfoStore.go +++ b/server/channels/store/storetest/mocks/FileInfoStore.go @@ -14,13 +14,13 @@ type FileInfoStore struct { mock.Mock } -// AttachToPost provides a mock function with given fields: fileID, postID, creatorID -func (_m *FileInfoStore) AttachToPost(fileID string, postID string, creatorID string) error { - ret := _m.Called(fileID, postID, creatorID) +// AttachToPost provides a mock function with given fields: fileID, postID, channelID, creatorID +func (_m *FileInfoStore) AttachToPost(fileID string, postID string, channelID string, creatorID string) error { + ret := _m.Called(fileID, postID, channelID, creatorID) var r0 error - if rf, ok := ret.Get(0).(func(string, string, string) error); ok { - r0 = rf(fileID, postID, creatorID) + if rf, ok := ret.Get(0).(func(string, string, string, string) error); ok { + r0 = rf(fileID, postID, channelID, creatorID) } else { r0 = ret.Error(0) } diff --git a/server/channels/store/timerlayer/timerlayer.go b/server/channels/store/timerlayer/timerlayer.go index 75752bb963..219154d479 100644 --- a/server/channels/store/timerlayer/timerlayer.go +++ b/server/channels/store/timerlayer/timerlayer.go @@ -3182,10 +3182,10 @@ func (s *TimerLayerEmojiStore) Search(name string, prefixOnly bool, limit int) ( return result, err } -func (s *TimerLayerFileInfoStore) AttachToPost(fileID string, postID string, creatorID string) error { +func (s *TimerLayerFileInfoStore) AttachToPost(fileID string, postID string, channelID string, creatorID string) error { start := time.Now() - err := s.FileInfoStore.AttachToPost(fileID, postID, creatorID) + err := s.FileInfoStore.AttachToPost(fileID, postID, channelID, creatorID) elapsed := float64(time.Since(start)) / float64(time.Second) if s.Root.Metrics != nil { diff --git a/server/platform/services/slackimport/slackimport.go b/server/platform/services/slackimport/slackimport.go index 301caed20b..3cc7a1f365 100644 --- a/server/platform/services/slackimport/slackimport.go +++ b/server/platform/services/slackimport/slackimport.go @@ -680,7 +680,7 @@ func (si *SlackImporter) oldImportPost(post *model.Post) string { firstPostId = post.Id } for _, fileId := range post.FileIds { - if err := si.store.FileInfo().AttachToPost(fileId, post.Id, post.UserId); err != nil { + if err := si.store.FileInfo().AttachToPost(fileId, post.Id, post.ChannelId, post.UserId); err != nil { mlog.Error( "Error attaching files to post.", mlog.String("post_id", post.Id),