From 28ed744d0c881a132ea31e16dbfaffc0747522c5 Mon Sep 17 00:00:00 2001 From: Mike Dalessio Date: Fri, 16 May 2025 10:35:51 -0400 Subject: [PATCH] refactor: Extract a Card::Entropy concern to encompass behavior related to auto-closing and auto-reconsidering. Note that putting this code in a single place reveals an asymmetry between the actions: - Auto-closing period is an optional attribute of a collection - Auto-reconsidering period is hard-coded to 30 days for all collections --- app/assets/stylesheets/bubble.css | 4 +- app/models/card.rb | 6 +-- app/models/card/closeable.rb | 26 ---------- app/models/card/engageable.rb | 22 +++----- app/models/card/entropy.rb | 47 +++++++++++++++++ app/views/cards/display/_preview.html.erb | 8 +-- .../cards/display/preview/_bubble.html.erb | 4 +- test/models/card/closeable_test.rb | 26 ---------- test/models/card/engageable_test.rb | 20 ++------ test/models/card/entropy_test.rb | 50 +++++++++++++++++++ 10 files changed, 117 insertions(+), 96 deletions(-) create mode 100644 app/models/card/entropy.rb create mode 100644 test/models/card/entropy_test.rb diff --git a/app/assets/stylesheets/bubble.css b/app/assets/stylesheets/bubble.css index 0b330b06a..43baf342b 100644 --- a/app/assets/stylesheets/bubble.css +++ b/app/assets/stylesheets/bubble.css @@ -52,12 +52,12 @@ } } -.bubble--closing { +.bubble--considering { inset-inline-start: calc(-1 * var(--bubble-gap)); translate: -100% -50%; } -.bubble--considering { +.bubble--doing { inset-inline-end: calc(-1 * var(--bubble-gap)); translate: 100% -50%; } diff --git a/app/models/card.rb b/app/models/card.rb index 69588ea88..bbb5e5843 100644 --- a/app/models/card.rb +++ b/app/models/card.rb @@ -1,7 +1,7 @@ class Card < ApplicationRecord - include Assignable, Colored, Engageable, Eventable, Golden, - Mentions, Pinnable, Closeable, Readable, Searchable, Staged, - Statuses, Taggable, Watchable + include Assignable, Colored, Engageable, Entropy, Eventable, + Golden, Mentions, Pinnable, Closeable, Readable, Searchable, + Staged, Statuses, Taggable, Watchable belongs_to :collection, touch: true belongs_to :creator, class_name: "User", default: -> { Current.user } diff --git a/app/models/card/closeable.rb b/app/models/card/closeable.rb index 46c3a9696..afcdbc53d 100644 --- a/app/models/card/closeable.rb +++ b/app/models/card/closeable.rb @@ -1,8 +1,6 @@ module Card::Closeable extend ActiveSupport::Concern - AUTO_CLOSE_REMINDER_BEFORE = 7.days - included do has_one :closure, dependent: :destroy @@ -10,30 +8,6 @@ module Card::Closeable scope :open, -> { where.missing(:closure) } scope :recently_closed_first, -> { closed.order("closures.created_at": :desc) } - scope :in_auto_closing_collection, -> { joins(:collection).merge(Collection.auto_closing) } - scope :due_to_be_closed, -> { considering.in_auto_closing_collection.where("last_active_at <= DATETIME('now', '-' || auto_close_period || ' seconds')") } - - delegate :auto_closing?, :auto_close_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 - end - - def auto_close_at - last_active_at + auto_close_period if auto_closing? && last_active_at - end - - def days_until_close - (auto_close_at.to_date - Date.current).to_i if auto_close_at - end - - def closing_soon? - considering? && auto_closing? && Time.current >= auto_close_at - AUTO_CLOSE_REMINDER_BEFORE end def closed? diff --git a/app/models/card/engageable.rb b/app/models/card/engageable.rb index aa5279d64..9db8e6a64 100644 --- a/app/models/card/engageable.rb +++ b/app/models/card/engageable.rb @@ -1,15 +1,11 @@ module Card::Engageable extend ActiveSupport::Concern - STAGNATED_AFTER = 30.days - AUTO_RECONSIDER_REMINDER_BEFORE = 7.days - included do has_one :engagement, dependent: :destroy, class_name: "Card::Engagement" scope :considering, -> { published_or_drafted_by(Current.user).open.where.missing(:engagement) } scope :doing, -> { published.open.joins(:engagement) } - scope :stagnated, -> { doing.where(last_active_at: ..STAGNATED_AFTER.ago) } scope :by_engagement_status, ->(status) do case status.to_s @@ -19,16 +15,6 @@ module Card::Engageable end end - class_methods do - def auto_reconsider_all_stagnated - stagnated.find_each(&:reconsider) - end - end - - def auto_reconsider_at - last_active_at + STAGNATED_AFTER if last_active_at - end - def doing? open? && published? && engagement.present? end @@ -37,6 +23,14 @@ module Card::Engageable open? && published? && engagement.blank? end + def engagement_status + if doing? + "doing" + elsif considering? + "considering" + end + end + def engage unless doing? transaction do diff --git a/app/models/card/entropy.rb b/app/models/card/entropy.rb new file mode 100644 index 000000000..b0eded7a3 --- /dev/null +++ b/app/models/card/entropy.rb @@ -0,0 +1,47 @@ +module Card::Entropy + extend ActiveSupport::Concern + + AUTO_RECONSIDER_PERIOD = 30.days + ENTROPY_REMINDER_BEFORE = 7.days + + included do + scope :in_auto_closing_collection, -> { joins(:collection).merge(Collection.auto_closing) } + + scope :stagnated, -> { doing.where(last_active_at: ..AUTO_RECONSIDER_PERIOD.ago) } + scope :due_to_be_closed, -> { considering.in_auto_closing_collection.where("last_active_at <= DATETIME('now', '-' || auto_close_period || ' seconds')") } + + delegate :auto_closing?, :auto_close_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 subject_to_entropy? + doing? || (auto_closing? && considering?) + end + + def auto_close_at + last_active_at + auto_close_period if auto_closing? && last_active_at + 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 last_active_at + end + + def days_until_reconsider + (auto_reconsider_at.to_date - Date.current).to_i if auto_reconsider_at + end +end diff --git a/app/views/cards/display/_preview.html.erb b/app/views/cards/display/_preview.html.erb index eadeadaba..071630a8d 100644 --- a/app/views/cards/display/_preview.html.erb +++ b/app/views/cards/display/_preview.html.erb @@ -33,12 +33,8 @@ <%= render "cards/display/common/background", card: card %> - <% if card.auto_closing? %> - <% if card.considering? %> - <%= render "cards/display/preview/bubble", card: card, style: "closing" %> - <% elsif card.doing? %> - <%= render "cards/display/preview/bubble", card: card, style: "considering" %> - <% end %> + <% if card.subject_to_entropy? %> + <%= render "cards/display/preview/bubble", card: card %> <% end %> <% end %> <% end %> diff --git a/app/views/cards/display/preview/_bubble.html.erb b/app/views/cards/display/preview/_bubble.html.erb index 13faa9920..c05989755 100644 --- a/app/views/cards/display/preview/_bubble.html.erb +++ b/app/views/cards/display/preview/_bubble.html.erb @@ -1,6 +1,6 @@ -