Upgrade rails to 7.2.2 so that we can proceed with the rails 8 upgrade afterwards # Changelog - `.circleci/config.yml` — align CI DB setup with GitHub Actions (`db:create` + `db:schema:load`) to avoid trigger-dependent prep steps. - `.rubocop.yml` — add `rubocop-rspec_rails` and disable new cops that don't match existing spec style. - `AGENTS.md` — document that specs should run without `.env` (rename temporarily when present). - `Gemfile` — upgrade to Rails 7.2, switch Azure storage gem, pin `commonmarker`, bump `sidekiq-cron`, add `rubocop-rspec_rails`, and relax some gem pins. - `Gemfile.lock` — dependency lockfile updates from the Rails 7.2 and gem changes. - `app/controllers/api/v1/accounts/integrations/linear_controller.rb` — stringify params before passing to the Linear service to keep key types stable. - `app/controllers/super_admin/instance_statuses_controller.rb` — use `MigrationContext` API for migration status in Rails 7.2. - `app/models/installation_config.rb` — add commentary on YAML serialization and future JSONB migration (no behavior change). - `app/models/integrations/hook.rb` — ensure hook type is set on create only and guard against missing app. - `app/models/user.rb` — update enum syntax for Rails 7.2 deprecation, serialize OTP backup codes with JSON, and use Ruby `alias`. - `app/services/crm/leadsquared/setup_service.rb` — stringify hook settings keys before merge to keep JSON shape consistent. - `app/services/macros/execution_service.rb` — remove macro-specific assignee activity workaround; rely on standard assignment handlers. - `config/application.rb` — load Rails 7.2 defaults. - `config/storage.yml` — update Azure Active Storage service name to `AzureBlob`. - `db/migrate/20230515051424_update_article_image_keys.rb` — use credentials `secret_key_base` with fallback to legacy secrets. - `docker/Dockerfile` — add `yaml-dev` and `pkgconf` packages for native extensions (Ruby 3.4 / psych). - `lib/seeders/reports/message_creator.rb` — add parentheses for clarity in range calculation. - `package.json` — pin Vite version and bump `vite-plugin-ruby`. - `pnpm-lock.yaml` — lockfile changes from JS dependency updates. - `spec/builders/v2/report_builder_spec.rb` — disable transactional fixtures; truncate tables per example via Rails `truncate_tables` so after_commit callbacks run with clean isolation; keep builder spec metadata minimal. - `spec/builders/v2/reports/label_summary_builder_spec.rb` — disable transactional fixtures + truncate tables via Rails `truncate_tables`; revert to real `resolved!`/`open!`/`resolved!` flow for multiple resolution events; align date range to `Time.zone` to avoid offset gaps; keep builder spec metadata minimal. - `spec/controllers/api/v1/accounts/macros_controller_spec.rb` — assert `assignee_id` instead of activity message to avoid transaction-timing flakes. - `spec/services/telegram/incoming_message_service_spec.rb` — reference the contact tied to the created conversation instead of `Contact.all.first` to avoid order-dependent failures when other specs leave data behind. - `spec/mailers/administrator_notifications/shared/smtp_config_shared.rb` — use `with_modified_env` instead of stubbing mailer internals. - `spec/services/account/sign_up_email_validation_service_spec.rb` — compare error `class.name` for parallel/reload-safe assertions.
113 lines
3.1 KiB
Ruby
113 lines
3.1 KiB
Ruby
# == Schema Information
|
|
#
|
|
# Table name: integrations_hooks
|
|
#
|
|
# id :bigint not null, primary key
|
|
# access_token :string
|
|
# hook_type :integer default("account")
|
|
# settings :jsonb
|
|
# status :integer default("enabled")
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# account_id :integer
|
|
# app_id :string
|
|
# inbox_id :integer
|
|
# reference_id :string
|
|
#
|
|
class Integrations::Hook < ApplicationRecord
|
|
include Reauthorizable
|
|
|
|
attr_readonly :app_id, :account_id, :inbox_id, :hook_type
|
|
before_validation :ensure_hook_type, on: :create
|
|
after_create :trigger_setup_if_crm
|
|
|
|
# TODO: Remove guard once encryption keys become mandatory (target 3-4 releases out).
|
|
encrypts :access_token, deterministic: true if Chatwoot.encryption_configured?
|
|
|
|
validates :account_id, presence: true
|
|
validates :app_id, presence: true
|
|
validates :inbox_id, presence: true, if: -> { hook_type == 'inbox' }
|
|
validate :validate_settings_json_schema
|
|
validate :ensure_feature_enabled
|
|
validates :app_id, uniqueness: { scope: [:account_id], unless: -> { app.present? && app.params[:allow_multiple_hooks].present? } }
|
|
|
|
# TODO: This seems to be only used for slack at the moment
|
|
# We can add a validator when storing the integration settings and toggle this in future
|
|
enum status: { disabled: 0, enabled: 1 }
|
|
|
|
belongs_to :account
|
|
belongs_to :inbox, optional: true
|
|
has_secure_token :access_token
|
|
|
|
enum hook_type: { account: 0, inbox: 1 }
|
|
|
|
scope :account_hooks, -> { where(hook_type: 'account') }
|
|
scope :inbox_hooks, -> { where(hook_type: 'inbox') }
|
|
|
|
def app
|
|
@app ||= Integrations::App.find(id: app_id)
|
|
end
|
|
|
|
def slack?
|
|
app_id == 'slack'
|
|
end
|
|
|
|
def dialogflow?
|
|
app_id == 'dialogflow'
|
|
end
|
|
|
|
def notion?
|
|
app_id == 'notion'
|
|
end
|
|
|
|
def disable
|
|
update(status: 'disabled')
|
|
end
|
|
|
|
def process_event(_event)
|
|
# OpenAI integration migrated to Captain::EditorService
|
|
# Other integrations (slack, dialogflow, etc.) handled via HookJob
|
|
{ error: 'No processor found' }
|
|
end
|
|
|
|
def feature_allowed?
|
|
return true if app.blank?
|
|
|
|
flag = app.params[:feature_flag]
|
|
return true unless flag
|
|
|
|
account.feature_enabled?(flag)
|
|
end
|
|
|
|
private
|
|
|
|
def ensure_feature_enabled
|
|
errors.add(:feature_flag, 'Feature not enabled') unless feature_allowed?
|
|
end
|
|
|
|
def ensure_hook_type
|
|
return if app.blank?
|
|
|
|
self.hook_type = app.params[:hook_type]
|
|
end
|
|
|
|
def validate_settings_json_schema
|
|
return if app.blank? || app.params[:settings_json_schema].blank?
|
|
|
|
errors.add(:settings, ': Invalid settings data') unless JSONSchemer.schema(app.params[:settings_json_schema]).valid?(settings)
|
|
end
|
|
|
|
def trigger_setup_if_crm
|
|
# we need setup services to create data prerequisite to functioning of the integration
|
|
# in case of Leadsquared, we need to create a custom activity type for capturing conversations and transcripts
|
|
# https://apidocs.leadsquared.com/create-new-activity-type-api/
|
|
return unless crm_integration?
|
|
|
|
::Crm::SetupJob.perform_later(id)
|
|
end
|
|
|
|
def crm_integration?
|
|
%w[leadsquared].include?(app_id)
|
|
end
|
|
end
|