Skip to content

Commit f30f3f5

Browse files
committed
fix(whatsapp): address code review findings from Codex and manual review
P1 fixes: - Parse Unix epoch timestamps with Time.zone.at instead of Time.zone.parse which silently fell back to Time.current for all GoWA webhook messages - Halt execution in resolve_device_id when inbox validation fails, preventing NoMethodError on non-WhatsApp channels P2 fixes: - Fall back to ID-based query in messages_after when reference message is deleted, preserving incremental cursor semantics (upstream behavior) - Merge duplicate 'video'/'video_note' branches in case statement - Replace update_column with update in inbox callback to run validations
1 parent a5bbe3e commit f30f3f5

4 files changed

Lines changed: 16 additions & 8 deletions

File tree

app/controllers/api/v1/accounts/whatsapp_web/devices_controller.rb

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,18 +113,21 @@ def resolve_device_id
113113
@inbox = Current.account.inboxes.find_by(id: params[:id])
114114

115115
if @inbox
116-
validate_whatsapp_web_inbox
116+
return validate_whatsapp_web_inbox unless valid_whatsapp_web_inbox?
117+
117118
@device_id = @inbox.channel.provider_config['device_id']
118119
else
119120
# Pre-inbox setup: params[:id] is the device_id directly
120121
@device_id = params[:id]
121122
end
122123
end
123124

124-
def validate_whatsapp_web_inbox
125+
def valid_whatsapp_web_inbox?
125126
channel = @inbox.channel
126-
return if channel.is_a?(Channel::Whatsapp) && channel.provider == Channel::Whatsapp::WHATSAPP_WEB_PROVIDER
127+
channel.is_a?(Channel::Whatsapp) && channel.provider == Channel::Whatsapp::WHATSAPP_WEB_PROVIDER
128+
end
127129

130+
def validate_whatsapp_web_inbox
128131
render json: {
129132
success: false,
130133
error: 'Inbox is not a WhatsApp Web channel'

app/finders/message_finder.rb

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ def messages_after(after_id)
3636
# Find the created_at of the reference message to paginate correctly
3737
# This handles history-synced messages that have higher IDs but older timestamps
3838
reference_message = @conversation.messages.find_by(id: after_id)
39-
return messages.reorder('created_at asc').limit(100) unless reference_message
39+
# Fall back to ID-based query if reference message was deleted (original upstream behavior)
40+
return messages.reorder('created_at asc').where('id > ?', after_id).limit(100) unless reference_message
4041

4142
messages.reorder('created_at asc')
4243
.where('created_at > ? OR (created_at = ? AND id > ?)',

app/models/inbox.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ def delete_round_robin_agents
245245
def enable_lock_to_single_conversation_for_whatsapp_web
246246
return unless channel.is_a?(Channel::Whatsapp) && channel.whatsapp_web?
247247

248-
update_column(:lock_to_single_conversation, true)
248+
update(lock_to_single_conversation: true)
249249
end
250250

251251
def check_channel_type?

app/services/whatsapp/incoming_message_whatsapp_web_service.rb

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -720,7 +720,12 @@ def merge_chat_info_preserving_name(enriched_chat, chat_info)
720720
def parse_timestamp(timestamp_str)
721721
return Time.current if timestamp_str.blank?
722722

723-
Time.zone.parse(timestamp_str)
723+
# GoWA sends Unix epoch seconds (e.g. "1712345678")
724+
if timestamp_str.to_s.match?(/\A\d+\z/)
725+
Time.zone.at(timestamp_str.to_i)
726+
else
727+
Time.zone.parse(timestamp_str)
728+
end
724729
rescue ArgumentError
725730
Time.current
726731
end
@@ -1091,11 +1096,10 @@ def add_history_media_to_payload(payload, message, chat)
10911096

10921097
case media_type.downcase
10931098
when 'image' then payload[:image] = media_obj
1094-
when 'video' then payload[:video] = media_obj
1099+
when 'video', 'video_note' then payload[:video] = media_obj
10951100
when 'audio' then payload[:audio] = media_obj
10961101
when 'document' then payload[:document] = media_obj
10971102
when 'sticker' then payload[:sticker] = media_obj
1098-
when 'video_note' then payload[:video] = media_obj # PTV messages are video
10991103
end
11001104
end
11011105

0 commit comments

Comments
 (0)