Refactor to introduce an entropy model

Instead of keeping two tracks of similar logic (auto-reconsider / auto-close).
This commit is contained in:
Jorge Manrubia
2025-06-04 14:38:22 +02:00
parent 407141f376
commit db86d17880
11 changed files with 73 additions and 74 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
class Account < ApplicationRecord
include Entropy, Joinable
include Entropic, Joinable
has_many_attached :uploads
end
@@ -1,4 +1,4 @@
module Account::Entropy
module Account::Entropic
extend ActiveSupport::Concern
included do
+1 -1
View File
@@ -1,5 +1,5 @@
class Card < ApplicationRecord
include Assignable, Colored, Engageable, Entropy, Eventable,
include Assignable, Colored, Engageable, Entropic, Eventable,
Golden, Mentions, Pinnable, Closeable, Readable, Searchable,
Staged, Statuses, Taggable, Watchable
+35
View File
@@ -0,0 +1,35 @@
module Card::Entropic
extend ActiveSupport::Concern
included do
scope :entropic_by, ->(period_name) do
left_outer_joins(collection: :entropy_configuration)
.where("last_active_at <= DATETIME('now', '-' || COALESCE(entropy_configurations.#{period_name}, ?) || ' seconds')",
Entropy::Configuration.default.public_send(period_name))
end
scope :stagnated, -> { doing.entropic_by(:auto_reconsider_period) }
scope :due_to_be_closed, -> { considering.entropic_by(:auto_close_period) }
delegate :auto_close_period, :auto_reconsider_period, to: :collection
end
class_methods do
def auto_close_all_due
due_to_be_closed.find_each do |card|
card.close(user: User.system, reason: "Closed")
end
end
def auto_reconsider_all_stagnated
stagnated.find_each(&:reconsider)
end
end
def entropy
Card::Entropy.for(self)
end
def has_entropy?
entropy.present?
end
end
+14 -52
View File
@@ -1,62 +1,24 @@
module Card::Entropy
extend ActiveSupport::Concern
class Card::Entropy
attr_reader :card, :auto_clean_period
AUTO_RECONSIDER_PERIOD = 30.days
ENTROPY_REMINDER_BEFORE = 7.days
class << self
def for(card)
return unless card.last_active_at
included do
scope :entropic_by, ->(period_name) do
left_outer_joins(collection: :entropy_configuration)
.where("last_active_at <= DATETIME('now', '-' || COALESCE(entropy_configurations.#{period_name}, ?) || ' seconds')",
Entropy::Configuration.default.public_send(period_name))
end
scope :stagnated, -> { doing.entropic_by(:auto_reconsider_period) }
scope :due_to_be_closed, -> { considering.entropic_by(:auto_close_period) }
delegate :auto_close_period, :auto_reconsider_period, to: :collection
end
class_methods do
def auto_close_all_due
due_to_be_closed.find_each do |card|
card.close(user: User.system, reason: "Closed")
if card.considering?
new(card, card.auto_close_period)
elsif card.doing?
new(card, card.auto_reconsider_period)
end
end
def auto_reconsider_all_stagnated
stagnated.find_each(&:reconsider)
end
end
def subject_to_entropy?
auto_reconsidering? || auto_closing?
def initialize(card, auto_clean_period)
@card = card
@auto_clean_period = auto_clean_period
end
def auto_reconsidering?
doing? && last_active_at
end
def auto_closing?
considering? && last_active_at
end
def auto_close_at
last_active_at + auto_close_period if auto_closing?
end
def days_until_close
(auto_close_at.to_date - Date.current).to_i if auto_close_at
end
def auto_reconsider_at
last_active_at + auto_reconsider_period if auto_reconsidering?
end
def days_until_reconsider
(auto_reconsider_at.to_date - Date.current).to_i if auto_reconsider_at
end
def entropy_cleaned_at
auto_close_at || auto_reconsider_at
def auto_clean_at
card.last_active_at + auto_clean_period
end
end
+1 -1
View File
@@ -1,5 +1,5 @@
class Collection < ApplicationRecord
include AutoClosing, Accessible, Broadcastable, Entropy, Filterable, Workflowing
include AutoClosing, Accessible, Broadcastable, Entropic, Filterable, Workflowing
belongs_to :creator, class_name: "User", default: -> { Current.user }
@@ -1,4 +1,4 @@
module Collection::Entropy
module Collection::Entropic
extend ActiveSupport::Concern
included do
+6 -4
View File
@@ -22,10 +22,12 @@
</details>
<span class="card-perma__closure-message">
<% if card.doing? %>
Falls back to <em>Considering</em> if no activity <%= local_datetime_tag(card.auto_reconsider_at, style: :indays) -%>.
<% elsif card.auto_closing? %>
Auto-closes if no activity <%= local_datetime_tag(card.auto_close_at, style: :indays) -%>.
<% if card.has_entropy? %>
<% if card.doing? %>
Falls back to <em>Considering</em> if no activity <%= local_datetime_tag(card.entropy.auto_clean_at, style: :indays) -%>.
<% else %>
Auto-closes if no activity <%= local_datetime_tag(card.entropy.auto_clean_at, style: :indays) -%>.
<% end %>
<% end %>
</span>
<% end %>
+1 -1
View File
@@ -29,7 +29,7 @@
<%= render "cards/display/common/background", card: card %>
<% if card.subject_to_entropy? %>
<% if card.has_entropy? %>
<%= render "cards/display/preview/bubble", card: card %>
<% end %>
<% end %>
@@ -1,7 +1,7 @@
<div hidden class="bubble bubble--<%= card.engagement_status %>"
data-controller="bubble" data-action="turbo:morph-element->bubble#update"
data-bubble-reminder-before-value="<%= Card::ENTROPY_REMINDER_BEFORE.in_days.to_i %>"
data-bubble-closes-at-value="<%= card.entropy_cleaned_at.iso8601 %>"
data-bubble-reminder-before-value="<%= card.entropy.auto_clean_period.seconds.in_days.to_i %>"
data-bubble-closes-at-value="<%= card.entropy.auto_clean_at.iso8601 %>"
data-bubble-entropy-action-value="<%= card_entropy_action(card) %>">
<svg viewBox="0 0 200 100">
<path id="top-half" fill="transparent" d="M 20,100 A 80,80 0 0,1 180,100" />
@@ -1,6 +1,6 @@
require "test_helper"
class Card::EntropyTest < ActiveSupport::TestCase
class Card::EntropicTest < ActiveSupport::TestCase
setup do
Current.session = sessions(:david)
end
@@ -11,7 +11,7 @@ class Card::EntropyTest < ActiveSupport::TestCase
entropy_configurations(:writebook_collection).destroy
entropy_configurations("37s_account").reload.update! auto_close_period: 456.days
cards(:layout).update! last_active_at: 2.day.ago
assert_equal (456 - 2).days.from_now, cards(:layout).auto_close_at
assert_equal (456 - 2).days.from_now, cards(:layout).entropy.auto_clean_at
end
test "auto_close_at infers the period from the collection when present" do
@@ -19,7 +19,7 @@ class Card::EntropyTest < ActiveSupport::TestCase
entropy_configurations(:writebook_collection).update! auto_close_period: 123.days
cards(:layout).update! last_active_at: 2.day.ago
assert_equal (123 - 2).days.from_now, cards(:layout).auto_close_at
assert_equal (123 - 2).days.from_now, cards(:layout).entropy.auto_clean_at
end
test "auto_reconsider_at uses the period defined in the account by default" do
@@ -29,7 +29,7 @@ class Card::EntropyTest < ActiveSupport::TestCase
entropy_configurations(:writebook_collection).destroy
entropy_configurations("37s_account").reload.update! auto_reconsider_period: 456.days
cards(:layout).update! last_active_at: 2.day.ago
assert_equal (456 - 2).days.from_now, cards(:layout).auto_reconsider_at
assert_equal (456 - 2).days.from_now, cards(:layout).entropy.auto_clean_at
end
test "auto_reconsider_at infers the period from the collection when present" do
@@ -38,7 +38,7 @@ class Card::EntropyTest < ActiveSupport::TestCase
cards(:layout).engage
entropy_configurations(:writebook_collection).update! auto_reconsider_period: 123.days
cards(:layout).update! last_active_at: 2.day.ago
assert_equal (123 - 2).days.from_now, cards(:layout).auto_reconsider_at
assert_equal (123 - 2).days.from_now, cards(:layout).entropy.auto_clean_at
end
test "auto close all due using the default account entropy configuration" do
@@ -105,11 +105,11 @@ class Card::EntropyTest < ActiveSupport::TestCase
assert_equal Time.current, cards(:logo).last_active_at
end
test "entropy_cleaned_at returns when the entropy will be cleaned" do
assert_equal cards(:layout).auto_close_at, cards(:layout).entropy_cleaned_at
assert_not_nil cards(:layout).entropy_cleaned_at
test ".entropy.auto_clean_at returns when the entropy will be cleaned" do
assert_equal cards(:layout).entropy.auto_clean_at, cards(:layout).entropy.auto_clean_at
assert_not_nil cards(:layout).entropy.auto_clean_at
assert_equal cards(:logo).auto_reconsider_at, cards(:logo).entropy_cleaned_at
assert_not_nil cards(:logo).entropy_cleaned_at
assert_equal cards(:logo).entropy.auto_clean_at, cards(:logo).entropy.auto_clean_at
assert_not_nil cards(:logo).entropy.auto_clean_at
end
end