8.1 KiB
8.1 KiB
Code Context
Query: contact management, contact inbox, custom attribute definition, custom filter, contact merge, contact search, CRM, note, label
Entry Points
- AddRegexToCustomAttributeDefinition (class) - db/migrate/20230905060223_add_regex_to_custom_attribute_definition.rb:1
- CustomAttributeDefinition (class) - app/models/custom_attribute_definition.rb:24
- CustomAttributeDefinitionPolicy (class) - app/policies/custom_attribute_definition_policy.rb:1
Related Symbols
- app/models/application_record.rb: ApplicationRecord:1
- app/policies/application_policy.rb: ApplicationPolicy:1
- db/migrate/20230905060223_add_regex_to_custom_attribute_definition.rb: change:2
- app/models/custom_attribute_definition.rb: normalize_attribute_fields:54, sync_widget_pre_chat_custom_fields:59, update_widget_pre_chat_custom_fields:63, attribute_must_not_conflict:67
- app/policies/custom_attribute_definition_policy.rb: index?:2, show?:6, create?:10
Code
AddRegexToCustomAttributeDefinition (db/migrate/20230905060223_add_regex_to_custom_attribute_definition.rb:1)
class AddRegexToCustomAttributeDefinition < ActiveRecord::Migration[7.0]
def change
add_column :custom_attribute_definitions, :regex_pattern, :string
add_column :custom_attribute_definitions, :regex_cue, :string
end
end
CustomAttributeDefinition (app/models/custom_attribute_definition.rb:24)
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_
// ... truncated ...
CustomAttributeDefinitionPolicy (app/policies/custom_attribute_definition_policy.rb:1)
class CustomAttributeDefinitionPolicy < ApplicationPolicy
def index?
@account_user.administrator? || @account_user.agent?
end
def show?
@account_user.administrator? || @account_user.agent?
end
def create?
@account_user.administrator?
end
def update?
@account_user.administrator?
end
def destroy?
@account_user.administrator?
end
end
change (db/migrate/20230905060223_add_regex_to_custom_attribute_definition.rb:2)
def change
add_column :custom_attribute_definitions, :regex_pattern, :string
add_column :custom_attribute_definitions, :regex_cue, :string
end
normalize_attribute_fields (app/models/custom_attribute_definition.rb:54)
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
sync_widget_pre_chat_custom_fields (app/models/custom_attribute_definition.rb:59)
def sync_widget_pre_chat_custom_fields
::Inboxes::SyncWidgetPreChatCustomFieldsJob.perform_later(account, attribute_key)
end
update_widget_pre_chat_custom_fields (app/models/custom_attribute_definition.rb:63)
def update_widget_pre_chat_custom_fields
::Inboxes::UpdateWidgetPreChatCustomFieldsJob.perform_later(account, self)
end
attribute_must_not_conflict (app/models/custom_attribute_definition.rb:67)
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
index? (app/policies/custom_attribute_definition_policy.rb:2)
def index?
@account_user.administrator? || @account_user.agent?
end
show? (app/policies/custom_attribute_definition_policy.rb:6)
def show?
@account_user.administrator? || @account_user.agent?
end
create? (app/policies/custom_attribute_definition_policy.rb:10)
def create?
@account_user.administrator?
end
update? (app/policies/custom_attribute_definition_policy.rb:14)
def update?
@account_user.administrator?
end
destroy? (app/policies/custom_attribute_definition_policy.rb:18)
def destroy?
@account_user.administrator?
end
ApplicationRecord (app/models/application_record.rb:1)
class ApplicationRecord < ActiveRecord::Base
include Events::Types
self.abstract_class = true
before_validation :validates_column_content_length
# the models that exposed in email templates through liquid
def droppables
%w[Account Channel Conversation Inbox User Message]
end
# ModelDrop class should exist in app/drops
def to_drop
return unless droppables.include?(self.class.name)
"#{self.class.name}Drop".constantize.new(self)
end
private
# Generic validation for all columns of type string and text
# Validates the length of the column to prevent DOS via large payloads
# if a custom length validation is already present, skip the validation
def validates_column_content_length
self.class.columns.each do |column|
check_and_validate_content_length(column) if column_of_type_string_or_text?(column)
end
end
def column_of_type_string_or_text?(column)
%i[string text].include?(column.type)
end
def check_and_validate_content_length(column)
length_validator = self.class.validators_on(column.name).find { |v| v.kind == :length }
validate_content_length(column) if length_validator.blank?
end
def validate_content_length(column)
max_length = column.type == :text ? 20_000 : 255
return if self[column.name].nil? || self[column.name].length <= max_length
errors.add(column.name.to_sym, "is too long (maximum is #{max_length} characters)")
end
def normalize_empty_string_to_nil(attrs = [])
attrs
// ... truncated ...
ApplicationPolicy (app/policies/application_policy.rb:1)
class ApplicationPolicy
attr_reader :user_context, :user, :record, :account, :account_user
def initialize(user_context, record)
@user_context = user_context
@user = user_context[:user]
@account = user_context[:account]
@account_user = user_context[:account_user]
@record = record
end
def index?
false
end
def show?
scope.exists?(id: record.id)
end
def create?
false
end
def new?
create?
end
def update?
false
end
def edit?
update?
end
def destroy?
false
end
def scope
Pundit.policy_scope!(user_context, record.class)
end
class Scope
attr_reader :user_context, :user, :scope, :account, :account_user
def initialize(user_context, scope)
@user_context = user_context
@user = user_context[:user]
@account = user_context[:account]
@account_user = user_context[:account_user]
@scope = scope
end
def resolve
scope
end
end
end