## Description Adds the account-level `unread_count_for_filters` feature flag as the dark-launch gate for filtered sidebar unread counts. This reuses the deprecated `quoted_email_reply` flag slot, resets the reused bit for existing accounts, and removes stale defaults so new accounts do not reference the old flag. This also adds the feature where we are now calculating the unread counts for built in filters like mentions, participating and unattended along with unread count for saved filters/folders. Closes [CW-7262](https://linear.app/chatwoot/issue/CW-7262/unread-counts-for-filters-folders) ## Type of change - [ ] Bug fix (non-breaking change which fixes an issue) - [x] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality not to work as expected) - [ ] This change requires a documentation update
101 lines
4.2 KiB
Ruby
101 lines
4.2 KiB
Ruby
# == Schema Information
|
|
#
|
|
# Table name: custom_attribute_definitions
|
|
#
|
|
# id :bigint not null, primary key
|
|
# attribute_description :text
|
|
# attribute_display_name :string
|
|
# attribute_display_type :integer default("text")
|
|
# attribute_key :string
|
|
# attribute_model :integer default("conversation_attribute")
|
|
# attribute_values :jsonb
|
|
# default_value :integer
|
|
# regex_cue :string
|
|
# regex_pattern :string
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# account_id :bigint
|
|
#
|
|
# Indexes
|
|
#
|
|
# attribute_key_model_index (attribute_key,attribute_model,account_id) UNIQUE
|
|
# index_custom_attribute_definitions_on_account_id (account_id)
|
|
#
|
|
class CustomAttributeDefinition < ApplicationRecord
|
|
STANDARD_ATTRIBUTES = {
|
|
:conversation => %w[status priority assignee_id inbox_id team_id display_id campaign_id labels browser_language country_code referer created_at
|
|
last_activity_at],
|
|
:contact => %w[name email phone_number identifier country_code city company_name created_at last_activity_at referer blocked],
|
|
:company => %w[name domain description contacts_count created_at updated_at last_activity_at]
|
|
}.freeze
|
|
|
|
scope :with_attribute_model, ->(attribute_model) { attribute_model.presence && where(attribute_model: attribute_model) }
|
|
validates :attribute_display_name, presence: true
|
|
before_validation :normalize_attribute_fields
|
|
|
|
validates :attribute_key,
|
|
presence: true,
|
|
uniqueness: { scope: [:account_id, :attribute_model] },
|
|
format: { with: /\A[\p{L}\p{N}_.\-]+\z/, message: I18n.t('errors.custom_attribute_definition.attribute_key_format') }
|
|
|
|
validates :attribute_display_type, presence: true
|
|
validates :attribute_model, presence: true
|
|
validate :attribute_must_not_conflict, on: :create
|
|
|
|
enum attribute_model: { conversation_attribute: 0, contact_attribute: 1, company_attribute: 2 }
|
|
enum attribute_display_type: { text: 0, number: 1, currency: 2, percent: 3, link: 4, date: 5, list: 6, checkbox: 7 }
|
|
|
|
belongs_to :account
|
|
after_update :update_widget_pre_chat_custom_fields, unless: :company_attribute?
|
|
after_destroy :sync_widget_pre_chat_custom_fields, unless: :company_attribute?
|
|
after_update_commit :invalidate_filtered_unread_count_filters_update, if: :conversation_attribute_before_or_after?
|
|
after_destroy_commit :invalidate_filtered_unread_count_filters_destroy, if: :conversation_attribute?
|
|
|
|
private
|
|
|
|
def normalize_attribute_fields
|
|
self.attribute_key = attribute_key.strip if attribute_key.present?
|
|
self.attribute_display_name = attribute_display_name.strip if attribute_display_name.present?
|
|
end
|
|
|
|
def sync_widget_pre_chat_custom_fields
|
|
::Inboxes::SyncWidgetPreChatCustomFieldsJob.perform_later(account, attribute_key)
|
|
end
|
|
|
|
def update_widget_pre_chat_custom_fields
|
|
::Inboxes::UpdateWidgetPreChatCustomFieldsJob.perform_later(account, self)
|
|
end
|
|
|
|
def invalidate_filtered_unread_count_filters_update
|
|
invalidate_filtered_unread_count_filters
|
|
end
|
|
|
|
def invalidate_filtered_unread_count_filters_destroy
|
|
invalidate_filtered_unread_count_filters
|
|
end
|
|
|
|
def invalidate_filtered_unread_count_filters
|
|
filters_changed = ::Conversations::UnreadCounts::FilteredCountInvalidator.new(account).custom_attribute_definition_changed!(self)
|
|
dispatch_account_cache_invalidated if filters_changed
|
|
end
|
|
|
|
def dispatch_account_cache_invalidated
|
|
Rails.configuration.dispatcher.dispatch(ACCOUNT_CACHE_INVALIDATED, Time.zone.now, account: account, cache_keys: account.cache_keys)
|
|
end
|
|
|
|
def conversation_attribute_before_or_after?
|
|
conversation_attribute? || attribute_model_previously_was == 'conversation_attribute'
|
|
end
|
|
|
|
def attribute_must_not_conflict
|
|
model_keys = attribute_model.to_s.delete_suffix('_attribute').to_sym
|
|
standard_attributes = STANDARD_ATTRIBUTES[model_keys]
|
|
return if standard_attributes.blank?
|
|
return unless attribute_key.in?(standard_attributes)
|
|
|
|
errors.add(:attribute_key, I18n.t('errors.custom_attribute_definition.key_conflict'))
|
|
end
|
|
end
|
|
|
|
CustomAttributeDefinition.include_mod_with('Concerns::CustomAttributeDefinition')
|