MM-55468 Ensure custom status emojis exist (#25501)

* MM-55468 Ensure custom status emojis exist

* Fix plugin API unit test

* Print underlying error as detailed error message

* Convert CustomStatusModal tests to React Testing Library and improve a11y

* Don't suggest custom statuses with non-existent emojis

* Silence test error by providing fake translation strings
Этот коммит содержится в:
Harrison Healey
2023-12-08 10:35:15 -05:00
коммит произвёл GitHub
родитель 109f4643c6
Коммит b1e745894b
14 изменённых файлов: 320 добавлений и 115 удалений

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

@@ -366,3 +366,17 @@ func (a *App) deleteReactionsForEmoji(rctx request.CTX, emojiName string) {
rctx.Logger().Warn("Unable to delete reactions when deleting emoji", mlog.String("emoji_name", emojiName), mlog.Err(err))
}
}
func (a *App) confirmEmojiExists(c request.CTX, emojiName string) *model.AppError {
if model.IsSystemEmojiName(emojiName) {
return nil
}
err := model.IsValidEmojiName(emojiName)
if err != nil {
return err
}
_, err = a.GetEmojiByName(c, emojiName)
return err
}

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

@@ -513,7 +513,7 @@ func TestPluginAPIUserCustomStatus(t *testing.T) {
defer th.App.PermanentDeleteUser(th.Context, user1)
custom := &model.CustomStatus{
Emoji: ":tada:",
Emoji: "tada",
Text: "honk",
}

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

@@ -77,6 +77,13 @@ func (a *App) SetCustomStatus(c request.CTX, userID string, cs *model.CustomStat
return model.NewAppError("SetCustomStatus", "api.custom_status.set_custom_statuses.update.app_error", nil, "", http.StatusBadRequest)
}
// Ensure the emoji exists before saving the custom status even if it's deleted afterwards
if cs.Emoji != "" {
if err := a.confirmEmojiExists(c, cs.Emoji); err != nil {
return model.NewAppError("SetCustomStatus", "api.custom_status.set_custom_statuses.emoji_not_found", nil, err.Error(), http.StatusBadRequest)
}
}
user, err := a.GetUser(userID)
if err != nil {
return err

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

@@ -6,6 +6,7 @@ package app
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
@@ -22,7 +23,7 @@ func TestCustomStatus(t *testing.T) {
user := th.BasicUser
cs := &model.CustomStatus{
Emoji: ":smile:",
Emoji: "smile",
Text: "honk!",
}
@@ -91,7 +92,7 @@ func TestCustomStatusErrors(t *testing.T) {
require.NoError(t, err)
cs := &model.CustomStatus{
Emoji: ":smile:",
Emoji: "smile",
Text: "honk!",
}
@@ -108,3 +109,91 @@ func TestCustomStatusErrors(t *testing.T) {
})
}
}
func TestSetCustomStatus(t *testing.T) {
th := Setup(t).InitBasic()
defer th.TearDown()
th.App.UpdateConfig(func(cfg *model.Config) {
*cfg.ServiceSettings.EnableCustomEmoji = true
})
emoji := th.CreateEmoji()
for _, testCase := range []struct {
Name string
Input *model.CustomStatus
ExpectsError bool
}{
{
Name: "should be able to set custom status with text and emoji",
Input: &model.CustomStatus{
Emoji: "smile",
Text: "honk!",
},
ExpectsError: false,
},
{
Name: "should be able to set custom status with only text",
Input: &model.CustomStatus{
Text: "honk!",
},
ExpectsError: false,
},
{
Name: "should be able to set custom status with just a system emoji",
Input: &model.CustomStatus{
Emoji: "smile",
},
ExpectsError: false,
},
{
Name: "should be able to set custom status with just a custom emoji",
Input: &model.CustomStatus{
Emoji: emoji.Name,
},
ExpectsError: false,
},
{
Name: "should not be able to set custom status without text or emoji",
Input: &model.CustomStatus{},
ExpectsError: true,
},
{
Name: "should not be able to set custom status with a non-existent emoji name",
Input: &model.CustomStatus{
Emoji: "somethingthatdoesntexist",
},
ExpectsError: true,
},
{
Name: "should not be able to set custom status with an invalid emoji name",
Input: &model.CustomStatus{
Emoji: "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz",
Text: "honk!",
},
ExpectsError: true,
},
} {
t.Run(testCase.Name, func(t *testing.T) {
err := th.App.SetCustomStatus(th.Context, th.BasicUser.Id, testCase.Input)
defer th.App.RemoveCustomStatus(th.Context, th.BasicUser.Id)
if testCase.ExpectsError {
require.NotNil(t, err)
} else {
require.Nil(t, err)
}
customStatus, err := th.App.GetCustomStatus(th.BasicUser.Id)
require.Nil(t, err)
if testCase.ExpectsError {
assert.NotEqual(t, testCase.Input, customStatus)
} else {
assert.Equal(t, testCase.Input, customStatus)
}
})
}
}

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

@@ -1717,6 +1717,10 @@
"id": "api.custom_status.recent_custom_statuses.delete.app_error",
"translation": "Failed to delete the recent status. Please try adding the status first or contact your system administrator for details."
},
{
"id": "api.custom_status.set_custom_statuses.emoji_not_found",
"translation": "Failed to update the custom status. An emoji with the given name does not exist."
},
{
"id": "api.custom_status.set_custom_statuses.update.app_error",
"translation": "Failed to update the custom status. Please add either emoji or custom text status or both."

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

@@ -36,7 +36,7 @@ func (emoji *Emoji) Auditable() map[string]interface{} {
}
}
func inSystemEmoji(emojiName string) bool {
func IsSystemEmojiName(emojiName string) bool {
_, ok := SystemEmojis[emojiName]
return ok
}
@@ -92,7 +92,7 @@ func IsValidEmojiName(name string) *AppError {
if name == "" || len(name) > EmojiNameMaxLength || !IsValidAlphaNumHyphenUnderscorePlus(name) {
return NewAppError("Emoji.IsValid", "model.emoji.name.app_error", nil, "", http.StatusBadRequest)
}
if inSystemEmoji(name) {
if IsSystemEmojiName(name) {
return NewAppError("Emoji.IsValid", "model.emoji.system_emoji_name.app_error", nil, "", http.StatusBadRequest)
}