diff --git a/app/controllers/api/v1/accounts/articles_controller.rb b/app/controllers/api/v1/accounts/articles_controller.rb index 4a8363fdd..439ba3e31 100644 --- a/app/controllers/api/v1/accounts/articles_controller.rb +++ b/app/controllers/api/v1/accounts/articles_controller.rb @@ -30,8 +30,8 @@ class Api::V1::Accounts::ArticlesController < Api::V1::Accounts::BaseController end def update - @article.update!(article_params) if params[:article].present? - render json: { error: @article.errors.messages }, status: :unprocessable_entity and return unless @article.valid? + persist_article_changes if params[:article].present? + render json: { message: @article.errors.full_messages.to_sentence }, status: :unprocessable_entity and return unless @article.valid? end def destroy @@ -67,12 +67,26 @@ class Api::V1::Accounts::ArticlesController < Api::V1::Accounts::BaseController @portal ||= Current.account.portals.find_by!(slug: params[:portal_id]) end + # Draft-only autosaves must not bump the public-facing updated_at, so write + # them with update_columns (which skips the timestamp). update_columns also + # skips validations, so assign and validate first to avoid persisting content + # that exceeds the column length limit. + def persist_article_changes + keys = article_params.to_h.keys + if keys.any? && (keys - %w[draft_title draft_content]).empty? + @article.assign_attributes(article_params) + @article.update_columns(article_params.to_h) if @article.valid? # rubocop:disable Rails/SkipsModelValidations + else + @article.update!(article_params) + end + end + def article_params params.require(:article).permit( :title, :slug, :position, :content, :description, :category_id, :author_id, :associated_article_id, :status, - :locale, meta: [:title, - :description, - { tags: [] }] + :locale, :draft_title, :draft_content, meta: [:title, + :description, + { tags: [] }] ) end diff --git a/app/controllers/api/v1/accounts/base_controller.rb b/app/controllers/api/v1/accounts/base_controller.rb index e30effc59..f08b87e60 100644 --- a/app/controllers/api/v1/accounts/base_controller.rb +++ b/app/controllers/api/v1/accounts/base_controller.rb @@ -2,5 +2,14 @@ class Api::V1::Accounts::BaseController < Api::BaseController include SwitchLocale include EnsureCurrentAccountHelper before_action :current_account + before_action :validate_token_api_access, if: :authenticate_by_access_token? around_action :switch_locale_using_account_locale + + private + + def validate_token_api_access + return if Current.account.api_and_webhooks_enabled? + + render json: { error: 'API access is not enabled for this account' }, status: :forbidden + end end diff --git a/app/controllers/api/v1/accounts/dashboard_apps_controller.rb b/app/controllers/api/v1/accounts/dashboard_apps_controller.rb index a8d7ebcb9..4226db1cc 100644 --- a/app/controllers/api/v1/accounts/dashboard_apps_controller.rb +++ b/app/controllers/api/v1/accounts/dashboard_apps_controller.rb @@ -1,4 +1,5 @@ class Api::V1::Accounts::DashboardAppsController < Api::V1::Accounts::BaseController + before_action :check_authorization before_action :fetch_dashboard_apps, except: [:create] before_action :fetch_dashboard_app, only: [:show, :update, :destroy] diff --git a/app/controllers/api/v1/accounts/whatsapp/authorizations_controller.rb b/app/controllers/api/v1/accounts/whatsapp/authorizations_controller.rb index db94113d9..580ae77c6 100644 --- a/app/controllers/api/v1/accounts/whatsapp/authorizations_controller.rb +++ b/app/controllers/api/v1/accounts/whatsapp/authorizations_controller.rb @@ -1,4 +1,6 @@ class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts::BaseController + # Reconfiguring/reauthorizing a live inbox swaps its credentials, so restrict it to admins. + before_action :check_admin_authorization?, if: -> { params[:inbox_id].present? } before_action :fetch_and_validate_inbox, if: -> { params[:inbox_id].present? } # POST /api/v1/accounts/:account_id/whatsapp/authorization @@ -31,7 +33,7 @@ class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts: end def validate_reauthorization_required - return if @inbox.channel.reauthorization_required? || can_upgrade_to_embedded_signup? + return if @inbox.channel.reauthorization_required? || can_reconfigure_channel? render json: { success: false, @@ -39,10 +41,13 @@ class Api::V1::Accounts::Whatsapp::AuthorizationsController < Api::V1::Accounts: }, status: :unprocessable_entity end - def can_upgrade_to_embedded_signup? + def can_reconfigure_channel? channel = @inbox.channel return false unless channel.provider == 'whatsapp_cloud' + # Reconfiguring a live embedded-signup channel requires the feature flag. + return Current.account.feature_enabled?('whatsapp_reconfigure') if channel.provider_config['source'] == 'embedded_signup' + true end diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb index fb991949a..9438a1660 100644 --- a/app/controllers/api/v1/accounts_controller.rb +++ b/app/controllers/api/v1/accounts_controller.rb @@ -8,6 +8,7 @@ class Api::V1::AccountsController < Api::BaseController before_action :ensure_account_name, only: [:create] before_action :validate_captcha, only: [:create] before_action :fetch_account, except: [:create] + before_action :validate_token_api_access, if: :authenticate_by_access_token?, except: [:create] before_action :check_authorization, except: [:create] rescue_from CustomExceptions::Account::InvalidEmail, @@ -105,6 +106,12 @@ class Api::V1::AccountsController < Api::BaseController @current_account_user = @account.account_users.find_by(user_id: current_user.id) end + def validate_token_api_access + return if @account.api_and_webhooks_enabled? + + render json: { error: 'API access is not enabled for this account' }, status: :forbidden + end + def account_params params.permit(:account_name, :email, :name, :password, :locale, :domain, :support_email, :user_full_name) end diff --git a/app/javascript/dashboard/components-next/HelpCenter/ArticleCard/ArticleCard.vue b/app/javascript/dashboard/components-next/HelpCenter/ArticleCard/ArticleCard.vue index 564888f0d..4d0cd0c71 100644 --- a/app/javascript/dashboard/components-next/HelpCenter/ArticleCard/ArticleCard.vue +++ b/app/javascript/dashboard/components-next/HelpCenter/ArticleCard/ArticleCard.vue @@ -1,5 +1,5 @@ + + diff --git a/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditor.vue b/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditor.vue index 59c710a37..6540b6460 100644 --- a/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditor.vue +++ b/app/javascript/dashboard/components-next/HelpCenter/Pages/ArticleEditorPage/ArticleEditor.vue @@ -1,6 +1,6 @@