From 22789e0201851a5eddfbfb339affecc74fd84cee Mon Sep 17 00:00:00 2001 From: Robin Ward <robin.ward@gmail.com> Date: Wed, 3 Jun 2020 14:45:23 -0400 Subject: [PATCH] New `bootstrap.json` endpoint for starting up Discourse Discourse needs a bunch of data preloaded before it can start up. Normally we throw blobs of this into the HTML document that is requested but in some cases that's awkward to retrieve. For example with Ember CLI you have a separate javascript application that needs to make its own HTML. This API endpoint returns a JSON object with all the data Discourse needs to bootstrap and start up. --- app/controllers/bootstrap_controller.rb | 29 ++++++++++++++++ app/helpers/application_helper.rb | 1 + config/routes.rb | 2 ++ spec/requests/bootstrap_controller_spec.rb | 40 ++++++++++++++++++++++ 4 files changed, 72 insertions(+) create mode 100644 app/controllers/bootstrap_controller.rb create mode 100644 spec/requests/bootstrap_controller_spec.rb diff --git a/app/controllers/bootstrap_controller.rb b/app/controllers/bootstrap_controller.rb new file mode 100644 index 00000000000..dca7007c586 --- /dev/null +++ b/app/controllers/bootstrap_controller.rb @@ -0,0 +1,29 @@ +# frozen_string_literal: true + +class BootstrapController < ApplicationController + include ApplicationHelper + include ActionView::Helpers::AssetUrlHelper + + # This endpoint allows us to produce the data required to start up Discourse via JSON API, + # so that you don't have to scrape the HTML for `data-*` payloads + def index + locale = script_asset_path("locales/#{I18n.locale}") + + preload_anonymous_data + if current_user + current_user.sync_notification_channel_position + preload_current_user_data + end + + bootstrap = { + theme_ids: theme_ids, + title: SiteSetting.title, + current_homepage: current_homepage, + locale_script: "#{Discourse.base_url}#{locale}", + setup_data: client_side_setup_data, + preloaded: @preloaded + } + + render_json_dump(bootstrap: bootstrap) + end +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 482b2477d3d..f6bda658a38 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -356,6 +356,7 @@ module ApplicationHelper end def loading_admin? + return false unless defined?(controller) controller.class.name.split("::").first == "Admin" end diff --git a/config/routes.rb b/config/routes.rb index 69ade71938a..e763252bc69 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -14,6 +14,8 @@ Discourse::Application.routes.draw do match "/404", to: "exceptions#not_found", via: [:get, :post] get "/404-body" => "exceptions#not_found_body" + get "/bootstrap" => "bootstrap#index" + post "webhooks/aws" => "webhooks#aws" post "webhooks/mailgun" => "webhooks#mailgun" post "webhooks/mailjet" => "webhooks#mailjet" diff --git a/spec/requests/bootstrap_controller_spec.rb b/spec/requests/bootstrap_controller_spec.rb new file mode 100644 index 00000000000..6495eb4d282 --- /dev/null +++ b/spec/requests/bootstrap_controller_spec.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true + +require 'rails_helper' + +describe BootstrapController do + + it "returns data as anonymous" do + get "/bootstrap.json" + expect(response.status).to eq(200) + + json = response.parsed_body + expect(json).to be_present + + bootstrap = json['bootstrap'] + expect(bootstrap).to be_present + expect(bootstrap['title']).to be_present + expect(bootstrap['setup_data']['base_url']).to eq(Discourse.base_url) + preloaded = bootstrap['preloaded'] + expect(preloaded['site']).to be_present + expect(preloaded['siteSettings']).to be_present + expect(preloaded['currentUser']).to be_blank + expect(preloaded['topicTrackingStates']).to be_blank + end + + it "returns user data when authenticated" do + user = Fabricate(:user) + sign_in(user) + get "/bootstrap.json" + expect(response.status).to eq(200) + + json = response.parsed_body + expect(json).to be_present + + bootstrap = json['bootstrap'] + preloaded = bootstrap['preloaded'] + expect(preloaded['currentUser']).to be_present + expect(preloaded['topicTrackingStates']).to be_present + end + +end