Since embedded signup has been disabled on production, WhatsApp inboxes that were created through it have no way to be managed going forward. This PR lets admins transfer an embedded signup inbox to a manual Cloud API setup: the inbox settings Configuration tab now shows the webhook verification token and a "Switch to Manual Setup" form (pre-populated with the Phone Number ID, Business Account ID, and API key stored during the embedded signup journey) instead of the old Reconfigure button. Saving the form updates the channel's `provider_config` without the `source: embedded_signup` marker, so the inbox becomes a regular manually-configured WhatsApp Cloud inbox. The backend re-validates the submitted credentials against Meta before accepting the change. ## How to test 1. Open the settings page of a WhatsApp inbox created via embedded signup → Configuration tab. 2. The Reconfigure button is gone; you see the webhook verification token and a Switch to Manual Setup form pre-filled with the stored credentials. 3. Configure the webhook in your own Meta app using the verification token, enter a permanent access token from that app, and click "Switch to Manual Setup". 4. On success the page switches to the standard manual configuration view (verify token, API key update), and messaging continues to work with the new credentials. Invalid credentials are rejected with an error. ## What changed - `ConfigurationPage.vue`: replaced the embedded-signup Reconfigure section (and the hidden reauthorize component) with the manual transfer form. - New `WHATSAPP_MANUAL_TRANSFER_*` translation keys. --------- Co-authored-by: Muhsin <12408980+muhsin-k@users.noreply.github.com> Co-authored-by: Muhsin Keloth <muhsinkeramam@gmail.com> Co-authored-by: iamsivin <iamsivin@gmail.com>
191 lines
6.2 KiB
Ruby
191 lines
6.2 KiB
Ruby
class Api::V1::Accounts::InboxesController < Api::V1::Accounts::BaseController
|
|
include Api::V1::InboxesHelper
|
|
before_action :fetch_inbox, except: [:index, :create]
|
|
before_action :fetch_agent_bot, only: [:set_agent_bot]
|
|
# we are already handling the authorization in fetch inbox
|
|
before_action :check_authorization, except: [:show]
|
|
|
|
include Api::V1::Accounts::Concerns::WhatsappHealthManagement
|
|
|
|
def index
|
|
@inboxes = policy_scope(Current.account.inboxes)
|
|
.includes(:channel, :portal, :working_hours, { avatar_attachment: :blob })
|
|
.order_by_name
|
|
end
|
|
|
|
def show; end
|
|
|
|
# Deprecated: This API will be removed in 2.7.0
|
|
def assignable_agents
|
|
@assignable_agents = @inbox.assignable_agents
|
|
end
|
|
|
|
def campaigns
|
|
@campaigns = @inbox.campaigns
|
|
end
|
|
|
|
def avatar
|
|
@inbox.avatar.attachment.destroy! if @inbox.avatar.attached?
|
|
head :ok
|
|
end
|
|
|
|
def create
|
|
ActiveRecord::Base.transaction do
|
|
channel = create_channel
|
|
@inbox = Current.account.inboxes.build(
|
|
{
|
|
name: inbox_name(channel),
|
|
channel: channel
|
|
}.merge(
|
|
permitted_params.except(:channel)
|
|
)
|
|
)
|
|
@inbox.save!
|
|
end
|
|
end
|
|
|
|
def update
|
|
inbox_params = permitted_params.except(:channel, :csat_config)
|
|
inbox_params[:csat_config] = format_csat_config(permitted_params[:csat_config]) if permitted_params[:csat_config].present?
|
|
@inbox.update!(inbox_params)
|
|
update_inbox_working_hours
|
|
update_channel if channel_update_required?
|
|
end
|
|
|
|
def agent_bot
|
|
@agent_bot = @inbox.agent_bot
|
|
end
|
|
|
|
def set_agent_bot
|
|
if @agent_bot
|
|
agent_bot_inbox = @inbox.agent_bot_inbox || AgentBotInbox.new(inbox: @inbox)
|
|
agent_bot_inbox.agent_bot = @agent_bot
|
|
agent_bot_inbox.save!
|
|
elsif @inbox.agent_bot_inbox.present?
|
|
@inbox.agent_bot_inbox.destroy!
|
|
end
|
|
head :ok
|
|
end
|
|
|
|
def reset_secret
|
|
return head :not_found unless @inbox.api?
|
|
|
|
@inbox.channel.reset_secret!
|
|
end
|
|
|
|
def destroy
|
|
::DeleteObjectJob.perform_later(@inbox, Current.user, request.ip) if @inbox.present?
|
|
render status: :ok, json: { message: I18n.t('messages.inbox_deletetion_response') }
|
|
end
|
|
|
|
private
|
|
|
|
def fetch_inbox
|
|
@inbox = Current.account.inboxes.find(params[:id])
|
|
authorize @inbox, :show?
|
|
end
|
|
|
|
def fetch_agent_bot
|
|
@agent_bot = AgentBot.accessible_to(Current.account).find(params[:agent_bot]) if params[:agent_bot]
|
|
end
|
|
|
|
def create_channel
|
|
return unless allowed_channel_types.include?(permitted_params[:channel][:type])
|
|
|
|
account_channels_method.create!(permitted_params(channel_type_from_params::EDITABLE_ATTRS)[:channel].except(:type))
|
|
end
|
|
|
|
def allowed_channel_types
|
|
%w[web_widget api email line telegram whatsapp sms]
|
|
end
|
|
|
|
def update_inbox_working_hours
|
|
@inbox.update_working_hours(params.permit(working_hours: Inbox::OFFISABLE_ATTRS)[:working_hours]) if params[:working_hours]
|
|
end
|
|
|
|
def update_channel
|
|
channel_attributes = get_channel_attributes(@inbox.channel_type)
|
|
return if permitted_params(channel_attributes)[:channel].blank?
|
|
|
|
validate_and_update_email_channel(channel_attributes) if @inbox.inbox_type == 'Email'
|
|
|
|
reauthorize_and_update_channel(channel_attributes)
|
|
update_channel_feature_flags
|
|
end
|
|
|
|
def channel_update_required?
|
|
permitted_params(get_channel_attributes(@inbox.channel_type))[:channel].present?
|
|
end
|
|
|
|
def validate_and_update_email_channel(channel_attributes)
|
|
validate_email_channel(channel_attributes)
|
|
rescue StandardError => e
|
|
render json: { message: e }, status: :unprocessable_entity and return
|
|
end
|
|
|
|
def reauthorize_and_update_channel(channel_attributes)
|
|
@inbox.channel.update!(permitted_params(channel_attributes)[:channel])
|
|
@inbox.channel.reauthorized! if @inbox.channel.respond_to?(:reauthorized!)
|
|
end
|
|
|
|
def update_channel_feature_flags
|
|
return unless @inbox.web_widget?
|
|
return unless permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel].key? :selected_feature_flags
|
|
|
|
@inbox.channel.selected_feature_flags = permitted_params(Channel::WebWidget::EDITABLE_ATTRS)[:channel][:selected_feature_flags]
|
|
@inbox.channel.save!
|
|
end
|
|
|
|
def format_csat_config(config)
|
|
formatted = {
|
|
'display_type' => config['display_type'] || 'emoji',
|
|
'message' => config['message'] || '',
|
|
:survey_rules => {
|
|
'operator' => config.dig('survey_rules', 'operator') || 'contains',
|
|
'values' => config.dig('survey_rules', 'values') || []
|
|
},
|
|
'button_text' => config['button_text'] || 'Please rate us',
|
|
'language' => config['language'] || 'en'
|
|
}
|
|
format_template_config(config, formatted)
|
|
formatted
|
|
end
|
|
|
|
def format_template_config(config, formatted)
|
|
formatted['template'] = config['template'] if config['template'].present?
|
|
end
|
|
|
|
def inbox_attributes
|
|
[:name, :avatar, :greeting_enabled, :greeting_message, :enable_email_collect, :csat_survey_enabled,
|
|
:enable_auto_assignment, :working_hours_enabled, :out_of_office_message, :timezone, :allow_messages_after_resolved,
|
|
:lock_to_single_conversation, :portal_id, :sender_name_type, :business_name,
|
|
{ csat_config: [:display_type, :message, :button_text, :language,
|
|
{ survey_rules: [:operator, { values: [] }],
|
|
template: [:name, :template_id, :friendly_name, :content_sid, :approval_sid, :created_at, :language, :status] }] }]
|
|
end
|
|
|
|
def permitted_params(channel_attributes = [])
|
|
# We will remove this line after fixing https://linear.app/chatwoot/issue/CW-1567/null-value-passed-as-null-string-to-backend
|
|
params.each { |k, v| params[k] = params[k] == 'null' ? nil : v }
|
|
params.permit(*inbox_attributes, channel: [:type, *channel_attributes])
|
|
end
|
|
|
|
def channel_type_from_params
|
|
{
|
|
'web_widget' => Channel::WebWidget,
|
|
'api' => Channel::Api,
|
|
'email' => Channel::Email,
|
|
'line' => Channel::Line,
|
|
'telegram' => Channel::Telegram,
|
|
'whatsapp' => Channel::Whatsapp,
|
|
'sms' => Channel::Sms
|
|
}[permitted_params[:channel][:type]]
|
|
end
|
|
|
|
def get_channel_attributes(channel_type)
|
|
channel_type.constantize.const_defined?(:EDITABLE_ATTRS) ? channel_type.constantize::EDITABLE_ATTRS.presence : []
|
|
end
|
|
end
|
|
|
|
Api::V1::Accounts::InboxesController.prepend_mod_with('Api::V1::Accounts::InboxesController')
|