FEATURE: new hide_user_profiles_from_public site setting

This commit is contained in:
Régis Hanol 2015-10-28 19:56:08 +01:00
parent d9997a6b9e
commit bb79e6aff7
11 changed files with 127 additions and 59 deletions

View file

@ -56,6 +56,13 @@ export default Ember.Component.extend({
});
},
@computed()
showUserDirectoryLink() {
if (!this.siteSettings.enable_user_directory) return false;
if (this.siteSettings.hide_user_profiles_from_public && !this.currentUser) return false;
return true;
},
actions: {
keyboardShortcuts() {
this.sendAction('showKeyboardAction');

View file

@ -39,6 +39,11 @@ export default Ember.Controller.extend({
// XSS protection (should be encapsulated)
username = username.toString().replace(/[^A-Za-z0-9_\.\-]/g, "");
// No user card for anon
if (this.siteSettings.hide_user_profiles_from_public && !this.currentUser) {
return;
}
// Don't show on mobile
if (Discourse.Mobile.mobileView) {
const url = "/users/" + username;

View file

@ -33,6 +33,12 @@ export default Discourse.Route.extend({
}
},
beforeModel() {
if (this.siteSettings.hide_user_profiles_from_public && !this.currentUser) {
this.replaceWith("discovery");
}
},
model(params) {
// If we're viewing the currently logged in user, return that object instead
const currentUser = this.currentUser;

View file

@ -23,6 +23,12 @@ export default Discourse.Route.extend({
}
},
beforeModel() {
if (this.siteSettings.hide_user_profiles_from_public && !this.currentUser) {
this.replaceWith("discovery");
}
},
model(params) {
// If we refresh via `refreshModel` set the old model to loading
this._params = params;

View file

@ -57,7 +57,7 @@
<li>{{d-link route="badges" class="badge-link" label="badges.title"}}</li>
{{/if}}
{{#if siteSettings.enable_user_directory}}
{{#if showUserDirectoryLink}}
<li>{{d-link route="users" class="user-directory-link" label="directory.title"}}</li>
{{/if}}

View file

@ -29,6 +29,8 @@ class UsersController < ApplicationController
end
def show
raise Discourse::InvalidAccess if SiteSetting.hide_user_profiles_from_public && !current_user
@user = fetch_user_from_params
user_serializer = UserSerializer.new(@user, scope: guardian, root: 'user')
if params[:stats].to_s == "false"
@ -162,7 +164,6 @@ class UsersController < ApplicationController
end
def my_redirect
raise Discourse::NotFound if params[:path] !~ /^[a-z\-\/]+$/
if current_user.blank?

View file

@ -1162,6 +1162,8 @@ en:
anonymous_posting_min_trust_level: "Minimum trust level required 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."
allow_profile_backgrounds: "Allow users to upload profile backgrounds."
sequential_replies_threshold: "Number posts a user has to make in a row in a topic before being reminded about too many sequential replies. "

View file

@ -342,6 +342,9 @@ users:
client: true
anonymous_account_duration_minutes:
default: 10080
hide_user_profiles_from_public:
default: false
client: true
posting:
min_post_length:

View file

@ -379,6 +379,8 @@ class Search
end
def user_search
return if SiteSetting.hide_user_profiles_from_public && !@guardian.user
users = User.includes(:user_search_data)
.where("active = true AND user_search_data.search_data @@ #{ts_query("simple")}")
.order("CASE WHEN username_lower = '#{@original_term.downcase}' THEN 0 ELSE 1 END")

View file

@ -85,6 +85,21 @@ describe Search do
expect(result.users.length).to eq(1)
expect(result.users[0].id).to eq(user.id)
end
context 'hiding user profiles' do
before { SiteSetting.stubs(:hide_user_profiles_from_public).returns(true) }
it 'returns no result for anon' do
expect(result.users.length).to eq(0)
end
it 'returns a result for logged in users' do
result = Search.execute('bruce', type_filter: 'user', guardian: Guardian.new(user))
expect(result.users.length).to eq(1)
end
end
end
context 'inactive users' do
@ -119,7 +134,6 @@ describe Search do
TopicAllowedUser.create!(user_id: reply.user_id, topic_id: topic.id)
TopicAllowedUser.create!(user_id: post.user_id, topic_id: topic.id)
results = Search.execute('mars',
type_filter: 'private_messages',
guardian: Guardian.new(reply.user))

View file

@ -3,71 +3,93 @@ require 'spec_helper'
describe UsersController do
describe '.show' do
let(:user) { log_in }
it 'returns success' do
xhr :get, :show, username: user.username, format: :json
expect(response).to be_success
json = JSON.parse(response.body)
context "anon" do
expect(json["user"]["has_title_badges"]).to eq(false)
let(:user) { Discourse.system_user }
end
it "returns not found when the username doesn't exist" do
xhr :get, :show, username: 'madeuppity'
expect(response).not_to be_success
end
it 'returns not found when the user is inactive' do
inactive = Fabricate(:user, active: false)
xhr :get, :show, username: inactive.username
expect(response).not_to be_success
end
it "raises an error on invalid access" do
Guardian.any_instance.expects(:can_see?).with(user).returns(false)
xhr :get, :show, username: user.username
expect(response).to be_forbidden
end
describe "user profile views" do
let(:other_user) { Fabricate(:user) }
it "should track a user profile view for a signed in user" do
UserProfileView.expects(:add).with(other_user.user_profile.id, request.remote_ip, user.id)
xhr :get, :show, username: other_user.username
end
it "should not track a user profile view for a user viewing his own profile" do
UserProfileView.expects(:add).never
xhr :get, :show, username: user.username
end
it "should track a user profile view for an anon user" do
UserProfileView.expects(:add).with(other_user.user_profile.id, request.remote_ip, nil)
xhr :get, :show, username: other_user.username
end
it "skips tracking" do
UserProfileView.expects(:add).never
xhr :get, :show, { username: user.username, skip_track_visit: true }
end
end
context "fetching a user by external_id" do
before { user.create_single_sign_on_record(external_id: '997', last_payload: '') }
it "returns fetch for a matching external_id" do
xhr :get, :show, external_id: '997'
it "returns success" do
xhr :get, :show, username: user.username, format: :json
expect(response).to be_success
end
it "returns not found when external_id doesn't match" do
xhr :get, :show, external_id: '99'
it "raises an error for anon when profiles are hidden" do
SiteSetting.stubs(:hide_user_profiles_from_public).returns(true)
xhr :get, :show, username: user.username, format: :json
expect(response).not_to be_success
end
end
context "logged in" do
let(:user) { log_in }
it 'returns success' do
xhr :get, :show, username: user.username, format: :json
expect(response).to be_success
json = JSON.parse(response.body)
expect(json["user"]["has_title_badges"]).to eq(false)
end
it "returns not found when the username doesn't exist" do
xhr :get, :show, username: 'madeuppity'
expect(response).not_to be_success
end
it 'returns not found when the user is inactive' do
inactive = Fabricate(:user, active: false)
xhr :get, :show, username: inactive.username
expect(response).not_to be_success
end
it "raises an error on invalid access" do
Guardian.any_instance.expects(:can_see?).with(user).returns(false)
xhr :get, :show, username: user.username
expect(response).to be_forbidden
end
describe "user profile views" do
let(:other_user) { Fabricate(:user) }
it "should track a user profile view for a signed in user" do
UserProfileView.expects(:add).with(other_user.user_profile.id, request.remote_ip, user.id)
xhr :get, :show, username: other_user.username
end
it "should not track a user profile view for a user viewing his own profile" do
UserProfileView.expects(:add).never
xhr :get, :show, username: user.username
end
it "should track a user profile view for an anon user" do
UserProfileView.expects(:add).with(other_user.user_profile.id, request.remote_ip, nil)
xhr :get, :show, username: other_user.username
end
it "skips tracking" do
UserProfileView.expects(:add).never
xhr :get, :show, { username: user.username, skip_track_visit: true }
end
end
context "fetching a user by external_id" do
before { user.create_single_sign_on_record(external_id: '997', last_payload: '') }
it "returns fetch for a matching external_id" do
xhr :get, :show, external_id: '997'
expect(response).to be_success
end
it "returns not found when external_id doesn't match" do
xhr :get, :show, external_id: '99'
expect(response).not_to be_success
end
end
end
end
describe '.user_preferences_redirect' do