diff --git a/app/assets/javascripts/discourse/models/user.js.es6 b/app/assets/javascripts/discourse/models/user.js.es6 index 23816363e..62874c5b2 100644 --- a/app/assets/javascripts/discourse/models/user.js.es6 +++ b/app/assets/javascripts/discourse/models/user.js.es6 @@ -181,6 +181,7 @@ const User = Discourse.Model.extend({ 'email_direct', 'email_always', 'email_private_messages', + 'allow_private_messages', 'dynamic_favicon', 'digest_after_days', 'new_topic_duration_minutes', diff --git a/app/assets/javascripts/discourse/templates/user/preferences.hbs b/app/assets/javascripts/discourse/templates/user/preferences.hbs index d7cc7b20c..7d9ee810c 100644 --- a/app/assets/javascripts/discourse/templates/user/preferences.hbs +++ b/app/assets/javascripts/discourse/templates/user/preferences.hbs @@ -211,6 +211,7 @@ {{preference-checkbox labelKey="user.enable_quoting" checked=enable_quoting}} {{preference-checkbox labelKey="user.dynamic_favicon" checked=dynamic_favicon}} {{preference-checkbox labelKey="user.disable_jump_reply" checked=disable_jump_reply}} + {{preference-checkbox labelKey="user.allow_private_messages" checked=allow_private_messages}} {{#unless editHistoryVisible}} {{preference-checkbox labelKey="user.edit_history_public" checked=edit_history_public}} {{/unless}} diff --git a/app/serializers/user_serializer.rb b/app/serializers/user_serializer.rb index f589b329f..31273a8a9 100644 --- a/app/serializers/user_serializer.rb +++ b/app/serializers/user_serializer.rb @@ -95,7 +95,8 @@ class UserSerializer < BasicUserSerializer :custom_avatar_upload_id, :has_title_badges, :card_image_badge, - :card_image_badge_id + :card_image_badge_id, + :allow_private_messages untrusted_attributes :bio_raw, :bio_cooked, @@ -157,6 +158,10 @@ class UserSerializer < BasicUserSerializer object.user_profile.location end + def allow_private_messages + object.user_profile.allow_private_messages + end + def can_edit scope.can_edit?(object) end diff --git a/app/services/user_updater.rb b/app/services/user_updater.rb index 8fd14c236..8dc753cb9 100644 --- a/app/services/user_updater.rb +++ b/app/services/user_updater.rb @@ -19,11 +19,6 @@ class UserUpdater :edit_history_public ] - PROFILE_ATTR = [ - :location, - :dismissed_banner_key - ] - def initialize(actor, user) @user = user @guardian = Guardian.new(actor) @@ -33,6 +28,9 @@ class UserUpdater user_profile = user.user_profile user_profile.website = format_url(attributes.fetch(:website) { user_profile.website }) user_profile.bio_raw = attributes.fetch(:bio_raw) { user_profile.bio_raw } + user_profile.allow_private_messages = attributes.fetch(:allow_private_messages) { + user_profile.allow_private_messages + } user.name = attributes.fetch(:name) { user.name } user.locale = attributes.fetch(:locale) { user.locale } diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 3294e75a4..2a1d3522b 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -335,6 +335,7 @@ en: dismiss_notifications: "Mark all as Read" dismiss_notifications_tooltip: "Mark all unread notifications as read" disable_jump_reply: "Don't jump to my post after I reply" + allow_private_messages: "Allow users to send me private messages" dynamic_favicon: "Show incoming message notifications on favicon (experimental)" edit_history_public: "Let other users view my post revisions" external_links_in_new_tab: "Open all external links in a new tab" diff --git a/db/migrate/20150323034933_add_allow_private_messages_to_user_profile.rb b/db/migrate/20150323034933_add_allow_private_messages_to_user_profile.rb new file mode 100644 index 000000000..f80bc1b11 --- /dev/null +++ b/db/migrate/20150323034933_add_allow_private_messages_to_user_profile.rb @@ -0,0 +1,5 @@ +class AddAllowPrivateMessagesToUserProfile < ActiveRecord::Migration + def change + add_column :user_profiles, :allow_private_messages, :boolean, default: true, null: false + end +end diff --git a/lib/guardian.rb b/lib/guardian.rb index d3e2911ee..3cff69012 100644 --- a/lib/guardian.rb +++ b/lib/guardian.rb @@ -260,6 +260,8 @@ class Guardian (SiteSetting.enable_private_messages || @user.username == SiteSetting.site_contact_username || @user == Discourse.system_user) && + # Only staff can send PMs to users that opt-out + (!target.is_a?(User) || is_staff? || target.user_profile.allow_private_messages) && # Can't send PMs to suspended users (is_staff? || target.is_a?(Group) || !target.suspended?) end diff --git a/spec/components/post_creator_spec.rb b/spec/components/post_creator_spec.rb index 77d658f08..bd64f97f2 100644 --- a/spec/components/post_creator_spec.rb +++ b/spec/components/post_creator_spec.rb @@ -393,14 +393,30 @@ describe PostCreator do let(:target_user1) { Fabricate(:coding_horror) } let(:target_user2) { Fabricate(:moderator) } let(:unrelated) { Fabricate(:user) } - let(:post) do - PostCreator.create(user, title: 'hi there welcome to my topic', + + def create_pm(from, to) + PostCreator.create(from, title: 'hi there welcome to my topic', raw: "this is my awesome message @#{unrelated.username_lower}", archetype: Archetype.private_message, - target_usernames: [target_user1.username, target_user2.username].join(','), + target_usernames: to.join(','), category: 1) end + let(:post) do + create_pm(user, [target_user1.username, target_user2.username]) + end + + it 'disallows PM to end users that disable it' do + profile = target_user2.user_profile + profile.allow_private_messages = false + profile.save + + post = create_pm(user, [target_user2.username]) + + expect(post).to be_nil + + end + it 'acts correctly' do # It's not a warning expect(post.topic.warning).to be_blank @@ -476,10 +492,11 @@ describe PostCreator do end let(:unrelated) { Fabricate(:user) } let(:post) do - PostCreator.create(user, title: 'hi there welcome to my topic', + PostCreator.new(user, title: 'hi there welcome to my topic', raw: "this is my awesome message @#{unrelated.username_lower}", archetype: Archetype.private_message, - target_group_names: group.name) + target_group_names: group.name).create + end it 'acts correctly' do