Revert "chore: Upgrade Rails to 7.2.2 and update Gemfile dependencies (#11037)"

This reverts commit ef6ba8aabd.
This commit is contained in:
Sojan Jose
2026-02-03 21:09:42 -08:00
parent ef6ba8aabd
commit 9eb3ee44a8
28 changed files with 311 additions and 360 deletions

View File

@@ -279,10 +279,10 @@ jobs:
echo -en "\nINSTALLATION_ENV=circleci" >> ".env" echo -en "\nINSTALLATION_ENV=circleci" >> ".env"
echo -en "\nOPENSEARCH_URL=http://localhost:9200" >> ".env" echo -en "\nOPENSEARCH_URL=http://localhost:9200" >> ".env"
# Database setup (match GitHub Actions flow) # Database setup
- run: - run:
name: Create database + load schema name: Run DB migrations
command: bundle exec rake db:create db:schema:load command: bundle exec rails db:chatwoot_prepare
# Run backend tests (parallelized) # Run backend tests (parallelized)
- run: - run:

View File

@@ -2,7 +2,6 @@ plugins:
- rubocop-performance - rubocop-performance
- rubocop-rails - rubocop-rails
- rubocop-rspec - rubocop-rspec
- rubocop-rspec_rails
- rubocop-factory_bot - rubocop-factory_bot
require: require:
@@ -204,12 +203,6 @@ RSpec/MultipleExpectations:
RSpec/MultipleMemoizedHelpers: RSpec/MultipleMemoizedHelpers:
Max: 14 Max: 14
RSpecRails/InferredSpecType:
Enabled: false
RSpecRails/NegationBeValid:
Enabled: false
# custom rules # custom rules
UseFromEmail: UseFromEmail:
Enabled: true Enabled: true

View File

@@ -13,7 +13,6 @@
- **Ruby Version**: Manage Ruby via `rbenv` and install the version listed in `.ruby-version` (e.g., `rbenv install $(cat .ruby-version)`) - **Ruby Version**: Manage Ruby via `rbenv` and install the version listed in `.ruby-version` (e.g., `rbenv install $(cat .ruby-version)`)
- **rbenv setup**: Before running any `bundle` or `rspec` commands, init rbenv in your shell (`eval "$(rbenv init -)"`) so the correct Ruby/Bundler versions are used - **rbenv setup**: Before running any `bundle` or `rspec` commands, init rbenv in your shell (`eval "$(rbenv init -)"`) so the correct Ruby/Bundler versions are used
- Always prefer `bundle exec` for Ruby CLI tasks (rspec, rake, rubocop, etc.) - Always prefer `bundle exec` for Ruby CLI tasks (rspec, rake, rubocop, etc.)
- **Test env**: Specs should run without `.env`. If present, temporarily rename it (e.g., `.env` -> `.env.bak`) while running specs and restore afterward.
## Code Style ## Code Style

23
Gemfile
View File

@@ -3,10 +3,8 @@ source 'https://rubygems.org'
ruby '3.4.4' ruby '3.4.4'
##-- base gems for rails --## ##-- base gems for rails --##
gem 'rack-cors', '2.0.0', require: 'rack/cors'
gem 'rack-cors', require: 'rack/cors' gem 'rails', '~> 7.1'
gem 'rails', '~> 7.2.0'
# Reduces boot times through caching; required in config/boot.rb # Reduces boot times through caching; required in config/boot.rb
gem 'bootsnap', require: false gem 'bootsnap', require: false
@@ -33,9 +31,7 @@ gem 'haikunator'
# Template parsing safely # Template parsing safely
gem 'liquid' gem 'liquid'
# Parse Markdown to HTML # Parse Markdown to HTML
# ref: https://github.com/gjtorikian/commonmarker/issues/358 gem 'commonmarker'
# can upgrade one this issue is fixed
gem 'commonmarker', '~> 0.23.11'
# Validate Data against JSON Schema # Validate Data against JSON Schema
gem 'json_schemer' gem 'json_schemer'
# used in swagger build # used in swagger build
@@ -53,7 +49,9 @@ gem 'csv-safe'
##-- for active storage --## ##-- for active storage --##
gem 'aws-sdk-s3', require: false gem 'aws-sdk-s3', require: false
gem 'azure-blob', require: false # original gem isn't maintained actively
# we wanted updated version of faraday which is a dependency for slack-ruby-client
gem 'azure-storage-blob', git: 'https://github.com/chatwoot/azure-storage-ruby', branch: 'chatwoot', require: false
gem 'google-cloud-storage', '>= 1.48.0', require: false gem 'google-cloud-storage', '>= 1.48.0', require: false
gem 'image_processing' gem 'image_processing'
@@ -91,9 +89,9 @@ gem 'jwt'
gem 'pundit' gem 'pundit'
# super admin # super admin
gem 'administrate' gem 'administrate', '>= 0.20.1'
gem 'administrate-field-active_storage' gem 'administrate-field-active_storage', '>= 1.0.3'
gem 'administrate-field-belongs_to_search' gem 'administrate-field-belongs_to_search', '>= 0.9.0'
##--- gems for pubsub service ---## ##--- gems for pubsub service ---##
# https://karolgalanciak.com/blog/2019/11/30/from-activerecord-callbacks-to-publish-slash-subscribe-pattern-and-event-driven-design/ # https://karolgalanciak.com/blog/2019/11/30/from-activerecord-callbacks-to-publish-slash-subscribe-pattern-and-event-driven-design/
@@ -133,7 +131,7 @@ gem 'sentry-sidekiq', '>= 5.19.0', require: false
##-- background job processing --## ##-- background job processing --##
gem 'sidekiq', '>= 7.3.1' gem 'sidekiq', '>= 7.3.1'
# We want cron jobs # We want cron jobs
gem 'sidekiq-cron', '>= 2.3.1' gem 'sidekiq-cron', '>= 1.12.0'
# for sidekiq healthcheck # for sidekiq healthcheck
gem 'sidekiq_alive' gem 'sidekiq_alive'
@@ -264,7 +262,6 @@ group :development, :test do
gem 'rubocop-performance', require: false gem 'rubocop-performance', require: false
gem 'rubocop-rails', require: false gem 'rubocop-rails', require: false
gem 'rubocop-rspec', require: false gem 'rubocop-rspec', require: false
gem 'rubocop-rspec_rails', require: false
gem 'rubocop-factory_bot', require: false gem 'rubocop-factory_bot', require: false
gem 'seed_dump' gem 'seed_dump'
gem 'shoulda-matchers' gem 'shoulda-matchers'

View File

@@ -1,89 +1,110 @@
GIT GIT
remote: https://github.com/chatwoot/devise-secure_password remote: https://github.com/chatwoot/azure-storage-ruby
revision: 479987594b576dbf23aed8dbd962e78342bc683c revision: 9957cf899d33a285b5dfe15bdb875292398e392b
branch: chatwoot branch: chatwoot
specs: specs:
devise-secure_password (2.1.0) azure-storage-blob (2.0.3)
azure-storage-common (~> 2.0)
nokogiri (~> 1, >= 1.10.8)
azure-storage-common (2.0.4)
faraday (~> 2.0)
faraday-follow_redirects (~> 0.3.0)
faraday-net_http_persistent (~> 2.0)
net-http-persistent (~> 4.0)
nokogiri (~> 1, >= 1.10.8)
GIT
remote: https://github.com/chatwoot/devise-secure_password
revision: adcc85fe1babfe40feae73dbcae64d14fff86e69
branch: chatwoot
specs:
devise-secure_password (2.0.1)
devise (>= 4.0.0, < 5.0.0) devise (>= 4.0.0, < 5.0.0)
railties (>= 5.0.0, < 8.0.0) railties (>= 5.0.0, < 8.0.0)
GEM GEM
remote: https://rubygems.org/ remote: https://rubygems.org/
specs: specs:
actioncable (7.2.2.2) actioncable (7.1.5.2)
actionpack (= 7.2.2.2) actionpack (= 7.1.5.2)
activesupport (= 7.2.2.2) activesupport (= 7.1.5.2)
nio4r (~> 2.0) nio4r (~> 2.0)
websocket-driver (>= 0.6.1) websocket-driver (>= 0.6.1)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
actionmailbox (7.2.2.2) actionmailbox (7.1.5.2)
actionpack (= 7.2.2.2) actionpack (= 7.1.5.2)
activejob (= 7.2.2.2) activejob (= 7.1.5.2)
activerecord (= 7.2.2.2) activerecord (= 7.1.5.2)
activestorage (= 7.2.2.2) activestorage (= 7.1.5.2)
activesupport (= 7.2.2.2) activesupport (= 7.1.5.2)
mail (>= 2.8.0) mail (>= 2.7.1)
actionmailer (7.2.2.2) net-imap
actionpack (= 7.2.2.2) net-pop
actionview (= 7.2.2.2) net-smtp
activejob (= 7.2.2.2) actionmailer (7.1.5.2)
activesupport (= 7.2.2.2) actionpack (= 7.1.5.2)
mail (>= 2.8.0) actionview (= 7.1.5.2)
activejob (= 7.1.5.2)
activesupport (= 7.1.5.2)
mail (~> 2.5, >= 2.5.4)
net-imap
net-pop
net-smtp
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
actionpack (7.2.2.2) actionpack (7.1.5.2)
actionview (= 7.2.2.2) actionview (= 7.1.5.2)
activesupport (= 7.2.2.2) activesupport (= 7.1.5.2)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
racc racc
rack (>= 2.2.4, < 3.2) rack (>= 2.2.4)
rack-session (>= 1.0.1) rack-session (>= 1.0.1)
rack-test (>= 0.6.3) rack-test (>= 0.6.3)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
useragent (~> 0.16) actiontext (7.1.5.2)
actiontext (7.2.2.2) actionpack (= 7.1.5.2)
actionpack (= 7.2.2.2) activerecord (= 7.1.5.2)
activerecord (= 7.2.2.2) activestorage (= 7.1.5.2)
activestorage (= 7.2.2.2) activesupport (= 7.1.5.2)
activesupport (= 7.2.2.2)
globalid (>= 0.6.0) globalid (>= 0.6.0)
nokogiri (>= 1.8.5) nokogiri (>= 1.8.5)
actionview (7.2.2.2) actionview (7.1.5.2)
activesupport (= 7.2.2.2) activesupport (= 7.1.5.2)
builder (~> 3.1) builder (~> 3.1)
erubi (~> 1.11) erubi (~> 1.11)
rails-dom-testing (~> 2.2) rails-dom-testing (~> 2.2)
rails-html-sanitizer (~> 1.6) rails-html-sanitizer (~> 1.6)
active_record_query_trace (1.8) active_record_query_trace (1.8)
activejob (7.2.2.2) activejob (7.1.5.2)
activesupport (= 7.2.2.2) activesupport (= 7.1.5.2)
globalid (>= 0.3.6) globalid (>= 0.3.6)
activemodel (7.2.2.2) activemodel (7.1.5.2)
activesupport (= 7.2.2.2) activesupport (= 7.1.5.2)
activerecord (7.2.2.2) activerecord (7.1.5.2)
activemodel (= 7.2.2.2) activemodel (= 7.1.5.2)
activesupport (= 7.2.2.2) activesupport (= 7.1.5.2)
timeout (>= 0.4.0) timeout (>= 0.4.0)
activerecord-import (2.1.0) activerecord-import (2.1.0)
activerecord (>= 4.2) activerecord (>= 4.2)
activestorage (7.2.2.2) activestorage (7.1.5.2)
actionpack (= 7.2.2.2) actionpack (= 7.1.5.2)
activejob (= 7.2.2.2) activejob (= 7.1.5.2)
activerecord (= 7.2.2.2) activerecord (= 7.1.5.2)
activesupport (= 7.2.2.2) activesupport (= 7.1.5.2)
marcel (~> 1.0) marcel (~> 1.0)
activesupport (7.2.2.2) activesupport (7.1.5.2)
base64 base64
benchmark (>= 0.3) benchmark (>= 0.3)
bigdecimal bigdecimal
concurrent-ruby (~> 1.0, >= 1.3.1) concurrent-ruby (~> 1.0, >= 1.0.2)
connection_pool (>= 2.2.5) connection_pool (>= 2.2.5)
drb drb
i18n (>= 1.6, < 2) i18n (>= 1.6, < 2)
logger (>= 1.4.2) logger (>= 1.4.2)
minitest (>= 5.1) minitest (>= 5.1)
mutex_m
securerandom (>= 0.3) securerandom (>= 0.3)
tzinfo (~> 2.0, >= 2.0.5) tzinfo (~> 2.0)
acts-as-taggable-on (12.0.0) acts-as-taggable-on (12.0.0)
activerecord (>= 7.1, < 8.1) activerecord (>= 7.1, < 8.1)
zeitwerk (>= 2.4, < 3.0) zeitwerk (>= 2.4, < 3.0)
@@ -100,10 +121,10 @@ GEM
administrate-field-active_storage (1.0.3) administrate-field-active_storage (1.0.3)
administrate (>= 0.2.2) administrate (>= 0.2.2)
rails (>= 7.0) rails (>= 7.0)
administrate-field-belongs_to_search (0.10.0) administrate-field-belongs_to_search (0.9.0)
administrate (>= 0.3, < 1.0) administrate (>= 0.3, < 1.0)
jbuilder (~> 2) jbuilder (~> 2)
rails (>= 4.2, < 8.0) rails (>= 4.2, < 7.2)
selectize-rails (~> 0.6) selectize-rails (~> 0.6)
ai-agents (0.7.0) ai-agents (0.7.0)
ruby_llm (~> 1.8.2) ruby_llm (~> 1.8.2)
@@ -120,8 +141,8 @@ GEM
aws-sdk-s3 (~> 1, >= 1.123.0) aws-sdk-s3 (~> 1, >= 1.123.0)
aws-sdk-sns (~> 1, >= 1.61.0) aws-sdk-sns (~> 1, >= 1.61.0)
aws-eventstream (1.4.0) aws-eventstream (1.4.0)
aws-partitions (1.1205.0) aws-partitions (1.1198.0)
aws-sdk-core (3.241.3) aws-sdk-core (3.240.0)
aws-eventstream (~> 1, >= 1.3.0) aws-eventstream (~> 1, >= 1.3.0)
aws-partitions (~> 1, >= 1.992.0) aws-partitions (~> 1, >= 1.992.0)
aws-sigv4 (~> 1.9) aws-sigv4 (~> 1.9)
@@ -129,11 +150,11 @@ GEM
bigdecimal bigdecimal
jmespath (~> 1, >= 1.6.1) jmespath (~> 1, >= 1.6.1)
logger logger
aws-sdk-kms (1.120.0) aws-sdk-kms (1.118.0)
aws-sdk-core (~> 3, >= 3.241.3) aws-sdk-core (~> 3, >= 3.239.1)
aws-sigv4 (~> 1.5) aws-sigv4 (~> 1.5)
aws-sdk-s3 (1.211.0) aws-sdk-s3 (1.208.0)
aws-sdk-core (~> 3, >= 3.241.3) aws-sdk-core (~> 3, >= 3.234.0)
aws-sdk-kms (~> 1) aws-sdk-kms (~> 1)
aws-sigv4 (~> 1.5) aws-sigv4 (~> 1.5)
aws-sdk-sns (1.70.0) aws-sdk-sns (1.70.0)
@@ -141,22 +162,20 @@ GEM
aws-sigv4 (~> 1.1) aws-sigv4 (~> 1.1)
aws-sigv4 (1.12.1) aws-sigv4 (1.12.1)
aws-eventstream (~> 1, >= 1.0.2) aws-eventstream (~> 1, >= 1.0.2)
azure-blob (0.5.9.1)
rexml
barnes (0.0.9) barnes (0.0.9)
multi_json (~> 1) multi_json (~> 1)
statsd-ruby (~> 1.1) statsd-ruby (~> 1.1)
base64 (0.3.0) base64 (0.3.0)
bcrypt (3.1.20) bcrypt (3.1.20)
benchmark (0.5.0) benchmark (0.4.1)
bigdecimal (4.0.1) bigdecimal (3.2.2)
bindex (0.8.1) bindex (0.8.1)
bootsnap (1.16.0) bootsnap (1.16.0)
msgpack (~> 1.2) msgpack (~> 1.2)
brakeman (5.4.1) brakeman (5.4.1)
browser (5.3.1) browser (5.3.1)
builder (3.3.0) builder (3.3.0)
bullet (7.2.0) bullet (8.0.7)
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
uniform_notifier (~> 1.11) uniform_notifier (~> 1.11)
bundle-audit (0.1.0) bundle-audit (0.1.0)
@@ -165,21 +184,17 @@ GEM
bundler (>= 1.2.0, < 3) bundler (>= 1.2.0, < 3)
thor (~> 1.0) thor (~> 1.0)
byebug (11.1.3) byebug (11.1.3)
cgi (0.5.1)
childprocess (5.1.0) childprocess (5.1.0)
logger (~> 1.5) logger (~> 1.5)
climate_control (1.2.0) climate_control (1.2.0)
coderay (1.1.3) coderay (1.1.3)
commonmarker (0.23.11) commonmarker (0.23.10)
concurrent-ruby (1.3.6) concurrent-ruby (1.3.5)
connection_pool (3.0.2) connection_pool (2.5.3)
crack (1.0.0) crack (1.0.0)
bigdecimal bigdecimal
rexml rexml
crass (1.0.6) crass (1.0.6)
cronex (0.15.0)
tzinfo
unicode (>= 0.4.4.5)
csv (3.3.0) csv (3.3.0)
csv-safe (3.3.1) csv-safe (3.3.1)
csv (~> 3.0) csv (~> 3.0)
@@ -189,15 +204,14 @@ GEM
activerecord (>= 5.a) activerecord (>= 5.a)
database_cleaner-core (~> 2.0.0) database_cleaner-core (~> 2.0.0)
database_cleaner-core (2.0.1) database_cleaner-core (2.0.1)
datadog (2.25.0) datadog (2.19.0)
cgi datadog-ruby_core_source (~> 3.4, >= 3.4.1)
datadog-ruby_core_source (~> 3.5, >= 3.5.0) libdatadog (~> 18.1.0.1.0)
libdatadog (~> 24.0.1.1.0) libddwaf (~> 1.24.1.0.3)
libddwaf (~> 1.30.0.0.0)
logger logger
msgpack msgpack
datadog-ruby_core_source (3.5.1) datadog-ruby_core_source (3.4.1)
date (3.5.1) date (3.4.1)
debug (1.8.0) debug (1.8.0)
irb (>= 1.5.0) irb (>= 1.5.0)
reline (>= 0.3.1) reline (>= 0.3.1)
@@ -208,10 +222,10 @@ GEM
railties (>= 4.1.0) railties (>= 4.1.0)
responders responders
warden (~> 1.2.3) warden (~> 1.2.3)
devise-two-factor (6.3.0) devise-two-factor (6.1.0)
activesupport (>= 7.0, < 8.2) activesupport (>= 7.0, < 8.1)
devise (>= 4.0, < 5.0) devise (~> 4.0)
railties (>= 7.0, < 8.2) railties (>= 7.0, < 8.1)
rotp (~> 6.0) rotp (~> 6.0)
devise_token_auth (1.2.5) devise_token_auth (1.2.5)
bcrypt (~> 3.0) bcrypt (~> 3.0)
@@ -230,31 +244,31 @@ GEM
down (5.4.0) down (5.4.0)
addressable (~> 2.8) addressable (~> 2.8)
drb (2.2.3) drb (2.2.3)
dry-cli (1.4.1) dry-cli (1.1.0)
dry-configurable (1.3.0) dry-configurable (1.3.0)
dry-core (~> 1.1) dry-core (~> 1.1)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
dry-core (1.2.0) dry-core (1.1.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
logger logger
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
dry-inflector (1.3.1) dry-inflector (1.2.0)
dry-initializer (3.2.0) dry-initializer (3.2.0)
dry-logic (1.6.0) dry-logic (1.6.0)
bigdecimal bigdecimal
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
dry-core (~> 1.1) dry-core (~> 1.1)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
dry-schema (1.15.0) dry-schema (1.14.1)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
dry-configurable (~> 1.0, >= 1.0.1) dry-configurable (~> 1.0, >= 1.0.1)
dry-core (~> 1.1) dry-core (~> 1.1)
dry-initializer (~> 3.2) dry-initializer (~> 3.2)
dry-logic (~> 1.6) dry-logic (~> 1.5)
dry-types (~> 1.8) dry-types (~> 1.8)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
dry-types (1.9.0) dry-types (1.8.3)
bigdecimal (>= 3.0) bigdecimal (~> 3.0)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
dry-core (~> 1.0) dry-core (~> 1.0)
dry-inflector (~> 1.0) dry-inflector (~> 1.0)
@@ -268,9 +282,8 @@ GEM
ruby2_keywords ruby2_keywords
email-provider-info (0.0.1) email-provider-info (0.0.1)
email_reply_trimmer (0.1.13) email_reply_trimmer (0.1.13)
erb (6.0.1) erubi (1.13.0)
erubi (1.13.1) et-orbi (1.2.11)
et-orbi (1.3.0)
tzinfo tzinfo
event_stream_parser (1.0.0) event_stream_parser (1.0.0)
execjs (2.8.1) execjs (2.8.1)
@@ -284,27 +297,34 @@ GEM
railties (>= 5.0.0) railties (>= 5.0.0)
faker (3.2.0) faker (3.2.0)
i18n (>= 1.8.11, < 2) i18n (>= 1.8.11, < 2)
faraday (2.9.0) faraday (2.13.1)
faraday-net_http (>= 2.0, < 3.2) faraday-net_http (>= 2.0, < 3.5)
faraday-mashify (1.0.2) json
logger
faraday-follow_redirects (0.3.0)
faraday (>= 1, < 3)
faraday-mashify (1.0.0)
faraday (~> 2.0) faraday (~> 2.0)
hashie hashie
faraday-multipart (1.0.4) faraday-multipart (1.0.4)
multipart-post (~> 2) multipart-post (~> 2)
faraday-net_http (3.1.0) faraday-net_http (3.4.0)
net-http net-http (>= 0.5.0)
faraday-net_http_persistent (2.1.0)
faraday (~> 2.5)
net-http-persistent (~> 4.0)
faraday-retry (2.2.1) faraday-retry (2.2.1)
faraday (~> 2.0) faraday (~> 2.0)
faraday_middleware-aws-sigv4 (1.0.1) faraday_middleware-aws-sigv4 (1.0.1)
aws-sigv4 (~> 1.0) aws-sigv4 (~> 1.0)
faraday (>= 2.0, < 3) faraday (>= 2.0, < 3)
fast-mcp (1.6.0) fast-mcp (1.5.0)
addressable (~> 2.8) addressable (~> 2.8)
base64 base64
dry-schema (~> 1.14) dry-schema (~> 1.14)
json (~> 2.0) json (~> 2.0)
mime-types (~> 3.4) mime-types (~> 3.4)
rack (>= 2.0, < 4.0) rack (~> 3.1)
fcm (1.0.8) fcm (1.0.8)
faraday (>= 1.0.0, < 3.0) faraday (>= 1.0.0, < 3.0)
googleauth (~> 1) googleauth (~> 1)
@@ -421,21 +441,19 @@ GEM
http-cookie (1.0.5) http-cookie (1.0.5)
domain_name (~> 0.5) domain_name (~> 0.5)
http-form_data (2.3.0) http-form_data (2.3.0)
httparty (0.24.2) httparty (0.24.0)
csv csv
mini_mime (>= 1.0.0) mini_mime (>= 1.0.0)
multi_xml (>= 0.5.2) multi_xml (>= 0.5.2)
httpclient (2.8.3) httpclient (2.8.3)
i18n (1.14.8) i18n (1.14.7)
concurrent-ruby (~> 1.0) concurrent-ruby (~> 1.0)
image_processing (1.12.2) image_processing (1.12.2)
mini_magick (>= 4.9.5, < 5) mini_magick (>= 4.9.5, < 5)
ruby-vips (>= 2.0.17, < 3) ruby-vips (>= 2.0.17, < 3)
io-console (0.8.2) io-console (0.6.0)
irb (1.16.0) irb (1.7.2)
pp (>= 0.6.0) reline (>= 0.3.6)
rdoc (>= 4.0.0)
reline (>= 0.4.2)
iso-639 (0.3.8) iso-639 (0.3.8)
csv csv
jbuilder (2.11.5) jbuilder (2.11.5)
@@ -446,7 +464,7 @@ GEM
rails-dom-testing (>= 1, < 3) rails-dom-testing (>= 1, < 3)
railties (>= 4.2.0) railties (>= 4.2.0)
thor (>= 0.14, < 2.0) thor (>= 0.14, < 2.0)
json (2.12.0) json (2.13.2)
json_refs (0.1.8) json_refs (0.1.8)
hana hana
json_schemer (0.2.24) json_schemer (0.2.24)
@@ -461,7 +479,7 @@ GEM
judoscale-sidekiq (1.8.2) judoscale-sidekiq (1.8.2)
judoscale-ruby (= 1.8.2) judoscale-ruby (= 1.8.2)
sidekiq (>= 5.0) sidekiq (>= 5.0)
jwt (2.8.1) jwt (2.10.1)
base64 base64
kaminari (1.2.2) kaminari (1.2.2)
activesupport (>= 4.1.0) activesupport (>= 4.1.0)
@@ -488,15 +506,15 @@ GEM
logger (~> 1.6) logger (~> 1.6)
letter_opener (1.10.0) letter_opener (1.10.0)
launchy (>= 2.2, < 4) launchy (>= 2.2, < 4)
libdatadog (24.0.1.1.0) libdatadog (18.1.0.1.0)
libdatadog (24.0.1.1.0-x86_64-linux) libdatadog (18.1.0.1.0-x86_64-linux)
libddwaf (1.30.0.0.0) libddwaf (1.24.1.0.3)
ffi (~> 1.0) ffi (~> 1.0)
libddwaf (1.30.0.0.0-arm64-darwin) libddwaf (1.24.1.0.3-arm64-darwin)
ffi (~> 1.0) ffi (~> 1.0)
libddwaf (1.30.0.0.0-x86_64-darwin) libddwaf (1.24.1.0.3-x86_64-darwin)
ffi (~> 1.0) ffi (~> 1.0)
libddwaf (1.30.0.0.0-x86_64-linux) libddwaf (1.24.1.0.3-x86_64-linux)
ffi (~> 1.0) ffi (~> 1.0)
line-bot-api (1.28.0) line-bot-api (1.28.0)
lint_roller (1.1.0) lint_roller (1.1.0)
@@ -513,7 +531,7 @@ GEM
activesupport (>= 4) activesupport (>= 4)
railties (>= 4) railties (>= 4)
request_store (~> 1.0) request_store (~> 1.0)
loofah (2.25.0) loofah (2.23.1)
crass (~> 1.0.2) crass (~> 1.0.2)
nokogiri (>= 1.12.0) nokogiri (>= 1.12.0)
mail (2.8.1) mail (2.8.1)
@@ -533,19 +551,21 @@ GEM
mini_magick (4.12.0) mini_magick (4.12.0)
mini_mime (1.1.5) mini_mime (1.1.5)
mini_portile2 (2.8.9) mini_portile2 (2.8.9)
minitest (5.27.0) minitest (5.25.5)
mock_redis (0.36.0) mock_redis (0.36.0)
ruby2_keywords ruby2_keywords
msgpack (1.8.0) msgpack (1.8.0)
multi_json (1.15.0) multi_json (1.15.0)
multi_xml (0.8.1) multi_xml (0.8.0)
bigdecimal (>= 3.1, < 5) bigdecimal (>= 3.1, < 5)
multipart-post (2.3.0) multipart-post (2.3.0)
mutex_m (0.3.0) mutex_m (0.3.0)
neighbor (0.2.3) neighbor (0.2.3)
activerecord (>= 5.2) activerecord (>= 5.2)
net-http (0.4.1) net-http (0.6.0)
uri uri
net-http-persistent (4.0.2)
connection_pool (~> 2.2)
net-imap (0.4.20) net-imap (0.4.20)
date date
net-protocol net-protocol
@@ -562,14 +582,14 @@ GEM
newrelic_rpm (9.6.0) newrelic_rpm (9.6.0)
base64 base64
nio4r (2.7.3) nio4r (2.7.3)
nokogiri (1.19.0) nokogiri (1.18.9)
mini_portile2 (~> 2.8.2) mini_portile2 (~> 2.8.2)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.0-arm64-darwin) nokogiri (1.18.9-arm64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.0-x86_64-darwin) nokogiri (1.18.9-x86_64-darwin)
racc (~> 1.4) racc (~> 1.4)
nokogiri (1.19.0-x86_64-linux-gnu) nokogiri (1.18.9-x86_64-linux-gnu)
racc (~> 1.4) racc (~> 1.4)
oauth (1.1.0) oauth (1.1.0)
oauth-tty (~> 1.0, >= 1.0.1) oauth-tty (~> 1.0, >= 1.0.1)
@@ -587,8 +607,9 @@ GEM
oj (3.16.10) oj (3.16.10)
bigdecimal (>= 3.0) bigdecimal (>= 3.0)
ostruct (>= 0.2) ostruct (>= 0.2)
omniauth (2.1.2) omniauth (2.1.4)
hashie (>= 3.4.6) hashie (>= 3.4.6)
logger
rack (>= 2.2.3) rack (>= 2.2.3)
rack-protection rack-protection
omniauth-google-oauth2 (1.1.3) omniauth-google-oauth2 (1.1.3)
@@ -640,9 +661,6 @@ GEM
activerecord (>= 5.2) activerecord (>= 5.2)
activesupport (>= 5.2) activesupport (>= 5.2)
pgvector (0.1.1) pgvector (0.1.1)
pp (0.6.3)
prettyprint
prettyprint (0.2.0)
prism (1.4.0) prism (1.4.0)
procore-sift (1.0.0) procore-sift (1.0.0)
activerecord (>= 6.1) activerecord (>= 6.1)
@@ -651,9 +669,6 @@ GEM
method_source (~> 1.0) method_source (~> 1.0)
pry-rails (0.3.9) pry-rails (0.3.9)
pry (>= 0.10.4) pry (>= 0.10.4)
psych (5.3.1)
date
stringio
public_suffix (6.0.2) public_suffix (6.0.2)
puma (6.4.3) puma (6.4.3)
nio4r (~> 2.0) nio4r (~> 2.0)
@@ -661,7 +676,7 @@ GEM
activesupport (>= 3.0.0) activesupport (>= 3.0.0)
raabro (1.4.0) raabro (1.4.0)
racc (1.8.1) racc (1.8.1)
rack (3.1.19) rack (3.2.3)
rack-attack (6.7.0) rack-attack (6.7.0)
rack (>= 1.0, < 4) rack (>= 1.0, < 4)
rack-contrib (2.5.0) rack-contrib (2.5.0)
@@ -679,57 +694,53 @@ GEM
rack-session (2.1.1) rack-session (2.1.1)
base64 (>= 0.1.0) base64 (>= 0.1.0)
rack (>= 3.0.0) rack (>= 3.0.0)
rack-test (2.2.0) rack-test (2.1.0)
rack (>= 1.3) rack (>= 1.3)
rack-timeout (0.6.3) rack-timeout (0.6.3)
rackup (2.3.1) rackup (2.2.1)
rack (>= 3) rack (>= 3)
rails (7.2.2.2) rails (7.1.5.2)
actioncable (= 7.2.2.2) actioncable (= 7.1.5.2)
actionmailbox (= 7.2.2.2) actionmailbox (= 7.1.5.2)
actionmailer (= 7.2.2.2) actionmailer (= 7.1.5.2)
actionpack (= 7.2.2.2) actionpack (= 7.1.5.2)
actiontext (= 7.2.2.2) actiontext (= 7.1.5.2)
actionview (= 7.2.2.2) actionview (= 7.1.5.2)
activejob (= 7.2.2.2) activejob (= 7.1.5.2)
activemodel (= 7.2.2.2) activemodel (= 7.1.5.2)
activerecord (= 7.2.2.2) activerecord (= 7.1.5.2)
activestorage (= 7.2.2.2) activestorage (= 7.1.5.2)
activesupport (= 7.2.2.2) activesupport (= 7.1.5.2)
bundler (>= 1.15.0) bundler (>= 1.15.0)
railties (= 7.2.2.2) railties (= 7.1.5.2)
rails-dom-testing (2.3.0) rails-dom-testing (2.2.0)
activesupport (>= 5.0.0) activesupport (>= 5.0.0)
minitest minitest
nokogiri (>= 1.6) nokogiri (>= 1.6)
rails-html-sanitizer (1.6.2) rails-html-sanitizer (1.6.1)
loofah (~> 2.21) loofah (~> 2.21)
nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0) nokogiri (>= 1.15.7, != 1.16.7, != 1.16.6, != 1.16.5, != 1.16.4, != 1.16.3, != 1.16.2, != 1.16.1, != 1.16.0.rc1, != 1.16.0)
railties (7.2.2.2) railties (7.1.5.2)
actionpack (= 7.2.2.2) actionpack (= 7.1.5.2)
activesupport (= 7.2.2.2) activesupport (= 7.1.5.2)
irb (~> 1.13) irb
rackup (>= 1.0.0) rackup (>= 1.0.0)
rake (>= 12.2) rake (>= 12.2)
thor (~> 1.0, >= 1.2.2) thor (~> 1.0, >= 1.2.2)
zeitwerk (~> 2.6) zeitwerk (~> 2.6)
rainbow (3.1.1) rainbow (3.1.1)
rake (13.3.1) rake (13.2.1)
rb-fsevent (0.11.2) rb-fsevent (0.11.2)
rb-inotify (0.10.1) rb-inotify (0.10.1)
ffi (~> 1.0) ffi (~> 1.0)
rdoc (7.1.0)
erb
psych (>= 4.0.0)
tsort
redis (5.0.6) redis (5.0.6)
redis-client (>= 0.9.0) redis-client (>= 0.9.0)
redis-client (0.25.2) redis-client (0.22.2)
connection_pool connection_pool
redis-namespace (1.10.0) redis-namespace (1.10.0)
redis (>= 4) redis (>= 4)
regexp_parser (2.10.0) regexp_parser (2.10.0)
reline (0.6.3) reline (0.3.6)
io-console (~> 0.5) io-console (~> 0.5)
representable (3.2.0) representable (3.2.0)
declarative (< 0.1.0) declarative (< 0.1.0)
@@ -799,10 +810,6 @@ GEM
rubocop-rspec (3.6.0) rubocop-rspec (3.6.0)
lint_roller (~> 1.1) lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1) rubocop (~> 1.72, >= 1.72.1)
rubocop-rspec_rails (2.31.0)
lint_roller (~> 1.1)
rubocop (~> 1.72, >= 1.72.1)
rubocop-rspec (~> 3.5)
ruby-openai (7.3.1) ruby-openai (7.3.1)
event_stream_parser (>= 0.3.0, < 2.0.0) event_stream_parser (>= 0.3.0, < 2.0.0)
faraday (>= 1) faraday (>= 1)
@@ -825,8 +832,9 @@ GEM
faraday-net_http (>= 1) faraday-net_http (>= 1)
faraday-retry (>= 1) faraday-retry (>= 1)
marcel (~> 1.0) marcel (~> 1.0)
ruby_llm-schema (~> 0.2.1)
zeitwerk (~> 2) zeitwerk (~> 2)
ruby_llm-schema (0.1.0) ruby_llm-schema (0.2.5)
ruby_parser (3.20.0) ruby_parser (3.20.0)
sexp_processor (~> 4.16) sexp_processor (~> 4.16)
sass (3.7.4) sass (3.7.4)
@@ -846,8 +854,9 @@ GEM
parser parser
scss_lint (0.60.0) scss_lint (0.60.0)
sass (~> 3.5, >= 3.5.5) sass (~> 3.5, >= 3.5.5)
searchkick (6.0.3) searchkick (5.5.2)
activemodel (>= 7.2) activemodel (>= 7.1)
hashie
securerandom (0.4.1) securerandom (0.4.1)
seed_dump (3.3.1) seed_dump (3.3.1)
activerecord (>= 4) activerecord (>= 4)
@@ -876,17 +885,16 @@ GEM
zeitwerk (~> 2.5) zeitwerk (~> 2.5)
shoulda-matchers (5.3.0) shoulda-matchers (5.3.0)
activesupport (>= 5.2.0) activesupport (>= 5.2.0)
sidekiq (7.3.9) sidekiq (7.3.1)
base64 concurrent-ruby (< 2)
connection_pool (>= 2.3.0) connection_pool (>= 2.3.0)
logger logger
rack (>= 2.2.4) rack (>= 2.2.4)
redis-client (>= 0.22.2) redis-client (>= 0.22.2)
sidekiq-cron (2.3.1) sidekiq-cron (1.12.0)
cronex (>= 0.13.0) fugit (~> 1.8)
fugit (~> 1.8, >= 1.11.1)
globalid (>= 1.0.1) globalid (>= 1.0.1)
sidekiq (>= 6.5.0) sidekiq (>= 6)
sidekiq_alive (2.5.0) sidekiq_alive (2.5.0)
gserver (~> 0.0.1) gserver (~> 0.0.1)
sidekiq (>= 5, < 9) sidekiq (>= 5, < 9)
@@ -926,13 +934,12 @@ GEM
squasher (0.7.2) squasher (0.7.2)
stackprof (0.2.25) stackprof (0.2.25)
statsd-ruby (1.5.0) statsd-ruby (1.5.0)
stringio (3.2.0) stripe (18.0.1)
stripe (18.1.0)
telephone_number (1.4.20) telephone_number (1.4.20)
test-prof (1.2.1) test-prof (1.2.1)
thor (1.5.0) thor (1.4.0)
tidewave (0.4.1) tidewave (0.2.0)
fast-mcp (~> 1.6.0) fast-mcp (~> 1.5.0)
rack (>= 2.0) rack (>= 2.0)
rails (>= 7.1.0) rails (>= 7.1.0)
tilt (2.3.0) tilt (2.3.0)
@@ -941,8 +948,7 @@ GEM
i18n i18n
timeout (0.4.3) timeout (0.4.3)
trailblazer-option (0.1.2) trailblazer-option (0.1.2)
tsort (0.2.0) twilio-ruby (7.6.0)
twilio-ruby (5.77.0)
faraday (>= 0.9, < 3.0) faraday (>= 0.9, < 3.0)
jwt (>= 1.5, < 3.0) jwt (>= 1.5, < 3.0)
nokogiri (>= 1.6, < 2.0) nokogiri (>= 1.6, < 2.0)
@@ -958,25 +964,21 @@ GEM
unf (0.1.4) unf (0.1.4)
unf_ext unf_ext
unf_ext (0.0.8.2) unf_ext (0.0.8.2)
unicode (0.4.4.5)
unicode-display_width (3.1.4) unicode-display_width (3.1.4)
unicode-emoji (~> 4.0, >= 4.0.4) unicode-emoji (~> 4.0, >= 4.0.4)
unicode-emoji (4.0.4) unicode-emoji (4.0.4)
uniform_notifier (1.17.0) uniform_notifier (1.17.0)
uri (1.1.1) uri (1.0.4)
uri_template (0.7.0) uri_template (0.7.0)
useragent (0.16.11)
valid_email2 (5.2.6) valid_email2 (5.2.6)
activemodel (>= 3.2) activemodel (>= 3.2)
mail (~> 2.5) mail (~> 2.5)
version_gem (1.1.4) version_gem (1.1.4)
vite_rails (3.0.20) vite_rails (3.0.17)
railties (>= 5.1, < 9) railties (>= 5.1, < 8)
vite_ruby (~> 3.0, >= 3.2.2) vite_ruby (~> 3.0, >= 3.2.2)
vite_ruby (3.9.2) vite_ruby (3.8.0)
dry-cli (>= 0.7, < 2) dry-cli (>= 0.7, < 2)
logger (~> 1.6)
mutex_m
rack-proxy (~> 0.6, >= 0.6.1) rack-proxy (~> 0.6, >= 0.6.1)
zeitwerk (~> 2.2) zeitwerk (~> 2.2)
warden (1.2.9) warden (1.2.9)
@@ -993,7 +995,7 @@ GEM
addressable (>= 2.8.0) addressable (>= 2.8.0)
crack (>= 0.3.2) crack (>= 0.3.2)
hashdiff (>= 0.4.0, < 2.0.0) hashdiff (>= 0.4.0, < 2.0.0)
websocket-driver (0.8.0) websocket-driver (0.7.7)
base64 base64
websocket-extensions (>= 0.1.0) websocket-extensions (>= 0.1.0)
websocket-extensions (0.1.5) websocket-extensions (0.1.5)
@@ -1001,7 +1003,7 @@ GEM
working_hours (1.4.1) working_hours (1.4.1)
activesupport (>= 3.2) activesupport (>= 3.2)
tzinfo tzinfo
zeitwerk (2.7.4) zeitwerk (2.6.17)
PLATFORMS PLATFORMS
arm64-darwin-20 arm64-darwin-20
@@ -1018,16 +1020,16 @@ DEPENDENCIES
active_record_query_trace active_record_query_trace
activerecord-import activerecord-import
acts-as-taggable-on acts-as-taggable-on
administrate administrate (>= 0.20.1)
administrate-field-active_storage administrate-field-active_storage (>= 1.0.3)
administrate-field-belongs_to_search administrate-field-belongs_to_search (>= 0.9.0)
ai-agents (>= 0.7.0) ai-agents (>= 0.7.0)
annotaterb annotaterb
attr_extras attr_extras
audited (~> 5.4, >= 5.4.1) audited (~> 5.4, >= 5.4.1)
aws-actionmailbox-ses (~> 0) aws-actionmailbox-ses (~> 0)
aws-sdk-s3 aws-sdk-s3
azure-blob azure-storage-blob!
barnes barnes
bootsnap bootsnap
brakeman brakeman
@@ -1036,7 +1038,7 @@ DEPENDENCIES
bundle-audit bundle-audit
byebug byebug
climate_control climate_control
commonmarker (~> 0.23.11) commonmarker
csv-safe csv-safe
database_cleaner database_cleaner
datadog (~> 2.0) datadog (~> 2.0)
@@ -1106,10 +1108,10 @@ DEPENDENCIES
puma puma
pundit pundit
rack-attack (>= 6.7.0) rack-attack (>= 6.7.0)
rack-cors rack-cors (= 2.0.0)
rack-mini-profiler (>= 3.2.0) rack-mini-profiler (>= 3.2.0)
rack-timeout rack-timeout
rails (~> 7.2.0) rails (~> 7.1)
redis redis
redis-namespace redis-namespace
responders (>= 3.1.1) responders (>= 3.1.1)
@@ -1122,7 +1124,6 @@ DEPENDENCIES
rubocop-performance rubocop-performance
rubocop-rails rubocop-rails
rubocop-rspec rubocop-rspec
rubocop-rspec_rails
ruby-openai ruby-openai
ruby_llm (>= 1.8.2) ruby_llm (>= 1.8.2)
ruby_llm-schema ruby_llm-schema
@@ -1136,7 +1137,7 @@ DEPENDENCIES
shopify_api shopify_api
shoulda-matchers shoulda-matchers
sidekiq (>= 7.3.1) sidekiq (>= 7.3.1)
sidekiq-cron (>= 2.3.1) sidekiq-cron (>= 1.12.0)
sidekiq_alive sidekiq_alive
simplecov (>= 0.21) simplecov (>= 0.21)
simplecov_json_formatter simplecov_json_formatter

View File

@@ -28,7 +28,7 @@ class Api::V1::Accounts::Integrations::LinearController < Api::V1::Accounts::Bas
end end
def create_issue def create_issue
issue = linear_processor_service.create_issue(permitted_params.to_h.stringify_keys, Current.user) issue = linear_processor_service.create_issue(permitted_params, Current.user)
if issue[:error] if issue[:error]
render json: { error: issue[:error] }, status: :unprocessable_entity render json: { error: issue[:error] }, status: :unprocessable_entity
else else

View File

@@ -20,9 +20,7 @@ class SuperAdmin::InstanceStatusesController < SuperAdmin::ApplicationController
end end
def instance_meta def instance_meta
migrations_paths = ActiveRecord::Migrator.migrations_paths @metrics['Database Migrations'] = ActiveRecord::Base.connection.migration_context.needs_migration? ? 'pending' : 'completed'
migrations_context = ActiveRecord::MigrationContext.new(migrations_paths)
@metrics['Database Migrations'] = migrations_context.needs_migration? ? 'pending' : 'completed'
end end
def chatwoot_version def chatwoot_version

View File

@@ -19,11 +19,6 @@ class InstallationConfig < ApplicationRecord
# https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017 # https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017
# FIX ME : fixes breakage of installation config. we need to migrate. # FIX ME : fixes breakage of installation config. we need to migrate.
# Fix configuration in application.rb # Fix configuration in application.rb
#
# Note: This whole thing is because we store the installation config serialized in YAML in Database
# This serialized version stores HashWithIndifferentAccess, We could avoid all this complexity if we store the value as JSONB
# We could also avoid this issue if we migrate the installation config to JSONB
# We should do this migration at some point in time.
serialize :serialized_value, coder: YAML, type: ActiveSupport::HashWithIndifferentAccess serialize :serialized_value, coder: YAML, type: ActiveSupport::HashWithIndifferentAccess
before_validation :set_lock before_validation :set_lock

View File

@@ -18,7 +18,7 @@ class Integrations::Hook < ApplicationRecord
include Reauthorizable include Reauthorizable
attr_readonly :app_id, :account_id, :inbox_id, :hook_type attr_readonly :app_id, :account_id, :inbox_id, :hook_type
before_validation :ensure_hook_type, on: :create before_validation :ensure_hook_type
after_create :trigger_setup_if_crm after_create :trigger_setup_if_crm
# TODO: Remove guard once encryption keys become mandatory (target 3-4 releases out). # TODO: Remove guard once encryption keys become mandatory (target 3-4 releases out).
@@ -86,9 +86,7 @@ class Integrations::Hook < ApplicationRecord
end end
def ensure_hook_type def ensure_hook_type
return if app.blank? self.hook_type = app.params[:hook_type] if app.present?
self.hook_type = app.params[:hook_type]
end end
def validate_settings_json_schema def validate_settings_json_schema

View File

@@ -421,8 +421,6 @@ class Message < ApplicationRecord
end end
def reindex_for_search def reindex_for_search
return unless respond_to?(:reindex)
reindex(mode: :async) reindex(mode: :async)
end end
end end

View File

@@ -69,7 +69,7 @@ class User < ApplicationRecord
# TODO: remove in a future version once online status is moved to account users # TODO: remove in a future version once online status is moved to account users
# remove the column availability from users # remove the column availability from users
enum :availability, { online: 0, offline: 1, busy: 2 } enum availability: { online: 0, offline: 1, busy: 2 }
# The validation below has been commented out as it does not # The validation below has been commented out as it does not
# work because :validatable in devise overrides this. # work because :validatable in devise overrides this.
@@ -77,7 +77,7 @@ class User < ApplicationRecord
validates :email, presence: true validates :email, presence: true
serialize :otp_backup_codes, coder: JSON, type: Array serialize :otp_backup_codes, type: Array
# Encrypt sensitive MFA fields # Encrypt sensitive MFA fields
encrypts :otp_secret, deterministic: true encrypts :otp_secret, deterministic: true
@@ -88,7 +88,7 @@ class User < ApplicationRecord
accepts_nested_attributes_for :account_users accepts_nested_attributes_for :account_users
has_many :assigned_conversations, foreign_key: 'assignee_id', class_name: 'Conversation', dependent: :nullify, inverse_of: :assignee has_many :assigned_conversations, foreign_key: 'assignee_id', class_name: 'Conversation', dependent: :nullify, inverse_of: :assignee
alias conversations assigned_conversations alias_attribute :conversations, :assigned_conversations
has_many :csat_survey_responses, foreign_key: 'assigned_agent_id', dependent: :nullify, inverse_of: :assigned_agent has_many :csat_survey_responses, foreign_key: 'assigned_agent_id', dependent: :nullify, inverse_of: :assigned_agent
has_many :reviewed_csat_survey_responses, foreign_key: 'review_notes_updated_by_id', class_name: 'CsatSurveyResponse', has_many :reviewed_csat_survey_responses, foreign_key: 'review_notes_updated_by_id', class_name: 'CsatSurveyResponse',
dependent: :nullify, inverse_of: :review_notes_updated_by dependent: :nullify, inverse_of: :review_notes_updated_by

View File

@@ -82,7 +82,7 @@ class Crm::Leadsquared::SetupService
end end
def update_hook_settings(params) def update_hook_settings(params)
@hook.settings = @hook.settings.merge(params.stringify_keys) @hook.settings = @hook.settings.merge(params)
@hook.save! @hook.save!
end end

View File

@@ -36,7 +36,7 @@ end
module Chatwoot module Chatwoot
class Application < Rails::Application class Application < Rails::Application
# Initialize configuration defaults for originally generated Rails version. # Initialize configuration defaults for originally generated Rails version.
config.load_defaults 7.2 config.load_defaults 7.0
config.eager_load_paths << Rails.root.join('lib') config.eager_load_paths << Rails.root.join('lib')
config.eager_load_paths << Rails.root.join('enterprise/lib') config.eager_load_paths << Rails.root.join('enterprise/lib')

View File

@@ -23,7 +23,7 @@ google:
# Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key)
microsoft: microsoft:
service: AzureBlob service: AzureStorage
storage_account_name: <%= ENV.fetch('AZURE_STORAGE_ACCOUNT_NAME', '') %> storage_account_name: <%= ENV.fetch('AZURE_STORAGE_ACCOUNT_NAME', '') %>
storage_access_key: <%= ENV.fetch('AZURE_STORAGE_ACCESS_KEY', '') %> storage_access_key: <%= ENV.fetch('AZURE_STORAGE_ACCESS_KEY', '') %>
container: <%= ENV.fetch('AZURE_STORAGE_CONTAINER', '') %> container: <%= ENV.fetch('AZURE_STORAGE_CONTAINER', '') %>

View File

@@ -12,10 +12,7 @@ class ArticleKeyConverter
def convert_key(id) def convert_key(id)
verifier_name = 'ActiveStorage' verifier_name = 'ActiveStorage'
secret_key_base = Rails.application.credentials.secret_key_base || key_generator = ActiveSupport::KeyGenerator.new(Rails.application.secrets.secret_key_base, iterations: 1000,
Rails.application.secrets.secret_key_base
key_generator = ActiveSupport::KeyGenerator.new(secret_key_base,
iterations: 1000,
hash_digest_class: OpenSSL::Digest::SHA1) hash_digest_class: OpenSSL::Digest::SHA1)
key_generator = ActiveSupport::CachingKeyGenerator.new(key_generator) key_generator = ActiveSupport::CachingKeyGenerator.new(key_generator)
secret = key_generator.generate_key(verifier_name.to_s) secret = key_generator.generate_key(verifier_name.to_s)

View File

@@ -29,8 +29,6 @@ RUN apk update && apk add --no-cache \
tar \ tar \
build-base \ build-base \
tzdata \ tzdata \
yaml-dev \
pkgconf \
postgresql-dev \ postgresql-dev \
postgresql-client \ postgresql-client \
git \ git \

View File

@@ -15,7 +15,7 @@ class Seeders::Reports::MessageCreator
end end
def create_messages def create_messages
message_count = rand(MESSAGES_PER_CONVERSATION..(MESSAGES_PER_CONVERSATION + 5)) message_count = rand(MESSAGES_PER_CONVERSATION..MESSAGES_PER_CONVERSATION + 5)
first_agent_reply = true first_agent_reply = true
message_count.times do |i| message_count.times do |i|

View File

@@ -144,8 +144,8 @@
"prosemirror-model": "^1.22.3", "prosemirror-model": "^1.22.3",
"size-limit": "^8.2.4", "size-limit": "^8.2.4",
"tailwindcss": "^3.4.13", "tailwindcss": "^3.4.13",
"vite": "5.4.21", "vite": "^5.4.21",
"vite-plugin-ruby": "^5.1.1", "vite-plugin-ruby": "^5.0.0",
"vitest": "3.0.5" "vitest": "3.0.5"
}, },
"engines": { "engines": {

18
pnpm-lock.yaml generated
View File

@@ -351,8 +351,8 @@ importers:
specifier: 5.4.21 specifier: 5.4.21
version: 5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) version: 5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
vite-plugin-ruby: vite-plugin-ruby:
specifier: ^5.1.1 specifier: ^5.0.0
version: 5.1.1(vite@5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) version: 5.0.0(vite@5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0))
vitest: vitest:
specifier: 3.0.5 specifier: 3.0.5
version: 3.0.5(@types/node@22.7.0)(jsdom@27.2.0)(sass@1.79.3)(terser@5.33.0) version: 3.0.5(@types/node@22.7.0)(jsdom@27.2.0)(sass@1.79.3)(terser@5.33.0)
@@ -4519,8 +4519,8 @@ packages:
engines: {node: ^18.0.0 || >=20.0.0} engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true hasBin: true
vite-plugin-ruby@5.1.1: vite-plugin-ruby@5.0.0:
resolution: {integrity: sha512-I1dXJq2ywdvTD2Cz5LYNcYLujqQ3eUxPoCjruRdfm2QBtHBY15NEeb6x5HuPM3T5S+y8S3p9fwRsieQQCjk0gg==} resolution: {integrity: sha512-c8PjTp21Ah/ttgnNUyu0qvCXZI08Jr9I24oUKg3TRIRhF5GcOZ++6wtlTCrNFd9COEQbpXHxlRIXd/MEg0iZJw==}
peerDependencies: peerDependencies:
vite: 5.4.21 vite: 5.4.21
@@ -6245,7 +6245,7 @@ snapshots:
agent-base@6.0.2: agent-base@6.0.2:
dependencies: dependencies:
debug: 4.4.3 debug: 4.4.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -7647,7 +7647,7 @@ snapshots:
dependencies: dependencies:
'@tootallnate/once': 2.0.0 '@tootallnate/once': 2.0.0
agent-base: 6.0.2 agent-base: 6.0.2
debug: 4.4.3 debug: 4.4.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -7661,7 +7661,7 @@ snapshots:
https-proxy-agent@5.0.1: https-proxy-agent@5.0.1:
dependencies: dependencies:
agent-base: 6.0.2 agent-base: 6.0.2
debug: 4.4.3 debug: 4.4.0
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
@@ -9599,9 +9599,9 @@ snapshots:
- supports-color - supports-color
- terser - terser
vite-plugin-ruby@5.1.1(vite@5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)): vite-plugin-ruby@5.0.0(vite@5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)):
dependencies: dependencies:
debug: 4.4.3 debug: 4.3.5
fast-glob: 3.3.2 fast-glob: 3.3.2
vite: 5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) vite: 5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)
transitivePeerDependencies: transitivePeerDependencies:

View File

@@ -1,22 +1,15 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe V2::ReportBuilder do describe V2::ReportBuilder do
include ActiveJob::TestHelper include ActiveJob::TestHelper
self.use_transactional_tests = false let_it_be(:account) { create(:account) }
let_it_be(:label_1) { create(:label, title: 'Label_1', account: account) }
def truncate_test_data let_it_be(:label_2) { create(:label, title: 'Label_2', account: account) }
connection = ActiveRecord::Base.connection
connection.truncate_tables(*connection.tables)
end
before { truncate_test_data }
let(:account) { create(:account) }
let!(:label_1) { create(:label, title: 'Label_1', account: account) }
let!(:label_2) { create(:label, title: 'Label_2', account: account) }
describe '#timeseries' do describe '#timeseries' do
before do # Use before_all to share expensive setup across all tests in this describe block
# This runs once instead of 21 times, dramatically speeding up the suite
before_all do
travel_to(Time.zone.today) do travel_to(Time.zone.today) do
user = create(:user, account: account) user = create(:user, account: account)
inbox = create(:inbox, account: account) inbox = create(:inbox, account: account)
@@ -28,7 +21,7 @@ RSpec.describe V2::ReportBuilder do
perform_enqueued_jobs do perform_enqueued_jobs do
10.times do 10.times do
conversation = create(:conversation, account: account, conversation = create(:conversation, account: account,
inbox: inbox, inbox: inbox, assignee: user,
created_at: Time.zone.today) created_at: Time.zone.today)
create_list(:message, 5, message_type: 'outgoing', create_list(:message, 5, message_type: 'outgoing',
account: account, inbox: inbox, account: account, inbox: inbox,
@@ -44,7 +37,7 @@ RSpec.describe V2::ReportBuilder do
5.times do 5.times do
conversation = create(:conversation, account: account, conversation = create(:conversation, account: account,
inbox: inbox, inbox: inbox, assignee: user,
created_at: (Time.zone.today - 2.days)) created_at: (Time.zone.today - 2.days))
create_list(:message, 3, message_type: 'outgoing', create_list(:message, 3, message_type: 'outgoing',
account: account, inbox: inbox, account: account, inbox: inbox,

View File

@@ -2,19 +2,11 @@ require 'rails_helper'
RSpec.describe V2::Reports::LabelSummaryBuilder do RSpec.describe V2::Reports::LabelSummaryBuilder do
include ActiveJob::TestHelper include ActiveJob::TestHelper
self.use_transactional_tests = false
def truncate_test_data let_it_be(:account) { create(:account) }
connection = ActiveRecord::Base.connection let_it_be(:label_1) { create(:label, title: 'label_1', account: account) }
connection.truncate_tables(*connection.tables) let_it_be(:label_2) { create(:label, title: 'label_2', account: account) }
end let_it_be(:label_3) { create(:label, title: 'label_3', account: account) }
before { truncate_test_data }
let(:account) { create(:account) }
let!(:label_1) { create(:label, title: 'label_1', account: account) }
let!(:label_2) { create(:label, title: 'label_2', account: account) }
let!(:label_3) { create(:label, title: 'label_3', account: account) }
let(:params) do let(:params) do
{ {
@@ -100,7 +92,7 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do
# Create conversations with label_1 # Create conversations with label_1
3.times do 3.times do
conversation = create(:conversation, account: account, conversation = create(:conversation, account: account,
inbox: inbox, inbox: inbox, assignee: user,
created_at: Time.zone.today) created_at: Time.zone.today)
create_list(:message, 2, message_type: 'outgoing', create_list(:message, 2, message_type: 'outgoing',
account: account, inbox: inbox, account: account, inbox: inbox,
@@ -118,7 +110,7 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do
# Create conversations with label_2 # Create conversations with label_2
2.times do 2.times do
conversation = create(:conversation, account: account, conversation = create(:conversation, account: account,
inbox: inbox, inbox: inbox, assignee: user,
created_at: Time.zone.today) created_at: Time.zone.today)
create_list(:message, 1, message_type: 'outgoing', create_list(:message, 1, message_type: 'outgoing',
account: account, inbox: inbox, account: account, inbox: inbox,
@@ -237,7 +229,7 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do
perform_enqueued_jobs do perform_enqueued_jobs do
# Conversation within range # Conversation within range
conversation_in_range = create(:conversation, account: account, conversation_in_range = create(:conversation, account: account,
inbox: inbox, inbox: inbox, assignee: user,
created_at: 2.days.ago) created_at: 2.days.ago)
conversation_in_range.update_labels('label_1') conversation_in_range.update_labels('label_1')
conversation_in_range.label_list conversation_in_range.label_list
@@ -252,7 +244,7 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do
# Conversation outside range (too old) # Conversation outside range (too old)
conversation_out_of_range = create(:conversation, account: account, conversation_out_of_range = create(:conversation, account: account,
inbox: inbox, inbox: inbox, assignee: user,
created_at: 1.week.ago) created_at: 1.week.ago)
conversation_out_of_range.update_labels('label_1') conversation_out_of_range.update_labels('label_1')
conversation_out_of_range.label_list conversation_out_of_range.label_list
@@ -294,7 +286,7 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do
perform_enqueued_jobs do perform_enqueued_jobs do
conversation = create(:conversation, account: account, conversation = create(:conversation, account: account,
inbox: inbox, inbox: inbox, assignee: user,
created_at: Time.zone.today) created_at: Time.zone.today)
conversation.update_labels('label_1') conversation.update_labels('label_1')
conversation.label_list conversation.label_list
@@ -331,8 +323,8 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do
let(:account2_builder) do let(:account2_builder) do
described_class.new(account: account2, params: { described_class.new(account: account2, params: {
business_hours: false, business_hours: false,
since: test_date.in_time_zone.to_i.to_s, since: test_date.to_time.to_i.to_s,
until: test_date.end_of_day.in_time_zone.to_i.to_s, until: test_date.end_of_day.to_time.to_i.to_s,
timezone_offset: 0 timezone_offset: 0
}) })
end end
@@ -351,7 +343,7 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do
perform_enqueued_jobs do perform_enqueued_jobs do
conversation = create(:conversation, account: account2, conversation = create(:conversation, account: account2,
inbox: inbox, inbox: inbox, assignee: user,
created_at: test_date) created_at: test_date)
conversation.update_labels(unique_label_name) conversation.update_labels(unique_label_name)
conversation.label_list conversation.label_list
@@ -366,7 +358,6 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do
# Second resolution # Second resolution
conversation.resolved! conversation.resolved!
end end
perform_enqueued_jobs
end end
end end

View File

@@ -388,7 +388,7 @@ RSpec.describe 'Api::V1::Accounts::MacrosController', type: :request do
headers: administrator.create_new_auth_token headers: administrator.create_new_auth_token
end end
expect(conversation.reload.assignee_id).to eq(user_1.id) expect(conversation.messages.activity.last.content).to eq("Assigned to #{user_1.name} by #{administrator.name}")
end end
it 'Assign the agent when he is not inbox member' do it 'Assign the agent when he is not inbox member' do
@@ -402,7 +402,7 @@ RSpec.describe 'Api::V1::Accounts::MacrosController', type: :request do
headers: administrator.create_new_auth_token headers: administrator.create_new_auth_token
end end
expect(conversation.reload.assignee_id).to be_nil expect(conversation.messages.activity.last.content).not_to eq("Assigned to #{user_1.name} by #{administrator.name}")
end end
it 'Assign the labels' do it 'Assign the labels' do

View File

@@ -1,6 +1,12 @@
require 'rails_helper' require 'rails_helper'
RSpec.describe BulkActionsJob do RSpec.describe BulkActionsJob do
params = {
type: 'Conversation',
fields: { status: 'snoozed' },
ids: Conversation.first(3).pluck(:display_id)
}
subject(:job) { described_class.perform_later(account: account, params: params, user: agent) } subject(:job) { described_class.perform_later(account: account, params: params, user: agent) }
let(:account) { create(:account) } let(:account) { create(:account) }
@@ -8,8 +14,6 @@ RSpec.describe BulkActionsJob do
let!(:conversation_1) { create(:conversation, account_id: account.id, status: :open) } let!(:conversation_1) { create(:conversation, account_id: account.id, status: :open) }
let!(:conversation_2) { create(:conversation, account_id: account.id, status: :open) } let!(:conversation_2) { create(:conversation, account_id: account.id, status: :open) }
let!(:conversation_3) { create(:conversation, account_id: account.id, status: :open) } let!(:conversation_3) { create(:conversation, account_id: account.id, status: :open) }
let(:conversation_ids) { Conversation.where(id: [conversation_1.id, conversation_2.id, conversation_3.id]).pluck(:display_id) }
let(:params) { { type: 'Conversation', fields: { status: 'snoozed' }, ids: conversation_ids } }
before do before do
Conversation.all.find_each do |conversation| Conversation.all.find_each do |conversation|
@@ -34,10 +38,10 @@ RSpec.describe BulkActionsJob do
params = { params = {
type: 'Conversation', type: 'Conversation',
fields: { status: 'snoozed', assignee_id: agent.id }, fields: { status: 'snoozed', assignee_id: agent.id },
ids: conversation_ids ids: Conversation.first(3).pluck(:display_id)
} }
expect(conversation_1.status).to eq('open') expect(Conversation.first.status).to eq('open')
described_class.perform_now(account: account, params: params, user: agent) described_class.perform_now(account: account, params: params, user: agent)
@@ -50,32 +54,32 @@ RSpec.describe BulkActionsJob do
params = { params = {
type: 'Conversation', type: 'Conversation',
fields: { status: 'snoozed', assignee_id: agent.id }, fields: { status: 'snoozed', assignee_id: agent.id },
ids: conversation_ids ids: Conversation.first(3).pluck(:display_id)
} }
expect(conversation_1.assignee_id).to be_nil expect(Conversation.first.assignee_id).to be_nil
described_class.perform_now(account: account, params: params, user: agent) described_class.perform_now(account: account, params: params, user: agent)
expect(conversation_1.reload.assignee_id).to eq(agent.id) expect(Conversation.first.assignee_id).to eq(agent.id)
expect(conversation_2.reload.assignee_id).to eq(agent.id) expect(Conversation.second.assignee_id).to eq(agent.id)
expect(conversation_3.reload.assignee_id).to eq(agent.id) expect(Conversation.third.assignee_id).to eq(agent.id)
end end
it 'bulk updates the snoozed_until' do it 'bulk updates the snoozed_until' do
params = { params = {
type: 'Conversation', type: 'Conversation',
fields: { status: 'snoozed', snoozed_until: Time.zone.now }, fields: { status: 'snoozed', snoozed_until: Time.zone.now },
ids: conversation_ids ids: Conversation.first(3).pluck(:display_id)
} }
expect(conversation_1.snoozed_until).to be_nil expect(Conversation.first.snoozed_until).to be_nil
described_class.perform_now(account: account, params: params, user: agent) described_class.perform_now(account: account, params: params, user: agent)
expect(conversation_1.reload.snoozed_until).to be_present expect(Conversation.first.snoozed_until).to be_present
expect(conversation_2.reload.snoozed_until).to be_present expect(Conversation.second.snoozed_until).to be_present
expect(conversation_3.reload.snoozed_until).to be_present expect(Conversation.third.snoozed_until).to be_present
end end
end end
end end

View File

@@ -1,9 +1,11 @@
# frozen_string_literal: true # frozen_string_literal: true
RSpec.shared_context 'with smtp config' do RSpec.shared_context 'with smtp config' do
around do |example| before do
# Set SMTP_ADDRESS so mailers build a Mail::Message in test without touching real SMTP. # We need to use allow_any_instance_of here because smtp_config_set_or_development?
# Scoped to this shared context to avoid affecting other specs. # is defined in ApplicationMailer and needs to be stubbed for all mailer instances
with_modified_env('SMTP_ADDRESS' => 'smtp.example.com') { example.run } # rubocop:disable RSpec/AnyInstance
allow_any_instance_of(ApplicationMailer).to receive(:smtp_config_set_or_development?).and_return(true)
# rubocop:enable RSpec/AnyInstance
end end
end end

View File

@@ -28,7 +28,8 @@ RSpec.describe ContactInbox do
obj.reload obj.reload
# ensure the column is nil in database # ensure the column is nil in database
expect(described_class.where(id: obj.id).pick(:pubsub_token)).to be_nil results = ActiveRecord::Base.connection.execute('Select * from contact_inboxes;')
expect(results.first['pubsub_token']).to be_nil
new_token = obj.pubsub_token new_token = obj.pubsub_token
obj.update(source_id: '234234323') obj.update(source_id: '234234323')

View File

@@ -20,7 +20,7 @@ RSpec.describe Account::SignUpEmailValidationService, type: :service do
it 'raises InvalidEmail with invalid message' do it 'raises InvalidEmail with invalid message' do
allow(ValidEmail2::Address).to receive(:new).with(email).and_return(invalid_email_address) allow(ValidEmail2::Address).to receive(:new).with(email).and_return(invalid_email_address)
expect { service.perform }.to raise_error do |error| expect { service.perform }.to raise_error do |error|
expect(error.class.name).to eq('CustomExceptions::Account::InvalidEmail') expect(error).to be_a(CustomExceptions::Account::InvalidEmail)
expect(error.message).to eq(I18n.t('errors.signup.invalid_email')) expect(error.message).to eq(I18n.t('errors.signup.invalid_email'))
end end
end end
@@ -32,7 +32,7 @@ RSpec.describe Account::SignUpEmailValidationService, type: :service do
it 'raises InvalidEmail with blocked domain message' do it 'raises InvalidEmail with blocked domain message' do
allow(ValidEmail2::Address).to receive(:new).with(email).and_return(valid_email_address) allow(ValidEmail2::Address).to receive(:new).with(email).and_return(valid_email_address)
expect { service.perform }.to raise_error do |error| expect { service.perform }.to raise_error do |error|
expect(error.class.name).to eq('CustomExceptions::Account::InvalidEmail') expect(error).to be_a(CustomExceptions::Account::InvalidEmail)
expect(error.message).to eq(I18n.t('errors.signup.blocked_domain')) expect(error.message).to eq(I18n.t('errors.signup.blocked_domain'))
end end
end end
@@ -44,7 +44,7 @@ RSpec.describe Account::SignUpEmailValidationService, type: :service do
it 'raises InvalidEmail with blocked domain message' do it 'raises InvalidEmail with blocked domain message' do
allow(ValidEmail2::Address).to receive(:new).with(email).and_return(valid_email_address) allow(ValidEmail2::Address).to receive(:new).with(email).and_return(valid_email_address)
expect { service.perform }.to raise_error do |error| expect { service.perform }.to raise_error do |error|
expect(error.class.name).to eq('CustomExceptions::Account::InvalidEmail') expect(error).to be_a(CustomExceptions::Account::InvalidEmail)
expect(error.message).to eq(I18n.t('errors.signup.blocked_domain')) expect(error.message).to eq(I18n.t('errors.signup.blocked_domain'))
end end
end end
@@ -56,7 +56,7 @@ RSpec.describe Account::SignUpEmailValidationService, type: :service do
it 'raises InvalidEmail with disposable message' do it 'raises InvalidEmail with disposable message' do
allow(ValidEmail2::Address).to receive(:new).with(email).and_return(disposable_email_address) allow(ValidEmail2::Address).to receive(:new).with(email).and_return(disposable_email_address)
expect { service.perform }.to raise_error do |error| expect { service.perform }.to raise_error do |error|
expect(error.class.name).to eq('CustomExceptions::Account::InvalidEmail') expect(error).to be_a(CustomExceptions::Account::InvalidEmail)
expect(error.message).to eq(I18n.t('errors.signup.disposable_email')) expect(error.message).to eq(I18n.t('errors.signup.disposable_email'))
end end
end end

View File

@@ -42,11 +42,6 @@ describe Telegram::IncomingMessageService do
} }
end end
def contact_for(source_id = nil)
source_id ||= message_params.dig('from', 'id')
ContactInbox.find_by!(inbox: telegram_channel.inbox, source_id: source_id).contact
end
describe '#perform' do describe '#perform' do
context 'when valid text message params' do context 'when valid text message params' do
it 'creates appropriate conversations, message and contacts' do it 'creates appropriate conversations, message and contacts' do
@@ -56,7 +51,7 @@ describe Telegram::IncomingMessageService do
}.with_indifferent_access }.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
expect(telegram_channel.inbox.messages.first.content).to eq('test') expect(telegram_channel.inbox.messages.first.content).to eq('test')
end end
end end
@@ -69,9 +64,9 @@ describe Telegram::IncomingMessageService do
}.with_indifferent_access }.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
expect(contact_for.additional_attributes['social_telegram_user_id']).to eq(23) expect(Contact.all.first.additional_attributes['social_telegram_user_id']).to eq(23)
expect(contact_for.additional_attributes['social_telegram_user_name']).to eq('sojan') expect(Contact.all.first.additional_attributes['social_telegram_user_name']).to eq('sojan')
expect(telegram_channel.inbox.messages.first.content).to eq('test') expect(telegram_channel.inbox.messages.first.content).to eq('test')
end end
end end
@@ -112,7 +107,7 @@ describe Telegram::IncomingMessageService do
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(telegram_channel.inbox.conversations.last.additional_attributes).to include({ 'chat_id' => 23, expect(telegram_channel.inbox.conversations.last.additional_attributes).to include({ 'chat_id' => 23,
'business_connection_id' => 'eooW3KF5WB5HxTD7T826' }) 'business_connection_id' => 'eooW3KF5WB5HxTD7T826' })
contact = contact_for contact = Contact.all.first
expect(contact.name).to eq('Sojan Jose') expect(contact.name).to eq('Sojan Jose')
expect(contact.additional_attributes['language_code']).to eq('en') expect(contact.additional_attributes['language_code']).to eq('en')
message = telegram_channel.inbox.messages.first message = telegram_channel.inbox.messages.first
@@ -136,7 +131,7 @@ describe Telegram::IncomingMessageService do
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(telegram_channel.inbox.conversations.last.additional_attributes).to include({ 'chat_id' => 23, expect(telegram_channel.inbox.conversations.last.additional_attributes).to include({ 'chat_id' => 23,
'business_connection_id' => 'eooW3KF5WB5HxTD7T826' }) 'business_connection_id' => 'eooW3KF5WB5HxTD7T826' })
contact = contact_for contact = Contact.all.first
expect(contact.name).to eq('Sojan Jose') expect(contact.name).to eq('Sojan Jose')
# TODO: The language code is not present when we send the first message to the client. # TODO: The language code is not present when we send the first message to the client.
# Should we update it when the user replies? # Should we update it when the user replies?
@@ -166,9 +161,9 @@ describe Telegram::IncomingMessageService do
}.with_indifferent_access }.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
expect(contact_for.additional_attributes['social_telegram_user_id']).to eq(23) expect(Contact.all.first.additional_attributes['social_telegram_user_id']).to eq(23)
expect(contact_for.additional_attributes['social_telegram_user_name']).to eq('sojan') expect(Contact.all.first.additional_attributes['social_telegram_user_name']).to eq('sojan')
expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('audio') expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('audio')
end end
end end
@@ -187,7 +182,7 @@ describe Telegram::IncomingMessageService do
}.with_indifferent_access }.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('image') expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('image')
end end
end end
@@ -212,7 +207,7 @@ describe Telegram::IncomingMessageService do
}.with_indifferent_access }.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('image') expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('image')
end end
end end
@@ -234,7 +229,7 @@ describe Telegram::IncomingMessageService do
}.with_indifferent_access }.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('video') expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('video')
end end
end end
@@ -263,7 +258,7 @@ describe Telegram::IncomingMessageService do
}.with_indifferent_access }.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('video') expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('video')
end end
end end
@@ -282,7 +277,7 @@ describe Telegram::IncomingMessageService do
}.with_indifferent_access }.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('audio') expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('audio')
end end
end end
@@ -303,7 +298,7 @@ describe Telegram::IncomingMessageService do
}.with_indifferent_access }.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('file') expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('file')
end end
end end
@@ -341,7 +336,7 @@ describe Telegram::IncomingMessageService do
}.with_indifferent_access }.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('location') expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('location')
end end
@@ -360,7 +355,7 @@ describe Telegram::IncomingMessageService do
}.with_indifferent_access }.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
attachment = telegram_channel.inbox.messages.first.attachments.first attachment = telegram_channel.inbox.messages.first.attachments.first
expect(attachment.file_type).to eq('location') expect(attachment.file_type).to eq('location')
@@ -393,8 +388,8 @@ describe Telegram::IncomingMessageService do
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for(5_171_248).name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
expect(contact_for(5_171_248).additional_attributes['social_telegram_user_id']).to eq(5_171_248) expect(Contact.all.first.additional_attributes['social_telegram_user_id']).to eq(5_171_248)
expect(telegram_channel.inbox.messages.first.content).to eq('Option 1') expect(telegram_channel.inbox.messages.first.content).to eq('Option 1')
end end
end end
@@ -411,7 +406,7 @@ describe Telegram::IncomingMessageService do
}.with_indifferent_access }.with_indifferent_access
described_class.new(inbox: telegram_channel.inbox, params: params).perform described_class.new(inbox: telegram_channel.inbox, params: params).perform
expect(telegram_channel.inbox.conversations.count).not_to eq(0) expect(telegram_channel.inbox.conversations.count).not_to eq(0)
expect(contact_for.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('contact') expect(telegram_channel.inbox.messages.first.attachments.first.file_type).to eq('contact')
end end
end end

View File

@@ -3,7 +3,6 @@ require 'rails_helper'
describe Whatsapp::IncomingMessageWhatsappCloudService do describe Whatsapp::IncomingMessageWhatsappCloudService do
describe '#perform' do describe '#perform' do
let!(:whatsapp_channel) { create(:channel_whatsapp, provider: 'whatsapp_cloud', sync_templates: false, validate_provider_config: false) } let!(:whatsapp_channel) { create(:channel_whatsapp, provider: 'whatsapp_cloud', sync_templates: false, validate_provider_config: false) }
let(:sender_number) { '2423423243' }
let(:params) do let(:params) do
{ {
phone_number: whatsapp_channel.phone_number, phone_number: whatsapp_channel.phone_number,
@@ -11,9 +10,9 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do
entry: [{ entry: [{
changes: [{ changes: [{
value: { value: {
contacts: [{ profile: { name: 'Sojan Jose' }, wa_id: sender_number }], contacts: [{ profile: { name: 'Sojan Jose' }, wa_id: '2423423243' }],
messages: [{ messages: [{
from: sender_number, from: '2423423243',
image: { image: {
id: 'b1c68f38-8734-4ad3-b4a1-ef0c10d683', id: 'b1c68f38-8734-4ad3-b4a1-ef0c10d683',
mime_type: 'image/jpeg', mime_type: 'image/jpeg',
@@ -49,7 +48,7 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do
described_class.new(inbox: whatsapp_channel.inbox, params: params).perform described_class.new(inbox: whatsapp_channel.inbox, params: params).perform
expect(whatsapp_channel.inbox.conversations.count).not_to eq(0) expect(whatsapp_channel.inbox.conversations.count).not_to eq(0)
expect_contact_name expect(Contact.all.first.name).to eq('Sojan Jose')
expect(whatsapp_channel.inbox.messages.first.content).to eq('Check out my product!') expect(whatsapp_channel.inbox.messages.first.content).to eq('Check out my product!')
expect(whatsapp_channel.inbox.messages.first.attachments.present?).to be false expect(whatsapp_channel.inbox.messages.first.attachments.present?).to be false
expect(whatsapp_channel.authorization_error_count).to eq(1) expect(whatsapp_channel.authorization_error_count).to eq(1)
@@ -64,9 +63,9 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do
entry: [{ entry: [{
changes: [{ changes: [{
value: { value: {
contacts: [{ profile: { name: 'Sojan Jose' }, wa_id: sender_number }], contacts: [{ profile: { name: 'Sojan Jose' }, wa_id: '2423423243' }],
messages: [{ messages: [{
from: sender_number, from: '2423423243',
image: { image: {
id: 'b1c68f38-8734-4ad3-b4a1-ef0c10d683', id: 'b1c68f38-8734-4ad3-b4a1-ef0c10d683',
mime_type: 'image/jpeg', mime_type: 'image/jpeg',
@@ -89,7 +88,7 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do
it 'with attachment errors' do it 'with attachment errors' do
described_class.new(inbox: whatsapp_channel.inbox, params: error_params).perform described_class.new(inbox: whatsapp_channel.inbox, params: error_params).perform
expect(whatsapp_channel.inbox.conversations.count).not_to eq(0) expect(whatsapp_channel.inbox.conversations.count).not_to eq(0)
expect_contact_name expect(Contact.all.first.name).to eq('Sojan Jose')
expect(whatsapp_channel.inbox.messages.count).to eq(0) expect(whatsapp_channel.inbox.messages.count).to eq(0)
end end
end end
@@ -99,7 +98,7 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do
described_class.new(inbox: whatsapp_channel.inbox, params: { phone_number: whatsapp_channel.phone_number, described_class.new(inbox: whatsapp_channel.inbox, params: { phone_number: whatsapp_channel.phone_number,
object: 'whatsapp_business_account', entry: {} }).perform object: 'whatsapp_business_account', entry: {} }).perform
expect(whatsapp_channel.inbox.conversations.count).to eq(0) expect(whatsapp_channel.inbox.conversations.count).to eq(0)
expect(Contact.find_by(phone_number: contact_phone_number)).to be_nil expect(Contact.all.first).to be_nil
expect(whatsapp_channel.inbox.messages.count).to eq(0) expect(whatsapp_channel.inbox.messages.count).to eq(0)
end end
end end
@@ -137,7 +136,7 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do
end end
def expect_contact_name def expect_contact_name
expect(contact_from_number&.name).to eq('Sojan Jose') expect(Contact.all.first.name).to eq('Sojan Jose')
end end
def expect_message_content def expect_message_content
@@ -147,12 +146,4 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do
def expect_message_has_attachment def expect_message_has_attachment
expect(whatsapp_channel.inbox.messages.first.attachments.present?).to be true expect(whatsapp_channel.inbox.messages.first.attachments.present?).to be true
end end
def contact_phone_number
"+#{sender_number}"
end
def contact_from_number
Contact.find_by(phone_number: contact_phone_number)
end
end end