diff --git a/app/adapters/signal_adapter/inbound.rb b/app/adapters/signal_adapter/inbound.rb index 2c370ac18..b93dccbe6 100644 --- a/app/adapters/signal_adapter/inbound.rb +++ b/app/adapters/signal_adapter/inbound.rb @@ -4,6 +4,7 @@ module SignalAdapter UNKNOWN_CONTRIBUTOR = :unknown_contributor UNKNOWN_CONTENT = :unknown_content CONNECT = :connect + HANDLE_DELIVERY_RECEIPT = :handle_delivery_receipt class Inbound UNKNOWN_CONTENT_KEYS = %w[mentions contacts sticker].freeze @@ -66,6 +67,8 @@ def initialize_sender(signal_message) def initialize_message(signal_message) is_data_message = signal_message.dig(:envelope, :dataMessage) is_remove_emoji = signal_message.dig(:envelope, :dataMessage, :reaction, :isRemove) + is_delivery_receipt = signal_message.dig(:envelope, :receiptMessage) + trigger(HANDLE_DELIVERY_RECEIPT, is_delivery_receipt, sender) if is_delivery_receipt return nil if !is_data_message || is_remove_emoji data_message = signal_message.dig(:envelope, :dataMessage) diff --git a/app/components/checkbox/checkbox.html.erb b/app/components/checkbox/checkbox.html.erb index 2b09a60fd..26fd445a7 100644 --- a/app/components/checkbox/checkbox.html.erb +++ b/app/components/checkbox/checkbox.html.erb @@ -7,4 +7,4 @@ <%= checked ? 'checked' : '' %> <%= required ? 'required' : '' %> <%= attrs %> -/> \ No newline at end of file +/> diff --git a/app/jobs/signal_adapter/receive_polling_job.rb b/app/jobs/signal_adapter/receive_polling_job.rb index 45a79ea22..30d918ce5 100644 --- a/app/jobs/signal_adapter/receive_polling_job.rb +++ b/app/jobs/signal_adapter/receive_polling_job.rb @@ -17,9 +17,7 @@ def perform(*_args) adapter = SignalAdapter::Inbound.new adapter.on(SignalAdapter::CONNECT) do |contributor| - contributor.update!(signal_onboarding_completed_at: Time.zone.now) - SignalAdapter::Outbound.send_welcome_message!(contributor) - SignalAdapter::AttachContributorsAvatarJob.perform_later(contributor) + handle_connect(contributor) end adapter.on(SignalAdapter::UNKNOWN_CONTRIBUTOR) do |signal_phone_number| @@ -31,6 +29,10 @@ def perform(*_args) SignalAdapter::Outbound.send_unknown_content_message!(contributor) end + adapter.on(SignalAdapter::HANDLE_DELIVERY_RECEIPT) do |delivery_receipt, contributor| + handle_delivery_receipt(delivery_receipt, contributor) + end + signal_messages.each do |raw_message| adapter.consume(raw_message) { |m| m.contributor.reply(adapter) } rescue StandardError => e @@ -60,5 +62,18 @@ def ping_monitoring_service def queue_empty? Delayed::Job.where(queue: queue_name, failed_at: nil).none? end + + def handle_connect(contributor) + contributor.update!(signal_onboarding_completed_at: Time.zone.now) + SignalAdapter::Outbound.send_welcome_message!(contributor) + SignalAdapter::AttachContributorsAvatarJob.perform_later(contributor) + end + + def handle_delivery_receipt(delivery_receipt, contributor) + datetime = Time.zone.at(delivery_receipt[:when] / 1000).to_datetime + latest_received_message = contributor.received_messages.first + latest_received_message.update(received_at: datetime) if delivery_receipt[:isDelivery] + latest_received_message.update(read_at: datetime) if delivery_receipt[:isRead] + end end end diff --git a/db/migrate/20230915070544_add_received_at_to_messages.rb b/db/migrate/20230915070544_add_received_at_to_messages.rb new file mode 100644 index 000000000..3696d62ab --- /dev/null +++ b/db/migrate/20230915070544_add_received_at_to_messages.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddReceivedAtToMessages < ActiveRecord::Migration[6.1] + def change + add_column :messages, :received_at, :datetime, default: nil + end +end diff --git a/db/migrate/20231024144124_add_read_at_to_messages.rb b/db/migrate/20231024144124_add_read_at_to_messages.rb new file mode 100644 index 000000000..5dbf6a6ad --- /dev/null +++ b/db/migrate/20231024144124_add_read_at_to_messages.rb @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +class AddReadAtToMessages < ActiveRecord::Migration[6.1] + def change + add_column :messages, :read_at, :datetime, default: nil + end +end diff --git a/db/schema.rb b/db/schema.rb index 3e6fb9997..74b98d80a 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2023_06_30_061952) do +ActiveRecord::Schema.define(version: 2023_10_24_144124) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -169,6 +169,8 @@ t.boolean "highlighted", default: false t.bigint "creator_id" t.string "sender_type" + t.datetime "received_at" + t.datetime "read_at" t.index ["creator_id"], name: "index_messages_on_creator_id" t.index ["recipient_id"], name: "index_messages_on_recipient_id" t.index ["request_id"], name: "index_messages_on_request_id" diff --git a/spec/adapters/signal_adapter/inbound_spec.rb b/spec/adapters/signal_adapter/inbound_spec.rb index e7d3fb5d5..9f96968e2 100644 --- a/spec/adapters/signal_adapter/inbound_spec.rb +++ b/spec/adapters/signal_adapter/inbound_spec.rb @@ -24,17 +24,20 @@ { envelope: { source: '+4912345789', + sourceNumber: '+4912345789', + sourceUuid: 'valid_uuid', + sourceName: 'Signal Contributor', sourceDevice: 1, - timestamp: 1_626_711_330_462, + timestamp: 1_694_759_894_782, receiptMessage: { - when: 1_626_711_330_462, + when: 1_694_759_894_782, isDelivery: true, isRead: false, - timestamps: [ - 1_626_711_326_111 - ] + isViewed: false, + timestamps: [1_694_759_894_066] } - } + }, + account: Setting.signal_server_phone_number } end @@ -205,6 +208,7 @@ end context 'given a receipt message' do + before { create(:message, recipient_id: contributor.id) } let(:signal_message) { signal_receipt_message } it { should be(nil) } @@ -454,5 +458,25 @@ it { should have_received(:call).with(contributor) } end end + + describe 'HANDLE_DELIVERY_RECEIPT' do + let(:handle_delivery_receipt_callback) { spy('handle_delivery_receipt_callback') } + let(:signal_message) { signal_receipt_message } + + before do + adapter.on(SignalAdapter::HANDLE_DELIVERY_RECEIPT) do |delivery_receipt, contributor| + handle_delivery_receipt_callback.call(delivery_receipt, contributor) + end + end + + subject do + adapter.consume(signal_message) + handle_delivery_receipt_callback + end + + describe 'if the message is a delivery receipt' do + it { should have_received(:call) } + end + end end end