* feat(whatsapp): allow converting inbox between WhatsApp providers Adds a Convert flow to switch a WhatsApp inbox between the four supported providers (default/360dialog, whatsapp_cloud, baileys, zapi) without losing conversations, agents, or history. - Channel::Whatsapp#convert_provider! runs inside a transaction: disconnects the old provider, clears provider_connection and message_templates, assigns the new provider/config, and triggers webhook setup plus template resync on the new service. - New POST /api/v1/accounts/:id/inboxes/:id/convert_provider endpoint guarded by InboxPolicy#convert_provider? (admin only). - UI adds a Convert button on the inbox Settings page with a type-to-confirm ConvertInboxModal that lists the effects before redirecting to a dedicated route reusing the WhatsApp provider wizard in convert mode (phone number locked, current provider hidden from the picker). * chore(whatsapp): polish convert UI colors and expand specs - Settings: use slate for the Convert trigger and ruby for the modal confirm to mirror the delete gate instead of the less conventional amber variant. - Drop the redundant "current provider is hidden from the list" sentence from the convert wizard description. - Add specs for the post-conversion webhook setup path (triggered and skipped branches) and the sync_templates error-rescue behaviour. * fix: address CodeRabbit review on convert-provider flow - Whitelist provider_config keys in the convert endpoint via permit rather than permit!, and default to an empty hash when omitted so the request no longer crashes. - Pre-validate the new provider config before disconnecting the old session so a bad target config no longer terminates the existing provider; also keep the disconnect bound to the old provider_url. - Guard ConvertInboxModal's submit handler so pressing Enter cannot bypass the type-to-confirm gate, and migrate it to <script setup>. - Reject invalid ?provider= query values in convert mode so hidden providers (Twilio, the current provider) cannot be reached via URL. - Await the inbox fetch in InboxConvert before running the route guard so directly opening the route for a non-WhatsApp inbox redirects. - Remove the unreachable second CloudWhatsapp branch in Whatsapp.vue. * fix: address second CodeRabbit round on convert-provider flow - Unify provider picker validation so create mode also rejects unknown ?provider= values, with a single helper that accepts available providers plus the whatsapp_manual fallback. - Simplify the pre-validation rollback in convert_provider!: the errors snapshot/merge dance was redundant because assign_attributes does not clear errors. - Follow the repo convention of asserting on error.class.name so the rollback spec stays stable under reloading/parallel environments. - Strengthen the controller success spec with provider_connection and message_templates cleanup invariants, and set Content-Type on the templates stub so HTTParty parses the empty data array correctly. * fix: address third CodeRabbit round on convert-provider flow - Add 360Dialog entry to the Whatsapp provider catalog, keep it hidden from the create picker (preserving the existing fork behavior) but expose it in the convert picker where it is a valid target. Restore URL reachability for ?provider=360dialog in create mode. - Scope the WHATSAPP_MANUAL allowance to create mode only: the manual fallback flow is not reachable in convert mode. - Redirect to the inboxes list in InboxConvert when the inbox is still absent after the store fetch, so the page no longer stays blank. - Use an explicit allowlist of WhatsApp providers to gate the Convert button instead of negating Twilio, so adding a new WhatsApp channel type will not silently expose the flow. - Bind the disabled provider display field with :value instead of v-model, since the underlying computed is getter-only. - Add Content-Type: application/json to the templates stub in the model spec so HTTParty parses the empty data array. * fix: address fourth CodeRabbit round on convert-provider flow - Reject no-op conversions that target the same provider as the one already configured, so the endpoint no longer wipes provider connection and message templates on a request that changes nothing. - Call the provider service's disconnect directly so failures abort the conversion instead of being silently swallowed; otherwise the old external session could remain live while the inbox flips to the new provider. - Cover both behaviors with specs. * fix: address fifth CodeRabbit round on convert-provider flow - Reset the Vuelidate state when closing ConvertInboxModal so reopening the gate does not surface stale validation errors. - Call teardown_webhooks before converting away from whatsapp_cloud so the Meta webhook subscription is removed for embedded_signup channels, mirroring the destroy-time cleanup (manual-setup channels keep the existing no-op behavior). Swallow teardown failures so a flaky Meta call does not abort the swap. - Switch the rollback specs to compare message_templates counts instead of the boolean be_present matcher so they remain meaningful if the fixture happens to have an empty templates list. * fix: address sixth CodeRabbit round on convert-provider flow - Derive the convert header's current-provider label from the shared PROVIDER_CATALOG so the picker and header stay in sync. - Assert the full Cloud provider_config payload and the absence of the Baileys-only provider_url key on both the controller success spec and the model atomic-swap spec. - In the sync-error spec, reload and assert that the record was actually flipped to the new provider before the sync rescue fires, so the test can't pass on a pre-save failure. * test: pin 422 error payload on convert_provider negative paths The unsupported-conversion and invalid-config specs only checked the status code, so they would have stayed green if the 422 started coming from a different branch. Pin the response body so each example actually covers the failure case it names. * fix(baileys): save custom host as provider_url, not url The Baileys form was writing the custom endpoint to provider_config['url'] while the backend reads provider_config['provider_url']. That silently broke the custom-host feature for newly created or converted Baileys inboxes: they always fell back to BAILEYS_PROVIDER_DEFAULT_URL. Align the key on both ends. * fix(whatsapp): skip second validation pass in convert_provider! The transaction's save! was re-running validate_provider_config after the old provider's session had already been disconnected, so a transient Graph API failure on the second check could roll back the swap while leaving the external session terminated — the exact inconsistency the pre-flight valid? was meant to rule out. Capture the validated provider_config snapshot after valid? (so fields populated by before_validation callbacks like webhook_verify_token are preserved) and switch the final persist to save!(validate: false) so the earlier check stays authoritative. * fix: normalize provider-conversion failures and pass accountId - The convert_provider action only rescued ActiveRecord::RecordInvalid, so disconnect/teardown failures bubbled up as 500 with no stable payload. Catch StandardError, log the class + message, and return a 422 with a generic user-facing message so the dashboard can surface the error consistently. - Nested settings routes live under /accounts/:accountId, so the router push from Settings.vue must include accountId alongside inboxId. Mirrors how sibling pages navigate to settings_inbox_show. * fix: report missing :provider as 400 and sync modal v-model - The generic rescue StandardError on convert_provider was masking ActionController::ParameterMissing behind a misleading provider-conversion error message. Catch it explicitly before the generic rescue and return 400 with the parameter-missing message. - ConvertInboxModal's closeModal now drives localShow to false so parents using v-model:show stay in sync on every close path, not only when the explicit onClose listener flips the flag. * fix(whatsapp): serialize concurrent convert_provider calls with_lock Without a per-record lock, two admin requests against the same inbox could both pass the pre-flight validation, race the disconnect/save, and then run setup_webhooks/sync_templates in arbitrary order, leaving the persisted provider out of sync with the external configuration. Wrap the whole convert flow in with_lock so the loser blocks until the winner commits; the subsequent no-op guard then rejects a second conversion request targeting the provider the first one just set. * test: harden convert_provider policy + controller failure specs - Pass accountId explicitly in InboxConvert redirects so the route navigation mirrors how Settings.vue reaches settings_inbox_convert. - Add a spec that assigns the agent to the inbox and still expects 401, so a future regression in InboxPolicy#convert_provider? can no longer slip past on the show policy alone. - Add a spec that stubs convert_provider! to raise StandardError and asserts the controller's generic-failure 422 payload, pinning the dashboard contract for provider-side failures. * test: pin convert_provider success response payload Parse the rendered body and assert provider + provider_config so the spec catches regressions where the DB is updated correctly but the serialized response drifts (dashboard store commits response.data). * fix(whatsapp): reset teardown guard after pre-conversion webhook cleanup teardown_webhooks memoizes @webhook_teardown_initiated = true to prevent double execution during destroy. Calling it from convert_provider! leaves that flag set, so a subsequent destroy! or follow-up conversion on the same instance would skip webhook removal silently. Reset the flag in an ensure block so the destroy-time guard stays scoped to destroy only. * fix: include accountId in post-conversion redirect params * test: pin same-provider convert returns 422 * fix(whatsapp): reset template columns when post-conversion sync fails * fix(convert): enforce provider allowlist in InboxConvert route guard * test: broaden Cloud templates stub to match account-scoped path * test(whatsapp): cover cloud to baileys conversion branch
733 lines
27 KiB
Ruby
733 lines
27 KiB
Ruby
Rails.application.routes.draw do
|
|
# AUTH STARTS
|
|
mount_devise_token_auth_for 'User', at: 'auth', controllers: {
|
|
confirmations: 'devise_overrides/confirmations',
|
|
passwords: 'devise_overrides/passwords',
|
|
sessions: 'devise_overrides/sessions',
|
|
token_validations: 'devise_overrides/token_validations',
|
|
omniauth_callbacks: 'devise_overrides/omniauth_callbacks'
|
|
}, via: [:get, :post]
|
|
|
|
post 'resend_confirmation', to: 'auth/resend_confirmations#create'
|
|
|
|
## renders the frontend paths only if its not an api only server
|
|
if ActiveModel::Type::Boolean.new.cast(ENV.fetch('CW_API_ONLY_SERVER', false))
|
|
root to: 'api#index'
|
|
else
|
|
root to: 'dashboard#index'
|
|
|
|
get '/app', to: 'dashboard#index'
|
|
get '/app/*params', to: 'dashboard#index'
|
|
get '/app/accounts/:account_id/settings/inboxes/new/twitter', to: 'dashboard#index', as: 'app_new_twitter_inbox'
|
|
get '/app/accounts/:account_id/settings/inboxes/new/microsoft', to: 'dashboard#index', as: 'app_new_microsoft_inbox'
|
|
get '/app/accounts/:account_id/settings/inboxes/new/instagram', to: 'dashboard#index', as: 'app_new_instagram_inbox'
|
|
get '/app/accounts/:account_id/settings/inboxes/new/tiktok', to: 'dashboard#index', as: 'app_new_tiktok_inbox'
|
|
get '/app/accounts/:account_id/settings/inboxes/new/:inbox_id/agents', to: 'dashboard#index', as: 'app_twitter_inbox_agents'
|
|
get '/app/accounts/:account_id/settings/inboxes/new/:inbox_id/agents', to: 'dashboard#index', as: 'app_email_inbox_agents'
|
|
get '/app/accounts/:account_id/settings/inboxes/new/:inbox_id/agents', to: 'dashboard#index', as: 'app_instagram_inbox_agents'
|
|
get '/app/accounts/:account_id/settings/inboxes/new/:inbox_id/agents', to: 'dashboard#index', as: 'app_tiktok_inbox_agents'
|
|
get '/app/accounts/:account_id/settings/inboxes/:inbox_id', to: 'dashboard#index', as: 'app_instagram_inbox_settings'
|
|
get '/app/accounts/:account_id/settings/inboxes/:inbox_id', to: 'dashboard#index', as: 'app_tiktok_inbox_settings'
|
|
get '/app/accounts/:account_id/settings/inboxes/:inbox_id', to: 'dashboard#index', as: 'app_email_inbox_settings'
|
|
|
|
resource :widget, only: [:show]
|
|
namespace :survey do
|
|
resources :responses, only: [:show]
|
|
end
|
|
resource :slack_uploads, only: [:show]
|
|
end
|
|
|
|
get '/health', to: 'health#show'
|
|
get '/api', to: 'api#index'
|
|
namespace :api, defaults: { format: 'json' } do
|
|
namespace :v1 do
|
|
# ----------------------------------
|
|
# start of account scoped api routes
|
|
resources :accounts, only: [:create, :show, :update] do
|
|
member do
|
|
post :update_active_at
|
|
get :cache_keys
|
|
end
|
|
|
|
scope module: :accounts do
|
|
namespace :actions do
|
|
resource :contact_merge, only: [:create]
|
|
end
|
|
resource :bulk_actions, only: [:create]
|
|
resources :agents, only: [:index, :create, :update, :destroy] do
|
|
post :bulk_create, on: :collection
|
|
end
|
|
namespace :captain do
|
|
resource :preferences, only: [:show, :update]
|
|
resources :assistants do
|
|
member do
|
|
post :playground
|
|
end
|
|
collection do
|
|
get :tools
|
|
end
|
|
resources :inboxes, only: [:index, :create, :destroy], param: :inbox_id
|
|
resources :scenarios
|
|
end
|
|
resources :assistant_responses
|
|
resources :bulk_actions, only: [:create]
|
|
resources :copilot_threads, only: [:index, :create] do
|
|
resources :copilot_messages, only: [:index, :create]
|
|
end
|
|
resources :custom_tools do
|
|
post :test, on: :collection
|
|
end
|
|
resources :documents, only: [:index, :show, :create, :destroy]
|
|
resource :tasks, only: [], controller: 'tasks' do
|
|
post :rewrite
|
|
post :summarize
|
|
post :reply_suggestion
|
|
post :label_suggestion
|
|
post :follow_up
|
|
end
|
|
end
|
|
resource :saml_settings, only: [:show, :create, :update, :destroy]
|
|
resources :agent_bots, only: [:index, :create, :show, :update, :destroy] do
|
|
delete :avatar, on: :member
|
|
post :reset_access_token, on: :member
|
|
post :reset_secret, on: :member
|
|
end
|
|
resources :contact_inboxes, only: [] do
|
|
collection do
|
|
post :filter
|
|
end
|
|
end
|
|
resources :assignable_agents, only: [:index]
|
|
resource :audit_logs, only: [:show]
|
|
resources :callbacks, only: [] do
|
|
collection do
|
|
post :register_facebook_page
|
|
get :register_facebook_page
|
|
post :facebook_pages
|
|
post :reauthorize_page
|
|
end
|
|
end
|
|
resources :canned_responses, only: [:index, :create, :update, :destroy]
|
|
resources :automation_rules, only: [:index, :create, :show, :update, :destroy] do
|
|
post :clone
|
|
end
|
|
resources :macros, only: [:index, :create, :show, :update, :destroy] do
|
|
post :execute, on: :member
|
|
end
|
|
resources :sla_policies, only: [:index, :create, :show, :update, :destroy]
|
|
resources :custom_roles, only: [:index, :create, :show, :update, :destroy]
|
|
resources :agent_capacity_policies, only: [:index, :create, :show, :update, :destroy] do
|
|
scope module: :agent_capacity_policies do
|
|
resources :users, only: [:index, :create, :destroy]
|
|
resources :inbox_limits, only: [:create, :update, :destroy]
|
|
end
|
|
end
|
|
resources :campaigns, only: [:index, :create, :show, :update, :destroy]
|
|
resources :dashboard_apps, only: [:index, :show, :create, :update, :destroy]
|
|
namespace :channels do
|
|
resource :twilio_channel, only: [:create]
|
|
end
|
|
resources :conversations, only: [:index, :create, :show, :update, :destroy] do
|
|
collection do
|
|
get :meta
|
|
get :search
|
|
post :filter
|
|
post :presence_subscribe_bulk
|
|
end
|
|
scope module: :conversations do
|
|
resources :messages, only: [:index, :create, :destroy, :update] do
|
|
member do
|
|
post :translate
|
|
post :retry
|
|
patch :edit_content
|
|
end
|
|
resources :attachments, only: [:update]
|
|
end
|
|
resources :scheduled_messages, only: [:index, :create, :update, :destroy]
|
|
resources :recurring_scheduled_messages, only: [:index, :create, :update, :destroy]
|
|
resources :assignments, only: [:create]
|
|
resources :labels, only: [:create, :index]
|
|
resource :participants, only: [:show, :create, :update, :destroy]
|
|
resource :direct_uploads, only: [:create]
|
|
resource :draft_messages, only: [:show, :update, :destroy]
|
|
end
|
|
member do
|
|
post :mute
|
|
post :unmute
|
|
post :transcript
|
|
post :toggle_status
|
|
post :toggle_priority
|
|
post :toggle_typing_status
|
|
post :presence_subscribe
|
|
post :update_last_seen
|
|
post :unread
|
|
post :custom_attributes
|
|
get :attachments
|
|
get :inbox_assistant
|
|
get :reporting_events if ChatwootApp.enterprise?
|
|
end
|
|
end
|
|
|
|
namespace :internal_chat do
|
|
resource :search, only: [:show], controller: 'search'
|
|
resources :categories, only: [:index, :create, :update, :destroy]
|
|
resources :channels, only: [:index, :create, :show, :update, :destroy] do
|
|
member do
|
|
post :archive
|
|
post :unarchive
|
|
post :toggle_typing_status
|
|
post :mark_read
|
|
post :mark_unread
|
|
end
|
|
resources :members, controller: 'channel_members', only: [:index, :create, :update, :destroy]
|
|
resources :messages, only: [:index, :create, :update, :destroy] do
|
|
member do
|
|
post :pin
|
|
delete :unpin
|
|
get :thread
|
|
end
|
|
end
|
|
resource :draft, only: [:update, :destroy]
|
|
end
|
|
resources :messages, only: [] do
|
|
resources :reactions, only: [:create, :destroy]
|
|
end
|
|
resources :polls, only: [:create] do
|
|
member do
|
|
post :vote
|
|
delete :vote, action: :unvote
|
|
end
|
|
end
|
|
resources :drafts, only: [:index]
|
|
end
|
|
|
|
resources :search, only: [:index] do
|
|
collection do
|
|
get :conversations
|
|
get :messages
|
|
get :contacts
|
|
get :articles
|
|
end
|
|
end
|
|
|
|
resources :companies, only: [:index, :show, :create, :update, :destroy] do
|
|
collection do
|
|
get :search
|
|
end
|
|
end
|
|
resources :groups, only: [:create]
|
|
resources :contacts, only: [:index, :show, :update, :create, :destroy] do
|
|
collection do
|
|
get :active
|
|
get :search
|
|
post :filter
|
|
post :import
|
|
post :export
|
|
end
|
|
member do
|
|
get :contactable_inboxes
|
|
post :destroy_custom_attributes
|
|
post :sync_group
|
|
delete :avatar
|
|
end
|
|
scope module: :contacts do
|
|
resources :conversations, only: [:index]
|
|
resources :contact_inboxes, only: [:create]
|
|
resources :group_members, only: [:index, :create, :destroy] do
|
|
patch ':member_id', to: 'group_members#update', on: :collection
|
|
end
|
|
resource :group_metadata, only: [:update]
|
|
resource :group_invite, only: [:show] do
|
|
post :revoke, on: :member
|
|
end
|
|
resources :group_join_requests, only: [:index] do
|
|
post :handle, on: :collection
|
|
end
|
|
resource :group_admin, only: [:update], controller: 'group_admin' do
|
|
post :leave, on: :member
|
|
end
|
|
resources :labels, only: [:create, :index]
|
|
resources :notes
|
|
post :call, on: :member, to: 'calls#create' if ChatwootApp.enterprise?
|
|
end
|
|
end
|
|
resources :csat_survey_responses, only: [:index] do
|
|
collection do
|
|
get :metrics
|
|
get :download
|
|
end
|
|
member do
|
|
patch :update if ChatwootApp.enterprise?
|
|
end
|
|
end
|
|
resources :applied_slas, only: [:index] do
|
|
collection do
|
|
get :metrics
|
|
get :download
|
|
end
|
|
end
|
|
resources :reporting_events, only: [:index] if ChatwootApp.enterprise?
|
|
resources :custom_attribute_definitions, only: [:index, :show, :create, :update, :destroy]
|
|
resources :custom_filters, only: [:index, :show, :create, :update, :destroy]
|
|
resources :inboxes, only: [:index, :show, :create, :update, :destroy] do
|
|
get :assignable_agents, on: :member
|
|
get :campaigns, on: :member
|
|
get :agent_bot, on: :member
|
|
post :set_agent_bot, on: :member
|
|
post :setup_channel_provider, on: :member
|
|
post :disconnect_channel_provider, on: :member
|
|
post :convert_provider, on: :member
|
|
delete :avatar, on: :member
|
|
post :sync_templates, on: :member
|
|
get :health, on: :member
|
|
post :register_webhook, on: :member
|
|
post :reset_secret, on: :member
|
|
post :on_whatsapp, on: :member
|
|
if ChatwootApp.enterprise?
|
|
resource :conference, only: %i[create destroy], controller: 'conference' do
|
|
get :token, on: :member
|
|
end
|
|
end
|
|
|
|
resource :csat_template, only: [:show, :create], controller: 'inbox_csat_templates' do
|
|
post :analyze, on: :collection
|
|
post :link, on: :member
|
|
get :available_templates, on: :member
|
|
end
|
|
end
|
|
|
|
resources :inbox_members, only: [:create, :show], param: :inbox_id do
|
|
collection do
|
|
delete :destroy
|
|
patch :update
|
|
end
|
|
end
|
|
resources :labels, only: [:index, :show, :create, :update, :destroy]
|
|
|
|
resources :notifications, only: [:index, :update, :destroy] do
|
|
collection do
|
|
post :read_all
|
|
get :unread_count
|
|
post :destroy_all
|
|
end
|
|
member do
|
|
post :snooze
|
|
post :unread
|
|
end
|
|
end
|
|
resource :notification_settings, only: [:show, :update]
|
|
|
|
resources :teams do
|
|
resources :team_members, only: [:index, :create] do
|
|
collection do
|
|
delete :destroy
|
|
patch :update
|
|
end
|
|
end
|
|
end
|
|
|
|
# Assignment V2 Routes
|
|
resources :assignment_policies do
|
|
resources :inboxes, only: [:index, :create, :destroy], module: :assignment_policies
|
|
end
|
|
|
|
resources :inboxes, only: [] do
|
|
resource :assignment_policy, only: [:show, :create, :destroy], module: :inboxes
|
|
end
|
|
|
|
namespace :twitter do
|
|
resource :authorization, only: [:create]
|
|
end
|
|
|
|
namespace :microsoft do
|
|
resource :authorization, only: [:create]
|
|
end
|
|
|
|
namespace :google do
|
|
resource :authorization, only: [:create]
|
|
end
|
|
|
|
namespace :instagram do
|
|
resource :authorization, only: [:create]
|
|
end
|
|
|
|
namespace :tiktok do
|
|
resource :authorization, only: [:create]
|
|
end
|
|
|
|
namespace :notion do
|
|
resource :authorization, only: [:create]
|
|
end
|
|
|
|
namespace :whatsapp do
|
|
resource :authorization, only: [:create]
|
|
end
|
|
|
|
resources :webhooks, only: [:index, :create, :update, :destroy]
|
|
namespace :integrations do
|
|
resources :apps, only: [:index, :show]
|
|
resources :hooks, only: [:show, :create, :update, :destroy] do
|
|
member do
|
|
post :process_event
|
|
end
|
|
end
|
|
resource :slack, only: [:create, :update, :destroy], controller: 'slack' do
|
|
member do
|
|
get :list_all_channels
|
|
end
|
|
end
|
|
resource :dyte, controller: 'dyte', only: [] do
|
|
collection do
|
|
post :create_a_meeting
|
|
post :add_participant_to_meeting
|
|
end
|
|
end
|
|
resource :shopify, controller: 'shopify', only: [:destroy] do
|
|
collection do
|
|
post :auth
|
|
get :orders
|
|
end
|
|
end
|
|
resource :linear, controller: 'linear', only: [] do
|
|
collection do
|
|
delete :destroy
|
|
get :teams
|
|
get :team_entities
|
|
post :create_issue
|
|
post :link_issue
|
|
post :unlink_issue
|
|
get :search_issue
|
|
get :linked_issues
|
|
end
|
|
end
|
|
resource :notion, controller: 'notion', only: [] do
|
|
collection do
|
|
delete :destroy
|
|
end
|
|
end
|
|
end
|
|
resources :working_hours, only: [:update]
|
|
|
|
resources :portals do
|
|
member do
|
|
patch :archive
|
|
delete :logo
|
|
post :send_instructions
|
|
get :ssl_status
|
|
end
|
|
resources :categories do
|
|
post :reorder, on: :collection
|
|
end
|
|
resources :articles do
|
|
post :reorder, on: :collection
|
|
end
|
|
end
|
|
|
|
resources :upload, only: [:create]
|
|
end
|
|
end
|
|
# end of account scoped api routes
|
|
# ----------------------------------
|
|
|
|
namespace :integrations do
|
|
resources :webhooks, only: [:create]
|
|
end
|
|
|
|
# Frontend API endpoint to trigger SAML authentication flow
|
|
post 'auth/saml_login', to: 'auth#saml_login'
|
|
|
|
resource :profile, only: [:show, :update] do
|
|
delete :avatar, on: :collection
|
|
member do
|
|
post :availability
|
|
post :auto_offline
|
|
put :set_active_account
|
|
post :resend_confirmation
|
|
post :reset_access_token
|
|
end
|
|
|
|
# MFA routes
|
|
scope module: 'profile' do
|
|
resource :mfa, controller: 'mfa', only: [:show, :create, :destroy] do
|
|
post :verify
|
|
post :backup_codes
|
|
end
|
|
resources :inbox_signatures, only: %i[index show update destroy], param: :inbox_id
|
|
end
|
|
end
|
|
|
|
resource :notification_subscriptions, only: [:create, :destroy]
|
|
|
|
namespace :widget do
|
|
resource :direct_uploads, only: [:create]
|
|
resource :config, only: [:create]
|
|
resources :campaigns, only: [:index]
|
|
resources :events, only: [:create]
|
|
resources :messages, only: [:index, :create, :update]
|
|
resources :conversations, only: [:index, :create] do
|
|
collection do
|
|
post :destroy_custom_attributes
|
|
post :set_custom_attributes
|
|
post :update_last_seen
|
|
post :toggle_typing
|
|
post :transcript
|
|
get :toggle_status
|
|
end
|
|
end
|
|
resource :contact, only: [:show, :update] do
|
|
collection do
|
|
post :destroy_custom_attributes
|
|
patch :set_user
|
|
end
|
|
end
|
|
resources :inbox_members, only: [:index]
|
|
resources :labels, only: [:create, :destroy]
|
|
namespace :integrations do
|
|
resource :dyte, controller: 'dyte', only: [] do
|
|
collection do
|
|
post :add_participant_to_meeting
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
namespace :v2 do
|
|
resources :accounts, only: [:create] do
|
|
scope module: :accounts do
|
|
resources :summary_reports, only: [] do
|
|
collection do
|
|
get :agent
|
|
get :team
|
|
get :inbox
|
|
get :label
|
|
get :channel
|
|
end
|
|
end
|
|
resources :reports, only: [:index] do
|
|
collection do
|
|
get :summary
|
|
get :bot_summary
|
|
get :agents
|
|
get :inboxes
|
|
get :labels
|
|
get :teams
|
|
get :conversations
|
|
get :conversations_summary
|
|
get :conversation_traffic
|
|
get :bot_metrics
|
|
get :inbox_label_matrix
|
|
get :first_response_time_distribution
|
|
get :outgoing_messages_count
|
|
end
|
|
end
|
|
resource :year_in_review, only: [:show]
|
|
resources :live_reports, only: [] do
|
|
collection do
|
|
get :conversation_metrics
|
|
get :grouped_conversation_metrics
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if ChatwootApp.enterprise?
|
|
namespace :enterprise, defaults: { format: 'json' } do
|
|
namespace :api do
|
|
namespace :v1 do
|
|
resources :accounts do
|
|
member do
|
|
post :checkout
|
|
post :subscription
|
|
get :limits
|
|
post :toggle_deletion
|
|
post :topup_checkout
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
post 'webhooks/stripe', to: 'webhooks/stripe#process_payload'
|
|
post 'webhooks/firecrawl', to: 'webhooks/firecrawl#process_payload'
|
|
end
|
|
end
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Routes for platform APIs
|
|
namespace :platform, defaults: { format: 'json' } do
|
|
namespace :api do
|
|
namespace :v1 do
|
|
resources :users, only: [:create, :show, :update, :destroy] do
|
|
member do
|
|
get :login
|
|
post :token
|
|
end
|
|
end
|
|
resources :agent_bots, only: [:index, :create, :show, :update, :destroy] do
|
|
delete :avatar, on: :member
|
|
end
|
|
resources :accounts, only: [:index, :create, :show, :update, :destroy] do
|
|
resources :account_users, only: [:index, :create] do
|
|
collection do
|
|
delete :destroy
|
|
end
|
|
end
|
|
resources :email_channel_migrations, only: [:create]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Routes for inbox APIs Exposed to contacts
|
|
namespace :public, defaults: { format: 'json' } do
|
|
namespace :api do
|
|
namespace :v1 do
|
|
resources :inboxes do
|
|
scope module: :inboxes do
|
|
resources :contacts, only: [:create, :show, :update] do
|
|
resources :conversations, only: [:index, :create, :show] do
|
|
member do
|
|
post :toggle_status
|
|
post :toggle_typing
|
|
post :update_last_seen
|
|
end
|
|
|
|
resources :messages, only: [:index, :create, :update]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
resources :csat_survey, only: [:show, :update]
|
|
end
|
|
end
|
|
end
|
|
|
|
get 'hc/:slug', to: 'public/api/v1/portals#show'
|
|
get 'hc/:slug/sitemap.xml', to: 'public/api/v1/portals#sitemap'
|
|
get 'hc/:slug/:locale', to: 'public/api/v1/portals#show'
|
|
get 'hc/:slug/:locale/articles', to: 'public/api/v1/portals/articles#index'
|
|
get 'hc/:slug/:locale/categories', to: 'public/api/v1/portals/categories#index'
|
|
get 'hc/:slug/:locale/categories/:category_slug', to: 'public/api/v1/portals/categories#show'
|
|
get 'hc/:slug/:locale/categories/:category_slug/articles', to: 'public/api/v1/portals/articles#index'
|
|
get 'hc/:slug/articles/:article_slug.png', to: 'public/api/v1/portals/articles#tracking_pixel'
|
|
get 'hc/:slug/articles/:article_slug', to: 'public/api/v1/portals/articles#show'
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Used in mailer templates
|
|
resource :app, only: [:index] do
|
|
resources :accounts do
|
|
resources :conversations, only: [:show]
|
|
end
|
|
end
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Routes for channel integrations
|
|
mount Facebook::Messenger::Server, at: 'bot'
|
|
get 'webhooks/twitter', to: 'api/v1/webhooks#twitter_crc'
|
|
post 'webhooks/twitter', to: 'api/v1/webhooks#twitter_events'
|
|
post 'webhooks/line/:line_channel_id', to: 'webhooks/line#process_payload'
|
|
post 'webhooks/telegram/:bot_token', to: 'webhooks/telegram#process_payload'
|
|
post 'webhooks/sms/:phone_number', to: 'webhooks/sms#process_payload'
|
|
get 'webhooks/whatsapp/:phone_number', to: 'webhooks/whatsapp#verify'
|
|
post 'webhooks/whatsapp/:phone_number', to: 'webhooks/whatsapp#process_payload'
|
|
get 'webhooks/instagram', to: 'webhooks/instagram#verify'
|
|
post 'webhooks/instagram', to: 'webhooks/instagram#events'
|
|
post 'webhooks/tiktok', to: 'webhooks/tiktok#events'
|
|
post 'webhooks/shopify', to: 'webhooks/shopify#events'
|
|
|
|
namespace :twitter do
|
|
resource :callback, only: [:show]
|
|
end
|
|
|
|
namespace :linear do
|
|
resource :callback, only: [:show]
|
|
end
|
|
|
|
namespace :shopify do
|
|
resource :callback, only: [:show]
|
|
end
|
|
|
|
namespace :twilio do
|
|
resources :callback, only: [:create]
|
|
resources :delivery_status, only: [:create]
|
|
|
|
if ChatwootApp.enterprise?
|
|
post 'voice/call/:phone', to: 'voice#call_twiml', as: :voice_call
|
|
post 'voice/status/:phone', to: 'voice#status', as: :voice_status
|
|
post 'voice/conference_status/:phone', to: 'voice#conference_status', as: :voice_conference_status
|
|
end
|
|
end
|
|
|
|
get 'microsoft/callback', to: 'microsoft/callbacks#show'
|
|
get 'google/callback', to: 'google/callbacks#show'
|
|
get 'instagram/callback', to: 'instagram/callbacks#show'
|
|
get 'tiktok/callback', to: 'tiktok/callbacks#show'
|
|
get 'notion/callback', to: 'notion/callbacks#show'
|
|
# ----------------------------------------------------------------------
|
|
# Routes for external service verifications
|
|
get '.well-known/assetlinks.json' => 'android_app#assetlinks'
|
|
get '.well-known/apple-app-site-association' => 'apple_app#site_association'
|
|
get '.well-known/microsoft-identity-association.json' => 'microsoft#identity_association'
|
|
get '.well-known/cf-custom-hostname-challenge/:id', to: 'custom_domains#verify'
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Internal Monitoring Routes
|
|
require 'sidekiq/web'
|
|
require 'sidekiq/cron/web'
|
|
|
|
devise_for :super_admins, path: 'super_admin', controllers: { sessions: 'super_admin/devise/sessions' }
|
|
devise_scope :super_admin do
|
|
get 'super_admin/logout', to: 'super_admin/devise/sessions#destroy'
|
|
namespace :super_admin do
|
|
root to: 'dashboard#index'
|
|
|
|
resource :app_config, only: [:show, :create]
|
|
|
|
# order of resources affect the order of sidebar navigation in super admin
|
|
resources :accounts, only: [:index, :new, :create, :show, :edit, :update, :destroy] do
|
|
post :seed, on: :member
|
|
post :reset_cache, on: :member
|
|
end
|
|
resources :users, only: [:index, :new, :create, :show, :edit, :update, :destroy] do
|
|
delete :avatar, on: :member, action: :destroy_avatar
|
|
end
|
|
|
|
resources :access_tokens, only: [:index, :show]
|
|
resources :installation_configs, only: [:index, :new, :create, :show, :edit, :update]
|
|
resources :agent_bots, only: [:index, :new, :create, :show, :edit, :update, :destroy] do
|
|
delete :avatar, on: :member, action: :destroy_avatar
|
|
end
|
|
resources :platform_apps, only: [:index, :new, :create, :show, :edit, :update, :destroy]
|
|
resource :instance_status, only: [:show]
|
|
|
|
resource :settings, only: [:show] do
|
|
get :refresh, on: :collection
|
|
end
|
|
|
|
# resources that doesn't appear in primary navigation in super admin
|
|
resources :account_users, only: [:new, :create, :show, :destroy]
|
|
end
|
|
authenticated :super_admin do
|
|
mount Sidekiq::Web => '/monitoring/sidekiq'
|
|
end
|
|
end
|
|
|
|
namespace :installation do
|
|
get 'onboarding', to: 'onboarding#index'
|
|
post 'onboarding', to: 'onboarding#create'
|
|
end
|
|
|
|
# ---------------------------------------------------------------------
|
|
# Routes for swagger docs
|
|
get '/swagger/*path', to: 'swagger#respond'
|
|
get '/swagger', to: 'swagger#respond'
|
|
|
|
# ----------------------------------------------------------------------
|
|
# Routes for testing
|
|
resources :widget_tests, only: [:index] unless Rails.env.production?
|
|
end
|