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
This commit is contained in:
@@ -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%;
|
||||
}
|
||||
|
||||
+3
-3
@@ -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 }
|
||||
|
||||
@@ -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?
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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 %>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<div hidden class="bubble bubble--<%= style %>"
|
||||
<div hidden class="bubble bubble--<%= card.engagement_status %>"
|
||||
data-controller="bubble" data-action="turbo:morph-element->bubble#update"
|
||||
data-bubble-reminder-before-value="<%= Card::AUTO_CLOSE_REMINDER_BEFORE.in_days.to_i %>"
|
||||
data-bubble-reminder-before-value="<%= Card::ENTROPY_REMINDER_BEFORE.in_days.to_i %>"
|
||||
data-bubble-closes-at-value="<%= card.auto_close_at.iso8601 %>"
|
||||
data-bubble-entropy-action-value="<%= card_entropy_action(card) %>">
|
||||
<svg viewBox="0 0 200 100">
|
||||
|
||||
@@ -26,30 +26,4 @@ class Card::CloseableTest < ActiveSupport::TestCase
|
||||
cards(:logo).update! last_active_at: 2.day.ago
|
||||
assert_equal (123-2).days.from_now, cards(:logo).auto_close_at
|
||||
end
|
||||
|
||||
test "auto close all due" do
|
||||
cards(:logo, :shipping).each(&:reconsider)
|
||||
|
||||
cards(:logo).update!(last_active_at: 1.day.ago - collections(:writebook).auto_close_period)
|
||||
cards(:shipping).update!(last_active_at: 1.day.from_now - collections(:writebook).auto_close_period)
|
||||
|
||||
assert_difference -> { Card.closed.count }, +1 do
|
||||
Card.auto_close_all_due
|
||||
end
|
||||
|
||||
assert cards(:logo).reload.closed?
|
||||
assert_not cards(:shipping).reload.closed?
|
||||
end
|
||||
|
||||
test "don't auto close those cards where the collection has no auto close period" do
|
||||
cards(:logo, :shipping).each(&:reconsider)
|
||||
|
||||
collections(:writebook).update auto_close_period: nil
|
||||
|
||||
assert_no_difference -> { Card.closed.count } do
|
||||
Card.auto_close_all_due
|
||||
end
|
||||
|
||||
assert_not cards(:logo).reload.closed?
|
||||
end
|
||||
end
|
||||
|
||||
@@ -11,6 +11,9 @@ class Card::EngageableTest < ActiveSupport::TestCase
|
||||
|
||||
assert_not cards(:logo).considering?
|
||||
assert cards(:text).considering?
|
||||
|
||||
assert_equal "doing", cards(:logo).engagement_status
|
||||
assert_equal "considering", cards(:text).engagement_status
|
||||
end
|
||||
|
||||
test "change the engagement" do
|
||||
@@ -46,21 +49,4 @@ class Card::EngageableTest < ActiveSupport::TestCase
|
||||
assert_includes Card.considering, cards(:text)
|
||||
assert_not_includes Card.considering, cards(:logo)
|
||||
end
|
||||
|
||||
test "auto_reconsider_all_stagnated" do
|
||||
travel_to Time.current
|
||||
|
||||
cards(:logo, :shipping).each(&:engage)
|
||||
|
||||
cards(:logo).update!(last_active_at: 1.day.ago - Card::Engageable::STAGNATED_AFTER)
|
||||
cards(:shipping).update!(last_active_at: 1.day.from_now - Card::Engageable::STAGNATED_AFTER)
|
||||
|
||||
assert_difference -> { Card.considering.count }, +1 do
|
||||
Card.auto_reconsider_all_stagnated
|
||||
end
|
||||
|
||||
assert cards(:shipping).reload.doing?
|
||||
assert cards(:logo).reload.considering?
|
||||
assert_equal Time.current, cards(:logo).last_active_at
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
require "test_helper"
|
||||
|
||||
class Card::EntropyTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
Current.session = sessions(:david)
|
||||
end
|
||||
|
||||
test "auto close all due" do
|
||||
cards(:logo, :shipping).each(&:reconsider)
|
||||
|
||||
cards(:logo).update!(last_active_at: 1.day.ago - collections(:writebook).auto_close_period)
|
||||
cards(:shipping).update!(last_active_at: 1.day.from_now - collections(:writebook).auto_close_period)
|
||||
|
||||
assert_difference -> { Card.closed.count }, +1 do
|
||||
Card.auto_close_all_due
|
||||
end
|
||||
|
||||
assert cards(:logo).reload.closed?
|
||||
assert_not cards(:shipping).reload.closed?
|
||||
end
|
||||
|
||||
test "don't auto close those cards where the collection has no auto close period" do
|
||||
cards(:logo, :shipping).each(&:reconsider)
|
||||
|
||||
collections(:writebook).update auto_close_period: nil
|
||||
|
||||
assert_no_difference -> { Card.closed.count } do
|
||||
Card.auto_close_all_due
|
||||
end
|
||||
|
||||
assert_not cards(:logo).reload.closed?
|
||||
end
|
||||
|
||||
test "auto_reconsider_all_stagnated" do
|
||||
travel_to Time.current
|
||||
|
||||
cards(:logo, :shipping).each(&:engage)
|
||||
|
||||
cards(:logo).update!(last_active_at: 1.day.ago - Card::AUTO_RECONSIDER_PERIOD)
|
||||
cards(:shipping).update!(last_active_at: 1.day.from_now - Card::AUTO_RECONSIDER_PERIOD)
|
||||
|
||||
assert_difference -> { Card.considering.count }, +1 do
|
||||
Card.auto_reconsider_all_stagnated
|
||||
end
|
||||
|
||||
assert cards(:shipping).reload.doing?
|
||||
assert cards(:logo).reload.considering?
|
||||
assert_equal Time.current, cards(:logo).last_active_at
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user