12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- class Validations::ChannelEmailAccountUniquenessValidator < ActiveModel::Validator
- MATCHED_KEYS = %i[adapter].freeze
- MATCHED_OPTIONS_KEYS = %i[host port user folder].freeze
- MATCHED_AREAS = %w[Email::Account Google::Account Microsoft365::Account].freeze
- def validate(record)
- return if MATCHED_AREAS.exclude?(record.area)
- return if !matching_changes?(record)
- record_data = extract_matched_data(record.options)
- return if scope(record).none? { matches?(record_data, _1) }
- record.errors.add :base, __('The provided email account is already in use.')
- end
- private
- # https://github.com/zammad/zammad/issues/5111
- # Some systems may have duplicate channels created before this validation was added
- # Checking uniqueness on any update blocks XOAuth2 token update on such channels
- def matching_changes?(record)
- extract_matched_data(record.options) != extract_matched_data(record.options_was)
- end
- def scope(record)
- record
- .class
- .where(area: record.area)
- .then { record.persisted? ? _1.where.not(id: record.id) : _1 }
- end
- def matches?(record_data, other_record)
- other_record_data = extract_matched_data(other_record.options)
- return false if other_record_data.blank?
- record_data == other_record_data
- end
- def extract_matched_data(options)
- server_data = options&.dig(:inbound)
- return if !server_data
- values = server_data.slice(*MATCHED_KEYS)
- options_values = server_data[:options]&.slice(*MATCHED_OPTIONS_KEYS) || {}
- values
- .merge(options_values)
- .transform_values(&:to_s)
- end
- end
|