diff --git a/app/assets/javascripts/app/controllers/ticket_overview.coffee b/app/assets/javascripts/app/controllers/ticket_overview.coffee index 06d958ee9..1cd9cf4a0 100644 --- a/app/assets/javascripts/app/controllers/ticket_overview.coffee +++ b/app/assets/javascripts/app/controllers/ticket_overview.coffee @@ -1097,11 +1097,11 @@ class Table extends App.Controller id: object.organization_id value callbackCheckbox = (id, checked, e) => - if @$('table').find('input[name="bulk"]:checked').length == 0 - @bulkForm.hide() - else + if @shouldShowBulkForm() @bulkForm.render() @bulkForm.show() + else + @bulkForm.hide() if @lastChecked && e.shiftKey # check items in a row @@ -1191,11 +1191,11 @@ class Table extends App.Controller # show/hide bulk action @$('.table-overview').delegate('input[name="bulk"], input[name="bulk_all"]', 'change', (e) => - if @$('.table-overview').find('input[name="bulk"]:checked').length == 0 + if @shouldShowBulkForm() + @bulkForm.show() + else @bulkForm.hide() @bulkForm.reset() - else - @bulkForm.show() ) # deselect bulk_all if one item is uncheck observ @@ -1215,6 +1215,17 @@ class Table extends App.Controller bulkAll.prop('indeterminate', true) ) + shouldShowBulkForm: => + items = @$('table').find('input[name="bulk"]:checked') + return false if items.length == 0 + + ticket_ids = _.map(items, (el) -> $(el).val() ) + ticket_group_ids = _.map(App.Ticket.findAll(ticket_ids), (ticket) -> ticket.group_id) + ticket_group_ids = _.uniq(ticket_group_ids) + user_permissions = App.Session.get('group_ids') + group_permissions = ticket_group_ids.map (id) -> user_permissions[id] + _.every(group_permissions, (list) -> 'full' in list || 'change' in list) + viewmode: (e) => e.preventDefault() @view_mode = $(e.target).data('mode') diff --git a/test/browser/agent_ticket_overview_level0_test.rb b/test/browser/agent_ticket_overview_level0_test.rb index bd8475b02..74a83ec7b 100644 --- a/test/browser/agent_ticket_overview_level0_test.rb +++ b/test/browser/agent_ticket_overview_level0_test.rb @@ -468,4 +468,184 @@ class AgentTicketOverviewLevel0Test < TestCase # cleanup tasks_close_all() end + + # verify fix for issue #2026 - Bulk action should not be shown if user has no change permissions + def test_no_bulk_action_when_missing_change_permission + @browser = browser_instance + login( + username: 'master@example.com', + password: 'test', + url: browser_url, + ) + tasks_close_all() + + # create new group + group_create( + data: { + name: 'some group2', + }, + ) + + click( + css: 'a[href="#manage"]', + ) + click( + css: '.content.active a[href="#manage/groups"]', + ) + + user_edit( + data: { + login: 'master@example.com', + permissions: { 1 => ['full'], + 2 => ['full'], + 3 => ['full'], } + }, + ) + + user_create( + data: { + firstname: 'Tester', + lastname: 'Agent 2', + email: 'agent2@example.com', + password: 'test', + role: 'Agent', + permissions: { 1 => %w[read create overview], + 2 => ['full'], + 3 => ['full'], } + }, + ) + + # create new tickets + can_change_ticket = ticket_create( + data: { + customer: 'nico', + group: 'some group2', + title: 'overview test #5', + body: 'overview test #5', + } + ) + cannot_change_ticket = ticket_create( + data: { + customer: 'nico', + group: 'Users', + title: 'overview test #6', + body: 'overview test #6', + } + ) + + logout() # logout as master@example.com then login as agent2@example.com + login( + username: 'agent2@example.com', + password: 'test', + url: browser_url, + ) + tasks_close_all() + + # open Overview menu tab + click( + css: '.js-menu .js-overviewsMenuItem', + ) + + # enable full overviews + execute( + js: '$(".content.active .sidebar").css("display", "block")', + ) + + # click Unassigned & Open tab + click( + css: '.content.active [href="#ticket/view/all_unassigned"]', + ) + + watch_for( + css: '.content.active', + value: 'overview test #6', + timeout: 8, + ) + + # first select the ticket that we have change rights to + check( + css: '.content.active table tr td input[value="' + can_change_ticket[:id] + '"]', + ) + + # check that the bulk action form appears + exists( + displayed: true, + css: '.content.active .bulkAction', + ) + + # then select the ticket that we do not have change rights to + scroll_to( + position: 'top', + css: '.content.active table tr td input[value="' + cannot_change_ticket[:id] + '"] + .icon-checkbox.icon-unchecked', + ) + check( + css: '.content.active table tr td input[value="' + cannot_change_ticket[:id] + '"]', + ) + + # check that the bulk action form disappears + exists( + displayed: false, + css: '.content.active .bulkAction', + ) + + # de-select the ticket that we do not have change rights to + uncheck( + css: '.content.active table tr td input[value="' + cannot_change_ticket[:id] + '"]', + fast: true, + ) + + # check that the bulk action form appears again + exists( + displayed: true, + css: '.content.active .bulkAction', + ) + + # de-select the ticket that we have change rights to + uncheck( + css: '.content.active table tr td input[value="' + can_change_ticket[:id] + '"]', + fast: true, + ) + + # check that the bulk action form disappears again + exists( + displayed: false, + css: '.content.active .bulkAction', + ) + + # cleanup + tasks_close_all() + logout() # logout as agent2@example.com and then login as master@example.com to clean up tickets + login( + username: 'master@example.com', + password: 'test', + url: browser_url, + ) + tasks_close_all() + + # open ticket by search + ticket_open_by_search( + number: cannot_change_ticket[:number], + ) + sleep 1 + + # close ticket + ticket_update( + data: { + state: 'closed', + } + ) + + # open ticket by search + ticket_open_by_search( + number: can_change_ticket[:number], + ) + sleep 1 + + # close ticket + ticket_update( + data: { + state: 'closed', + } + ) + end end diff --git a/test/browser_test_helper.rb b/test/browser_test_helper.rb index 8e7d742ef..86f83c7b6 100644 --- a/test/browser_test_helper.rb +++ b/test/browser_test_helper.rb @@ -2829,6 +2829,22 @@ wait untill text in selector disabppears lastname: 'Manage Lastname' + random, email: user_email, password: 'some-pass', + role: 'Admin', # optional, choose among [Admin, Agent, Customer] + # defaults to Customer if not provided + }, + ) + + user_create( + browser: browser2, + data: { + #login: 'some login' + random, + firstname: 'Manage Firstname' + random, + lastname: 'Manage Lastname' + random, + email: user_email, + password: 'some-pass', + role: 'Agent', # when the role is Agent an array of permissions for each group is optionally accepted + permissions: { 1 => %w[read create overview], + 2 => ['full'], } }, ) @@ -2901,11 +2917,46 @@ wait untill text in selector disabppears retry if retries < 3 end end - check( + + if data[:role] + if data[:role] == 'Admin' + check( + browser: instance, + css: '.modal input[name=role_ids][value=1]', + ) + elsif data[:role] == 'Customer' + check( + browser: instance, + css: '.modal input[name=role_ids][value=3]', + ) + elsif data[:role] == 'Agent' + check( + browser: instance, + css: '.modal input[name=role_ids][value=2]', + ) + data[:permissions].each do |key, value| + value.each do |permission| + check( + browser: instance, + css: ".modal input[name=\"group_ids::#{key}\"][value=\"#{permission}\"]", + ) + end + end + else + raise "Unknown :role \"#{data[:role]}\" in user_create()" + end + else + check( + browser: instance, + css: '.modal input[name=role_ids][value=3]', + ) + end + + click( browser: instance, - css: '.modal input[name=role_ids][value=3]', + css: '.modal .js-submit', ) - instance.find_elements(css: '.modal button.js-submit')[0].click + modal_disappear( browser: instance, timeout: 10, @@ -2939,6 +2990,144 @@ wait untill text in selector disabppears assert(true, 'user created') end +=begin + + user_edit( + browser: browser2, + data: { + login: 'some login' + random, + firstname: 'Manage Firstname' + random, + lastname: 'Manage Lastname' + random, + email: user_email, + password: 'some-pass', + role: 'Agent', # when the role is Agent an array of permissions for each group is optionally accepted + permissions: { 1 => %w[read create overview], + 2 => ['full'], } + }, + ) + +=end + + def user_edit(params = {}) + switch_window_focus(params) + log('user_edit', params) + + instance = params[:browser] || @browser + data = params[:data] + + click( + browser: instance, + css: 'a[href="#manage"]', + mute_log: true, + ) + click( + browser: instance, + css: '.content.active a[href="#manage/users"]', + mute_log: true, + ) + instance.find_elements(css: '.content.active .user-list td:first-child').each do |element| + next if element.text.strip != data[:login] + element.click + break + end + modal_ready(browser: instance) + if data[:firstname] + element = instance.find_elements(css: '.modal input[name=firstname]')[0] + element.clear + element.send_keys(data[:firstname]) + end + if data[:lastname] + element = instance.find_elements(css: '.modal input[name=lastname]')[0] + element.clear + element.send_keys(data[:lastname]) + end + if data[:email] + element = instance.find_elements(css: '.modal input[name=email]')[0] + element.clear + element.send_keys(data[:email]) + end + if data[:password] + element = instance.find_elements(css: '.modal input[name=password]')[0] + element.clear + element.send_keys(data[:password]) + element = instance.find_elements(css: '.modal input[name=password_confirm]')[0] + element.clear + element.send_keys(data[:password]) + end + if data[:phone] + element = instance.find_elements(css: '.modal input[name=phone]')[0] + element.clear + element.send_keys(data[:phone]) + end + if data[:active].present? + select(css: 'select[name="active"]', value: data[:active] ? 'active' : 'inactive' ) + end + + if data[:organization] + element = instance.find_elements(css: '.modal input.searchableSelect-main')[0] + element.clear + element.send_keys(data[:organization]) + + begin + retries ||= 0 + target = nil + until target + sleep 0.5 + target = instance.find_elements(css: ".modal li[title='#{data[:organization]}']")[0] + end + target.click() + rescue Selenium::WebDriver::Error::StaleElementReferenceError + sleep retries + retries += 1 + retry if retries < 3 + end + end + + if data[:role] + if data[:role] == 'Admin' + check( + browser: instance, + css: '.modal input[name=role_ids][value=1]', + ) + elsif data[:role] == 'Customer' + check( + browser: instance, + css: '.modal input[name=role_ids][value=3]', + ) + elsif data[:role] == 'Agent' + check( + browser: instance, + css: '.modal input[name=role_ids][value=2]', + ) + else + raise "Unknown :role \"#{data[:role]}\" in user_create()" + end + end + + if data[:permissions].present? + data[:permissions].each do |key, value| + value.each do |permission| + check( + browser: instance, + css: ".modal input[name=\"group_ids::#{key}\"][value=\"#{permission}\"]", + ) + end + end + end + + click( + browser: instance, + css: '.modal .js-submit', + ) + + modal_disappear( + browser: instance, + timeout: 10, + ) + + assert(true, 'user updated') + end + =begin organization_create(