* feat(whatsapp): show contact typing and recording indicators via baileys presence Subscribe to WhatsApp presence updates via the baileys-api provider to display real-time typing and recording indicators in the dashboard. - Handle presence.update webhook events (composing, recording, paused, available) and broadcast via ActionCable - Add conversation.recording event to ActionCable, webhook, and channel listeners for parity with typing_on/typing_off - Show "typing..." / "recording..." in green text on the chat list, replacing the message preview - Show "X is typing" / "X is recording audio" in the conversation view - Add presence_subscribe provider config option (default off) to gate all subscription calls to the baileys-api - Subscribe to presence on conversation open and periodically (1 min) for the top 10 chat list conversations - Consolidate contact LID from presence.update jidAlt payload - Prevent echo-back of contact typing events to the channel Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address review feedback - Filter chat list typing indicator to contact-only events - Add dedupe to presence subscribe bulk calls - Use strong parameters for conversation_ids - Remove redundant YAML quotes in swagger webhook enum Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address review feedback - Extract phone from data[:id] when JID is @s.whatsapp.net (fallback when jidAlt is absent) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address review feedback - Filter recording users in getTypingUsersText to show correct names - Add 10s timeout to presence_subscribe HTTP request Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: scope typing timer per user instead of per conversation Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: make presence subscribe best-effort with rescue per channel Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> * fix: address review feedback - Add messagePreviewClass to typing preview for consistent padding - Fix specs to use WebMock assertions instead of instance spying Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
50 lines
1.9 KiB
Ruby
50 lines
1.9 KiB
Ruby
# == Schema Information
|
|
#
|
|
# Table name: webhooks
|
|
#
|
|
# id :bigint not null, primary key
|
|
# name :string
|
|
# secret :string
|
|
# subscriptions :jsonb
|
|
# url :text
|
|
# webhook_type :integer default("account_type")
|
|
# created_at :datetime not null
|
|
# updated_at :datetime not null
|
|
# account_id :integer
|
|
# inbox_id :integer
|
|
#
|
|
# Indexes
|
|
#
|
|
# index_webhooks_on_account_id_and_url (account_id,url) UNIQUE
|
|
#
|
|
|
|
class Webhook < ApplicationRecord
|
|
belongs_to :account
|
|
belongs_to :inbox, optional: true
|
|
|
|
has_secure_token :secret
|
|
encrypts :secret if Chatwoot.encryption_configured?
|
|
|
|
validates :account_id, presence: true
|
|
validates :url, uniqueness: { scope: [:account_id] }, format: URI::DEFAULT_PARSER.make_regexp(%w[http https])
|
|
validate :validate_webhook_subscriptions
|
|
enum webhook_type: { account_type: 0, inbox_type: 1 }
|
|
|
|
ALLOWED_WEBHOOK_EVENTS = %w[conversation_status_changed conversation_updated conversation_created contact_created contact_updated
|
|
message_created message_incoming message_outgoing message_updated webwidget_triggered
|
|
inbox_created inbox_updated conversation_typing_on conversation_typing_off conversation_recording
|
|
provider_event_received internal_chat_message_created internal_chat_message_updated
|
|
internal_chat_message_deleted internal_chat_channel_updated].freeze
|
|
|
|
private
|
|
|
|
def validate_webhook_subscriptions
|
|
invalid_subscriptions = !subscriptions.instance_of?(Array) ||
|
|
subscriptions.blank? ||
|
|
(subscriptions.uniq - ALLOWED_WEBHOOK_EVENTS).length.positive?
|
|
errors.add(:subscriptions, I18n.t('errors.webhook.invalid')) if invalid_subscriptions
|
|
end
|
|
end
|
|
|
|
Webhook.include_mod_with('Audit::Webhook')
|