zammad/zammad

View on GitHub
app/models/core_workflow/condition.rb

Summary

Maintainability
A
25 mins
Test Coverage
# Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/

class CoreWorkflow::Condition
  include ::Mixin::HasBackends

  attr_accessor :user, :payload, :workflow, :attribute_object, :result_object, :check

  def initialize(result_object:, workflow: nil)
    @user             = result_object.user
    @payload          = result_object.payload
    @workflow         = workflow
    @attribute_object = result_object.attributes
    @result_object    = result_object
    @check            = nil
  end

  def attributes
    @attribute_object.send(@check)
  end

  def condition_key_value_object(key_split)
    case key_split[0]
    when 'article'
      key_split.shift
      obj = @attribute_object.article
    when 'session'
      key_split.shift
      obj = user
    when attributes.class.to_s.downcase
      key_split.shift
      obj = attributes
    else
      obj = attributes
    end
    obj
  end

  def condition_key_value_tags(attribute, obj)
    return if !obj.instance_of?(Ticket)
    return if attribute != 'tags'

    params_tags = payload.dig('params', 'tags')
    tags        = obj.try(:tag_list)

    if @check == 'selected'
      tags += if params_tags.is_a?(Array)
                params_tags
              else
                params_tags.to_s.split(', ')
              end
    end
    tags
  end

  def condition_key_value_group_permissions(attribute, obj)
    return if !obj.instance_of?(User)
    return if attribute !~ %r{^group_ids_(full|create|change|read|overview)$}

    obj.group_ids_access($1)
  end

  def condition_key_value_obj(attribute, obj)
    obj.try(attribute.to_sym)
  end

  def condition_key_value(key)
    return Array(key) if key == 'custom.module'

    key_split = key.split('.')
    obj       = condition_key_value_object(key_split)
    key_split.each do |attribute|
      obj = condition_key_value_tags(attribute, obj) || condition_key_value_group_permissions(attribute, obj) || condition_key_value_obj(attribute, obj)
    end

    condition_value_result(obj)
  end

  def condition_value_result(obj)
    Array.wrap(obj).map do |v|
      if v.is_a?(Hash)
        v['value'].to_s.html2text
      else
        v.to_s.html2text
      end
    end
  end

  def condition_value_match?(key, condition, value)
    "CoreWorkflow::Condition::#{condition['operator'].tr(' ()', '_').camelize}".constantize&.new(condition_object: self, result_object: result_object, key: key, condition: condition, value: value)&.match
  end

  def pre_condition(condition)
    pre_condition_current_user(condition)
    pre_condition_not_set(condition)
  end

  def pre_condition_current_user(condition)
    return if condition['pre_condition'] != 'current_user.id'

    condition['value'] = [user.id.to_s]
  end

  def pre_condition_not_set(condition)
    return if condition['pre_condition'] != 'not_set'

    condition['operator'] = 'not_set'
  end

  def condition_match?(key, condition)
    pre_condition(condition)
    value_key = condition_key_value(key)
    condition_value_match?(key, condition, value_key)
  end

  def condition_selector_match?(selector)
    result = true
    selector.each do |key, value|
      next if condition_match?(key, value)

      result = false

      break
    end
    result
  end

  def condition_attributes_match?(check)
    @check = check

    condition = @workflow.send(:"condition_#{@check}")
    return true if condition.blank?

    condition_selector_match?(condition)
  end

  def object_match?
    return true if @workflow.object.blank?

    @workflow.object.include?(@payload['class_name'])
  end

  def screen_match?
    return true if @workflow.preferences['screen'].blank?

    Array(@workflow.preferences['screen']).include?(@payload['screen'])
  end

  def match_all?
    return if !object_match?
    return if !screen_match?
    return if !condition_attributes_match?('saved')
    return if !condition_attributes_match?('selected')

    true
  end
end