Commit 845c8d0b authored by Martin Wortschack's avatar Martin Wortschack

Block emojis from user name

- Use JS regex for emoji validation
- Add test for blocking emojis in full name
- Fix existing tests for user status that failed locally
parent c243b154
import $ from 'jquery'; import $ from 'jquery';
import createFlash from '~/flash'; import createFlash from '~/flash';
import GfmAutoComplete from '~/gfm_auto_complete'; import GfmAutoComplete from '~/gfm_auto_complete';
import emojiRegex from 'emoji-regex';
import EmojiMenu from './emoji_menu'; import EmojiMenu from './emoji_menu';
const defaultStatusEmoji = 'speech_balloon'; const defaultStatusEmoji = 'speech_balloon';
...@@ -42,6 +43,17 @@ document.addEventListener('DOMContentLoaded', () => { ...@@ -42,6 +43,17 @@ document.addEventListener('DOMContentLoaded', () => {
const emojiAutocomplete = new GfmAutoComplete(); const emojiAutocomplete = new GfmAutoComplete();
emojiAutocomplete.setup($(statusMessageField), { emojis: true }); emojiAutocomplete.setup($(statusMessageField), { emojis: true });
const userNameInput = document.getElementById('user_name');
userNameInput.addEventListener('input', () => {
const EMOJI_REGEX = emojiRegex();
if (EMOJI_REGEX.test(userNameInput.value)) {
// set field to invalid so it gets detected by GlFieldErrors
userNameInput.setCustomValidity('Invalid field');
} else {
userNameInput.setCustomValidity('');
}
});
import(/* webpackChunkName: 'emoji' */ '~/emoji') import(/* webpackChunkName: 'emoji' */ '~/emoji')
.then(Emoji => { .then(Emoji => {
const emojiMenu = new EmojiMenu( const emojiMenu = new EmojiMenu(
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
- @content_class = "limit-container-width" unless fluid_layout - @content_class = "limit-container-width" unless fluid_layout
- gravatar_link = link_to Gitlab.config.gravatar.host, 'https://' + Gitlab.config.gravatar.host - gravatar_link = link_to Gitlab.config.gravatar.host, 'https://' + Gitlab.config.gravatar.host
= bootstrap_form_for @user, url: profile_path, method: :put, html: { multipart: true, class: 'edit-user prepend-top-default js-quick-submit' }, authenticity_token: true do |f| = bootstrap_form_for @user, url: profile_path, method: :put, html: { multipart: true, class: 'edit-user prepend-top-default js-quick-submit gl-show-field-errors' }, authenticity_token: true do |f|
= form_errors(@user) = form_errors(@user)
.row .row
...@@ -77,10 +77,10 @@ ...@@ -77,10 +77,10 @@
.col-lg-8 .col-lg-8
.row .row
- if @user.read_only_attribute?(:name) - if @user.read_only_attribute?(:name)
= f.text_field :name, required: true, readonly: true, wrapper: { class: 'col-md-9' }, = f.text_field :name, required: true, readonly: true, wrapper: { class: 'col-md-9 qa-full-name' },
help: s_("Profiles|Your name was automatically set based on your %{provider_label} account, so people you know can recognize you") % { provider_label: attribute_provider_label(:name) } help: s_("Profiles|Your name was automatically set based on your %{provider_label} account, so people you know can recognize you") % { provider_label: attribute_provider_label(:name) }
- else - else
= f.text_field :name, label: 'Full name', required: true, wrapper: { class: 'col-md-9' }, help: s_("Profiles|Enter your name, so people you know can recognize you") = f.text_field :name, label: 'Full name', required: true, title: s_("Profiles|Using emojis in names seems fun, but please try to set a status message instead"), wrapper: { class: 'col-md-9 qa-full-name' }, help: s_("Profiles|Enter your name, so people you know can recognize you")
= f.text_field :id, readonly: true, label: 'User ID', wrapper: { class: 'col-md-3' } = f.text_field :id, readonly: true, label: 'User ID', wrapper: { class: 'col-md-3' }
- if @user.read_only_attribute?(:email) - if @user.read_only_attribute?(:email)
......
---
title: Block emojis and symbol characters from users full names
merge_request: 24523
author:
type: other
...@@ -5399,6 +5399,9 @@ msgstr "" ...@@ -5399,6 +5399,9 @@ msgstr ""
msgid "Profiles|Username successfully changed" msgid "Profiles|Username successfully changed"
msgstr "" msgstr ""
msgid "Profiles|Using emojis in names seems fun, but please try to set a status message instead"
msgstr ""
msgid "Profiles|What's your status?" msgid "Profiles|What's your status?"
msgstr "" msgstr ""
......
...@@ -10,6 +10,7 @@ describe 'User edit profile' do ...@@ -10,6 +10,7 @@ describe 'User edit profile' do
def submit_settings def submit_settings
click_button 'Update profile settings' click_button 'Update profile settings'
wait_for_requests if respond_to?(:wait_for_requests)
end end
it 'changes user profile' do it 'changes user profile' do
...@@ -35,6 +36,17 @@ describe 'User edit profile' do ...@@ -35,6 +36,17 @@ describe 'User edit profile' do
expect(page).to have_content('Profile was successfully updated') expect(page).to have_content('Profile was successfully updated')
end end
it 'shows an error if the full name contains an emoji', :js do
simulate_input('#user_name', 'Martin 😀')
submit_settings
page.within('.qa-full-name') do
expect(page).to have_css '.gl-field-error-outline'
expect(find('.gl-field-error')).not_to have_selector('.hidden')
expect(find('.gl-field-error')).to have_content('Using emojis in names seems fun, but please try to set a status message instead')
end
end
context 'user avatar' do context 'user avatar' do
before do before do
attach_file(:user_avatar, Rails.root.join('spec', 'fixtures', 'banana_sample.gif')) attach_file(:user_avatar, Rails.root.join('spec', 'fixtures', 'banana_sample.gif'))
...@@ -61,6 +73,11 @@ describe 'User edit profile' do ...@@ -61,6 +73,11 @@ describe 'User edit profile' do
end end
context 'user status', :js do context 'user status', :js do
def visit_user
visit user_path(user)
wait_for_requests
end
def select_emoji(emoji_name, is_modal = false) def select_emoji(emoji_name, is_modal = false)
emoji_menu_class = is_modal ? '.js-modal-status-emoji-menu' : '.js-status-emoji-menu' emoji_menu_class = is_modal ? '.js-modal-status-emoji-menu' : '.js-status-emoji-menu'
toggle_button = find('.js-toggle-emoji-menu') toggle_button = find('.js-toggle-emoji-menu')
...@@ -71,18 +88,16 @@ describe 'User edit profile' do ...@@ -71,18 +88,16 @@ describe 'User edit profile' do
context 'profile edit form' do context 'profile edit form' do
it 'shows the user status form' do it 'shows the user status form' do
visit(profile_path)
expect(page).to have_content('Current status') expect(page).to have_content('Current status')
end end
it 'adds emoji to user status' do it 'adds emoji to user status' do
emoji = 'biohazard' emoji = 'biohazard'
visit(profile_path)
select_emoji(emoji) select_emoji(emoji)
submit_settings submit_settings
visit user_path(user) visit_user
within('.cover-status') do within('.cover-status') do
expect(page).to have_emoji(emoji) expect(page).to have_emoji(emoji)
end end
...@@ -90,11 +105,11 @@ describe 'User edit profile' do ...@@ -90,11 +105,11 @@ describe 'User edit profile' do
it 'adds message to user status' do it 'adds message to user status' do
message = 'I have something to say' message = 'I have something to say'
visit(profile_path)
fill_in 'js-status-message-field', with: message fill_in 'js-status-message-field', with: message
submit_settings submit_settings
visit user_path(user) visit_user
within('.cover-status') do within('.cover-status') do
expect(page).to have_emoji('speech_balloon') expect(page).to have_emoji('speech_balloon')
expect(page).to have_content message expect(page).to have_content message
...@@ -104,12 +119,12 @@ describe 'User edit profile' do ...@@ -104,12 +119,12 @@ describe 'User edit profile' do
it 'adds message and emoji to user status' do it 'adds message and emoji to user status' do
emoji = 'tanabata_tree' emoji = 'tanabata_tree'
message = 'Playing outside' message = 'Playing outside'
visit(profile_path)
select_emoji(emoji) select_emoji(emoji)
fill_in 'js-status-message-field', with: message fill_in 'js-status-message-field', with: message
submit_settings submit_settings
visit user_path(user) visit_user
within('.cover-status') do within('.cover-status') do
expect(page).to have_emoji(emoji) expect(page).to have_emoji(emoji)
expect(page).to have_content message expect(page).to have_content message
...@@ -119,7 +134,8 @@ describe 'User edit profile' do ...@@ -119,7 +134,8 @@ describe 'User edit profile' do
it 'clears the user status' do it 'clears the user status' do
user_status = create(:user_status, user: user, message: 'Eating bread', emoji: 'stuffed_flatbread') user_status = create(:user_status, user: user, message: 'Eating bread', emoji: 'stuffed_flatbread')
visit user_path(user) visit_user
within('.cover-status') do within('.cover-status') do
expect(page).to have_emoji(user_status.emoji) expect(page).to have_emoji(user_status.emoji)
expect(page).to have_content user_status.message expect(page).to have_content user_status.message
...@@ -129,15 +145,13 @@ describe 'User edit profile' do ...@@ -129,15 +145,13 @@ describe 'User edit profile' do
click_button 'js-clear-user-status-button' click_button 'js-clear-user-status-button'
submit_settings submit_settings
wait_for_requests visit_user
visit user_path(user)
expect(page).not_to have_selector '.cover-status' expect(page).not_to have_selector '.cover-status'
end end
it 'displays a default emoji if only message is entered' do it 'displays a default emoji if only message is entered' do
message = 'a status without emoji' message = 'a status without emoji'
visit(profile_path)
fill_in 'js-status-message-field', with: message fill_in 'js-status-message-field', with: message
within('.js-toggle-emoji-menu') do within('.js-toggle-emoji-menu') do
...@@ -162,6 +176,7 @@ describe 'User edit profile' do ...@@ -162,6 +176,7 @@ describe 'User edit profile' do
page.within "#set-user-status-modal" do page.within "#set-user-status-modal" do
click_button 'Set status' click_button 'Set status'
end end
wait_for_requests
end end
before do before do
...@@ -202,7 +217,8 @@ describe 'User edit profile' do ...@@ -202,7 +217,8 @@ describe 'User edit profile' do
select_emoji(emoji, true) select_emoji(emoji, true)
set_user_status_in_modal set_user_status_in_modal
visit user_path(user) visit_user
within('.cover-status') do within('.cover-status') do
expect(page).to have_emoji(emoji) expect(page).to have_emoji(emoji)
end end
...@@ -225,7 +241,8 @@ describe 'User edit profile' do ...@@ -225,7 +241,8 @@ describe 'User edit profile' do
find('.js-status-message-field').native.send_keys(message) find('.js-status-message-field').native.send_keys(message)
set_user_status_in_modal set_user_status_in_modal
visit user_path(user) visit_user
within('.cover-status') do within('.cover-status') do
expect(page).to have_emoji('speech_balloon') expect(page).to have_emoji('speech_balloon')
expect(page).to have_content message expect(page).to have_content message
...@@ -240,7 +257,8 @@ describe 'User edit profile' do ...@@ -240,7 +257,8 @@ describe 'User edit profile' do
find('.js-status-message-field').native.send_keys(message) find('.js-status-message-field').native.send_keys(message)
set_user_status_in_modal set_user_status_in_modal
visit user_path(user) visit_user
within('.cover-status') do within('.cover-status') do
expect(page).to have_emoji(emoji) expect(page).to have_emoji(emoji)
expect(page).to have_content message expect(page).to have_content message
...@@ -250,7 +268,9 @@ describe 'User edit profile' do ...@@ -250,7 +268,9 @@ describe 'User edit profile' do
it 'clears the user status with the "X" button' do it 'clears the user status with the "X" button' do
user_status = create(:user_status, user: user, message: 'Eating bread', emoji: 'stuffed_flatbread') user_status = create(:user_status, user: user, message: 'Eating bread', emoji: 'stuffed_flatbread')
visit user_path(user) visit_user
wait_for_requests
within('.cover-status') do within('.cover-status') do
expect(page).to have_emoji(user_status.emoji) expect(page).to have_emoji(user_status.emoji)
expect(page).to have_content user_status.message expect(page).to have_content user_status.message
...@@ -265,14 +285,18 @@ describe 'User edit profile' do ...@@ -265,14 +285,18 @@ describe 'User edit profile' do
find('.js-clear-user-status-button').click find('.js-clear-user-status-button').click
set_user_status_in_modal set_user_status_in_modal
visit user_path(user) visit_user
wait_for_requests
expect(page).not_to have_selector '.cover-status' expect(page).not_to have_selector '.cover-status'
end end
it 'clears the user status with the "Remove status" button' do it 'clears the user status with the "Remove status" button' do
user_status = create(:user_status, user: user, message: 'Eating bread', emoji: 'stuffed_flatbread') user_status = create(:user_status, user: user, message: 'Eating bread', emoji: 'stuffed_flatbread')
visit user_path(user) visit_user
wait_for_requests
within('.cover-status') do within('.cover-status') do
expect(page).to have_emoji(user_status.emoji) expect(page).to have_emoji(user_status.emoji)
expect(page).to have_content user_status.message expect(page).to have_content user_status.message
...@@ -288,7 +312,8 @@ describe 'User edit profile' do ...@@ -288,7 +312,8 @@ describe 'User edit profile' do
click_button 'Remove status' click_button 'Remove status'
end end
visit user_path(user) visit_user
expect(page).not_to have_selector '.cover-status' expect(page).not_to have_selector '.cover-status'
end end
......
...@@ -3395,6 +3395,11 @@ elliptic@^6.0.0: ...@@ -3395,6 +3395,11 @@ elliptic@^6.0.0:
minimalistic-assert "^1.0.0" minimalistic-assert "^1.0.0"
minimalistic-crypto-utils "^1.0.0" minimalistic-crypto-utils "^1.0.0"
emoji-regex@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
emoji-unicode-version@^0.2.1: emoji-unicode-version@^0.2.1:
version "0.2.1" version "0.2.1"
resolved "https://registry.yarnpkg.com/emoji-unicode-version/-/emoji-unicode-version-0.2.1.tgz#0ebf3666b5414097971d34994e299fce75cdbafc" resolved "https://registry.yarnpkg.com/emoji-unicode-version/-/emoji-unicode-version-0.2.1.tgz#0ebf3666b5414097971d34994e299fce75cdbafc"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment