Add protection against reactions to unpublished articles (#473)

This commit is contained in:
Ben Halpern 2018-06-21 15:44:04 -04:00 committed by GitHub
parent ff36271108
commit 1127b2e61b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 21 additions and 2 deletions

View file

@ -10,7 +10,7 @@ class Reaction < ApplicationRecord
validates :category, inclusion: { in: %w(like thinking hands unicorn thumbsdown vomit readinglist) }
validates :reactable_type, inclusion: { in: %w(Comment Article) }
validates :user_id, uniqueness: {:scope => [:reactable_id, :reactable_type, :category]}
validate :user_permissions
validate :permissions
before_save :assign_points
after_save :update_reactable
@ -79,6 +79,7 @@ class Reaction < ApplicationRecord
CacheBuster.new.bust "/reactions/logged_out_reaction_counts?commentable_id=#{reactable.commentable_id}&commentable_type=#{reactable.commentable_type}"
end
CacheBuster.new.bust user.path
occasionally_sync_reaction_counts
end
handle_asynchronously :update_reactable
@ -114,9 +115,19 @@ class Reaction < ApplicationRecord
self.points = user ? (base_points * user.reputation_modifier) : -5
end
def user_permissions
def permissions
if category == "vomit" || category == "thumbsdown"
errors.add(:category, "is not valid.") unless user.has_role?(:trusted)
end
if reactable_type == "Article" && !reactable.published
errors.add(:reactable_id, "is not valid.")
end
end
def occasionally_sync_reaction_counts
# Fixes any out-of-sync positive_reactions_count
if rand(6) == 1 || reactable.positive_reactions_count.negative?
reactable.update_column(:positive_reactions_count, reactable.reactions.where("points > ?", 0).size)
end
end
end

View file

@ -28,6 +28,14 @@ RSpec.describe Reaction, type: :model do
expect(reaction).not_to be_valid
end
it "does not allow reaction on unpublished article" do
reaction = build(:reaction, user_id: user.id, reactable_id: article.id, reactable_type: "Article")
expect(reaction).to be_valid
article.update_column(:published, false)
reaction = build(:reaction, user_id: user.id, reactable_id: article.id, reactable_type: "Article")
expect(reaction).not_to be_valid
end
context "if user is trusted" do
before { user.add_role(:trusted) }