[MM-21378] Add mutex to model.Post to guard against race conditions on Post.Props (#13884)
* Add mutex to model.Post to guard against race conditions on Post.Props * Rename mutex * Add GetProp() method to Post * Fix more tests * Fix flaky test Benchmarks: BenchmarkPostPropsGet_indirect BenchmarkPostPropsGet_indirect-2 85026746 13.0 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_indirect-4 90273747 13.0 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_indirect-8 88324293 13.0 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_indirect-16 91427720 13.1 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_direct BenchmarkPostPropsGet_direct-2 1000000000 0.242 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_direct-4 1000000000 0.241 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_direct-8 1000000000 0.240 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsGet_direct-16 1000000000 0.241 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsAdd_indirect BenchmarkPostPropsAdd_indirect-2 5602224 203 ns/op 336 B/op 2 allocs/op BenchmarkPostPropsAdd_indirect-4 5959496 206 ns/op 336 B/op 2 allocs/op BenchmarkPostPropsAdd_indirect-8 5833999 205 ns/op 336 B/op 2 allocs/op BenchmarkPostPropsAdd_indirect-16 5802493 225 ns/op 336 B/op 2 allocs/op BenchmarkPostPropsAdd_direct BenchmarkPostPropsAdd_direct-2 100000000 11.3 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsAdd_direct-4 100000000 11.3 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsAdd_direct-8 100000000 11.6 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsAdd_direct-16 99840794 11.4 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsDel_indirect BenchmarkPostPropsDel_indirect-2 18824002 61.9 ns/op 48 B/op 1 allocs/op BenchmarkPostPropsDel_indirect-4 19470736 63.8 ns/op 48 B/op 1 allocs/op BenchmarkPostPropsDel_indirect-8 17640460 65.3 ns/op 48 B/op 1 allocs/op BenchmarkPostPropsDel_indirect-16 18692962 65.4 ns/op 48 B/op 1 allocs/op BenchmarkPostPropsDel_direct BenchmarkPostPropsDel_direct-2 516257440 2.34 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsDel_direct-4 514865216 2.43 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsDel_direct-8 511330477 2.37 ns/op 0 B/op 0 allocs/op BenchmarkPostPropsDel_direct-16 499504010 2.38 ns/op 0 B/op 0 allocs/op
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
9e580361c2
Коммит
1e53fe85ad
@@ -616,7 +616,6 @@ func TestExecuteGetCommand(t *testing.T) {
|
|||||||
assert.True(t, len(commandResponse.TriggerId) == 26)
|
assert.True(t, len(commandResponse.TriggerId) == 26)
|
||||||
|
|
||||||
expectedCommandResponse.TriggerId = commandResponse.TriggerId
|
expectedCommandResponse.TriggerId = commandResponse.TriggerId
|
||||||
expectedCommandResponse.Props["from_webhook"] = "true"
|
|
||||||
require.Equal(t, expectedCommandResponse, commandResponse)
|
require.Equal(t, expectedCommandResponse, commandResponse)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -675,9 +674,7 @@ func TestExecutePostCommand(t *testing.T) {
|
|||||||
assert.True(t, len(commandResponse.TriggerId) == 26)
|
assert.True(t, len(commandResponse.TriggerId) == 26)
|
||||||
|
|
||||||
expectedCommandResponse.TriggerId = commandResponse.TriggerId
|
expectedCommandResponse.TriggerId = commandResponse.TriggerId
|
||||||
expectedCommandResponse.Props["from_webhook"] = "true"
|
|
||||||
require.Equal(t, expectedCommandResponse, commandResponse)
|
require.Equal(t, expectedCommandResponse, commandResponse)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestExecuteCommandAgainstChannelOnAnotherTeam(t *testing.T) {
|
func TestExecuteCommandAgainstChannelOnAnotherTeam(t *testing.T) {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ func TestCreatePost(t *testing.T) {
|
|||||||
require.Equal(t, "#hashtag", rpost.Hashtags, "hashtag didn't match")
|
require.Equal(t, "#hashtag", rpost.Hashtags, "hashtag didn't match")
|
||||||
require.Empty(t, rpost.FileIds)
|
require.Empty(t, rpost.FileIds)
|
||||||
require.Equal(t, 0, int(rpost.EditAt), "newly created post shouldn't have EditAt set")
|
require.Equal(t, 0, int(rpost.EditAt), "newly created post shouldn't have EditAt set")
|
||||||
require.Nil(t, rpost.Props[model.PROPS_ADD_CHANNEL_MEMBER], "newly created post shouldn't have Props['add_channel_member'] set")
|
require.Nil(t, rpost.GetProp(model.PROPS_ADD_CHANNEL_MEMBER), "newly created post shouldn't have Props['add_channel_member'] set")
|
||||||
|
|
||||||
post.RootId = rpost.Id
|
post.RootId = rpost.Id
|
||||||
post.ParentId = rpost.Id
|
post.ParentId = rpost.Id
|
||||||
@@ -574,7 +574,7 @@ func TestCreatePostSendOutOfChannelMentions(t *testing.T) {
|
|||||||
|
|
||||||
wpost := model.PostFromJson(strings.NewReader(event.GetData()["post"].(string)))
|
wpost := model.PostFromJson(strings.NewReader(event.GetData()["post"].(string)))
|
||||||
|
|
||||||
acm, ok := wpost.Props[model.PROPS_ADD_CHANNEL_MEMBER].(map[string]interface{})
|
acm, ok := wpost.GetProp(model.PROPS_ADD_CHANNEL_MEMBER).(map[string]interface{})
|
||||||
require.True(t, ok, "should have received ephemeral post with 'add_channel_member' in props")
|
require.True(t, ok, "should have received ephemeral post with 'add_channel_member' in props")
|
||||||
require.True(t, acm["post_id"] != nil, "should not be nil")
|
require.True(t, acm["post_id"] != nil, "should not be nil")
|
||||||
require.True(t, acm["user_ids"] != nil, "should not be nil")
|
require.True(t, acm["user_ids"] != nil, "should not be nil")
|
||||||
@@ -677,20 +677,20 @@ func TestUpdatePost(t *testing.T) {
|
|||||||
t.Run("new message, invalid props", func(t *testing.T) {
|
t.Run("new message, invalid props", func(t *testing.T) {
|
||||||
msg1 := "#hashtag a" + model.NewId() + " update post again"
|
msg1 := "#hashtag a" + model.NewId() + " update post again"
|
||||||
rpost.Message = msg1
|
rpost.Message = msg1
|
||||||
rpost.Props[model.PROPS_ADD_CHANNEL_MEMBER] = "no good"
|
rpost.AddProp(model.PROPS_ADD_CHANNEL_MEMBER, "no good")
|
||||||
rrupost, resp := Client.UpdatePost(rpost.Id, rpost)
|
rrupost, resp := Client.UpdatePost(rpost.Id, rpost)
|
||||||
CheckNoError(t, resp)
|
CheckNoError(t, resp)
|
||||||
|
|
||||||
assert.Equal(t, msg1, rrupost.Message, "failed to update message")
|
assert.Equal(t, msg1, rrupost.Message, "failed to update message")
|
||||||
assert.Equal(t, "#hashtag", rrupost.Hashtags, "failed to update hashtags")
|
assert.Equal(t, "#hashtag", rrupost.Hashtags, "failed to update hashtags")
|
||||||
assert.Nil(t, rrupost.Props[model.PROPS_ADD_CHANNEL_MEMBER], "failed to sanitize Props['add_channel_member'], should be nil")
|
assert.Nil(t, rrupost.GetProp(model.PROPS_ADD_CHANNEL_MEMBER), "failed to sanitize Props['add_channel_member'], should be nil")
|
||||||
|
|
||||||
actual, resp := Client.GetPost(rpost.Id, "")
|
actual, resp := Client.GetPost(rpost.Id, "")
|
||||||
CheckNoError(t, resp)
|
CheckNoError(t, resp)
|
||||||
|
|
||||||
assert.Equal(t, msg1, actual.Message, "failed to update message")
|
assert.Equal(t, msg1, actual.Message, "failed to update message")
|
||||||
assert.Equal(t, "#hashtag", actual.Hashtags, "failed to update hashtags")
|
assert.Equal(t, "#hashtag", actual.Hashtags, "failed to update hashtags")
|
||||||
assert.Nil(t, actual.Props[model.PROPS_ADD_CHANNEL_MEMBER], "failed to sanitize Props['add_channel_member'], should be nil")
|
assert.Nil(t, actual.GetProp(model.PROPS_ADD_CHANNEL_MEMBER), "failed to sanitize Props['add_channel_member'], should be nil")
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("join/leave post", func(t *testing.T) {
|
t.Run("join/leave post", func(t *testing.T) {
|
||||||
@@ -848,7 +848,7 @@ func TestPatchPost(t *testing.T) {
|
|||||||
|
|
||||||
assert.False(t, rpost.IsPinned, "IsPinned did not update properly")
|
assert.False(t, rpost.IsPinned, "IsPinned did not update properly")
|
||||||
assert.Equal(t, "#otherhashtag other message", rpost.Message, "Message did not update properly")
|
assert.Equal(t, "#otherhashtag other message", rpost.Message, "Message did not update properly")
|
||||||
assert.Equal(t, *patch.Props, rpost.Props, "Props did not update properly")
|
assert.Equal(t, *patch.Props, rpost.GetProps(), "Props did not update properly")
|
||||||
assert.Equal(t, "#otherhashtag", rpost.Hashtags, "Message did not update properly")
|
assert.Equal(t, "#otherhashtag", rpost.Hashtags, "Message did not update properly")
|
||||||
assert.Equal(t, model.StringArray(fileIds[0:2]), rpost.FileIds, "FileIds should not update")
|
assert.Equal(t, model.StringArray(fileIds[0:2]), rpost.FileIds, "FileIds should not update")
|
||||||
assert.False(t, rpost.HasReactions, "HasReactions did not update properly")
|
assert.False(t, rpost.HasReactions, "HasReactions did not update properly")
|
||||||
@@ -865,7 +865,7 @@ func TestPatchPost(t *testing.T) {
|
|||||||
|
|
||||||
rpost2, resp := Client.PatchPost(post.Id, patch2)
|
rpost2, resp := Client.PatchPost(post.Id, patch2)
|
||||||
CheckNoError(t, resp)
|
CheckNoError(t, resp)
|
||||||
assert.NotEmpty(t, rpost2.Props["attachments"])
|
assert.NotEmpty(t, rpost2.GetProp("attachments"))
|
||||||
assert.NotEqual(t, rpost.EditAt, rpost2.EditAt)
|
assert.NotEqual(t, rpost.EditAt, rpost2.EditAt)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -489,7 +489,7 @@ func TestAddChannelMemberNoUserRequestor(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, model.POST_JOIN_CHANNEL, post.Type)
|
assert.Equal(t, model.POST_JOIN_CHANNEL, post.Type)
|
||||||
assert.Equal(t, user.Id, post.UserId)
|
assert.Equal(t, user.Id, post.UserId)
|
||||||
assert.Equal(t, user.Username, post.Props["username"])
|
assert.Equal(t, user.Username, post.GetProp("username"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -520,7 +520,7 @@ func (a *App) HandleCommandResponsePost(command *model.Command, args *model.Comm
|
|||||||
post.ParentId = args.ParentId
|
post.ParentId = args.ParentId
|
||||||
post.UserId = args.UserId
|
post.UserId = args.UserId
|
||||||
post.Type = response.Type
|
post.Type = response.Type
|
||||||
post.Props = response.Props
|
post.SetProps(response.Props)
|
||||||
|
|
||||||
if len(response.ChannelId) != 0 {
|
if len(response.ChannelId) != 0 {
|
||||||
_, err := a.GetChannelMember(response.ChannelId, args.UserId)
|
_, err := a.GetChannelMember(response.ChannelId, args.UserId)
|
||||||
|
|||||||
@@ -104,16 +104,16 @@ func TestHandleCommandResponsePost(t *testing.T) {
|
|||||||
assert.Equal(t, args.ParentId, post.ParentId)
|
assert.Equal(t, args.ParentId, post.ParentId)
|
||||||
assert.Equal(t, args.UserId, post.UserId)
|
assert.Equal(t, args.UserId, post.UserId)
|
||||||
assert.Equal(t, resp.Type, post.Type)
|
assert.Equal(t, resp.Type, post.Type)
|
||||||
assert.Equal(t, resp.Props, post.Props)
|
assert.Equal(t, resp.Props, post.GetProps())
|
||||||
assert.Equal(t, resp.Text, post.Message)
|
assert.Equal(t, resp.Text, post.Message)
|
||||||
assert.Nil(t, post.Props["override_icon_url"])
|
assert.Nil(t, post.GetProp("override_icon_url"))
|
||||||
assert.Nil(t, post.Props["override_username"])
|
assert.Nil(t, post.GetProp("override_username"))
|
||||||
assert.Nil(t, post.Props["from_webhook"])
|
assert.Nil(t, post.GetProp("from_webhook"))
|
||||||
|
|
||||||
// Command is not built in, so it is a bot command.
|
// Command is not built in, so it is a bot command.
|
||||||
builtIn = false
|
builtIn = false
|
||||||
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
||||||
assert.Equal(t, "true", post.Props["from_webhook"])
|
assert.Equal(t, "true", post.GetProp("from_webhook"))
|
||||||
|
|
||||||
builtIn = true
|
builtIn = true
|
||||||
|
|
||||||
@@ -135,23 +135,23 @@ func TestHandleCommandResponsePost(t *testing.T) {
|
|||||||
|
|
||||||
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Nil(t, post.Props["override_username"])
|
assert.Nil(t, post.GetProp("override_username"))
|
||||||
|
|
||||||
*th.App.Config().ServiceSettings.EnablePostUsernameOverride = true
|
*th.App.Config().ServiceSettings.EnablePostUsernameOverride = true
|
||||||
|
|
||||||
// Override username config is turned on. Override username through command property.
|
// Override username config is turned on. Override username through command property.
|
||||||
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, command.Username, post.Props["override_username"])
|
assert.Equal(t, command.Username, post.GetProp("override_username"))
|
||||||
assert.Equal(t, "true", post.Props["from_webhook"])
|
assert.Equal(t, "true", post.GetProp("from_webhook"))
|
||||||
|
|
||||||
command.Username = ""
|
command.Username = ""
|
||||||
|
|
||||||
// Override username through response property.
|
// Override username through response property.
|
||||||
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, resp.Username, post.Props["override_username"])
|
assert.Equal(t, resp.Username, post.GetProp("override_username"))
|
||||||
assert.Equal(t, "true", post.Props["from_webhook"])
|
assert.Equal(t, "true", post.GetProp("from_webhook"))
|
||||||
|
|
||||||
*th.App.Config().ServiceSettings.EnablePostUsernameOverride = false
|
*th.App.Config().ServiceSettings.EnablePostUsernameOverride = false
|
||||||
|
|
||||||
@@ -162,23 +162,23 @@ func TestHandleCommandResponsePost(t *testing.T) {
|
|||||||
|
|
||||||
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Nil(t, post.Props["override_icon_url"])
|
assert.Nil(t, post.GetProp("override_icon_url"))
|
||||||
|
|
||||||
*th.App.Config().ServiceSettings.EnablePostIconOverride = true
|
*th.App.Config().ServiceSettings.EnablePostIconOverride = true
|
||||||
|
|
||||||
// Override icon url config is turned on. Override icon url through command property.
|
// Override icon url config is turned on. Override icon url through command property.
|
||||||
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, command.IconURL, post.Props["override_icon_url"])
|
assert.Equal(t, command.IconURL, post.GetProp("override_icon_url"))
|
||||||
assert.Equal(t, "true", post.Props["from_webhook"])
|
assert.Equal(t, "true", post.GetProp("from_webhook"))
|
||||||
|
|
||||||
command.IconURL = ""
|
command.IconURL = ""
|
||||||
|
|
||||||
// Override icon url through response property.
|
// Override icon url through response property.
|
||||||
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, resp.IconURL, post.Props["override_icon_url"])
|
assert.Equal(t, resp.IconURL, post.GetProp("override_icon_url"))
|
||||||
assert.Equal(t, "true", post.Props["from_webhook"])
|
assert.Equal(t, "true", post.GetProp("from_webhook"))
|
||||||
|
|
||||||
// Test Slack text conversion.
|
// Test Slack text conversion.
|
||||||
resp.Text = "<!channel>"
|
resp.Text = "<!channel>"
|
||||||
@@ -186,7 +186,7 @@ func TestHandleCommandResponsePost(t *testing.T) {
|
|||||||
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
post, err = th.App.HandleCommandResponsePost(command, args, resp, builtIn)
|
||||||
assert.Nil(t, err)
|
assert.Nil(t, err)
|
||||||
assert.Equal(t, "@channel", post.Message)
|
assert.Equal(t, "@channel", post.Message)
|
||||||
assert.Equal(t, "true", post.Props["from_webhook"])
|
assert.Equal(t, "true", post.GetProp("from_webhook"))
|
||||||
|
|
||||||
// Test Slack attachments text conversion.
|
// Test Slack attachments text conversion.
|
||||||
resp.Attachments = []*model.SlackAttachment{
|
resp.Attachments = []*model.SlackAttachment{
|
||||||
@@ -201,7 +201,7 @@ func TestHandleCommandResponsePost(t *testing.T) {
|
|||||||
if assert.Len(t, post.Attachments(), 1) {
|
if assert.Len(t, post.Attachments(), 1) {
|
||||||
assert.Equal(t, "@here", post.Attachments()[0].Text)
|
assert.Equal(t, "@here", post.Attachments()[0].Text)
|
||||||
}
|
}
|
||||||
assert.Equal(t, "true", post.Props["from_webhook"])
|
assert.Equal(t, "true", post.GetProp("from_webhook"))
|
||||||
|
|
||||||
channel = th.CreatePrivateChannel(th.BasicTeam)
|
channel = th.CreatePrivateChannel(th.BasicTeam)
|
||||||
resp.ChannelId = channel.Id
|
resp.ChannelId = channel.Id
|
||||||
|
|||||||
@@ -331,7 +331,7 @@ func (a *App) MigrateFilenamesToFileInfos(post *model.Post) []*model.FileInfo {
|
|||||||
|
|
||||||
// Copy and save the updated post
|
// Copy and save the updated post
|
||||||
newPost := &model.Post{}
|
newPost := &model.Post{}
|
||||||
*newPost = *post
|
newPost = post.Clone()
|
||||||
|
|
||||||
newPost.Filenames = []string{}
|
newPost.Filenames = []string{}
|
||||||
newPost.FileIds = fileIds
|
newPost.FileIds = fileIds
|
||||||
|
|||||||
@@ -138,14 +138,14 @@ func (a *App) DoPostActionWithCookie(postId, actionId, userId, selectedOption st
|
|||||||
// Save the original values that may need to be preserved (including selected
|
// Save the original values that may need to be preserved (including selected
|
||||||
// Props, i.e. override_username, override_icon_url)
|
// Props, i.e. override_username, override_icon_url)
|
||||||
for _, key := range model.PostActionRetainPropKeys {
|
for _, key := range model.PostActionRetainPropKeys {
|
||||||
value, ok := post.Props[key]
|
value, ok := post.GetProps()[key]
|
||||||
if ok {
|
if ok {
|
||||||
retain[key] = value
|
retain[key] = value
|
||||||
} else {
|
} else {
|
||||||
remove = append(remove, key)
|
remove = append(remove, key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
originalProps = post.Props
|
originalProps = post.GetProps()
|
||||||
originalIsPinned = post.IsPinned
|
originalIsPinned = post.IsPinned
|
||||||
originalHasReactions = post.HasReactions
|
originalHasReactions = post.HasReactions
|
||||||
|
|
||||||
@@ -219,14 +219,14 @@ func (a *App) DoPostActionWithCookie(postId, actionId, userId, selectedOption st
|
|||||||
response.Update.Id = postId
|
response.Update.Id = postId
|
||||||
|
|
||||||
// Restore the post attributes and Props that need to be preserved
|
// Restore the post attributes and Props that need to be preserved
|
||||||
if response.Update.Props == nil {
|
if response.Update.GetProps() == nil {
|
||||||
response.Update.Props = originalProps
|
response.Update.SetProps(originalProps)
|
||||||
} else {
|
} else {
|
||||||
for key, value := range retain {
|
for key, value := range retain {
|
||||||
response.Update.AddProp(key, value)
|
response.Update.AddProp(key, value)
|
||||||
}
|
}
|
||||||
for _, key := range remove {
|
for _, key := range remove {
|
||||||
delete(response.Update.Props, key)
|
response.Update.DelProp(key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
response.Update.IsPinned = originalIsPinned
|
response.Update.IsPinned = originalIsPinned
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ func TestPostActionInvalidURL(t *testing.T) {
|
|||||||
|
|
||||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.NotEmpty(t, attachments[0].Actions)
|
require.NotEmpty(t, attachments[0].Actions)
|
||||||
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
||||||
@@ -158,7 +158,7 @@ func TestPostAction(t *testing.T) {
|
|||||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
require.NotEmpty(t, attachments[0].Actions)
|
require.NotEmpty(t, attachments[0].Actions)
|
||||||
@@ -195,7 +195,7 @@ func TestPostAction(t *testing.T) {
|
|||||||
post2, err := th.App.CreatePostAsUser(&menuPost, "")
|
post2, err := th.App.CreatePostAsUser(&menuPost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
attachments2, ok := post2.Props["attachments"].([]*model.SlackAttachment)
|
attachments2, ok := post2.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
require.NotEmpty(t, attachments2[0].Actions)
|
require.NotEmpty(t, attachments2[0].Actions)
|
||||||
@@ -253,7 +253,7 @@ func TestPostAction(t *testing.T) {
|
|||||||
postplugin, err := th.App.CreatePostAsUser(&interactivePostPlugin, "")
|
postplugin, err := th.App.CreatePostAsUser(&interactivePostPlugin, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
attachmentsPlugin, ok := postplugin.Props["attachments"].([]*model.SlackAttachment)
|
attachmentsPlugin, ok := postplugin.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
_, err = th.App.DoPostAction(postplugin.Id, attachmentsPlugin[0].Actions[0].Id, th.BasicUser.Id, "")
|
_, err = th.App.DoPostAction(postplugin.Id, attachmentsPlugin[0].Actions[0].Id, th.BasicUser.Id, "")
|
||||||
@@ -294,7 +294,7 @@ func TestPostAction(t *testing.T) {
|
|||||||
postSiteURL, err := th.App.CreatePostAsUser(&interactivePostSiteURL, "")
|
postSiteURL, err := th.App.CreatePostAsUser(&interactivePostSiteURL, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
attachmentsSiteURL, ok := postSiteURL.Props["attachments"].([]*model.SlackAttachment)
|
attachmentsSiteURL, ok := postSiteURL.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
_, err = th.App.DoPostAction(postSiteURL.Id, attachmentsSiteURL[0].Actions[0].Id, th.BasicUser.Id, "")
|
_, err = th.App.DoPostAction(postSiteURL.Id, attachmentsSiteURL[0].Actions[0].Id, th.BasicUser.Id, "")
|
||||||
@@ -336,7 +336,7 @@ func TestPostAction(t *testing.T) {
|
|||||||
postSubpath, err := th.App.CreatePostAsUser(&interactivePostSubpath, "")
|
postSubpath, err := th.App.CreatePostAsUser(&interactivePostSubpath, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
attachmentsSubpath, ok := postSubpath.Props["attachments"].([]*model.SlackAttachment)
|
attachmentsSubpath, ok := postSubpath.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
_, err = th.App.DoPostAction(postSubpath.Id, attachmentsSubpath[0].Actions[0].Id, th.BasicUser.Id, "")
|
_, err = th.App.DoPostAction(postSubpath.Id, attachmentsSubpath[0].Actions[0].Id, th.BasicUser.Id, "")
|
||||||
@@ -410,7 +410,7 @@ func TestPostActionProps(t *testing.T) {
|
|||||||
|
|
||||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
|
|
||||||
clientTriggerId, err := th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "")
|
clientTriggerId, err := th.App.DoPostAction(post.Id, attachments[0].Actions[0].Id, th.BasicUser.Id, "")
|
||||||
@@ -422,11 +422,11 @@ func TestPostActionProps(t *testing.T) {
|
|||||||
|
|
||||||
assert.True(t, newPost.IsPinned)
|
assert.True(t, newPost.IsPinned)
|
||||||
assert.False(t, newPost.HasReactions)
|
assert.False(t, newPost.HasReactions)
|
||||||
assert.Nil(t, newPost.Props["B"])
|
assert.Nil(t, newPost.GetProp("B"))
|
||||||
assert.Nil(t, newPost.Props["override_username"])
|
assert.Nil(t, newPost.GetProp("override_username"))
|
||||||
assert.Equal(t, "AA", newPost.Props["A"])
|
assert.Equal(t, "AA", newPost.GetProp("A"))
|
||||||
assert.Equal(t, "old_override_icon", newPost.Props["override_icon_url"])
|
assert.Equal(t, "old_override_icon", newPost.GetProp("override_icon_url"))
|
||||||
assert.Equal(t, false, newPost.Props["from_webhook"])
|
assert.Equal(t, false, newPost.GetProp("from_webhook"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestSubmitInteractiveDialog(t *testing.T) {
|
func TestSubmitInteractiveDialog(t *testing.T) {
|
||||||
@@ -578,7 +578,7 @@ func TestPostActionRelativeURL(t *testing.T) {
|
|||||||
|
|
||||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.NotEmpty(t, attachments[0].Actions)
|
require.NotEmpty(t, attachments[0].Actions)
|
||||||
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
||||||
@@ -618,7 +618,7 @@ func TestPostActionRelativeURL(t *testing.T) {
|
|||||||
|
|
||||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.NotEmpty(t, attachments[0].Actions)
|
require.NotEmpty(t, attachments[0].Actions)
|
||||||
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
||||||
@@ -658,7 +658,7 @@ func TestPostActionRelativeURL(t *testing.T) {
|
|||||||
|
|
||||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.NotEmpty(t, attachments[0].Actions)
|
require.NotEmpty(t, attachments[0].Actions)
|
||||||
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
||||||
@@ -699,7 +699,7 @@ func TestPostActionRelativeURL(t *testing.T) {
|
|||||||
|
|
||||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.NotEmpty(t, attachments[0].Actions)
|
require.NotEmpty(t, attachments[0].Actions)
|
||||||
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
||||||
@@ -739,7 +739,7 @@ func TestPostActionRelativeURL(t *testing.T) {
|
|||||||
|
|
||||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.NotEmpty(t, attachments[0].Actions)
|
require.NotEmpty(t, attachments[0].Actions)
|
||||||
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
||||||
@@ -813,7 +813,7 @@ func TestPostActionRelativePluginURL(t *testing.T) {
|
|||||||
|
|
||||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.NotEmpty(t, attachments[0].Actions)
|
require.NotEmpty(t, attachments[0].Actions)
|
||||||
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
||||||
@@ -853,7 +853,7 @@ func TestPostActionRelativePluginURL(t *testing.T) {
|
|||||||
|
|
||||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.NotEmpty(t, attachments[0].Actions)
|
require.NotEmpty(t, attachments[0].Actions)
|
||||||
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
||||||
@@ -893,7 +893,7 @@ func TestPostActionRelativePluginURL(t *testing.T) {
|
|||||||
|
|
||||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.NotEmpty(t, attachments[0].Actions)
|
require.NotEmpty(t, attachments[0].Actions)
|
||||||
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
||||||
@@ -933,7 +933,7 @@ func TestPostActionRelativePluginURL(t *testing.T) {
|
|||||||
|
|
||||||
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
post, err := th.App.CreatePostAsUser(&interactivePost, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
attachments, ok := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
require.True(t, ok)
|
require.True(t, ok)
|
||||||
require.NotEmpty(t, attachments[0].Actions)
|
require.NotEmpty(t, attachments[0].Actions)
|
||||||
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
require.NotEmpty(t, attachments[0].Actions[0].Id)
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
|
|||||||
mentions.addMention(otherUserId, DMMention)
|
mentions.addMention(otherUserId, DMMention)
|
||||||
}
|
}
|
||||||
|
|
||||||
if post.Props["from_webhook"] == "true" {
|
if post.GetProp("from_webhook") == "true" {
|
||||||
mentions.addMention(post.UserId, DMMention)
|
mentions.addMention(post.UserId, DMMention)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -81,7 +81,7 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
|
|||||||
// Add an implicit mention when a user is added to a channel
|
// Add an implicit mention when a user is added to a channel
|
||||||
// even if the user has set 'username mentions' to false in account settings.
|
// even if the user has set 'username mentions' to false in account settings.
|
||||||
if post.Type == model.POST_ADD_TO_CHANNEL {
|
if post.Type == model.POST_ADD_TO_CHANNEL {
|
||||||
addedUserId, ok := post.Props[model.POST_PROPS_ADDED_USER_ID].(string)
|
addedUserId, ok := post.GetProp(model.POST_PROPS_ADDED_USER_ID).(string)
|
||||||
if ok {
|
if ok {
|
||||||
mentions.addMention(addedUserId, KeywordMention)
|
mentions.addMention(addedUserId, KeywordMention)
|
||||||
}
|
}
|
||||||
@@ -103,7 +103,7 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
|
|||||||
}
|
}
|
||||||
|
|
||||||
// prevent the user from mentioning themselves
|
// prevent the user from mentioning themselves
|
||||||
if post.Props["from_webhook"] != "true" {
|
if post.GetProp("from_webhook") != "true" {
|
||||||
mentions.removeMention(post.UserId)
|
mentions.removeMention(post.UserId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -118,7 +118,7 @@ func (a *App) SendNotifications(post *model.Post, team *model.Team, channel *mod
|
|||||||
for _, profile := range profileMap {
|
for _, profile := range profileMap {
|
||||||
if (profile.NotifyProps[model.PUSH_NOTIFY_PROP] == model.USER_NOTIFY_ALL ||
|
if (profile.NotifyProps[model.PUSH_NOTIFY_PROP] == model.USER_NOTIFY_ALL ||
|
||||||
channelMemberNotifyPropsMap[profile.Id][model.PUSH_NOTIFY_PROP] == model.CHANNEL_NOTIFY_ALL) &&
|
channelMemberNotifyPropsMap[profile.Id][model.PUSH_NOTIFY_PROP] == model.CHANNEL_NOTIFY_ALL) &&
|
||||||
(post.UserId != profile.Id || post.Props["from_webhook"] == "true") &&
|
(post.UserId != profile.Id || post.GetProp("from_webhook") == "true") &&
|
||||||
!post.IsSystemMessage() {
|
!post.IsSystemMessage() {
|
||||||
allActivityPushUserIds = append(allActivityPushUserIds, profile.Id)
|
allActivityPushUserIds = append(allActivityPushUserIds, profile.Id)
|
||||||
}
|
}
|
||||||
@@ -733,7 +733,7 @@ func (n *PostNotification) GetSenderName(userNameFormat string, overridesAllowed
|
|||||||
}
|
}
|
||||||
|
|
||||||
if overridesAllowed && n.Channel.Type != model.CHANNEL_DIRECT {
|
if overridesAllowed && n.Channel.Type != model.CHANNEL_DIRECT {
|
||||||
if value, ok := n.Post.Props["override_username"]; ok && n.Post.Props["from_webhook"] == "true" {
|
if value, ok := n.Post.GetProps()["override_username"]; ok && n.Post.GetProp("from_webhook") == "true" {
|
||||||
return value.(string)
|
return value.(string)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -425,7 +425,7 @@ func DoesNotifyPropsAllowPushNotification(user *model.User, channelNotifyProps m
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (userNotify == model.USER_NOTIFY_ALL || channelNotify == model.CHANNEL_NOTIFY_ALL) &&
|
if (userNotify == model.USER_NOTIFY_ALL || channelNotify == model.CHANNEL_NOTIFY_ALL) &&
|
||||||
(post.UserId != user.Id || post.Props["from_webhook"] == "true") {
|
(post.UserId != user.Id || post.GetProp("from_webhook") == "true") {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -521,16 +521,16 @@ func (a *App) buildFullPushNotificationMessage(contentsConfig string, post *mode
|
|||||||
}
|
}
|
||||||
|
|
||||||
msg.SenderName = senderName
|
msg.SenderName = senderName
|
||||||
if ou, ok := post.Props["override_username"].(string); ok && *cfg.ServiceSettings.EnablePostUsernameOverride {
|
if ou, ok := post.GetProp("override_username").(string); ok && *cfg.ServiceSettings.EnablePostUsernameOverride {
|
||||||
msg.OverrideUsername = ou
|
msg.OverrideUsername = ou
|
||||||
msg.SenderName = ou
|
msg.SenderName = ou
|
||||||
}
|
}
|
||||||
|
|
||||||
if oi, ok := post.Props["override_icon_url"].(string); ok && *cfg.ServiceSettings.EnablePostIconOverride {
|
if oi, ok := post.GetProp("override_icon_url").(string); ok && *cfg.ServiceSettings.EnablePostIconOverride {
|
||||||
msg.OverrideIconUrl = oi
|
msg.OverrideIconUrl = oi
|
||||||
}
|
}
|
||||||
|
|
||||||
if fw, ok := post.Props["from_webhook"].(string); ok {
|
if fw, ok := post.GetProp("from_webhook").(string); ok {
|
||||||
msg.FromWebhook = fw
|
msg.FromWebhook = fw
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1613,7 +1613,7 @@ func TestPostNotificationGetSenderName(t *testing.T) {
|
|||||||
"overridden username": {
|
"overridden username": {
|
||||||
post: overriddenPost,
|
post: overriddenPost,
|
||||||
allowOverrides: true,
|
allowOverrides: true,
|
||||||
expected: overriddenPost.Props["override_username"].(string),
|
expected: overriddenPost.GetProp("override_username").(string),
|
||||||
},
|
},
|
||||||
"overridden username, direct channel": {
|
"overridden username, direct channel": {
|
||||||
channel: &model.Channel{Type: model.CHANNEL_DIRECT},
|
channel: &model.Channel{Type: model.CHANNEL_DIRECT},
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ func TestPluginDeadlock(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
|
func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
|
||||||
if _, from_plugin := post.Props["from_plugin"]; from_plugin {
|
if _, from_plugin := post.GetProps()["from_plugin"]; from_plugin {
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ func TestPluginDeadlock(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
|
func (p *MyPlugin) MessageWillBePosted(c *plugin.Context, post *model.Post) (*model.Post, string) {
|
||||||
if _, from_plugin := post.Props["from_plugin"]; from_plugin {
|
if _, from_plugin := post.GetProps()["from_plugin"]; from_plugin {
|
||||||
return nil, ""
|
return nil, ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
26
app/post.go
26
app/post.go
@@ -73,7 +73,7 @@ func (a *App) CreatePostAsUser(post *model.Post, currentSessionId string) (*mode
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update the LastViewAt only if the post does not have from_webhook prop set (eg. Zapier app)
|
// Update the LastViewAt only if the post does not have from_webhook prop set (eg. Zapier app)
|
||||||
if _, ok := post.Props["from_webhook"]; !ok {
|
if _, ok := post.GetProps()["from_webhook"]; !ok {
|
||||||
if _, err := a.MarkChannelsAsViewed([]string{post.ChannelId}, post.UserId, currentSessionId); err != nil {
|
if _, err := a.MarkChannelsAsViewed([]string{post.ChannelId}, post.UserId, currentSessionId); err != nil {
|
||||||
mlog.Error(
|
mlog.Error(
|
||||||
"Encountered error updating last viewed",
|
"Encountered error updating last viewed",
|
||||||
@@ -241,12 +241,12 @@ func (a *App) CreatePost(post *model.Post, channel *model.Channel, triggerWebhoo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Temporary fix so old plugins don't clobber new fields in SlackAttachment struct, see MM-13088
|
// Temporary fix so old plugins don't clobber new fields in SlackAttachment struct, see MM-13088
|
||||||
if attachments, ok := post.Props["attachments"].([]*model.SlackAttachment); ok {
|
if attachments, ok := post.GetProp("attachments").([]*model.SlackAttachment); ok {
|
||||||
jsonAttachments, err := json.Marshal(attachments)
|
jsonAttachments, err := json.Marshal(attachments)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
attachmentsInterface := []interface{}{}
|
attachmentsInterface := []interface{}{}
|
||||||
err = json.Unmarshal(jsonAttachments, &attachmentsInterface)
|
err = json.Unmarshal(jsonAttachments, &attachmentsInterface)
|
||||||
post.Props["attachments"] = attachmentsInterface
|
post.AddProp("attachments", attachmentsInterface)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
mlog.Error("Could not convert post attachments to map interface.", mlog.Err(err))
|
mlog.Error("Could not convert post attachments to map interface.", mlog.Err(err))
|
||||||
@@ -384,8 +384,8 @@ func (a *App) FillInPostProps(post *model.Post, channel *model.Channel) *model.A
|
|||||||
|
|
||||||
if len(channelMentionsProp) > 0 {
|
if len(channelMentionsProp) > 0 {
|
||||||
post.AddProp("channel_mentions", channelMentionsProp)
|
post.AddProp("channel_mentions", channelMentionsProp)
|
||||||
} else if post.Props != nil {
|
} else if post.GetProps() != nil {
|
||||||
delete(post.Props, "channel_mentions")
|
post.DelProp("channel_mentions")
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -439,8 +439,8 @@ func (a *App) SendEphemeralPost(userId string, post *model.Post) *model.Post {
|
|||||||
if post.CreateAt == 0 {
|
if post.CreateAt == 0 {
|
||||||
post.CreateAt = model.GetMillis()
|
post.CreateAt = model.GetMillis()
|
||||||
}
|
}
|
||||||
if post.Props == nil {
|
if post.GetProps() == nil {
|
||||||
post.Props = model.StringInterface{}
|
post.SetProps(make(model.StringInterface))
|
||||||
}
|
}
|
||||||
|
|
||||||
post.GenerateActionIds()
|
post.GenerateActionIds()
|
||||||
@@ -457,8 +457,8 @@ func (a *App) UpdateEphemeralPost(userId string, post *model.Post) *model.Post {
|
|||||||
post.Type = model.POST_EPHEMERAL
|
post.Type = model.POST_EPHEMERAL
|
||||||
|
|
||||||
post.UpdateAt = model.GetMillis()
|
post.UpdateAt = model.GetMillis()
|
||||||
if post.Props == nil {
|
if post.GetProps() == nil {
|
||||||
post.Props = model.StringInterface{}
|
post.SetProps(make(model.StringInterface))
|
||||||
}
|
}
|
||||||
|
|
||||||
post.GenerateActionIds()
|
post.GenerateActionIds()
|
||||||
@@ -526,7 +526,7 @@ func (a *App) UpdatePost(post *model.Post, safeUpdate bool) (*model.Post, *model
|
|||||||
}
|
}
|
||||||
|
|
||||||
newPost := &model.Post{}
|
newPost := &model.Post{}
|
||||||
*newPost = *oldPost
|
newPost = oldPost.Clone()
|
||||||
|
|
||||||
if newPost.Message != post.Message {
|
if newPost.Message != post.Message {
|
||||||
newPost.Message = post.Message
|
newPost.Message = post.Message
|
||||||
@@ -538,7 +538,7 @@ func (a *App) UpdatePost(post *model.Post, safeUpdate bool) (*model.Post, *model
|
|||||||
newPost.IsPinned = post.IsPinned
|
newPost.IsPinned = post.IsPinned
|
||||||
newPost.HasReactions = post.HasReactions
|
newPost.HasReactions = post.HasReactions
|
||||||
newPost.FileIds = post.FileIds
|
newPost.FileIds = post.FileIds
|
||||||
newPost.Props = post.Props
|
newPost.SetProps(post.GetProps())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoid deep-equal checks if EditAt was already modified through message change
|
// Avoid deep-equal checks if EditAt was already modified through message change
|
||||||
@@ -1220,7 +1220,7 @@ func isCommentMention(user *model.User, post *model.Post, otherPosts map[string]
|
|||||||
|
|
||||||
func isPostMention(user *model.User, post *model.Post, keywords map[string][]string, otherPosts map[string]*model.Post, mentionedByThread map[string]bool, checkForCommentMentions bool) bool {
|
func isPostMention(user *model.User, post *model.Post, keywords map[string][]string, otherPosts map[string]*model.Post, mentionedByThread map[string]bool, checkForCommentMentions bool) bool {
|
||||||
// Prevent the user from mentioning themselves
|
// Prevent the user from mentioning themselves
|
||||||
if post.UserId == user.Id && post.Props["from_webhook"] != "true" {
|
if post.UserId == user.Id && post.GetProp("from_webhook") != "true" {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1232,7 +1232,7 @@ func isPostMention(user *model.User, post *model.Post, keywords map[string][]str
|
|||||||
|
|
||||||
// Check for mentions caused by being added to the channel
|
// Check for mentions caused by being added to the channel
|
||||||
if post.Type == model.POST_ADD_TO_CHANNEL {
|
if post.Type == model.POST_ADD_TO_CHANNEL {
|
||||||
if addedUserId, ok := post.Props[model.POST_PROPS_ADDED_USER_ID].(string); ok && addedUserId == user.Id {
|
if addedUserId, ok := post.GetProp(model.POST_PROPS_ADDED_USER_ID).(string); ok && addedUserId == user.Id {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ func (a *App) PreparePostListForClient(originalList *model.PostList) *model.Post
|
|||||||
// OverrideIconURLIfEmoji changes the post icon override URL prop, if it has an emoji icon,
|
// OverrideIconURLIfEmoji changes the post icon override URL prop, if it has an emoji icon,
|
||||||
// so that it points to the URL (relative) of the emoji - static if emoji is default, /api if custom.
|
// so that it points to the URL (relative) of the emoji - static if emoji is default, /api if custom.
|
||||||
func (a *App) OverrideIconURLIfEmoji(post *model.Post) {
|
func (a *App) OverrideIconURLIfEmoji(post *model.Post) {
|
||||||
prop, ok := post.Props[model.POST_PROPS_OVERRIDE_ICON_EMOJI]
|
prop, ok := post.GetProps()[model.POST_PROPS_OVERRIDE_ICON_EMOJI]
|
||||||
if !ok || prop == nil {
|
if !ok || prop == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -149,7 +149,7 @@ func (a *App) getEmojisAndReactionsForPost(post *model.Post) ([]*model.Emoji, []
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) getEmbedForPost(post *model.Post, firstLink string, isNewPost bool) (*model.PostEmbed, error) {
|
func (a *App) getEmbedForPost(post *model.Post, firstLink string, isNewPost bool) (*model.PostEmbed, error) {
|
||||||
if _, ok := post.Props["attachments"]; ok {
|
if _, ok := post.GetProps()["attachments"]; ok {
|
||||||
return &model.PostEmbed{
|
return &model.PostEmbed{
|
||||||
Type: model.POST_EMBED_MESSAGE_ATTACHMENT,
|
Type: model.POST_EMBED_MESSAGE_ATTACHMENT,
|
||||||
}, nil
|
}, nil
|
||||||
|
|||||||
@@ -307,10 +307,10 @@ func TestPreparePostForClient(t *testing.T) {
|
|||||||
t.Run("does not override icon URL", func(t *testing.T) {
|
t.Run("does not override icon URL", func(t *testing.T) {
|
||||||
clientPost := prepare(false, url, emoji)
|
clientPost := prepare(false, url, emoji)
|
||||||
|
|
||||||
s, ok := clientPost.Props[model.POST_PROPS_OVERRIDE_ICON_URL]
|
s, ok := clientPost.GetProps()[model.POST_PROPS_OVERRIDE_ICON_URL]
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.EqualValues(t, url, s)
|
assert.EqualValues(t, url, s)
|
||||||
s, ok = clientPost.Props[model.POST_PROPS_OVERRIDE_ICON_EMOJI]
|
s, ok = clientPost.GetProps()[model.POST_PROPS_OVERRIDE_ICON_EMOJI]
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.EqualValues(t, emoji, s)
|
assert.EqualValues(t, emoji, s)
|
||||||
})
|
})
|
||||||
@@ -318,10 +318,10 @@ func TestPreparePostForClient(t *testing.T) {
|
|||||||
t.Run("overrides icon URL", func(t *testing.T) {
|
t.Run("overrides icon URL", func(t *testing.T) {
|
||||||
clientPost := prepare(true, url, emoji)
|
clientPost := prepare(true, url, emoji)
|
||||||
|
|
||||||
s, ok := clientPost.Props[model.POST_PROPS_OVERRIDE_ICON_URL]
|
s, ok := clientPost.GetProps()[model.POST_PROPS_OVERRIDE_ICON_URL]
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.EqualValues(t, overridenUrl, s)
|
assert.EqualValues(t, overridenUrl, s)
|
||||||
s, ok = clientPost.Props[model.POST_PROPS_OVERRIDE_ICON_EMOJI]
|
s, ok = clientPost.GetProps()[model.POST_PROPS_OVERRIDE_ICON_EMOJI]
|
||||||
assert.True(t, ok)
|
assert.True(t, ok)
|
||||||
assert.EqualValues(t, emoji, s)
|
assert.EqualValues(t, emoji, s)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -256,13 +256,13 @@ func TestUpdatePostEditAt(t *testing.T) {
|
|||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|
||||||
post := &model.Post{}
|
post := &model.Post{}
|
||||||
*post = *th.BasicPost
|
post = th.BasicPost.Clone()
|
||||||
|
|
||||||
post.IsPinned = true
|
post.IsPinned = true
|
||||||
saved, err := th.App.UpdatePost(post, true)
|
saved, err := th.App.UpdatePost(post, true)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, saved.EditAt, post.EditAt, "shouldn't have updated post.EditAt when pinning post")
|
assert.Equal(t, saved.EditAt, post.EditAt, "shouldn't have updated post.EditAt when pinning post")
|
||||||
*post = *saved
|
post = saved.Clone()
|
||||||
|
|
||||||
time.Sleep(time.Millisecond * 100)
|
time.Sleep(time.Millisecond * 100)
|
||||||
|
|
||||||
@@ -279,7 +279,7 @@ func TestUpdatePostTimeLimit(t *testing.T) {
|
|||||||
defer th.TearDown()
|
defer th.TearDown()
|
||||||
|
|
||||||
post := &model.Post{}
|
post := &model.Post{}
|
||||||
*post = *th.BasicPost
|
post = th.BasicPost.Clone()
|
||||||
|
|
||||||
th.App.SetLicense(model.NewTestLicense())
|
th.App.SetLicense(model.NewTestLicense())
|
||||||
|
|
||||||
@@ -433,7 +433,7 @@ func TestPostChannelMentions(t *testing.T) {
|
|||||||
"mention-test": map[string]interface{}{
|
"mention-test": map[string]interface{}{
|
||||||
"display_name": "Mention Test",
|
"display_name": "Mention Test",
|
||||||
},
|
},
|
||||||
}, result.Props["channel_mentions"])
|
}, result.GetProp("channel_mentions"))
|
||||||
|
|
||||||
post.Message = fmt.Sprintf("goodbye, ~%v!", channelToMention.Name)
|
post.Message = fmt.Sprintf("goodbye, ~%v!", channelToMention.Name)
|
||||||
result, err = th.App.UpdatePost(post, false)
|
result, err = th.App.UpdatePost(post, false)
|
||||||
@@ -442,7 +442,7 @@ func TestPostChannelMentions(t *testing.T) {
|
|||||||
"mention-test": map[string]interface{}{
|
"mention-test": map[string]interface{}{
|
||||||
"display_name": "Mention Test",
|
"display_name": "Mention Test",
|
||||||
},
|
},
|
||||||
}, result.Props["channel_mentions"])
|
}, result.GetProp("channel_mentions"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestImageProxy(t *testing.T) {
|
func TestImageProxy(t *testing.T) {
|
||||||
@@ -694,7 +694,7 @@ func TestCreatePost(t *testing.T) {
|
|||||||
}
|
}
|
||||||
rpost, err := th.App.CreatePost(postWithNoMention, th.BasicChannel, false)
|
rpost, err := th.App.CreatePost(postWithNoMention, th.BasicChannel, false)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, rpost.Props, model.StringInterface{})
|
assert.Equal(t, rpost.GetProps(), model.StringInterface{})
|
||||||
|
|
||||||
postWithMention := &model.Post{
|
postWithMention := &model.Post{
|
||||||
ChannelId: th.BasicChannel.Id,
|
ChannelId: th.BasicChannel.Id,
|
||||||
@@ -703,7 +703,7 @@ func TestCreatePost(t *testing.T) {
|
|||||||
}
|
}
|
||||||
rpost, err = th.App.CreatePost(postWithMention, th.BasicChannel, false)
|
rpost, err = th.App.CreatePost(postWithMention, th.BasicChannel, false)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, rpost.Props, model.StringInterface{})
|
assert.Equal(t, rpost.GetProps(), model.StringInterface{})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Sets prop when post has mentions and user does not have USE_CHANNEL_MENTIONS", func(t *testing.T) {
|
t.Run("Sets prop when post has mentions and user does not have USE_CHANNEL_MENTIONS", func(t *testing.T) {
|
||||||
@@ -716,7 +716,7 @@ func TestCreatePost(t *testing.T) {
|
|||||||
}
|
}
|
||||||
rpost, err := th.App.CreatePost(postWithNoMention, th.BasicChannel, false)
|
rpost, err := th.App.CreatePost(postWithNoMention, th.BasicChannel, false)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, rpost.Props, model.StringInterface{})
|
assert.Equal(t, rpost.GetProps(), model.StringInterface{})
|
||||||
|
|
||||||
postWithMention := &model.Post{
|
postWithMention := &model.Post{
|
||||||
ChannelId: th.BasicChannel.Id,
|
ChannelId: th.BasicChannel.Id,
|
||||||
@@ -725,7 +725,7 @@ func TestCreatePost(t *testing.T) {
|
|||||||
}
|
}
|
||||||
rpost, err = th.App.CreatePost(postWithMention, th.BasicChannel, false)
|
rpost, err = th.App.CreatePost(postWithMention, th.BasicChannel, false)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, rpost.Props[model.POST_PROPS_MENTION_HIGHLIGHT_DISABLED], true)
|
assert.Equal(t, rpost.GetProp(model.POST_PROPS_MENTION_HIGHLIGHT_DISABLED), true)
|
||||||
|
|
||||||
th.AddPermissionToRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_USER_ROLE_ID)
|
th.AddPermissionToRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_USER_ROLE_ID)
|
||||||
})
|
})
|
||||||
@@ -787,13 +787,13 @@ func TestPatchPost(t *testing.T) {
|
|||||||
|
|
||||||
rpost, err = th.App.PatchPost(rpost.Id, patchWithNoMention)
|
rpost, err = th.App.PatchPost(rpost.Id, patchWithNoMention)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, rpost.Props, model.StringInterface{})
|
assert.Equal(t, rpost.GetProps(), model.StringInterface{})
|
||||||
|
|
||||||
patchWithMention := &model.PostPatch{Message: model.NewString("This patch has a mention now @here")}
|
patchWithMention := &model.PostPatch{Message: model.NewString("This patch has a mention now @here")}
|
||||||
|
|
||||||
rpost, err = th.App.PatchPost(rpost.Id, patchWithMention)
|
rpost, err = th.App.PatchPost(rpost.Id, patchWithMention)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, rpost.Props, model.StringInterface{})
|
assert.Equal(t, rpost.GetProps(), model.StringInterface{})
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("Sets prop when user does not have USE_CHANNEL_MENTIONS", func(t *testing.T) {
|
t.Run("Sets prop when user does not have USE_CHANNEL_MENTIONS", func(t *testing.T) {
|
||||||
@@ -802,13 +802,13 @@ func TestPatchPost(t *testing.T) {
|
|||||||
patchWithNoMention := &model.PostPatch{Message: model.NewString("This patch still does not have a mention")}
|
patchWithNoMention := &model.PostPatch{Message: model.NewString("This patch still does not have a mention")}
|
||||||
rpost, err = th.App.PatchPost(rpost.Id, patchWithNoMention)
|
rpost, err = th.App.PatchPost(rpost.Id, patchWithNoMention)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, rpost.Props, model.StringInterface{})
|
assert.Equal(t, rpost.GetProps(), model.StringInterface{})
|
||||||
|
|
||||||
patchWithMention := &model.PostPatch{Message: model.NewString("This patch has a mention now @here")}
|
patchWithMention := &model.PostPatch{Message: model.NewString("This patch has a mention now @here")}
|
||||||
|
|
||||||
rpost, err = th.App.PatchPost(rpost.Id, patchWithMention)
|
rpost, err = th.App.PatchPost(rpost.Id, patchWithMention)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
assert.Equal(t, rpost.Props[model.POST_PROPS_MENTION_HIGHLIGHT_DISABLED], true)
|
assert.Equal(t, rpost.GetProp(model.POST_PROPS_MENTION_HIGHLIGHT_DISABLED), true)
|
||||||
|
|
||||||
th.AddPermissionToRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_USER_ROLE_ID)
|
th.AddPermissionToRole(model.PERMISSION_USE_CHANNEL_MENTIONS.Id, model.CHANNEL_USER_ROLE_ID)
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -168,20 +168,21 @@ func SplitWebhookPost(post *model.Post, maxPostSize int) ([]*model.Post, *model.
|
|||||||
splits := make([]*model.Post, 0)
|
splits := make([]*model.Post, 0)
|
||||||
remainingText := post.Message
|
remainingText := post.Message
|
||||||
|
|
||||||
base := *post
|
base := post.Clone()
|
||||||
base.Message = ""
|
base.Message = ""
|
||||||
base.Props = make(map[string]interface{})
|
base.SetProps(make(map[string]interface{}))
|
||||||
for k, v := range post.Props {
|
for k, v := range post.GetProps() {
|
||||||
if k != "attachments" {
|
if k != "attachments" {
|
||||||
base.Props[k] = v
|
base.AddProp(k, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if utf8.RuneCountInString(model.StringInterfaceToJson(base.Props)) > model.POST_PROPS_MAX_USER_RUNES {
|
|
||||||
|
if utf8.RuneCountInString(model.StringInterfaceToJson(base.GetProps())) > model.POST_PROPS_MAX_USER_RUNES {
|
||||||
return nil, model.NewAppError("SplitWebhookPost", "web.incoming_webhook.split_props_length.app_error", map[string]interface{}{"Max": model.POST_PROPS_MAX_USER_RUNES}, "", http.StatusBadRequest)
|
return nil, model.NewAppError("SplitWebhookPost", "web.incoming_webhook.split_props_length.app_error", map[string]interface{}{"Max": model.POST_PROPS_MAX_USER_RUNES}, "", http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
for utf8.RuneCountInString(remainingText) > maxPostSize {
|
for utf8.RuneCountInString(remainingText) > maxPostSize {
|
||||||
split := base
|
split := base.Clone()
|
||||||
x := 0
|
x := 0
|
||||||
for index := range remainingText {
|
for index := range remainingText {
|
||||||
x++
|
x++
|
||||||
@@ -191,20 +192,20 @@ func SplitWebhookPost(post *model.Post, maxPostSize int) ([]*model.Post, *model.
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
splits = append(splits, &split)
|
splits = append(splits, split)
|
||||||
}
|
}
|
||||||
|
|
||||||
split := base
|
split := base.Clone()
|
||||||
split.Message = remainingText
|
split.Message = remainingText
|
||||||
splits = append(splits, &split)
|
splits = append(splits, split)
|
||||||
|
|
||||||
attachments, _ := post.Props["attachments"].([]*model.SlackAttachment)
|
attachments, _ := post.GetProp("attachments").([]*model.SlackAttachment)
|
||||||
for _, attachment := range attachments {
|
for _, attachment := range attachments {
|
||||||
newAttachment := *attachment
|
newAttachment := *attachment
|
||||||
for {
|
for {
|
||||||
lastSplit := splits[len(splits)-1]
|
lastSplit := splits[len(splits)-1]
|
||||||
newProps := make(map[string]interface{})
|
newProps := make(map[string]interface{})
|
||||||
for k, v := range lastSplit.Props {
|
for k, v := range lastSplit.GetProps() {
|
||||||
newProps[k] = v
|
newProps[k] = v
|
||||||
}
|
}
|
||||||
origAttachments, _ := newProps["attachments"].([]*model.SlackAttachment)
|
origAttachments, _ := newProps["attachments"].([]*model.SlackAttachment)
|
||||||
@@ -213,13 +214,13 @@ func SplitWebhookPost(post *model.Post, maxPostSize int) ([]*model.Post, *model.
|
|||||||
runeCount := utf8.RuneCountInString(newPropsString)
|
runeCount := utf8.RuneCountInString(newPropsString)
|
||||||
|
|
||||||
if runeCount <= model.POST_PROPS_MAX_USER_RUNES {
|
if runeCount <= model.POST_PROPS_MAX_USER_RUNES {
|
||||||
lastSplit.Props = newProps
|
lastSplit.SetProps(newProps)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(origAttachments) > 0 {
|
if len(origAttachments) > 0 {
|
||||||
newSplit := base
|
newSplit := base
|
||||||
splits = append(splits, &newSplit)
|
splits = append(splits, newSplit)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,7 +237,7 @@ func SplitWebhookPost(post *model.Post, maxPostSize int) ([]*model.Post, *model.
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
lastSplit.Props = newProps
|
lastSplit.SetProps(newProps)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -302,9 +302,9 @@ func TestCreateWebhookPost(t *testing.T) {
|
|||||||
}, model.POST_SLACK_ATTACHMENT, "")
|
}, model.POST_SLACK_ATTACHMENT, "")
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
assert.Contains(t, post.Props, "from_webhook", "missing from_webhook prop")
|
assert.Contains(t, post.GetProps(), "from_webhook", "missing from_webhook prop")
|
||||||
assert.Contains(t, post.Props, "attachments", "missing attachments prop")
|
assert.Contains(t, post.GetProps(), "attachments", "missing attachments prop")
|
||||||
assert.Contains(t, post.Props, "webhook_display_name", "missing webhook_display_name prop")
|
assert.Contains(t, post.GetProps(), "webhook_display_name", "missing webhook_display_name prop")
|
||||||
|
|
||||||
_, err = th.App.CreateWebhookPost(hook.UserId, th.BasicChannel, "foo", "user", "http://iconurl", "", nil, model.POST_SYSTEM_GENERIC, "")
|
_, err = th.App.CreateWebhookPost(hook.UserId, th.BasicChannel, "foo", "user", "http://iconurl", "", nil, model.POST_SYSTEM_GENERIC, "")
|
||||||
require.NotNil(t, err, "Should have failed - bad post type")
|
require.NotNil(t, err, "Should have failed - bad post type")
|
||||||
@@ -449,7 +449,7 @@ func TestSplitWebhookPost(t *testing.T) {
|
|||||||
for i, split := range splits {
|
for i, split := range splits {
|
||||||
if i < len(tc.Expected) {
|
if i < len(tc.Expected) {
|
||||||
assert.Equal(t, tc.Expected[i].Message, split.Message)
|
assert.Equal(t, tc.Expected[i].Message, split.Message)
|
||||||
assert.Equal(t, tc.Expected[i].Props["attachments"], split.Props["attachments"])
|
assert.Equal(t, tc.Expected[i].GetProp("attachments"), split.GetProp("attachments"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -610,17 +610,17 @@ func TestTriggerOutGoingWebhookWithUsernameAndIconURL(t *testing.T) {
|
|||||||
select {
|
select {
|
||||||
case webhookPost := <-createdPost:
|
case webhookPost := <-createdPost:
|
||||||
assert.Equal(t, webhookPost.Message, "sample response text from test server")
|
assert.Equal(t, webhookPost.Message, "sample response text from test server")
|
||||||
assert.Equal(t, webhookPost.Props["from_webhook"], "true")
|
assert.Equal(t, webhookPost.GetProp("from_webhook"), "true")
|
||||||
if testCase.ExpectedIconUrl != "" {
|
if testCase.ExpectedIconUrl != "" {
|
||||||
assert.Equal(t, webhookPost.Props["override_icon_url"], testCase.ExpectedIconUrl)
|
assert.Equal(t, webhookPost.GetProp("override_icon_url"), testCase.ExpectedIconUrl)
|
||||||
} else {
|
} else {
|
||||||
assert.Nil(t, webhookPost.Props["override_icon_url"])
|
assert.Nil(t, webhookPost.GetProp("override_icon_url"))
|
||||||
}
|
}
|
||||||
|
|
||||||
if testCase.ExpectedUsername != "" {
|
if testCase.ExpectedUsername != "" {
|
||||||
assert.Equal(t, webhookPost.Props["override_username"], testCase.ExpectedUsername)
|
assert.Equal(t, webhookPost.GetProp("override_username"), testCase.ExpectedUsername)
|
||||||
} else {
|
} else {
|
||||||
assert.Nil(t, webhookPost.Props["override_username"])
|
assert.Nil(t, webhookPost.GetProp("override_username"))
|
||||||
}
|
}
|
||||||
case <-time.After(5 * time.Second):
|
case <-time.After(5 * time.Second):
|
||||||
require.Fail(t, "Timeout, webhook response not created as post")
|
require.Fail(t, "Timeout, webhook response not created as post")
|
||||||
|
|||||||
@@ -368,8 +368,8 @@ func (r *SubmitDialogResponse) ToJson() []byte {
|
|||||||
|
|
||||||
func (o *Post) StripActionIntegrations() {
|
func (o *Post) StripActionIntegrations() {
|
||||||
attachments := o.Attachments()
|
attachments := o.Attachments()
|
||||||
if o.Props["attachments"] != nil {
|
if o.GetProp("attachments") != nil {
|
||||||
o.Props["attachments"] = attachments
|
o.AddProp("attachments", attachments)
|
||||||
}
|
}
|
||||||
for _, attachment := range attachments {
|
for _, attachment := range attachments {
|
||||||
for _, action := range attachment.Actions {
|
for _, action := range attachment.Actions {
|
||||||
@@ -390,10 +390,10 @@ func (o *Post) GetAction(id string) *PostAction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *Post) GenerateActionIds() {
|
func (o *Post) GenerateActionIds() {
|
||||||
if o.Props["attachments"] != nil {
|
if o.GetProp("attachments") != nil {
|
||||||
o.Props["attachments"] = o.Attachments()
|
o.AddProp("attachments", o.Attachments())
|
||||||
}
|
}
|
||||||
if attachments, ok := o.Props["attachments"].([]*SlackAttachment); ok {
|
if attachments, ok := o.GetProp("attachments").([]*SlackAttachment); ok {
|
||||||
for _, attachment := range attachments {
|
for _, attachment := range attachments {
|
||||||
for _, action := range attachment.Actions {
|
for _, action := range attachment.Actions {
|
||||||
if action.Id == "" {
|
if action.Id == "" {
|
||||||
@@ -411,7 +411,7 @@ func AddPostActionCookies(o *Post, secret []byte) *Post {
|
|||||||
retainProps := map[string]interface{}{}
|
retainProps := map[string]interface{}{}
|
||||||
removeProps := []string{}
|
removeProps := []string{}
|
||||||
for _, key := range PostActionRetainPropKeys {
|
for _, key := range PostActionRetainPropKeys {
|
||||||
value, ok := p.Props[key]
|
value, ok := p.GetProps()[key]
|
||||||
if ok {
|
if ok {
|
||||||
retainProps[key] = value
|
retainProps[key] = value
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
106
model/post.go
106
model/post.go
@@ -5,11 +5,13 @@ package model
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
"io"
|
"io"
|
||||||
"net/http"
|
"net/http"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"unicode/utf8"
|
"unicode/utf8"
|
||||||
|
|
||||||
"github.com/mattermost/mattermost-server/v5/utils/markdown"
|
"github.com/mattermost/mattermost-server/v5/utils/markdown"
|
||||||
@@ -83,7 +85,8 @@ type Post struct {
|
|||||||
MessageSource string `json:"message_source,omitempty" db:"-"`
|
MessageSource string `json:"message_source,omitempty" db:"-"`
|
||||||
|
|
||||||
Type string `json:"type"`
|
Type string `json:"type"`
|
||||||
Props StringInterface `json:"props"`
|
propsMu sync.RWMutex `db:"-"` // Unexported mutex used to guard Post.Props.
|
||||||
|
Props StringInterface `json:"props"` // Deprecated: use GetProps()
|
||||||
Hashtags string `json:"hashtags"`
|
Hashtags string `json:"hashtags"`
|
||||||
Filenames StringArray `json:"filenames,omitempty"` // Deprecated, do not use this field any more
|
Filenames StringArray `json:"filenames,omitempty"` // Deprecated, do not use this field any more
|
||||||
FileIds StringArray `json:"file_ids,omitempty"`
|
FileIds StringArray `json:"file_ids,omitempty"`
|
||||||
@@ -156,10 +159,46 @@ type PostForIndexing struct {
|
|||||||
ParentCreateAt *int64 `json:"parent_create_at"`
|
ParentCreateAt *int64 `json:"parent_create_at"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clone shallowly copies the post.
|
// ShallowCopy is an utility function to shallow copy a Post to the given
|
||||||
|
// destination without touching the internal RWMutex.
|
||||||
|
func (o *Post) ShallowCopy(dst *Post) error {
|
||||||
|
if dst == nil {
|
||||||
|
return errors.New("dst cannot be nil")
|
||||||
|
}
|
||||||
|
o.propsMu.RLock()
|
||||||
|
defer o.propsMu.RUnlock()
|
||||||
|
dst.propsMu.Lock()
|
||||||
|
defer dst.propsMu.Unlock()
|
||||||
|
dst.Id = o.Id
|
||||||
|
dst.CreateAt = o.CreateAt
|
||||||
|
dst.UpdateAt = o.UpdateAt
|
||||||
|
dst.EditAt = o.EditAt
|
||||||
|
dst.DeleteAt = o.DeleteAt
|
||||||
|
dst.IsPinned = o.IsPinned
|
||||||
|
dst.UserId = o.UserId
|
||||||
|
dst.ChannelId = o.ChannelId
|
||||||
|
dst.RootId = o.RootId
|
||||||
|
dst.ParentId = o.ParentId
|
||||||
|
dst.OriginalId = o.OriginalId
|
||||||
|
dst.Message = o.Message
|
||||||
|
dst.MessageSource = o.MessageSource
|
||||||
|
dst.Type = o.Type
|
||||||
|
dst.Props = o.Props
|
||||||
|
dst.Hashtags = o.Hashtags
|
||||||
|
dst.Filenames = o.Filenames
|
||||||
|
dst.FileIds = o.FileIds
|
||||||
|
dst.PendingPostId = o.PendingPostId
|
||||||
|
dst.HasReactions = o.HasReactions
|
||||||
|
dst.ReplyCount = o.ReplyCount
|
||||||
|
dst.Metadata = o.Metadata
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clone shallowly copies the post and returns the copy.
|
||||||
func (o *Post) Clone() *Post {
|
func (o *Post) Clone() *Post {
|
||||||
copy := *o
|
copy := &Post{}
|
||||||
return ©
|
o.ShallowCopy(copy)
|
||||||
|
return copy
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Post) ToJson() string {
|
func (o *Post) ToJson() string {
|
||||||
@@ -199,7 +238,6 @@ func (o *Post) Etag() string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *Post) IsValid(maxPostSize int) *AppError {
|
func (o *Post) IsValid(maxPostSize int) *AppError {
|
||||||
|
|
||||||
if len(o.Id) != 26 {
|
if len(o.Id) != 26 {
|
||||||
return NewAppError("Post.IsValid", "model.post.is_valid.id.app_error", nil, "", http.StatusBadRequest)
|
return NewAppError("Post.IsValid", "model.post.is_valid.id.app_error", nil, "", http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
@@ -286,7 +324,7 @@ func (o *Post) IsValid(maxPostSize int) *AppError {
|
|||||||
return NewAppError("Post.IsValid", "model.post.is_valid.file_ids.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
return NewAppError("Post.IsValid", "model.post.is_valid.file_ids.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
if utf8.RuneCountInString(StringInterfaceToJson(o.Props)) > POST_PROPS_MAX_RUNES {
|
if utf8.RuneCountInString(StringInterfaceToJson(o.GetProps())) > POST_PROPS_MAX_RUNES {
|
||||||
return NewAppError("Post.IsValid", "model.post.is_valid.props.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
return NewAppError("Post.IsValid", "model.post.is_valid.props.app_error", nil, "id="+o.Id, http.StatusBadRequest)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,8 +337,8 @@ func (o *Post) SanitizeProps() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, member := range membersToSanitize {
|
for _, member := range membersToSanitize {
|
||||||
if _, ok := o.Props[member]; ok {
|
if _, ok := o.GetProps()[member]; ok {
|
||||||
delete(o.Props, member)
|
o.DelProp(member)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -321,8 +359,8 @@ func (o *Post) PreSave() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *Post) PreCommit() {
|
func (o *Post) PreCommit() {
|
||||||
if o.Props == nil {
|
if o.GetProps() == nil {
|
||||||
o.Props = make(map[string]interface{})
|
o.SetProps(make(map[string]interface{}))
|
||||||
}
|
}
|
||||||
|
|
||||||
if o.Filenames == nil {
|
if o.Filenames == nil {
|
||||||
@@ -340,16 +378,49 @@ func (o *Post) PreCommit() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *Post) MakeNonNil() {
|
func (o *Post) MakeNonNil() {
|
||||||
if o.Props == nil {
|
if o.GetProps() == nil {
|
||||||
o.Props = make(map[string]interface{})
|
o.SetProps(make(map[string]interface{}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (o *Post) DelProp(key string) {
|
||||||
|
o.propsMu.Lock()
|
||||||
|
defer o.propsMu.Unlock()
|
||||||
|
propsCopy := make(map[string]interface{}, len(o.Props)-1)
|
||||||
|
for k, v := range o.Props {
|
||||||
|
propsCopy[k] = v
|
||||||
|
}
|
||||||
|
delete(propsCopy, key)
|
||||||
|
o.Props = propsCopy
|
||||||
|
}
|
||||||
|
|
||||||
func (o *Post) AddProp(key string, value interface{}) {
|
func (o *Post) AddProp(key string, value interface{}) {
|
||||||
|
o.propsMu.Lock()
|
||||||
|
defer o.propsMu.Unlock()
|
||||||
|
propsCopy := make(map[string]interface{}, len(o.Props)+1)
|
||||||
|
for k, v := range o.Props {
|
||||||
|
propsCopy[k] = v
|
||||||
|
}
|
||||||
|
propsCopy[key] = value
|
||||||
|
o.Props = propsCopy
|
||||||
|
}
|
||||||
|
|
||||||
o.MakeNonNil()
|
func (o *Post) GetProps() StringInterface {
|
||||||
|
o.propsMu.RLock()
|
||||||
|
defer o.propsMu.RUnlock()
|
||||||
|
return o.Props
|
||||||
|
}
|
||||||
|
|
||||||
o.Props[key] = value
|
func (o *Post) SetProps(props StringInterface) {
|
||||||
|
o.propsMu.Lock()
|
||||||
|
defer o.propsMu.Unlock()
|
||||||
|
o.Props = props
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *Post) GetProp(key string) interface{} {
|
||||||
|
o.propsMu.RLock()
|
||||||
|
defer o.propsMu.RUnlock()
|
||||||
|
return o.Props[key]
|
||||||
}
|
}
|
||||||
|
|
||||||
func (o *Post) IsSystemMessage() bool {
|
func (o *Post) IsSystemMessage() bool {
|
||||||
@@ -379,7 +450,8 @@ func (o *Post) Patch(patch *PostPatch) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if patch.Props != nil {
|
if patch.Props != nil {
|
||||||
o.Props = *patch.Props
|
newProps := *patch.Props
|
||||||
|
o.SetProps(newProps)
|
||||||
}
|
}
|
||||||
|
|
||||||
if patch.FileIds != nil {
|
if patch.FileIds != nil {
|
||||||
@@ -464,11 +536,11 @@ func findAtChannelMention(message string) (mention string, found bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (o *Post) Attachments() []*SlackAttachment {
|
func (o *Post) Attachments() []*SlackAttachment {
|
||||||
if attachments, ok := o.Props["attachments"].([]*SlackAttachment); ok {
|
if attachments, ok := o.GetProp("attachments").([]*SlackAttachment); ok {
|
||||||
return attachments
|
return attachments
|
||||||
}
|
}
|
||||||
var ret []*SlackAttachment
|
var ret []*SlackAttachment
|
||||||
if attachments, ok := o.Props["attachments"].([]interface{}); ok {
|
if attachments, ok := o.GetProp("attachments").([]interface{}); ok {
|
||||||
for _, attachment := range attachments {
|
for _, attachment := range attachments {
|
||||||
if enc, err := json.Marshal(attachment); err == nil {
|
if enc, err := json.Marshal(attachment); err == nil {
|
||||||
var decoded SlackAttachment
|
var decoded SlackAttachment
|
||||||
|
|||||||
@@ -46,9 +46,9 @@ func (o *PostList) StripActionIntegrations() {
|
|||||||
posts := o.Posts
|
posts := o.Posts
|
||||||
o.Posts = make(map[string]*Post)
|
o.Posts = make(map[string]*Post)
|
||||||
for id, post := range posts {
|
for id, post := range posts {
|
||||||
pcopy := *post
|
pcopy := post.Clone()
|
||||||
pcopy.StripActionIntegrations()
|
pcopy.StripActionIntegrations()
|
||||||
o.Posts[id] = &pcopy
|
o.Posts[id] = pcopy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ package model
|
|||||||
import (
|
import (
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"strings"
|
"strings"
|
||||||
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -18,7 +19,7 @@ func TestPostToJson(t *testing.T) {
|
|||||||
ro := PostFromJson(strings.NewReader(j))
|
ro := PostFromJson(strings.NewReader(j))
|
||||||
|
|
||||||
assert.NotNil(t, ro)
|
assert.NotNil(t, ro)
|
||||||
assert.Equal(t, o, *ro)
|
assert.Equal(t, &o, ro.Clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPostFromJsonError(t *testing.T) {
|
func TestPostFromJsonError(t *testing.T) {
|
||||||
@@ -124,7 +125,7 @@ func TestPostSanitizeProps(t *testing.T) {
|
|||||||
|
|
||||||
post1.SanitizeProps()
|
post1.SanitizeProps()
|
||||||
|
|
||||||
require.Nil(t, post1.Props[PROPS_ADD_CHANNEL_MEMBER])
|
require.Nil(t, post1.GetProp(PROPS_ADD_CHANNEL_MEMBER))
|
||||||
|
|
||||||
post2 := &Post{
|
post2 := &Post{
|
||||||
Message: "test",
|
Message: "test",
|
||||||
@@ -135,7 +136,7 @@ func TestPostSanitizeProps(t *testing.T) {
|
|||||||
|
|
||||||
post2.SanitizeProps()
|
post2.SanitizeProps()
|
||||||
|
|
||||||
require.Nil(t, post2.Props[PROPS_ADD_CHANNEL_MEMBER])
|
require.Nil(t, post2.GetProp(PROPS_ADD_CHANNEL_MEMBER))
|
||||||
|
|
||||||
post3 := &Post{
|
post3 := &Post{
|
||||||
Message: "test",
|
Message: "test",
|
||||||
@@ -147,9 +148,9 @@ func TestPostSanitizeProps(t *testing.T) {
|
|||||||
|
|
||||||
post3.SanitizeProps()
|
post3.SanitizeProps()
|
||||||
|
|
||||||
require.Nil(t, post3.Props[PROPS_ADD_CHANNEL_MEMBER])
|
require.Nil(t, post3.GetProp(PROPS_ADD_CHANNEL_MEMBER))
|
||||||
|
|
||||||
require.NotNil(t, post3.Props["attachments"])
|
require.NotNil(t, post3.GetProp("attachments"))
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestPost_AttachmentsEqual(t *testing.T) {
|
func TestPost_AttachmentsEqual(t *testing.T) {
|
||||||
@@ -502,6 +503,182 @@ func BenchmarkRewriteImageURLs(b *testing.B) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPostShallowCopy(t *testing.T) {
|
||||||
|
var dst *Post
|
||||||
|
p := &Post{
|
||||||
|
Id: NewId(),
|
||||||
|
}
|
||||||
|
|
||||||
|
err := p.ShallowCopy(dst)
|
||||||
|
require.Error(t, err)
|
||||||
|
|
||||||
|
dst = &Post{}
|
||||||
|
err = p.ShallowCopy(dst)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Equal(t, p, dst)
|
||||||
|
require.Condition(t, func() bool {
|
||||||
|
return p != dst
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestPostClone(t *testing.T) {
|
||||||
|
p := &Post{
|
||||||
|
Id: NewId(),
|
||||||
|
}
|
||||||
|
|
||||||
|
pp := p.Clone()
|
||||||
|
require.Equal(t, p, pp)
|
||||||
|
require.Condition(t, func() bool {
|
||||||
|
return p != pp
|
||||||
|
})
|
||||||
|
require.Condition(t, func() bool {
|
||||||
|
return &p.propsMu != &pp.propsMu
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkClonePost(b *testing.B) {
|
||||||
|
p := Post{}
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = p.Clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPostPropsGet_indirect(b *testing.B) {
|
||||||
|
p := Post{
|
||||||
|
Props: make(StringInterface),
|
||||||
|
}
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = p.GetProps()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPostPropsGet_direct(b *testing.B) {
|
||||||
|
p := Post{
|
||||||
|
Props: make(StringInterface),
|
||||||
|
}
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = p.Props
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPostPropsAdd_indirect(b *testing.B) {
|
||||||
|
p := Post{
|
||||||
|
Props: make(StringInterface),
|
||||||
|
}
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
p.AddProp("test", "somevalue")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPostPropsAdd_direct(b *testing.B) {
|
||||||
|
p := Post{
|
||||||
|
Props: make(StringInterface),
|
||||||
|
}
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
p.Props["test"] = "somevalue"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPostPropsDel_indirect(b *testing.B) {
|
||||||
|
p := Post{
|
||||||
|
Props: make(StringInterface),
|
||||||
|
}
|
||||||
|
p.AddProp("test", "somevalue")
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
p.DelProp("test")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPostPropsDel_direct(b *testing.B) {
|
||||||
|
p := Post{
|
||||||
|
Props: make(StringInterface),
|
||||||
|
}
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
delete(p.Props, "test")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPostPropGet_direct(b *testing.B) {
|
||||||
|
p := Post{
|
||||||
|
Props: make(StringInterface),
|
||||||
|
}
|
||||||
|
p.Props["somekey"] = "somevalue"
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = p.Props["somekey"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPostPropGet_indirect(b *testing.B) {
|
||||||
|
p := Post{
|
||||||
|
Props: make(StringInterface),
|
||||||
|
}
|
||||||
|
p.Props["somekey"] = "somevalue"
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
_ = p.GetProp("somekey")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// TestPostPropsDataRace tries to trigger data race conditions related to Post.Props.
|
||||||
|
// It's meant to be run with the -race flag.
|
||||||
|
func TestPostPropsDataRace(t *testing.T) {
|
||||||
|
p := Post{Message: "test"}
|
||||||
|
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(7)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
p.AddProp("test", "test")
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
_ = p.GetProp("test")
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
p.AddProp("test", "test2")
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
_ = p.GetProps()["test"]
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
p.DelProp("test")
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
p.SetProps(make(StringInterface))
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
_ = p.Clone()
|
||||||
|
}
|
||||||
|
wg.Done()
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
func Test_findAtChannelMention(t *testing.T) {
|
func Test_findAtChannelMention(t *testing.T) {
|
||||||
testCases := []struct {
|
testCases := []struct {
|
||||||
Name string
|
Name string
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ func (p *HelpPlugin) MessageHasBeenPosted(c *plugin.Context, post *model.Post) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Ignore posts this plugin made.
|
// Ignore posts this plugin made.
|
||||||
if sentByPlugin, _ := post.Props["sent_by_plugin"].(bool); sentByPlugin {
|
if sentByPlugin, _ := post.GetProp("sent_by_plugin").(bool); sentByPlugin {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -148,7 +148,7 @@ func (p *HelpersImpl) ShouldProcessMessage(post *model.Post, options ...ShouldPr
|
|||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if !messageProcessOptions.AllowWebhook && post.Props["from_webhook"] == "true" {
|
if !messageProcessOptions.AllowWebhook && post.GetProp("from_webhook") == "true" {
|
||||||
return false, nil
|
return false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -433,9 +433,9 @@ func (s *SqlPostStore) Delete(postId string, time int64, deleteByID string) *mod
|
|||||||
return appErr(err.Error())
|
return appErr(err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
post.Props[model.POST_PROPS_DELETE_BY] = deleteByID
|
post.AddProp(model.POST_PROPS_DELETE_BY, deleteByID)
|
||||||
|
|
||||||
_, err = s.GetMaster().Exec("UPDATE Posts SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt, Props = :Props WHERE Id = :Id OR RootId = :RootId", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": postId, "RootId": postId, "Props": model.StringInterfaceToJson(post.Props)})
|
_, err = s.GetMaster().Exec("UPDATE Posts SET DeleteAt = :DeleteAt, UpdateAt = :UpdateAt, Props = :Props WHERE Id = :Id OR RootId = :RootId", map[string]interface{}{"DeleteAt": time, "UpdateAt": time, "Id": postId, "RootId": postId, "Props": model.StringInterfaceToJson(post.GetProps())})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return appErr(err.Error())
|
return appErr(err.Error())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -733,7 +733,7 @@ func testEditExportMessage(t *testing.T, ss store.Store) {
|
|||||||
|
|
||||||
//user 1 edits the previous post
|
//user 1 edits the previous post
|
||||||
post1e := &model.Post{}
|
post1e := &model.Post{}
|
||||||
*post1e = *post1
|
post1e = post1.Clone()
|
||||||
post1e.Message = "edit " + post1.Message
|
post1e.Message = "edit " + post1.Message
|
||||||
|
|
||||||
post1e, err = ss.Post().Update(post1e, post1)
|
post1e, err = ss.Post().Update(post1e, post1)
|
||||||
@@ -845,7 +845,7 @@ func testEditAfterExportMessage(t *testing.T, ss store.Store) {
|
|||||||
postEditTime := post1.UpdateAt + 1
|
postEditTime := post1.UpdateAt + 1
|
||||||
//user 1 edits the previous post
|
//user 1 edits the previous post
|
||||||
post1e := &model.Post{}
|
post1e := &model.Post{}
|
||||||
*post1e = *post1
|
post1e = post1.Clone()
|
||||||
post1e.EditAt = postEditTime
|
post1e.EditAt = postEditTime
|
||||||
post1e.Message = "edit " + post1.Message
|
post1e.Message = "edit " + post1.Message
|
||||||
post1e, err = ss.Post().Update(post1e, post1)
|
post1e, err = ss.Post().Update(post1e, post1)
|
||||||
|
|||||||
@@ -259,16 +259,16 @@ func testFileInfoGetForUser(t *testing.T, ss store.Store) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func testFileInfoGetWithOptions(t *testing.T, ss store.Store) {
|
func testFileInfoGetWithOptions(t *testing.T, ss store.Store) {
|
||||||
makePost := func(chId string, user string) model.Post {
|
makePost := func(chId string, user string) *model.Post {
|
||||||
post := model.Post{}
|
post := model.Post{}
|
||||||
post.ChannelId = chId
|
post.ChannelId = chId
|
||||||
post.UserId = user
|
post.UserId = user
|
||||||
_, err := ss.Post().Save(&post)
|
_, err := ss.Post().Save(&post)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
return post
|
return &post
|
||||||
}
|
}
|
||||||
|
|
||||||
makeFile := func(post model.Post, user string, createAt int64, idPrefix string) model.FileInfo {
|
makeFile := func(post *model.Post, user string, createAt int64, idPrefix string) model.FileInfo {
|
||||||
id := model.NewId()
|
id := model.NewId()
|
||||||
id = idPrefix + id[1:] // hacky way to get sortable Ids to confirm secondary Id sort works
|
id = idPrefix + id[1:] // hacky way to get sortable Ids to confirm secondary Id sort works
|
||||||
fileInfo := model.FileInfo{
|
fileInfo := model.FileInfo{
|
||||||
@@ -300,7 +300,7 @@ func testFileInfoGetWithOptions(t *testing.T, ss store.Store) {
|
|||||||
epoch := time.Date(2020, 1, 1, 1, 1, 1, 1, time.UTC)
|
epoch := time.Date(2020, 1, 1, 1, 1, 1, 1, time.UTC)
|
||||||
file1_1 := makeFile(post1_1, userId1, epoch.AddDate(0, 0, 1).Unix(), "a") // file 1 by user 1
|
file1_1 := makeFile(post1_1, userId1, epoch.AddDate(0, 0, 1).Unix(), "a") // file 1 by user 1
|
||||||
file1_2 := makeFile(post1_2, userId1, epoch.AddDate(0, 0, 2).Unix(), "b") // file 2 by user 1
|
file1_2 := makeFile(post1_2, userId1, epoch.AddDate(0, 0, 2).Unix(), "b") // file 2 by user 1
|
||||||
file1_3 := makeFile(model.Post{}, userId1, epoch.AddDate(0, 0, 3).Unix(), "c") // file that is not attached to a post
|
file1_3 := makeFile(&model.Post{}, userId1, epoch.AddDate(0, 0, 3).Unix(), "c") // file that is not attached to a post
|
||||||
file2_1 := makeFile(post2_1, userId2, epoch.AddDate(0, 0, 4).Unix(), "d") // file 2 by user 1
|
file2_1 := makeFile(post2_1, userId2, epoch.AddDate(0, 0, 4).Unix(), "d") // file 2 by user 1
|
||||||
file2_2 := makeFile(post2_2, userId2, epoch.AddDate(0, 0, 5).Unix(), "e")
|
file2_2 := makeFile(post2_2, userId2, epoch.AddDate(0, 0, 5).Unix(), "e")
|
||||||
|
|
||||||
|
|||||||
@@ -88,6 +88,8 @@ func testPostStoreSave(t *testing.T, ss store.Store) {
|
|||||||
_, err := ss.Post().Save(&rootPost)
|
_, err := ss.Post().Save(&rootPost)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
|
time.Sleep(2 * time.Millisecond)
|
||||||
|
|
||||||
replyPost := model.Post{}
|
replyPost := model.Post{}
|
||||||
replyPost.ChannelId = rootPost.ChannelId
|
replyPost.ChannelId = rootPost.ChannelId
|
||||||
replyPost.UserId = model.NewId()
|
replyPost.UserId = model.NewId()
|
||||||
@@ -410,8 +412,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
|
|||||||
|
|
||||||
require.Equal(t, ro1.Message, o1.Message, "Failed to save/get")
|
require.Equal(t, ro1.Message, o1.Message, "Failed to save/get")
|
||||||
|
|
||||||
o1a := &model.Post{}
|
o1a := ro1.Clone()
|
||||||
*o1a = *ro1
|
|
||||||
o1a.Message = ro1.Message + "BBBBBBBBBB"
|
o1a.Message = ro1.Message + "BBBBBBBBBB"
|
||||||
_, err = ss.Post().Update(o1a, ro1)
|
_, err = ss.Post().Update(o1a, ro1)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
@@ -422,8 +423,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
|
|||||||
ro1a := r1.Posts[o1.Id]
|
ro1a := r1.Posts[o1.Id]
|
||||||
require.Equal(t, ro1a.Message, o1a.Message, "Failed to update/get")
|
require.Equal(t, ro1a.Message, o1a.Message, "Failed to update/get")
|
||||||
|
|
||||||
o2a := &model.Post{}
|
o2a := ro2.Clone()
|
||||||
*o2a = *ro2
|
|
||||||
o2a.Message = ro2.Message + "DDDDDDD"
|
o2a.Message = ro2.Message + "DDDDDDD"
|
||||||
_, err = ss.Post().Update(o2a, ro2)
|
_, err = ss.Post().Update(o2a, ro2)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
@@ -434,8 +434,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
|
|||||||
|
|
||||||
require.Equal(t, ro2a.Message, o2a.Message, "Failed to update/get")
|
require.Equal(t, ro2a.Message, o2a.Message, "Failed to update/get")
|
||||||
|
|
||||||
o3a := &model.Post{}
|
o3a := ro3.Clone()
|
||||||
*o3a = *ro3
|
|
||||||
o3a.Message = ro3.Message + "WWWWWWW"
|
o3a.Message = ro3.Message + "WWWWWWW"
|
||||||
_, err = ss.Post().Update(o3a, ro3)
|
_, err = ss.Post().Update(o3a, ro3)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
@@ -460,8 +459,7 @@ func testPostStoreUpdate(t *testing.T, ss store.Store) {
|
|||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
ro4 := r4.Posts[o4.Id]
|
ro4 := r4.Posts[o4.Id]
|
||||||
|
|
||||||
o4a := &model.Post{}
|
o4a := ro4.Clone()
|
||||||
*o4a = *ro4
|
|
||||||
o4a.Filenames = []string{}
|
o4a.Filenames = []string{}
|
||||||
o4a.FileIds = []string{model.NewId()}
|
o4a.FileIds = []string{model.NewId()}
|
||||||
_, err = ss.Post().Update(o4a, ro4)
|
_, err = ss.Post().Update(o4a, ro4)
|
||||||
@@ -497,7 +495,7 @@ func testPostStoreDelete(t *testing.T, ss store.Store) {
|
|||||||
|
|
||||||
posts, _ := ss.Post().GetPostsCreatedAt(o1.ChannelId, o1.CreateAt)
|
posts, _ := ss.Post().GetPostsCreatedAt(o1.ChannelId, o1.CreateAt)
|
||||||
post := posts[0]
|
post := posts[0]
|
||||||
actual := post.Props[model.POST_PROPS_DELETE_BY]
|
actual := post.GetProp(model.POST_PROPS_DELETE_BY)
|
||||||
|
|
||||||
assert.Equal(t, deleteByID, actual, "Expected (*Post).Props[model.POST_PROPS_DELETE_BY] to be %v but got %v.", deleteByID, actual)
|
assert.Equal(t, deleteByID, actual, "Expected (*Post).Props[model.POST_PROPS_DELETE_BY] to be %v but got %v.", deleteByID, actual)
|
||||||
|
|
||||||
@@ -2291,16 +2289,13 @@ func testPostStoreOverwriteMultiple(t *testing.T, ss store.Store) {
|
|||||||
require.Equal(t, ro5.Filenames, o5.Filenames, "Failed to save/get")
|
require.Equal(t, ro5.Filenames, o5.Filenames, "Failed to save/get")
|
||||||
|
|
||||||
t.Run("overwrite changing message", func(t *testing.T) {
|
t.Run("overwrite changing message", func(t *testing.T) {
|
||||||
o1a := &model.Post{}
|
o1a := ro1.Clone()
|
||||||
*o1a = *ro1
|
|
||||||
o1a.Message = ro1.Message + "BBBBBBBBBB"
|
o1a.Message = ro1.Message + "BBBBBBBBBB"
|
||||||
|
|
||||||
o2a := &model.Post{}
|
o2a := ro2.Clone()
|
||||||
*o2a = *ro2
|
|
||||||
o2a.Message = ro2.Message + "DDDDDDD"
|
o2a.Message = ro2.Message + "DDDDDDD"
|
||||||
|
|
||||||
o3a := &model.Post{}
|
o3a := ro3.Clone()
|
||||||
*o3a = *ro3
|
|
||||||
o3a.Message = ro3.Message + "WWWWWWW"
|
o3a.Message = ro3.Message + "WWWWWWW"
|
||||||
|
|
||||||
_, err = ss.Post().OverwriteMultiple([]*model.Post{o1a, o2a, o3a})
|
_, err = ss.Post().OverwriteMultiple([]*model.Post{o1a, o2a, o3a})
|
||||||
@@ -2324,13 +2319,11 @@ func testPostStoreOverwriteMultiple(t *testing.T, ss store.Store) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("overwrite clearing filenames", func(t *testing.T) {
|
t.Run("overwrite clearing filenames", func(t *testing.T) {
|
||||||
o4a := &model.Post{}
|
o4a := ro4.Clone()
|
||||||
*o4a = *ro4
|
|
||||||
o4a.Filenames = []string{}
|
o4a.Filenames = []string{}
|
||||||
o4a.FileIds = []string{model.NewId()}
|
o4a.FileIds = []string{model.NewId()}
|
||||||
|
|
||||||
o5a := &model.Post{}
|
o5a := ro5.Clone()
|
||||||
*o5a = *ro5
|
|
||||||
o5a.Filenames = []string{}
|
o5a.Filenames = []string{}
|
||||||
o5a.FileIds = []string{}
|
o5a.FileIds = []string{}
|
||||||
|
|
||||||
@@ -2406,20 +2399,17 @@ func testPostStoreOverwrite(t *testing.T, ss store.Store) {
|
|||||||
require.Equal(t, ro4.Message, o4.Message, "Failed to save/get")
|
require.Equal(t, ro4.Message, o4.Message, "Failed to save/get")
|
||||||
|
|
||||||
t.Run("overwrite changing message", func(t *testing.T) {
|
t.Run("overwrite changing message", func(t *testing.T) {
|
||||||
o1a := &model.Post{}
|
o1a := ro1.Clone()
|
||||||
*o1a = *ro1
|
|
||||||
o1a.Message = ro1.Message + "BBBBBBBBBB"
|
o1a.Message = ro1.Message + "BBBBBBBBBB"
|
||||||
_, err = ss.Post().Overwrite(o1a)
|
_, err = ss.Post().Overwrite(o1a)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
o2a := &model.Post{}
|
o2a := ro2.Clone()
|
||||||
*o2a = *ro2
|
|
||||||
o2a.Message = ro2.Message + "DDDDDDD"
|
o2a.Message = ro2.Message + "DDDDDDD"
|
||||||
_, err = ss.Post().Overwrite(o2a)
|
_, err = ss.Post().Overwrite(o2a)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
o3a := &model.Post{}
|
o3a := ro3.Clone()
|
||||||
*o3a = *ro3
|
|
||||||
o3a.Message = ro3.Message + "WWWWWWW"
|
o3a.Message = ro3.Message + "WWWWWWW"
|
||||||
_, err = ss.Post().Overwrite(o3a)
|
_, err = ss.Post().Overwrite(o3a)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
@@ -2442,8 +2432,7 @@ func testPostStoreOverwrite(t *testing.T, ss store.Store) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("overwrite clearing filenames", func(t *testing.T) {
|
t.Run("overwrite clearing filenames", func(t *testing.T) {
|
||||||
o4a := &model.Post{}
|
o4a := ro4.Clone()
|
||||||
*o4a = *ro4
|
|
||||||
o4a.Filenames = []string{}
|
o4a.Filenames = []string{}
|
||||||
o4a.FileIds = []string{model.NewId()}
|
o4a.FileIds = []string{model.NewId()}
|
||||||
_, err = ss.Post().Overwrite(o4a)
|
_, err = ss.Post().Overwrite(o4a)
|
||||||
@@ -2863,8 +2852,7 @@ func testPostStoreGetDirectPostParentsForExportAfterDeleted(t *testing.T, ss sto
|
|||||||
p1, err = ss.Post().Save(p1)
|
p1, err = ss.Post().Save(p1)
|
||||||
require.Nil(t, err)
|
require.Nil(t, err)
|
||||||
|
|
||||||
o1a := &model.Post{}
|
o1a := p1.Clone()
|
||||||
*o1a = *p1
|
|
||||||
o1a.DeleteAt = 1
|
o1a.DeleteAt = 1
|
||||||
o1a.Message = p1.Message + "BBBBBBBBBB"
|
o1a.Message = p1.Message + "BBBBBBBBBB"
|
||||||
_, err = ss.Post().Update(o1a, p1)
|
_, err = ss.Post().Update(o1a, p1)
|
||||||
|
|||||||
Ссылка в новой задаче
Block a user