From c2029df9bcfa05c19cf3644f2e686da35e267c68 Mon Sep 17 00:00:00 2001 From: tobi <31960611+tsmethurst@users.noreply.github.com> Date: Thu, 21 Nov 2024 12:13:55 +0100 Subject: [PATCH] [feature] Allow emoji shortcode to be 1-character length (#3556) * [feature] Allow emoji shortcode to be 1-character length * testerino fixeroni * spaghet --- docs/api/swagger.yaml | 4 ++-- internal/api/client/admin/emojicreate.go | 2 +- internal/api/client/admin/emojiupdate.go | 2 +- internal/api/client/admin/emojiupdate_test.go | 2 +- internal/regexes/regexes.go | 2 +- internal/validate/formvalidation.go | 4 ++-- internal/validate/formvalidation_test.go | 6 +++++- web/source/settings/views/admin/emoji/local/new-emoji.tsx | 2 +- .../settings/views/admin/emoji/local/use-shortcode.ts | 6 +++--- 9 files changed, 17 insertions(+), 13 deletions(-) diff --git a/docs/api/swagger.yaml b/docs/api/swagger.yaml index 2370cc36c..4e30e9552 100644 --- a/docs/api/swagger.yaml +++ b/docs/api/swagger.yaml @@ -4920,7 +4920,7 @@ paths: - description: The code to use for the emoji, which will be used by instance denizens to select it. This must be unique on the instance. in: formData name: shortcode - pattern: \w{2,30} + pattern: \w{1,30} required: true type: string - description: A png or gif image of the emoji. Animated pngs work too! To ensure compatibility with other fedi implementations, emoji size limit is 50kb by default. @@ -5066,7 +5066,7 @@ paths: - description: The code to use for the emoji, which will be used by instance denizens to select it. This must be unique on the instance. Works for the `copy` action type only. in: formData name: shortcode - pattern: \w{2,30} + pattern: \w{1,30} type: string - description: A new png or gif image to use for the emoji. Animated pngs work too! To ensure compatibility with other fedi implementations, emoji size limit is 50kb by default. Works for LOCAL emojis only. in: formData diff --git a/internal/api/client/admin/emojicreate.go b/internal/api/client/admin/emojicreate.go index 9696200de..07fa4d4a8 100644 --- a/internal/api/client/admin/emojicreate.go +++ b/internal/api/client/admin/emojicreate.go @@ -53,7 +53,7 @@ // The code to use for the emoji, which will be used by instance denizens to select it. // This must be unique on the instance. // type: string -// pattern: \w{2,30} +// pattern: \w{1,30} // required: true // - // name: image diff --git a/internal/api/client/admin/emojiupdate.go b/internal/api/client/admin/emojiupdate.go index ec6987024..b8ac101c0 100644 --- a/internal/api/client/admin/emojiupdate.go +++ b/internal/api/client/admin/emojiupdate.go @@ -85,7 +85,7 @@ // The code to use for the emoji, which will be used by instance denizens to select it. // This must be unique on the instance. Works for the `copy` action type only. // type: string -// pattern: \w{2,30} +// pattern: \w{1,30} // - // name: image // in: formData diff --git a/internal/api/client/admin/emojiupdate_test.go b/internal/api/client/admin/emojiupdate_test.go index 17eb05fd9..b6dffa887 100644 --- a/internal/api/client/admin/emojiupdate_test.go +++ b/internal/api/client/admin/emojiupdate_test.go @@ -560,7 +560,7 @@ func (suite *EmojiUpdateTestSuite) TestEmojiUpdateCopyEmptyShortcode() { b, err := io.ReadAll(result.Body) suite.NoError(err) - suite.Equal(`{"error":"Bad Request: shortcode did not pass validation, must be between 2 and 30 characters, letters, numbers, and underscores only"}`, string(b)) + suite.Equal(`{"error":"Bad Request: shortcode did not pass validation, must be between 1 and 30 characters, letters, numbers, and underscores only"}`, string(b)) } func (suite *EmojiUpdateTestSuite) TestEmojiUpdateCopyNoShortcode() { diff --git a/internal/regexes/regexes.go b/internal/regexes/regexes.go index 799557657..515f69a12 100644 --- a/internal/regexes/regexes.go +++ b/internal/regexes/regexes.go @@ -46,7 +46,7 @@ domainGrp = `(?:` + alphaNumeric + `|\.|\-|\:)` // Non-capturing group that matches against a single valid domain character. mentionName = `^@(` + usernameGrp + `+)(?:@(` + domainGrp + `+))?$` // Extract parts of one mention, maybe including domain. mentionFinder = `(?:^|\s)(@` + usernameGrp + `+(?:@` + domainGrp + `+)?)` // Extract all mentions from a text, each mention may include domain. - emojiShortcode = `\w{2,30}` // Pattern for emoji shortcodes. maximumEmojiShortcodeLength = 30 + emojiShortcode = `\w{1,30}` // Pattern for emoji shortcodes. maximumEmojiShortcodeLength = 30 emojiFinder = `(?:\b)?:(` + emojiShortcode + `):(?:\b)?` // Extract all emoji shortcodes from a text. emojiValidator = `^` + emojiShortcode + `$` // Validate a single emoji shortcode. usernameStrict = `^[a-z0-9_]{1,64}$` // Pattern for usernames on THIS instance. maximumUsernameLength = 64 diff --git a/internal/validate/formvalidation.go b/internal/validate/formvalidation.go index e8ec3380b..207e8e05e 100644 --- a/internal/validate/formvalidation.go +++ b/internal/validate/formvalidation.go @@ -190,11 +190,11 @@ func CustomCSS(customCSS string) error { } // EmojiShortcode just runs the given shortcode through the regular expression -// for emoji shortcodes, to figure out whether it's a valid shortcode, ie., 2-30 characters, +// for emoji shortcodes, to figure out whether it's a valid shortcode, ie., 1-30 characters, // a-zA-Z, numbers, and underscores. func EmojiShortcode(shortcode string) error { if !regexes.EmojiValidator.MatchString(shortcode) { - return fmt.Errorf("shortcode %s did not pass validation, must be between 2 and 30 characters, letters, numbers, and underscores only", shortcode) + return fmt.Errorf("shortcode %s did not pass validation, must be between 1 and 30 characters, letters, numbers, and underscores only", shortcode) } return nil } diff --git a/internal/validate/formvalidation_test.go b/internal/validate/formvalidation_test.go index 7c1ff7b7f..93762cd37 100644 --- a/internal/validate/formvalidation_test.go +++ b/internal/validate/formvalidation_test.go @@ -345,7 +345,7 @@ type testStruct struct { }, { shortcode: "p", - ok: false, + ok: true, }, { shortcode: "pp", @@ -361,6 +361,10 @@ type testStruct struct { }, { shortcode: "_", + ok: true, + }, + { + shortcode: "", ok: false, }, { diff --git a/web/source/settings/views/admin/emoji/local/new-emoji.tsx b/web/source/settings/views/admin/emoji/local/new-emoji.tsx index b9c37ca8e..879a412bd 100644 --- a/web/source/settings/views/admin/emoji/local/new-emoji.tsx +++ b/web/source/settings/views/admin/emoji/local/new-emoji.tsx @@ -119,7 +119,7 @@ export default function NewEmojiForm() { label="Shortcode, must be unique among the instance's local emoji" autoCapitalize="none" spellCheck="false" - {...{pattern: "^\\w{2,30}$"}} + {...{pattern: "^\\w{1,30}$"}} /> 30) { - return "Shortcode must be between 2 and 30 characters"; + if (code.length < 1 || code.length > 30) { + return "Shortcode must be between 1 and 30 characters"; } if (!shortcodeRegex.test(code)) {