diff --git a/app/logical/concerns/has_bit_flags.rb b/app/logical/concerns/has_bit_flags.rb index c05b6d54a..9364c042f 100644 --- a/app/logical/concerns/has_bit_flags.rb +++ b/app/logical/concerns/has_bit_flags.rb @@ -6,6 +6,7 @@ module HasBitFlags def has_bit_flags(attributes, field: :bit_flags) attributes.each.with_index do |attribute, i| bit_flag = 1 << i + field_was = "#{field}_was" define_method(attribute) do send(field) & bit_flag > 0 @@ -15,6 +16,14 @@ module HasBitFlags send(field) & bit_flag > 0 end + define_method("#{attribute}_was") do + send(field_was) & bit_flag > 0 + end + + define_method("#{attribute}_was?") do + send(field_was) & bit_flag > 0 + end + define_method("#{attribute}=") do |val| if val.to_s =~ /[t1y]/ send("#{field}=", send(field) | bit_flag) diff --git a/app/models/user.rb b/app/models/user.rb index 4ff18780c..74b21d966 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -103,6 +103,7 @@ class User < ApplicationRecord validates :per_page, inclusion: { in: (1..PostSets::Post::MAX_PER_PAGE) } validates :password, confirmation: true validates :comment_threshold, inclusion: { in: (-100..5) } + validate :validate_enable_private_favorites, on: :update before_validation :normalize_blacklisted_tags before_create :promote_to_owner_if_first_user has_many :artist_versions, foreign_key: :updater_id @@ -192,6 +193,14 @@ class User < ApplicationRecord end end + concerning :ValidationMethods do + def validate_enable_private_favorites + if enable_private_favorites_was == false && enable_private_favorites == true && !Pundit.policy!(self, self).can_enable_private_favorites? + errors.add(:base, "Can't enable privacy mode without a Gold account") + end + end + end + concerning :AuthenticationMethods do def password=(new_password) @password = new_password diff --git a/app/policies/user_policy.rb b/app/policies/user_policy.rb index ebf97d350..75ae4deb5 100644 --- a/app/policies/user_policy.rb +++ b/app/policies/user_policy.rb @@ -31,6 +31,10 @@ class UserPolicy < ApplicationPolicy user.is_admin? || record.id == user.id || !record.enable_private_favorites? end + def can_enable_private_favorites? + user.is_gold? + end + def permitted_attributes_for_create [:name, :password, :password_confirmation, { email_address_attributes: [:address] }] end diff --git a/app/views/users/edit.html.erb b/app/views/users/edit.html.erb index fe556b763..0d7487658 100644 --- a/app/views/users/edit.html.erb +++ b/app/views/users/edit.html.erb @@ -63,7 +63,13 @@ <%= f.input :hide_deleted_posts, :as => :select, :label => "Deleted post filter", :hint => "Remove deleted posts from search results", :include_blank => false, :collection => [["Yes", "true"], ["No", "false"]] %> <%= f.input :show_deleted_children, :as => :select, :label => "Show deleted children", :hint => "Show thumbnail borders on parent posts even if the children are deleted", :include_blank => false, :collection => [["Yes", "true"], ["No", "false"]] %> <%= f.input :disable_categorized_saved_searches, :hint => "Don't show dialog box when creating a new saved search", :as => :select, :collection => [["No", "false"], ["Yes", "true"]], :include_blank => false %> - <%= f.input :enable_private_favorites, :label => "Private favorites and votes", :as => :select, :hint => "Make your favorites and upvotes private", :collection => [["No", "false"], ["Yes", "true"]], :include_blank => false %> + <% if policy(@user).can_enable_private_favorites? %> + <%= f.input :enable_private_favorites, label: "Private favorites and votes", as: :select, hint: "Make your favorites and upvotes private", collection: { "No" => false, "Yes" => true }, include_blank: false %> + <% elsif @user.enable_private_favorites? %> + <%= f.input :enable_private_favorites, label: "Private favorites and votes", as: :select, hint: "Make your favorites and upvotes private. (Warning: if you disable this, you can't re-enable it without ".html_safe + link_to("upgrading to a Gold account", new_user_upgrade_path) + " first. (".html_safe + link_to_wiki("learn more", "help:privacy_mode") + ")".html_safe, collection: { "No" => false, "Yes" => true }, include_blank: false %> + <% else %> + <%= f.input :enable_private_favorites, label: "Private favorites and votes", as: :select, hint: link_to("Upgrade to Danbooru Gold to enable private favorites and upvotes", new_user_upgrade_path), collection: { "No" => false, "Yes" => true }, include_blank: false %> + <% end %> <%= f.input :disable_tagged_filenames, :as => :select, :hint => "Don't include tags in image filenames", :collection => [["No", "false"], ["Yes", "true"]], :include_blank => false %> <%= f.input :disable_mobile_gestures, :as => :select, :hint => "Disable swipe left / swipe right gestures on mobile", :collection => [["No", "false"], ["Yes", "true"]], :include_blank => false %> <%= f.input :disable_post_tooltips, :as => :select, :hint => "Disable advanced tooltips when hovering over thumbnails", :collection => [["No", "false"], ["Yes", "true"]], :include_blank => false %> diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb index e71d27c12..8053f0ddb 100644 --- a/test/functional/users_controller_test.rb +++ b/test/functional/users_controller_test.rb @@ -420,6 +420,34 @@ class UsersControllerTest < ActionDispatch::IntegrationTest assert_equal("xyz", @user.favorite_tags) end + context "for a Member-level user" do + should "allow disabling the private favorites option" do + @user = create(:user, enable_private_favorites: true) + put_auth user_path(@user), @user, params: { user: { enable_private_favorites: false }} + + assert_redirected_to edit_user_path(@user) + assert_equal(false, @user.reload.enable_private_favorites) + end + + should "not allow enabling the private favorites option" do + @user = create(:user, enable_private_favorites: false) + put_auth user_path(@user), @user, params: { user: { enable_private_favorites: true }} + + assert_redirected_to edit_user_path(@user) + assert_equal(false, @user.reload.enable_private_favorites) + end + end + + context "for a Gold-level user" do + should "allow enabling the private favorites option" do + @user = create(:gold_user, enable_private_favorites: false) + put_auth user_path(@user), @user, params: { user: { enable_private_favorites: true }} + + assert_redirected_to edit_user_path(@user) + assert_equal(true, @user.reload.enable_private_favorites) + end + end + context "changing the level" do should "not work" do @owner = create(:owner_user)