From f5af4768eb86917042b95286096bc9939080d65b Mon Sep 17 00:00:00 2001 From: Sam Date: Mon, 9 Mar 2015 11:45:36 +1100 Subject: [PATCH] FEATURE: add clean support for running Discourse in a subfolder To setup set DISCOURSE_RELATIVE_URL_ROOT to the folder you wish --- app/assets/javascripts/discourse.js | 10 ++++++++++ .../discourse/initializers/live-development.js.es6 | 2 +- .../javascripts/discourse/lib/highlight-syntax.js.es6 | 2 +- app/assets/javascripts/discourse/lib/lightbox.js.es6 | 2 +- .../javascripts/discourse/routes/discourse_location.js | 4 ++++ .../javascripts/discourse/routes/discourse_route.js | 6 ++++++ app/controllers/application_controller.rb | 10 +++++++--- app/controllers/categories_controller.rb | 2 +- app/controllers/forums_controller.rb | 2 +- app/controllers/invites_controller.rb | 10 +++++----- app/controllers/session_controller.rb | 10 +++++----- app/controllers/static_controller.rb | 6 ++++-- app/controllers/user_avatars_controller.rb | 2 +- app/controllers/users_controller.rb | 2 +- app/helpers/application_helper.rb | 4 ++++ app/views/application/_header.html.erb | 2 +- app/views/categories/index.html.erb | 2 +- app/views/exceptions/not_found.html.erb | 4 ++-- app/views/layouts/crawler.html.erb | 2 +- app/views/users/activate_account.html.erb | 2 +- app/views/users/password_reset.html.erb | 2 +- app/views/users/perform_account_activation.html.erb | 2 +- config/application.rb | 4 ++++ config/discourse_defaults.conf | 5 +++++ config/initializers/logster.rb | 3 +++ lib/middleware/turbo_dev.rb | 5 +++-- lib/sass/discourse_stylesheets.rb | 8 ++++++-- 27 files changed, 81 insertions(+), 34 deletions(-) diff --git a/app/assets/javascripts/discourse.js b/app/assets/javascripts/discourse.js index f72cb294275..37a49d8d9ca 100644 --- a/app/assets/javascripts/discourse.js +++ b/app/assets/javascripts/discourse.js @@ -5,6 +5,10 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, { rootElement: '#main', _docTitle: document.title, + script: function(url) { + return $LAB.script(this.getURL(url)); + }, + getURL: function(url) { if (!url) { return url; } @@ -16,6 +20,12 @@ window.Discourse = Ember.Application.createWithMixins(Discourse.Ajax, { u = u.substring(0, u.length-1); } if (url.indexOf(u) !== -1) return url; + + if(u.length > 0 && url[0] !== "/") { + // we got to root this + url = "/" + url; + } + return u + url; }, diff --git a/app/assets/javascripts/discourse/initializers/live-development.js.es6 b/app/assets/javascripts/discourse/initializers/live-development.js.es6 index df4b54c356b..fbfd5b7918c 100644 --- a/app/assets/javascripts/discourse/initializers/live-development.js.es6 +++ b/app/assets/javascripts/discourse/initializers/live-development.js.es6 @@ -41,7 +41,7 @@ export default { // Reload handlebars var js = me.name.replace(".hbs", "").replace("app/assets/javascripts", "/assets"); - $LAB.script(js + "?hash=" + me.hash).wait(function() { + Discourse.script(js + "?hash=" + me.hash).wait(function() { var templateName; templateName = js.replace(".js", "").replace("/assets/", ""); return _.each(Ember.View.views, function(view) { diff --git a/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 b/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 index 784add9d223..6308a252659 100644 --- a/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 +++ b/app/assets/javascripts/discourse/lib/highlight-syntax.js.es6 @@ -3,7 +3,7 @@ export default function highlightSyntax($elem) { const selector = Discourse.SiteSettings.autohighlight_all_code ? 'pre code' : 'pre code[class]'; $(selector, $elem).each(function(i, e) { - return $LAB.script("/javascripts/highlight.pack.js").wait(function() { + return Discourse.script("/javascripts/highlight.pack.js").wait(function() { return hljs.highlightBlock(e); }); }); diff --git a/app/assets/javascripts/discourse/lib/lightbox.js.es6 b/app/assets/javascripts/discourse/lib/lightbox.js.es6 index b5f272180a8..a705ddf07ee 100644 --- a/app/assets/javascripts/discourse/lib/lightbox.js.es6 +++ b/app/assets/javascripts/discourse/lib/lightbox.js.es6 @@ -1,6 +1,6 @@ export default function($elem) { $("a.lightbox", $elem).each(function(i, e) { - $LAB.script("/javascripts/jquery.magnific-popup-min.js").wait(function() { + Discourse.script("/javascripts/jquery.magnific-popup-min.js").wait(function() { var $e = $(e); // do not lightbox spoiled images if ($e.parents(".spoiler").length > 0 || $e.parents(".spoiled").length > 0) { return; } diff --git a/app/assets/javascripts/discourse/routes/discourse_location.js b/app/assets/javascripts/discourse/routes/discourse_location.js index b939e6c9539..22fcc3c80cf 100644 --- a/app/assets/javascripts/discourse/routes/discourse_location.js +++ b/app/assets/javascripts/discourse/routes/discourse_location.js @@ -204,6 +204,10 @@ Ember.DiscourseLocation = Ember.Object.extend({ if (url !== '') { rootURL = rootURL.replace(/\/$/, ''); + + if (rootURL.length > 0 && url.indexOf(rootURL + "/") === 0){ + rootURL = ""; + } } return rootURL + url; diff --git a/app/assets/javascripts/discourse/routes/discourse_route.js b/app/assets/javascripts/discourse/routes/discourse_route.js index 926c457ea7b..17c3579436e 100644 --- a/app/assets/javascripts/discourse/routes/discourse_route.js +++ b/app/assets/javascripts/discourse/routes/discourse_route.js @@ -113,6 +113,12 @@ Discourse.Route.reopenClass({ } }); + if (Discourse.BaseUri) { + Discourse.Router.reopen({ + rootURL: Discourse.BaseUri + "/" + }); + } + Discourse.Router.map(function() { var router = this; diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d36718044c2..0b7308ed570 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -88,7 +88,7 @@ class ApplicationController < ActionController::Base if (request.format && request.format.json?) || request.xhr? || !request.get? rescue_discourse_actions(:not_logged_in, 403, true) else - redirect_to "/" + redirect_to path("/") end end @@ -379,7 +379,7 @@ class ApplicationController < ActionController::Base # redirect user to the SSO page if we need to log in AND SSO is enabled if SiteSetting.login_required? if SiteSetting.enable_sso? - redirect_to '/session/sso' + redirect_to path('/session/sso') else redirect_to :login end @@ -387,7 +387,7 @@ class ApplicationController < ActionController::Base end def block_if_readonly_mode - return if request.fullpath.start_with?("/admin/backups") + return if request.fullpath.start_with?(path "/admin/backups") raise Discourse::ReadOnly.new if !request.get? && Discourse.readonly_mode? end @@ -404,6 +404,10 @@ class ApplicationController < ActionController::Base protected + def path(p) + "#{GlobalSetting.relative_url_root}#{p}" + end + def render_post_json(post, add_raw=true) post_serializer = PostSerializer.new(post, scope: guardian, root: false) post_serializer.add_raw = add_raw diff --git a/app/controllers/categories_controller.rb b/app/controllers/categories_controller.rb index c93ad37ab07..74219e7d995 100644 --- a/app/controllers/categories_controller.rb +++ b/app/controllers/categories_controller.rb @@ -7,7 +7,7 @@ class CategoriesController < ApplicationController skip_before_filter :check_xhr, only: [:index, :redirect] def redirect - redirect_to "/c/#{params[:path]}" + redirect_to path("/c/#{params[:path]}") end def index diff --git a/app/controllers/forums_controller.rb b/app/controllers/forums_controller.rb index 505f98a2ff4..ea80a017fe5 100644 --- a/app/controllers/forums_controller.rb +++ b/app/controllers/forums_controller.rb @@ -17,7 +17,7 @@ class ForumsController < ApplicationController end def home_redirect - redirect_to '/' + redirect_to path('/') end end diff --git a/app/controllers/invites_controller.rb b/app/controllers/invites_controller.rb index c5289ce4316..6756e4a2f51 100644 --- a/app/controllers/invites_controller.rb +++ b/app/controllers/invites_controller.rb @@ -19,13 +19,13 @@ class InvitesController < ApplicationController topic = invite.topics.first if topic.present? - redirect_to "#{Discourse.base_uri}#{topic.relative_url}" + redirect_to path("#{topic.relative_url}") return end end end - redirect_to "/" + redirect_to path("/") end def create @@ -40,7 +40,7 @@ class InvitesController < ApplicationController guardian.ensure_can_send_multiple_invites!(current_user) end - if Invite.invite_by_email(params[:email], current_user, topic=nil, group_ids) + if Invite.invite_by_email(params[:email], current_user, _topic=nil, group_ids) render json: success_json else render json: failed_json, status: 422 @@ -77,13 +77,13 @@ class InvitesController < ApplicationController topic = invite.topics.first if topic.present? - redirect_to "#{Discourse.base_uri}#{topic.relative_url}" + redirect_to path("#{topic.relative_url}") return end end end - redirect_to "/" + redirect_to path("/") end def destroy diff --git a/app/controllers/session_controller.rb b/app/controllers/session_controller.rb index 6a1317cb75f..00dbbe1d74b 100644 --- a/app/controllers/session_controller.rb +++ b/app/controllers/session_controller.rb @@ -12,7 +12,7 @@ class SessionController < ApplicationController def sso if SiteSetting.enable_sso - redirect_to DiscourseSingleSignOn.generate_url(params[:return_path] || '/') + redirect_to DiscourseSingleSignOn.generate_url(params[:return_path] || path('/')) else render nothing: true, status: 404 end @@ -32,7 +32,7 @@ class SessionController < ApplicationController redirect_to sso.to_url(sso.return_sso_url) else session[:sso_payload] = request.query_string - redirect_to '/login' + redirect_to path('/login') end else render nothing: true, status: 404 @@ -47,7 +47,7 @@ class SessionController < ApplicationController raise "User #{params[:session_id]} not found" if user.blank? log_on_user(user) - redirect_to "/" + redirect_to path("/") end def sso_login @@ -80,9 +80,9 @@ class SessionController < ApplicationController if return_path !~ /^\/[^\/]/ begin uri = URI(return_path) - return_path = "/" unless uri.host == Discourse.current_hostname + return_path = path("/") unless uri.host == Discourse.current_hostname rescue - return_path = "/" + return_path = path("/") end end diff --git a/app/controllers/static_controller.rb b/app/controllers/static_controller.rb index 0b1bd1baa1a..532cb168b83 100644 --- a/app/controllers/static_controller.rb +++ b/app/controllers/static_controller.rb @@ -4,7 +4,7 @@ class StaticController < ApplicationController skip_before_filter :verify_authenticity_token, only: [:enter] def show - return redirect_to('/') if current_user && params[:id] == 'login' + return redirect_to(path '/') if current_user && params[:id] == 'login' map = { "faq" => {redirect: "faq_url", topic_id: "guidelines_topic_id"}, @@ -60,15 +60,17 @@ class StaticController < ApplicationController params.delete(:username) params.delete(:password) - destination = "/" + destination = path("/") if params[:redirect].present? && !params[:redirect].match(login_path) begin forum_uri = URI(Discourse.base_url) uri = URI(params[:redirect]) + if uri.path.present? && (uri.host.blank? || uri.host == forum_uri.host) && uri.path !~ /\./ + destination = uri.path end rescue URI::InvalidURIError diff --git a/app/controllers/user_avatars_controller.rb b/app/controllers/user_avatars_controller.rb index 919be6db10b..b8f1a34923b 100644 --- a/app/controllers/user_avatars_controller.rb +++ b/app/controllers/user_avatars_controller.rb @@ -58,7 +58,7 @@ class UserAvatarsController < ApplicationController upload ||= user.uploaded_avatar if user.uploaded_avatar_id == version if user.uploaded_avatar && !upload - return redirect_to "/user_avatar/#{hostname}/#{user.username_lower}/#{size}/#{user.uploaded_avatar_id}.png" + return redirect_to path("/user_avatar/#{hostname}/#{user.username_lower}/#{size}/#{user.uploaded_avatar_id}.png") elsif upload original = Discourse.store.path_for(upload) if Discourse.store.external? || File.exists?(original) diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 5673c3298d4..98b4e3911be 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -142,7 +142,7 @@ class UsersController < ApplicationController def my_redirect if current_user.present? && params[:path] =~ /^[a-z\-\/]+$/ - redirect_to "/users/#{current_user.username}/#{params[:path]}" + redirect_to path("/users/#{current_user.username}/#{params[:path]}") return end raise Discourse::NotFound.new diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 59c8bbb7f5c..b910470d4d7 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -23,6 +23,10 @@ module ApplicationHelper end end + def path(path) + "#{GlobalSetting.relative_url_root}#{path}" + end + def script(*args) if SiteSetting.enable_cdn_js_debugging && GlobalSetting.cdn_url tags = javascript_include_tag(*args, "crossorigin" => "anonymous") diff --git a/app/views/application/_header.html.erb b/app/views/application/_header.html.erb index d0f3c8b39fc..ddcb6da88fd 100644 --- a/app/views/application/_header.html.erb +++ b/app/views/application/_header.html.erb @@ -13,7 +13,7 @@ <% unless current_user %>
- <%= I18n.t('log_in') %> + " class='btn btn-primary btn-small'><%= I18n.t('log_in') %>
<% end %> diff --git a/app/views/categories/index.html.erb b/app/views/categories/index.html.erb index ad9266aa138..2b189514a6e 100644 --- a/app/views/categories/index.html.erb +++ b/app/views/categories/index.html.erb @@ -1,6 +1,6 @@ <% @list.categories.each do |c| %>
-

<%= c.name %>

+

"><%= c.name %>

<%- if c.displayable_topics.present? %> <% c.displayable_topics.each do |t| %> diff --git a/app/views/exceptions/not_found.html.erb b/app/views/exceptions/not_found.html.erb index 47ab572429d..c7030dec488 100644 --- a/app/views/exceptions/not_found.html.erb +++ b/app/views/exceptions/not_found.html.erb @@ -11,7 +11,7 @@
<% end %>
- <%= t 'page_not_found.see_more' %>… + " class="btn"><%= t 'page_not_found.see_more' %>…

<%= t 'page_not_found.recent_topics' %>

@@ -21,7 +21,7 @@
<% end %>
- <%= t 'page_not_found.see_more' %>… + " class="btn"><%= t 'page_not_found.see_more' %>… diff --git a/app/views/layouts/crawler.html.erb b/app/views/layouts/crawler.html.erb index 9ef563c5544..c4d7dc14da8 100644 --- a/app/views/layouts/crawler.html.erb +++ b/app/views/layouts/crawler.html.erb @@ -19,7 +19,7 @@ <%= SiteCustomization.custom_header(session[:preview_style]) %> <%- end %>
- + ">
<%= yield %> diff --git a/app/views/users/activate_account.html.erb b/app/views/users/activate_account.html.erb index 3d33bb8270f..c0c1ab5287c 100644 --- a/app/views/users/activate_account.html.erb +++ b/app/views/users/activate_account.html.erb @@ -17,7 +17,7 @@ (function() { function activateAccount() { $('#activate-account-button').prop('disabled', true); - $.ajax("/users/hp").then(function(hp) { + $.ajax("<%= path "/users/hp" %>").then(function(hp) { $('#password_confirmation').val(hp.value); $('#challenge').val(hp.challenge.split("").reverse().join("")); $('#activate-account-form').submit(); diff --git a/app/views/users/password_reset.html.erb b/app/views/users/password_reset.html.erb index dd77729fecf..585d2c8dd6b 100644 --- a/app/views/users/password_reset.html.erb +++ b/app/views/users/password_reset.html.erb @@ -20,7 +20,7 @@ <% else %>

- <%= t('password_reset.continue', site_name: SiteSetting.title) %> + "><%= t('password_reset.continue', site_name: SiteSetting.title) %> <% end %>

<% else %> diff --git a/app/views/users/perform_account_activation.html.erb b/app/views/users/perform_account_activation.html.erb index 7424cf6243a..09d66b2224f 100644 --- a/app/views/users/perform_account_activation.html.erb +++ b/app/views/users/perform_account_activation.html.erb @@ -12,7 +12,7 @@

<%= t 'activation.approval_required' %>

<% else %>

<%= t('activation.please_continue') %>

-

<%= t('activation.continue_button', site_name: SiteSetting.title) -%>

+

"><%= t('activation.continue_button', site_name: SiteSetting.title) -%>

<%= render partial: 'auto_redirect_home' %> <% end %> <%end%> diff --git a/config/application.rb b/config/application.rb index 8124238a788..193810ffcfc 100644 --- a/config/application.rb +++ b/config/application.rb @@ -156,6 +156,10 @@ module Discourse require 'auth' Discourse.activate_plugins! unless Rails.env.test? and ENV['LOAD_PLUGINS'] != "1" + if GlobalSetting.relative_url_root.present? + config.relative_url_root = GlobalSetting.relative_url_root + end + config.after_initialize do # So open id logs somewhere sane OpenID::Util.logger = Rails.logger diff --git a/config/discourse_defaults.conf b/config/discourse_defaults.conf index 248aff6421b..299e91fc2fc 100644 --- a/config/discourse_defaults.conf +++ b/config/discourse_defaults.conf @@ -119,3 +119,8 @@ new_version_emails = true connection_reaper_age = 30 # run reap check every 30 seconds connection_reaper_interval = 30 + +# set to relative URL (for subdirectory hosting) +# IMPORTANT: path must not include a trailing / +# EG: /forum +relative_url_root = diff --git a/config/initializers/logster.rb b/config/initializers/logster.rb index 48abc05567e..525512ae208 100644 --- a/config/initializers/logster.rb +++ b/config/initializers/logster.rb @@ -49,3 +49,6 @@ Logster.config.current_context = lambda{|env,&blk| ActiveRecord::Base.connection_handler.clear_active_connections! end } + +# TODO logster should be able to do this automatically +Logster.config.subdirectory = "#{GlobalSetting.relative_url_root}/logs" diff --git a/lib/middleware/turbo_dev.rb b/lib/middleware/turbo_dev.rb index 03b3c575385..d3b7eb3e1b4 100644 --- a/lib/middleware/turbo_dev.rb +++ b/lib/middleware/turbo_dev.rb @@ -17,11 +17,12 @@ module Middleware end def call(env) - is_asset = (env['REQUEST_PATH'] =~ /^\/assets\//) + root = "#{GlobalSetting.relative_url_root}/assets/" + is_asset = env['REQUEST_PATH'] && env['REQUEST_PATH'].starts_with?(root) # hack to bypass all middleware if serving assets, a lot faster 4.5 seconds -> 1.5 seconds if (etag = env['HTTP_IF_NONE_MATCH']) && is_asset - name = $' + name = env['REQUEST_PATH'][(root.length)..-1] etag = etag.gsub "\"", "" asset = Rails.application.assets.find_asset(name) if asset && asset.digest == etag diff --git a/lib/sass/discourse_stylesheets.rb b/lib/sass/discourse_stylesheets.rb index 1ad84bc30e3..2b8195fcc22 100644 --- a/lib/sass/discourse_stylesheets.rb +++ b/lib/sass/discourse_stylesheets.rb @@ -114,12 +114,16 @@ class DiscourseStylesheets "#{GlobalSetting.cdn_url}#{stylesheet_relpath}?__ws=#{Discourse.current_hostname}" end + def root_path + "#{GlobalSetting.relative_url_root}/" + end + def stylesheet_relpath - "/#{CACHE_PATH}/#{stylesheet_filename}" + "#{root_path}#{CACHE_PATH}/#{stylesheet_filename}" end def stylesheet_relpath_no_digest - "/#{CACHE_PATH}/#{stylesheet_filename_no_digest}" + "#{root_path}#{CACHE_PATH}/#{stylesheet_filename_no_digest}" end def stylesheet_filename