Просмотр исходного кода

Improved performance of ticket zoom and reduced cpu load scheduler.

Martin Edenhofer 7 лет назад
Родитель
Сommit
6f87ebf7c7

+ 2 - 2
app/models/channel/filter/identify_sender.rb

@@ -143,7 +143,7 @@ module Channel::Filter::IdentifySender
     end
   end
 
-  def self.user_create(data)
+  def self.user_create(data, role_ids = nil)
     if data[:email] !~ /@/
       data[:email] += '@local'
     end
@@ -166,7 +166,7 @@ module Channel::Filter::IdentifySender
     end
 
     # create new user
-    role_ids = Role.signup_role_ids
+    role_ids ||= Role.signup_role_ids
 
     # fillup
     %w[firstname lastname].each do |item|

+ 7 - 7
app/models/concerns/has_groups.rb

@@ -28,7 +28,7 @@ module HasGroups
       #   #=> [#<Group id: 1, access="full", ...>, ...]
       #
       # @example Groups for given access(es)es plus 'full'
-      #   user.groups.access('read', 'write')
+      #   user.groups.access('read', 'change')
       #   #=> [#<Group id: 1, access="full", ...>, ...]
       #
       # @return [ActiveRecord::AssociationRelation<[<Group]>] List of Groups with :through attributes
@@ -139,7 +139,7 @@ module HasGroups
   #
   # @example
   #   user.group_names_access_map
-  #   #=> {'Users' => 'full', 'Support' => ['read', 'write']}
+  #   #=> {'Users' => 'full', 'Support' => ['read', 'change']}
   #
   # @return [Hash<String=>String,Array<String>>] The map of Group name to access
   def group_names_access_map
@@ -149,8 +149,8 @@ module HasGroups
   # Stores a map of Group ID to access. Deletes all other relations.
   #
   # @example
-  #   user.group_names_access_map = {'Users' => 'full', 'Support' => ['read', 'write']}
-  #   #=> {'Users' => 'full', 'Support' => ['read', 'write']}
+  #   user.group_names_access_map = {'Users' => 'full', 'Support' => ['read', 'change']}
+  #   #=> {'Users' => 'full', 'Support' => ['read', 'change']}
   #
   # @return [Hash<String=>String,Array<String>>] The given map
   def group_names_access_map=(name_access_map)
@@ -163,7 +163,7 @@ module HasGroups
   #
   # @example
   #   user.group_ids_access_map
-  #   #=> {1 => 'full', 42 => ['read', 'write']}
+  #   #=> {1 => 'full', 42 => ['read', 'change']}
   #
   # @return [Hash<Integer=>String,Array<String>>] The map of Group ID to access
   def group_ids_access_map
@@ -173,8 +173,8 @@ module HasGroups
   # Stores a map of Group ID to access. Deletes all other relations.
   #
   # @example
-  #   user.group_ids_access_map = {1 => 'full', 42 => ['read', 'write']}
-  #   #=> {1 => 'full', 42 => ['read', 'write']}
+  #   user.group_ids_access_map = {1 => 'full', 42 => ['read', 'change']}
+  #   #=> {1 => 'full', 42 => ['read', 'change']}
   #
   # @return [Hash<Integer=>String,Array<String>>] The given map
   def group_ids_access_map=(id_access_map)

+ 58 - 23
app/models/ticket/screen_options.rb

@@ -7,46 +7,59 @@ list attributes
 
   result = Ticket::ScreenOptions.attributes_to_change(
     ticket_id: 123,
-    article_id: 123,
 
     ticket: ticket_model,
     current_user: User.find(123),
   )
 
+  or only with user
+
+  result = Ticket::ScreenOptions.attributes_to_change(
+    current_user: User.find(123),
+  )
+
 returns
 
   result = {
-    type_id:            type_ids,
-    state_id:           state_ids,
-    priority_id:        priority_ids,
-    owner_id:           owner_ids,
-    group_id:           group_ids,
-    group_id__owner_id: groups_users,
-  }
+    :form_meta => {
+      :filter => {
+        :state_id => [1, 2, 4, 7, 3],
+        :priority_id => [2, 1, 3],
+        :type_id => [10, 5],
+        :group_id => [12]
+      },
+    },
+    :dependencies => {
+      :group_id => {
+        "" => {
+          : owner_id => []
+        },
+        12 => {
+          : owner_id => [4, 5, 6, 7]
+        }
+      }
+    }
 
 =end
 
   def self.attributes_to_change(params)
     raise 'current_user param needed' if !params[:current_user]
 
-    if params[:ticket_id]
+    if params[:ticket].blank? && params[:ticket_id].present?
       params[:ticket] = Ticket.find(params[:ticket_id])
     end
-    if params[:article_id]
-      params[:article] = Ticket::Article.find(params[:article_id])
-    end
 
     filter = {}
     assets = {}
 
     # get ticket states
     state_ids = []
-    if params[:ticket]
+    if params[:ticket].present?
       state_type = params[:ticket].state.state_type
     end
     state_types = ['open', 'closed', 'pending action', 'pending reminder']
     if state_type && !state_types.include?(state_type.name)
-      state_ids.push params[:ticket].state.id
+      state_ids.push params[:ticket].state_id
     end
     state_types.each do |type|
       state_type = Ticket::StateType.find_by(name: type)
@@ -81,32 +94,54 @@ returns
     filter[:type_id] = type_ids
 
     # get group / user relations
-    agents = {}
-    User.with_permissions('ticket.agent').each do |user|
-      agents[ user.id ] = 1
-    end
-
     dependencies = { group_id: { '' => { owner_id: [] } } }
 
     filter[:group_id] = []
     groups = if params[:current_user].permissions?('ticket.agent')
-               params[:current_user].groups_access(%w[create edit])
+               if params[:ticket].present?
+                 params[:current_user].groups_access(%w[edit])
+               else
+                 params[:current_user].groups_access(%w[create])
+               end
              else
                Group.where(active: true)
              end
 
+    agents = {}
+    agent_role_ids = Role.with_permissions('ticket.agent').pluck(:id)
+    agent_user_ids = User.joins(:roles).where(users: { active: true }).where('roles_users.role_id IN (?)', agent_role_ids).pluck(:id)
     groups.each do |group|
       filter[:group_id].push group.id
       assets = group.assets(assets)
       dependencies[:group_id][group.id] = { owner_id: [] }
 
-      User.group_access(group.id, 'full').each do |user|
-        next if !agents[ user.id ]
+      group_agent_user_ids = User.joins(', groups_users').where("users.id = groups_users.user_id AND groups_users.access = 'full' AND groups_users.group_id = ? AND users.id IN (?)", group.id, agent_user_ids).pluck(:id)
+      group_agent_roles_ids = Role.joins(', roles_groups').where("roles.id = roles_groups.role_id AND roles_groups.access = 'full' AND roles_groups.group_id = ? AND roles.id IN (?)", group.id, agent_role_ids).pluck(:id)
+      group_agent_role_user_ids = User.joins(:roles).where(roles: { id: group_agent_roles_ids }).pluck(:id)
+
+      User.where(id: group_agent_user_ids.concat(group_agent_role_user_ids).uniq, active: true).each do |user|
+        dependencies[:group_id][group.id][:owner_id].push user.id
+        next if agents[user.id]
+        agents[user.id] = true
         assets = user.assets(assets)
-        dependencies[:group_id][ group.id ][ :owner_id ].push user.id
       end
+
     end
+=begin
+    # for performance reasons we moved from api calls to optimized sql queries
+    groups.each do |group|
+      filter[:group_id].push group.id
+      assets = group.assets(assets)
+      dependencies[:group_id][group.id] = { owner_id: [] }
 
+      User.group_access(group.id, 'full').each do |user|
+        dependencies[:group_id][ group.id ][:owner_id].push user.id
+        next if agents[user.id]
+        agents[user.id] = true
+        assets = user.assets(assets)
+      end
+    end
+=end
     {
       assets:    assets,
       form_meta: {

+ 14 - 14
spec/models/concerns/has_groups_examples.rb

@@ -55,7 +55,7 @@ RSpec.shared_examples 'HasGroups' do
             group_access_instance.group_names_access_map = {
               group_full.name     => 'full',
               group_read.name     => 'read',
-              group_inactive.name => 'write',
+              group_inactive.name => 'change',
             }
           end
 
@@ -72,7 +72,7 @@ RSpec.shared_examples 'HasGroups' do
           end
 
           it 'filters for given access list parameter' do
-            expect(group_access_instance.groups.access('read', 'write')).to include(group_read, group_inactive)
+            expect(group_access_instance.groups.access('read', 'change')).to include(group_read, group_inactive)
           end
 
           it 'always includes full access groups' do
@@ -161,7 +161,7 @@ RSpec.shared_examples 'HasGroups' do
         end
 
         it "doesn't list for no access" do
-          result = group_access_instance.group_ids_access('write')
+          result = group_access_instance.group_ids_access('change')
           expect(result).not_to include(group_read.id)
         end
       end
@@ -169,12 +169,12 @@ RSpec.shared_examples 'HasGroups' do
       context 'access list' do
 
         it 'lists access Group IDs' do
-          result = group_access_instance.group_ids_access(%w[read write])
+          result = group_access_instance.group_ids_access(%w[read edit])
           expect(result).to include(group_read.id)
         end
 
         it "doesn't list for no access" do
-          result = group_access_instance.group_ids_access(%w[write create])
+          result = group_access_instance.group_ids_access(%w[edit create])
           expect(result).not_to include(group_read.id)
         end
       end
@@ -223,7 +223,7 @@ RSpec.shared_examples 'HasGroups' do
           expect do
             group_access_instance.group_names_access_map = {
               group_full.name => 'full',
-              group_read.name => %w[read write],
+              group_read.name => %w[read edit],
             }
           end.to change {
             described_class.group_through.klass.count
@@ -309,7 +309,7 @@ RSpec.shared_examples 'HasGroups' do
           expect do
             group_access_instance.group_ids_access_map = {
               group_full.id => 'full',
-              group_read.id => %w[read write],
+              group_read.id => %w[read edit],
             }
           end.to change {
             described_class.group_through.klass.count
@@ -497,7 +497,7 @@ RSpec.shared_examples 'HasGroups' do
       group_access_instance.group_names_access_map = {
         group_full.name     => 'full',
         group_read.name     => 'read',
-        group_inactive.name => 'write',
+        group_inactive.name => 'change',
       }
       expect do
         group_access_instance.destroy
@@ -516,18 +516,18 @@ RSpec.shared_examples '#group_access? call' do
     end
 
     it 'checks negative' do
-      expect(group_access_instance.group_access?(group_parameter, 'write')).to be false
+      expect(group_access_instance.group_access?(group_parameter, 'change')).to be false
     end
   end
 
   context 'access list' do
 
     it 'checks positive' do
-      expect(group_access_instance.group_access?(group_parameter, %w[read write])).to be true
+      expect(group_access_instance.group_access?(group_parameter, %w[read edit])).to be true
     end
 
     it 'checks negative' do
-      expect(group_access_instance.group_access?(group_parameter, %w[write create])).to be false
+      expect(group_access_instance.group_access?(group_parameter, %w[edit create])).to be false
     end
   end
 end
@@ -540,18 +540,18 @@ RSpec.shared_examples '.group_access call' do
     end
 
     it 'excludes non access IDs' do
-      expect(described_class.group_access(group_parameter, 'write')).not_to include(group_access_instance)
+      expect(described_class.group_access(group_parameter, 'change')).not_to include(group_access_instance)
     end
   end
 
   context 'access list' do
 
     it 'lists access IDs' do
-      expect(described_class.group_access(group_parameter, %w[read write])).to include(group_access_instance)
+      expect(described_class.group_access(group_parameter, %w[read edit])).to include(group_access_instance)
     end
 
     it 'excludes non access IDs' do
-      expect(described_class.group_access(group_parameter, %w[write create])).not_to include(group_access_instance)
+      expect(described_class.group_access(group_parameter, %w[edit create])).not_to include(group_access_instance)
     end
   end
 end

+ 9 - 9
spec/models/concerns/has_roles_examples.rb

@@ -165,7 +165,7 @@ RSpec.shared_examples 'HasRoles' do
           end
 
           it "doesn't list for no access" do
-            result = group_access_instance.group_ids_access('write')
+            result = group_access_instance.group_ids_access('change')
             expect(result).not_to include(group_role.id)
           end
 
@@ -182,12 +182,12 @@ RSpec.shared_examples 'HasRoles' do
         context 'access list' do
 
           it 'lists access Group IDs' do
-            result = group_access_instance.group_ids_access(%w[read write])
+            result = group_access_instance.group_ids_access(%w[read change])
             expect(result).to include(group_role.id)
           end
 
           it "doesn't list for no access" do
-            result = group_access_instance.group_ids_access(%w[write create])
+            result = group_access_instance.group_ids_access(%w[change create])
             expect(result).not_to include(group_role.id)
           end
 
@@ -230,18 +230,18 @@ RSpec.shared_examples '#role_access? call' do
     end
 
     it 'checks negative' do
-      expect(group_access_instance.role_access?(group_parameter, 'write')).to be false
+      expect(group_access_instance.role_access?(group_parameter, 'change')).to be false
     end
   end
 
   context 'access list' do
 
     it 'checks positive' do
-      expect(group_access_instance.role_access?(group_parameter, %w[read write])).to be true
+      expect(group_access_instance.role_access?(group_parameter, %w[read change])).to be true
     end
 
     it 'checks negative' do
-      expect(group_access_instance.role_access?(group_parameter, %w[write create])).to be false
+      expect(group_access_instance.role_access?(group_parameter, %w[change create])).to be false
     end
   end
 end
@@ -254,18 +254,18 @@ RSpec.shared_examples '.role_access_ids call' do
     end
 
     it 'excludes non access IDs' do
-      expect(described_class.role_access_ids(group_parameter, 'write')).not_to include(group_access_instance.id)
+      expect(described_class.role_access_ids(group_parameter, 'change')).not_to include(group_access_instance.id)
     end
   end
 
   context 'access list' do
 
     it 'lists access IDs' do
-      expect(described_class.role_access_ids(group_parameter, %w[read write])).to include(group_access_instance.id)
+      expect(described_class.role_access_ids(group_parameter, %w[read change])).to include(group_access_instance.id)
     end
 
     it 'excludes non access IDs' do
-      expect(described_class.role_access_ids(group_parameter, %w[write create])).not_to include(group_access_instance.id)
+      expect(described_class.role_access_ids(group_parameter, %w[change create])).not_to include(group_access_instance.id)
     end
   end
 end

+ 606 - 0
test/unit/ticket_screen_options_test.rb

@@ -0,0 +1,606 @@
+
+require 'test_helper'
+
+class TicketScreenOptionsTest < ActiveSupport::TestCase
+
+  test 'base' do
+
+    group1 = Group.create!(
+      name: 'Group 1',
+      active: true,
+      email_address: EmailAddress.first,
+      created_by_id: 1,
+      updated_by_id: 1,
+    )
+    group2 = Group.create!(
+      name: 'Group 2',
+      active: true,
+      created_by_id: 1,
+      updated_by_id: 1,
+    )
+    group3 = Group.create!(
+      name: 'Group 3',
+      active: true,
+      created_by_id: 1,
+      updated_by_id: 1,
+    )
+
+    agent1 = User.create!(
+      login: 'agent1@example.com',
+      firstname: 'Role',
+      lastname: 'Agent1',
+      email: 'agent1@example.com',
+      password: 'agentpw',
+      active: true,
+      roles: Role.where(name: %w[Admin Agent]),
+      updated_by_id: 1,
+      created_by_id: 1,
+    )
+    agent1.group_names_access_map = {
+      group1.name => 'full',
+      group2.name => %w[read change],
+      group3.name => 'full',
+    }
+
+    agent2 = User.create!(
+      login: 'agent2@example.com',
+      firstname: 'Role',
+      lastname: 'Agent2',
+      email: 'agent2@example.com',
+      password: 'agentpw',
+      active: true,
+      roles: Role.where(name: %w[Admin Agent]),
+      updated_by_id: 1,
+      created_by_id: 1,
+    )
+    agent2.group_names_access_map = {
+      group1.name => 'full',
+      group2.name => %w[read change],
+      group3.name => ['create'],
+    }
+
+    agent3 = User.create!(
+      login: 'agent3@example.com',
+      firstname: 'Role',
+      lastname: 'Agent3',
+      email: 'agent3@example.com',
+      password: 'agentpw',
+      active: true,
+      roles: Role.where(name: %w[Admin Agent]),
+      updated_by_id: 1,
+      created_by_id: 1,
+    )
+    agent3.group_names_access_map = {
+      group1.name => 'full',
+      group2.name => ['full'],
+    }
+
+    agent4 = User.create!(
+      login: 'agent4@example.com',
+      firstname: 'Role',
+      lastname: 'Agent4',
+      email: 'agent4@example.com',
+      password: 'agentpw',
+      active: true,
+      roles: Role.where(name: %w[Admin Agent]),
+      updated_by_id: 1,
+      created_by_id: 1,
+    )
+    agent4.group_names_access_map = {
+      group1.name => 'full',
+      group2.name => %w[read overview change],
+    }
+
+    agent5 = User.create!(
+      login: 'agent5@example.com',
+      firstname: 'Role',
+      lastname: 'Agent5',
+      email: 'agent5@example.com',
+      password: 'agentpw',
+      active: true,
+      roles: Role.where(name: %w[Admin Agent]),
+      updated_by_id: 1,
+      created_by_id: 1,
+    )
+    agent5.group_names_access_map = {
+      group3.name => 'full',
+    }
+
+    agent6 = User.create!(
+      login: 'agent6@example.com',
+      firstname: 'Role',
+      lastname: 'Agent6',
+      email: 'agent6@example.com',
+      password: 'agentpw',
+      active: true,
+      roles: Role.where(name: %w[Admin Agent]),
+      updated_by_id: 1,
+      created_by_id: 1,
+    )
+
+    result = Ticket::ScreenOptions.attributes_to_change(
+      current_user: agent1,
+    )
+
+    assert(result[:form_meta])
+    assert(result[:form_meta][:filter])
+    assert(result[:form_meta][:filter][:state_id])
+    assert_equal([
+                   Ticket::State.lookup(name: 'open').id,
+                   Ticket::State.lookup(name: 'pending reminder').id,
+                   Ticket::State.lookup(name: 'closed').id,
+                   Ticket::State.lookup(name: 'pending close').id,
+                 ], result[:form_meta][:filter][:state_id].sort)
+    assert(result[:form_meta][:filter][:priority_id])
+    assert_equal([
+                   Ticket::Priority.lookup(name: '1 low').id,
+                   Ticket::Priority.lookup(name: '2 normal').id,
+                   Ticket::Priority.lookup(name: '3 high').id,
+                 ], result[:form_meta][:filter][:priority_id].sort)
+    assert(result[:form_meta][:filter][:type_id])
+    assert_equal([], result[:form_meta][:filter][:type_id].sort)
+    assert(result[:form_meta][:filter][:group_id])
+    assert_equal([group1.id, group3.id], result[:form_meta][:filter][:group_id].sort)
+    assert(result[:form_meta][:dependencies])
+    assert(result[:form_meta][:dependencies][:group_id])
+    assert_equal(3, result[:form_meta][:dependencies][:group_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][''])
+    assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id])
+    assert_equal(4, result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent2.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent3.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent4.id))
+    assert(result[:form_meta][:dependencies][:group_id][group3.id])
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id])
+    assert_equal(2, result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].include?(agent5.id))
+
+    result = Ticket::ScreenOptions.attributes_to_change(
+      current_user: agent2,
+    )
+
+    assert(result[:form_meta])
+    assert(result[:form_meta][:filter])
+    assert(result[:form_meta][:filter][:state_id])
+    assert_equal([
+                   Ticket::State.lookup(name: 'open').id,
+                   Ticket::State.lookup(name: 'pending reminder').id,
+                   Ticket::State.lookup(name: 'closed').id,
+                   Ticket::State.lookup(name: 'pending close').id,
+                 ], result[:form_meta][:filter][:state_id].sort)
+    assert(result[:form_meta][:filter][:priority_id])
+    assert_equal([
+                   Ticket::Priority.lookup(name: '1 low').id,
+                   Ticket::Priority.lookup(name: '2 normal').id,
+                   Ticket::Priority.lookup(name: '3 high').id,
+                 ], result[:form_meta][:filter][:priority_id].sort)
+    assert(result[:form_meta][:filter][:type_id])
+    assert_equal([], result[:form_meta][:filter][:type_id].sort)
+    assert(result[:form_meta][:filter][:group_id])
+    assert_equal([group1.id, group3.id], result[:form_meta][:filter][:group_id].sort)
+    assert(result[:form_meta][:dependencies])
+    assert(result[:form_meta][:dependencies][:group_id])
+    assert_equal(3, result[:form_meta][:dependencies][:group_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][''])
+    assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id])
+    assert_equal(4, result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent2.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent3.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent4.id))
+    assert_equal(2, result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].include?(agent5.id))
+
+    result = Ticket::ScreenOptions.attributes_to_change(
+      current_user: agent3,
+    )
+
+    assert(result[:form_meta])
+    assert(result[:form_meta][:filter])
+    assert(result[:form_meta][:filter][:state_id])
+    assert_equal([
+                   Ticket::State.lookup(name: 'open').id,
+                   Ticket::State.lookup(name: 'pending reminder').id,
+                   Ticket::State.lookup(name: 'closed').id,
+                   Ticket::State.lookup(name: 'pending close').id,
+                 ], result[:form_meta][:filter][:state_id].sort)
+    assert(result[:form_meta][:filter][:priority_id])
+    assert_equal([
+                   Ticket::Priority.lookup(name: '1 low').id,
+                   Ticket::Priority.lookup(name: '2 normal').id,
+                   Ticket::Priority.lookup(name: '3 high').id,
+                 ], result[:form_meta][:filter][:priority_id].sort)
+    assert(result[:form_meta][:filter][:type_id])
+    assert_equal([], result[:form_meta][:filter][:type_id].sort)
+    assert(result[:form_meta][:filter][:group_id])
+    assert_equal([group1.id, group2.id], result[:form_meta][:filter][:group_id].sort)
+    assert(result[:form_meta][:dependencies])
+    assert(result[:form_meta][:dependencies][:group_id])
+    assert_equal(3, result[:form_meta][:dependencies][:group_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][''])
+    assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id])
+    assert_equal(4, result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent2.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent3.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent4.id))
+    assert_equal(1, result[:form_meta][:dependencies][:group_id][group2.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group2.id][:owner_id].include?(agent3.id))
+
+    ticket1 = Ticket.create!(
+      title: 'some title 1',
+      group: group1,
+      customer_id: 2,
+      state: Ticket::State.lookup(name: 'new'),
+      priority: Ticket::Priority.lookup(name: '2 normal'),
+      updated_by_id: 1,
+      created_by_id: 1,
+    )
+    article1 = Ticket::Article.create!(
+      ticket_id: ticket1.id,
+      from: 'some_sender@example.com',
+      to: 'some_recipient@example.com',
+      subject: 'some subject',
+      message_id: 'some@id',
+      body: 'some message',
+      internal: false,
+      sender: Ticket::Article::Sender.find_by(name: 'Customer'),
+      type: Ticket::Article::Type.find_by(name: 'email'),
+      updated_by_id: 1,
+      created_by_id: 1,
+    )
+
+    ticket2 = Ticket.create!(
+      title: 'some title 2',
+      group: group2,
+      customer_id: 2,
+      state: Ticket::State.lookup(name: 'new'),
+      priority: Ticket::Priority.lookup(name: '2 normal'),
+      updated_by_id: 1,
+      created_by_id: 1,
+    )
+    article2 = Ticket::Article.create!(
+      ticket_id: ticket2.id,
+      from: 'some_sender@example.com',
+      to: 'some_recipient@example.com',
+      subject: 'some subject',
+      message_id: 'some@id',
+      body: 'some message',
+      internal: false,
+      sender: Ticket::Article::Sender.find_by(name: 'Customer'),
+      type: Ticket::Article::Type.find_by(name: 'email'),
+      updated_by_id: 1,
+      created_by_id: 1,
+    )
+
+    result = Ticket::ScreenOptions.attributes_to_change(
+      ticket_id: ticket1.id,
+      current_user: agent1,
+    )
+
+    assert(result[:form_meta])
+    assert(result[:form_meta][:filter])
+    assert(result[:form_meta][:filter][:state_id])
+    assert_equal([
+                   Ticket::State.lookup(name: 'new').id,
+                   Ticket::State.lookup(name: 'open').id,
+                   Ticket::State.lookup(name: 'pending reminder').id,
+                   Ticket::State.lookup(name: 'closed').id,
+                   Ticket::State.lookup(name: 'pending close').id,
+                 ], result[:form_meta][:filter][:state_id].sort)
+    assert(result[:form_meta][:filter][:priority_id])
+    assert_equal([
+                   Ticket::Priority.lookup(name: '1 low').id,
+                   Ticket::Priority.lookup(name: '2 normal').id,
+                   Ticket::Priority.lookup(name: '3 high').id,
+                 ], result[:form_meta][:filter][:priority_id].sort)
+    assert(result[:form_meta][:filter][:type_id])
+    assert_equal([
+                   Ticket::Article::Type.lookup(name: 'email').id,
+                   Ticket::Article::Type.lookup(name: 'phone').id,
+                   Ticket::Article::Type.lookup(name: 'note').id,
+                 ], result[:form_meta][:filter][:type_id].sort)
+    assert(result[:form_meta][:filter][:group_id])
+    assert_equal([group1.id, group3.id], result[:form_meta][:filter][:group_id].sort)
+    assert(result[:form_meta][:dependencies])
+    assert(result[:form_meta][:dependencies][:group_id])
+    assert_equal(3, result[:form_meta][:dependencies][:group_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][''])
+    assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id])
+    assert_equal(4, result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent2.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent3.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent4.id))
+    assert(result[:form_meta][:dependencies][:group_id][group3.id])
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id])
+    assert_equal(2, result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].include?(agent5.id))
+
+    result = Ticket::ScreenOptions.attributes_to_change(
+      ticket_id: ticket2.id,
+      current_user: agent1,
+    )
+
+    assert(result[:form_meta])
+    assert(result[:form_meta][:filter])
+    assert(result[:form_meta][:filter][:state_id])
+    assert_equal([
+                   Ticket::State.lookup(name: 'new').id,
+                   Ticket::State.lookup(name: 'open').id,
+                   Ticket::State.lookup(name: 'pending reminder').id,
+                   Ticket::State.lookup(name: 'closed').id,
+                   Ticket::State.lookup(name: 'pending close').id,
+                 ], result[:form_meta][:filter][:state_id].sort)
+    assert(result[:form_meta][:filter][:priority_id])
+    assert_equal([
+                   Ticket::Priority.lookup(name: '1 low').id,
+                   Ticket::Priority.lookup(name: '2 normal').id,
+                   Ticket::Priority.lookup(name: '3 high').id,
+                 ], result[:form_meta][:filter][:priority_id].sort)
+    assert(result[:form_meta][:filter][:type_id])
+    assert_equal([
+                   Ticket::Article::Type.lookup(name: 'phone').id,
+                   Ticket::Article::Type.lookup(name: 'note').id,
+                 ], result[:form_meta][:filter][:type_id].sort)
+    assert(result[:form_meta][:filter][:group_id])
+    assert_equal([group1.id, group3.id], result[:form_meta][:filter][:group_id].sort)
+    assert(result[:form_meta][:dependencies])
+    assert(result[:form_meta][:dependencies][:group_id])
+    assert_equal(3, result[:form_meta][:dependencies][:group_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][''])
+    assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id])
+    assert_equal(4, result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent2.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent3.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent4.id))
+    assert(result[:form_meta][:dependencies][:group_id][group3.id])
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id])
+    assert_equal(2, result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].include?(agent5.id))
+
+    result = Ticket::ScreenOptions.attributes_to_change(
+      ticket_id: ticket2.id,
+      current_user: agent1,
+    )
+
+    assert(result[:form_meta])
+    assert(result[:form_meta][:filter])
+    assert(result[:form_meta][:filter][:state_id])
+    assert_equal([
+                   Ticket::State.lookup(name: 'new').id,
+                   Ticket::State.lookup(name: 'open').id,
+                   Ticket::State.lookup(name: 'pending reminder').id,
+                   Ticket::State.lookup(name: 'closed').id,
+                   Ticket::State.lookup(name: 'pending close').id,
+                 ], result[:form_meta][:filter][:state_id].sort)
+    assert(result[:form_meta][:filter][:priority_id])
+    assert_equal([
+                   Ticket::Priority.lookup(name: '1 low').id,
+                   Ticket::Priority.lookup(name: '2 normal').id,
+                   Ticket::Priority.lookup(name: '3 high').id,
+                 ], result[:form_meta][:filter][:priority_id].sort)
+    assert(result[:form_meta][:filter][:type_id])
+    assert_equal([
+                   Ticket::Article::Type.lookup(name: 'phone').id,
+                   Ticket::Article::Type.lookup(name: 'note').id,
+                 ], result[:form_meta][:filter][:type_id].sort)
+    assert(result[:form_meta][:filter][:group_id])
+    assert_equal([group1.id, group3.id], result[:form_meta][:filter][:group_id].sort)
+    assert(result[:form_meta][:dependencies])
+    assert(result[:form_meta][:dependencies][:group_id])
+    assert_equal(3, result[:form_meta][:dependencies][:group_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][''])
+    assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id])
+    assert_equal(4, result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent2.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent3.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent4.id))
+    assert(result[:form_meta][:dependencies][:group_id][group3.id])
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id])
+    assert_equal(2, result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group3.id][:owner_id].include?(agent5.id))
+
+    result = Ticket::ScreenOptions.attributes_to_change(
+      ticket_id: ticket1.id,
+      current_user: agent2,
+    )
+
+    assert(result[:form_meta])
+    assert(result[:form_meta][:filter])
+    assert(result[:form_meta][:filter][:state_id])
+    assert_equal([
+                   Ticket::State.lookup(name: 'new').id,
+                   Ticket::State.lookup(name: 'open').id,
+                   Ticket::State.lookup(name: 'pending reminder').id,
+                   Ticket::State.lookup(name: 'closed').id,
+                   Ticket::State.lookup(name: 'pending close').id,
+                 ], result[:form_meta][:filter][:state_id].sort)
+    assert(result[:form_meta][:filter][:priority_id])
+    assert_equal([
+                   Ticket::Priority.lookup(name: '1 low').id,
+                   Ticket::Priority.lookup(name: '2 normal').id,
+                   Ticket::Priority.lookup(name: '3 high').id,
+                 ], result[:form_meta][:filter][:priority_id].sort)
+    assert(result[:form_meta][:filter][:type_id])
+    assert_equal([
+                   Ticket::Article::Type.lookup(name: 'email').id,
+                   Ticket::Article::Type.lookup(name: 'phone').id,
+                   Ticket::Article::Type.lookup(name: 'note').id,
+                 ], result[:form_meta][:filter][:type_id].sort)
+    assert(result[:form_meta][:filter][:group_id])
+    assert_equal([group1.id], result[:form_meta][:filter][:group_id].sort)
+    assert(result[:form_meta][:dependencies])
+    assert(result[:form_meta][:dependencies][:group_id])
+    assert_equal(2, result[:form_meta][:dependencies][:group_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][''])
+    assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id])
+    assert_equal(4, result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent2.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent3.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent4.id))
+
+    result = Ticket::ScreenOptions.attributes_to_change(
+      ticket_id: ticket2.id,
+      current_user: agent2,
+    )
+
+    assert(result[:form_meta])
+    assert(result[:form_meta][:filter])
+    assert(result[:form_meta][:filter][:state_id])
+    assert_equal([
+                   Ticket::State.lookup(name: 'new').id,
+                   Ticket::State.lookup(name: 'open').id,
+                   Ticket::State.lookup(name: 'pending reminder').id,
+                   Ticket::State.lookup(name: 'closed').id,
+                   Ticket::State.lookup(name: 'pending close').id,
+                 ], result[:form_meta][:filter][:state_id].sort)
+    assert(result[:form_meta][:filter][:priority_id])
+    assert_equal([
+                   Ticket::Priority.lookup(name: '1 low').id,
+                   Ticket::Priority.lookup(name: '2 normal').id,
+                   Ticket::Priority.lookup(name: '3 high').id,
+                 ], result[:form_meta][:filter][:priority_id].sort)
+    assert(result[:form_meta][:filter][:type_id])
+    assert_equal([
+                   Ticket::Article::Type.lookup(name: 'phone').id,
+                   Ticket::Article::Type.lookup(name: 'note').id,
+                 ], result[:form_meta][:filter][:type_id].sort)
+    assert(result[:form_meta][:filter][:group_id])
+    assert_equal([group1.id], result[:form_meta][:filter][:group_id].sort)
+    assert(result[:form_meta][:dependencies])
+    assert(result[:form_meta][:dependencies][:group_id])
+    assert_equal(2, result[:form_meta][:dependencies][:group_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][''])
+    assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id])
+    assert_equal(4, result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent2.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent3.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent4.id))
+
+    result = Ticket::ScreenOptions.attributes_to_change(
+      ticket_id: ticket1.id,
+      current_user: agent3,
+    )
+
+    assert(result[:form_meta])
+    assert(result[:form_meta][:filter])
+    assert(result[:form_meta][:filter][:state_id])
+    assert_equal([
+                   Ticket::State.lookup(name: 'new').id,
+                   Ticket::State.lookup(name: 'open').id,
+                   Ticket::State.lookup(name: 'pending reminder').id,
+                   Ticket::State.lookup(name: 'closed').id,
+                   Ticket::State.lookup(name: 'pending close').id,
+                 ], result[:form_meta][:filter][:state_id].sort)
+    assert(result[:form_meta][:filter][:priority_id])
+    assert_equal([
+                   Ticket::Priority.lookup(name: '1 low').id,
+                   Ticket::Priority.lookup(name: '2 normal').id,
+                   Ticket::Priority.lookup(name: '3 high').id,
+                 ], result[:form_meta][:filter][:priority_id].sort)
+    assert(result[:form_meta][:filter][:type_id])
+    assert_equal([
+                   Ticket::Article::Type.lookup(name: 'email').id,
+                   Ticket::Article::Type.lookup(name: 'phone').id,
+                   Ticket::Article::Type.lookup(name: 'note').id,
+                 ], result[:form_meta][:filter][:type_id].sort)
+    assert(result[:form_meta][:filter][:group_id])
+    assert_equal([group1.id, group2.id], result[:form_meta][:filter][:group_id].sort)
+    assert(result[:form_meta][:dependencies])
+    assert(result[:form_meta][:dependencies][:group_id])
+    assert_equal(3, result[:form_meta][:dependencies][:group_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][''])
+    assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id])
+    assert_equal(4, result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent2.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent3.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent4.id))
+    assert_equal(1, result[:form_meta][:dependencies][:group_id][group2.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group2.id][:owner_id].include?(agent3.id))
+
+    result = Ticket::ScreenOptions.attributes_to_change(
+      ticket_id: ticket2.id,
+      current_user: agent3,
+    )
+
+    assert(result[:form_meta])
+    assert(result[:form_meta][:filter])
+    assert(result[:form_meta][:filter][:state_id])
+    assert_equal([
+                   Ticket::State.lookup(name: 'new').id,
+                   Ticket::State.lookup(name: 'open').id,
+                   Ticket::State.lookup(name: 'pending reminder').id,
+                   Ticket::State.lookup(name: 'closed').id,
+                   Ticket::State.lookup(name: 'pending close').id,
+                 ], result[:form_meta][:filter][:state_id].sort)
+    assert(result[:form_meta][:filter][:priority_id])
+    assert_equal([
+                   Ticket::Priority.lookup(name: '1 low').id,
+                   Ticket::Priority.lookup(name: '2 normal').id,
+                   Ticket::Priority.lookup(name: '3 high').id,
+                 ], result[:form_meta][:filter][:priority_id].sort)
+    assert(result[:form_meta][:filter][:type_id])
+    assert_equal([
+                   Ticket::Article::Type.lookup(name: 'phone').id,
+                   Ticket::Article::Type.lookup(name: 'note').id,
+                 ], result[:form_meta][:filter][:type_id].sort)
+    assert(result[:form_meta][:filter][:group_id])
+    assert_equal([group1.id, group2.id], result[:form_meta][:filter][:group_id].sort)
+    assert(result[:form_meta][:dependencies])
+    assert(result[:form_meta][:dependencies][:group_id])
+    assert_equal(3, result[:form_meta][:dependencies][:group_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][''])
+    assert(result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert_equal([], result[:form_meta][:dependencies][:group_id][''][:owner_id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id])
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id])
+    assert_equal(4, result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent1.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent2.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent3.id))
+    assert(result[:form_meta][:dependencies][:group_id][group1.id][:owner_id].include?(agent4.id))
+    assert_equal(1, result[:form_meta][:dependencies][:group_id][group2.id][:owner_id].count)
+    assert(result[:form_meta][:dependencies][:group_id][group2.id][:owner_id].include?(agent3.id))
+
+  end
+
+end