mirror of
https://github.com/discourse/discourse.git
synced 2024-11-22 09:42:02 +08:00
DEV: Change anonymous_posting_min_trust_level to a group-based setting (#24072)
No plugins or themes rely on anonymous_posting_min_trust_level so we can just switch straight over to anonymous_posting_allowed_groups This also adds an AUTO_GROUPS const which can be imported in JS tests which is analogous to the one defined in group.rb. This can be used to set the current user's groups where JS tests call for checking these groups against site settings. Finally a AtLeastOneGroupValidator validator is added for group_list site settings which ensures that at least one group is always selected, since if you want to allow all users to use a feature in this way you can just use the everyone group.
This commit is contained in:
parent
5e395d4382
commit
9db4eaa870
|
@ -15,10 +15,9 @@ export default class AdminRoute extends DiscourseRoute {
|
|||
|
||||
activate() {
|
||||
if (
|
||||
!this.currentUser.isInAnyGroups(
|
||||
this.siteSettings.groupSettingArray(
|
||||
"enable_experimental_admin_ui_groups"
|
||||
)
|
||||
!this.siteSettings.userInAnyGroups(
|
||||
"enable_experimental_admin_ui_groups",
|
||||
this.currentUser
|
||||
)
|
||||
) {
|
||||
return DiscourseURL.redirectTo("/admin");
|
||||
|
|
|
@ -28,8 +28,10 @@ export default class UserMenuProfileTabContent extends Component {
|
|||
get showToggleAnonymousButton() {
|
||||
return (
|
||||
(this.siteSettings.allow_anonymous_posting &&
|
||||
this.currentUser.trust_level >=
|
||||
this.siteSettings.anonymous_posting_min_trust_level) ||
|
||||
this.siteSettings.userInAnyGroups(
|
||||
"anonymous_posting_allowed_groups",
|
||||
this.currentUser
|
||||
)) ||
|
||||
this.currentUser.is_anonymous
|
||||
);
|
||||
}
|
||||
|
|
|
@ -21,3 +21,50 @@ export const SIDEBAR_URL = {
|
|||
export const SIDEBAR_SECTION = {
|
||||
max_title_length: 30,
|
||||
};
|
||||
|
||||
export const AUTO_GROUPS = {
|
||||
everyone: {
|
||||
id: 0,
|
||||
automatic: true,
|
||||
name: "everyone",
|
||||
display_name: "everyone",
|
||||
},
|
||||
admins: { id: 1, automatic: true, name: "admins", display_name: "admins" },
|
||||
moderators: {
|
||||
id: 2,
|
||||
automatic: true,
|
||||
name: "moderators",
|
||||
display_name: "moderators",
|
||||
},
|
||||
staff: { id: 3, automatic: true, name: "staff", display_name: "staff" },
|
||||
trust_level_0: {
|
||||
id: 10,
|
||||
automatic: true,
|
||||
name: "trust_level_0",
|
||||
display_name: "trust_level_0",
|
||||
},
|
||||
trust_level_1: {
|
||||
id: 11,
|
||||
automatic: true,
|
||||
name: "trust_level_1",
|
||||
display_name: "trust_level_1",
|
||||
},
|
||||
trust_level_2: {
|
||||
id: 12,
|
||||
automatic: true,
|
||||
name: "trust_level_2",
|
||||
display_name: "trust_level_2",
|
||||
},
|
||||
trust_level_3: {
|
||||
id: 13,
|
||||
automatic: true,
|
||||
name: "trust_level_3",
|
||||
display_name: "trust_level_3",
|
||||
},
|
||||
trust_level_4: {
|
||||
id: 14,
|
||||
automatic: true,
|
||||
name: "trust_level_4",
|
||||
display_name: "trust_level_4",
|
||||
},
|
||||
};
|
||||
|
|
|
@ -31,10 +31,9 @@ export default class AdminRevampSectionLink extends BaseSectionLink {
|
|||
|
||||
return (
|
||||
this.currentUser.staff &&
|
||||
this.currentUser.isInAnyGroups(
|
||||
this.siteSettings.groupSettingArray(
|
||||
"enable_experimental_admin_ui_groups"
|
||||
)
|
||||
this.siteSettings.userInAnyGroups(
|
||||
"enable_experimental_admin_ui_groups",
|
||||
this.currentUser
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -2,26 +2,35 @@ import { TrackedObject } from "@ember-compat/tracked-built-ins";
|
|||
import { disableImplicitInjections } from "discourse/lib/implicit-injections";
|
||||
import PreloadStore from "discourse/lib/preload-store";
|
||||
|
||||
export function createSiteSettingsFromPreloaded(data) {
|
||||
const settings = new TrackedObject(data);
|
||||
|
||||
settings.groupSettingArray = (groupSetting) => {
|
||||
const setting = settings[groupSetting];
|
||||
if (!setting) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return setting
|
||||
.toString()
|
||||
.split("|")
|
||||
.filter(Boolean)
|
||||
.map((groupId) => parseInt(groupId, 10));
|
||||
};
|
||||
|
||||
settings.userInAnyGroups = (groupSetting, user) => {
|
||||
const groupIds = settings.groupSettingArray(groupSetting);
|
||||
return user.isInAnyGroups(groupIds);
|
||||
};
|
||||
|
||||
return settings;
|
||||
}
|
||||
|
||||
@disableImplicitInjections
|
||||
export default class SiteSettingsService {
|
||||
static isServiceFactory = true;
|
||||
|
||||
static create() {
|
||||
const settings = new TrackedObject(PreloadStore.get("siteSettings"));
|
||||
|
||||
settings.groupSettingArray = (groupSetting) => {
|
||||
const setting = settings[groupSetting];
|
||||
if (!setting) {
|
||||
return [];
|
||||
}
|
||||
|
||||
return setting
|
||||
.toString()
|
||||
.split("|")
|
||||
.filter(Boolean)
|
||||
.map((groupId) => parseInt(groupId, 10));
|
||||
};
|
||||
|
||||
return settings;
|
||||
return createSiteSettingsFromPreloaded(PreloadStore.get("siteSettings"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ import { click, currentURL, triggerKeyEvent, visit } from "@ember/test-helpers";
|
|||
import { test } from "qunit";
|
||||
import { Promise } from "rsvp";
|
||||
import DButton from "discourse/components/d-button";
|
||||
import { AUTO_GROUPS } from "discourse/lib/constants";
|
||||
import { withPluginApi } from "discourse/lib/plugin-api";
|
||||
import { NOTIFICATION_TYPES } from "discourse/tests/fixtures/concerns/notification-types";
|
||||
import TopicFixtures from "discourse/tests/fixtures/topic";
|
||||
|
@ -30,7 +31,7 @@ acceptance("User menu", function (needs) {
|
|||
|
||||
needs.settings({
|
||||
allow_anonymous_posting: true,
|
||||
anonymous_posting_min_trust_level: 3,
|
||||
anonymous_posting_allowed_groups: "3",
|
||||
});
|
||||
|
||||
let requestHeaders = {};
|
||||
|
@ -564,6 +565,10 @@ acceptance("User menu", function (needs) {
|
|||
"Do Not Disturb button has the right icon when Do Not Disturb is enabled"
|
||||
);
|
||||
|
||||
assert.ok(
|
||||
exists("#quick-access-profile ul li.enable-anonymous .btn"),
|
||||
"toggle anon button is shown"
|
||||
);
|
||||
let toggleAnonButton = query(
|
||||
"#quick-access-profile ul li.enable-anonymous .btn"
|
||||
);
|
||||
|
@ -602,7 +607,15 @@ acceptance("User menu", function (needs) {
|
|||
);
|
||||
|
||||
await click("header.d-header"); // close the menu
|
||||
updateCurrentUser({ is_anonymous: false, trust_level: 2 });
|
||||
updateCurrentUser({
|
||||
is_anonymous: false,
|
||||
trust_level: 2,
|
||||
groups: [
|
||||
AUTO_GROUPS.trust_level_0,
|
||||
AUTO_GROUPS.trust_level_1,
|
||||
AUTO_GROUPS.trust_level_2,
|
||||
],
|
||||
});
|
||||
await click(".d-header-icons .current-user");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
|
@ -616,9 +629,17 @@ acceptance("User menu", function (needs) {
|
|||
);
|
||||
|
||||
await click("header.d-header"); // close the menu
|
||||
updateCurrentUser({ is_anonymous: true, trust_level: 2 });
|
||||
updateCurrentUser({
|
||||
is_anonymous: true,
|
||||
trust_level: 2,
|
||||
groups: [
|
||||
AUTO_GROUPS.trust_level_0,
|
||||
AUTO_GROUPS.trust_level_1,
|
||||
AUTO_GROUPS.trust_level_2,
|
||||
],
|
||||
});
|
||||
this.siteSettings.allow_anonymous_posting = false;
|
||||
this.siteSettings.anonymous_posting_min_trust_level = 3;
|
||||
this.siteSettings.anonymous_posting_allowed_groups = "3";
|
||||
await click(".d-header-icons .current-user");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
|
@ -628,9 +649,19 @@ acceptance("User menu", function (needs) {
|
|||
);
|
||||
|
||||
await click("header.d-header"); // close the menu
|
||||
updateCurrentUser({ is_anonymous: false, trust_level: 4 });
|
||||
updateCurrentUser({
|
||||
is_anonymous: true,
|
||||
trust_level: 4,
|
||||
groups: [
|
||||
AUTO_GROUPS.trust_level_0,
|
||||
AUTO_GROUPS.trust_level_1,
|
||||
AUTO_GROUPS.trust_level_2,
|
||||
AUTO_GROUPS.trust_level_3,
|
||||
AUTO_GROUPS.trust_level_4,
|
||||
],
|
||||
});
|
||||
this.siteSettings.allow_anonymous_posting = false;
|
||||
this.siteSettings.anonymous_posting_min_trust_level = 3;
|
||||
this.siteSettings.anonymous_posting_allowed_groups = "3";
|
||||
await click(".d-header-icons .current-user");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
|
@ -640,9 +671,17 @@ acceptance("User menu", function (needs) {
|
|||
);
|
||||
|
||||
await click("header.d-header"); // close the menu
|
||||
updateCurrentUser({ is_anonymous: false, trust_level: 2 });
|
||||
updateCurrentUser({
|
||||
is_anonymous: false,
|
||||
trust_level: 2,
|
||||
groups: [
|
||||
AUTO_GROUPS.trust_level_0,
|
||||
AUTO_GROUPS.trust_level_1,
|
||||
AUTO_GROUPS.trust_level_2,
|
||||
],
|
||||
});
|
||||
this.siteSettings.allow_anonymous_posting = true;
|
||||
this.siteSettings.anonymous_posting_min_trust_level = 3;
|
||||
this.siteSettings.anonymous_posting_allowed_groups = "3";
|
||||
await click(".d-header-icons .current-user");
|
||||
await click("#user-menu-button-profile");
|
||||
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
import { deepFreeze } from "discourse-common/lib/object";
|
||||
import {
|
||||
AUTO_GROUPS,
|
||||
} from "discourse/lib/constants";
|
||||
|
||||
export default {
|
||||
"/session/current.json": deepFreeze({
|
||||
|
@ -30,18 +33,12 @@ export default {
|
|||
can_review: true,
|
||||
ignored_users: [],
|
||||
groups: [
|
||||
{
|
||||
id: 10,
|
||||
automatic: true,
|
||||
name: "trust_level_0",
|
||||
display_name: "trust_level_0",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
automatic: true,
|
||||
name: "trust_level_1",
|
||||
display_name: "trust_level_1",
|
||||
}
|
||||
AUTO_GROUPS.admins,
|
||||
AUTO_GROUPS.moderators,
|
||||
AUTO_GROUPS.staff,
|
||||
AUTO_GROUPS.trust_level_0,
|
||||
AUTO_GROUPS.trust_level_1,
|
||||
AUTO_GROUPS.trust_level_2,
|
||||
],
|
||||
user_option: {
|
||||
external_links_in_new_tab: false,
|
||||
|
|
|
@ -3,6 +3,7 @@ import { setupRenderingTest as emberSetupRenderingTest } from "ember-qunit";
|
|||
import $ from "jquery";
|
||||
import QUnit, { test } from "qunit";
|
||||
import { autoLoadModules } from "discourse/instance-initializers/auto-load-modules";
|
||||
import { AUTO_GROUPS } from "discourse/lib/constants";
|
||||
import Session from "discourse/models/session";
|
||||
import Site from "discourse/models/site";
|
||||
import TopicTrackingState from "discourse/models/topic-tracking-state";
|
||||
|
@ -27,20 +28,7 @@ export function setupRenderingTest(hooks) {
|
|||
name: "Robin Ward",
|
||||
admin: false,
|
||||
moderator: false,
|
||||
groups: [
|
||||
{
|
||||
id: 10,
|
||||
automatic: true,
|
||||
name: "trust_level_0",
|
||||
display_name: "trust_level_0",
|
||||
},
|
||||
{
|
||||
id: 11,
|
||||
automatic: true,
|
||||
name: "trust_level_1",
|
||||
display_name: "trust_level_1",
|
||||
},
|
||||
],
|
||||
groups: [AUTO_GROUPS.trust_level_0, AUTO_GROUPS.trust_level_1],
|
||||
user_option: {
|
||||
timezone: "Australia/Brisbane",
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { TrackedObject } from "@ember-compat/tracked-built-ins";
|
||||
import { createSiteSettingsFromPreloaded } from "discourse/services/site-settings";
|
||||
|
||||
const CLIENT_SETTING_TEST_OVERRIDES = {
|
||||
title: "QUnit Discourse Tests",
|
||||
|
@ -38,6 +38,6 @@ export function mergeSettings(other) {
|
|||
}
|
||||
|
||||
export function resetSettings() {
|
||||
siteSettings = new TrackedObject(ORIGINAL_CLIENT_SITE_SETTINGS);
|
||||
siteSettings = createSiteSettingsFromPreloaded(ORIGINAL_CLIENT_SITE_SETTINGS);
|
||||
return siteSettings;
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ class AnonymousShadowCreator
|
|||
def get
|
||||
return unless user
|
||||
return unless SiteSetting.allow_anonymous_posting
|
||||
return if user.trust_level < SiteSetting.anonymous_posting_min_trust_level
|
||||
return if !user.in_any_groups?(SiteSetting.anonymous_posting_allowed_groups_map)
|
||||
return if SiteSetting.must_approve_users? && !user.approved?
|
||||
|
||||
shadow = user.shadow_user
|
||||
|
|
|
@ -2177,6 +2177,7 @@ en:
|
|||
allow_anonymous_posting: "Allow users to switch to anonymous mode"
|
||||
allow_anonymous_likes: "Allow anonymous users to like posts"
|
||||
anonymous_posting_min_trust_level: "Minimum trust level required to enable anonymous posting"
|
||||
anonymous_posting_allowed_groups: "Groups that are allowed to enable anonymous posting"
|
||||
anonymous_account_duration_minutes: "To protect anonymity create a new anonymous account every N minutes for each user. Example: if set to 600, as soon as 600 minutes elapse from last post AND user switches to anon, a new anonymous account is created."
|
||||
|
||||
hide_user_profiles_from_public: "Disable user cards, user profiles and user directory for anonymous users."
|
||||
|
@ -2488,7 +2489,7 @@ en:
|
|||
reply_by_email_address_is_empty: "You must set a 'reply by email address' before enabling reply by email."
|
||||
email_polling_disabled: "You must enable either manual, POP3 polling or have a custom mail poller enabled before enabling reply by email."
|
||||
user_locale_not_enabled: "You must first enable 'allow user locale' before enabling this setting."
|
||||
personal_message_enabled_groups_invalid: "You must specify at least one group for this setting. If you do not want anyone except staff to send PMs, choose the staff group."
|
||||
at_least_one_group_required: "You must specify at least one group for this setting."
|
||||
invalid_regex: "Regex is invalid or not allowed."
|
||||
invalid_regex_with_message: "The regex '%{regex}' has an error: %{message}"
|
||||
email_editable_enabled: "You must disable 'email editable' before enabling this setting."
|
||||
|
|
|
@ -682,6 +682,13 @@ users:
|
|||
default: 1
|
||||
enum: "TrustLevelSetting"
|
||||
client: true
|
||||
anonymous_posting_allowed_groups:
|
||||
default: "11" # auto group trust_level_1
|
||||
type: group_list
|
||||
client: true
|
||||
allow_any: false
|
||||
refresh: true
|
||||
validator: "AtLeastOneGroupValidator"
|
||||
anonymous_account_duration_minutes:
|
||||
default: 10080
|
||||
max: 99000
|
||||
|
@ -860,7 +867,7 @@ posting:
|
|||
client: true
|
||||
allow_any: false
|
||||
refresh: true
|
||||
validator: "PersonalMessageEnabledGroupsValidator"
|
||||
validator: "AtLeastOneGroupValidator"
|
||||
editing_grace_period: 300
|
||||
editing_grace_period_max_diff: 100
|
||||
editing_grace_period_max_diff_high_trust: 400
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class MigrateTlToGroupSettingsAnonymousPostingMinTl < ActiveRecord::Migration[7.0]
|
||||
def up
|
||||
anonymous_posting_min_trust_level_raw =
|
||||
DB.query_single(
|
||||
"SELECT value FROM site_settings WHERE name = 'anonymous_posting_min_trust_level'",
|
||||
).first
|
||||
|
||||
# Default for old setting is TL1, we only need to do anything if it's been changed in the DB.
|
||||
if anonymous_posting_min_trust_level_raw.present?
|
||||
# Matches Group::AUTO_GROUPS to the trust levels.
|
||||
anonymous_posting_allowed_groups =
|
||||
case anonymous_posting_min_trust_level_raw
|
||||
when "0"
|
||||
"10"
|
||||
when "1"
|
||||
"11"
|
||||
when "2"
|
||||
"12"
|
||||
when "3"
|
||||
"13"
|
||||
when "4"
|
||||
"14"
|
||||
end
|
||||
|
||||
# Data_type 20 is group_list.
|
||||
exec(<<~SQL, setting: anonymous_posting_allowed_groups)
|
||||
INSERT INTO site_settings(name, value, data_type, created_at, updated_at)
|
||||
VALUES('anonymous_posting_allowed_groups', :setting, '20', NOW(), NOW())
|
||||
SQL
|
||||
end
|
||||
end
|
||||
|
||||
def down
|
||||
raise ActiveRecord::IrreversibleMigration
|
||||
end
|
||||
end
|
|
@ -8,6 +8,7 @@ module SiteSettings::DeprecatedSettings
|
|||
# [<old setting>, <new_setting>, <override>, <version to drop>]
|
||||
["search_tokenize_chinese_japanese_korean", "search_tokenize_chinese", true, "2.9"],
|
||||
["default_categories_regular", "default_categories_normal", true, "3.0"],
|
||||
["anonymous_posting_min_trust_level", "anonymous_posting_allowed_groups", false, "3.3"],
|
||||
]
|
||||
|
||||
def setup_deprecated_methods
|
||||
|
|
|
@ -133,6 +133,18 @@ end
|
|||
task "javascript:update_constants" => :environment do
|
||||
task_name = "update_constants"
|
||||
|
||||
auto_groups =
|
||||
Group::AUTO_GROUPS.inject({}) do |result, (group_name, group_id)|
|
||||
result.merge(
|
||||
group_name => {
|
||||
id: group_id,
|
||||
automatic: true,
|
||||
name: group_name,
|
||||
display_name: group_name,
|
||||
},
|
||||
)
|
||||
end
|
||||
|
||||
write_template("discourse/app/lib/constants.js", task_name, <<~JS)
|
||||
export const SEARCH_PRIORITIES = #{Searchable::PRIORITIES.to_json};
|
||||
|
||||
|
@ -147,6 +159,8 @@ task "javascript:update_constants" => :environment do
|
|||
export const SIDEBAR_SECTION = {
|
||||
max_title_length: #{SidebarSection::MAX_TITLE_LENGTH},
|
||||
}
|
||||
|
||||
export const AUTO_GROUPS = #{auto_groups.to_json};
|
||||
JS
|
||||
|
||||
pretty_notifications = Notification.types.map { |n| " #{n[0]}: #{n[1]}," }.join("\n")
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class PersonalMessageEnabledGroupsValidator
|
||||
class AtLeastOneGroupValidator
|
||||
def initialize(opts = {})
|
||||
@opts = opts
|
||||
end
|
||||
|
@ -10,6 +10,6 @@ class PersonalMessageEnabledGroupsValidator
|
|||
end
|
||||
|
||||
def error_message
|
||||
I18n.t("site_settings.errors.personal_message_enabled_groups_invalid")
|
||||
I18n.t("site_settings.errors.at_least_one_group_required")
|
||||
end
|
||||
end
|
|
@ -67,8 +67,9 @@ export default class Chat extends Service {
|
|||
|
||||
return (
|
||||
this.currentUser.staff ||
|
||||
this.currentUser.isInAnyGroups(
|
||||
this.siteSettings.groupSettingArray("direct_message_enabled_groups")
|
||||
this.siteSettings.userInAnyGroups(
|
||||
"direct_message_enabled_groups",
|
||||
this.currentUser
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
@ -128,6 +128,7 @@ RSpec.describe User do
|
|||
|
||||
it "should initiate bot for real user only" do
|
||||
user = Fabricate(:user, trust_level: 1)
|
||||
Group.refresh_automatic_groups!
|
||||
shadow = AnonymousShadowCreator.get(user)
|
||||
|
||||
expect(TopicAllowedUser.where(user_id: shadow.id).count).to eq(0)
|
||||
|
|
|
@ -153,6 +153,7 @@ RSpec.describe ApplicationController do
|
|||
it "should not redirect anonymous users when enforce_second_factor is 'all'" do
|
||||
SiteSetting.enforce_second_factor = "all"
|
||||
SiteSetting.allow_anonymous_posting = true
|
||||
Group.refresh_automatic_groups!
|
||||
sign_in(user)
|
||||
|
||||
post "/u/toggle-anon.json"
|
||||
|
|
|
@ -607,6 +607,7 @@ RSpec.describe UsersController do
|
|||
user = sign_in(Fabricate(:user))
|
||||
user.trust_level = 1
|
||||
user.save!
|
||||
Group.refresh_automatic_groups!
|
||||
|
||||
post "/u/toggle-anon.json"
|
||||
expect(response.status).to eq(200)
|
||||
|
|
|
@ -8,10 +8,16 @@ RSpec.describe AnonymousShadowCreator do
|
|||
context "when anonymous posting is enabled" do
|
||||
fab!(:user) { Fabricate(:user, trust_level: 3) }
|
||||
|
||||
before { SiteSetting.allow_anonymous_posting = true }
|
||||
before do
|
||||
SiteSetting.allow_anonymous_posting = true
|
||||
SiteSetting.anonymous_posting_allowed_groups = "11"
|
||||
Group.refresh_automatic_groups!
|
||||
end
|
||||
|
||||
it "returns no shadow if trust level is not met" do
|
||||
expect(AnonymousShadowCreator.get(Fabricate.build(:user, trust_level: 0))).to eq(nil)
|
||||
it "returns no shadow if the user is not in a group that is allowed to anonymously post" do
|
||||
user = Fabricate(:user, trust_level: 0)
|
||||
Group.refresh_automatic_groups!
|
||||
expect(AnonymousShadowCreator.get(user)).to eq(nil)
|
||||
end
|
||||
|
||||
it "returns no shadow if must_approve_users is true and user is not approved" do
|
||||
|
|
Loading…
Reference in New Issue
Block a user