From ecb10ed62fdff179e34f82b0ff2569da8390f4ad Mon Sep 17 00:00:00 2001 From: Saturnino Abril Date: Sat, 22 Apr 2017 21:52:03 +0900 Subject: APIv4 DELETE /users/{user_id}/posts/{post_id}/reactions/name (#6117) * APIv4 DELETE /users/{user_id}/posts/{post_id}/reactions/name * updated v3 deleteReaction endpoint * update parameter of app.DeleteReactionForPost() * update utils.IsValidAlphaNum, add utils.IsValidAlphaNumHyphenUnderscore, and add related tests --- model/client4.go | 10 +++ model/emoji.go | 2 +- model/emoji_test.go | 20 ++++++ model/reaction.go | 2 +- model/reaction_test.go | 15 ++++ model/team.go | 2 +- model/utils.go | 24 +++---- model/utils_test.go | 188 +++++++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 247 insertions(+), 16 deletions(-) (limited to 'model') diff --git a/model/client4.go b/model/client4.go index ac5ebf03e..1a2ce523b 100644 --- a/model/client4.go +++ b/model/client4.go @@ -2533,3 +2533,13 @@ func (c *Client4) GetReactions(postId string) ([]*Reaction, *Response) { return ReactionsFromJson(r.Body), BuildResponse(r) } } + +// DeleteReaction deletes reaction of a user in a post. +func (c *Client4) DeleteReaction(reaction *Reaction) (bool, *Response) { + if r, err := c.DoApiDelete(c.GetUserRoute(reaction.UserId) + c.GetPostRoute(reaction.PostId) + fmt.Sprintf("/reactions/%v", reaction.EmojiName)); err != nil { + return false, &Response{StatusCode: r.StatusCode, Error: err} + } else { + defer closeBody(r) + return CheckStatusOK(r), BuildResponse(r) + } +} diff --git a/model/emoji.go b/model/emoji.go index 7f2792777..5ade868cd 100644 --- a/model/emoji.go +++ b/model/emoji.go @@ -34,7 +34,7 @@ func (emoji *Emoji) IsValid() *AppError { return NewLocAppError("Emoji.IsValid", "model.emoji.user_id.app_error", nil, "") } - if len(emoji.Name) == 0 || len(emoji.Name) > 64 { + if len(emoji.Name) == 0 || len(emoji.Name) > 64 || !IsValidAlphaNumHyphenUnderscore(emoji.Name, false) { return NewLocAppError("Emoji.IsValid", "model.emoji.name.app_error", nil, "") } diff --git a/model/emoji_test.go b/model/emoji_test.go index 81de50c6b..1e1c46714 100644 --- a/model/emoji_test.go +++ b/model/emoji_test.go @@ -56,8 +56,28 @@ func TestEmojiIsValid(t *testing.T) { t.Fatal() } + emoji.Name = "" + if err := emoji.IsValid(); err == nil { + t.Fatal(err) + } + emoji.Name = strings.Repeat("1", 64) if err := emoji.IsValid(); err != nil { t.Fatal(err) } + + emoji.Name = "name-" + if err := emoji.IsValid(); err != nil { + t.Fatal(err) + } + + emoji.Name = "name_" + if err := emoji.IsValid(); err != nil { + t.Fatal(err) + } + + emoji.Name = "name:" + if err := emoji.IsValid(); err == nil { + t.Fatal(err) + } } diff --git a/model/reaction.go b/model/reaction.go index 4a02df8cb..5dbf07152 100644 --- a/model/reaction.go +++ b/model/reaction.go @@ -60,7 +60,7 @@ func (o *Reaction) IsValid() *AppError { return NewLocAppError("Reaction.IsValid", "model.reaction.is_valid.post_id.app_error", nil, "post_id="+o.PostId) } - if len(o.EmojiName) == 0 || len(o.EmojiName) > 64 { + if len(o.EmojiName) == 0 || len(o.EmojiName) > 64 || !IsValidAlphaNumHyphenUnderscore(o.EmojiName, false) { return NewLocAppError("Reaction.IsValid", "model.reaction.is_valid.emoji_name.app_error", nil, "emoji_name="+o.EmojiName) } diff --git a/model/reaction_test.go b/model/reaction_test.go index e980b106d..e447e4329 100644 --- a/model/reaction_test.go +++ b/model/reaction_test.go @@ -57,6 +57,21 @@ func TestReactionIsValid(t *testing.T) { t.Fatal(err) } + reaction.EmojiName = "emoji-" + if err := reaction.IsValid(); err != nil { + t.Fatal(err) + } + + reaction.EmojiName = "emoji_" + if err := reaction.IsValid(); err != nil { + t.Fatal(err) + } + + reaction.EmojiName = "emoji:" + if err := reaction.IsValid(); err == nil { + t.Fatal(err) + } + reaction.CreateAt = 0 if err := reaction.IsValid(); err == nil { t.Fatal("create at should be invalid") diff --git a/model/team.go b/model/team.go index 74d371ac2..4fe03f2fc 100644 --- a/model/team.go +++ b/model/team.go @@ -233,7 +233,7 @@ func IsReservedTeamName(s string) bool { func IsValidTeamName(s string) bool { - if !IsValidAlphaNum(s, false) { + if !IsValidAlphaNum(s) { return false } diff --git a/model/utils.go b/model/utils.go index 6d8fafeea..cddf38166 100644 --- a/model/utils.go +++ b/model/utils.go @@ -297,7 +297,7 @@ var reservedName = []string{ func IsValidChannelIdentifier(s string) bool { - if !IsValidAlphaNum(s, true) { + if !IsValidAlphaNumHyphenUnderscore(s, true) { return false } @@ -308,22 +308,20 @@ func IsValidChannelIdentifier(s string) bool { return true } -var validAlphaNumUnderscore = regexp.MustCompile(`^[a-z0-9]+([a-z\-\_0-9]+|(__)?)[a-z0-9]+$`) -var validAlphaNum = regexp.MustCompile(`^[a-z0-9]+([a-z\-0-9]+|(__)?)[a-z0-9]+$`) +func IsValidAlphaNum(s string) bool { + validAlphaNum := regexp.MustCompile(`^[a-z0-9]+([a-z\-0-9]+|(__)?)[a-z0-9]+$`) -func IsValidAlphaNum(s string, allowUnderscores bool) bool { - var match bool - if allowUnderscores { - match = validAlphaNumUnderscore.MatchString(s) - } else { - match = validAlphaNum.MatchString(s) - } + return validAlphaNum.MatchString(s) +} - if !match { - return false +func IsValidAlphaNumHyphenUnderscore(s string, withFormat bool) bool { + if withFormat { + validAlphaNumHyphenUnderscore := regexp.MustCompile(`^[a-z0-9]+([a-z\-\_0-9]+|(__)?)[a-z0-9]+$`) + return validAlphaNumHyphenUnderscore.MatchString(s) } - return true + validSimpleAlphaNumHyphenUnderscore := regexp.MustCompile(`^[a-zA-Z0-9\-_]+$`) + return validSimpleAlphaNumHyphenUnderscore.MatchString(s) } func Etag(parts ...interface{}) string { diff --git a/model/utils_test.go b/model/utils_test.go index e77ce80fb..94ee55aa9 100644 --- a/model/utils_test.go +++ b/model/utils_test.go @@ -137,3 +137,191 @@ func TestParseHashtags(t *testing.T) { } } } + +func TestIsValidAlphaNum(t *testing.T) { + cases := []struct { + Input string + Result bool + }{ + { + Input: "test", + Result: true, + }, + { + Input: "test-name", + Result: true, + }, + { + Input: "test--name", + Result: true, + }, + { + Input: "test__name", + Result: true, + }, + { + Input: "-", + Result: false, + }, + { + Input: "__", + Result: false, + }, + { + Input: "test-", + Result: false, + }, + { + Input: "test--", + Result: false, + }, + { + Input: "test__", + Result: false, + }, + { + Input: "test:name", + Result: false, + }, + } + + for _, tc := range cases { + actual := IsValidAlphaNum(tc.Input) + if actual != tc.Result { + t.Fatalf("case: %v\tshould returned: %#v", tc, tc.Result) + } + } +} + +func TestIsValidAlphaNumHyphenUnderscore(t *testing.T) { + casesWithFormat := []struct { + Input string + Result bool + }{ + { + Input: "test", + Result: true, + }, + { + Input: "test-name", + Result: true, + }, + { + Input: "test--name", + Result: true, + }, + { + Input: "test__name", + Result: true, + }, + { + Input: "test_name", + Result: true, + }, + { + Input: "test_-name", + Result: true, + }, + { + Input: "-", + Result: false, + }, + { + Input: "__", + Result: false, + }, + { + Input: "test-", + Result: false, + }, + { + Input: "test--", + Result: false, + }, + { + Input: "test__", + Result: false, + }, + { + Input: "test:name", + Result: false, + }, + } + + for _, tc := range casesWithFormat { + actual := IsValidAlphaNumHyphenUnderscore(tc.Input, true) + if actual != tc.Result { + t.Fatalf("case: %v\tshould returned: %#v", tc, tc.Result) + } + } + + casesWithoutFormat := []struct { + Input string + Result bool + }{ + { + Input: "test", + Result: true, + }, + { + Input: "test-name", + Result: true, + }, + { + Input: "test--name", + Result: true, + }, + { + Input: "test__name", + Result: true, + }, + { + Input: "test_name", + Result: true, + }, + { + Input: "test_-name", + Result: true, + }, + { + Input: "-", + Result: true, + }, + { + Input: "_", + Result: true, + }, + { + Input: "test-", + Result: true, + }, + { + Input: "test--", + Result: true, + }, + { + Input: "test__", + Result: true, + }, + { + Input: ".", + Result: false, + }, + + { + Input: "test,", + Result: false, + }, + { + Input: "test:name", + Result: false, + }, + } + + for _, tc := range casesWithoutFormat { + actual := IsValidAlphaNumHyphenUnderscore(tc.Input, false) + if actual != tc.Result { + t.Fatalf("case: '%v'\tshould returned: %#v", tc.Input, tc.Result) + } + } +} -- cgit v1.2.3-1-g7c22