mirror of
https://github.com/discourse/discourse.git
synced 2024-11-25 09:42:07 +08:00
readonly mode
This commit is contained in:
parent
faf03fdeb1
commit
e7472dc374
|
@ -8,8 +8,9 @@ Discourse.addInitializer(function() {
|
||||||
|
|
||||||
Discourse.MessageBus.alwaysLongPoll = Discourse.Environment === "development";
|
Discourse.MessageBus.alwaysLongPoll = Discourse.Environment === "development";
|
||||||
Discourse.MessageBus.start();
|
Discourse.MessageBus.start();
|
||||||
|
|
||||||
Discourse.MessageBus.subscribe("/global/asset-version", function(version){
|
Discourse.MessageBus.subscribe("/global/asset-version", function(version){
|
||||||
Discourse.set("assetVersion",version);
|
Discourse.set("assetVersion", version);
|
||||||
|
|
||||||
if(Discourse.get("requiresRefresh")) {
|
if(Discourse.get("requiresRefresh")) {
|
||||||
// since we can do this transparently for people browsing the forum
|
// since we can do this transparently for people browsing the forum
|
||||||
|
@ -24,5 +25,15 @@ Discourse.addInitializer(function() {
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Discourse.set("isReadOnly", Discourse.Site.currentProp("is_readonly"));
|
||||||
|
|
||||||
|
Discourse.MessageBus.subscribe("/global/read-only", function (enabled) {
|
||||||
|
Discourse.set("isReadOnly", enabled);
|
||||||
|
if (enabled) {
|
||||||
|
bootbox.alert(I18n.t("read_only_mode_enabled"));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus);
|
Discourse.KeyValueStore.init("discourse_", Discourse.MessageBus);
|
||||||
}, true);
|
}, true);
|
||||||
|
|
|
@ -29,7 +29,7 @@ class ApplicationController < ActionController::Base
|
||||||
before_filter :set_mobile_view
|
before_filter :set_mobile_view
|
||||||
before_filter :inject_preview_style
|
before_filter :inject_preview_style
|
||||||
before_filter :disable_customization
|
before_filter :disable_customization
|
||||||
before_filter :block_if_maintenance_mode
|
before_filter :block_if_readonly_mode
|
||||||
before_filter :authorize_mini_profiler
|
before_filter :authorize_mini_profiler
|
||||||
before_filter :store_incoming_links
|
before_filter :store_incoming_links
|
||||||
before_filter :preload_json
|
before_filter :preload_json
|
||||||
|
@ -50,7 +50,6 @@ class ApplicationController < ActionController::Base
|
||||||
raise
|
raise
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
# Some exceptions
|
# Some exceptions
|
||||||
class RenderEmpty < Exception; end
|
class RenderEmpty < Exception; end
|
||||||
|
|
||||||
|
@ -87,6 +86,11 @@ class ApplicationController < ActionController::Base
|
||||||
rescue_discourse_actions("[error: 'invalid access']", 403) # TODO: this breaks json responses
|
rescue_discourse_actions("[error: 'invalid access']", 403) # TODO: this breaks json responses
|
||||||
end
|
end
|
||||||
|
|
||||||
|
rescue_from Discourse::ReadOnly do
|
||||||
|
# can this happen on a not .json format?
|
||||||
|
render json: failed_json.merge(message: I18n.t("read_only_mode_enabled"))
|
||||||
|
end
|
||||||
|
|
||||||
def rescue_discourse_actions(message, error)
|
def rescue_discourse_actions(message, error)
|
||||||
if request.format && request.format.json?
|
if request.format && request.format.json?
|
||||||
# TODO: this doesn't make sense. Stuffing an html page into a json response will cause
|
# TODO: this doesn't make sense. Stuffing an html page into a json response will cause
|
||||||
|
@ -249,16 +253,6 @@ class ApplicationController < ActionController::Base
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def block_if_maintenance_mode
|
|
||||||
if Discourse.maintenance_mode?
|
|
||||||
if request.format.json?
|
|
||||||
render status: 503, json: failed_json.merge(message: I18n.t('site_under_maintenance'))
|
|
||||||
else
|
|
||||||
render status: 503, file: File.join( Rails.root, 'public', '503.html' ), layout: false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def mini_profiler_enabled?
|
def mini_profiler_enabled?
|
||||||
defined?(Rack::MiniProfiler) && current_user.try(:admin?)
|
defined?(Rack::MiniProfiler) && current_user.try(:admin?)
|
||||||
end
|
end
|
||||||
|
@ -288,6 +282,11 @@ class ApplicationController < ActionController::Base
|
||||||
redirect_to :login if SiteSetting.login_required?
|
redirect_to :login if SiteSetting.login_required?
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def block_if_readonly_mode
|
||||||
|
return if request.put? && request.fullpath == "/admin/backups/readonly"
|
||||||
|
raise Discourse::ReadOnly.new unless request.get? || !Discourse.readonly_mode?
|
||||||
|
end
|
||||||
|
|
||||||
def build_not_found_page(status=404, layout=false)
|
def build_not_found_page(status=404, layout=false)
|
||||||
@top_viewed = Topic.top_viewed(10)
|
@top_viewed = Topic.top_viewed(10)
|
||||||
@recent = Topic.recent(10)
|
@recent = Topic.recent(10)
|
||||||
|
|
|
@ -8,7 +8,8 @@ class SiteSerializer < ApplicationSerializer
|
||||||
:periods,
|
:periods,
|
||||||
:top_menu_items,
|
:top_menu_items,
|
||||||
:anonymous_top_menu_items,
|
:anonymous_top_menu_items,
|
||||||
:uncategorized_category_id # this is hidden so putting it here
|
:uncategorized_category_id, # this is hidden so putting it here
|
||||||
|
:is_readonly
|
||||||
|
|
||||||
has_many :categories, serializer: BasicCategorySerializer, embed: :objects
|
has_many :categories, serializer: BasicCategorySerializer, embed: :objects
|
||||||
has_many :post_action_types, embed: :objects
|
has_many :post_action_types, embed: :objects
|
||||||
|
@ -45,4 +46,8 @@ class SiteSerializer < ApplicationSerializer
|
||||||
SiteSetting.uncategorized_category_id
|
SiteSetting.uncategorized_category_id
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def is_readonly
|
||||||
|
Discourse.readonly_mode?
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -409,7 +409,9 @@ uncategorized:
|
||||||
summary_likes_required: 1
|
summary_likes_required: 1
|
||||||
summary_percent_filter: 20
|
summary_percent_filter: 20
|
||||||
send_welcome_message: true
|
send_welcome_message: true
|
||||||
allow_import: false
|
allow_import:
|
||||||
|
client: true
|
||||||
|
default: false
|
||||||
educate_until_posts:
|
educate_until_posts:
|
||||||
client: true
|
client: true
|
||||||
default: 2
|
default: 2
|
||||||
|
|
|
@ -27,6 +27,9 @@ module Discourse
|
||||||
|
|
||||||
class InvalidPost < Exception; end
|
class InvalidPost < Exception; end
|
||||||
|
|
||||||
|
# When read-only mode is enabled
|
||||||
|
class ReadOnly < Exception; end
|
||||||
|
|
||||||
# Cross site request forgery
|
# Cross site request forgery
|
||||||
class CSRF < Exception; end
|
class CSRF < Exception; end
|
||||||
|
|
||||||
|
@ -138,18 +141,20 @@ module Discourse
|
||||||
return base_url_no_prefix + base_uri
|
return base_url_no_prefix + base_uri
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.enable_maintenance_mode
|
def self.enable_readonly_mode
|
||||||
$redis.set maintenance_mode_key, 1
|
$redis.set readonly_mode_key, 1
|
||||||
|
MessageBus.publish(readonly_channel, true)
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.disable_maintenance_mode
|
def self.disable_readonly_mode
|
||||||
$redis.del maintenance_mode_key
|
$redis.del readonly_mode_key
|
||||||
|
MessageBus.publish(readonly_channel, false)
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.maintenance_mode?
|
def self.readonly_mode?
|
||||||
!!$redis.get( maintenance_mode_key )
|
!!$redis.get(readonly_mode_key)
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.git_version
|
def self.git_version
|
||||||
|
@ -198,9 +203,12 @@ module Discourse
|
||||||
Rails.configuration.action_controller.asset_host
|
Rails.configuration.action_controller.asset_host
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
def self.readonly_mode_key
|
||||||
|
"readonly_mode"
|
||||||
def self.maintenance_mode_key
|
|
||||||
'maintenance_mode'
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.readonly_channel
|
||||||
|
"/global/read-only"
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -82,5 +82,39 @@ describe Discourse do
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context "#enable_readonly_mode" do
|
||||||
|
|
||||||
|
it "adds a key in redis and publish a message through the message bus" do
|
||||||
|
$redis.expects(:set).with(Discourse.readonly_mode_key, 1)
|
||||||
|
MessageBus.expects(:publish).with(Discourse.readonly_channel, true)
|
||||||
|
Discourse.enable_readonly_mode
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context "#disable_readonly_mode" do
|
||||||
|
|
||||||
|
it "removes a key from redis and publish a message through the message bus" do
|
||||||
|
$redis.expects(:del).with(Discourse.readonly_mode_key)
|
||||||
|
MessageBus.expects(:publish).with(Discourse.readonly_channel, false)
|
||||||
|
Discourse.disable_readonly_mode
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
context "#readonly_mode?" do
|
||||||
|
|
||||||
|
it "returns true when the key is present in redis" do
|
||||||
|
$redis.expects(:get).with(Discourse.readonly_mode_key).returns("1")
|
||||||
|
Discourse.readonly_mode?.should == true
|
||||||
|
end
|
||||||
|
|
||||||
|
it "returns false when the key is not present in redis" do
|
||||||
|
$redis.expects(:get).with(Discourse.readonly_mode_key).returns(nil)
|
||||||
|
Discourse.readonly_mode?.should == false
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user