From 9eb3ee44a84737c13f1028df8aa50b8b0ff98700 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Tue, 3 Feb 2026 21:09:42 -0800 Subject: [PATCH] Revert "chore: Upgrade Rails to 7.2.2 and update Gemfile dependencies (#11037)" This reverts commit ef6ba8aabd0e52e9cee1b61c8497671e057fa9d8. --- .circleci/config.yml | 6 +- .rubocop.yml | 7 - AGENTS.md | 1 - Gemfile | 23 +- Gemfile.lock | 385 +++++++++--------- .../integrations/linear_controller.rb | 2 +- .../instance_statuses_controller.rb | 4 +- app/models/installation_config.rb | 5 - app/models/integrations/hook.rb | 6 +- app/models/message.rb | 2 - app/models/user.rb | 6 +- app/services/crm/leadsquared/setup_service.rb | 2 +- config/application.rb | 2 +- config/storage.yml | 2 +- ...0230515051424_update_article_image_keys.rb | 7 +- docker/Dockerfile | 2 - lib/seeders/reports/message_creator.rb | 2 +- package.json | 4 +- pnpm-lock.yaml | 18 +- spec/builders/v2/report_builder_spec.rb | 25 +- .../v2/reports/label_summary_builder_spec.rb | 33 +- .../api/v1/accounts/macros_controller_spec.rb | 4 +- spec/jobs/bulk_actions_job_spec.rb | 32 +- .../shared/smtp_config_shared.rb | 10 +- spec/models/contact_inbox_spec.rb | 3 +- .../sign_up_email_validation_service_spec.rb | 8 +- .../telegram/incoming_message_service_spec.rb | 45 +- ...ing_message_whatsapp_cloud_service_spec.rb | 25 +- 28 files changed, 311 insertions(+), 360 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index 624e4a1ac..c0320652b 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -279,10 +279,10 @@ jobs: echo -en "\nINSTALLATION_ENV=circleci" >> ".env" echo -en "\nOPENSEARCH_URL=http://localhost:9200" >> ".env" - # Database setup (match GitHub Actions flow) + # Database setup - run: - name: Create database + load schema - command: bundle exec rake db:create db:schema:load + name: Run DB migrations + command: bundle exec rails db:chatwoot_prepare # Run backend tests (parallelized) - run: diff --git a/.rubocop.yml b/.rubocop.yml index 25d684cbe..d87f08bfd 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -2,7 +2,6 @@ plugins: - rubocop-performance - rubocop-rails - rubocop-rspec - - rubocop-rspec_rails - rubocop-factory_bot require: @@ -204,12 +203,6 @@ RSpec/MultipleExpectations: RSpec/MultipleMemoizedHelpers: Max: 14 -RSpecRails/InferredSpecType: - Enabled: false - -RSpecRails/NegationBeValid: - Enabled: false - # custom rules UseFromEmail: Enabled: true diff --git a/AGENTS.md b/AGENTS.md index add9d5040..474fe6e7f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -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)`) - **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.) -- **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 diff --git a/Gemfile b/Gemfile index f0fb62413..1ae6cf093 100644 --- a/Gemfile +++ b/Gemfile @@ -3,10 +3,8 @@ source 'https://rubygems.org' ruby '3.4.4' ##-- base gems for rails --## - -gem 'rack-cors', require: 'rack/cors' -gem 'rails', '~> 7.2.0' - +gem 'rack-cors', '2.0.0', require: 'rack/cors' +gem 'rails', '~> 7.1' # Reduces boot times through caching; required in config/boot.rb gem 'bootsnap', require: false @@ -33,9 +31,7 @@ gem 'haikunator' # Template parsing safely gem 'liquid' # Parse Markdown to HTML -# ref: https://github.com/gjtorikian/commonmarker/issues/358 -# can upgrade one this issue is fixed -gem 'commonmarker', '~> 0.23.11' +gem 'commonmarker' # Validate Data against JSON Schema gem 'json_schemer' # used in swagger build @@ -53,7 +49,9 @@ gem 'csv-safe' ##-- for active storage --## 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 'image_processing' @@ -91,9 +89,9 @@ gem 'jwt' gem 'pundit' # super admin -gem 'administrate' -gem 'administrate-field-active_storage' -gem 'administrate-field-belongs_to_search' +gem 'administrate', '>= 0.20.1' +gem 'administrate-field-active_storage', '>= 1.0.3' +gem 'administrate-field-belongs_to_search', '>= 0.9.0' ##--- gems for pubsub service ---## # 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 --## gem 'sidekiq', '>= 7.3.1' # We want cron jobs -gem 'sidekiq-cron', '>= 2.3.1' +gem 'sidekiq-cron', '>= 1.12.0' # for sidekiq healthcheck gem 'sidekiq_alive' @@ -264,7 +262,6 @@ group :development, :test do gem 'rubocop-performance', require: false gem 'rubocop-rails', require: false gem 'rubocop-rspec', require: false - gem 'rubocop-rspec_rails', require: false gem 'rubocop-factory_bot', require: false gem 'seed_dump' gem 'shoulda-matchers' diff --git a/Gemfile.lock b/Gemfile.lock index 6b485cf29..1cdfabee0 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,89 +1,110 @@ GIT - remote: https://github.com/chatwoot/devise-secure_password - revision: 479987594b576dbf23aed8dbd962e78342bc683c + remote: https://github.com/chatwoot/azure-storage-ruby + revision: 9957cf899d33a285b5dfe15bdb875292398e392b branch: chatwoot 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) railties (>= 5.0.0, < 8.0.0) GEM remote: https://rubygems.org/ specs: - actioncable (7.2.2.2) - actionpack (= 7.2.2.2) - activesupport (= 7.2.2.2) + actioncable (7.1.5.2) + actionpack (= 7.1.5.2) + activesupport (= 7.1.5.2) nio4r (~> 2.0) websocket-driver (>= 0.6.1) zeitwerk (~> 2.6) - actionmailbox (7.2.2.2) - actionpack (= 7.2.2.2) - activejob (= 7.2.2.2) - activerecord (= 7.2.2.2) - activestorage (= 7.2.2.2) - activesupport (= 7.2.2.2) - mail (>= 2.8.0) - actionmailer (7.2.2.2) - actionpack (= 7.2.2.2) - actionview (= 7.2.2.2) - activejob (= 7.2.2.2) - activesupport (= 7.2.2.2) - mail (>= 2.8.0) + actionmailbox (7.1.5.2) + actionpack (= 7.1.5.2) + activejob (= 7.1.5.2) + activerecord (= 7.1.5.2) + activestorage (= 7.1.5.2) + activesupport (= 7.1.5.2) + mail (>= 2.7.1) + net-imap + net-pop + net-smtp + actionmailer (7.1.5.2) + actionpack (= 7.1.5.2) + 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) - actionpack (7.2.2.2) - actionview (= 7.2.2.2) - activesupport (= 7.2.2.2) + actionpack (7.1.5.2) + actionview (= 7.1.5.2) + activesupport (= 7.1.5.2) nokogiri (>= 1.8.5) racc - rack (>= 2.2.4, < 3.2) + rack (>= 2.2.4) rack-session (>= 1.0.1) rack-test (>= 0.6.3) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) - useragent (~> 0.16) - actiontext (7.2.2.2) - actionpack (= 7.2.2.2) - activerecord (= 7.2.2.2) - activestorage (= 7.2.2.2) - activesupport (= 7.2.2.2) + actiontext (7.1.5.2) + actionpack (= 7.1.5.2) + activerecord (= 7.1.5.2) + activestorage (= 7.1.5.2) + activesupport (= 7.1.5.2) globalid (>= 0.6.0) nokogiri (>= 1.8.5) - actionview (7.2.2.2) - activesupport (= 7.2.2.2) + actionview (7.1.5.2) + activesupport (= 7.1.5.2) builder (~> 3.1) erubi (~> 1.11) rails-dom-testing (~> 2.2) rails-html-sanitizer (~> 1.6) active_record_query_trace (1.8) - activejob (7.2.2.2) - activesupport (= 7.2.2.2) + activejob (7.1.5.2) + activesupport (= 7.1.5.2) globalid (>= 0.3.6) - activemodel (7.2.2.2) - activesupport (= 7.2.2.2) - activerecord (7.2.2.2) - activemodel (= 7.2.2.2) - activesupport (= 7.2.2.2) + activemodel (7.1.5.2) + activesupport (= 7.1.5.2) + activerecord (7.1.5.2) + activemodel (= 7.1.5.2) + activesupport (= 7.1.5.2) timeout (>= 0.4.0) activerecord-import (2.1.0) activerecord (>= 4.2) - activestorage (7.2.2.2) - actionpack (= 7.2.2.2) - activejob (= 7.2.2.2) - activerecord (= 7.2.2.2) - activesupport (= 7.2.2.2) + activestorage (7.1.5.2) + actionpack (= 7.1.5.2) + activejob (= 7.1.5.2) + activerecord (= 7.1.5.2) + activesupport (= 7.1.5.2) marcel (~> 1.0) - activesupport (7.2.2.2) + activesupport (7.1.5.2) base64 benchmark (>= 0.3) bigdecimal - concurrent-ruby (~> 1.0, >= 1.3.1) + concurrent-ruby (~> 1.0, >= 1.0.2) connection_pool (>= 2.2.5) drb i18n (>= 1.6, < 2) logger (>= 1.4.2) minitest (>= 5.1) + mutex_m securerandom (>= 0.3) - tzinfo (~> 2.0, >= 2.0.5) + tzinfo (~> 2.0) acts-as-taggable-on (12.0.0) activerecord (>= 7.1, < 8.1) zeitwerk (>= 2.4, < 3.0) @@ -100,10 +121,10 @@ GEM administrate-field-active_storage (1.0.3) administrate (>= 0.2.2) rails (>= 7.0) - administrate-field-belongs_to_search (0.10.0) + administrate-field-belongs_to_search (0.9.0) administrate (>= 0.3, < 1.0) jbuilder (~> 2) - rails (>= 4.2, < 8.0) + rails (>= 4.2, < 7.2) selectize-rails (~> 0.6) ai-agents (0.7.0) ruby_llm (~> 1.8.2) @@ -120,8 +141,8 @@ GEM aws-sdk-s3 (~> 1, >= 1.123.0) aws-sdk-sns (~> 1, >= 1.61.0) aws-eventstream (1.4.0) - aws-partitions (1.1205.0) - aws-sdk-core (3.241.3) + aws-partitions (1.1198.0) + aws-sdk-core (3.240.0) aws-eventstream (~> 1, >= 1.3.0) aws-partitions (~> 1, >= 1.992.0) aws-sigv4 (~> 1.9) @@ -129,11 +150,11 @@ GEM bigdecimal jmespath (~> 1, >= 1.6.1) logger - aws-sdk-kms (1.120.0) - aws-sdk-core (~> 3, >= 3.241.3) + aws-sdk-kms (1.118.0) + aws-sdk-core (~> 3, >= 3.239.1) aws-sigv4 (~> 1.5) - aws-sdk-s3 (1.211.0) - aws-sdk-core (~> 3, >= 3.241.3) + aws-sdk-s3 (1.208.0) + aws-sdk-core (~> 3, >= 3.234.0) aws-sdk-kms (~> 1) aws-sigv4 (~> 1.5) aws-sdk-sns (1.70.0) @@ -141,22 +162,20 @@ GEM aws-sigv4 (~> 1.1) aws-sigv4 (1.12.1) aws-eventstream (~> 1, >= 1.0.2) - azure-blob (0.5.9.1) - rexml barnes (0.0.9) multi_json (~> 1) statsd-ruby (~> 1.1) base64 (0.3.0) bcrypt (3.1.20) - benchmark (0.5.0) - bigdecimal (4.0.1) + benchmark (0.4.1) + bigdecimal (3.2.2) bindex (0.8.1) bootsnap (1.16.0) msgpack (~> 1.2) brakeman (5.4.1) browser (5.3.1) builder (3.3.0) - bullet (7.2.0) + bullet (8.0.7) activesupport (>= 3.0.0) uniform_notifier (~> 1.11) bundle-audit (0.1.0) @@ -165,21 +184,17 @@ GEM bundler (>= 1.2.0, < 3) thor (~> 1.0) byebug (11.1.3) - cgi (0.5.1) childprocess (5.1.0) logger (~> 1.5) climate_control (1.2.0) coderay (1.1.3) - commonmarker (0.23.11) - concurrent-ruby (1.3.6) - connection_pool (3.0.2) + commonmarker (0.23.10) + concurrent-ruby (1.3.5) + connection_pool (2.5.3) crack (1.0.0) bigdecimal rexml crass (1.0.6) - cronex (0.15.0) - tzinfo - unicode (>= 0.4.4.5) csv (3.3.0) csv-safe (3.3.1) csv (~> 3.0) @@ -189,15 +204,14 @@ GEM activerecord (>= 5.a) database_cleaner-core (~> 2.0.0) database_cleaner-core (2.0.1) - datadog (2.25.0) - cgi - datadog-ruby_core_source (~> 3.5, >= 3.5.0) - libdatadog (~> 24.0.1.1.0) - libddwaf (~> 1.30.0.0.0) + datadog (2.19.0) + datadog-ruby_core_source (~> 3.4, >= 3.4.1) + libdatadog (~> 18.1.0.1.0) + libddwaf (~> 1.24.1.0.3) logger msgpack - datadog-ruby_core_source (3.5.1) - date (3.5.1) + datadog-ruby_core_source (3.4.1) + date (3.4.1) debug (1.8.0) irb (>= 1.5.0) reline (>= 0.3.1) @@ -208,10 +222,10 @@ GEM railties (>= 4.1.0) responders warden (~> 1.2.3) - devise-two-factor (6.3.0) - activesupport (>= 7.0, < 8.2) - devise (>= 4.0, < 5.0) - railties (>= 7.0, < 8.2) + devise-two-factor (6.1.0) + activesupport (>= 7.0, < 8.1) + devise (~> 4.0) + railties (>= 7.0, < 8.1) rotp (~> 6.0) devise_token_auth (1.2.5) bcrypt (~> 3.0) @@ -230,31 +244,31 @@ GEM down (5.4.0) addressable (~> 2.8) drb (2.2.3) - dry-cli (1.4.1) + dry-cli (1.1.0) dry-configurable (1.3.0) dry-core (~> 1.1) zeitwerk (~> 2.6) - dry-core (1.2.0) + dry-core (1.1.0) concurrent-ruby (~> 1.0) logger zeitwerk (~> 2.6) - dry-inflector (1.3.1) + dry-inflector (1.2.0) dry-initializer (3.2.0) dry-logic (1.6.0) bigdecimal concurrent-ruby (~> 1.0) dry-core (~> 1.1) zeitwerk (~> 2.6) - dry-schema (1.15.0) + dry-schema (1.14.1) concurrent-ruby (~> 1.0) dry-configurable (~> 1.0, >= 1.0.1) dry-core (~> 1.1) dry-initializer (~> 3.2) - dry-logic (~> 1.6) + dry-logic (~> 1.5) dry-types (~> 1.8) zeitwerk (~> 2.6) - dry-types (1.9.0) - bigdecimal (>= 3.0) + dry-types (1.8.3) + bigdecimal (~> 3.0) concurrent-ruby (~> 1.0) dry-core (~> 1.0) dry-inflector (~> 1.0) @@ -268,9 +282,8 @@ GEM ruby2_keywords email-provider-info (0.0.1) email_reply_trimmer (0.1.13) - erb (6.0.1) - erubi (1.13.1) - et-orbi (1.3.0) + erubi (1.13.0) + et-orbi (1.2.11) tzinfo event_stream_parser (1.0.0) execjs (2.8.1) @@ -284,27 +297,34 @@ GEM railties (>= 5.0.0) faker (3.2.0) i18n (>= 1.8.11, < 2) - faraday (2.9.0) - faraday-net_http (>= 2.0, < 3.2) - faraday-mashify (1.0.2) + faraday (2.13.1) + faraday-net_http (>= 2.0, < 3.5) + json + logger + faraday-follow_redirects (0.3.0) + faraday (>= 1, < 3) + faraday-mashify (1.0.0) faraday (~> 2.0) hashie faraday-multipart (1.0.4) multipart-post (~> 2) - faraday-net_http (3.1.0) - net-http + faraday-net_http (3.4.0) + 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 (~> 2.0) faraday_middleware-aws-sigv4 (1.0.1) aws-sigv4 (~> 1.0) faraday (>= 2.0, < 3) - fast-mcp (1.6.0) + fast-mcp (1.5.0) addressable (~> 2.8) base64 dry-schema (~> 1.14) json (~> 2.0) mime-types (~> 3.4) - rack (>= 2.0, < 4.0) + rack (~> 3.1) fcm (1.0.8) faraday (>= 1.0.0, < 3.0) googleauth (~> 1) @@ -421,21 +441,19 @@ GEM http-cookie (1.0.5) domain_name (~> 0.5) http-form_data (2.3.0) - httparty (0.24.2) + httparty (0.24.0) csv mini_mime (>= 1.0.0) multi_xml (>= 0.5.2) httpclient (2.8.3) - i18n (1.14.8) + i18n (1.14.7) concurrent-ruby (~> 1.0) image_processing (1.12.2) mini_magick (>= 4.9.5, < 5) ruby-vips (>= 2.0.17, < 3) - io-console (0.8.2) - irb (1.16.0) - pp (>= 0.6.0) - rdoc (>= 4.0.0) - reline (>= 0.4.2) + io-console (0.6.0) + irb (1.7.2) + reline (>= 0.3.6) iso-639 (0.3.8) csv jbuilder (2.11.5) @@ -446,7 +464,7 @@ GEM rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) - json (2.12.0) + json (2.13.2) json_refs (0.1.8) hana json_schemer (0.2.24) @@ -461,7 +479,7 @@ GEM judoscale-sidekiq (1.8.2) judoscale-ruby (= 1.8.2) sidekiq (>= 5.0) - jwt (2.8.1) + jwt (2.10.1) base64 kaminari (1.2.2) activesupport (>= 4.1.0) @@ -488,15 +506,15 @@ GEM logger (~> 1.6) letter_opener (1.10.0) launchy (>= 2.2, < 4) - libdatadog (24.0.1.1.0) - libdatadog (24.0.1.1.0-x86_64-linux) - libddwaf (1.30.0.0.0) + libdatadog (18.1.0.1.0) + libdatadog (18.1.0.1.0-x86_64-linux) + libddwaf (1.24.1.0.3) ffi (~> 1.0) - libddwaf (1.30.0.0.0-arm64-darwin) + libddwaf (1.24.1.0.3-arm64-darwin) ffi (~> 1.0) - libddwaf (1.30.0.0.0-x86_64-darwin) + libddwaf (1.24.1.0.3-x86_64-darwin) ffi (~> 1.0) - libddwaf (1.30.0.0.0-x86_64-linux) + libddwaf (1.24.1.0.3-x86_64-linux) ffi (~> 1.0) line-bot-api (1.28.0) lint_roller (1.1.0) @@ -513,7 +531,7 @@ GEM activesupport (>= 4) railties (>= 4) request_store (~> 1.0) - loofah (2.25.0) + loofah (2.23.1) crass (~> 1.0.2) nokogiri (>= 1.12.0) mail (2.8.1) @@ -533,19 +551,21 @@ GEM mini_magick (4.12.0) mini_mime (1.1.5) mini_portile2 (2.8.9) - minitest (5.27.0) + minitest (5.25.5) mock_redis (0.36.0) ruby2_keywords msgpack (1.8.0) multi_json (1.15.0) - multi_xml (0.8.1) + multi_xml (0.8.0) bigdecimal (>= 3.1, < 5) multipart-post (2.3.0) mutex_m (0.3.0) neighbor (0.2.3) activerecord (>= 5.2) - net-http (0.4.1) + net-http (0.6.0) uri + net-http-persistent (4.0.2) + connection_pool (~> 2.2) net-imap (0.4.20) date net-protocol @@ -562,14 +582,14 @@ GEM newrelic_rpm (9.6.0) base64 nio4r (2.7.3) - nokogiri (1.19.0) + nokogiri (1.18.9) mini_portile2 (~> 2.8.2) racc (~> 1.4) - nokogiri (1.19.0-arm64-darwin) + nokogiri (1.18.9-arm64-darwin) racc (~> 1.4) - nokogiri (1.19.0-x86_64-darwin) + nokogiri (1.18.9-x86_64-darwin) racc (~> 1.4) - nokogiri (1.19.0-x86_64-linux-gnu) + nokogiri (1.18.9-x86_64-linux-gnu) racc (~> 1.4) oauth (1.1.0) oauth-tty (~> 1.0, >= 1.0.1) @@ -587,8 +607,9 @@ GEM oj (3.16.10) bigdecimal (>= 3.0) ostruct (>= 0.2) - omniauth (2.1.2) + omniauth (2.1.4) hashie (>= 3.4.6) + logger rack (>= 2.2.3) rack-protection omniauth-google-oauth2 (1.1.3) @@ -640,9 +661,6 @@ GEM activerecord (>= 5.2) activesupport (>= 5.2) pgvector (0.1.1) - pp (0.6.3) - prettyprint - prettyprint (0.2.0) prism (1.4.0) procore-sift (1.0.0) activerecord (>= 6.1) @@ -651,9 +669,6 @@ GEM method_source (~> 1.0) pry-rails (0.3.9) pry (>= 0.10.4) - psych (5.3.1) - date - stringio public_suffix (6.0.2) puma (6.4.3) nio4r (~> 2.0) @@ -661,7 +676,7 @@ GEM activesupport (>= 3.0.0) raabro (1.4.0) racc (1.8.1) - rack (3.1.19) + rack (3.2.3) rack-attack (6.7.0) rack (>= 1.0, < 4) rack-contrib (2.5.0) @@ -679,57 +694,53 @@ GEM rack-session (2.1.1) base64 (>= 0.1.0) rack (>= 3.0.0) - rack-test (2.2.0) + rack-test (2.1.0) rack (>= 1.3) rack-timeout (0.6.3) - rackup (2.3.1) + rackup (2.2.1) rack (>= 3) - rails (7.2.2.2) - actioncable (= 7.2.2.2) - actionmailbox (= 7.2.2.2) - actionmailer (= 7.2.2.2) - actionpack (= 7.2.2.2) - actiontext (= 7.2.2.2) - actionview (= 7.2.2.2) - activejob (= 7.2.2.2) - activemodel (= 7.2.2.2) - activerecord (= 7.2.2.2) - activestorage (= 7.2.2.2) - activesupport (= 7.2.2.2) + rails (7.1.5.2) + actioncable (= 7.1.5.2) + actionmailbox (= 7.1.5.2) + actionmailer (= 7.1.5.2) + actionpack (= 7.1.5.2) + actiontext (= 7.1.5.2) + actionview (= 7.1.5.2) + activejob (= 7.1.5.2) + activemodel (= 7.1.5.2) + activerecord (= 7.1.5.2) + activestorage (= 7.1.5.2) + activesupport (= 7.1.5.2) bundler (>= 1.15.0) - railties (= 7.2.2.2) - rails-dom-testing (2.3.0) + railties (= 7.1.5.2) + rails-dom-testing (2.2.0) activesupport (>= 5.0.0) minitest nokogiri (>= 1.6) - rails-html-sanitizer (1.6.2) + rails-html-sanitizer (1.6.1) 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) - railties (7.2.2.2) - actionpack (= 7.2.2.2) - activesupport (= 7.2.2.2) - irb (~> 1.13) + railties (7.1.5.2) + actionpack (= 7.1.5.2) + activesupport (= 7.1.5.2) + irb rackup (>= 1.0.0) rake (>= 12.2) thor (~> 1.0, >= 1.2.2) zeitwerk (~> 2.6) rainbow (3.1.1) - rake (13.3.1) + rake (13.2.1) rb-fsevent (0.11.2) rb-inotify (0.10.1) ffi (~> 1.0) - rdoc (7.1.0) - erb - psych (>= 4.0.0) - tsort redis (5.0.6) redis-client (>= 0.9.0) - redis-client (0.25.2) + redis-client (0.22.2) connection_pool redis-namespace (1.10.0) redis (>= 4) regexp_parser (2.10.0) - reline (0.6.3) + reline (0.3.6) io-console (~> 0.5) representable (3.2.0) declarative (< 0.1.0) @@ -799,10 +810,6 @@ GEM rubocop-rspec (3.6.0) lint_roller (~> 1.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) event_stream_parser (>= 0.3.0, < 2.0.0) faraday (>= 1) @@ -825,8 +832,9 @@ GEM faraday-net_http (>= 1) faraday-retry (>= 1) marcel (~> 1.0) + ruby_llm-schema (~> 0.2.1) zeitwerk (~> 2) - ruby_llm-schema (0.1.0) + ruby_llm-schema (0.2.5) ruby_parser (3.20.0) sexp_processor (~> 4.16) sass (3.7.4) @@ -846,8 +854,9 @@ GEM parser scss_lint (0.60.0) sass (~> 3.5, >= 3.5.5) - searchkick (6.0.3) - activemodel (>= 7.2) + searchkick (5.5.2) + activemodel (>= 7.1) + hashie securerandom (0.4.1) seed_dump (3.3.1) activerecord (>= 4) @@ -876,17 +885,16 @@ GEM zeitwerk (~> 2.5) shoulda-matchers (5.3.0) activesupport (>= 5.2.0) - sidekiq (7.3.9) - base64 + sidekiq (7.3.1) + concurrent-ruby (< 2) connection_pool (>= 2.3.0) logger rack (>= 2.2.4) redis-client (>= 0.22.2) - sidekiq-cron (2.3.1) - cronex (>= 0.13.0) - fugit (~> 1.8, >= 1.11.1) + sidekiq-cron (1.12.0) + fugit (~> 1.8) globalid (>= 1.0.1) - sidekiq (>= 6.5.0) + sidekiq (>= 6) sidekiq_alive (2.5.0) gserver (~> 0.0.1) sidekiq (>= 5, < 9) @@ -926,13 +934,12 @@ GEM squasher (0.7.2) stackprof (0.2.25) statsd-ruby (1.5.0) - stringio (3.2.0) - stripe (18.1.0) + stripe (18.0.1) telephone_number (1.4.20) test-prof (1.2.1) - thor (1.5.0) - tidewave (0.4.1) - fast-mcp (~> 1.6.0) + thor (1.4.0) + tidewave (0.2.0) + fast-mcp (~> 1.5.0) rack (>= 2.0) rails (>= 7.1.0) tilt (2.3.0) @@ -941,8 +948,7 @@ GEM i18n timeout (0.4.3) trailblazer-option (0.1.2) - tsort (0.2.0) - twilio-ruby (5.77.0) + twilio-ruby (7.6.0) faraday (>= 0.9, < 3.0) jwt (>= 1.5, < 3.0) nokogiri (>= 1.6, < 2.0) @@ -958,25 +964,21 @@ GEM unf (0.1.4) unf_ext unf_ext (0.0.8.2) - unicode (0.4.4.5) unicode-display_width (3.1.4) unicode-emoji (~> 4.0, >= 4.0.4) unicode-emoji (4.0.4) uniform_notifier (1.17.0) - uri (1.1.1) + uri (1.0.4) uri_template (0.7.0) - useragent (0.16.11) valid_email2 (5.2.6) activemodel (>= 3.2) mail (~> 2.5) version_gem (1.1.4) - vite_rails (3.0.20) - railties (>= 5.1, < 9) + vite_rails (3.0.17) + railties (>= 5.1, < 8) vite_ruby (~> 3.0, >= 3.2.2) - vite_ruby (3.9.2) + vite_ruby (3.8.0) dry-cli (>= 0.7, < 2) - logger (~> 1.6) - mutex_m rack-proxy (~> 0.6, >= 0.6.1) zeitwerk (~> 2.2) warden (1.2.9) @@ -993,7 +995,7 @@ GEM addressable (>= 2.8.0) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - websocket-driver (0.8.0) + websocket-driver (0.7.7) base64 websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) @@ -1001,7 +1003,7 @@ GEM working_hours (1.4.1) activesupport (>= 3.2) tzinfo - zeitwerk (2.7.4) + zeitwerk (2.6.17) PLATFORMS arm64-darwin-20 @@ -1018,16 +1020,16 @@ DEPENDENCIES active_record_query_trace activerecord-import acts-as-taggable-on - administrate - administrate-field-active_storage - administrate-field-belongs_to_search + administrate (>= 0.20.1) + administrate-field-active_storage (>= 1.0.3) + administrate-field-belongs_to_search (>= 0.9.0) ai-agents (>= 0.7.0) annotaterb attr_extras audited (~> 5.4, >= 5.4.1) aws-actionmailbox-ses (~> 0) aws-sdk-s3 - azure-blob + azure-storage-blob! barnes bootsnap brakeman @@ -1036,7 +1038,7 @@ DEPENDENCIES bundle-audit byebug climate_control - commonmarker (~> 0.23.11) + commonmarker csv-safe database_cleaner datadog (~> 2.0) @@ -1106,10 +1108,10 @@ DEPENDENCIES puma pundit rack-attack (>= 6.7.0) - rack-cors + rack-cors (= 2.0.0) rack-mini-profiler (>= 3.2.0) rack-timeout - rails (~> 7.2.0) + rails (~> 7.1) redis redis-namespace responders (>= 3.1.1) @@ -1122,7 +1124,6 @@ DEPENDENCIES rubocop-performance rubocop-rails rubocop-rspec - rubocop-rspec_rails ruby-openai ruby_llm (>= 1.8.2) ruby_llm-schema @@ -1136,7 +1137,7 @@ DEPENDENCIES shopify_api shoulda-matchers sidekiq (>= 7.3.1) - sidekiq-cron (>= 2.3.1) + sidekiq-cron (>= 1.12.0) sidekiq_alive simplecov (>= 0.21) simplecov_json_formatter diff --git a/app/controllers/api/v1/accounts/integrations/linear_controller.rb b/app/controllers/api/v1/accounts/integrations/linear_controller.rb index 295739a57..eb6525bb1 100644 --- a/app/controllers/api/v1/accounts/integrations/linear_controller.rb +++ b/app/controllers/api/v1/accounts/integrations/linear_controller.rb @@ -28,7 +28,7 @@ class Api::V1::Accounts::Integrations::LinearController < Api::V1::Accounts::Bas end 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] render json: { error: issue[:error] }, status: :unprocessable_entity else diff --git a/app/controllers/super_admin/instance_statuses_controller.rb b/app/controllers/super_admin/instance_statuses_controller.rb index 3c6adc4c1..b0e97b95d 100644 --- a/app/controllers/super_admin/instance_statuses_controller.rb +++ b/app/controllers/super_admin/instance_statuses_controller.rb @@ -20,9 +20,7 @@ class SuperAdmin::InstanceStatusesController < SuperAdmin::ApplicationController end def instance_meta - migrations_paths = ActiveRecord::Migrator.migrations_paths - migrations_context = ActiveRecord::MigrationContext.new(migrations_paths) - @metrics['Database Migrations'] = migrations_context.needs_migration? ? 'pending' : 'completed' + @metrics['Database Migrations'] = ActiveRecord::Base.connection.migration_context.needs_migration? ? 'pending' : 'completed' end def chatwoot_version diff --git a/app/models/installation_config.rb b/app/models/installation_config.rb index 6f9bf3269..a7400460c 100644 --- a/app/models/installation_config.rb +++ b/app/models/installation_config.rb @@ -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 # FIX ME : fixes breakage of installation config. we need to migrate. # 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 before_validation :set_lock diff --git a/app/models/integrations/hook.rb b/app/models/integrations/hook.rb index 8805000ef..518b405da 100644 --- a/app/models/integrations/hook.rb +++ b/app/models/integrations/hook.rb @@ -18,7 +18,7 @@ class Integrations::Hook < ApplicationRecord include Reauthorizable 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 # TODO: Remove guard once encryption keys become mandatory (target 3-4 releases out). @@ -86,9 +86,7 @@ class Integrations::Hook < ApplicationRecord end def ensure_hook_type - return if app.blank? - - self.hook_type = app.params[:hook_type] + self.hook_type = app.params[:hook_type] if app.present? end def validate_settings_json_schema diff --git a/app/models/message.rb b/app/models/message.rb index aa4bb2f55..20b9a756d 100644 --- a/app/models/message.rb +++ b/app/models/message.rb @@ -421,8 +421,6 @@ class Message < ApplicationRecord end def reindex_for_search - return unless respond_to?(:reindex) - reindex(mode: :async) end end diff --git a/app/models/user.rb b/app/models/user.rb index 741c54107..b14bcd158 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -69,7 +69,7 @@ class User < ApplicationRecord # TODO: remove in a future version once online status is moved to account 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 # work because :validatable in devise overrides this. @@ -77,7 +77,7 @@ class User < ApplicationRecord validates :email, presence: true - serialize :otp_backup_codes, coder: JSON, type: Array + serialize :otp_backup_codes, type: Array # Encrypt sensitive MFA fields encrypts :otp_secret, deterministic: true @@ -88,7 +88,7 @@ class User < ApplicationRecord accepts_nested_attributes_for :account_users 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 :reviewed_csat_survey_responses, foreign_key: 'review_notes_updated_by_id', class_name: 'CsatSurveyResponse', dependent: :nullify, inverse_of: :review_notes_updated_by diff --git a/app/services/crm/leadsquared/setup_service.rb b/app/services/crm/leadsquared/setup_service.rb index 12117115b..0433f68fd 100644 --- a/app/services/crm/leadsquared/setup_service.rb +++ b/app/services/crm/leadsquared/setup_service.rb @@ -82,7 +82,7 @@ class Crm::Leadsquared::SetupService end def update_hook_settings(params) - @hook.settings = @hook.settings.merge(params.stringify_keys) + @hook.settings = @hook.settings.merge(params) @hook.save! end diff --git a/config/application.rb b/config/application.rb index f6cd37931..aa150794a 100644 --- a/config/application.rb +++ b/config/application.rb @@ -36,7 +36,7 @@ end module Chatwoot class Application < Rails::Application # 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('enterprise/lib') diff --git a/config/storage.yml b/config/storage.yml index ccf00e382..c01eb04d4 100644 --- a/config/storage.yml +++ b/config/storage.yml @@ -23,7 +23,7 @@ google: # Use rails credentials:edit to set the Azure Storage secret (as azure_storage:storage_access_key) microsoft: - service: AzureBlob + service: AzureStorage storage_account_name: <%= ENV.fetch('AZURE_STORAGE_ACCOUNT_NAME', '') %> storage_access_key: <%= ENV.fetch('AZURE_STORAGE_ACCESS_KEY', '') %> container: <%= ENV.fetch('AZURE_STORAGE_CONTAINER', '') %> diff --git a/db/migrate/20230515051424_update_article_image_keys.rb b/db/migrate/20230515051424_update_article_image_keys.rb index 21891b35f..3e8b9f77d 100644 --- a/db/migrate/20230515051424_update_article_image_keys.rb +++ b/db/migrate/20230515051424_update_article_image_keys.rb @@ -12,11 +12,8 @@ class ArticleKeyConverter def convert_key(id) verifier_name = 'ActiveStorage' - secret_key_base = Rails.application.credentials.secret_key_base || - Rails.application.secrets.secret_key_base - key_generator = ActiveSupport::KeyGenerator.new(secret_key_base, - iterations: 1000, - hash_digest_class: OpenSSL::Digest::SHA1) + key_generator = ActiveSupport::KeyGenerator.new(Rails.application.secrets.secret_key_base, iterations: 1000, + hash_digest_class: OpenSSL::Digest::SHA1) key_generator = ActiveSupport::CachingKeyGenerator.new(key_generator) secret = key_generator.generate_key(verifier_name.to_s) verifier = ActiveSupport::MessageVerifier.new(secret) diff --git a/docker/Dockerfile b/docker/Dockerfile index 16e5cb253..645a61a55 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -29,8 +29,6 @@ RUN apk update && apk add --no-cache \ tar \ build-base \ tzdata \ - yaml-dev \ - pkgconf \ postgresql-dev \ postgresql-client \ git \ diff --git a/lib/seeders/reports/message_creator.rb b/lib/seeders/reports/message_creator.rb index cf3e826ab..fc10716d9 100644 --- a/lib/seeders/reports/message_creator.rb +++ b/lib/seeders/reports/message_creator.rb @@ -15,7 +15,7 @@ class Seeders::Reports::MessageCreator end 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 message_count.times do |i| diff --git a/package.json b/package.json index 777c87fd2..04821480d 100644 --- a/package.json +++ b/package.json @@ -144,8 +144,8 @@ "prosemirror-model": "^1.22.3", "size-limit": "^8.2.4", "tailwindcss": "^3.4.13", - "vite": "5.4.21", - "vite-plugin-ruby": "^5.1.1", + "vite": "^5.4.21", + "vite-plugin-ruby": "^5.0.0", "vitest": "3.0.5" }, "engines": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6f48be943..7a1b6f35f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -351,8 +351,8 @@ importers: specifier: 5.4.21 version: 5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) vite-plugin-ruby: - specifier: ^5.1.1 - version: 5.1.1(vite@5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) + specifier: ^5.0.0 + version: 5.0.0(vite@5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0)) vitest: 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) @@ -4519,8 +4519,8 @@ packages: engines: {node: ^18.0.0 || >=20.0.0} hasBin: true - vite-plugin-ruby@5.1.1: - resolution: {integrity: sha512-I1dXJq2ywdvTD2Cz5LYNcYLujqQ3eUxPoCjruRdfm2QBtHBY15NEeb6x5HuPM3T5S+y8S3p9fwRsieQQCjk0gg==} + vite-plugin-ruby@5.0.0: + resolution: {integrity: sha512-c8PjTp21Ah/ttgnNUyu0qvCXZI08Jr9I24oUKg3TRIRhF5GcOZ++6wtlTCrNFd9COEQbpXHxlRIXd/MEg0iZJw==} peerDependencies: vite: 5.4.21 @@ -6245,7 +6245,7 @@ snapshots: agent-base@6.0.2: dependencies: - debug: 4.4.3 + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -7647,7 +7647,7 @@ snapshots: dependencies: '@tootallnate/once': 2.0.0 agent-base: 6.0.2 - debug: 4.4.3 + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -7661,7 +7661,7 @@ snapshots: https-proxy-agent@5.0.1: dependencies: agent-base: 6.0.2 - debug: 4.4.3 + debug: 4.4.0 transitivePeerDependencies: - supports-color @@ -9599,9 +9599,9 @@ snapshots: - supports-color - 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: - debug: 4.4.3 + debug: 4.3.5 fast-glob: 3.3.2 vite: 5.4.21(@types/node@22.7.0)(sass@1.79.3)(terser@5.33.0) transitivePeerDependencies: diff --git a/spec/builders/v2/report_builder_spec.rb b/spec/builders/v2/report_builder_spec.rb index 9de1eed3b..3f86b0348 100644 --- a/spec/builders/v2/report_builder_spec.rb +++ b/spec/builders/v2/report_builder_spec.rb @@ -1,22 +1,15 @@ require 'rails_helper' -RSpec.describe V2::ReportBuilder do +describe V2::ReportBuilder do include ActiveJob::TestHelper - self.use_transactional_tests = false - - def truncate_test_data - 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) } + let_it_be(:account) { create(:account) } + let_it_be(:label_1) { create(:label, title: 'Label_1', account: account) } + let_it_be(:label_2) { create(:label, title: 'Label_2', account: account) } 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 user = create(:user, account: account) inbox = create(:inbox, account: account) @@ -28,7 +21,7 @@ RSpec.describe V2::ReportBuilder do perform_enqueued_jobs do 10.times do conversation = create(:conversation, account: account, - inbox: inbox, + inbox: inbox, assignee: user, created_at: Time.zone.today) create_list(:message, 5, message_type: 'outgoing', account: account, inbox: inbox, @@ -44,7 +37,7 @@ RSpec.describe V2::ReportBuilder do 5.times do conversation = create(:conversation, account: account, - inbox: inbox, + inbox: inbox, assignee: user, created_at: (Time.zone.today - 2.days)) create_list(:message, 3, message_type: 'outgoing', account: account, inbox: inbox, diff --git a/spec/builders/v2/reports/label_summary_builder_spec.rb b/spec/builders/v2/reports/label_summary_builder_spec.rb index 0f299798d..f0eb6cefd 100644 --- a/spec/builders/v2/reports/label_summary_builder_spec.rb +++ b/spec/builders/v2/reports/label_summary_builder_spec.rb @@ -2,19 +2,11 @@ require 'rails_helper' RSpec.describe V2::Reports::LabelSummaryBuilder do include ActiveJob::TestHelper - self.use_transactional_tests = false - def truncate_test_data - 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) } - let!(:label_3) { create(:label, title: 'label_3', account: account) } + let_it_be(:account) { create(:account) } + let_it_be(:label_1) { create(:label, title: 'label_1', account: account) } + let_it_be(:label_2) { create(:label, title: 'label_2', account: account) } + let_it_be(:label_3) { create(:label, title: 'label_3', account: account) } let(:params) do { @@ -100,7 +92,7 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do # Create conversations with label_1 3.times do conversation = create(:conversation, account: account, - inbox: inbox, + inbox: inbox, assignee: user, created_at: Time.zone.today) create_list(:message, 2, message_type: 'outgoing', account: account, inbox: inbox, @@ -118,7 +110,7 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do # Create conversations with label_2 2.times do conversation = create(:conversation, account: account, - inbox: inbox, + inbox: inbox, assignee: user, created_at: Time.zone.today) create_list(:message, 1, message_type: 'outgoing', account: account, inbox: inbox, @@ -237,7 +229,7 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do perform_enqueued_jobs do # Conversation within range conversation_in_range = create(:conversation, account: account, - inbox: inbox, + inbox: inbox, assignee: user, created_at: 2.days.ago) conversation_in_range.update_labels('label_1') conversation_in_range.label_list @@ -252,7 +244,7 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do # Conversation outside range (too old) conversation_out_of_range = create(:conversation, account: account, - inbox: inbox, + inbox: inbox, assignee: user, created_at: 1.week.ago) conversation_out_of_range.update_labels('label_1') conversation_out_of_range.label_list @@ -294,7 +286,7 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do perform_enqueued_jobs do conversation = create(:conversation, account: account, - inbox: inbox, + inbox: inbox, assignee: user, created_at: Time.zone.today) conversation.update_labels('label_1') conversation.label_list @@ -331,8 +323,8 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do let(:account2_builder) do described_class.new(account: account2, params: { business_hours: false, - since: test_date.in_time_zone.to_i.to_s, - until: test_date.end_of_day.in_time_zone.to_i.to_s, + since: test_date.to_time.to_i.to_s, + until: test_date.end_of_day.to_time.to_i.to_s, timezone_offset: 0 }) end @@ -351,7 +343,7 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do perform_enqueued_jobs do conversation = create(:conversation, account: account2, - inbox: inbox, + inbox: inbox, assignee: user, created_at: test_date) conversation.update_labels(unique_label_name) conversation.label_list @@ -366,7 +358,6 @@ RSpec.describe V2::Reports::LabelSummaryBuilder do # Second resolution conversation.resolved! end - perform_enqueued_jobs end end diff --git a/spec/controllers/api/v1/accounts/macros_controller_spec.rb b/spec/controllers/api/v1/accounts/macros_controller_spec.rb index 7fb6fcf63..87d301d88 100644 --- a/spec/controllers/api/v1/accounts/macros_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/macros_controller_spec.rb @@ -388,7 +388,7 @@ RSpec.describe 'Api::V1::Accounts::MacrosController', type: :request do headers: administrator.create_new_auth_token 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 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 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 it 'Assign the labels' do diff --git a/spec/jobs/bulk_actions_job_spec.rb b/spec/jobs/bulk_actions_job_spec.rb index 0e589f86a..3b0ff8133 100644 --- a/spec/jobs/bulk_actions_job_spec.rb +++ b/spec/jobs/bulk_actions_job_spec.rb @@ -1,6 +1,12 @@ require 'rails_helper' 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) } 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_2) { 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 Conversation.all.find_each do |conversation| @@ -34,10 +38,10 @@ RSpec.describe BulkActionsJob do params = { type: 'Conversation', 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) @@ -50,32 +54,32 @@ RSpec.describe BulkActionsJob do params = { type: 'Conversation', 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) - expect(conversation_1.reload.assignee_id).to eq(agent.id) - expect(conversation_2.reload.assignee_id).to eq(agent.id) - expect(conversation_3.reload.assignee_id).to eq(agent.id) + expect(Conversation.first.assignee_id).to eq(agent.id) + expect(Conversation.second.assignee_id).to eq(agent.id) + expect(Conversation.third.assignee_id).to eq(agent.id) end it 'bulk updates the snoozed_until' do params = { type: 'Conversation', 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) - expect(conversation_1.reload.snoozed_until).to be_present - expect(conversation_2.reload.snoozed_until).to be_present - expect(conversation_3.reload.snoozed_until).to be_present + expect(Conversation.first.snoozed_until).to be_present + expect(Conversation.second.snoozed_until).to be_present + expect(Conversation.third.snoozed_until).to be_present end end end diff --git a/spec/mailers/administrator_notifications/shared/smtp_config_shared.rb b/spec/mailers/administrator_notifications/shared/smtp_config_shared.rb index 0bb18a337..96d4dbb0d 100644 --- a/spec/mailers/administrator_notifications/shared/smtp_config_shared.rb +++ b/spec/mailers/administrator_notifications/shared/smtp_config_shared.rb @@ -1,9 +1,11 @@ # frozen_string_literal: true RSpec.shared_context 'with smtp config' do - around do |example| - # Set SMTP_ADDRESS so mailers build a Mail::Message in test without touching real SMTP. - # Scoped to this shared context to avoid affecting other specs. - with_modified_env('SMTP_ADDRESS' => 'smtp.example.com') { example.run } + before do + # We need to use allow_any_instance_of here because smtp_config_set_or_development? + # is defined in ApplicationMailer and needs to be stubbed for all mailer instances + # 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 diff --git a/spec/models/contact_inbox_spec.rb b/spec/models/contact_inbox_spec.rb index b19d58934..c0a2faf9e 100644 --- a/spec/models/contact_inbox_spec.rb +++ b/spec/models/contact_inbox_spec.rb @@ -28,7 +28,8 @@ RSpec.describe ContactInbox do obj.reload # 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 obj.update(source_id: '234234323') diff --git a/spec/services/account/sign_up_email_validation_service_spec.rb b/spec/services/account/sign_up_email_validation_service_spec.rb index a4b1231be..3f907f02c 100644 --- a/spec/services/account/sign_up_email_validation_service_spec.rb +++ b/spec/services/account/sign_up_email_validation_service_spec.rb @@ -20,7 +20,7 @@ RSpec.describe Account::SignUpEmailValidationService, type: :service do it 'raises InvalidEmail with invalid message' do allow(ValidEmail2::Address).to receive(:new).with(email).and_return(invalid_email_address) 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')) end end @@ -32,7 +32,7 @@ RSpec.describe Account::SignUpEmailValidationService, type: :service do it 'raises InvalidEmail with blocked domain message' do allow(ValidEmail2::Address).to receive(:new).with(email).and_return(valid_email_address) 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')) end end @@ -44,7 +44,7 @@ RSpec.describe Account::SignUpEmailValidationService, type: :service do it 'raises InvalidEmail with blocked domain message' do allow(ValidEmail2::Address).to receive(:new).with(email).and_return(valid_email_address) 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')) end end @@ -56,7 +56,7 @@ RSpec.describe Account::SignUpEmailValidationService, type: :service do it 'raises InvalidEmail with disposable message' do allow(ValidEmail2::Address).to receive(:new).with(email).and_return(disposable_email_address) 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')) end end diff --git a/spec/services/telegram/incoming_message_service_spec.rb b/spec/services/telegram/incoming_message_service_spec.rb index 3d63e6a8f..528161afe 100644 --- a/spec/services/telegram/incoming_message_service_spec.rb +++ b/spec/services/telegram/incoming_message_service_spec.rb @@ -42,11 +42,6 @@ describe Telegram::IncomingMessageService do } 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 context 'when valid text message params' do it 'creates appropriate conversations, message and contacts' do @@ -56,7 +51,7 @@ describe Telegram::IncomingMessageService do }.with_indifferent_access described_class.new(inbox: telegram_channel.inbox, params: params).perform 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') end end @@ -69,9 +64,9 @@ describe Telegram::IncomingMessageService do }.with_indifferent_access described_class.new(inbox: telegram_channel.inbox, params: params).perform expect(telegram_channel.inbox.conversations.count).not_to eq(0) - expect(contact_for.name).to eq('Sojan Jose') - expect(contact_for.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.name).to eq('Sojan Jose') + expect(Contact.all.first.additional_attributes['social_telegram_user_id']).to eq(23) + expect(Contact.all.first.additional_attributes['social_telegram_user_name']).to eq('sojan') expect(telegram_channel.inbox.messages.first.content).to eq('test') 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.last.additional_attributes).to include({ 'chat_id' => 23, 'business_connection_id' => 'eooW3KF5WB5HxTD7T826' }) - contact = contact_for + contact = Contact.all.first expect(contact.name).to eq('Sojan Jose') expect(contact.additional_attributes['language_code']).to eq('en') 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.last.additional_attributes).to include({ 'chat_id' => 23, 'business_connection_id' => 'eooW3KF5WB5HxTD7T826' }) - contact = contact_for + contact = Contact.all.first expect(contact.name).to eq('Sojan Jose') # TODO: The language code is not present when we send the first message to the client. # Should we update it when the user replies? @@ -166,9 +161,9 @@ describe Telegram::IncomingMessageService do }.with_indifferent_access described_class.new(inbox: telegram_channel.inbox, params: params).perform expect(telegram_channel.inbox.conversations.count).not_to eq(0) - expect(contact_for.name).to eq('Sojan Jose') - expect(contact_for.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.name).to eq('Sojan Jose') + expect(Contact.all.first.additional_attributes['social_telegram_user_id']).to eq(23) + 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') end end @@ -187,7 +182,7 @@ describe Telegram::IncomingMessageService do }.with_indifferent_access described_class.new(inbox: telegram_channel.inbox, params: params).perform 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') end end @@ -212,7 +207,7 @@ describe Telegram::IncomingMessageService do }.with_indifferent_access described_class.new(inbox: telegram_channel.inbox, params: params).perform 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') end end @@ -234,7 +229,7 @@ describe Telegram::IncomingMessageService do }.with_indifferent_access described_class.new(inbox: telegram_channel.inbox, params: params).perform 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') end end @@ -263,7 +258,7 @@ describe Telegram::IncomingMessageService do }.with_indifferent_access described_class.new(inbox: telegram_channel.inbox, params: params).perform 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') end end @@ -282,7 +277,7 @@ describe Telegram::IncomingMessageService do }.with_indifferent_access described_class.new(inbox: telegram_channel.inbox, params: params).perform 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') end end @@ -303,7 +298,7 @@ describe Telegram::IncomingMessageService do }.with_indifferent_access described_class.new(inbox: telegram_channel.inbox, params: params).perform 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') end end @@ -341,7 +336,7 @@ describe Telegram::IncomingMessageService do }.with_indifferent_access described_class.new(inbox: telegram_channel.inbox, params: params).perform 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') end @@ -360,7 +355,7 @@ describe Telegram::IncomingMessageService do }.with_indifferent_access described_class.new(inbox: telegram_channel.inbox, params: params).perform 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 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 expect(telegram_channel.inbox.conversations.count).not_to eq(0) - expect(contact_for(5_171_248).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.name).to eq('Sojan Jose') + 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') end end @@ -411,7 +406,7 @@ describe Telegram::IncomingMessageService do }.with_indifferent_access described_class.new(inbox: telegram_channel.inbox, params: params).perform 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') end end diff --git a/spec/services/whatsapp/incoming_message_whatsapp_cloud_service_spec.rb b/spec/services/whatsapp/incoming_message_whatsapp_cloud_service_spec.rb index 286292774..2ac3bb651 100644 --- a/spec/services/whatsapp/incoming_message_whatsapp_cloud_service_spec.rb +++ b/spec/services/whatsapp/incoming_message_whatsapp_cloud_service_spec.rb @@ -3,7 +3,6 @@ require 'rails_helper' describe Whatsapp::IncomingMessageWhatsappCloudService do describe '#perform' do let!(:whatsapp_channel) { create(:channel_whatsapp, provider: 'whatsapp_cloud', sync_templates: false, validate_provider_config: false) } - let(:sender_number) { '2423423243' } let(:params) do { phone_number: whatsapp_channel.phone_number, @@ -11,9 +10,9 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do entry: [{ changes: [{ value: { - contacts: [{ profile: { name: 'Sojan Jose' }, wa_id: sender_number }], + contacts: [{ profile: { name: 'Sojan Jose' }, wa_id: '2423423243' }], messages: [{ - from: sender_number, + from: '2423423243', image: { id: 'b1c68f38-8734-4ad3-b4a1-ef0c10d683', mime_type: 'image/jpeg', @@ -49,7 +48,7 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do described_class.new(inbox: whatsapp_channel.inbox, params: params).perform 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.attachments.present?).to be false expect(whatsapp_channel.authorization_error_count).to eq(1) @@ -64,9 +63,9 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do entry: [{ changes: [{ value: { - contacts: [{ profile: { name: 'Sojan Jose' }, wa_id: sender_number }], + contacts: [{ profile: { name: 'Sojan Jose' }, wa_id: '2423423243' }], messages: [{ - from: sender_number, + from: '2423423243', image: { id: 'b1c68f38-8734-4ad3-b4a1-ef0c10d683', mime_type: 'image/jpeg', @@ -89,7 +88,7 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do it 'with attachment errors' do described_class.new(inbox: whatsapp_channel.inbox, params: error_params).perform 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) end end @@ -99,7 +98,7 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do described_class.new(inbox: whatsapp_channel.inbox, params: { phone_number: whatsapp_channel.phone_number, object: 'whatsapp_business_account', entry: {} }).perform 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) end end @@ -137,7 +136,7 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do end def expect_contact_name - expect(contact_from_number&.name).to eq('Sojan Jose') + expect(Contact.all.first.name).to eq('Sojan Jose') end def expect_message_content @@ -147,12 +146,4 @@ describe Whatsapp::IncomingMessageWhatsappCloudService do def expect_message_has_attachment expect(whatsapp_channel.inbox.messages.first.attachments.present?).to be true end - - def contact_phone_number - "+#{sender_number}" - end - - def contact_from_number - Contact.find_by(phone_number: contact_phone_number) - end end