feat: Add WhatsApp reauthorization bankend flow
This commit is contained in:
@@ -32,6 +32,28 @@ class Whatsapp::EmbeddedController < ApplicationController
|
||||
handle_signup_error(e)
|
||||
end
|
||||
|
||||
def reauthorize
|
||||
# Reauthorize existing WhatsApp inbox using embedded signup flow
|
||||
validate_authorization_code!
|
||||
return if performed?
|
||||
|
||||
validate_required_parameters!
|
||||
return if performed?
|
||||
|
||||
validate_inbox_id!
|
||||
return if performed?
|
||||
|
||||
channel = process_reauthorization
|
||||
@inbox = channel.inbox
|
||||
|
||||
# Clear reauthorization required flag
|
||||
channel.reauthorized!
|
||||
|
||||
render json: { message: 'WhatsApp channel reauthorized successfully' }, status: :ok
|
||||
rescue StandardError => e
|
||||
handle_signup_error(e)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_authorization_code!
|
||||
@@ -51,6 +73,14 @@ class Whatsapp::EmbeddedController < ApplicationController
|
||||
}, status: :bad_request
|
||||
end
|
||||
|
||||
def validate_inbox_id!
|
||||
return if params[:inbox_id].present?
|
||||
|
||||
render json: {
|
||||
error: 'Missing inbox_id parameter'
|
||||
}, status: :bad_request
|
||||
end
|
||||
|
||||
def process_signup
|
||||
service = Whatsapp::EmbeddedSignupService.new(
|
||||
account: Current.account,
|
||||
@@ -63,6 +93,19 @@ class Whatsapp::EmbeddedController < ApplicationController
|
||||
service.perform
|
||||
end
|
||||
|
||||
def process_reauthorization
|
||||
service = Whatsapp::EmbeddedSignupService.new(
|
||||
account: Current.account,
|
||||
code: params[:code],
|
||||
business_id: params[:business_id],
|
||||
waba_id: params[:waba_id],
|
||||
phone_number_id: params[:phone_number_id],
|
||||
inbox_id: params[:inbox_id]
|
||||
)
|
||||
|
||||
service.perform_reauthorization
|
||||
end
|
||||
|
||||
def handle_signup_error(error)
|
||||
Rails.logger.error("WhatsApp embedded signup processing error: #{error.message}")
|
||||
Rails.logger.error(error.backtrace.join("\n"))
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
class Whatsapp::EmbeddedSignupService
|
||||
include Rails.application.routes.url_helpers
|
||||
|
||||
def initialize(account:, code:, business_id:, waba_id:, phone_number_id:)
|
||||
def initialize(account:, code:, business_id:, waba_id:, phone_number_id:, inbox_id: nil)
|
||||
@account = account
|
||||
@code = code
|
||||
@business_id = business_id
|
||||
@waba_id = waba_id
|
||||
@phone_number_id = phone_number_id
|
||||
@inbox_id = inbox_id
|
||||
end
|
||||
|
||||
def perform
|
||||
@@ -33,6 +34,43 @@ class Whatsapp::EmbeddedSignupService
|
||||
raise e
|
||||
end
|
||||
|
||||
def perform_reauthorization
|
||||
# Validate required parameters
|
||||
unless @code.present? && @business_id.present? && @waba_id.present? && @phone_number_id.present? && @inbox_id.present?
|
||||
raise ArgumentError, 'Code, business_id, waba_id, phone_number_id, and inbox_id are all required for reauthorization'
|
||||
end
|
||||
|
||||
# Find the existing inbox and channel
|
||||
inbox = @account.inboxes.find_by(id: @inbox_id)
|
||||
raise ActiveRecord::RecordNotFound, 'Inbox not found' unless inbox
|
||||
raise ArgumentError, 'Inbox is not a WhatsApp channel' unless inbox.channel_type == 'Channel::Whatsapp'
|
||||
|
||||
channel = inbox.channel
|
||||
raise ArgumentError, 'Channel is not WhatsApp Cloud provider' unless channel.provider == 'whatsapp_cloud'
|
||||
|
||||
GlobalConfig.clear_cache
|
||||
# Exchange code for new access token
|
||||
access_token = exchange_code_for_token
|
||||
|
||||
# Use the provided business info directly
|
||||
phone_info = fetch_phone_info_via_waba(@waba_id, @phone_number_id, access_token)
|
||||
|
||||
# Validate that the token has access to the provided WABA
|
||||
validate_token_waba_access(access_token, @waba_id)
|
||||
|
||||
# Update the channel with new access token and configuration
|
||||
update_channel_for_reauthorization(channel, phone_info, access_token)
|
||||
|
||||
# Re-register webhook with new token
|
||||
register_phone_number(phone_info[:phone_number_id], access_token)
|
||||
override_waba_webhook(@waba_id, channel, access_token)
|
||||
|
||||
channel
|
||||
rescue StandardError => e
|
||||
Rails.logger.error("[WHATSAPP] Reauthorization failed: #{e.message}")
|
||||
raise e
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def whatsapp_api_version
|
||||
@@ -138,6 +176,18 @@ class Whatsapp::EmbeddedSignupService
|
||||
)
|
||||
end
|
||||
|
||||
def update_channel_for_reauthorization(channel, phone_info, access_token)
|
||||
# Update channel with new access token and configuration
|
||||
channel.update!(
|
||||
provider_config: channel.provider_config.merge(
|
||||
'api_key' => access_token,
|
||||
'phone_number_id' => phone_info[:phone_number_id],
|
||||
'business_account_id' => @waba_id,
|
||||
'reauthorized_at' => Time.current.iso8601
|
||||
)
|
||||
)
|
||||
end
|
||||
|
||||
def sanitize_phone_number(phone_number)
|
||||
return phone_number if phone_number.blank?
|
||||
|
||||
|
||||
@@ -116,4 +116,5 @@ json.provider resource.channel.try(:provider)
|
||||
if resource.whatsapp?
|
||||
json.message_templates resource.channel.try(:message_templates)
|
||||
json.provider_config resource.channel.try(:provider_config) if Current.account_user&.administrator?
|
||||
json.reauthorization_required resource.channel.try(:reauthorization_required?)
|
||||
end
|
||||
|
||||
@@ -486,6 +486,7 @@ Rails.application.routes.draw do
|
||||
get 'signup', to: 'embedded#new'
|
||||
get 'signup/callback', to: 'embedded#callback'
|
||||
post 'embedded_signup', to: 'embedded#embedded_signup'
|
||||
post 'reauthorize', to: 'embedded#reauthorize'
|
||||
end
|
||||
|
||||
namespace :twitter do
|
||||
|
||||
Executable
+99
@@ -0,0 +1,99 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
# Script to get business account path for a specific inbox ID
|
||||
# Usage: ruby get_business_account_path.rb
|
||||
|
||||
# Set the inbox ID to query
|
||||
INBOX_ID = 1090
|
||||
|
||||
# Load Rails environment (assuming this script is run from the Rails app root)
|
||||
require_relative 'config/environment'
|
||||
|
||||
def get_business_account_path(inbox_id)
|
||||
# Find the inbox by ID
|
||||
inbox = Inbox.find(inbox_id)
|
||||
|
||||
# Check if this is a WhatsApp inbox
|
||||
unless inbox.whatsapp?
|
||||
puts "Error: Inbox #{inbox_id} is not a WhatsApp inbox. Channel type: #{inbox.channel_type}"
|
||||
return nil
|
||||
end
|
||||
|
||||
# Get the WhatsApp channel
|
||||
whatsapp_channel = inbox.channel
|
||||
|
||||
# Check if it's a WhatsApp Cloud provider
|
||||
unless whatsapp_channel.provider == 'whatsapp_cloud'
|
||||
puts "Error: Inbox #{inbox_id} is not using WhatsApp Cloud provider. Provider: #{whatsapp_channel.provider}"
|
||||
return nil
|
||||
end
|
||||
|
||||
# Get the business_account_id and api_key from provider_config
|
||||
business_account_id = whatsapp_channel.provider_config['business_account_id']
|
||||
api_key = whatsapp_channel.provider_config['api_key']
|
||||
|
||||
if business_account_id.blank?
|
||||
puts "Error: No business_account_id found in provider_config for inbox #{inbox_id}"
|
||||
return nil
|
||||
end
|
||||
|
||||
if api_key.blank?
|
||||
puts "Error: No api_key (access token) found in provider_config for inbox #{inbox_id}"
|
||||
return nil
|
||||
end
|
||||
|
||||
# Construct the business account path (following the pattern from WhatsappCloudService)
|
||||
api_base_path = ENV.fetch('WHATSAPP_CLOUD_BASE_URL', 'https://graph.facebook.com')
|
||||
business_account_path = "#{api_base_path}/v14.0/#{business_account_id}"
|
||||
|
||||
return {
|
||||
inbox_id: inbox_id,
|
||||
inbox_name: inbox.name,
|
||||
business_account_id: business_account_id,
|
||||
business_account_path: business_account_path,
|
||||
provider: whatsapp_channel.provider,
|
||||
phone_number: whatsapp_channel.phone_number,
|
||||
api_key: api_key,
|
||||
access_token: api_key # alias for clarity
|
||||
}
|
||||
|
||||
rescue ActiveRecord::RecordNotFound
|
||||
puts "Error: Inbox with ID #{inbox_id} not found"
|
||||
return nil
|
||||
rescue StandardError => e
|
||||
puts "Error: #{e.message}"
|
||||
puts e.backtrace.first(5).join("\n") if ENV['DEBUG']
|
||||
return nil
|
||||
end
|
||||
|
||||
# Main execution
|
||||
puts "Getting business account path for inbox ID: #{INBOX_ID}"
|
||||
puts '=' * 50
|
||||
|
||||
result = get_business_account_path(INBOX_ID)
|
||||
|
||||
if result
|
||||
puts 'Success! Found WhatsApp Business Account details:'
|
||||
puts
|
||||
puts "Inbox ID: #{result[:inbox_id]}"
|
||||
puts "Inbox Name: #{result[:inbox_name]}"
|
||||
puts "Phone Number: #{result[:phone_number]}"
|
||||
puts "Provider: #{result[:provider]}"
|
||||
puts "Business Account ID: #{result[:business_account_id]}"
|
||||
puts
|
||||
puts 'Business Account Path:'
|
||||
puts result[:business_account_path]
|
||||
puts
|
||||
puts 'Access Token (API Key):'
|
||||
puts result[:access_token]
|
||||
puts
|
||||
puts 'Complete API Endpoint Examples:'
|
||||
puts "• Message Templates: #{result[:business_account_path]}/message_templates?access_token=#{result[:access_token]}"
|
||||
puts "• Phone Numbers: #{result[:business_account_path]}/phone_numbers?access_token=#{result[:access_token]}"
|
||||
puts
|
||||
puts 'Authorization Header Format:'
|
||||
puts "Authorization: Bearer #{result[:access_token]}"
|
||||
else
|
||||
puts "Failed to get business account path for inbox ID #{INBOX_ID}"
|
||||
exit 1
|
||||
end
|
||||
Reference in New Issue
Block a user