votes: make private favorites and upvotes a Gold-only option.

Make private favorites and upvotes a Gold-only account option.

Existing Members with private favorites enabled are allowed to keep it
enabled, as long as they don't disable it. If they disable it, then they
can't re-enable it again without upgrading to Gold first.

This is a Gold-only option to prevent uploaders from creating multiple
accounts to upvote their own posts. If private upvotes were allowed for
Members, then it would be too easy to use fake accounts and private
upvotes to upvote your own posts.
This commit is contained in:
evazion
2021-11-16 17:09:06 -06:00
parent 055e5939b4
commit bc96eb864b
5 changed files with 57 additions and 1 deletions

View File

@@ -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)

View File

@@ -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

View File

@@ -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

View File

@@ -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 %>

View File

@@ -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)