app/mailers/weekly_digest_mailer.rb
# TODO extract this from this project.
# TODO, Write all the specs
class WeeklyDigestMailer < ApplicationMailer
add_template_helper(UsersHelper)
add_template_helper(ProtipsHelper)
add_template_helper(ApplicationHelper)
def self.queue
:digest_mailer
end
SPAM_NOTICE = "You're receiving this email because you signed up for Coderwall. We hate spam and make an effort to keep notifications to a minimum. To change your notification preferences, you can update your email settings here: http://coderwall.com/settings#email or immediately unsubscribe by clicking this link %unsubscribe_url%"
WEEKLY_DIGEST_EVENT = 'weekly_digest'
#################################################################################
def weekly_digest(username)
headers['X-Mailgun-Variables'] = {email_type: WEEKLY_DIGEST_EVENT}.to_json
track_campaign(WEEKLY_DIGEST_EVENT)
@user = User.find_by_username(username)
since = [@user.last_request_at || Time.at(0), 1.week.ago].min
# benchmark "digest:stats" do
@stats = @user.activity_stats(since, true).sort_by { |stat, count| -(count || 0) }
#@networks = @user.following_networks.most_protips
@user.touch(:last_email_sent)
@issue = weekly_digest_utm
#
# benchmark "digest:protips" do
@protips = protips_for(@user, 6)
abort_delivery if @protips.blank? || @protips.count < 4
# benchmark "digest:stars" do
stars = @user.following_users.where('last_request_at > ?', 1.month.ago)
@star_stat = star_stat_for_this_week
@star_stat_string = STARS[@star_stat]
@most = star_stats(stars).sort_by { |star| -star[@star_stat] }.first
@most = nil if @most && (@most[@star_stat] <= 0)
# benchmark "digest:team" do
@team, @job = get_team_and_job_for(@user)
# benchmark "digest:mark_sent" do
mark_sent(@job) unless @job.nil?
mail to: @user.email, subject: "#{ACTIVITY_SUBJECT_PREFIX} #{weekly_digest_subject_for(@user, @stats, @most)}"
rescue Exception => e
abort_delivery(e)
end
#################################################################################
def abort_delivery(error=nil)
#self.perform_deliveries = false
Rails.logger.error "sending bad email:#{error.message}"
end
private
def track_campaign(id)
headers['X-Mailgun-Campaign-Id'] = id
end
def benchmark(message, options={})
Rails.env.development? ? super(message, options) : yield
end
def weekly_digest_subject_for(user, stats, most)
stat_mention = (stats.first && (stats.first[1] >= 5) && "including #{stats.first[1]} new #{stats.first[0].to_s.humanize.downcase}") || nil
"Your weekly brief #{stat_mention} "
end
def star_stats(stars, since=1.week.ago)
stars.collect { |star| star.activity_stats(since, true) }.each_with_index.map { |stat, index| stat.merge(user: stars[index]) }
end
def protips_for(user, how_many=6)
if user.last_request_at && user.last_request_at < 5.days.ago
protips = Protip.trending_for_user(user).first(how_many)
protips += Protip.trending.first(how_many-protips.count) if protips.count < how_many
else
protips = Protip.hawt_for_user(user).results.first(how_many)
protips +=Protip.hawt.results.first(how_many) if protips.count < how_many
end
protips
end
def mark_all_sent(mailables)
mailables.map { |mailable| mark_sent(mailable) }
end
def mark_sent(mailable)
SentMail.create!(user: @user, sent_at: @user.last_email_sent, mailable: mailable)
end
def already_sent?(mailable, user)
SentMail.where(user_id: user.id, mailable_id: mailable.id, mailable_type: mailable.class.name).exists?
end
STARS = {protip_upvotes: "pro tip upvotes", followers: "followers", endorsements: "endorsements", protips_count: "protips"}
def star_stat_for_this_week
STARS.keys[week_of_the_month % 4]
end
def week_of_the_month
Date.today.cweek - Date.today.at_beginning_of_month.cweek
end
def teams_for_user(user)
Team.most_relevant_featured_for(user).select { |team| team.hiring? }
end
def weekly_digest_utm
{
utm_campaign: "weekly_digest",
utm_content: Date.today.midnight,
utm_medium: "email"
}
end
def get_team_and_job_for(user)
if user.team.try(:hiring?)
[user.team, user.team.jobs.sample]
else
teams = teams_for_user(user)
teams.each do |team|
best_job = team.best_positions_for(user).detect { |job| (job.team_id == user.team_id) or !already_sent?(job, user) }
return [team, best_job] unless best_job.nil?
end
end
[nil, nil]
end
end