diff --git a/app/models/card.rb b/app/models/card.rb index e2191aa41..4c17269c9 100644 --- a/app/models/card.rb +++ b/app/models/card.rb @@ -1,6 +1,6 @@ class Card < ApplicationRecord include Assignable, Colored, DraftCommenting, Engageable, Eventable, Golden, - Messages, Notifiable, Pinnable, Closeable, Scorable, Searchable, Staged, + Messages, Notifiable, Pinnable, Closeable, Searchable, Staged, Statuses, Taggable, Watchable belongs_to :collection, touch: true @@ -21,12 +21,11 @@ class Card < ApplicationRecord scope :indexed_by, ->(index) do case index - when "most_active" then ordered_by_activity - when "newest" then reverse_chronologically - when "oldest" then chronologically - when "latest" then latest - when "stalled" then ordered_by_staleness - when "closed" then closed + when "newest" then reverse_chronologically + when "oldest" then chronologically + when "latest" then latest + when "stalled" then chronologically + when "closed" then closed end end diff --git a/app/models/card/scorable.rb b/app/models/card/scorable.rb deleted file mode 100644 index 91b0856b5..000000000 --- a/app/models/card/scorable.rb +++ /dev/null @@ -1,64 +0,0 @@ -module Card::Scorable - extend ActiveSupport::Concern - - REFERENCE_DATE = Time.utc(2025, 1, 1) - - included do - scope :ordered_by_activity, -> { order activity_score_order: :desc } - - # Staleness is measured by the amount of activity_score lost since it was last updated. - # The factor 0.9 is chosen to make the decay curve closer to linear; an exponential - # curve would make recent items appear stale very quickly, due to the sharp dropoff. - scope :ordered_by_staleness, -> { order Arel.sql( - "coalesce(activity_score * (1 - power(0.9, julianday('now') - julianday(activity_score_at))), 0) desc" - ) } - end - - def rescore - score = calculate_activity_score - score_at = last_scorable_activity_at - - update! \ - activity_score: score, - activity_score_at: score_at, - activity_score_order: event_score_reference(score, score_at) - end - - private - def calculate_activity_score - scorable_events.sum { |event| event_score(event) } - end - - def event_score(event) - days_ago = (last_scorable_activity_at - event.created_at) / 1.day - event_weight(event) / (2**days_ago) - end - - def event_weight(event) - case - when event.comment&.first_by_author_on_card? then 20 - when event.comment&.follows_comment_by_another_author? then 15 - when event.commented? then 10 - else 0 - end - end - - def event_score_reference(score, activity_at) - # The reference score is used to make the activity score comparable - # across different cards, since it represents the card's activity - # level at a consistent point in time. - # - # We store this as log2 to tame the huge/tiny numbers we'd otherwise get - # when activity is far from the reference date. - days_diff = (activity_at - REFERENCE_DATE) / 1.day - Math.log2(1.0 + score) + days_diff - end - - def last_scorable_activity_at - scorable_events.maximum(:created_at) || created_at - end - - def scorable_events - events.where(action: :commented) - end -end diff --git a/test/models/card/scorable_test.rb b/test/models/card/scorable_test.rb deleted file mode 100644 index f24785e63..000000000 --- a/test/models/card/scorable_test.rb +++ /dev/null @@ -1,12 +0,0 @@ -require "test_helper" - -class Card::ScorableTest < ActiveSupport::TestCase - test "cards with no activity have a valid activity_score_order" do - card = Card.create! collection: collections(:writebook), creator: users(:kevin) - - card.rescore - - assert card.activity_score.zero? - assert_not card.activity_score_order.infinite? - end -end