docbrown/app/services/calculate_reaction_points.rb
Joshua Wehner 3f26694976
Refactor reaction categories as abstract class collection (#18540)
* Try a ReactionCategory abstract 'model'

* Use ReactionCategory

* Lookup category, pre-reaction

* Lookup category > constant

* Category can sometimes be nil?

* Try something friendlier for code reloading

* Refactor: extract point calculation out of Reaction

* Reaction Category can have color

* Rename reaction points service to follow convention

* method signature changed as well, calculate -> call

* Fix typo, leading comment, and rename data structures for clarity
2022-11-01 10:50:37 +01:00

77 lines
2 KiB
Ruby

# Reaction uses this class to calculate points before saving
class CalculateReactionPoints
DEFAULT_SCORE = 1.0
POINTS = {
"invalid" => 0,
"User" => 2,
"confirmed" => 2,
"positive" => 5,
"negative" => -5
}.freeze
# Days to ramp up new user points weight
NEW_USER_RAMPUP_DAYS_COUNT = 10
def self.call(reaction)
new(reaction).calculate_points
end
def initialize(reaction)
@reaction = reaction
end
def calculate_points
base_points = reaction_category_score
# Adjust for certain states
base_points = POINTS["invalid"] if status == "invalid"
base_points /= POINTS["User"] if reactable_type == "User"
base_points *= POINTS["confirmed"] if status == "confirmed"
unless persisted? # Actions we only want to apply upon initial creation
# Author's comment reaction counts for more weight on to their own posts. (5.0 vs 1.0)
base_points *= POINTS["positive"] if positive_reaction_to_comment_on_own_article?
# New users will have their reaction weight gradually ramp by 0.1 from 0 to 1.0.
base_points *= new_user_adjusted_points if new_untrusted_user # New users get minimal reaction weight
end
user ? (base_points * user.reputation_modifier) : POINTS["negative"]
end
attr_reader :reaction
delegate :category, :persisted?, :positive?, :reactable, :reactable_type, :status, :user, :user_id,
to: :reaction
private
def reaction_category
ReactionCategory[category]
end
def reaction_category_score
reaction_category&.score || DEFAULT_SCORE
end
def new_untrusted_user
user.registered_at > NEW_USER_RAMPUP_DAYS_COUNT.days.ago && !user.trusted? && !user.any_admin?
end
def new_user_adjusted_points
((Time.current - user.registered_at).seconds.in_days / NEW_USER_RAMPUP_DAYS_COUNT)
end
def positive_reaction_to_comment_on_own_article?
positive? && reaction_to_comment? && own_article?
end
def reaction_to_comment?
reactable_type == "Comment"
end
def own_article?
reactable&.commentable&.user_id == user_id
end
end