[MM-62427] Add message attachments validation (#30180)

* Add message attachments validation

* Add props validation

* Validate slack attachment fields

* Update tests and library usage

* Improve interactive dialog error for length checks

* Allow predefined colors for slack attachments

* Fix TestPostAction

* Use const for data source

* Add tests

* Cleanup unused props

* Add happy path tests

* lint fixes

* Add validation for PostActionOptions
Этот коммит содержится в:
Ben Schumacher
2025-03-20 12:53:50 +01:00
коммит произвёл GitHub
родитель 5609489e86
Коммит 9b5d8d52bf
47 изменённых файлов: 1402 добавлений и 355 удалений

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

@@ -8067,11 +8067,11 @@ func (s *RetryLayerPostStore) Overwrite(rctx request.CTX, post *model.Post) (*mo
}
func (s *RetryLayerPostStore) OverwriteMultiple(posts []*model.Post) ([]*model.Post, int, error) {
func (s *RetryLayerPostStore) OverwriteMultiple(rctx request.CTX, posts []*model.Post) ([]*model.Post, int, error) {
tries := 0
for {
result, resultVar1, err := s.PostStore.OverwriteMultiple(posts)
result, resultVar1, err := s.PostStore.OverwriteMultiple(rctx, posts)
if err == nil {
return result, resultVar1, nil
}
@@ -8235,11 +8235,11 @@ func (s *RetryLayerPostStore) Save(rctx request.CTX, post *model.Post) (*model.P
}
func (s *RetryLayerPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, error) {
func (s *RetryLayerPostStore) SaveMultiple(rctx request.CTX, posts []*model.Post) ([]*model.Post, int, error) {
tries := 0
for {
result, resultVar1, err := s.PostStore.SaveMultiple(posts)
result, resultVar1, err := s.PostStore.SaveMultiple(rctx, posts)
if err == nil {
return result, resultVar1, nil
}

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

@@ -147,7 +147,7 @@ func newSqlPostStore(sqlStore *SqlStore, metrics einterfaces.MetricsInterface) s
}
}
func (s *SqlPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, error) {
func (s *SqlPostStore) SaveMultiple(rctx request.CTX, posts []*model.Post) ([]*model.Post, int, error) {
channelNewPosts := make(map[string]int)
channelNewRootPosts := make(map[string]int)
maxDateNewPosts := make(map[string]int64)
@@ -160,9 +160,11 @@ func (s *SqlPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, er
}
post.PreSave()
maxPostSize := s.GetMaxPostSize()
if err := post.IsValid(maxPostSize); err != nil {
return nil, idx, err
}
post.ValidateProps(rctx.Logger())
if currentChannelCount, ok := channelNewPosts[post.ChannelId]; !ok {
if post.IsJoinLeaveMessage() {
@@ -293,7 +295,7 @@ func (s *SqlPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, er
}
func (s *SqlPostStore) Save(rctx request.CTX, post *model.Post) (*model.Post, error) {
posts, _, err := s.SaveMultiple([]*model.Post{post})
posts, _, err := s.SaveMultiple(rctx, []*model.Post{post})
if err != nil {
return nil, err
}
@@ -356,6 +358,7 @@ func (s *SqlPostStore) Update(rctx request.CTX, newPost *model.Post, oldPost *mo
if err := newPost.IsValid(maxPostSize); err != nil {
return nil, err
}
newPost.ValidateProps(rctx.Logger())
if _, err := s.GetMaster().NamedExec(`UPDATE Posts
SET CreateAt=:CreateAt,
@@ -409,14 +412,16 @@ func (s *SqlPostStore) Update(rctx request.CTX, newPost *model.Post, oldPost *mo
return newPost, nil
}
func (s *SqlPostStore) OverwriteMultiple(posts []*model.Post) (_ []*model.Post, _ int, err error) {
func (s *SqlPostStore) OverwriteMultiple(rctx request.CTX, posts []*model.Post) (_ []*model.Post, _ int, err error) {
updateAt := model.GetMillis()
maxPostSize := s.GetMaxPostSize()
for idx, post := range posts {
post.UpdateAt = updateAt
if appErr := post.IsValid(maxPostSize); appErr != nil {
return nil, idx, appErr
}
post.ValidateProps(rctx.Logger())
}
tx, err := s.GetMaster().Beginx()
@@ -464,7 +469,7 @@ func (s *SqlPostStore) OverwriteMultiple(posts []*model.Post) (_ []*model.Post,
}
func (s *SqlPostStore) Overwrite(rctx request.CTX, post *model.Post) (*model.Post, error) {
posts, _, err := s.OverwriteMultiple([]*model.Post{post})
posts, _, err := s.OverwriteMultiple(rctx, []*model.Post{post})
if err != nil {
return nil, err
}

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

@@ -364,7 +364,7 @@ type ThreadStore interface {
}
type PostStore interface {
SaveMultiple(posts []*model.Post) ([]*model.Post, int, error)
SaveMultiple(rctx request.CTX, posts []*model.Post) ([]*model.Post, int, error)
Save(rctx request.CTX, post *model.Post) (*model.Post, error)
Update(rctx request.CTX, newPost *model.Post, oldPost *model.Post) (*model.Post, error)
Get(ctx context.Context, id string, opts model.GetPostsOptions, userID string, sanitizeOptions map[string]bool) (*model.PostList, error)
@@ -394,7 +394,7 @@ type PostStore interface {
InvalidateLastPostTimeCache(channelID string)
GetPostsCreatedAt(channelID string, timestamp int64) ([]*model.Post, error)
Overwrite(rctx request.CTX, post *model.Post) (*model.Post, error)
OverwriteMultiple(posts []*model.Post) ([]*model.Post, int, error)
OverwriteMultiple(rctx request.CTX, posts []*model.Post) ([]*model.Post, int, error)
GetPostsByIds(postIds []string) ([]*model.Post, error)
GetEditHistoryForPost(postID string) ([]*model.Post, error)
GetPostsBatchForIndexing(startTime int64, startPostID string, limit int) ([]*model.PostForIndexing, error)

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

@@ -1037,9 +1037,9 @@ func (_m *PostStore) Overwrite(rctx request.CTX, post *model.Post) (*model.Post,
return r0, r1
}
// OverwriteMultiple provides a mock function with given fields: posts
func (_m *PostStore) OverwriteMultiple(posts []*model.Post) ([]*model.Post, int, error) {
ret := _m.Called(posts)
// OverwriteMultiple provides a mock function with given fields: rctx, posts
func (_m *PostStore) OverwriteMultiple(rctx request.CTX, posts []*model.Post) ([]*model.Post, int, error) {
ret := _m.Called(rctx, posts)
if len(ret) == 0 {
panic("no return value specified for OverwriteMultiple")
@@ -1048,25 +1048,25 @@ func (_m *PostStore) OverwriteMultiple(posts []*model.Post) ([]*model.Post, int,
var r0 []*model.Post
var r1 int
var r2 error
if rf, ok := ret.Get(0).(func([]*model.Post) ([]*model.Post, int, error)); ok {
return rf(posts)
if rf, ok := ret.Get(0).(func(request.CTX, []*model.Post) ([]*model.Post, int, error)); ok {
return rf(rctx, posts)
}
if rf, ok := ret.Get(0).(func([]*model.Post) []*model.Post); ok {
r0 = rf(posts)
if rf, ok := ret.Get(0).(func(request.CTX, []*model.Post) []*model.Post); ok {
r0 = rf(rctx, posts)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.Post)
}
}
if rf, ok := ret.Get(1).(func([]*model.Post) int); ok {
r1 = rf(posts)
if rf, ok := ret.Get(1).(func(request.CTX, []*model.Post) int); ok {
r1 = rf(rctx, posts)
} else {
r1 = ret.Get(1).(int)
}
if rf, ok := ret.Get(2).(func([]*model.Post) error); ok {
r2 = rf(posts)
if rf, ok := ret.Get(2).(func(request.CTX, []*model.Post) error); ok {
r2 = rf(rctx, posts)
} else {
r2 = ret.Error(2)
}
@@ -1239,9 +1239,9 @@ func (_m *PostStore) Save(rctx request.CTX, post *model.Post) (*model.Post, erro
return r0, r1
}
// SaveMultiple provides a mock function with given fields: posts
func (_m *PostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, error) {
ret := _m.Called(posts)
// SaveMultiple provides a mock function with given fields: rctx, posts
func (_m *PostStore) SaveMultiple(rctx request.CTX, posts []*model.Post) ([]*model.Post, int, error) {
ret := _m.Called(rctx, posts)
if len(ret) == 0 {
panic("no return value specified for SaveMultiple")
@@ -1250,25 +1250,25 @@ func (_m *PostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, erro
var r0 []*model.Post
var r1 int
var r2 error
if rf, ok := ret.Get(0).(func([]*model.Post) ([]*model.Post, int, error)); ok {
return rf(posts)
if rf, ok := ret.Get(0).(func(request.CTX, []*model.Post) ([]*model.Post, int, error)); ok {
return rf(rctx, posts)
}
if rf, ok := ret.Get(0).(func([]*model.Post) []*model.Post); ok {
r0 = rf(posts)
if rf, ok := ret.Get(0).(func(request.CTX, []*model.Post) []*model.Post); ok {
r0 = rf(rctx, posts)
} else {
if ret.Get(0) != nil {
r0 = ret.Get(0).([]*model.Post)
}
}
if rf, ok := ret.Get(1).(func([]*model.Post) int); ok {
r1 = rf(posts)
if rf, ok := ret.Get(1).(func(request.CTX, []*model.Post) int); ok {
r1 = rf(rctx, posts)
} else {
r1 = ret.Get(1).(int)
}
if rf, ok := ret.Get(2).(func([]*model.Post) error); ok {
r2 = rf(posts)
if rf, ok := ret.Get(2).(func(request.CTX, []*model.Post) error); ok {
r2 = rf(rctx, posts)
} else {
r2 = ret.Error(2)
}

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

@@ -140,7 +140,7 @@ func testPostAcknowledgementsStoreGetForPosts(t *testing.T, rctx request.CTX, ss
PersistentNotifications: model.NewPointer(false),
},
}
_, errIdx, err := ss.Post().SaveMultiple([]*model.Post{&p1, &p2})
_, errIdx, err := ss.Post().SaveMultiple(rctx, []*model.Post{&p1, &p2})
require.NoError(t, err)
require.Equal(t, -1, errIdx)

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

@@ -81,7 +81,7 @@ func testPostPersistentNotificationStoreGet(t *testing.T, rctx request.CTX, ss s
},
}
_, errIdx, err := ss.Post().SaveMultiple([]*model.Post{&p1, &p2, &p3, &p4, &p5})
_, errIdx, err := ss.Post().SaveMultiple(rctx, []*model.Post{&p1, &p2, &p3, &p4, &p5})
require.NoError(t, err)
require.Equal(t, -1, errIdx)
@@ -156,7 +156,7 @@ func testPostPersistentNotificationStoreUpdateLastSentAt(t *testing.T, rctx requ
},
}
_, errIdx, err := ss.Post().SaveMultiple([]*model.Post{&p1})
_, errIdx, err := ss.Post().SaveMultiple(rctx, []*model.Post{&p1})
require.NoError(t, err)
require.Equal(t, -1, errIdx)
@@ -235,7 +235,7 @@ func testPostPersistentNotificationStoreDelete(t *testing.T, rctx request.CTX, s
},
}
_, errIdx, err := ss.Post().SaveMultiple([]*model.Post{&p1, &p2, &p3})
_, errIdx, err := ss.Post().SaveMultiple(rctx, []*model.Post{&p1, &p2, &p3})
require.NoError(t, err)
require.Equal(t, -1, errIdx)
@@ -321,7 +321,7 @@ func testPostPersistentNotificationStoreDelete(t *testing.T, rctx request.CTX, s
},
}
_, errIdx, err := ss.Post().SaveMultiple([]*model.Post{&p1, &p2, &p3, &p4, &p5})
_, errIdx, err := ss.Post().SaveMultiple(rctx, []*model.Post{&p1, &p2, &p3, &p4, &p5})
require.NoError(t, err)
require.Equal(t, -1, errIdx)
@@ -425,7 +425,7 @@ func testPostPersistentNotificationStoreDelete(t *testing.T, rctx request.CTX, s
},
}
_, errIdx, err := ss.Post().SaveMultiple([]*model.Post{&p1, &p2, &p3, &p4, &p5})
_, errIdx, err := ss.Post().SaveMultiple(rctx, []*model.Post{&p1, &p2, &p3, &p4, &p5})
require.NoError(t, err)
require.Equal(t, -1, errIdx)

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

@@ -51,7 +51,7 @@ func testPostPriorityStoreGetForPost(t *testing.T, rctx request.CTX, ss store.St
p3.UserId = model.NewId()
p3.Message = NewTestID()
_, errIdx, err := ss.Post().SaveMultiple([]*model.Post{&p1, &p2, &p3})
_, errIdx, err := ss.Post().SaveMultiple(rctx, []*model.Post{&p1, &p2, &p3})
require.NoError(t, err)
require.Equal(t, -1, errIdx)

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

@@ -290,7 +290,7 @@ func testPostStoreSaveMultiple(t *testing.T, rctx request.CTX, ss store.Store) {
p4.Message = NewTestID()
t.Run("Save correctly a new set of posts", func(t *testing.T) {
newPosts, errIdx, err := ss.Post().SaveMultiple([]*model.Post{&p1, &p2, &p3})
newPosts, errIdx, err := ss.Post().SaveMultiple(rctx, []*model.Post{&p1, &p2, &p3})
require.NoError(t, err)
require.Equal(t, -1, errIdx)
for _, post := range newPosts {
@@ -358,7 +358,7 @@ func testPostStoreSaveMultiple(t *testing.T, rctx request.CTX, ss store.Store) {
o4.UserId = model.NewId()
o4.Message = NewTestID()
newPosts, errIdx, err := ss.Post().SaveMultiple([]*model.Post{&o1, &o2, &o3, &o4})
newPosts, errIdx, err := ss.Post().SaveMultiple(rctx, []*model.Post{&o1, &o2, &o3, &o4})
require.NoError(t, err, "couldn't save item")
require.Equal(t, -1, errIdx)
assert.Len(t, newPosts, 4)
@@ -369,7 +369,7 @@ func testPostStoreSaveMultiple(t *testing.T, rctx request.CTX, ss store.Store) {
})
t.Run("Try to save mixed, already saved and not saved posts", func(t *testing.T) {
newPosts, errIdx, err := ss.Post().SaveMultiple([]*model.Post{&p4, &p3})
newPosts, errIdx, err := ss.Post().SaveMultiple(rctx, []*model.Post{&p4, &p3})
require.Error(t, err)
require.Equal(t, 1, errIdx)
require.Nil(t, newPosts)
@@ -405,7 +405,7 @@ func testPostStoreSaveMultiple(t *testing.T, rctx request.CTX, ss store.Store) {
replyPost.Message = NewTestID()
replyPost.RootId = rootPost.Id
_, _, err = ss.Post().SaveMultiple([]*model.Post{&rootPost, &replyPost})
_, _, err = ss.Post().SaveMultiple(rctx, []*model.Post{&rootPost, &replyPost})
require.NoError(t, err)
rrootPost, err := ss.Post().GetSingle(rctx, rootPost.Id, false)
@@ -427,7 +427,7 @@ func testPostStoreSaveMultiple(t *testing.T, rctx request.CTX, ss store.Store) {
// Ensure update does not occur in the same timestamp as creation
time.Sleep(time.Millisecond)
_, _, err = ss.Post().SaveMultiple([]*model.Post{&replyPost2, &replyPost3})
_, _, err = ss.Post().SaveMultiple(rctx, []*model.Post{&replyPost2, &replyPost3})
require.NoError(t, err)
rrootPost2, err := ss.Post().GetSingle(rctx, rootPost.Id, false)
@@ -460,7 +460,7 @@ func testPostStoreSaveMultiple(t *testing.T, rctx request.CTX, ss store.Store) {
post3.UserId = model.NewId()
post3.Message = NewTestID()
_, _, err = ss.Post().SaveMultiple([]*model.Post{&post1, &post2, &post3})
_, _, err = ss.Post().SaveMultiple(rctx, []*model.Post{&post1, &post2, &post3})
require.NoError(t, err)
rchannel, err := ss.Channel().Get(channel.Id, false)
@@ -3772,7 +3772,7 @@ func testPostStoreOverwriteMultiple(t *testing.T, rctx request.CTX, ss store.Sto
o3a := ro3.Clone()
o3a.Message = ro3.Message + "WWWWWWW"
_, errIdx, err := ss.Post().OverwriteMultiple([]*model.Post{o1a, o2a, o3a})
_, errIdx, err := ss.Post().OverwriteMultiple(rctx, []*model.Post{o1a, o2a, o3a})
require.NoError(t, err)
require.Equal(t, -1, errIdx)
@@ -3802,7 +3802,7 @@ func testPostStoreOverwriteMultiple(t *testing.T, rctx request.CTX, ss store.Sto
o5a.Filenames = []string{}
o5a.FileIds = []string{}
_, errIdx, err := ss.Post().OverwriteMultiple([]*model.Post{o4a, o5a})
_, errIdx, err := ss.Post().OverwriteMultiple(rctx, []*model.Post{o4a, o5a})
require.NoError(t, err)
require.Equal(t, -1, errIdx)

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

@@ -93,7 +93,7 @@ func testThreadStorePopulation(t *testing.T, rctx request.CTX, ss store.Store) {
o4.UserId = model.NewId()
o4.Message = NewTestID()
newPosts, errIdx, err3 := ss.Post().SaveMultiple([]*model.Post{&o2, &o3, &o4})
newPosts, errIdx, err3 := ss.Post().SaveMultiple(rctx, []*model.Post{&o2, &o3, &o4})
opts := model.GetPostsOptions{
SkipFetchThreads: true,
@@ -135,7 +135,7 @@ func testThreadStorePopulation(t *testing.T, rctx request.CTX, ss store.Store) {
o5.RootId = newPosts[0].Id
o5.Message = NewTestID()
_, _, err = ss.Post().SaveMultiple([]*model.Post{&o5})
_, _, err = ss.Post().SaveMultiple(rctx, []*model.Post{&o5})
require.NoError(t, err, "couldn't save item")
thread, err = ss.Thread().Get(newPosts[0].Id)
@@ -185,7 +185,7 @@ func testThreadStorePopulation(t *testing.T, rctx request.CTX, ss store.Store) {
replyPost.Message = NewTestID()
replyPost.RootId = rootPost.RootId
newPosts, _, err := ss.Post().SaveMultiple([]*model.Post{&rootPost, &replyPost})
newPosts, _, err := ss.Post().SaveMultiple(rctx, []*model.Post{&rootPost, &replyPost})
require.NoError(t, err)
thread1, err := ss.Thread().Get(newPosts[0].RootId)
@@ -207,7 +207,7 @@ func testThreadStorePopulation(t *testing.T, rctx request.CTX, ss store.Store) {
replyPost3.Message = NewTestID()
replyPost3.RootId = rootPost.Id
_, _, err = ss.Post().SaveMultiple([]*model.Post{&replyPost2, &replyPost3})
_, _, err = ss.Post().SaveMultiple(rctx, []*model.Post{&replyPost2, &replyPost3})
require.NoError(t, err)
rrootPost2, err := ss.Post().GetSingle(rctx, rootPost.Id, false)
@@ -295,7 +295,7 @@ func testThreadStorePopulation(t *testing.T, rctx request.CTX, ss store.Store) {
rootPost.UserId = model.NewId()
rootPost.Message = NewTestID()
newPosts1, _, err := ss.Post().SaveMultiple([]*model.Post{&rootPost})
newPosts1, _, err := ss.Post().SaveMultiple(rctx, []*model.Post{&rootPost})
require.NoError(t, err)
replyPost := model.Post{}
@@ -304,7 +304,7 @@ func testThreadStorePopulation(t *testing.T, rctx request.CTX, ss store.Store) {
replyPost.Message = NewTestID()
replyPost.RootId = newPosts1[0].Id
_, _, err = ss.Post().SaveMultiple([]*model.Post{&replyPost})
_, _, err = ss.Post().SaveMultiple(rctx, []*model.Post{&replyPost})
require.NoError(t, err)
thread1, err := ss.Thread().Get(newPosts1[0].Id)

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

@@ -6433,10 +6433,10 @@ func (s *TimerLayerPostStore) Overwrite(rctx request.CTX, post *model.Post) (*mo
return result, err
}
func (s *TimerLayerPostStore) OverwriteMultiple(posts []*model.Post) ([]*model.Post, int, error) {
func (s *TimerLayerPostStore) OverwriteMultiple(rctx request.CTX, posts []*model.Post) ([]*model.Post, int, error) {
start := time.Now()
result, resultVar1, err := s.PostStore.OverwriteMultiple(posts)
result, resultVar1, err := s.PostStore.OverwriteMultiple(rctx, posts)
elapsed := float64(time.Since(start)) / float64(time.Second)
if s.Root.Metrics != nil {
@@ -6561,10 +6561,10 @@ func (s *TimerLayerPostStore) Save(rctx request.CTX, post *model.Post) (*model.P
return result, err
}
func (s *TimerLayerPostStore) SaveMultiple(posts []*model.Post) ([]*model.Post, int, error) {
func (s *TimerLayerPostStore) SaveMultiple(rctx request.CTX, posts []*model.Post) ([]*model.Post, int, error) {
start := time.Now()
result, resultVar1, err := s.PostStore.SaveMultiple(posts)
result, resultVar1, err := s.PostStore.SaveMultiple(rctx, posts)
elapsed := float64(time.Since(start)) / float64(time.Second)
if s.Root.Metrics != nil {