[MM-55143] Disallow reacting with an emoji that does not exist, limit the total number of unique reactions per post (#25331)

* [MM-55143] Disallow reacting with an emoji that does not exist

* WIP for server limit on emoji reactions

* WIP

* Implement default limit of 25 unique emoji reactions

* Add modal for reaction limit

* Fix test

* PR feedback

* Fix i18n

* Update admin string

* Merge'd

* Fixing some issues, check limits correctly based on other users reactions

* Fix typos

* Fix lint/test

* Add tests, fix other tests

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
Этот коммит содержится в:
Devin Binnie
2023-11-27 09:11:04 -05:00
коммит произвёл GitHub
родитель 0a38042d58
Коммит eaa5cce3ce
24 изменённых файлов: 652 добавлений и 29 удалений

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

@@ -94,6 +94,30 @@ func (_m *ReactionStore) DeleteOrphanedRowsByIds(r *model.RetentionIdsForDeletio
return r0
}
// ExistsOnPost provides a mock function with given fields: postId, emojiName
func (_m *ReactionStore) ExistsOnPost(postId string, emojiName string) (bool, error) {
ret := _m.Called(postId, emojiName)
var r0 bool
var r1 error
if rf, ok := ret.Get(0).(func(string, string) (bool, error)); ok {
return rf(postId, emojiName)
}
if rf, ok := ret.Get(0).(func(string, string) bool); ok {
r0 = rf(postId, emojiName)
} else {
r0 = ret.Get(0).(bool)
}
if rf, ok := ret.Get(1).(func(string, string) error); ok {
r1 = rf(postId, emojiName)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// GetForPost provides a mock function with given fields: postID, allowFromCache
func (_m *ReactionStore) GetForPost(postID string, allowFromCache bool) ([]*model.Reaction, error) {
ret := _m.Called(postID, allowFromCache)
@@ -146,6 +170,30 @@ func (_m *ReactionStore) GetForPostSince(postId string, since int64, excludeRemo
return r0, r1
}
// GetUniqueCountForPost provides a mock function with given fields: postId
func (_m *ReactionStore) GetUniqueCountForPost(postId string) (int, error) {
ret := _m.Called(postId)
var r0 int
var r1 error
if rf, ok := ret.Get(0).(func(string) (int, error)); ok {
return rf(postId)
}
if rf, ok := ret.Get(0).(func(string) int); ok {
r0 = rf(postId)
} else {
r0 = ret.Get(0).(int)
}
if rf, ok := ret.Get(1).(func(string) error); ok {
r1 = rf(postId)
} else {
r1 = ret.Error(1)
}
return r0, r1
}
// PermanentDeleteBatch provides a mock function with given fields: endTime, limit
func (_m *ReactionStore) PermanentDeleteBatch(endTime int64, limit int64) (int64, error) {
ret := _m.Called(endTime, limit)

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

@@ -29,6 +29,8 @@ func TestReactionStore(t *testing.T, rctx request.CTX, ss store.Store, s SqlStor
t.Run("PermanentDeleteBatch", func(t *testing.T) { testReactionStorePermanentDeleteBatch(t, rctx, ss) })
t.Run("ReactionBulkGetForPosts", func(t *testing.T) { testReactionBulkGetForPosts(t, rctx, ss) })
t.Run("ReactionDeadlock", func(t *testing.T) { testReactionDeadlock(t, rctx, ss) })
t.Run("ExistsOnPost", func(t *testing.T) { testExistsOnPost(t, rctx, ss) })
t.Run("GetUniqueCountForPost", func(t *testing.T) { testGetUniqueCountForPost(t, rctx, ss) })
}
func testReactionSave(t *testing.T, rctx request.CTX, ss store.Store) {
@@ -873,3 +875,66 @@ func testReactionDeadlock(t *testing.T, rctx request.CTX, ss store.Store) {
}()
wg.Wait()
}
func testExistsOnPost(t *testing.T, rctx request.CTX, ss store.Store) {
post, _ := ss.Post().Save(&model.Post{
ChannelId: model.NewId(),
UserId: model.NewId(),
})
emojiName := model.NewId()
reaction := &model.Reaction{
UserId: model.NewId(),
PostId: post.Id,
EmojiName: emojiName,
}
_, nErr := ss.Reaction().Save(reaction)
require.NoError(t, nErr)
exists, err := ss.Reaction().ExistsOnPost(post.Id, emojiName)
require.NoError(t, err)
require.True(t, exists)
exists, err = ss.Reaction().ExistsOnPost(post.Id, model.NewId())
require.NoError(t, err)
require.False(t, exists)
}
func testGetUniqueCountForPost(t *testing.T, rctx request.CTX, ss store.Store) {
post, _ := ss.Post().Save(&model.Post{
ChannelId: model.NewId(),
UserId: model.NewId(),
})
userId := model.NewId()
emojiName := model.NewId()
reaction := &model.Reaction{
UserId: userId,
PostId: post.Id,
EmojiName: emojiName,
}
_, nErr := ss.Reaction().Save(reaction)
require.NoError(t, nErr)
sameReaction := &model.Reaction{
UserId: model.NewId(),
PostId: post.Id,
EmojiName: emojiName,
}
_, nErr = ss.Reaction().Save(sameReaction)
require.NoError(t, nErr)
newReaction := &model.Reaction{
UserId: userId,
PostId: post.Id,
EmojiName: model.NewId(),
}
_, nErr = ss.Reaction().Save(newReaction)
require.NoError(t, nErr)
totalReactions, err := ss.Reaction().GetForPost(post.Id, false)
require.NoError(t, err)
require.Equal(t, 3, len(totalReactions))
count, err := ss.Reaction().GetUniqueCountForPost(post.Id)
require.NoError(t, err)
require.Equal(t, 2, count)
}