123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- class CoreWorkflow::Result
- include ::Mixin::HasBackends
- MAX_RERUN = 25
- attr_accessor :payload, :payload_backup, :user, :assets, :assets_in_result, :result, :rerun, :rerun_history, :form_updater, :restricted_fields
- def initialize(payload:, user:, assets: {}, assets_in_result: true, result: {}, form_updater: false)
- if payload.respond_to?(:permit!)
- payload = payload.permit!.to_h
- end
- raise ArgumentError, __("The required parameter 'payload->class_name' is missing.") if !payload['class_name']
- raise ArgumentError, __("The required parameter 'payload->screen' is missing.") if !payload['screen']
- @restricted_fields = {}
- @payload = payload
- @payload_backup = Marshal.load(Marshal.dump(payload))
- @user = user
- @assets = assets
- @assets_in_result = assets_in_result
- @result = result
- @form_updater = form_updater
- @rerun = false
- @rerun_history = []
- end
- def attributes
- @attributes ||= CoreWorkflow::Attributes.new(result_object: self)
- end
- def workflows
- CoreWorkflow.active.object(payload['class_name'])
- end
- def set_default
- @rerun = false
- set_payload_body
- set_payload_customer_id_default
- @result[:restrict_values] = {}
- %i[request_id visibility mandatory readonly select fill_in eval matched_workflows rerun_count].each do |group|
- @result[group] = attributes.send(:"#{group}_default")
- end
- set_form_updater_default
- # restrict init defaults to make sure param values to removed if not allowed
- attributes.restrict_values_default.each do |field, values|
- # skip initial rerun to improve performance
- # priority e.g. would trigger a rerun because its not set yet
- # but we skip rerun here because the initial values have no logic which
- # are dependent on form changes
- run_backend_value('set_fixed_to', field, values, skip_rerun: true, skip_mark_restricted: true)
- end
- set_default_only_shown_if_selectable
- end
- def set_payload_body
- @payload['params']['body'] = @payload.dig('params', 'article', 'body')
- end
- def set_payload_customer_id_default
- return if !@payload['params']['customer_id'].nil?
- return if !@user
- return if !@user.permissions?('ticket.customer')
- return if @user.permissions?('ticket.agent')
- @payload['params']['customer_id'] = @user.id.to_s
- end
- def set_form_updater_default
- return if !form_updater
- @result[:all_options] = attributes.all_options_default
- @result[:historical_options] = attributes.historical_options_default
- end
- def set_default_only_shown_if_selectable
- # only_shown_if_selectable should not work on bulk feature
- return if @payload['screen'] == 'overview_bulk'
- auto_hide = {}
- attributes.auto_select_default.each do |field, state|
- result = run_backend_value('auto_select', field, state)
- next if result.compact.blank?
- auto_hide[field] = true
- end
- auto_hide.each do |field, state|
- run_backend_value('hide', field, state)
- end
- end
- def run
- set_default
- workflows.each do |workflow|
- condition = CoreWorkflow::Condition.new(result_object: self, workflow: workflow)
- next if !condition.match_all?
- run_workflow(workflow)
- run_custom(workflow, condition)
- match_workflow(workflow)
- break if workflow.stop_after_match
- end
- consider_rerun
- end
- def matches_selector?(selector:, check:)
- condition_object = CoreWorkflow::Condition.new(result_object: self)
- condition_object.check = check
- condition_object.condition_selector_match?(selector)
- end
- def run_workflow(workflow)
- Array(workflow.perform).each do |field, config|
- run_backend(field, config)
- end
- end
- def run_custom(workflow, condition)
- Array(workflow.perform.dig('custom.module', 'execute')).each do |module_path|
- custom_module = module_path.constantize.new(condition_object: condition, result_object: self)
- custom_module.perform
- end
- end
- def run_backend(field, perform_config, skip_rerun: false, skip_mark_restricted: false)
- Array(perform_config['operator']).map do |backend|
- "CoreWorkflow::Result::#{backend.classify}"
- .constantize
- .new(result_object: self, field: field, perform_config: perform_config, skip_rerun: skip_rerun, skip_mark_restricted: skip_mark_restricted)
- .run
- end
- end
- def run_backend_value(backend, field, value, skip_rerun: false, skip_mark_restricted: false)
- perform_config = {
- 'operator' => backend,
- backend => value,
- }
- run_backend(field, perform_config, skip_rerun: skip_rerun, skip_mark_restricted: skip_mark_restricted)
- end
- def change_flags(flags)
- @result[:flags] ||= {}
- @result[:flags] = @result[:flags].merge(flags)
- end
- def match_workflow(workflow)
- @result[:matched_workflows] |= Array(workflow.id)
- end
- def assets_in_result?
- return false if assets == false
- return false if !@assets_in_result
- @result[:assets] = assets
- true
- end
- def workflow_restricted_fields
- @workflow_restricted_fields ||= begin
- result = []
- workflows.each do |workflow|
- fields = workflow.perform.each_with_object([]) do |(key, value), result_inner|
- next if %w[select remove_option set_fixed_to add_option].exclude?(value['operator'])
- result_inner << key.split('.')[-1]
- end
- result |= fields
- end
- result
- end
- end
- def filter_restrict_values
- @result[:restrict_values].select! do |field, _values|
- attribute = attributes.object_elements_hash[field]
- next if attribute && workflow_restricted_fields.exclude?(field) && !@restricted_fields[field] && !attributes.attribute_options_relation?(attribute) && !attributes.attribute_filter?(attribute)
- true
- end
- end
- def rerun_loop?
- return false if rerun_history.size < 3
- rerun_history.last(3).uniq.size != 3
- end
- def consider_rerun
- @rerun_history << Marshal.load(Marshal.dump(@result.except(:rerun_count)))
- if @rerun && @result[:rerun_count] < MAX_RERUN && !rerun_loop?
- @result[:rerun_count] += 1
- return run
- end
- filter_restrict_values if !@form_updater
- assets_in_result?
- @result
- end
- end
|