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
Этот коммит содержится в:
Agniva De Sarker
2023-03-23 22:14:04 +05:30
коммит произвёл GitHub
родитель 1edbde8aa3
Коммит 56b18ca7bf
25 изменённых файлов: 266 добавлений и 138 удалений

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

@@ -36,10 +36,14 @@ type GetFileInfosOptions struct {
} }
type FileInfo struct { type FileInfo struct {
Id string `json:"id"` Id string `json:"id"`
CreatorId string `json:"user_id"` CreatorId string `json:"user_id"`
PostId string `json:"post_id,omitempty"` PostId string `json:"post_id,omitempty"`
ChannelId string `db:"-" json:"channel_id"` // 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"` CreateAt int64 `json:"create_at"`
UpdateAt int64 `json:"update_at"` UpdateAt int64 `json:"update_at"`
DeleteAt int64 `json:"delete_at"` DeleteAt int64 `json:"delete_at"`

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

@@ -916,7 +916,7 @@ func TestGetFileLink(t *testing.T) {
CheckBadRequestStatus(t, resp) CheckBadRequestStatus(t, resp)
// Hacky way to assign file to a post (usually would be done by CreatePost call) // 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) require.NoError(t, err)
th.App.UpdateConfig(func(cfg *model.Config) { *cfg.FileSettings.EnablePublicLink = false }) 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 fileId := fileResp.FileInfos[0].Id
// Hacky way to assign file to a post (usually would be done by CreatePost call) // 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) require.NoError(t, err)
info, err := th.App.Srv().Store().FileInfo().Get(fileId) info, err := th.App.Srv().Store().FileInfo().Get(fileId)
@@ -1139,25 +1139,25 @@ func TestSearchFiles(t *testing.T) {
filename := "search for fileInfo1" filename := "search for fileInfo1"
fileInfo1, appErr := th.App.UploadFile(th.Context, data, th.BasicChannel.Id, filename) fileInfo1, appErr := th.App.UploadFile(th.Context, data, th.BasicChannel.Id, filename)
require.Nil(t, appErr) 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) require.NoError(t, err)
filename = "search for fileInfo2" filename = "search for fileInfo2"
fileInfo2, appErr := th.App.UploadFile(th.Context, data, th.BasicChannel.Id, filename) fileInfo2, appErr := th.App.UploadFile(th.Context, data, th.BasicChannel.Id, filename)
require.Nil(t, appErr) 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) require.NoError(t, err)
filename = "tagged search for fileInfo3" filename = "tagged search for fileInfo3"
fileInfo3, appErr := th.App.UploadFile(th.Context, data, th.BasicChannel.Id, filename) fileInfo3, appErr := th.App.UploadFile(th.Context, data, th.BasicChannel.Id, filename)
require.Nil(t, appErr) 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) require.NoError(t, err)
filename = "tagged for fileInfo4" filename = "tagged for fileInfo4"
fileInfo4, appErr := th.App.UploadFile(th.Context, data, th.BasicChannel.Id, filename) fileInfo4, appErr := th.App.UploadFile(th.Context, data, th.BasicChannel.Id, filename)
require.Nil(t, appErr) 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) require.NoError(t, err)
archivedChannel := th.CreatePublicChannel() archivedChannel := th.CreatePublicChannel()
@@ -1166,7 +1166,7 @@ func TestSearchFiles(t *testing.T) {
post := &model.Post{ChannelId: archivedChannel.Id, Message: model.NewId() + "a"} post := &model.Post{ChannelId: archivedChannel.Id, Message: model.NewId() + "a"}
rpost, _, err := client.CreatePost(post) rpost, _, err := client.CreatePost(post)
require.NoError(t, err) 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) require.NoError(t, err)
th.Client.DeleteChannel(archivedChannel.Id) th.Client.DeleteChannel(archivedChannel.Id)

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

@@ -274,6 +274,7 @@ func (a *App) getInfoForFilename(post *model.Post, teamID, channelID, userID, ol
info.Id = model.NewId() info.Id = model.NewId()
info.CreatorId = post.UserId info.CreatorId = post.UserId
info.PostId = post.Id info.PostId = post.Id
info.ChannelId = post.ChannelId
info.CreateAt = post.CreateAt info.CreateAt = post.CreateAt
info.UpdateAt = post.UpdateAt info.UpdateAt = post.UpdateAt
info.Path = path info.Path = path
@@ -1214,6 +1215,7 @@ func (a *App) CopyFileInfos(userID string, fileIDs []string) ([]string, *model.A
fileInfo.CreateAt = now fileInfo.CreateAt = now
fileInfo.UpdateAt = now fileInfo.UpdateAt = now
fileInfo.PostId = "" fileInfo.PostId = ""
fileInfo.ChannelId = ""
if _, err := a.Srv().Store().FileInfo().Save(fileInfo); err != nil { if _, err := a.Srv().Store().FileInfo().Save(fileInfo); err != nil {
var appErr *model.AppError var appErr *model.AppError

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

@@ -368,6 +368,7 @@ func TestSearchFilesInTeamForUser(t *testing.T) {
fileInfo, err := th.App.Srv().Store().FileInfo().Save(&model.FileInfo{ fileInfo, err := th.App.Srv().Store().FileInfo().Save(&model.FileInfo{
CreatorId: th.BasicUser.Id, CreatorId: th.BasicUser.Id,
PostId: th.BasicPost.Id, PostId: th.BasicPost.Id,
ChannelId: th.BasicPost.ChannelId,
Name: searchTerm, Name: searchTerm,
Path: searchTerm, Path: searchTerm,
Extension: "jpg", Extension: "jpg",

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

@@ -1638,7 +1638,7 @@ func (a *App) uploadAttachments(c request.CTX, attachments *[]imports.Attachment
func (a *App) updateFileInfoWithPostId(post *model.Post) { func (a *App) updateFileInfoWithPostId(post *model.Post) {
for _, fileID := range post.FileIds { 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)) mlog.Error("Error attaching files to post.", mlog.String("post_id", post.Id), mlog.Any("post_file_ids", post.FileIds), mlog.Err(err))
} }
} }

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

@@ -416,7 +416,7 @@ func (a *App) addPostPreviewProp(post *model.Post) (*model.Post, error) {
func (a *App) attachFilesToPost(post *model.Post) *model.AppError { func (a *App) attachFilesToPost(post *model.Post) *model.AppError {
var attachedIds []string var attachedIds []string
for _, fileID := range post.FileIds { 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 { 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)) mlog.Warn("Failed to attach file to post", mlog.String("file_id", fileID), mlog.String("post_id", post.Id), mlog.Err(err))
continue continue

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

@@ -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/000104_upgrade_notifyadmin.up.sql
channels/db/migrations/mysql/000105_remove_tokens.down.sql channels/db/migrations/mysql/000105_remove_tokens.down.sql
channels/db/migrations/mysql/000105_remove_tokens.up.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.down.sql
channels/db/migrations/postgres/000001_create_teams.up.sql channels/db/migrations/postgres/000001_create_teams.up.sql
channels/db/migrations/postgres/000002_create_team_members.down.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/000104_upgrade_notifyadmin.up.sql
channels/db/migrations/postgres/000105_remove_tokens.down.sql channels/db/migrations/postgres/000105_remove_tokens.down.sql
channels/db/migrations/postgres/000105_remove_tokens.up.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

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

@@ -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;

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

@@ -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;

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

@@ -0,0 +1,2 @@
DROP INDEX IF EXISTS idx_fileinfo_channel_id_create_at;
ALTER TABLE fileinfo DROP COLUMN IF EXISTS channelid;

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

@@ -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);

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

@@ -3477,7 +3477,7 @@ func (s *OpenTracingLayerEmojiStore) Search(name string, prefixOnly bool, limit
return result, err 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() origCtx := s.Root.Store.Context()
span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "FileInfoStore.AttachToPost") span, newCtx := tracing.StartSpanWithParentByContext(s.Root.Store.Context(), "FileInfoStore.AttachToPost")
s.Root.Store.SetContext(newCtx) s.Root.Store.SetContext(newCtx)
@@ -3486,7 +3486,7 @@ func (s *OpenTracingLayerFileInfoStore) AttachToPost(fileID string, postID strin
}() }()
defer span.Finish() defer span.Finish()
err := s.FileInfoStore.AttachToPost(fileID, postID, creatorID) err := s.FileInfoStore.AttachToPost(fileID, postID, channelID, creatorID)
if err != nil { if err != nil {
span.LogFields(spanlog.Error(err)) span.LogFields(spanlog.Error(err))
ext.Error.Set(span, true) ext.Error.Set(span, true)

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

@@ -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 tries := 0
for { for {
err := s.FileInfoStore.AttachToPost(fileID, postID, creatorID) err := s.FileInfoStore.AttachToPost(fileID, postID, channelID, creatorID)
if err == nil { if err == nil {
return nil return nil
} }

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

@@ -112,8 +112,8 @@ func (s SearchFileInfoStore) SetContent(fileID, content string) error {
return err return err
} }
func (s SearchFileInfoStore) AttachToPost(fileId, postId, creatorId string) error { func (s SearchFileInfoStore) AttachToPost(fileId, postId, channelId, creatorId string) error {
err := s.FileInfoStore.AttachToPost(fileId, postId, creatorId) err := s.FileInfoStore.AttachToPost(fileId, postId, channelId, creatorId)
if err == nil { if err == nil {
nFileInfo, err2 := s.FileInfoStore.GetFromMaster(fileId) nFileInfo, err2 := s.FileInfoStore.GetFromMaster(fileId)
if err2 == nil { if err2 == nil {

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

@@ -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) post2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "dm test", "", model.PostTypeDefault, 0, false)
require.NoError(t, err) 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) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) 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) post2, err := th.createPost(th.User.Id, th.ChannelBasic.Id, "dm test", "", model.PostTypeDefault, 20000, false)
require.NoError(t, err) 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) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -292,9 +292,9 @@ func testFileInfoSearchExactPhraseInQuotes(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -322,9 +322,9 @@ func testFileInfoSearchEmailAddresses(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -373,7 +373,7 @@ func testFileInfoSearchMarkdownUnderscores(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -420,9 +420,9 @@ func testFileInfoSearchNonLatinWords(t *testing.T, th *SearchTestHelper) {
defer th.deleteUserPosts(th.User.Id) defer th.deleteUserPosts(th.User.Id)
t.Run("Should be able to search chinese words", func(t *testing.T) { 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) 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) { 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) 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) { 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) 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) { 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -550,9 +550,9 @@ func testFileInfoSearchAlternativeSpellings(t *testing.T, th *SearchTestHelper)
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -578,9 +578,9 @@ func testFileInfoSearchAlternativeSpellingsAccents(t *testing.T, th *SearchTestH
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -612,9 +612,9 @@ func testFileInfoSearchOrExcludeFileInfosBySpecificUser(t *testing.T, th *Search
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
defer th.deleteUserFileInfos(th.User2.Id) defer th.deleteUserFileInfos(th.User2.Id)
@@ -635,9 +635,9 @@ func testFileInfoSearchOrExcludeFileInfosInChannel(t *testing.T, th *SearchTestH
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
defer th.deleteUserFileInfos(th.User2.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.User.Id)
defer th.deleteUserPosts(th.User2.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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
defer th.deleteUserFileInfos(th.User2.Id) defer th.deleteUserFileInfos(th.User2.Id)
@@ -716,11 +716,11 @@ func testFileInfoSearchOrExcludeByExtensions(t *testing.T, th *SearchTestHelper)
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -787,13 +787,13 @@ func testFileInfoFilterFilesInSpecificDate(t *testing.T, th *SearchTestHelper) {
defer th.deleteUserPosts(th.User.Id) defer th.deleteUserPosts(th.User.Id)
creationDate := model.GetMillisForTime(time.Date(2020, 03, 22, 12, 0, 0, 0, time.UTC)) 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) require.NoError(t, err)
creationDate2 := model.GetMillisForTime(time.Date(2020, 03, 23, 0, 0, 0, 0, time.UTC)) 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) require.NoError(t, err)
creationDate3 := model.GetMillisForTime(time.Date(2020, 03, 21, 23, 59, 59, 0, time.UTC)) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -830,13 +830,13 @@ func testFileInfoFilterFilesBeforeSpecificDate(t *testing.T, th *SearchTestHelpe
defer th.deleteUserPosts(th.User.Id) defer th.deleteUserPosts(th.User.Id)
creationDate := model.GetMillisForTime(time.Date(2020, 03, 01, 12, 0, 0, 0, time.UTC)) 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) require.NoError(t, err)
creationDate2 := model.GetMillisForTime(time.Date(2020, 03, 22, 23, 59, 59, 0, time.UTC)) 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) require.NoError(t, err)
creationDate3 := model.GetMillisForTime(time.Date(2020, 03, 26, 16, 55, 0, 0, time.UTC)) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -874,13 +874,13 @@ func testFileInfoFilterFilesAfterSpecificDate(t *testing.T, th *SearchTestHelper
defer th.deleteUserPosts(th.User.Id) defer th.deleteUserPosts(th.User.Id)
creationDate := model.GetMillisForTime(time.Date(2020, 03, 01, 12, 0, 0, 0, time.UTC)) 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) require.NoError(t, err)
creationDate2 := model.GetMillisForTime(time.Date(2020, 03, 22, 23, 59, 59, 0, time.UTC)) 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) require.NoError(t, err)
creationDate3 := model.GetMillisForTime(time.Date(2020, 03, 26, 16, 55, 0, 0, time.UTC)) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -917,11 +917,11 @@ func testFileInfoFilterFilesWithATerm(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -956,11 +956,11 @@ func testFileInfoSearchUsingBooleanOperators(t *testing.T, th *SearchTestHelper)
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -998,13 +998,13 @@ func testFileInfoSearchUsingCombinedFilters(t *testing.T, th *SearchTestHelper)
defer th.deleteUserPosts(th.User.Id) defer th.deleteUserPosts(th.User.Id)
creationDate := model.GetMillisForTime(time.Date(2020, 03, 01, 12, 0, 0, 0, time.UTC)) 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) require.NoError(t, err)
creationDate2 := model.GetMillisForTime(time.Date(2020, 03, 10, 12, 0, 0, 0, time.UTC)) 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) require.NoError(t, err)
creationDate3 := model.GetMillisForTime(time.Date(2020, 03, 20, 12, 0, 0, 0, time.UTC)) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
defer th.deleteUserFileInfos(th.User2.Id) defer th.deleteUserFileInfos(th.User2.Id)
@@ -1067,13 +1067,13 @@ func testFileInfoSearchIgnoringStopWords(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1129,11 +1129,11 @@ func testFileInfoSupportStemming(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1153,11 +1153,11 @@ func testFileInfoSupportWildcards(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1190,11 +1190,11 @@ func testFileInfoNotSupportPrecedingWildcards(t *testing.T, th *SearchTestHelper
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1212,9 +1212,9 @@ func testFileInfoSearchDiscardWildcardAlone(t *testing.T, th *SearchTestHelper)
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1233,9 +1233,9 @@ func testFileInfoSupportTermsWithDash(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1267,9 +1267,9 @@ func testFileInfoSupportTermsWithUnderscore(t *testing.T, th *SearchTestHelper)
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1307,11 +1307,11 @@ func testFileInfoSearchInDeletedOrArchivedChannels(t *testing.T, th *SearchTestH
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1382,9 +1382,9 @@ func testFileInfoSearchTermsWithDashes(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1431,9 +1431,9 @@ func testFileInfoSearchTermsWithDots(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1480,9 +1480,9 @@ func testFileInfoSearchTermsWithUnderscores(t *testing.T, th *SearchTestHelper)
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1532,11 +1532,11 @@ func testFileInfoSupportStemmingAndWildcards(t *testing.T, th *SearchTestHelper)
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) 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) post2, err := th.createPost(th.User.Id, th.ChannelPrivate.Id, "testmessage", "", model.PostTypeDefault, 0, false)
require.NoError(t, err) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1600,7 +1600,7 @@ func testFileInfoSlashShouldNotBeCharSeparator(t *testing.T, th *SearchTestHelpe
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)
@@ -1631,9 +1631,9 @@ func testFileInfoSearchEmailsWithoutQuotes(t *testing.T, th *SearchTestHelper) {
require.NoError(t, err) require.NoError(t, err)
defer th.deleteUserPosts(th.User.Id) 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) 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) require.NoError(t, err)
defer th.deleteUserFileInfos(th.User.Id) defer th.deleteUserFileInfos(th.User.Id)

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

@@ -371,10 +371,11 @@ func (th *SearchTestHelper) createPost(userID, channelID, message, hashtags, pos
return th.Store.Post().Save(postModel) 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{ return &model.FileInfo{
CreatorId: creatorID, CreatorId: creatorID,
PostId: postID, PostId: postID,
ChannelId: channelID,
CreateAt: createAt, CreateAt: createAt,
UpdateAt: createAt, UpdateAt: createAt,
DeleteAt: 0, 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 var creationTime int64 = 1000000
if createAt > 0 { if createAt > 0 {
creationTime = createAt 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) return th.Store.FileInfo().Save(fileInfoModel)
} }

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

@@ -2265,7 +2265,7 @@ func (s SqlChannelStore) GetFileCount(channelId string) (int64, error) {
FileInfo FileInfo
WHERE WHERE
FileInfo.DeleteAt = 0 FileInfo.DeleteAt = 0
AND FileInfo.PostId IN (SELECT id FROM Posts WHERE ChannelId = ?)`, AND FileInfo.ChannelId = ?`,
channelId) channelId)
if err != nil { if err != nil {
return 0, errors.Wrapf(err, "failed to count files with channelId=%s", channelId) return 0, errors.Wrapf(err, "failed to count files with channelId=%s", channelId)

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

@@ -88,6 +88,7 @@ func newSqlFileInfoStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterfac
"FileInfo.Id", "FileInfo.Id",
"FileInfo.CreatorId", "FileInfo.CreatorId",
"FileInfo.PostId", "FileInfo.PostId",
"COALESCE(FileInfo.ChannelId, '') AS ChannelId",
"FileInfo.CreateAt", "FileInfo.CreateAt",
"FileInfo.UpdateAt", "FileInfo.UpdateAt",
"FileInfo.DeleteAt", "FileInfo.DeleteAt",
@@ -118,10 +119,10 @@ func (fs SqlFileInfoStore) Save(info *model.FileInfo) (*model.FileInfo, error) {
query := ` query := `
INSERT INTO FileInfo 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) Name, Extension, Size, MimeType, Width, Height, HasPreviewImage, MiniPreview, Content, RemoteId)
VALUES 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) :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) { func (fs SqlFileInfoStore) GetByIds(ids []string) ([]*model.FileInfo, error) {
query := fs.getQueryBuilder(). query := fs.getQueryBuilder().
Select(append(fs.queryFields, "COALESCE(P.ChannelId, '') as ChannelId")...). Select(fs.queryFields...).
From("FileInfo"). From("FileInfo").
LeftJoin("Posts as P ON FileInfo.PostId=P.Id").
Where(sq.Eq{"FileInfo.Id": ids}). Where(sq.Eq{"FileInfo.Id": ids}).
Where(sq.Eq{"FileInfo.DeleteAt": 0}). Where(sq.Eq{"FileInfo.DeleteAt": 0}).
OrderBy("FileInfo.CreateAt DESC") OrderBy("FileInfo.CreateAt DESC")
@@ -166,6 +166,8 @@ func (fs SqlFileInfoStore) Upsert(info *model.FileInfo) (*model.FileInfo, error)
return nil, err return nil, err
} }
// PostID and ChannelID are deliberately ignored
// from the list of fields to keep those two immutable.
queryString, args, err := fs.getQueryBuilder(). queryString, args, err := fs.getQueryBuilder().
Update("FileInfo"). Update("FileInfo").
SetMap(map[string]any{ SetMap(map[string]any{
@@ -261,8 +263,7 @@ func (fs SqlFileInfoStore) GetWithOptions(page, perPage int, opt *model.GetFileI
From("FileInfo") From("FileInfo")
if len(opt.ChannelIds) > 0 { if len(opt.ChannelIds) > 0 {
query = query.Join("Posts ON FileInfo.PostId = Posts.Id"). query = query.Where(sq.Eq{"FileInfo.ChannelId": opt.ChannelIds})
Where(sq.Eq{"Posts.ChannelId": opt.ChannelIds})
} }
if len(opt.UserIds) > 0 { if len(opt.UserIds) > 0 {
@@ -388,10 +389,11 @@ func (fs SqlFileInfoStore) GetForUser(userId string) ([]*model.FileInfo, error)
return infos, nil 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(). query := fs.getQueryBuilder().
Update("FileInfo"). Update("FileInfo").
Set("PostId", postId). Set("PostId", postId).
Set("ChannelId", channelId).
Where(sq.And{ Where(sq.And{
sq.Eq{"Id": fileId}, sq.Eq{"Id": fileId},
sq.Eq{"PostId": ""}, sq.Eq{"PostId": ""},
@@ -506,10 +508,9 @@ func (fs SqlFileInfoStore) Search(paramsList []*model.SearchParams, userId, team
return nil, err return nil, err
} }
query := fs.getQueryBuilder(). query := fs.getQueryBuilder().
Select(append(fs.queryFields, "Coalesce(P.ChannelId, '') AS ChannelId")...). Select(fs.queryFields...).
From("FileInfo"). From("FileInfo").
LeftJoin("Posts as P ON FileInfo.PostId=P.Id"). LeftJoin("Channels as C ON C.Id=FileInfo.ChannelId").
LeftJoin("Channels as C ON C.Id=P.ChannelId").
LeftJoin("ChannelMembers as CM ON C.Id=CM.ChannelId"). LeftJoin("ChannelMembers as CM ON C.Id=CM.ChannelId").
Where(sq.Eq{"FileInfo.DeleteAt": 0}). Where(sq.Eq{"FileInfo.DeleteAt": 0}).
OrderBy("FileInfo.CreateAt DESC"). 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) { func (fs SqlFileInfoStore) GetFilesBatchForIndexing(startTime int64, startFileID string, limit int) ([]*model.FileForIndexing, error) {
files := []*model.FileForIndexing{} files := []*model.FileForIndexing{}
sql, args, _ := fs.getQueryBuilder(). sql, args, _ := fs.getQueryBuilder().
Select(append(fs.queryFields, "Coalesce(p.ChannelId, '') AS ChannelId")...). Select(fs.queryFields...).
From("FileInfo"). From("FileInfo").
LeftJoin("Posts AS p ON FileInfo.PostId = p.Id").
Where(sq.Or{ Where(sq.Or{
sq.Gt{"FileInfo.CreateAt": startTime}, sq.Gt{"FileInfo.CreateAt": startTime},
sq.And{ sq.And{

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

@@ -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 { func checkCommandsCommandWebhooksIntegrity(ss *SqlStore) model.IntegrityCheckResult {
return checkParentChildIntegrity(ss, relationalCheckConfig{ return checkParentChildIntegrity(ss, relationalCheckConfig{
parentName: "Commands", parentName: "Commands",
@@ -458,6 +467,7 @@ func checkChannelsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckRes
results <- checkChannelsIncomingWebhooksIntegrity(ss) results <- checkChannelsIncomingWebhooksIntegrity(ss)
results <- checkChannelsOutgoingWebhooksIntegrity(ss) results <- checkChannelsOutgoingWebhooksIntegrity(ss)
results <- checkChannelsPostsIntegrity(ss) results <- checkChannelsPostsIntegrity(ss)
results <- checkChannelsFileInfoIntegrity(ss)
} }
func checkCommandsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) { func checkCommandsIntegrity(ss *SqlStore, results chan<- model.IntegrityCheckResult) {

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

@@ -115,7 +115,7 @@ func createEmoji(ss store.Store, userId string) *model.Emoji {
return 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 := model.FileInfo{}
m.PostId = postId m.PostId = postId
m.CreatorId = userId 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) { t.Run("should generate a report with one record", func(t *testing.T) {
postId := model.NewId() postId := model.NewId()
info := createFileInfo(ss, postId, model.NewId()) info := createFileInfo(ss, postId, model.NewId(), model.NewId())
result := checkPostsFileInfoIntegrity(store) result := checkPostsFileInfoIntegrity(store)
require.NoError(t, result.Err) require.NoError(t, result.Err)
data := result.Data.(model.RelationalIntegrityCheckData) 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) { t.Run("should generate a report with one record", func(t *testing.T) {
user := createUser(ss) user := createUser(ss)
userId := user.Id 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) dbmap.Exec(`DELETE FROM Users WHERE Id=?`, user.Id)
result := checkUsersFileInfoIntegrity(store) result := checkUsersFileInfoIntegrity(store)
require.NoError(t, result.Err) require.NoError(t, result.Err)

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

@@ -699,7 +699,7 @@ type FileInfoStore interface {
GetForUser(userID string) ([]*model.FileInfo, error) GetForUser(userID string) ([]*model.FileInfo, error)
GetWithOptions(page, perPage int, opt *model.GetFileInfosOptions) ([]*model.FileInfo, error) GetWithOptions(page, perPage int, opt *model.GetFileInfosOptions) ([]*model.FileInfo, error)
InvalidateFileInfosForPostCache(postID string, deleted bool) 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) DeleteForPost(postID string) (string, error)
PermanentDelete(fileID string) error PermanentDelete(fileID string) error
PermanentDeleteBatch(endTime int64, limit int64) (int64, error) PermanentDeleteBatch(endTime int64, limit int64) (int64, error)

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

@@ -106,26 +106,31 @@ func testFileInfoSaveGetByPath(t *testing.T, ss store.Store) {
func testFileInfoGetForPost(t *testing.T, ss store.Store) { func testFileInfoGetForPost(t *testing.T, ss store.Store) {
userId := model.NewId() userId := model.NewId()
postId := model.NewId() postId := model.NewId()
channelId := model.NewId()
infos := []*model.FileInfo{ infos := []*model.FileInfo{
{ {
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: userId, CreatorId: userId,
Path: "file.txt", Path: "file.txt",
}, },
{ {
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: userId, CreatorId: userId,
Path: "file.txt", Path: "file.txt",
}, },
{ {
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: userId, CreatorId: userId,
Path: "file.txt", Path: "file.txt",
DeleteAt: 123, DeleteAt: 123,
}, },
{ {
PostId: model.NewId(), PostId: model.NewId(),
ChannelId: channelId,
CreatorId: userId, CreatorId: userId,
Path: "file.txt", Path: "file.txt",
}, },
@@ -225,25 +230,30 @@ func testFileInfoGetForUser(t *testing.T, ss store.Store) {
userId := model.NewId() userId := model.NewId()
userId2 := model.NewId() userId2 := model.NewId()
postId := model.NewId() postId := model.NewId()
channelId := model.NewId()
infos := []*model.FileInfo{ infos := []*model.FileInfo{
{ {
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: userId, CreatorId: userId,
Path: "file.txt", Path: "file.txt",
}, },
{ {
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: userId, CreatorId: userId,
Path: "file.txt", Path: "file.txt",
}, },
{ {
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: userId, CreatorId: userId,
Path: "file.txt", Path: "file.txt",
}, },
{ {
PostId: model.NewId(), PostId: model.NewId(),
ChannelId: channelId,
CreatorId: userId2, CreatorId: userId2,
Path: "file.txt", Path: "file.txt",
}, },
@@ -289,6 +299,9 @@ func testFileInfoGetWithOptions(t *testing.T, ss store.Store) {
if post.Id != "" { if post.Id != "" {
fileInfo.PostId = post.Id fileInfo.PostId = post.Id
} }
if post.ChannelId != "" {
fileInfo.ChannelId = post.ChannelId
}
_, err := ss.FileInfo().Save(&fileInfo) _, err := ss.FileInfo().Save(&fileInfo)
require.NoError(t, err) require.NoError(t, err)
return fileInfo return fileInfo
@@ -414,6 +427,7 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
t.Run("should attach files", func(t *testing.T) { t.Run("should attach files", func(t *testing.T) {
userId := model.NewId() userId := model.NewId()
postId := model.NewId() postId := model.NewId()
channelId := model.NewId()
info1, err := ss.FileInfo().Save(&model.FileInfo{ info1, err := ss.FileInfo().Save(&model.FileInfo{
CreatorId: userId, CreatorId: userId,
@@ -429,13 +443,15 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
require.Equal(t, "", info1.PostId) require.Equal(t, "", info1.PostId)
require.Equal(t, "", info2.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) assert.NoError(t, err)
info1.PostId = postId 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) assert.NoError(t, err)
info2.PostId = postId info2.PostId = postId
info2.ChannelId = channelId
data, err := ss.FileInfo().GetForPost(postId, true, false, false) data, err := ss.FileInfo().GetForPost(postId, true, false, false)
require.NoError(t, err) 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) { t.Run("should not attach files to multiple posts", func(t *testing.T) {
userId := model.NewId() userId := model.NewId()
postId := model.NewId() postId := model.NewId()
channelId := model.NewId()
info, err := ss.FileInfo().Save(&model.FileInfo{ info, err := ss.FileInfo().Save(&model.FileInfo{
CreatorId: userId, CreatorId: userId,
@@ -458,16 +475,17 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
require.Equal(t, "", info.PostId) 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) 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) require.Error(t, err)
}) })
t.Run("should not attach files owned from a different user", func(t *testing.T) { t.Run("should not attach files owned from a different user", func(t *testing.T) {
userId := model.NewId() userId := model.NewId()
postId := model.NewId() postId := model.NewId()
channelId := model.NewId()
info, err := ss.FileInfo().Save(&model.FileInfo{ info, err := ss.FileInfo().Save(&model.FileInfo{
CreatorId: model.NewId(), CreatorId: model.NewId(),
@@ -477,12 +495,13 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
require.Equal(t, "", info.PostId) 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) assert.Error(t, err)
}) })
t.Run("should attach files uploaded by nouser", func(t *testing.T) { t.Run("should attach files uploaded by nouser", func(t *testing.T) {
postId := model.NewId() postId := model.NewId()
channelId := model.NewId()
info, err := ss.FileInfo().Save(&model.FileInfo{ info, err := ss.FileInfo().Save(&model.FileInfo{
CreatorId: "nouser", CreatorId: "nouser",
@@ -491,12 +510,13 @@ func testFileInfoAttachToPost(t *testing.T, ss store.Store) {
require.NoError(t, err) require.NoError(t, err)
assert.Equal(t, "", info.PostId) 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) require.NoError(t, err)
data, err := ss.FileInfo().GetForPost(postId, true, false, false) data, err := ss.FileInfo().GetForPost(postId, true, false, false)
require.NoError(t, err) require.NoError(t, err)
info.PostId = postId info.PostId = postId
info.ChannelId = channelId
assert.EqualValues(t, []*model.FileInfo{info}, data) 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) { func testFileInfoDeleteForPost(t *testing.T, ss store.Store) {
userId := model.NewId() userId := model.NewId()
postId := model.NewId() postId := model.NewId()
channelId := model.NewId()
infos := []*model.FileInfo{ infos := []*model.FileInfo{
{ {
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: userId, CreatorId: userId,
Path: "file.txt", Path: "file.txt",
}, },
{ {
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: userId, CreatorId: userId,
Path: "file.txt", Path: "file.txt",
}, },
{ {
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: userId, CreatorId: userId,
Path: "file.txt", Path: "file.txt",
DeleteAt: 123, DeleteAt: 123,
}, },
{ {
PostId: model.NewId(), PostId: model.NewId(),
ChannelId: channelId,
CreatorId: userId, CreatorId: userId,
Path: "file.txt", Path: "file.txt",
}, },
@@ -549,6 +574,7 @@ func testFileInfoDeleteForPost(t *testing.T, ss store.Store) {
func testFileInfoPermanentDelete(t *testing.T, ss store.Store) { func testFileInfoPermanentDelete(t *testing.T, ss store.Store) {
info, err := ss.FileInfo().Save(&model.FileInfo{ info, err := ss.FileInfo().Save(&model.FileInfo{
PostId: model.NewId(), PostId: model.NewId(),
ChannelId: model.NewId(),
CreatorId: model.NewId(), CreatorId: model.NewId(),
Path: "file.txt", Path: "file.txt",
}) })
@@ -560,9 +586,11 @@ func testFileInfoPermanentDelete(t *testing.T, ss store.Store) {
func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) { func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) {
postId := model.NewId() postId := model.NewId()
channelId := model.NewId()
_, err := ss.FileInfo().Save(&model.FileInfo{ _, err := ss.FileInfo().Save(&model.FileInfo{
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: model.NewId(), CreatorId: model.NewId(),
Path: "file.txt", Path: "file.txt",
CreateAt: 1000, CreateAt: 1000,
@@ -571,6 +599,7 @@ func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) {
_, err = ss.FileInfo().Save(&model.FileInfo{ _, err = ss.FileInfo().Save(&model.FileInfo{
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: model.NewId(), CreatorId: model.NewId(),
Path: "file.txt", Path: "file.txt",
CreateAt: 1200, CreateAt: 1200,
@@ -579,6 +608,7 @@ func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) {
_, err = ss.FileInfo().Save(&model.FileInfo{ _, err = ss.FileInfo().Save(&model.FileInfo{
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: model.NewId(), CreatorId: model.NewId(),
Path: "file.txt", Path: "file.txt",
CreateAt: 2000, CreateAt: 2000,
@@ -600,9 +630,11 @@ func testFileInfoPermanentDeleteBatch(t *testing.T, ss store.Store) {
func testFileInfoPermanentDeleteByUser(t *testing.T, ss store.Store) { func testFileInfoPermanentDeleteByUser(t *testing.T, ss store.Store) {
userId := model.NewId() userId := model.NewId()
postId := model.NewId() postId := model.NewId()
channelId := model.NewId()
_, err := ss.FileInfo().Save(&model.FileInfo{ _, err := ss.FileInfo().Save(&model.FileInfo{
PostId: postId, PostId: postId,
ChannelId: channelId,
CreatorId: userId, CreatorId: userId,
Path: "file.txt", Path: "file.txt",
}) })
@@ -668,6 +700,7 @@ func testFileInfoStoreGetFilesBatchForIndexing(t *testing.T, ss store.Store) {
require.NoError(t, err) require.NoError(t, err)
f1, err := ss.FileInfo().Save(&model.FileInfo{ f1, err := ss.FileInfo().Save(&model.FileInfo{
PostId: o1.Id, PostId: o1.Id,
ChannelId: o1.ChannelId,
CreatorId: model.NewId(), CreatorId: model.NewId(),
Path: "file1.txt", Path: "file1.txt",
}) })
@@ -686,6 +719,7 @@ func testFileInfoStoreGetFilesBatchForIndexing(t *testing.T, ss store.Store) {
f2, err := ss.FileInfo().Save(&model.FileInfo{ f2, err := ss.FileInfo().Save(&model.FileInfo{
PostId: o2.Id, PostId: o2.Id,
ChannelId: o2.ChannelId,
CreatorId: model.NewId(), CreatorId: model.NewId(),
Path: "file2.txt", Path: "file2.txt",
}) })
@@ -705,6 +739,7 @@ func testFileInfoStoreGetFilesBatchForIndexing(t *testing.T, ss store.Store) {
f3, err := ss.FileInfo().Save(&model.FileInfo{ f3, err := ss.FileInfo().Save(&model.FileInfo{
PostId: o3.Id, PostId: o3.Id,
ChannelId: o3.ChannelId,
CreatorId: model.NewId(), CreatorId: model.NewId(),
Path: "file3.txt", Path: "file3.txt",
}) })
@@ -737,6 +772,7 @@ func testFileInfoStoreCountAll(t *testing.T, ss store.Store) {
require.NoError(t, err) require.NoError(t, err)
f1, err := ss.FileInfo().Save(&model.FileInfo{ f1, err := ss.FileInfo().Save(&model.FileInfo{
PostId: model.NewId(), PostId: model.NewId(),
ChannelId: model.NewId(),
CreatorId: model.NewId(), CreatorId: model.NewId(),
Path: "file1.txt", Path: "file1.txt",
}) })
@@ -744,12 +780,14 @@ func testFileInfoStoreCountAll(t *testing.T, ss store.Store) {
_, err = ss.FileInfo().Save(&model.FileInfo{ _, err = ss.FileInfo().Save(&model.FileInfo{
PostId: model.NewId(), PostId: model.NewId(),
ChannelId: model.NewId(),
CreatorId: model.NewId(), CreatorId: model.NewId(),
Path: "file2.txt", Path: "file2.txt",
}) })
require.NoError(t, err) require.NoError(t, err)
_, err = ss.FileInfo().Save(&model.FileInfo{ _, err = ss.FileInfo().Save(&model.FileInfo{
PostId: model.NewId(), PostId: model.NewId(),
ChannelId: model.NewId(),
CreatorId: model.NewId(), CreatorId: model.NewId(),
Path: "file3.txt", Path: "file3.txt",
}) })

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

@@ -14,13 +14,13 @@ type FileInfoStore struct {
mock.Mock mock.Mock
} }
// AttachToPost provides a mock function with given fields: fileID, postID, creatorID // AttachToPost provides a mock function with given fields: fileID, postID, channelID, creatorID
func (_m *FileInfoStore) AttachToPost(fileID string, postID string, creatorID string) error { func (_m *FileInfoStore) AttachToPost(fileID string, postID string, channelID string, creatorID string) error {
ret := _m.Called(fileID, postID, creatorID) ret := _m.Called(fileID, postID, channelID, creatorID)
var r0 error var r0 error
if rf, ok := ret.Get(0).(func(string, string, string) error); ok { if rf, ok := ret.Get(0).(func(string, string, string, string) error); ok {
r0 = rf(fileID, postID, creatorID) r0 = rf(fileID, postID, channelID, creatorID)
} else { } else {
r0 = ret.Error(0) r0 = ret.Error(0)
} }

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

@@ -3182,10 +3182,10 @@ func (s *TimerLayerEmojiStore) Search(name string, prefixOnly bool, limit int) (
return result, err 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() 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) elapsed := float64(time.Since(start)) / float64(time.Second)
if s.Root.Metrics != nil { if s.Root.Metrics != nil {

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

@@ -680,7 +680,7 @@ func (si *SlackImporter) oldImportPost(post *model.Post) string {
firstPostId = post.Id firstPostId = post.Id
} }
for _, fileId := range post.FileIds { 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( mlog.Error(
"Error attaching files to post.", "Error attaching files to post.",
mlog.String("post_id", post.Id), mlog.String("post_id", post.Id),