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
Этот коммит содержится в:
коммит произвёл
GitHub
родитель
109f4643c6
Коммит
b1e745894b
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
Ссылка в новой задаче
Block a user