From b7351354315560ca641b4cbfbb601f4196a98fe2 Mon Sep 17 00:00:00 2001 From: Jordan Brough Date: Wed, 23 Mar 2022 09:16:28 -0600 Subject: [PATCH 01/91] chore: Fix "action_mailer.delivery_method" in the test env (#4257) Fixes: #4247 --- config/initializers/mailer.rb | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/config/initializers/mailer.rb b/config/initializers/mailer.rb index 54a22f0dc..5c317d62f 100644 --- a/config/initializers/mailer.rb +++ b/config/initializers/mailer.rb @@ -3,7 +3,6 @@ Rails.application.configure do # Configuration Related to Action Mailer ######################################### - config.action_mailer.delivery_method = :smtp # We need the application frontend url to be used in our emails config.action_mailer.default_url_options = { host: ENV['FRONTEND_URL'] } if ENV['FRONTEND_URL'].present? # We load certain mailer templates from our database. This ensures changes to it is reflected immediately @@ -26,7 +25,7 @@ Rails.application.configure do smtp_settings[:ssl] = ActiveModel::Type::Boolean.new.cast(ENV.fetch('SMTP_SSL', true)) if ENV['SMTP_SSL'] smtp_settings[:tls] = ActiveModel::Type::Boolean.new.cast(ENV.fetch('SMTP_TLS', true)) if ENV['SMTP_TLS'] - config.action_mailer.delivery_method = :smtp + config.action_mailer.delivery_method = :smtp unless Rails.env.test? config.action_mailer.smtp_settings = smtp_settings # You can use letter opener for your local development by setting the environment variable config.action_mailer.delivery_method = :letter_opener if Rails.env.development? && ENV['LETTER_OPENER'] From 8b9aea231c271458bf3de594b3a09f04439ac82c Mon Sep 17 00:00:00 2001 From: giquieu Date: Thu, 24 Mar 2022 04:14:34 -0300 Subject: [PATCH 02/91] feat: support audio player on widget (#4250) --- .../widget/assets/scss/views/_conversation.scss | 10 ++++++++-- app/javascript/widget/components/AgentMessage.vue | 3 +++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/app/javascript/widget/assets/scss/views/_conversation.scss b/app/javascript/widget/assets/scss/views/_conversation.scss index dbf7f716f..7de312eac 100644 --- a/app/javascript/widget/assets/scss/views/_conversation.scss +++ b/app/javascript/widget/assets/scss/views/_conversation.scss @@ -51,7 +51,10 @@ .has-attachment { overflow: hidden; - padding: 0; + + :not([audio]) { + padding: 0; + } &.has-text { margin-top: $space-smaller; @@ -213,11 +216,14 @@ display: inline-block; font-size: $font-size-default; line-height: 1.5; - max-width: 100%; padding: $space-slab $space-normal; text-align: left; word-break: break-word; + :not([audio]) { + max-width: 100%; + } + >a { color: $color-primary; word-break: break-all; diff --git a/app/javascript/widget/components/AgentMessage.vue b/app/javascript/widget/components/AgentMessage.vue index def769bc3..f3d499126 100755 --- a/app/javascript/widget/components/AgentMessage.vue +++ b/app/javascript/widget/components/AgentMessage.vue @@ -34,6 +34,9 @@ :readable-time="readableTime" @error="onImageLoadError" /> + From c2647a1f271afb5e9593bb6353c81df90704740d Mon Sep 17 00:00:00 2001 From: Jordan Brough Date: Thu, 24 Mar 2022 01:58:25 -0600 Subject: [PATCH 03/91] chore: Use "destroy!" instead of "destroy" when not checking the return value (#4259) --- app/controllers/api/v1/accounts/agent_bots_controller.rb | 2 +- app/controllers/api/v1/accounts/agents_controller.rb | 2 +- app/controllers/api/v1/accounts/campaigns_controller.rb | 2 +- .../api/v1/accounts/canned_responses_controller.rb | 2 +- app/controllers/api/v1/accounts/contacts/notes_controller.rb | 2 +- .../v1/accounts/custom_attribute_definitions_controller.rb | 2 +- app/controllers/api/v1/accounts/custom_filters_controller.rb | 2 +- app/controllers/api/v1/accounts/inboxes_controller.rb | 2 +- .../api/v1/accounts/integrations/hooks_controller.rb | 2 +- .../api/v1/accounts/integrations/slack_controller.rb | 2 +- .../api/v1/accounts/kbase/categories_controller.rb | 2 +- app/controllers/api/v1/accounts/kbase/portals_controller.rb | 2 +- app/controllers/api/v1/accounts/labels_controller.rb | 2 +- app/controllers/api/v1/accounts/teams_controller.rb | 2 +- app/controllers/api/v1/accounts/webhooks_controller.rb | 2 +- .../api/v1/notification_subscriptions_controller.rb | 2 +- app/controllers/platform/api/v1/account_users_controller.rb | 2 +- app/models/team.rb | 2 +- spec/controllers/api/v1/widget/messages_controller_spec.rb | 4 ++-- spec/models/conversation_spec.rb | 2 +- 20 files changed, 21 insertions(+), 21 deletions(-) diff --git a/app/controllers/api/v1/accounts/agent_bots_controller.rb b/app/controllers/api/v1/accounts/agent_bots_controller.rb index 7348ef255..9f4ef2cd9 100644 --- a/app/controllers/api/v1/accounts/agent_bots_controller.rb +++ b/app/controllers/api/v1/accounts/agent_bots_controller.rb @@ -18,7 +18,7 @@ class Api::V1::Accounts::AgentBotsController < Api::V1::Accounts::BaseController end def destroy - @agent_bot.destroy + @agent_bot.destroy! head :ok end diff --git a/app/controllers/api/v1/accounts/agents_controller.rb b/app/controllers/api/v1/accounts/agents_controller.rb index 68389d3cd..09b648a6f 100644 --- a/app/controllers/api/v1/accounts/agents_controller.rb +++ b/app/controllers/api/v1/accounts/agents_controller.rb @@ -18,7 +18,7 @@ class Api::V1::Accounts::AgentsController < Api::V1::Accounts::BaseController end def destroy - @agent.current_account_user.destroy + @agent.current_account_user.destroy! head :ok end diff --git a/app/controllers/api/v1/accounts/campaigns_controller.rb b/app/controllers/api/v1/accounts/campaigns_controller.rb index 18d0998c8..6d2fb7729 100644 --- a/app/controllers/api/v1/accounts/campaigns_controller.rb +++ b/app/controllers/api/v1/accounts/campaigns_controller.rb @@ -11,7 +11,7 @@ class Api::V1::Accounts::CampaignsController < Api::V1::Accounts::BaseController end def destroy - @campaign.destroy + @campaign.destroy! head :ok end diff --git a/app/controllers/api/v1/accounts/canned_responses_controller.rb b/app/controllers/api/v1/accounts/canned_responses_controller.rb index bbfa9c4b7..031ffc415 100644 --- a/app/controllers/api/v1/accounts/canned_responses_controller.rb +++ b/app/controllers/api/v1/accounts/canned_responses_controller.rb @@ -17,7 +17,7 @@ class Api::V1::Accounts::CannedResponsesController < Api::V1::Accounts::BaseCont end def destroy - @canned_response.destroy + @canned_response.destroy! head :ok end diff --git a/app/controllers/api/v1/accounts/contacts/notes_controller.rb b/app/controllers/api/v1/accounts/contacts/notes_controller.rb index fb9f3c5c3..7bc9dd121 100644 --- a/app/controllers/api/v1/accounts/contacts/notes_controller.rb +++ b/app/controllers/api/v1/accounts/contacts/notes_controller.rb @@ -10,7 +10,7 @@ class Api::V1::Accounts::Contacts::NotesController < Api::V1::Accounts::Contacts end def destroy - @note.destroy + @note.destroy! head :ok end diff --git a/app/controllers/api/v1/accounts/custom_attribute_definitions_controller.rb b/app/controllers/api/v1/accounts/custom_attribute_definitions_controller.rb index 419540438..3840644ce 100644 --- a/app/controllers/api/v1/accounts/custom_attribute_definitions_controller.rb +++ b/app/controllers/api/v1/accounts/custom_attribute_definitions_controller.rb @@ -18,7 +18,7 @@ class Api::V1::Accounts::CustomAttributeDefinitionsController < Api::V1::Account end def destroy - @custom_attribute_definition.destroy + @custom_attribute_definition.destroy! head :no_content end diff --git a/app/controllers/api/v1/accounts/custom_filters_controller.rb b/app/controllers/api/v1/accounts/custom_filters_controller.rb index e6c7b6857..188f0e623 100644 --- a/app/controllers/api/v1/accounts/custom_filters_controller.rb +++ b/app/controllers/api/v1/accounts/custom_filters_controller.rb @@ -18,7 +18,7 @@ class Api::V1::Accounts::CustomFiltersController < Api::V1::Accounts::BaseContro end def destroy - @custom_filter.destroy + @custom_filter.destroy! head :no_content end diff --git a/app/controllers/api/v1/accounts/inboxes_controller.rb b/app/controllers/api/v1/accounts/inboxes_controller.rb index bcea2d9d7..66a71985d 100644 --- a/app/controllers/api/v1/accounts/inboxes_controller.rb +++ b/app/controllers/api/v1/accounts/inboxes_controller.rb @@ -73,7 +73,7 @@ class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController end def destroy - @inbox.destroy + @inbox.destroy! head :ok end diff --git a/app/controllers/api/v1/accounts/integrations/hooks_controller.rb b/app/controllers/api/v1/accounts/integrations/hooks_controller.rb index 18a16a30d..dd2af4ef2 100644 --- a/app/controllers/api/v1/accounts/integrations/hooks_controller.rb +++ b/app/controllers/api/v1/accounts/integrations/hooks_controller.rb @@ -11,7 +11,7 @@ class Api::V1::Accounts::Integrations::HooksController < Api::V1::Accounts::Base end def destroy - @hook.destroy + @hook.destroy! head :ok end diff --git a/app/controllers/api/v1/accounts/integrations/slack_controller.rb b/app/controllers/api/v1/accounts/integrations/slack_controller.rb index 537ddd688..b5571b245 100644 --- a/app/controllers/api/v1/accounts/integrations/slack_controller.rb +++ b/app/controllers/api/v1/accounts/integrations/slack_controller.rb @@ -20,7 +20,7 @@ class Api::V1::Accounts::Integrations::SlackController < Api::V1::Accounts::Base end def destroy - @hook.destroy + @hook.destroy! head :ok end diff --git a/app/controllers/api/v1/accounts/kbase/categories_controller.rb b/app/controllers/api/v1/accounts/kbase/categories_controller.rb index e114ee5e4..a40053dd2 100644 --- a/app/controllers/api/v1/accounts/kbase/categories_controller.rb +++ b/app/controllers/api/v1/accounts/kbase/categories_controller.rb @@ -14,7 +14,7 @@ class Api::V1::Accounts::Kbase::CategoriesController < Api::V1::Accounts::Kbase: end def destroy - @category.destroy + @category.destroy! head :ok end diff --git a/app/controllers/api/v1/accounts/kbase/portals_controller.rb b/app/controllers/api/v1/accounts/kbase/portals_controller.rb index e0788b587..804b2d421 100644 --- a/app/controllers/api/v1/accounts/kbase/portals_controller.rb +++ b/app/controllers/api/v1/accounts/kbase/portals_controller.rb @@ -14,7 +14,7 @@ class Api::V1::Accounts::Kbase::PortalsController < Api::V1::Accounts::Kbase::Ba end def destroy - @portal.destroy + @portal.destroy! head :ok end diff --git a/app/controllers/api/v1/accounts/labels_controller.rb b/app/controllers/api/v1/accounts/labels_controller.rb index 547b9e6d6..54455943b 100644 --- a/app/controllers/api/v1/accounts/labels_controller.rb +++ b/app/controllers/api/v1/accounts/labels_controller.rb @@ -18,7 +18,7 @@ class Api::V1::Accounts::LabelsController < Api::V1::Accounts::BaseController end def destroy - @label.destroy + @label.destroy! head :ok end diff --git a/app/controllers/api/v1/accounts/teams_controller.rb b/app/controllers/api/v1/accounts/teams_controller.rb index adfeed62e..e8688dcfb 100644 --- a/app/controllers/api/v1/accounts/teams_controller.rb +++ b/app/controllers/api/v1/accounts/teams_controller.rb @@ -18,7 +18,7 @@ class Api::V1::Accounts::TeamsController < Api::V1::Accounts::BaseController end def destroy - @team.destroy + @team.destroy! head :ok end diff --git a/app/controllers/api/v1/accounts/webhooks_controller.rb b/app/controllers/api/v1/accounts/webhooks_controller.rb index 58f9b21a0..0add18047 100644 --- a/app/controllers/api/v1/accounts/webhooks_controller.rb +++ b/app/controllers/api/v1/accounts/webhooks_controller.rb @@ -16,7 +16,7 @@ class Api::V1::Accounts::WebhooksController < Api::V1::Accounts::BaseController end def destroy - @webhook.destroy + @webhook.destroy! head :ok end diff --git a/app/controllers/api/v1/notification_subscriptions_controller.rb b/app/controllers/api/v1/notification_subscriptions_controller.rb index 5f1cf30e4..a01c2ca03 100644 --- a/app/controllers/api/v1/notification_subscriptions_controller.rb +++ b/app/controllers/api/v1/notification_subscriptions_controller.rb @@ -9,7 +9,7 @@ class Api::V1::NotificationSubscriptionsController < Api::BaseController def destroy notification_subscription = NotificationSubscription.where(["subscription_attributes->>'push_token' = ?", params[:push_token]]).first - notification_subscription.destroy + notification_subscription.destroy! head :ok end diff --git a/app/controllers/platform/api/v1/account_users_controller.rb b/app/controllers/platform/api/v1/account_users_controller.rb index 8f651cfd9..b8a8f701a 100644 --- a/app/controllers/platform/api/v1/account_users_controller.rb +++ b/app/controllers/platform/api/v1/account_users_controller.rb @@ -13,7 +13,7 @@ class Platform::Api::V1::AccountUsersController < PlatformController end def destroy - @resource.account_users.find_by(user_id: account_user_params[:user_id])&.destroy + @resource.account_users.find_by(user_id: account_user_params[:user_id])&.destroy! head :ok end diff --git a/app/models/team.rb b/app/models/team.rb index 22e9b3fc6..7c8a7f205 100644 --- a/app/models/team.rb +++ b/app/models/team.rb @@ -38,7 +38,7 @@ class Team < ApplicationRecord end def remove_member(user_id) - team_members.find_by(user_id: user_id)&.destroy + team_members.find_by(user_id: user_id)&.destroy! end def messages diff --git a/spec/controllers/api/v1/widget/messages_controller_spec.rb b/spec/controllers/api/v1/widget/messages_controller_spec.rb index be0ccae05..983f6f132 100644 --- a/spec/controllers/api/v1/widget/messages_controller_spec.rb +++ b/spec/controllers/api/v1/widget/messages_controller_spec.rb @@ -33,7 +33,7 @@ RSpec.describe '/api/v1/widget/messages', type: :request do describe 'POST /api/v1/widget/messages' do context 'when post request is made' do it 'creates message in conversation' do - conversation.destroy # Test all params + conversation.destroy! # Test all params message_params = { content: 'hello world', timestamp: Time.current } post api_v1_widget_messages_url, params: { website_token: web_widget.website_token, message: message_params }, @@ -46,7 +46,7 @@ RSpec.describe '/api/v1/widget/messages', type: :request do end it 'does not create the message' do - conversation.destroy # Test all params + conversation.destroy! # Test all params message_params = { content: "#{'h' * 150 * 1000}a", timestamp: Time.current } post api_v1_widget_messages_url, params: { website_token: web_widget.website_token, message: message_params }, diff --git a/spec/models/conversation_spec.rb b/spec/models/conversation_spec.rb index 356127043..d214b973b 100644 --- a/spec/models/conversation_spec.rb +++ b/spec/models/conversation_spec.rb @@ -482,7 +482,7 @@ RSpec.describe Conversation, type: :model do let!(:notification) { create(:notification, notification_type: 'conversation_creation', primary_actor: conversation) } it 'delete associated notifications if conversation is deleted' do - conversation.destroy + conversation.destroy! expect { notification.reload }.to raise_error ActiveRecord::RecordNotFound end end From 0cf970dafda39dcdf21d0ce51c1f3ddfeeaf6045 Mon Sep 17 00:00:00 2001 From: Jordan Brough Date: Thu, 24 Mar 2022 02:01:19 -0600 Subject: [PATCH 04/91] chore: Eliminate deprecation warning in "app_config_controller_spec.rb" (#4258) Fix the warning: Using `should` from rspec-expectations' old `:should` syntax without explicitly enabling the syntax is deprecated. Use the new `:expect` syntax or explicitly enable `:should` with `config.expect_with(:rspec) { |c| c.syntax = :should }` instead. --- spec/controllers/super_admin/app_config_controller_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/controllers/super_admin/app_config_controller_spec.rb b/spec/controllers/super_admin/app_config_controller_spec.rb index 3a81ac7d3..9cf7b9075 100644 --- a/spec/controllers/super_admin/app_config_controller_spec.rb +++ b/spec/controllers/super_admin/app_config_controller_spec.rb @@ -37,7 +37,7 @@ RSpec.describe 'Super Admin Application Config API', type: :request do post '/super_admin/app_config', params: { app_config: { TESTKEY: 'TESTVALUE' } } expect(response.status).to eq(302) - expect(response).should redirect_to(super_admin_app_config_path) + expect(response).to redirect_to(super_admin_app_config_path) config = GlobalConfig.get('TESTKEY') expect(config['TESTKEY']).to eq('TESTVALUE') From 7577c9c888bd1c79edfc946ddd8e63984915d2bd Mon Sep 17 00:00:00 2001 From: Vishnu Narayanan Date: Thu, 24 Mar 2022 13:33:15 +0530 Subject: [PATCH 05/91] fix: drop conv and campaign seq on account delete (#4256) Conversation and campaign sequences persist in the database even after the related account is deleted. This PR adds an after_desttory callback on the account model that will delete the associated sequences. Fixes: #4252 --- app/models/account.rb | 6 ++++++ spec/models/account_spec.rb | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/app/models/account.rb b/app/models/account.rb index ee595902a..be081767c 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -79,6 +79,7 @@ class Account < ApplicationRecord before_validation :validate_limit_keys after_create_commit :notify_creation + after_destroy :remove_account_sequences def agents users.where(account_users: { role: :agent }) @@ -137,4 +138,9 @@ class Account < ApplicationRecord def validate_limit_keys # method overridden in enterprise module end + + def remove_account_sequences + ActiveRecord::Base.connection.exec_query("drop sequence IF EXISTS camp_dpid_seq_#{id}") + ActiveRecord::Base.connection.exec_query("drop sequence IF EXISTS conv_dpid_seq_#{id}") + end end diff --git a/spec/models/account_spec.rb b/spec/models/account_spec.rb index bd835865b..ff5f9cca5 100644 --- a/spec/models/account_spec.rb +++ b/spec/models/account_spec.rb @@ -30,4 +30,14 @@ RSpec.describe Account do expect(account.usage_limits).to eq({ agents: ChatwootApp.max_limit, inboxes: ChatwootApp.max_limit }) end end + + context 'when after_destroy is called' do + it 'conv_dpid_seq and camp_dpid_seq_ are deleted' do + account = create(:account) + query = "select * from information_schema.sequences where sequence_name in ('camp_dpid_seq_#{account.id}', 'conv_dpid_seq_#{account.id}');" + expect(ActiveRecord::Base.connection.execute(query).count).to eq(2) + account.destroy + expect(ActiveRecord::Base.connection.execute(query).count).to eq(0) + end + end end From 14c53b8b5449e675ce339223ddd0e43e43a4ebdb Mon Sep 17 00:00:00 2001 From: Jordan Brough Date: Thu, 24 Mar 2022 02:20:04 -0600 Subject: [PATCH 06/91] chore: Use "contain_exactly" in some tests (#4243) --- .../api/v1/accounts/bulk_actions_controller_spec.rb | 12 ++++++------ spec/listeners/automation_rule_listener_spec.rb | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/spec/controllers/api/v1/accounts/bulk_actions_controller_spec.rb b/spec/controllers/api/v1/accounts/bulk_actions_controller_spec.rb index 598b2789c..27376b84f 100644 --- a/spec/controllers/api/v1/accounts/bulk_actions_controller_spec.rb +++ b/spec/controllers/api/v1/accounts/bulk_actions_controller_spec.rb @@ -109,8 +109,8 @@ RSpec.describe 'Api::V1::Accounts::BulkActionsController', type: :request do expect(response).to have_http_status(:success) end - expect(Conversation.first.label_list).to eq(%w[support priority_customer]) - expect(Conversation.second.label_list).to eq(%w[support priority_customer]) + expect(Conversation.first.label_list).to contain_exactly('support', 'priority_customer') + expect(Conversation.second.label_list).to contain_exactly('support', 'priority_customer') end end end @@ -126,8 +126,8 @@ RSpec.describe 'Api::V1::Accounts::BulkActionsController', type: :request do params = { type: 'Conversation', ids: Conversation.first(3).pluck(:display_id), labels: { remove: %w[support] } } - expect(Conversation.first.label_list).to eq(%w[support priority_customer]) - expect(Conversation.second.label_list).to eq(%w[support priority_customer]) + expect(Conversation.first.label_list).to contain_exactly('support', 'priority_customer') + expect(Conversation.second.label_list).to contain_exactly('support', 'priority_customer') perform_enqueued_jobs do post "/api/v1/accounts/#{account.id}/bulk_actions", @@ -137,8 +137,8 @@ RSpec.describe 'Api::V1::Accounts::BulkActionsController', type: :request do expect(response).to have_http_status(:success) end - expect(Conversation.first.label_list).to eq(['priority_customer']) - expect(Conversation.second.label_list).to eq(['priority_customer']) + expect(Conversation.first.label_list).to contain_exactly('priority_customer') + expect(Conversation.second.label_list).to contain_exactly('priority_customer') end end end diff --git a/spec/listeners/automation_rule_listener_spec.rb b/spec/listeners/automation_rule_listener_spec.rb index 8a24a7ea1..ff289a6dd 100644 --- a/spec/listeners/automation_rule_listener_spec.rb +++ b/spec/listeners/automation_rule_listener_spec.rb @@ -77,7 +77,7 @@ describe AutomationRuleListener do listener.conversation_status_changed(event) conversation.reload - expect(conversation.labels.pluck(:name)).to eq(%w[support priority_customer]) + expect(conversation.labels.pluck(:name)).to contain_exactly('support', 'priority_customer') end it 'triggers automation rule to assign best agents' do @@ -177,7 +177,7 @@ describe AutomationRuleListener do listener.conversation_updated(event) conversation.reload - expect(conversation.labels.pluck(:name)).to eq(%w[support priority_customer]) + expect(conversation.labels.pluck(:name)).to contain_exactly('support', 'priority_customer') end it 'triggers automation rule to assign best agents' do @@ -268,7 +268,7 @@ describe AutomationRuleListener do listener.message_created(event) conversation.reload - expect(conversation.labels.pluck(:name)).to eq(%w[support priority_customer]) + expect(conversation.labels.pluck(:name)).to contain_exactly('support', 'priority_customer') end it 'triggers automation rule to assign best agent' do From 60a0709de61348dd8ea72a3b399a9967851973eb Mon Sep 17 00:00:00 2001 From: Tejaswini Chile Date: Thu, 24 Mar 2022 15:38:28 +0530 Subject: [PATCH 07/91] Fix: added validation for custom and additional attribute (#4260) --- app/models/conversation.rb | 2 ++ .../jsonb_attributes_length_validator.rb | 21 +++++++++++++ spec/models/conversation_spec.rb | 31 +++++++++++++++++++ 3 files changed, 54 insertions(+) create mode 100644 app/models/jsonb_attributes_length_validator.rb diff --git a/app/models/conversation.rb b/app/models/conversation.rb index 6e3a91fb2..7bdb30ede 100644 --- a/app/models/conversation.rb +++ b/app/models/conversation.rb @@ -50,6 +50,8 @@ class Conversation < ApplicationRecord validates :account_id, presence: true validates :inbox_id, presence: true before_validation :validate_additional_attributes + validates :additional_attributes, jsonb_attributes_length: true + validates :custom_attributes, jsonb_attributes_length: true enum status: { open: 0, resolved: 1, pending: 2, snoozed: 3 } diff --git a/app/models/jsonb_attributes_length_validator.rb b/app/models/jsonb_attributes_length_validator.rb new file mode 100644 index 000000000..2eda4a354 --- /dev/null +++ b/app/models/jsonb_attributes_length_validator.rb @@ -0,0 +1,21 @@ +class JsonbAttributesLengthValidator < ActiveModel::EachValidator + def validate_each(record, attribute, value) + return if value.empty? + + @attribute = attribute + @record = record + + value.each do |key, attribute_value| + validate_keys(key, attribute_value) + end + end + + def validate_keys(key, attribute_value) + case attribute_value.class.name + when 'String' + @record.errors.add @attribute, "#{key} length should be < 1500" if attribute_value.length > 1500 + when 'Integer' + @record.errors.add @attribute, "#{key} value should be < 9999999999" if attribute_value > 9_999_999_999 + end + end +end diff --git a/spec/models/conversation_spec.rb b/spec/models/conversation_spec.rb index d214b973b..a1d67f7d0 100644 --- a/spec/models/conversation_spec.rb +++ b/spec/models/conversation_spec.rb @@ -58,6 +58,37 @@ RSpec.describe Conversation, type: :model do end end + describe '.validate jsonb attributes' do + let(:account) { create(:account) } + let(:agent) { create(:user, email: 'agent1@example.com', account: account) } + let(:inbox) { create(:inbox, account: account) } + let(:conversation) do + create( + :conversation, + account: account, + contact: create(:contact, account: account), + inbox: inbox, + assignee: nil + ) + end + + it 'validate length of additional_attributes value' do + conversation.additional_attributes = { company_name: 'some_company' * 200, contact_number: 19_999_999_999 } + conversation.valid? + error_messages = conversation.errors.messages + expect(error_messages[:additional_attributes][0]).to eq('company_name length should be < 1500') + expect(error_messages[:additional_attributes][1]).to eq('contact_number value should be < 9999999999') + end + + it 'validate length of custom_attributes value' do + conversation.custom_attributes = { company_name: 'some_company' * 200, contact_number: 19_999_999_999 } + conversation.valid? + error_messages = conversation.errors.messages + expect(error_messages[:custom_attributes][0]).to eq('company_name length should be < 1500') + expect(error_messages[:custom_attributes][1]).to eq('contact_number value should be < 9999999999') + end + end + describe '.after_update' do let!(:account) { create(:account) } let!(:old_assignee) do From 8e153d6350ffc5eab8f8dc2d64492a9500843397 Mon Sep 17 00:00:00 2001 From: Sojan Jose Date: Thu, 24 Mar 2022 19:25:07 +0530 Subject: [PATCH 08/91] fix: Redis 6 on Heroku breaks ActionCable config (#4269) Heroku made some SSL/TLS changes with Redis 6, which is breaking the ActionCable configuration. Hence providing an environment variable configuration `REDIS_OPENSSL_VERIFY_MODE` to fix that. set the value `none` for this environment variable in your Heroku installations where breakage occurs. fixes: #2420 --- .env.example | 5 +++++ app.json | 4 ++++ config/application.rb | 9 +++++++++ config/cable.yml | 2 ++ lib/redis/config.rb | 1 + spec/lib/redis/config_spec.rb | 4 ++-- 6 files changed, 23 insertions(+), 2 deletions(-) diff --git a/.env.example b/.env.example index 36ca66be1..cc7e1c2dd 100644 --- a/.env.example +++ b/.env.example @@ -32,6 +32,11 @@ REDIS_SENTINELS= # You can find list of master using "SENTINEL masters" command REDIS_SENTINEL_MASTER_NAME= +# Redis premium breakage in heroku fix +# enable the following configuration +# ref: https://github.com/chatwoot/chatwoot/issues/2420 +# REDIS_OPENSSL_VERIFY_MODE=none + # Postgres Database config variables POSTGRES_HOST=postgres POSTGRES_USERNAME=postgres diff --git a/app.json b/app.json index 0d908761c..64edc4a81 100644 --- a/app.json +++ b/app.json @@ -32,6 +32,10 @@ "INSTALLATION_ENV": { "description": "Installation method used for Chatwoot.", "value": "heroku" + }, + "REDIS_OPENSSL_VERIFY_MODE":{ + "description": "OpenSSL verification mode for Redis connections. ref https://help.heroku.com/HC0F8CUS/redis-connection-issues", + "value": "none" } }, "formation": { diff --git a/config/application.rb b/config/application.rb index 0c7490dd7..4a114e0d7 100644 --- a/config/application.rb +++ b/config/application.rb @@ -33,4 +33,13 @@ module Chatwoot def self.config @config ||= Rails.configuration.x end + + def self.redis_ssl_verify_mode + # Introduced this method to fix the issue in heroku where redis connections fail for redis 6 + # ref: https://github.com/chatwoot/chatwoot/issues/2420 + # + # unless the redis verify mode is explicitly specified as none, we will fall back to the default 'verify peer' + # ref: https://www.rubydoc.info/stdlib/openssl/OpenSSL/SSL/SSLContext#DEFAULT_PARAMS-constant + ENV['REDIS_OPENSSL_VERIFY_MODE'] == 'none' ? OpenSSL::SSL::VERIFY_NONE : OpenSSL::SSL::VERIFY_PEER + end end diff --git a/config/cable.yml b/config/cable.yml index 6bb7a7844..3ecf68ee8 100644 --- a/config/cable.yml +++ b/config/cable.yml @@ -2,6 +2,8 @@ default: &default adapter: redis url: <%= ENV.fetch('REDIS_URL', 'redis://127.0.0.1:6379') %> password: <%= ENV.fetch('REDIS_PASSWORD', nil).presence %> + ssl_params: + verify_mode: <%= Chatwoot.redis_ssl_verify_mode %> channel_prefix: <%= "chatwoot_#{Rails.env}_action_cable" %> development: diff --git a/lib/redis/config.rb b/lib/redis/config.rb index 6e286f142..8e91b5bb0 100644 --- a/lib/redis/config.rb +++ b/lib/redis/config.rb @@ -13,6 +13,7 @@ module Redis::Config { url: ENV.fetch('REDIS_URL', 'redis://127.0.0.1:6379'), password: ENV.fetch('REDIS_PASSWORD', nil).presence, + ssl_params: { verify_mode: Chatwoot.redis_ssl_verify_mode }, reconnect_attempts: 2, network_timeout: 5 } diff --git a/spec/lib/redis/config_spec.rb b/spec/lib/redis/config_spec.rb index a82065328..a9093c341 100644 --- a/spec/lib/redis/config_spec.rb +++ b/spec/lib/redis/config_spec.rb @@ -16,7 +16,7 @@ describe ::Redis::Config do it 'checks for app redis config' do app_config = described_class.app - expect(app_config.keys).to match_array([:url, :password, :network_timeout, :reconnect_attempts]) + expect(app_config.keys).to match_array([:url, :password, :network_timeout, :reconnect_attempts, :ssl_params]) expect(app_config[:url]).to eq(redis_url) expect(app_config[:password]).to eq(redis_pasword) end @@ -46,7 +46,7 @@ describe ::Redis::Config do end it 'checks for app redis config' do - expect(described_class.app.keys).to match_array([:url, :password, :sentinels, :network_timeout, :reconnect_attempts]) + expect(described_class.app.keys).to match_array([:url, :password, :sentinels, :network_timeout, :reconnect_attempts, :ssl_params]) expect(described_class.app[:url]).to eq("redis://#{redis_master_name}") expect(described_class.app[:sentinels]).to match_array(expected_sentinels) end From 131c0a8668c45eaebcbe416dd6d9daf01855b583 Mon Sep 17 00:00:00 2001 From: Jordan Brough Date: Thu, 24 Mar 2022 13:06:59 -0600 Subject: [PATCH 09/91] chore: Don't send confirmation email when creating User via platform api (#4272) The platform api automatically confirms users so we don't need to send this email. --- app/controllers/platform/api/v1/users_controller.rb | 2 +- spec/controllers/platform/api/v1/users_controller_spec.rb | 8 +++++--- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/controllers/platform/api/v1/users_controller.rb b/app/controllers/platform/api/v1/users_controller.rb index bf5b642f8..c9f256c6f 100644 --- a/app/controllers/platform/api/v1/users_controller.rb +++ b/app/controllers/platform/api/v1/users_controller.rb @@ -7,8 +7,8 @@ class Platform::Api::V1::UsersController < PlatformController def create @resource = (User.find_by(email: user_params[:email]) || User.new(user_params)) + @resource.skip_confirmation! @resource.save! - @resource.confirm @platform_app.platform_app_permissibles.find_or_create_by!(permissible: @resource) end diff --git a/spec/controllers/platform/api/v1/users_controller_spec.rb b/spec/controllers/platform/api/v1/users_controller_spec.rb index cc6fe448f..e2e9d17df 100644 --- a/spec/controllers/platform/api/v1/users_controller_spec.rb +++ b/spec/controllers/platform/api/v1/users_controller_spec.rb @@ -95,9 +95,11 @@ RSpec.describe 'Platform Users API', type: :request do let(:platform_app) { create(:platform_app) } it 'creates a new user and permissible for the user' do - post '/platform/api/v1/users/', params: { name: 'test', email: 'test@test.com', password: 'Password1!', - custom_attributes: { test: 'test_create' } }, - headers: { api_access_token: platform_app.access_token.token }, as: :json + expect do + post '/platform/api/v1/users/', params: { name: 'test', email: 'test@test.com', password: 'Password1!', + custom_attributes: { test: 'test_create' } }, + headers: { api_access_token: platform_app.access_token.token }, as: :json + end.not_to enqueue_mail expect(response).to have_http_status(:success) data = JSON.parse(response.body) From 6bfe0f2fc15af58cdf47c326f7c7bd2eb750679b Mon Sep 17 00:00:00 2001 From: Sivin Varghese <64252451+iamsivin@users.noreply.github.com> Date: Fri, 25 Mar 2022 11:27:45 +0530 Subject: [PATCH 10/91] feat: Add support for rich editor and allow CCs in email for a new conversation. (#4194) * feat: Add support for rich editor and allow CCs in email for a new conversation. * Minor fixes Co-authored-by: Fayaz Ahmed <15716057+fayazara@users.noreply.github.com> Co-authored-by: Muhsin Keloth --- .../widgets/conversation/ReplyEmailHead.vue | 4 +- .../conversation/contact/ConversationForm.vue | 46 ++++++++++++++++++- 2 files changed, 46 insertions(+), 4 deletions(-) diff --git a/app/javascript/dashboard/components/widgets/conversation/ReplyEmailHead.vue b/app/javascript/dashboard/components/widgets/conversation/ReplyEmailHead.vue index b2c7dd589..b2ec48805 100644 --- a/app/javascript/dashboard/components/widgets/conversation/ReplyEmailHead.vue +++ b/app/javascript/dashboard/components/widgets/conversation/ReplyEmailHead.vue @@ -8,7 +8,7 @@
-