docbrown/app/labor/email_logic.rb
rhymes 6553f08d94 Rubocop cleanups (#1415)
* Update rubocop-todo.yml with new violations

* Fix Layout/EmptyLine* rules

* Fix Layout/Indentation* rules

* Fix remaining Layout/* rules

* Fix Lint/DuplicateMethods by removing unused accessor

* Fix Lint/IneffectiveAccessModifier

* Fix Lint/MissingCopEnableDirective

* Re-run rubocop auto gen config

* Fix Layout/RescueEnsureAlignment

* Fix Naming/* rules

* Fix some RSpec/* rules

* Fix typos

* Fix RSpec/LetBeforeExamples

* Series should only be an attr_writer, not an attr_accessor

* Fix RSpec/InstanceVariable

* Fix RSpec/InstanceVariable

* Fix RSpec/RepeatedDescription and RSpec/RepeatedExample

* Fix Style/ClassAndModuleChildren

* Fix Style/ConditionalAssignment

* Fix some Style/* rules

* Trigger Travis CI build because failing tests are not failing locally

* Revert "Fix Style/ClassAndModuleChildren"

This reverts commit 1686801d8a1516ba1894f79e24401a20dea65f99.
2019-01-02 11:20:02 -05:00

99 lines
3.2 KiB
Ruby

class EmailLogic
attr_reader :open_percentage, :last_email_sent_at,
:days_until_next_email, :articles_to_send
def initialize(user)
@user = user
@open_percentage = nil
@ready_to_receive_email = nil
@last_email_sent_at = nil
@days_until_next_email = nil
@articles_to_send = []
end
def analyze
@last_email_sent_at = get_last_digest_email_user_received
@open_percentage = get_open_rate
@days_until_next_email = get_days_until_next_email
@ready_to_receive_email = get_user_readiness
if @ready_to_receive_email
@articles_to_send = get_articles_to_send
end
self
end
def should_receive_email?
@ready_to_receive_email
end
private
def get_articles_to_send
fresh_date = get_fresh_date
articles = if user_has_followings?
@user.followed_articles.
where("published_at > ?", fresh_date).
where(published: true, email_digest_eligible: true).
where.not(user_id: @user.id).
where("positive_reactions_count > ?", 15).
order("positive_reactions_count DESC").
limit(6)
else
Article.
where("published_at > ?", fresh_date).
where(published: true, featured: true, email_digest_eligible: true).
where.not(user_id: @user.id).
where("positive_reactions_count > ?", 30).
order("positive_reactions_count DESC").
limit(6)
end
if articles.length < 3
@ready_to_receive_email = false
end
articles
end
def get_days_until_next_email
# Relies on hyperbolic tangent function to model the frequency of the digest email
max_day = ApplicationConfig["PERIODIC_EMAIL_DIGEST_MAX"].to_i
min_day = ApplicationConfig["PERIODIC_EMAIL_DIGEST_MIN"].to_i
result = max_day * (1 - Math.tanh(2 * @open_percentage))
result = result.round
result < min_day ? min_day : result
end
def get_open_rate
past_sent_emails = @user.email_messages.where(mailer: "DigestMailer#digest_email").limit(10)
# Will stick with 50% open rate if @user has no/not-enough email digest history
return 0.5 if past_sent_emails.length < 10
past_sent_emails_count = past_sent_emails.count
past_opened_emails_count = past_sent_emails.where("opened_at IS NOT NULL").count
past_opened_emails_count / past_sent_emails_count
end
def get_user_readiness
return true unless @last_email_sent_at
# Has it been at least x days since @user received an email?
Time.current - @last_email_sent_at >= @days_until_next_email.days.to_i
end
def get_last_digest_email_user_received
@user.email_messages.where(mailer: "DigestMailer#digest_email").last&.sent_at
end
def get_fresh_date
a_few_days_ago = 4.days.ago.utc
return a_few_days_ago unless @last_email_sent_at
a_few_days_ago > @last_email_sent_at ? a_few_days_ago : @last_email_sent_at
end
def user_has_followings?
following_users = @user.cached_following_users_ids
following_tags = @user.cached_followed_tag_names
following_users.any? || following_tags.any?
end
end