Browse Source

Fixes #5462 - Reporting Profile - query does not support [owner_id].

Co-authored-by: Florian Liebe <fl@zammad.com>
Rolf Schmidt 1 month ago
parent
commit
d8effbdbe8

+ 1 - 1
lib/report/ticket_generic_time.rb

@@ -47,7 +47,7 @@ returns
     end
     selector.merge!(without_merged_tickets) # do not show merged tickets in reports
 
-    result_es = SearchIndexBackend.selectors('Ticket', selector, { current_user: params[:current_user] }, aggs_interval)
+    result_es = SearchIndexBackend.selectors('Ticket', selector, { current_user: params_origin[:current_user] }, aggs_interval) # use params_origin because deep_dup removes current_user.id
     case params[:interval]
     when 'month'
       stop_interval = 12

+ 3 - 1
lib/selector/search_index.rb

@@ -158,6 +158,7 @@ class Selector::SearchIndex < Selector::Base
 
       case data[:pre_condition]
       when 'not_set'
+        wildcard_or_term = 'term'
         data[:value] = if key_tmp.match?(%r{^(created_by|updated_by|owner|customer|user)_id})
                          1
                        end
@@ -175,6 +176,7 @@ class Selector::SearchIndex < Selector::Base
       when 'current_user.organization_id'
         raise "Use current_user.id in selector, but no current_user is set #{data.inspect}" if !current_user_id
 
+        wildcard_or_term = 'term'
         user = User.find_by(id: current_user_id)
         data[:value] = user.organization_id
       end
@@ -231,7 +233,7 @@ class Selector::SearchIndex < Selector::Base
     end
 
     # for pre condition not_set we want to check if values are defined for the object by exists
-    if data[:pre_condition] == 'not_set' && operators_is_isnot.include?(data[:operator]) && data[:value].nil?
+    if operators_is_isnot.include?(data[:operator]) && data[:value].nil?
       t['exists'] = {
         field: key_tmp,
       }

+ 127 - 4
spec/lib/selector/base_spec.rb

@@ -3,10 +3,13 @@
 require 'rails_helper'
 
 RSpec.describe Selector::Base, searchindex: true do
-  let(:agent)    { create(:agent, groups: [Group.first]) }
-  let(:ticket_1) { create(:ticket, title: 'bli', group: Group.first) }
-  let(:ticket_2) { create(:ticket, title: 'bla', group: Group.first) }
-  let(:ticket_3) { create(:ticket, title: 'blub', group: Group.first) }
+  let(:default_organization) { create(:organization) }
+  let(:agent)                { create(:agent, groups: [Group.first]) }
+  let(:agent_owner)          { create(:agent, groups: [Group.first], organization: default_organization) }
+  let(:default_customer)     { create(:customer, organization: default_organization) }
+  let(:ticket_1)             { create(:ticket, title: 'bli', group: Group.first, owner: agent_owner, customer: default_customer) }
+  let(:ticket_2)             { create(:ticket, title: 'bla', group: Group.first, owner: agent_owner, customer: default_customer) }
+  let(:ticket_3)             { create(:ticket, title: 'blub', group: Group.first, owner: agent_owner, customer: default_customer) }
 
   before do
     Ticket.destroy_all
@@ -347,6 +350,126 @@ RSpec.describe Selector::Base, searchindex: true do
     expect(result[:count]).to eq(3)
   end
 
+  it 'does support owner_id is not_set pre_condition', :aggregate_failures do
+    condition = {
+      operator:   'AND',
+      conditions: [
+        {
+          pre_condition: 'not_set',
+          name:          'ticket.owner_id',
+          operator:      'is',
+          value:         [],
+        },
+      ]
+    }
+
+    count, = Ticket.selectors(condition, { current_user: agent })
+    expect(count).to eq(0)
+
+    result = SearchIndexBackend.selectors('Ticket', condition, { current_user: agent })
+    expect(result[:count]).to eq(0)
+  end
+
+  it 'does support owner_id is not not_set pre_condition', :aggregate_failures do
+    condition = {
+      operator:   'AND',
+      conditions: [
+        {
+          pre_condition: 'not_set',
+          name:          'ticket.owner_id',
+          operator:      'is not',
+          value:         [],
+        },
+      ]
+    }
+
+    count, = Ticket.selectors(condition, { current_user: agent })
+    expect(count).to eq(3)
+
+    result = SearchIndexBackend.selectors('Ticket', condition, { current_user: agent })
+    expect(result[:count]).to eq(3)
+  end
+
+  it 'does support owner is current_user.id pre_condition', :aggregate_failures do
+    condition = {
+      operator:   'AND',
+      conditions: [
+        {
+          pre_condition: 'current_user.id',
+          name:          'ticket.owner_id',
+          operator:      'is',
+          value:         [],
+        },
+      ]
+    }
+
+    count, = Ticket.selectors(condition, { current_user: agent_owner })
+    expect(count).to eq(3)
+
+    result = SearchIndexBackend.selectors('Ticket', condition, { current_user: agent_owner })
+    expect(result[:count]).to eq(3)
+  end
+
+  it 'does support owner is current_user.id pre_condition but user has none', :aggregate_failures do
+    condition = {
+      operator:   'AND',
+      conditions: [
+        {
+          pre_condition: 'current_user.id',
+          name:          'ticket.owner_id',
+          operator:      'is',
+          value:         [],
+        },
+      ]
+    }
+
+    count, = Ticket.selectors(condition, { current_user: agent })
+    expect(count).to eq(0)
+
+    result = SearchIndexBackend.selectors('Ticket', condition, { current_user: agent })
+    expect(result[:count]).to eq(0)
+  end
+
+  it 'does support owner is current_user.organization_id pre_condition', :aggregate_failures do
+    condition = {
+      operator:   'AND',
+      conditions: [
+        {
+          pre_condition: 'current_user.organization_id',
+          name:          'ticket.organization_id',
+          operator:      'is',
+          value:         [],
+        },
+      ]
+    }
+
+    count, = Ticket.selectors(condition, { current_user: agent_owner })
+    expect(count).to eq(3)
+
+    result = SearchIndexBackend.selectors('Ticket', condition, { current_user: agent_owner })
+    expect(result[:count]).to eq(3)
+  end
+
+  it 'does support owner is current_user.organization_id pre_condition but user has none', :aggregate_failures do
+    condition = {
+      operator:   'AND',
+      conditions: [
+        {
+          pre_condition: 'current_user.organization_id',
+          name:          'ticket.organization_id',
+          operator:      'is',
+          value:         [],
+        },
+      ]
+    }
+
+    count, = Ticket.selectors(condition, { current_user: agent })
+    expect(count).to eq(0)
+
+    result = SearchIndexBackend.selectors('Ticket', condition, { current_user: agent })
+    expect(result[:count]).to eq(0)
+  end
+
   describe 'Report profile terminates with error if today is used as timestamp for condition #4901' do
     before do
       ticket_1.update(created_at: 1.day.ago)

+ 57 - 0
spec/requests/report_spec.rb

@@ -271,4 +271,61 @@ RSpec.describe 'Report', searchindex: true, type: :request do
       expect(json_response['data']['count::backlog']).to eq([0, 0, 7, 2, 0, 0, 0, 0, 0, 0, 0, 0])
     end
   end
+
+  describe 'Reporting Profile - query does not support [owner_id] #5462' do
+    let(:user_report_profile)         { create(:report_profile, condition: { 'ticket.owner_id'=>{ 'operator' => 'is', 'pre_condition' => 'current_user.id', 'value' => [], 'value_completion' => '' } }) }
+    let(:user_report_profile_unset)   { create(:report_profile, condition: { 'ticket.owner_id'=>{ 'operator' => 'is', 'pre_condition' => 'not_set', 'value' => [], 'value_completion' => '' } }) }
+    let(:organization_report_profile) { create(:report_profile, condition: { 'ticket.organization_id'=>{ 'operator' => 'is', 'pre_condition' => 'current_user.organization_id', 'value' => [], 'value_completion' => '' } }) }
+
+    it 'does generate reports with current user condition' do
+      authenticated_as(admin)
+      get '/api/v1/reports/sets', params: {
+        'metric'                  => 'count',
+        'year'                    => 2025,
+        'month'                   => 1,
+        'week'                    => 3,
+        'day'                     => 15,
+        'timeRange'               => 'year',
+        'profiles'                => {
+          user_report_profile.id.to_s => true
+        },
+        'downloadBackendSelected' => 'count::created'
+      }, as: :json
+      expect(response).to have_http_status(:ok)
+    end
+
+    it 'does generate reports with current user unset condition' do
+      authenticated_as(admin)
+      get '/api/v1/reports/sets', params: {
+        'metric'                  => 'count',
+        'year'                    => 2025,
+        'month'                   => 1,
+        'week'                    => 3,
+        'day'                     => 15,
+        'timeRange'               => 'year',
+        'profiles'                => {
+          user_report_profile_unset.id.to_s => true
+        },
+        'downloadBackendSelected' => 'count::created'
+      }, as: :json
+      expect(response).to have_http_status(:ok)
+    end
+
+    it 'does generate reports with current organization condition' do
+      authenticated_as(admin)
+      get '/api/v1/reports/sets', params: {
+        'metric'                  => 'count',
+        'year'                    => 2025,
+        'month'                   => 1,
+        'week'                    => 3,
+        'day'                     => 15,
+        'timeRange'               => 'year',
+        'profiles'                => {
+          organization_report_profile.id.to_s => true
+        },
+        'downloadBackendSelected' => 'count::created'
+      }, as: :json
+      expect(response).to have_http_status(:ok)
+    end
+  end
 end