From 9007bf1ecf61ac768e21ca07cfaaca9fb8e0c8bc Mon Sep 17 00:00:00 2001 From: Tanmay Deep Sharma <32020192+tds-1@users.noreply.github.com> Date: Thu, 10 Jul 2025 03:09:16 +0700 Subject: [PATCH 1/2] feat: Add WhatsApp reauthorization bankend flow --- .../whatsapp/embedded_controller.rb | 43 ++++++++ .../whatsapp/embedded_signup_service.rb | 52 +++++++++- app/views/api/v1/models/_inbox.json.jbuilder | 1 + config/routes.rb | 1 + get_business_account_path.rb | 99 +++++++++++++++++++ 5 files changed, 195 insertions(+), 1 deletion(-) create mode 100755 get_business_account_path.rb diff --git a/app/controllers/whatsapp/embedded_controller.rb b/app/controllers/whatsapp/embedded_controller.rb index 625a11f3e..feb582cc2 100644 --- a/app/controllers/whatsapp/embedded_controller.rb +++ b/app/controllers/whatsapp/embedded_controller.rb @@ -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")) diff --git a/app/services/whatsapp/embedded_signup_service.rb b/app/services/whatsapp/embedded_signup_service.rb index 95ecfac2b..d99b526dd 100644 --- a/app/services/whatsapp/embedded_signup_service.rb +++ b/app/services/whatsapp/embedded_signup_service.rb @@ -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? diff --git a/app/views/api/v1/models/_inbox.json.jbuilder b/app/views/api/v1/models/_inbox.json.jbuilder index c66a6eb78..8042ee47c 100644 --- a/app/views/api/v1/models/_inbox.json.jbuilder +++ b/app/views/api/v1/models/_inbox.json.jbuilder @@ -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 diff --git a/config/routes.rb b/config/routes.rb index 75119414c..578e15e71 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -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 diff --git a/get_business_account_path.rb b/get_business_account_path.rb new file mode 100755 index 000000000..aef6ed500 --- /dev/null +++ b/get_business_account_path.rb @@ -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 \ No newline at end of file From 50d023caedafa3355a3799f239a396433031c2aa Mon Sep 17 00:00:00 2001 From: Tanmay Deep Sharma <32020192+tds-1@users.noreply.github.com> Date: Thu, 10 Jul 2025 09:06:05 +0700 Subject: [PATCH 2/2] remove extra committed file --- .../whatsapp/embedded_controller.rb | 26 +-- app/services/whatsapp/api_service.rb | 97 ++++++++++ .../whatsapp/embedded_signup_service.rb | 172 +++--------------- app/services/whatsapp/token_validator.rb | 43 +++++ get_business_account_path.rb | 99 ---------- 5 files changed, 177 insertions(+), 260 deletions(-) create mode 100644 app/services/whatsapp/api_service.rb create mode 100644 app/services/whatsapp/token_validator.rb delete mode 100755 get_business_account_path.rb diff --git a/app/controllers/whatsapp/embedded_controller.rb b/app/controllers/whatsapp/embedded_controller.rb index feb582cc2..d19361b35 100644 --- a/app/controllers/whatsapp/embedded_controller.rb +++ b/app/controllers/whatsapp/embedded_controller.rb @@ -83,11 +83,13 @@ class Whatsapp::EmbeddedController < ApplicationController def process_signup 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] + { + account: Current.account, + code: params[:code], + business_id: params[:business_id], + waba_id: params[:waba_id], + phone_number_id: params[:phone_number_id] + } ) service.perform @@ -95,12 +97,14 @@ class Whatsapp::EmbeddedController < ApplicationController 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] + { + 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 diff --git a/app/services/whatsapp/api_service.rb b/app/services/whatsapp/api_service.rb new file mode 100644 index 000000000..071ac4d47 --- /dev/null +++ b/app/services/whatsapp/api_service.rb @@ -0,0 +1,97 @@ +# Handles WhatsApp API communication +module Whatsapp::ApiService + extend ActiveSupport::Concern + + def whatsapp_api_version + @whatsapp_api_version ||= GlobalConfigService.load('WHATSAPP_API_VERSION', 'v22.0') + end + + def exchange_code_for_token + response = Faraday.get( + "https://graph.facebook.com/#{whatsapp_api_version}/oauth/access_token", + { + client_id: GlobalConfigService.load('WHATSAPP_APP_ID', ''), + client_secret: GlobalConfigService.load('WHATSAPP_APP_SECRET', ''), + code: @code + } + ) + + raise "Token exchange failed: #{response.body}" unless response.success? + + data = JSON.parse(response.body) + raise "No access token in response: #{data}" unless data['access_token'] + + data['access_token'] + end + + def fetch_phone_info_via_waba(waba_id, phone_number_id, access_token) + response = Faraday.get( + "https://graph.facebook.com/#{whatsapp_api_version}/#{waba_id}/phone_numbers", + { access_token: access_token } + ) + + raise "WABA phone numbers fetch failed: #{response.body}" unless response.success? + + data = JSON.parse(response.body) + phone_numbers = data['data'] + phone_data = phone_numbers.find { |phone| phone['id'] == phone_number_id } || phone_numbers.first + + raise "No phone numbers found for WABA #{waba_id}" if phone_data.nil? + + display_phone_number = sanitize_phone_number(phone_data['display_phone_number']) + { + phone_number_id: phone_data['id'], + phone_number: "+#{display_phone_number}", + verified: phone_data['code_verification_status'] == 'VERIFIED', + business_name: phone_data['verified_name'] || phone_data['display_phone_number'] + } + end + + def register_phone_number(phone_number_id, access_token) + HTTParty.post( + "https://graph.facebook.com/#{whatsapp_api_version}/#{phone_number_id}/register", + { + headers: { 'Authorization' => "Bearer #{access_token}", 'Content-Type' => 'application/json' }, + body: { messaging_product: 'whatsapp', pin: '212834' }.to_json + } + ) + end + + def override_waba_webhook(waba_id, channel, access_token) + callback_url = "#{ENV.fetch('FRONTEND_URL', nil)}/webhooks/whatsapp/#{channel.phone_number}" + verify_token = channel.provider_config['webhook_verify_token'] + + response = HTTParty.post( + "https://graph.facebook.com/#{whatsapp_api_version}/#{waba_id}/subscribed_apps", + { + headers: { + 'Authorization' => "Bearer #{access_token}", + 'Content-Type' => 'application/json' + }, + body: { + override_callback_uri: callback_url, + verify_token: verify_token + }.to_json + } + ) + + return if response.success? + + Rails.logger.error("[WHATSAPP] Webhook override failed: #{response.body}") + raise "Webhook override failed: #{response.body}" + end + + private + + def sanitize_phone_number(phone_number) + return phone_number if phone_number.blank? + + phone_number.gsub(/[\s\-\(\)\.\+]/, '').strip + end + + def build_app_access_token + app_id = GlobalConfigService.load('WHATSAPP_APP_ID', '') + app_secret = GlobalConfigService.load('WHATSAPP_APP_SECRET', '') + "#{app_id}|#{app_secret}" + end +end \ No newline at end of file diff --git a/app/services/whatsapp/embedded_signup_service.rb b/app/services/whatsapp/embedded_signup_service.rb index d99b526dd..9d3e2df3c 100644 --- a/app/services/whatsapp/embedded_signup_service.rb +++ b/app/services/whatsapp/embedded_signup_service.rb @@ -1,13 +1,15 @@ class Whatsapp::EmbeddedSignupService include Rails.application.routes.url_helpers + include Whatsapp::ApiService + include Whatsapp::TokenValidator - 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 + def initialize(params) + @account = params[: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] end def perform @@ -35,33 +37,15 @@ class Whatsapp::EmbeddedSignupService 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' + validate_reauthorization_params! + channel = find_and_validate_channel 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) @@ -73,50 +57,21 @@ class Whatsapp::EmbeddedSignupService private - def whatsapp_api_version - @whatsapp_api_version ||= GlobalConfigService.load('WHATSAPP_API_VERSION', 'v22.0') + def validate_reauthorization_params! + return if @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 - def exchange_code_for_token - response = Faraday.get( - "https://graph.facebook.com/#{whatsapp_api_version}/oauth/access_token", - { - client_id: GlobalConfigService.load('WHATSAPP_APP_ID', ''), - client_secret: GlobalConfigService.load('WHATSAPP_APP_SECRET', ''), - code: @code - } - ) + def find_and_validate_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' - raise "Token exchange failed: #{response.body}" unless response.success? + channel = inbox.channel + raise ArgumentError, 'Channel is not WhatsApp Cloud provider' unless channel.provider == 'whatsapp_cloud' - data = JSON.parse(response.body) - raise "No access token in response: #{data}" unless data['access_token'] - - data['access_token'] - end - - def fetch_phone_info_via_waba(waba_id, phone_number_id, access_token) - # Get all phone numbers for the WABA - response = Faraday.get( - "https://graph.facebook.com/#{whatsapp_api_version}/#{waba_id}/phone_numbers", - { access_token: access_token } - ) - - raise "WABA phone numbers fetch failed: #{response.body}" unless response.success? - - data = JSON.parse(response.body) - phone_numbers = data['data'] - phone_data = phone_numbers.find { |phone| phone['id'] == phone_number_id } || phone_numbers.first - - raise "No phone numbers found for WABA #{waba_id}" if phone_data.nil? - - display_phone_number = sanitize_phone_number(phone_data['display_phone_number']) - { - phone_number_id: phone_data['id'], - phone_number: "+#{display_phone_number}", - verified: phone_data['code_verification_status'] == 'VERIFIED', - business_name: phone_data['verified_name'] || phone_data['display_phone_number'] - } + channel end def create_or_update_channel(waba_info, phone_info, access_token) @@ -134,16 +89,6 @@ class Whatsapp::EmbeddedSignupService end end - def register_phone_number(phone_number_id, access_token) - HTTParty.post( - "https://graph.facebook.com/#{whatsapp_api_version}/#{phone_number_id}/register", - { - headers: { 'Authorization' => "Bearer #{access_token}", 'Content-Type' => 'application/json' }, - body: { messaging_product: 'whatsapp', pin: '212834' }.to_json - } - ) - end - def find_existing_channel(phone_number) Channel::Whatsapp.find_by(account: @account, phone_number: phone_number) end @@ -187,77 +132,4 @@ class Whatsapp::EmbeddedSignupService ) ) end - - def sanitize_phone_number(phone_number) - return phone_number if phone_number.blank? - - phone_number.gsub(/[\s\-\(\)\.\+]/, '').strip - end - - def validate_token_waba_access(access_token, waba_id) - token_debug_data = fetch_token_debug_data(access_token) - waba_scope = extract_waba_scope(token_debug_data) - verify_waba_authorization(waba_scope, waba_id) - end - - def fetch_token_debug_data(access_token) - response = Faraday.get( - "https://graph.facebook.com/#{whatsapp_api_version}/debug_token", - { - input_token: access_token, - access_token: build_app_access_token - } - ) - - raise "Token validation failed: #{response.body}" unless response.success? - - JSON.parse(response.body) - end - - def extract_waba_scope(token_data) - granular_scopes = token_data.dig('data', 'granular_scopes') - waba_scope = granular_scopes&.find { |scope| scope['scope'] == 'whatsapp_business_management' } - - raise 'No WABA scope found in token' unless waba_scope - - waba_scope - end - - def verify_waba_authorization(waba_scope, waba_id) - authorized_waba_ids = waba_scope['target_ids'] || [] - - return if authorized_waba_ids.include?(waba_id) - - raise "Token does not have access to WABA #{waba_id}. Authorized WABAs: #{authorized_waba_ids}" - end - - def build_app_access_token - app_id = GlobalConfigService.load('WHATSAPP_APP_ID', '') - app_secret = GlobalConfigService.load('WHATSAPP_APP_SECRET', '') - "#{app_id}|#{app_secret}" - end - - def override_waba_webhook(waba_id, channel, access_token) - callback_url = "#{ENV.fetch('FRONTEND_URL', nil)}/webhooks/whatsapp/#{channel.phone_number}" - verify_token = channel.provider_config['webhook_verify_token'] - - response = HTTParty.post( - "https://graph.facebook.com/#{whatsapp_api_version}/#{waba_id}/subscribed_apps", - { - headers: { - 'Authorization' => "Bearer #{access_token}", - 'Content-Type' => 'application/json' - }, - body: { - override_callback_uri: callback_url, - verify_token: verify_token - }.to_json - } - ) - - return if response.success? - - Rails.logger.error("[WHATSAPP] Webhook override failed: #{response.body}") - raise "Webhook override failed: #{response.body}" - end end diff --git a/app/services/whatsapp/token_validator.rb b/app/services/whatsapp/token_validator.rb new file mode 100644 index 000000000..14e735e98 --- /dev/null +++ b/app/services/whatsapp/token_validator.rb @@ -0,0 +1,43 @@ +# Handles WhatsApp token validation +module Whatsapp::TokenValidator + extend ActiveSupport::Concern + + def validate_token_waba_access(access_token, waba_id) + token_debug_data = fetch_token_debug_data(access_token) + waba_scope = extract_waba_scope(token_debug_data) + verify_waba_authorization(waba_scope, waba_id) + end + + private + + def fetch_token_debug_data(access_token) + response = Faraday.get( + "https://graph.facebook.com/#{whatsapp_api_version}/debug_token", + { + input_token: access_token, + access_token: build_app_access_token + } + ) + + raise "Token validation failed: #{response.body}" unless response.success? + + JSON.parse(response.body) + end + + def extract_waba_scope(token_data) + granular_scopes = token_data.dig('data', 'granular_scopes') + waba_scope = granular_scopes&.find { |scope| scope['scope'] == 'whatsapp_business_management' } + + raise 'No WABA scope found in token' unless waba_scope + + waba_scope + end + + def verify_waba_authorization(waba_scope, waba_id) + authorized_waba_ids = waba_scope['target_ids'] || [] + + return if authorized_waba_ids.include?(waba_id) + + raise "Token does not have access to WABA #{waba_id}. Authorized WABAs: #{authorized_waba_ids}" + end +end \ No newline at end of file diff --git a/get_business_account_path.rb b/get_business_account_path.rb deleted file mode 100755 index aef6ed500..000000000 --- a/get_business_account_path.rb +++ /dev/null @@ -1,99 +0,0 @@ -#!/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 \ No newline at end of file