Commit 13a8ac48 authored by Jose Ivan Vargas's avatar Jose Ivan Vargas

Merge branch '241738-prevent-assignment-to-groups' into 'master'

Prevent assignment of groups using quick actions

See merge request gitlab-org/gitlab!42810
parents a3c7db1d d02ef2db
......@@ -34,6 +34,7 @@ export function membersBeforeSave(members) {
: '';
return {
type: member.type,
username: member.username,
avatarTag: autoCompleteAvatar.length === 1 ? txtAvatar : imgAvatar,
title: sanitize(title),
......@@ -275,9 +276,11 @@ class GfmAutoComplete {
return $.fn.atwho.default.callbacks.filter(query, data, searchKey);
}
if (command === MEMBER_COMMAND.ASSIGN) {
if (command === MEMBER_COMMAND.ASSIGN || command === MEMBER_COMMAND.REASSIGN) {
// Only include members which are not assigned to Issuable currently
return data.filter(member => !assignees.includes(member.search));
return data.filter(
member => member.type === 'User' && !assignees.includes(member.search),
);
} else if (command === MEMBER_COMMAND.UNASSIGN) {
// Only include members which are assigned to Issuable currently
return data.filter(member => assignees.includes(member.search));
......
......@@ -63,8 +63,13 @@ const autoCompleteMap = {
SidebarMediator.singleton?.store?.assignees?.map(assignee => assignee.username) || [];
}
if (doesCurrentLineStartWith('/assign', fullText, selectionStart)) {
return this.members.filter(member => !this.assignees.includes(member.username));
if (
doesCurrentLineStartWith('/assign', fullText, selectionStart) ||
doesCurrentLineStartWith('/reassign', fullText, selectionStart)
) {
return this.members.filter(
member => member.type === 'User' && !this.assignees.includes(member.username),
);
}
if (doesCurrentLineStartWith('/unassign', fullText, selectionStart)) {
......
......@@ -69,7 +69,7 @@ module QuickActions
def extract_users(params)
return [] if params.nil?
users = extract_references(params, :user)
users = extract_references(params, :mentioned_user)
if users.empty?
users =
......
---
title: Prevent assignment of groups using quick actions
merge_request: 42810
author:
type: fixed
......@@ -3,30 +3,49 @@
require 'spec_helper'
RSpec.describe 'GFM autocomplete EE', :js do
let(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
let(:another_user) { create(:user, name: 'another user', username: 'another.user') }
let(:project) { create(:project) }
let(:issue) { create(:issue, project: project) }
let_it_be(:user) { create(:user, name: '💃speciąl someone💃', username: 'someone.special') }
let_it_be(:another_user) { create(:user, name: 'another user', username: 'another.user') }
let_it_be(:project) { create(:project) }
let_it_be(:issue) { create(:issue, project: project) }
before do
let_it_be(:group) { create(:group) }
before_all do
project.add_maintainer(user)
project.add_developer(another_user)
group.add_developer(user)
end
context 'assignees' do
let(:issue_assignee) { create(:issue, project: project) }
let(:issue_assignee) { create(:issue, project: project, assignees: [user]) }
describe 'when tribute_autocomplete feature flag is off' do
before do
stub_feature_flags(tribute_autocomplete: false)
issue_assignee.update!(assignees: [user])
sign_in(user)
visit project_issue_path(project, issue_assignee)
wait_for_requests
end
it 'lists users who are currently not assigned to the issue when using /reassign' do
note = find('#note-body')
page.within '.timeline-content-form' do
note.native.send_keys('/reas')
end
find('.atwho-view li', text: '/reassign')
note.native.send_keys(:tab)
wait_for_requests
expect(find('#at-view-users .atwho-view-ul')).not_to have_content(user.username)
expect(find('#at-view-users .atwho-view-ul')).not_to have_content(group.name)
expect(find('#at-view-users .atwho-view-ul')).to have_content(another_user.username)
end
it 'only lists users who are currently assigned to the issue when using /unassign' do
note = find('#note-body')
page.within '.timeline-content-form' do
......@@ -48,14 +67,29 @@ RSpec.describe 'GFM autocomplete EE', :js do
before do
stub_feature_flags(tribute_autocomplete: true)
issue_assignee.update!(assignees: [user])
sign_in(user)
visit project_issue_path(project, issue_assignee)
wait_for_requests
end
it 'lists users who are currently not assigned to the issue when using /reassign' do
note = find('#note-body')
page.within '.timeline-content-form' do
note.native.send_keys('/reas')
end
find('.atwho-view li', text: '/reassign')
note.native.send_keys(:tab)
note.native.send_keys(:right)
wait_for_requests
expect(find('.tribute-container ul', visible: true)).not_to have_content(user.username)
expect(find('.tribute-container ul', visible: true)).not_to have_content(group.name)
expect(find('.tribute-container ul', visible: true)).to have_content(another_user.username)
end
it 'only lists users who are currently assigned to the issue when using /unassign' do
note = find('#note-body')
page.within '.timeline-content-form' do
......
......@@ -295,18 +295,21 @@ RSpec.describe 'GFM autocomplete', :js do
end
context 'assignees' do
let(:issue_assignee) { create(:issue, project: project) }
let(:unassigned_user) { create(:user) }
let_it_be(:issue_assignee) { create(:issue, project: project, assignees: [user]) }
let_it_be(:unassigned_user) { create(:user) }
before do
issue_assignee.update(assignees: [user])
let_it_be(:group) { create(:group) }
before_all do
project.add_maintainer(unassigned_user)
group.add_developer(user)
end
it 'lists users who are currently not assigned to the issue when using /assign' do
visit project_issue_path(project, issue_assignee)
wait_for_requests
note = find('#note-body')
page.within '.timeline-content-form' do
note.native.send_keys('/as')
......@@ -318,6 +321,7 @@ RSpec.describe 'GFM autocomplete', :js do
wait_for_requests
expect(find('#at-view-users .atwho-view-ul')).not_to have_content(user.username)
expect(find('#at-view-users .atwho-view-ul')).not_to have_content(group.name)
expect(find('#at-view-users .atwho-view-ul')).to have_content(unassigned_user.username)
end
......@@ -330,6 +334,7 @@ RSpec.describe 'GFM autocomplete', :js do
textarea.native.send_keys(:tab)
expect(find('#at-view-users .atwho-view-ul')).to have_content(unassigned_user.username)
expect(find('#at-view-users .atwho-view-ul')).not_to have_content(group.name)
expect(find('#at-view-users .atwho-view-ul')).to have_content(user.username)
end
end
......@@ -644,18 +649,21 @@ RSpec.describe 'GFM autocomplete', :js do
end
context 'assignees' do
let(:issue_assignee) { create(:issue, project: project) }
let(:unassigned_user) { create(:user) }
let_it_be(:issue_assignee) { create(:issue, project: project, assignees: [user]) }
let_it_be(:unassigned_user) { create(:user) }
before do
issue_assignee.update(assignees: [user])
let_it_be(:group) { create(:group) }
before_all do
project.add_maintainer(unassigned_user)
group.add_developer(user)
end
it 'lists users who are currently not assigned to the issue when using /assign' do
visit project_issue_path(project, issue_assignee)
wait_for_requests
note = find('#note-body')
page.within '.timeline-content-form' do
note.native.send_keys('/as')
......@@ -668,12 +676,15 @@ RSpec.describe 'GFM autocomplete', :js do
wait_for_requests
expect(find('.tribute-container ul', visible: true)).not_to have_content(user.username)
expect(find('.tribute-container ul', visible: true)).not_to have_content(group.name)
expect(find('.tribute-container ul', visible: true)).to have_content(unassigned_user.username)
end
it 'lists users who are currently not assigned to the issue when using /assign on the second line' do
visit project_issue_path(project, issue_assignee)
wait_for_requests
note = find('#note-body')
page.within '.timeline-content-form' do
note.native.send_keys('/assign @user2')
......
......@@ -278,6 +278,7 @@ describe('GfmAutoComplete', () => {
it('should set the text avatar if avatar_url is null', () => {
expect(membersBeforeSave([{ ...mockGroup, avatar_url: null }])).toEqual([
{
type: 'Group',
username: 'my-group',
avatarTag: '<div class="avatar rect-avatar center avatar-inline s26">M</div>',
title: 'My Group (2)',
......@@ -290,6 +291,7 @@ describe('GfmAutoComplete', () => {
it('should set the image avatar if avatar_url is given', () => {
expect(membersBeforeSave([mockGroup])).toEqual([
{
type: 'Group',
username: 'my-group',
avatarTag:
'<img src="./group.jpg" alt="my-group" class="avatar rect-avatar avatar-inline center s26"/>',
......@@ -303,6 +305,7 @@ describe('GfmAutoComplete', () => {
it('should set mentions disabled icon if mentionsDisabled is set', () => {
expect(membersBeforeSave([{ ...mockGroup, mentionsDisabled: true }])).toEqual([
{
type: 'Group',
username: 'my-group',
avatarTag:
'<img src="./group.jpg" alt="my-group" class="avatar rect-avatar avatar-inline center s26"/>',
......@@ -321,6 +324,7 @@ describe('GfmAutoComplete', () => {
]),
).toEqual([
{
type: 'User',
username: 'my-user',
avatarTag:
'<img src="./users.jpg" alt="my-user" class="avatar avatar-inline center s26"/>',
......
......@@ -834,6 +834,19 @@ RSpec.describe QuickActions::InterpretService do
let(:issuable) { issue }
end
context 'assigning to a group' do
let_it_be(:group) { create(:group, :public) }
before_all do
group.add_developer(create(:user))
end
it_behaves_like 'empty command', "Failed to assign a user because no user was found." do
let(:content) { "/assign #{group.to_reference}" }
let(:issuable) { issue }
end
end
context 'unassign command' do
let(:content) { '/unassign' }
......
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