diff options
Diffstat (limited to 'api4')
-rw-r--r-- | api4/reaction.go | 12 | ||||
-rw-r--r-- | api4/reaction_test.go | 464 |
2 files changed, 292 insertions, 184 deletions
diff --git a/api4/reaction.go b/api4/reaction.go index af637bf91..337b49751 100644 --- a/api4/reaction.go +++ b/api4/reaction.go @@ -32,8 +32,8 @@ func saveReaction(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionToChannelByPost(c.Session, reaction.PostId, model.PERMISSION_READ_CHANNEL) { - c.SetPermissionError(model.PERMISSION_READ_CHANNEL) + if !c.App.SessionHasPermissionToChannelByPost(c.Session, reaction.PostId, model.PERMISSION_ADD_REACTION) { + c.SetPermissionError(model.PERMISSION_ADD_REACTION) return } @@ -82,13 +82,13 @@ func deleteReaction(c *Context, w http.ResponseWriter, r *http.Request) { return } - if !c.App.SessionHasPermissionToChannelByPost(c.Session, c.Params.PostId, model.PERMISSION_READ_CHANNEL) { - c.SetPermissionError(model.PERMISSION_READ_CHANNEL) + if !c.App.SessionHasPermissionToChannelByPost(c.Session, c.Params.PostId, model.PERMISSION_REMOVE_REACTION) { + c.SetPermissionError(model.PERMISSION_REMOVE_REACTION) return } - if c.Params.UserId != c.Session.UserId && !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_MANAGE_SYSTEM) { - c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) + if c.Params.UserId != c.Session.UserId && !c.App.SessionHasPermissionTo(c.Session, model.PERMISSION_REMOVE_OTHERS_REACTIONS) { + c.SetPermissionError(model.PERMISSION_REMOVE_OTHERS_REACTIONS) return } diff --git a/api4/reaction_test.go b/api4/reaction_test.go index 93cd754c9..ac1a49671 100644 --- a/api4/reaction_test.go +++ b/api4/reaction_test.go @@ -19,116 +19,159 @@ func TestSaveReaction(t *testing.T) { userId := th.BasicUser.Id postId := th.BasicPost.Id + // Check the appropriate permissions are enforced. + defaultRolePermissions := th.SaveDefaultRolePermissions() + defer func() { + th.RestoreDefaultRolePermissions(defaultRolePermissions) + }() + reaction := &model.Reaction{ UserId: userId, PostId: postId, EmojiName: "smile", } - rr, resp := Client.SaveReaction(reaction) - CheckNoError(t, resp) + t.Run("successful-reaction", func(t *testing.T) { + rr, resp := Client.SaveReaction(reaction) + CheckNoError(t, resp) - if rr.UserId != reaction.UserId { - t.Fatal("UserId did not match") - } + if rr.UserId != reaction.UserId { + t.Fatal("UserId did not match") + } - if rr.PostId != reaction.PostId { - t.Fatal("PostId did not match") - } + if rr.PostId != reaction.PostId { + t.Fatal("PostId did not match") + } - if rr.EmojiName != reaction.EmojiName { - t.Fatal("EmojiName did not match") - } + if rr.EmojiName != reaction.EmojiName { + t.Fatal("EmojiName did not match") + } - if rr.CreateAt == 0 { - t.Fatal("CreateAt should exist") - } + if rr.CreateAt == 0 { + t.Fatal("CreateAt should exist") + } - if reactions, err := th.App.GetReactionsForPost(postId); err != nil && len(reactions) != 1 { - t.Fatal("didn't save reaction correctly") - } + if reactions, err := th.App.GetReactionsForPost(postId); err != nil && len(reactions) != 1 { + t.Fatal("didn't save reaction correctly") + } + }) - // saving a duplicate reaction - rr, resp = Client.SaveReaction(reaction) - CheckNoError(t, resp) + t.Run("duplicated-reaction", func(t *testing.T) { + _, resp := Client.SaveReaction(reaction) + CheckNoError(t, resp) - if reactions, err := th.App.GetReactionsForPost(postId); err != nil && len(reactions) != 1 { - t.Fatal("should have not save duplicated reaction") - } + if reactions, err := th.App.GetReactionsForPost(postId); err != nil && len(reactions) != 1 { + t.Fatal("should have not save duplicated reaction") + } + }) - reaction.EmojiName = "sad" + t.Run("save-second-reaction", func(t *testing.T) { + reaction.EmojiName = "sad" - rr, resp = Client.SaveReaction(reaction) - CheckNoError(t, resp) + rr, resp := Client.SaveReaction(reaction) + CheckNoError(t, resp) - if rr.EmojiName != reaction.EmojiName { - t.Fatal("EmojiName did not match") - } + if rr.EmojiName != reaction.EmojiName { + t.Fatal("EmojiName did not match") + } - if reactions, err := th.App.GetReactionsForPost(postId); err != nil && len(reactions) != 2 { - t.Fatal("should have save multiple reactions") - } + if reactions, err := th.App.GetReactionsForPost(postId); err != nil && len(reactions) != 2 { + t.Fatal("should have save multiple reactions") + } + }) - // saving special case - reaction.EmojiName = "+1" + t.Run("saving-special-case", func(t *testing.T) { + reaction.EmojiName = "+1" - rr, resp = Client.SaveReaction(reaction) - CheckNoError(t, resp) + rr, resp := Client.SaveReaction(reaction) + CheckNoError(t, resp) - if rr.EmojiName != reaction.EmojiName { - t.Fatal("EmojiName did not match") - } + if rr.EmojiName != reaction.EmojiName { + t.Fatal("EmojiName did not match") + } - if reactions, err := th.App.GetReactionsForPost(postId); err != nil && len(reactions) != 3 { - t.Fatal("should have save multiple reactions") - } + if reactions, err := th.App.GetReactionsForPost(postId); err != nil && len(reactions) != 3 { + t.Fatal("should have save multiple reactions") + } + }) + + t.Run("react-to-not-existing-post-id", func(t *testing.T) { + reaction.PostId = GenerateTestId() + + _, resp := Client.SaveReaction(reaction) + CheckForbiddenStatus(t, resp) + }) - reaction.PostId = GenerateTestId() + t.Run("react-to-not-valid-post-id", func(t *testing.T) { + reaction.PostId = "junk" - _, resp = Client.SaveReaction(reaction) - CheckForbiddenStatus(t, resp) + _, resp := Client.SaveReaction(reaction) + CheckBadRequestStatus(t, resp) + }) - reaction.PostId = "junk" + t.Run("react-as-not-existing-user-id", func(t *testing.T) { + reaction.PostId = postId + reaction.UserId = GenerateTestId() - _, resp = Client.SaveReaction(reaction) - CheckBadRequestStatus(t, resp) + _, resp := Client.SaveReaction(reaction) + CheckForbiddenStatus(t, resp) + }) - reaction.PostId = postId - reaction.UserId = GenerateTestId() + t.Run("react-as-not-valid-user-id", func(t *testing.T) { + reaction.UserId = "junk" - _, resp = Client.SaveReaction(reaction) - CheckForbiddenStatus(t, resp) + _, resp := Client.SaveReaction(reaction) + CheckBadRequestStatus(t, resp) + }) - reaction.UserId = "junk" + t.Run("react-as-empty-emoji-name", func(t *testing.T) { + reaction.UserId = userId + reaction.EmojiName = "" - _, resp = Client.SaveReaction(reaction) - CheckBadRequestStatus(t, resp) + _, resp := Client.SaveReaction(reaction) + CheckBadRequestStatus(t, resp) + }) - reaction.UserId = userId - reaction.EmojiName = "" + t.Run("react-as-not-valid-emoji-name", func(t *testing.T) { + reaction.EmojiName = strings.Repeat("a", 65) - _, resp = Client.SaveReaction(reaction) - CheckBadRequestStatus(t, resp) + _, resp := Client.SaveReaction(reaction) + CheckBadRequestStatus(t, resp) + }) - reaction.EmojiName = strings.Repeat("a", 65) + t.Run("react-as-other-user", func(t *testing.T) { + reaction.EmojiName = "smile" + otherUser := th.CreateUser() + Client.Logout() + Client.Login(otherUser.Email, otherUser.Password) - _, resp = Client.SaveReaction(reaction) - CheckBadRequestStatus(t, resp) + _, resp := Client.SaveReaction(reaction) + CheckForbiddenStatus(t, resp) + }) - reaction.EmojiName = "smile" - otherUser := th.CreateUser() - Client.Logout() - Client.Login(otherUser.Email, otherUser.Password) + t.Run("react-being-not-logged-in", func(t *testing.T) { + Client.Logout() + _, resp := Client.SaveReaction(reaction) + CheckUnauthorizedStatus(t, resp) + }) - _, resp = Client.SaveReaction(reaction) - CheckForbiddenStatus(t, resp) + t.Run("react-as-other-user-being-system-admin", func(t *testing.T) { + _, resp := th.SystemAdminClient.SaveReaction(reaction) + CheckForbiddenStatus(t, resp) + }) - Client.Logout() - _, resp = Client.SaveReaction(reaction) - CheckUnauthorizedStatus(t, resp) + t.Run("unable-to-create-reaction-without-permissions", func(t *testing.T) { + th.LoginBasic() - _, resp = th.SystemAdminClient.SaveReaction(reaction) - CheckForbiddenStatus(t, resp) + th.RemovePermissionFromRole(model.PERMISSION_ADD_REACTION.Id, model.CHANNEL_USER_ROLE_ID) + _, resp := Client.SaveReaction(reaction) + CheckForbiddenStatus(t, resp) + + if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 3 { + t.Fatal("should have not created a reactions") + } + th.AddPermissionToRole(model.PERMISSION_ADD_REACTION.Id, model.CHANNEL_USER_ROLE_ID) + }) } func TestGetReactions(t *testing.T) { @@ -177,29 +220,39 @@ func TestGetReactions(t *testing.T) { } } - rr, resp := Client.GetReactions(postId) - CheckNoError(t, resp) + t.Run("get-reactions", func(t *testing.T) { + rr, resp := Client.GetReactions(postId) + CheckNoError(t, resp) - assert.Len(t, rr, 5) - for _, r := range reactions { - assert.Contains(t, reactions, r) - } + assert.Len(t, rr, 5) + for _, r := range reactions { + assert.Contains(t, reactions, r) + } + }) - rr, resp = Client.GetReactions("junk") - CheckBadRequestStatus(t, resp) + t.Run("get-reactions-of-invalid-post-id", func(t *testing.T) { + rr, resp := Client.GetReactions("junk") + CheckBadRequestStatus(t, resp) - assert.Empty(t, rr) + assert.Empty(t, rr) + }) - _, resp = Client.GetReactions(GenerateTestId()) - CheckForbiddenStatus(t, resp) + t.Run("get-reactions-of-not-existing-post-id", func(t *testing.T) { + _, resp := Client.GetReactions(GenerateTestId()) + CheckForbiddenStatus(t, resp) + }) - Client.Logout() + t.Run("get-reactions-as-anonymous-user", func(t *testing.T) { + Client.Logout() - _, resp = Client.GetReactions(postId) - CheckUnauthorizedStatus(t, resp) + _, resp := Client.GetReactions(postId) + CheckUnauthorizedStatus(t, resp) + }) - _, resp = th.SystemAdminClient.GetReactions(postId) - CheckNoError(t, resp) + t.Run("get-reactions-as-system-admin", func(t *testing.T) { + _, resp := th.SystemAdminClient.GetReactions(postId) + CheckNoError(t, resp) + }) } func TestDeleteReaction(t *testing.T) { @@ -216,131 +269,186 @@ func TestDeleteReaction(t *testing.T) { EmojiName: "smile", } - th.App.SaveReactionForPost(r1) - if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 { - t.Fatal("didn't save reaction correctly") - } - - ok, resp := Client.DeleteReaction(r1) - CheckNoError(t, resp) - - if !ok { - t.Fatal("should have returned true") - } - - if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 0 { - t.Fatal("should have deleted reaction") - } - - // deleting one reaction when a post has multiple reactions r2 := &model.Reaction{ UserId: userId, PostId: postId, EmojiName: "smile-", } - th.App.SaveReactionForPost(r1) - th.App.SaveReactionForPost(r2) - if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 2 { - t.Fatal("didn't save reactions correctly") - } - - _, resp = Client.DeleteReaction(r2) - CheckNoError(t, resp) - - if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 || *reactions[0] != *r1 { - t.Fatal("should have deleted 1 reaction only") - } - - // deleting one reaction of name +1 r3 := &model.Reaction{ UserId: userId, PostId: postId, EmojiName: "+1", } - th.App.SaveReactionForPost(r3) - if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 2 { - t.Fatal("didn't save reactions correctly") - } - - _, resp = Client.DeleteReaction(r3) - CheckNoError(t, resp) - - if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 || *reactions[0] != *r1 { - t.Fatal("should have deleted 1 reaction only") - } - - // deleting a reaction made by another user r4 := &model.Reaction{ UserId: user2Id, PostId: postId, EmojiName: "smile_", } - th.LoginBasic2() - th.App.SaveReactionForPost(r4) - if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 2 { - t.Fatal("didn't save reaction correctly") - } + // Check the appropriate permissions are enforced. + defaultRolePermissions := th.SaveDefaultRolePermissions() + defer func() { + th.RestoreDefaultRolePermissions(defaultRolePermissions) + }() - th.LoginBasic() + t.Run("delete-reaction", func(t *testing.T) { + th.App.SaveReactionForPost(r1) + if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 { + t.Fatal("didn't save reaction correctly") + } - ok, resp = Client.DeleteReaction(r4) - CheckForbiddenStatus(t, resp) + ok, resp := Client.DeleteReaction(r1) + CheckNoError(t, resp) - if ok { - t.Fatal("should have returned false") - } + if !ok { + t.Fatal("should have returned true") + } - if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 2 { - t.Fatal("should have not deleted a reaction") - } + if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 0 { + t.Fatal("should have deleted reaction") + } + }) - r1.PostId = GenerateTestId() - _, resp = Client.DeleteReaction(r1) - CheckForbiddenStatus(t, resp) + t.Run("delete-reaction-when-post-has-multiple-reactions", func(t *testing.T) { + th.App.SaveReactionForPost(r1) + th.App.SaveReactionForPost(r2) + if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 2 { + t.Fatal("didn't save reactions correctly") + } + + _, resp := Client.DeleteReaction(r2) + CheckNoError(t, resp) - r1.PostId = "junk" + if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 || *reactions[0] != *r1 { + t.Fatal("should have deleted 1 reaction only") + } + }) + + t.Run("delete-reaction-when-plus-one-reaction-name", func(t *testing.T) { + th.App.SaveReactionForPost(r3) + if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 2 { + t.Fatal("didn't save reactions correctly") + } - _, resp = Client.DeleteReaction(r1) - CheckBadRequestStatus(t, resp) + _, resp := Client.DeleteReaction(r3) + CheckNoError(t, resp) - r1.PostId = postId - r1.UserId = GenerateTestId() + if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 || *reactions[0] != *r1 { + t.Fatal("should have deleted 1 reaction only") + } + }) - _, resp = Client.DeleteReaction(r1) - CheckForbiddenStatus(t, resp) + t.Run("delete-reaction-made-by-another-user", func(t *testing.T) { + th.LoginBasic2() + th.App.SaveReactionForPost(r4) + if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 2 { + t.Fatal("didn't save reaction correctly") + } - r1.UserId = "junk" + th.LoginBasic() - _, resp = Client.DeleteReaction(r1) - CheckBadRequestStatus(t, resp) + ok, resp := Client.DeleteReaction(r4) + CheckForbiddenStatus(t, resp) - r1.UserId = userId - r1.EmojiName = "" + if ok { + t.Fatal("should have returned false") + } - _, resp = Client.DeleteReaction(r1) - CheckNotFoundStatus(t, resp) + if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 2 { + t.Fatal("should have not deleted a reaction") + } + }) - r1.EmojiName = strings.Repeat("a", 65) + t.Run("delete-reaction-from-not-existing-post-id", func(t *testing.T) { + r1.PostId = GenerateTestId() + _, resp := Client.DeleteReaction(r1) + CheckForbiddenStatus(t, resp) + }) - _, resp = Client.DeleteReaction(r1) - CheckBadRequestStatus(t, resp) + t.Run("delete-reaction-from-not-valid-post-id", func(t *testing.T) { + r1.PostId = "junk" - Client.Logout() - r1.EmojiName = "smile" + _, resp := Client.DeleteReaction(r1) + CheckBadRequestStatus(t, resp) + }) - _, resp = Client.DeleteReaction(r1) - CheckUnauthorizedStatus(t, resp) + t.Run("delete-reaction-from-not-existing-user-id", func(t *testing.T) { + r1.PostId = postId + r1.UserId = GenerateTestId() - _, resp = th.SystemAdminClient.DeleteReaction(r1) - CheckNoError(t, resp) + _, resp := Client.DeleteReaction(r1) + CheckForbiddenStatus(t, resp) + }) - _, resp = th.SystemAdminClient.DeleteReaction(r4) - CheckNoError(t, resp) + t.Run("delete-reaction-from-not-valid-user-id", func(t *testing.T) { + r1.UserId = "junk" - if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 0 { - t.Fatal("should have deleted both reactions") - } + _, resp := Client.DeleteReaction(r1) + CheckBadRequestStatus(t, resp) + }) + + t.Run("delete-reaction-with-empty-name", func(t *testing.T) { + r1.UserId = userId + r1.EmojiName = "" + + _, resp := Client.DeleteReaction(r1) + CheckNotFoundStatus(t, resp) + }) + + t.Run("delete-reaction-with-not-existing-name", func(t *testing.T) { + r1.EmojiName = strings.Repeat("a", 65) + + _, resp := Client.DeleteReaction(r1) + CheckBadRequestStatus(t, resp) + }) + + t.Run("delete-reaction-as-anonymous-user", func(t *testing.T) { + Client.Logout() + r1.EmojiName = "smile" + + _, resp := Client.DeleteReaction(r1) + CheckUnauthorizedStatus(t, resp) + }) + + t.Run("delete-reaction-as-system-admin", func(t *testing.T) { + _, resp := th.SystemAdminClient.DeleteReaction(r1) + CheckNoError(t, resp) + + _, resp = th.SystemAdminClient.DeleteReaction(r4) + CheckNoError(t, resp) + + if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 0 { + t.Fatal("should have deleted both reactions") + } + }) + + t.Run("unable-to-delete-reaction-without-permissions", func(t *testing.T) { + th.LoginBasic() + + th.RemovePermissionFromRole(model.PERMISSION_REMOVE_REACTION.Id, model.CHANNEL_USER_ROLE_ID) + th.App.SaveReactionForPost(r1) + + _, resp := Client.DeleteReaction(r1) + CheckForbiddenStatus(t, resp) + + if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 { + t.Fatal("should have not deleted a reactions") + } + th.AddPermissionToRole(model.PERMISSION_REMOVE_REACTION.Id, model.CHANNEL_USER_ROLE_ID) + }) + + t.Run("unable-to-delete-others-reactions-without-permissions", func(t *testing.T) { + th.RemovePermissionFromRole(model.PERMISSION_REMOVE_OTHERS_REACTIONS.Id, model.SYSTEM_ADMIN_ROLE_ID) + th.App.SaveReactionForPost(r1) + + _, resp := th.SystemAdminClient.DeleteReaction(r1) + CheckForbiddenStatus(t, resp) + + if reactions, err := th.App.GetReactionsForPost(postId); err != nil || len(reactions) != 1 { + t.Fatal("should have not deleted a reactions") + } + th.AddPermissionToRole(model.PERMISSION_REMOVE_OTHERS_REACTIONS.Id, model.SYSTEM_ADMIN_ROLE_ID) + }) } |