diff --git a/app/controllers/static_controller.rb b/app/controllers/static_controller.rb index 63064c7e70f..20617146cf0 100644 --- a/app/controllers/static_controller.rb +++ b/app/controllers/static_controller.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true class StaticController < ApplicationController - skip_before_action :check_xhr, :redirect_to_login_if_required skip_before_action :verify_authenticity_token, only: [:brotli_asset, :cdn_asset, :enter, :favicon, :service_worker_asset] skip_before_action :preload_json, only: [:brotli_asset, :cdn_asset, :enter, :favicon, :service_worker_asset] @@ -11,24 +10,26 @@ class StaticController < ApplicationController PAGES_WITH_EMAIL_PARAM = ['login', 'password_reset', 'signup'] MODAL_PAGES = ['password_reset', 'signup'] + DEFAULT_PAGES = { + "faq" => { redirect: "faq_url", topic_id: "guidelines_topic_id" }, + "tos" => { redirect: "tos_url", topic_id: "tos_topic_id" }, + "privacy" => { redirect: "privacy_policy_url", topic_id: "privacy_topic_id" }, + } + CUSTOM_PAGES = {} # Add via `#add_topic_static_page` in plugin API def show return redirect_to(path '/') if current_user && (params[:id] == 'login' || params[:id] == 'signup') + if SiteSetting.login_required? && current_user.nil? && ['faq', 'guidelines'].include?(params[:id]) return redirect_to path('/login') end - map = { - "faq" => { redirect: "faq_url", topic_id: "guidelines_topic_id" }, - "tos" => { redirect: "tos_url", topic_id: "tos_topic_id" }, - "privacy" => { redirect: "privacy_policy_url", topic_id: "privacy_topic_id" } - } - + map = DEFAULT_PAGES.deep_merge(CUSTOM_PAGES) @page = params[:id] if map.has_key?(@page) site_setting_key = map[@page][:redirect] - url = SiteSetting.get(site_setting_key) + url = SiteSetting.get(site_setting_key) if site_setting_key return redirect_to(url) if url.present? end @@ -39,8 +40,12 @@ class StaticController < ApplicationController @page = @page.gsub(/[^a-z0-9\_\-]/, '') if map.has_key?(@page) - @topic = Topic.find_by_id(SiteSetting.get(map[@page][:topic_id])) + topic_id = map[@page][:topic_id] + topic_id = instance_exec(&topic_id) if topic_id.is_a?(Proc) + + @topic = Topic.find_by_id(SiteSetting.get(topic_id)) raise Discourse::NotFound unless @topic + title_prefix = if I18n.exists?("js.#{@page}") I18n.t("js.#{@page}") else @@ -48,17 +53,16 @@ class StaticController < ApplicationController end @title = "#{title_prefix} - #{SiteSetting.title}" @body = @topic.posts.first.cooked - @faq_overriden = !SiteSetting.faq_url.blank? + @faq_overridden = !SiteSetting.faq_url.blank? + render :show, layout: !request.xhr?, formats: [:html] return end - unless @title.present? - @title = if SiteSetting.short_site_description.present? - "#{SiteSetting.title} - #{SiteSetting.short_site_description}" - else - SiteSetting.title - end + @title = SiteSetting.title + + if SiteSetting.short_site_description.present? + @title << " - #{SiteSetting.short_site_description}" end if I18n.exists?("static.#{@page}") diff --git a/app/views/static/show.html.erb b/app/views/static/show.html.erb index b8a325f6617..b82fff8fa3b 100644 --- a/app/views/static/show.html.erb +++ b/app/views/static/show.html.erb @@ -3,7 +3,7 @@ <ul class='nav-pills' role='navigation' itemscope itemtype='http://schema.org/SiteNavigationElement'> <% unless SiteSetting.login_required? && current_user.nil? %> <li class="nav-item-about"><%= link_to t('js.about.simple_title'), about_index_path %></a></li> - <% if @faq_overriden %> + <% if @faq_overridden %> <li class='nav-item-guidelines'><a class='<%= @page == 'faq' ? 'active' : '' %>' href='<%= guidelines_path %>'><%= t 'js.guidelines' %></a></li> <li class='nav-item-faq'><a href='<%= faq_path %>'><%= t 'js.faq' %></a></li> <% else %> diff --git a/lib/plugin/instance.rb b/lib/plugin/instance.rb index ba526f4631e..1e9526aceda 100644 --- a/lib/plugin/instance.rb +++ b/lib/plugin/instance.rb @@ -994,6 +994,22 @@ class Plugin::Instance DiscoursePluginRegistry.register_notification_consolidation_plan(plan, self) end + # Allows customizing existing topic-backed static pages, like: + # faq, tos, privacy (see: StaticController) The block passed to this + # method has to return a SiteSetting name that contains a topic id. + # + # add_topic_static_page("faq") do |controller| + # current_user&.locale == "pl" ? "polish_faq_topic_id" : "faq_topic_id" + # end + # + # You can also add new pages in a plugin, but remember to add a route, + # for example: + # + # get "contact" => "static#show", id: "contact" + def add_topic_static_page(page, options = {}, &blk) + StaticController::CUSTOM_PAGES[page] = blk ? { topic_id: blk } : options + end + protected def self.js_path diff --git a/spec/requests/static_controller_spec.rb b/spec/requests/static_controller_spec.rb index 3156b2a7ab1..31b4928f5c6 100644 --- a/spec/requests/static_controller_spec.rb +++ b/spec/requests/static_controller_spec.rb @@ -277,6 +277,52 @@ describe StaticController do expect(response.body).to include("<title>FAQ - Discourse</title>") end end + + context "plugin api extensions" do + after do + Rails.application.reload_routes! + StaticController::CUSTOM_PAGES.clear + end + + it "adds new topic-backed pages" do + routes = Proc.new do + get "contact" => "static#show", id: "contact" + end + Discourse::Application.routes.send(:eval_block, routes) + + topic_id = Fabricate(:post, cooked: "contact info").topic_id + SiteSetting.setting(:contact_topic_id, topic_id) + + Plugin::Instance.new.add_topic_static_page("contact", topic_id: "contact_topic_id") + + get "/contact" + + expect(response.status).to eq(200) + expect(response.body).to include("contact info") + end + + it "replaces existing topic-backed pages" do + topic_id = Fabricate(:post, cooked: "Regular FAQ").topic_id + SiteSetting.setting(:faq_topic_id, topic_id) + polish_topic_id = Fabricate(:post, cooked: "Polish FAQ").topic_id + SiteSetting.setting(:polish_faq_topic_id, polish_topic_id) + + Plugin::Instance.new.add_topic_static_page("faq") do + current_user&.locale == "pl" ? "polish_faq_topic_id" : "faq_topic_id" + end + + get "/faq" + + expect(response.status).to eq(200) + expect(response.body).to include("Regular FAQ") + + sign_in(Fabricate(:user, locale: "pl")) + get "/faq" + + expect(response.status).to eq(200) + expect(response.body).to include("Polish FAQ") + end + end end describe '#enter' do