chore: clean up voice message components
This commit is contained in:
@@ -23,15 +23,41 @@ class Api::V1::Accounts::Channels::Voice::WebhooksController < Api::V1::Accounts
|
||||
|
||||
# Handle incoming calls from Twilio
|
||||
def incoming
|
||||
# Process incoming call using service
|
||||
service = Voice::IncomingCallService.new(account: Current.account, params: params.merge(host_with_port: request.host_with_port))
|
||||
twiml_response = service.process
|
||||
# Set CORS headers first to ensure they're included
|
||||
set_cors_headers
|
||||
|
||||
# Return TwiML response
|
||||
render xml: twiml_response
|
||||
rescue => e
|
||||
Rails.logger.error("Error processing incoming call: #{e.message}")
|
||||
render_error("An error occurred while processing your call. Please try again later.")
|
||||
# Log basic request info
|
||||
Rails.logger.info("🔔 INCOMING CALL WEBHOOK: CallSid=#{params['CallSid']} From=#{params['From']} To=#{params['To']}")
|
||||
|
||||
# Process incoming call using service
|
||||
begin
|
||||
# Ensure account is set properly
|
||||
if !Current.account && params[:account_id].present?
|
||||
Current.account = Account.find(params[:account_id])
|
||||
Rails.logger.info("👑 Set Current.account to #{Current.account.id}")
|
||||
end
|
||||
|
||||
# Validate required parameters
|
||||
validate_incoming_params
|
||||
|
||||
# Process the call
|
||||
service = Voice::IncomingCallService.new(
|
||||
account: Current.account,
|
||||
params: params.to_unsafe_h.merge(host_with_port: request.host_with_port)
|
||||
)
|
||||
twiml_response = service.process
|
||||
|
||||
# Return TwiML response
|
||||
Rails.logger.info("✅ INCOMING CALL: Successfully processed")
|
||||
render xml: twiml_response
|
||||
rescue StandardError => e
|
||||
# Log the error with detailed information
|
||||
Rails.logger.error("❌ INCOMING CALL ERROR: #{e.message}")
|
||||
Rails.logger.error("❌ BACKTRACE: #{e.backtrace[0..5].join("\n")}")
|
||||
|
||||
# Return friendly error message to caller
|
||||
render_error("We're sorry, but we're experiencing technical difficulties. Please try your call again later.")
|
||||
end
|
||||
end
|
||||
|
||||
# Handle conference status updates
|
||||
@@ -44,19 +70,31 @@ class Api::V1::Accounts::Channels::Voice::WebhooksController < Api::V1::Accounts
|
||||
return head :ok
|
||||
end
|
||||
|
||||
# Log basic request info
|
||||
Rails.logger.info("🎧 CONFERENCE STATUS WEBHOOK: ConferenceSid=#{params['ConferenceSid']} Event=#{params['StatusCallbackEvent']}")
|
||||
|
||||
# Process conference status updates using service
|
||||
begin
|
||||
# Set account for local development if needed
|
||||
if !Current.account && params[:account_id].present?
|
||||
Current.account = Account.find(params[:account_id])
|
||||
Rails.logger.info("👑 Set Current.account to #{Current.account.id}")
|
||||
end
|
||||
|
||||
# Validate required parameters
|
||||
if params['ConferenceSid'].blank? && params['CallSid'].blank?
|
||||
Rails.logger.error("❌ MISSING REQUIRED PARAMS: Need either ConferenceSid or CallSid")
|
||||
end
|
||||
|
||||
# Use service to process conference status
|
||||
service = Voice::ConferenceStatusService.new(account: Current.account, params: params)
|
||||
service.process
|
||||
rescue => e
|
||||
|
||||
Rails.logger.info("✅ CONFERENCE STATUS: Successfully processed")
|
||||
rescue StandardError => e
|
||||
# Log errors but don't affect the response
|
||||
Rails.logger.error("Error processing conference status: #{e.message[0..100]}")
|
||||
Rails.logger.error("❌ CONFERENCE STATUS ERROR: #{e.message}")
|
||||
Rails.logger.error("❌ BACKTRACE: #{e.backtrace[0..5].join("\n")}")
|
||||
end
|
||||
|
||||
# Always return a successful response for Twilio
|
||||
@@ -65,19 +103,44 @@ class Api::V1::Accounts::Channels::Voice::WebhooksController < Api::V1::Accounts
|
||||
|
||||
private
|
||||
|
||||
def validate_twilio_signature
|
||||
validator = Voice::TwilioValidatorService.new(
|
||||
account: Current.account,
|
||||
params: params,
|
||||
request: request
|
||||
)
|
||||
|
||||
if !validator.valid?
|
||||
render_error('Invalid Twilio signature')
|
||||
return false
|
||||
def validate_incoming_params
|
||||
if params['CallSid'].blank?
|
||||
raise "Missing required parameter: CallSid"
|
||||
end
|
||||
|
||||
true
|
||||
if params['From'].blank?
|
||||
raise "Missing required parameter: From"
|
||||
end
|
||||
|
||||
if params['To'].blank?
|
||||
raise "Missing required parameter: To"
|
||||
end
|
||||
|
||||
if Current.account.nil?
|
||||
raise "Current account not set"
|
||||
end
|
||||
end
|
||||
|
||||
def validate_twilio_signature
|
||||
begin
|
||||
validator = Voice::TwilioValidatorService.new(
|
||||
account: Current.account,
|
||||
params: params,
|
||||
request: request
|
||||
)
|
||||
|
||||
if !validator.valid?
|
||||
Rails.logger.error("❌ INVALID TWILIO SIGNATURE")
|
||||
render_error('Invalid Twilio signature')
|
||||
return false
|
||||
end
|
||||
|
||||
return true
|
||||
rescue StandardError => e
|
||||
Rails.logger.error("❌ TWILIO VALIDATION ERROR: #{e.message}")
|
||||
render_error('Error validating Twilio request')
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
def render_error(message)
|
||||
@@ -86,4 +149,4 @@ class Api::V1::Accounts::Channels::Voice::WebhooksController < Api::V1::Accounts
|
||||
response.hangup
|
||||
render xml: response.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -51,6 +51,34 @@ class Api::V1::Accounts::VoiceController < Api::V1::Accounts::BaseController
|
||||
|
||||
# Update conversation call status
|
||||
@conversation.additional_attributes['call_status'] = 'completed'
|
||||
@conversation.additional_attributes['call_ended_at'] = Time.now.to_i
|
||||
|
||||
# Calculate call duration if we have a start time
|
||||
if @conversation.additional_attributes['call_started_at']
|
||||
@conversation.additional_attributes['call_duration'] = Time.now.to_i - @conversation.additional_attributes['call_started_at'].to_i
|
||||
end
|
||||
|
||||
# Mark conversation as resolved
|
||||
@conversation.status = :resolved
|
||||
|
||||
# Update the voice call message status
|
||||
if call_message = find_voice_call_message
|
||||
content_attributes = call_message.content_attributes || {}
|
||||
content_attributes['data'] ||= {}
|
||||
content_attributes['data']['status'] = 'completed'
|
||||
content_attributes['data']['status_updated'] = Time.now.to_i
|
||||
content_attributes['data']['meta'] ||= {}
|
||||
content_attributes['data']['meta']['completed_at'] = Time.now.to_i
|
||||
content_attributes['data']['ended_at'] = Time.now.to_i
|
||||
|
||||
# Add duration if available
|
||||
if @conversation.additional_attributes['call_duration']
|
||||
content_attributes['data']['duration'] = @conversation.additional_attributes['call_duration']
|
||||
end
|
||||
|
||||
call_message.update(content_attributes: content_attributes)
|
||||
end
|
||||
|
||||
@conversation.save!
|
||||
|
||||
# Create an activity message noting the call has ended
|
||||
@@ -115,13 +143,32 @@ class Api::V1::Accounts::VoiceController < Api::V1::Accounts::BaseController
|
||||
|
||||
# Agent joining call via WebRTC
|
||||
|
||||
# Update conversation to show agent joined
|
||||
# Update conversation to show agent joined and set call status to active
|
||||
@conversation.additional_attributes['agent_joined'] = true
|
||||
@conversation.additional_attributes['joined_at'] = Time.now.to_i
|
||||
@conversation.additional_attributes['joined_by'] = {
|
||||
id: current_user.id,
|
||||
name: current_user.name
|
||||
}
|
||||
|
||||
# CRITICAL: Update call status to 'in-progress' to ensure UI updates properly
|
||||
# This is especially important for incoming calls where the status might not get updated otherwise
|
||||
@conversation.additional_attributes['call_status'] = 'in-progress'
|
||||
|
||||
# Also record started_at timestamp if not already set
|
||||
@conversation.additional_attributes['call_started_at'] = Time.now.to_i unless @conversation.additional_attributes['call_started_at']
|
||||
|
||||
# Update the call data in the voice call message
|
||||
if call_message = find_voice_call_message
|
||||
content_attributes = call_message.content_attributes || {}
|
||||
content_attributes['data'] ||= {}
|
||||
content_attributes['data']['status'] = 'in-progress'
|
||||
content_attributes['data']['status_updated'] = Time.now.to_i
|
||||
content_attributes['data']['meta'] ||= {}
|
||||
content_attributes['data']['meta']['active_at'] = Time.now.to_i
|
||||
call_message.update(content_attributes: content_attributes)
|
||||
end
|
||||
|
||||
@conversation.save!
|
||||
|
||||
# Create an activity message
|
||||
@@ -454,6 +501,29 @@ class Api::V1::Accounts::VoiceController < Api::V1::Accounts::BaseController
|
||||
@conversation = Current.account.conversations.find(params[:id] || params[:conversation_id])
|
||||
end
|
||||
|
||||
# Helper method to find the voice call message for the current call
|
||||
# Similar to the one in Voice::MessageUpdateService but simplified
|
||||
def find_voice_call_message
|
||||
return nil unless @conversation.present?
|
||||
|
||||
# Try to find by call_sid first
|
||||
if call_sid = params[:call_sid] || @conversation.additional_attributes&.dig('call_sid')
|
||||
message = @conversation.messages
|
||||
.where(content_type: 'voice_call')
|
||||
.where("content_attributes->'data'->>'call_sid' = ?", call_sid)
|
||||
.first
|
||||
|
||||
# If found, return it
|
||||
return message if message
|
||||
end
|
||||
|
||||
# Fall back to the most recent voice call message
|
||||
@conversation.messages
|
||||
.where(content_type: 'voice_call')
|
||||
.order(created_at: :desc)
|
||||
.first
|
||||
end
|
||||
|
||||
# Helper method to get base URL with extra resilience
|
||||
def base_url
|
||||
# Try several methods to determine the base URL, with detailed logging
|
||||
|
||||
Reference in New Issue
Block a user