Merge branch 'release/3.10.1'
This commit is contained in:
2
Gemfile
2
Gemfile
@@ -228,7 +228,7 @@ group :development, :test do
|
|||||||
gem 'mock_redis'
|
gem 'mock_redis'
|
||||||
gem 'pry-rails'
|
gem 'pry-rails'
|
||||||
gem 'rspec_junit_formatter'
|
gem 'rspec_junit_formatter'
|
||||||
gem 'rspec-rails', '>= 6.0.3'
|
gem 'rspec-rails', '>= 6.1.3'
|
||||||
gem 'rubocop', require: false
|
gem 'rubocop', require: false
|
||||||
gem 'rubocop-performance', require: false
|
gem 'rubocop-performance', require: false
|
||||||
gem 'rubocop-rails', require: false
|
gem 'rubocop-rails', require: false
|
||||||
|
|||||||
20
Gemfile.lock
20
Gemfile.lock
@@ -223,7 +223,7 @@ GEM
|
|||||||
http (>= 3.0)
|
http (>= 3.0)
|
||||||
ruby2_keywords
|
ruby2_keywords
|
||||||
email_reply_trimmer (0.1.13)
|
email_reply_trimmer (0.1.13)
|
||||||
erubi (1.12.0)
|
erubi (1.13.0)
|
||||||
et-orbi (1.2.7)
|
et-orbi (1.2.7)
|
||||||
tzinfo
|
tzinfo
|
||||||
execjs (2.8.1)
|
execjs (2.8.1)
|
||||||
@@ -460,7 +460,7 @@ 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.7)
|
mini_portile2 (2.8.7)
|
||||||
minitest (5.23.1)
|
minitest (5.24.0)
|
||||||
mock_redis (0.36.0)
|
mock_redis (0.36.0)
|
||||||
ruby2_keywords
|
ruby2_keywords
|
||||||
msgpack (1.7.0)
|
msgpack (1.7.0)
|
||||||
@@ -489,14 +489,14 @@ GEM
|
|||||||
newrelic_rpm (9.6.0)
|
newrelic_rpm (9.6.0)
|
||||||
base64
|
base64
|
||||||
nio4r (2.7.3)
|
nio4r (2.7.3)
|
||||||
nokogiri (1.16.5)
|
nokogiri (1.16.6)
|
||||||
mini_portile2 (~> 2.8.2)
|
mini_portile2 (~> 2.8.2)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.16.5-arm64-darwin)
|
nokogiri (1.16.6-arm64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.16.5-x86_64-darwin)
|
nokogiri (1.16.6-x86_64-darwin)
|
||||||
racc (~> 1.4)
|
racc (~> 1.4)
|
||||||
nokogiri (1.16.5-x86_64-linux)
|
nokogiri (1.16.6-x86_64-linux)
|
||||||
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)
|
||||||
@@ -631,13 +631,13 @@ GEM
|
|||||||
strscan (>= 3.0.9)
|
strscan (>= 3.0.9)
|
||||||
rspec-core (3.13.0)
|
rspec-core (3.13.0)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-expectations (3.13.0)
|
rspec-expectations (3.13.1)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-mocks (3.13.1)
|
rspec-mocks (3.13.1)
|
||||||
diff-lcs (>= 1.2.0, < 2.0)
|
diff-lcs (>= 1.2.0, < 2.0)
|
||||||
rspec-support (~> 3.13.0)
|
rspec-support (~> 3.13.0)
|
||||||
rspec-rails (6.1.2)
|
rspec-rails (6.1.3)
|
||||||
actionpack (>= 6.1)
|
actionpack (>= 6.1)
|
||||||
activesupport (>= 6.1)
|
activesupport (>= 6.1)
|
||||||
railties (>= 6.1)
|
railties (>= 6.1)
|
||||||
@@ -819,7 +819,7 @@ GEM
|
|||||||
working_hours (1.4.1)
|
working_hours (1.4.1)
|
||||||
activesupport (>= 3.2)
|
activesupport (>= 3.2)
|
||||||
tzinfo
|
tzinfo
|
||||||
zeitwerk (2.6.15)
|
zeitwerk (2.6.16)
|
||||||
|
|
||||||
PLATFORMS
|
PLATFORMS
|
||||||
arm64-darwin-20
|
arm64-darwin-20
|
||||||
@@ -922,7 +922,7 @@ DEPENDENCIES
|
|||||||
responders (>= 3.1.1)
|
responders (>= 3.1.1)
|
||||||
rest-client
|
rest-client
|
||||||
reverse_markdown
|
reverse_markdown
|
||||||
rspec-rails (>= 6.0.3)
|
rspec-rails (>= 6.1.3)
|
||||||
rspec_junit_formatter
|
rspec_junit_formatter
|
||||||
rubocop
|
rubocop
|
||||||
rubocop-performance
|
rubocop-performance
|
||||||
|
|||||||
@@ -257,7 +257,16 @@ export default {
|
|||||||
html_content: { full: fullHTMLContent } = {},
|
html_content: { full: fullHTMLContent } = {},
|
||||||
text_content: { full: fullTextContent } = {},
|
text_content: { full: fullTextContent } = {},
|
||||||
} = this.contentAttributes.email || {};
|
} = this.contentAttributes.email || {};
|
||||||
return fullHTMLContent || fullTextContent || '';
|
|
||||||
|
if (fullHTMLContent) {
|
||||||
|
return fullHTMLContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fullTextContent) {
|
||||||
|
return fullTextContent.replace(/\n/g, '<br>');
|
||||||
|
}
|
||||||
|
|
||||||
|
return '';
|
||||||
},
|
},
|
||||||
displayQuotedButton() {
|
displayQuotedButton() {
|
||||||
if (this.emailMessageContent.includes('<blockquote')) {
|
if (this.emailMessageContent.includes('<blockquote')) {
|
||||||
|
|||||||
@@ -42,14 +42,12 @@ class Notification::PushNotificationService
|
|||||||
app_account_conversation_url(account_id: conversation.account_id, id: conversation.display_id)
|
app_account_conversation_url(account_id: conversation.account_id, id: conversation.display_id)
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_browser_push?(subscription)
|
def can_send_browser_push?(subscription)
|
||||||
VapidService.public_key && subscription.browser_push?
|
VapidService.public_key && subscription.browser_push?
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_browser_push(subscription)
|
def browser_push_payload(subscription)
|
||||||
return unless send_browser_push?(subscription)
|
{
|
||||||
|
|
||||||
WebPush.payload_send(
|
|
||||||
message: JSON.generate(push_message),
|
message: JSON.generate(push_message),
|
||||||
endpoint: subscription.subscription_attributes['endpoint'],
|
endpoint: subscription.subscription_attributes['endpoint'],
|
||||||
p256dh: subscription.subscription_attributes['p256dh'],
|
p256dh: subscription.subscription_attributes['p256dh'],
|
||||||
@@ -62,11 +60,22 @@ class Notification::PushNotificationService
|
|||||||
ssl_timeout: 5,
|
ssl_timeout: 5,
|
||||||
open_timeout: 5,
|
open_timeout: 5,
|
||||||
read_timeout: 5
|
read_timeout: 5
|
||||||
)
|
}
|
||||||
rescue WebPush::ExpiredSubscription
|
end
|
||||||
|
|
||||||
|
def send_browser_push(subscription)
|
||||||
|
return unless can_send_browser_push?(subscription)
|
||||||
|
|
||||||
|
WebPush.payload_send(browser_push_payload(subscription))
|
||||||
|
Rails.logger.info("Browser push sent to #{user.email} with title #{push_message[:title]}")
|
||||||
|
rescue WebPush::ExpiredSubscription, WebPush::InvalidSubscription, WebPush::Unauthorized => e
|
||||||
|
Rails.logger.info "WebPush subscription expired: #{e.message}"
|
||||||
subscription.destroy!
|
subscription.destroy!
|
||||||
rescue Errno::ECONNRESET, Net::OpenTimeout, Net::ReadTimeout => e
|
rescue Errno::ECONNRESET, Net::OpenTimeout, Net::ReadTimeout => e
|
||||||
Rails.logger.error "WebPush operation error: #{e.message}"
|
Rails.logger.error "WebPush operation error: #{e.message}"
|
||||||
|
rescue StandardError => e
|
||||||
|
ChatwootExceptionTracker.new(e, account: notification.account).capture_exception
|
||||||
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_fcm_push(subscription)
|
def send_fcm_push(subscription)
|
||||||
@@ -98,7 +107,11 @@ class Notification::PushNotificationService
|
|||||||
end
|
end
|
||||||
|
|
||||||
def remove_subscription_if_error(subscription, response)
|
def remove_subscription_if_error(subscription, response)
|
||||||
subscription.destroy! if JSON.parse(response[:body])['results']&.first&.keys&.include?('error')
|
if JSON.parse(response[:body])['results']&.first&.keys&.include?('error')
|
||||||
|
subscription.destroy!
|
||||||
|
else
|
||||||
|
Rails.logger.info("FCM push sent to #{user.email} with title #{push_message[:title]}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def fcm_options(subscription)
|
def fcm_options(subscription)
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
shared: &shared
|
shared: &shared
|
||||||
version: '3.10.0'
|
version: '3.10.1'
|
||||||
|
|
||||||
development:
|
development:
|
||||||
<<: *shared
|
<<: *shared
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@chatwoot/chatwoot",
|
"name": "@chatwoot/chatwoot",
|
||||||
"version": "3.10.0",
|
"version": "3.10.1",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"eslint": "eslint app/**/*.{js,vue}",
|
"eslint": "eslint app/**/*.{js,vue}",
|
||||||
|
|||||||
@@ -6,5 +6,13 @@ FactoryBot.define do
|
|||||||
identifier { 'test' }
|
identifier { 'test' }
|
||||||
subscription_type { 'browser_push' }
|
subscription_type { 'browser_push' }
|
||||||
subscription_attributes { { endpoint: 'test', auth: 'test' } }
|
subscription_attributes { { endpoint: 'test', auth: 'test' } }
|
||||||
|
|
||||||
|
trait :browser_push do
|
||||||
|
subscription_type { 'browser_push' }
|
||||||
|
end
|
||||||
|
|
||||||
|
trait :fcm do
|
||||||
|
subscription_type { 'fcm' }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -7,33 +7,58 @@ describe Notification::PushNotificationService do
|
|||||||
let(:fcm_double) { instance_double(FCM) }
|
let(:fcm_double) { instance_double(FCM) }
|
||||||
let(:fcm_service_double) { instance_double(Notification::FcmService, fcm_client: fcm_double) }
|
let(:fcm_service_double) { instance_double(Notification::FcmService, fcm_client: fcm_double) }
|
||||||
|
|
||||||
before do
|
|
||||||
allow(WebPush).to receive(:payload_send).and_return(true)
|
|
||||||
allow(Notification::FcmService).to receive(:new).and_return(fcm_service_double)
|
|
||||||
allow(fcm_double).to receive(:send_v1).and_return({ body: { 'results': [] }.to_json })
|
|
||||||
allow(GlobalConfigService).to receive(:load).with('FIREBASE_PROJECT_ID', nil).and_return('test_project_id')
|
|
||||||
allow(GlobalConfigService).to receive(:load).with('FIREBASE_CREDENTIALS', nil).and_return('test_credentials')
|
|
||||||
end
|
|
||||||
|
|
||||||
describe '#perform' do
|
describe '#perform' do
|
||||||
it 'sends webpush notifications for webpush subscription' do
|
context 'when the push server returns success' do
|
||||||
with_modified_env VAPID_PUBLIC_KEY: 'test' do
|
before do
|
||||||
create(:notification_subscription, user: notification.user)
|
allow(WebPush).to receive(:payload_send).and_return(true)
|
||||||
|
allow(Rails.logger).to receive(:info)
|
||||||
|
allow(Notification::FcmService).to receive(:new).and_return(fcm_service_double)
|
||||||
|
allow(fcm_double).to receive(:send_v1).and_return({ body: { 'results': [] }.to_json })
|
||||||
|
allow(GlobalConfigService).to receive(:load).with('FIREBASE_PROJECT_ID', nil).and_return('test_project_id')
|
||||||
|
allow(GlobalConfigService).to receive(:load).with('FIREBASE_CREDENTIALS', nil).and_return('test_credentials')
|
||||||
|
end
|
||||||
|
|
||||||
described_class.new(notification: notification).perform
|
it 'sends webpush notifications for webpush subscription' do
|
||||||
expect(WebPush).to have_received(:payload_send)
|
with_modified_env VAPID_PUBLIC_KEY: 'test' do
|
||||||
expect(Notification::FcmService).not_to have_received(:new)
|
create(:notification_subscription, user: notification.user)
|
||||||
|
|
||||||
|
described_class.new(notification: notification).perform
|
||||||
|
expect(WebPush).to have_received(:payload_send)
|
||||||
|
expect(Notification::FcmService).not_to have_received(:new)
|
||||||
|
expect(Rails.logger).to have_received(:info).with("Browser push sent to #{user.email} with title #{notification.push_message_title}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'sends a fcm notification for firebase subscription' do
|
||||||
|
with_modified_env ENABLE_PUSH_RELAY_SERVER: 'false' do
|
||||||
|
create(:notification_subscription, user: notification.user, subscription_type: 'fcm')
|
||||||
|
|
||||||
|
described_class.new(notification: notification).perform
|
||||||
|
expect(Notification::FcmService).to have_received(:new)
|
||||||
|
expect(fcm_double).to have_received(:send_v1)
|
||||||
|
expect(WebPush).not_to have_received(:payload_send)
|
||||||
|
expect(Rails.logger).to have_received(:info).with("FCM push sent to #{user.email} with title #{notification.push_message_title}")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
it 'sends a fcm notification for firebase subscription' do
|
context 'when the push server returns error' do
|
||||||
with_modified_env ENABLE_PUSH_RELAY_SERVER: 'false' do
|
it 'sends webpush notifications for webpush subscription' do
|
||||||
create(:notification_subscription, user: notification.user, subscription_type: 'fcm')
|
with_modified_env VAPID_PUBLIC_KEY: 'test' do
|
||||||
|
mock_response = instance_double(Net::HTTPResponse, body: 'Subscription is invalid')
|
||||||
|
mock_host = 'fcm.googleapis.com'
|
||||||
|
|
||||||
|
allow(WebPush).to receive(:payload_send).and_raise(WebPush::InvalidSubscription.new(mock_response, mock_host))
|
||||||
|
allow(Rails.logger).to receive(:info)
|
||||||
|
|
||||||
|
create(:notification_subscription, :browser_push, user: notification.user)
|
||||||
|
|
||||||
|
expect(Rails.logger).to receive(:info) do |message|
|
||||||
|
expect(message).to include('WebPush subscription expired:')
|
||||||
|
end
|
||||||
|
|
||||||
described_class.new(notification: notification).perform
|
described_class.new(notification: notification).perform
|
||||||
expect(Notification::FcmService).to have_received(:new)
|
|
||||||
expect(fcm_double).to have_received(:send_v1)
|
|
||||||
expect(WebPush).not_to have_received(:payload_send)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
19
yarn.lock
19
yarn.lock
@@ -21315,21 +21315,16 @@ write-file-atomic@^4.0.2:
|
|||||||
signal-exit "^3.0.7"
|
signal-exit "^3.0.7"
|
||||||
|
|
||||||
ws@^6.2.1:
|
ws@^6.2.1:
|
||||||
version "6.2.2"
|
version "6.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.2.tgz#dd5cdbd57a9979916097652d78f1cc5faea0c32e"
|
resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.3.tgz#ccc96e4add5fd6fedbc491903075c85c5a11d9ee"
|
||||||
integrity sha512-zmhltoSR8u1cnDsD43TX59mzoMZsLKqUweyYBAIvTngR3shc0W6aOZylZmq/7hqyVxPdi+5Ud2QInblgyE72fw==
|
integrity sha512-jmTjYU0j60B+vHey6TfR3Z7RD61z/hmxBS3VMSGIrroOWXQEneK1zNuotOUrGyBHQj0yrpsLHPWtigEFd13ndA==
|
||||||
dependencies:
|
dependencies:
|
||||||
async-limiter "~1.0.0"
|
async-limiter "~1.0.0"
|
||||||
|
|
||||||
ws@^8.11.0:
|
ws@^8.11.0, ws@^8.2.3:
|
||||||
version "8.14.2"
|
version "8.17.1"
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.14.2.tgz#6c249a806eb2db7a20d26d51e7709eab7b2e6c7f"
|
resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.1.tgz#9293da530bb548febc95371d90f9c878727d919b"
|
||||||
integrity sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==
|
integrity sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==
|
||||||
|
|
||||||
ws@^8.2.3:
|
|
||||||
version "8.13.0"
|
|
||||||
resolved "https://registry.yarnpkg.com/ws/-/ws-8.13.0.tgz#9a9fb92f93cf41512a0735c8f4dd09b8a1211cd0"
|
|
||||||
integrity sha512-x9vcZYTrFPC7aSIbj7sRCYo7L/Xb8Iy+pW0ng0wt2vCJv7M9HOMy0UoN3rr+IFC7hb7vXoqS+P9ktyLLLhO+LA==
|
|
||||||
|
|
||||||
x-default-browser@^0.4.0:
|
x-default-browser@^0.4.0:
|
||||||
version "0.4.0"
|
version "0.4.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user