mirror of
https://github.com/discourse/discourse.git
synced 2025-10-03 17:21:20 +08:00
The reasons for these changes is https://meta.discourse.org/t/-/89605 broke and admins were not able to log back in if they had previously enabled the "read only" mode. Thus ensued a deep dive into how all the "read only" modes worked, which was made difficult due to the lack of tests. The "cornerstone" of this PR is the `read_only_mixin.rb` file which was improved to be able to differentiate between the "readonly" mode and the "staff writes only" mode. I then made use of the `allow_in_readonly_mode` and `allow_in_staff_writes_only_mode` method to **explicitely** list all the actions that should work in those modes. I also added the "readonly" mixin to the `WebhooksController` since it doesn't inherit from the `ApplicationController`. I improved the security of the `/u/admin-login` endpoint by always sending the same message no matter if we found or not an admin account with the provided email address. I added two system specs: 1. for ensuring that admins can log in via /u/admin-lgoin and then clicking the link in the email they received while the site is in readonly mode. 2. for ensuring the "staff writes only mode" is _actually_ tested by ensuring a moderator can log in and create a topic while the site is in that mode. Plenty of specs were updated to ensure 100% converage of the various "read only" modes.
67 lines
1.7 KiB
Ruby
67 lines
1.7 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module ReadOnlyMixin
|
|
module ClassMethods
|
|
def actions_allowed_in_readonly_mode
|
|
@actions_allowed_in_readonly_mode ||= []
|
|
end
|
|
|
|
def actions_allowed_in_staff_writes_only_mode
|
|
@actions_allowed_in_staff_writes_only_mode ||= []
|
|
end
|
|
|
|
def allow_in_readonly_mode(*actions)
|
|
actions_allowed_in_readonly_mode.concat(actions.map(&:to_sym))
|
|
end
|
|
|
|
def allow_in_staff_writes_only_mode(*actions)
|
|
actions_allowed_in_staff_writes_only_mode.concat(actions.map(&:to_sym))
|
|
end
|
|
|
|
def allowed_in_readonly_mode?(action)
|
|
actions_allowed_in_readonly_mode.include?(action.to_sym)
|
|
end
|
|
|
|
def allowed_in_staff_writes_only_mode?(action)
|
|
actions_allowed_in_staff_writes_only_mode.include?(action.to_sym)
|
|
end
|
|
end
|
|
|
|
def check_readonly_mode
|
|
if Discourse.readonly_mode?
|
|
@readonly_mode = true
|
|
@staff_writes_only_mode = false
|
|
elsif Discourse.staff_writes_only_mode?
|
|
@readonly_mode = true
|
|
@staff_writes_only_mode = true
|
|
else
|
|
@readonly_mode = false
|
|
@staff_writes_only_mode = false
|
|
end
|
|
end
|
|
|
|
def add_readonly_header
|
|
response.headers["Discourse-Readonly"] = "true" if @readonly_mode
|
|
end
|
|
|
|
def allowed_in_readonly_mode?
|
|
self.class.allowed_in_readonly_mode?(action_name)
|
|
end
|
|
|
|
def allowed_in_staff_writes_only_mode?
|
|
self.class.allowed_in_staff_writes_only_mode?(action_name)
|
|
end
|
|
|
|
def block_if_readonly_mode
|
|
return if request.get? || request.head?
|
|
if @staff_writes_only_mode && (allowed_in_staff_writes_only_mode? || current_user&.staff?)
|
|
return
|
|
end
|
|
return if !@readonly_mode || allowed_in_readonly_mode?
|
|
raise Discourse::ReadOnly
|
|
end
|
|
|
|
def self.included(base)
|
|
base.extend(ClassMethods)
|
|
end
|
|
end
|