mirror of
https://github.com/codeninjasllc/discourse.git
synced 2025-02-17 04:01:29 -05:00
Allow ReadOnly to propogate up to the Ember app via Response Header
This commit is contained in:
parent
5b3f99aa50
commit
3a6efa25f0
8 changed files with 58 additions and 16 deletions
|
@ -1,13 +1,7 @@
|
|||
/**
|
||||
This mixin provides an 'ajax' method that can be used to perform ajax requests that
|
||||
respect Discourse paths and the run loop.
|
||||
|
||||
@class Discourse.Ajax
|
||||
@extends Ember.Mixin
|
||||
@namespace Discourse
|
||||
@module Discourse
|
||||
**/
|
||||
|
||||
var _trackView = false;
|
||||
|
||||
Discourse.Ajax = Em.Mixin.create({
|
||||
|
@ -56,8 +50,14 @@ Discourse.Ajax = Em.Mixin.create({
|
|||
args.headers['Discourse-Track-View'] = true;
|
||||
}
|
||||
|
||||
args.success = function(xhr) {
|
||||
Ember.run(null, resolve, xhr);
|
||||
args.success = function(data, textStatus, xhr) {
|
||||
if (xhr.getResponseHeader('Discourse-Readonly')) {
|
||||
Ember.run(function() {
|
||||
Discourse.Site.currentProp('isReadOnly', true);
|
||||
});
|
||||
}
|
||||
|
||||
Ember.run(null, resolve, data);
|
||||
};
|
||||
|
||||
args.error = function(xhr, textStatus) {
|
||||
|
|
|
@ -42,6 +42,7 @@ class ApplicationController < ActionController::Base
|
|||
before_filter :preload_json
|
||||
before_filter :check_xhr
|
||||
before_filter :redirect_to_login_if_required
|
||||
after_filter :add_readonly_header
|
||||
|
||||
layout :set_layout
|
||||
|
||||
|
@ -53,6 +54,10 @@ class ApplicationController < ActionController::Base
|
|||
@use_crawler_layout ||= (has_escaped_fragment? || CrawlerDetection.crawler?(request.user_agent))
|
||||
end
|
||||
|
||||
def add_readonly_header
|
||||
response.headers['Discourse-Readonly'] = 'true' if Discourse.readonly_mode?
|
||||
end
|
||||
|
||||
def slow_platform?
|
||||
request.user_agent =~ /Android/
|
||||
end
|
||||
|
@ -394,7 +399,7 @@ class ApplicationController < ActionController::Base
|
|||
|
||||
def block_if_readonly_mode
|
||||
return if request.fullpath.start_with?(path "/admin/backups")
|
||||
raise Discourse::ReadOnly.new if !request.get? && Discourse.readonly_mode?
|
||||
raise Discourse::ReadOnly.new if !(request.get? || request.head?) && Discourse.readonly_mode?
|
||||
end
|
||||
|
||||
def build_not_found_page(status=404, layout=false)
|
||||
|
|
|
@ -613,7 +613,7 @@ en:
|
|||
logout: "You were logged out."
|
||||
refresh: "Refresh"
|
||||
read_only_mode:
|
||||
enabled: "An administrator enabled read-only mode. You can continue to browse the site but interactions may not work."
|
||||
enabled: "Read-only mode is enabled. You can continue to browse the site but interactions may not work."
|
||||
login_disabled: "Login is disabled while the site is in read only mode."
|
||||
too_few_topics_notice: "Create at least 5 public topics and %{posts} public posts to get discussion started. New users cannot earn trust levels unless there's content for them to read. This message appears only to staff."
|
||||
|
||||
|
|
|
@ -191,7 +191,7 @@ module Discourse
|
|||
end
|
||||
|
||||
def self.readonly_mode?
|
||||
!!$redis.get(readonly_mode_key)
|
||||
DiscourseRedis.recently_readonly? || !!$redis.get(readonly_mode_key)
|
||||
end
|
||||
|
||||
def self.request_refresh!
|
||||
|
|
|
@ -4,6 +4,19 @@
|
|||
require_dependency 'cache'
|
||||
class DiscourseRedis
|
||||
|
||||
def self.recently_readonly?
|
||||
return false unless @last_read_only
|
||||
@last_read_only > 15.seconds.ago
|
||||
end
|
||||
|
||||
def self.received_readonly!
|
||||
@last_read_only = Time.now
|
||||
end
|
||||
|
||||
def self.clear_readonly!
|
||||
@last_read_only = nil
|
||||
end
|
||||
|
||||
def self.raw_connection(config = nil)
|
||||
config ||= self.config
|
||||
redis_opts = {host: config['host'], port: config['port'], db: config['db']}
|
||||
|
@ -38,7 +51,10 @@ class DiscourseRedis
|
|||
yield
|
||||
rescue Redis::CommandError => ex
|
||||
if ex.message =~ /READONLY/
|
||||
STDERR.puts "WARN: Redis is in a readonly state. Performed a noop"
|
||||
unless DiscourseRedis.recently_readonly?
|
||||
STDERR.puts "WARN: Redis is in a readonly state. Performed a noop"
|
||||
end
|
||||
DiscourseRedis.received_readonly!
|
||||
else
|
||||
raise ex
|
||||
end
|
||||
|
|
|
@ -107,16 +107,23 @@ describe Discourse do
|
|||
|
||||
context "#readonly_mode?" do
|
||||
|
||||
after do
|
||||
DiscourseRedis.clear_readonly!
|
||||
end
|
||||
|
||||
it "is false by default" do
|
||||
expect(Discourse.readonly_mode?).to eq(false)
|
||||
end
|
||||
|
||||
it "returns true when the key is present in redis" do
|
||||
$redis.expects(:get).with(Discourse.readonly_mode_key).returns("1")
|
||||
expect(Discourse.readonly_mode?).to eq(true)
|
||||
end
|
||||
|
||||
it "returns false when the key is not present in redis" do
|
||||
$redis.expects(:get).with(Discourse.readonly_mode_key).returns(nil)
|
||||
expect(Discourse.readonly_mode?).to eq(false)
|
||||
it "returns true when DiscourseRedis is recently read only" do
|
||||
DiscourseRedis.received_readonly!
|
||||
expect(Discourse.readonly_mode?).to eq(true)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
context "#handle_exception" do
|
||||
|
|
|
@ -107,6 +107,18 @@ describe TopicsController do
|
|||
end
|
||||
end
|
||||
|
||||
describe "read only header" do
|
||||
it "returns no read only header by default" do
|
||||
get :show, {topic_id: topic.id}
|
||||
expect(response.headers['Discourse-Readonly']).to eq(nil)
|
||||
end
|
||||
|
||||
it "returns a readonly header if the site is read only" do
|
||||
DiscourseRedis.received_readonly!
|
||||
get :show, {topic_id: topic.id}
|
||||
expect(response.headers['Discourse-Readonly']).to eq('true')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'api' do
|
||||
|
|
|
@ -113,6 +113,8 @@ Spork.prefork do
|
|||
# very expensive IO operations
|
||||
SiteSetting.automatically_download_gravatars = false
|
||||
|
||||
DiscourseRedis.clear_readonly!
|
||||
|
||||
I18n.locale = :en
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in a new issue