Skip to content

Updated Popular Protips emailer with New Relic promotion option #189

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Sep 2, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ gem 'awesome_print'
gem 'faraday', '~> 0.8.1'
gem 'metamagic'

gem "mail_view", "~> 2.0.4"

# ----------------


Expand Down
31 changes: 17 additions & 14 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,17 +1,3 @@
GIT
remote: git://github.com/emberjs/ember-rails.git
revision: 5e5a398f3c67c3a3b84b7513b93b22bf81055cc9
specs:
ember-rails (0.15.0)
active_model_serializers
barber (>= 0.4.1)
ember-data-source (>= 1.0.0.beta.5)
ember-source (>= 1.1.0)
execjs (>= 1.2)
handlebars-source (> 1.0.0)
jquery-rails (>= 1.0.17)
railties (>= 3.1)

GIT
remote: git://github.com/nixme/jazz_hands.git
revision: 5e4b48f145883ecb14b55bf04eacc28ac9662676
Expand All @@ -38,6 +24,20 @@ GIT
mime-types (>= 1.25, < 3.0)
rest-client (~> 1.4)

GIT
remote: git://github.com/emberjs/ember-rails.git
revision: 5e5a398f3c67c3a3b84b7513b93b22bf81055cc9
specs:
ember-rails (0.15.0)
active_model_serializers
barber (>= 0.4.1)
ember-data-source (>= 1.0.0.beta.5)
ember-source (>= 1.1.0)
execjs (>= 1.2)
handlebars-source (> 1.0.0)
jquery-rails (>= 1.0.17)
railties (>= 3.1)

GEM
remote: https://rubygems.org/
remote: https://rails-assets.org/
Expand Down Expand Up @@ -350,6 +350,8 @@ GEM
mail (2.5.4)
mime-types (~> 1.16)
treetop (~> 1.4.8)
mail_view (2.0.4)
tilt
memoizable (0.4.2)
thread_safe (~> 0.3, >= 0.3.1)
metamagic (3.1.6)
Expand Down Expand Up @@ -753,6 +755,7 @@ DEPENDENCIES
launchy
linkedin
local_time
mail_view (~> 2.0.4)
metamagic
mini_magick
mixpanel
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions app/clock.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
RefreshStaleUsersWorker.perform_async
end

# On the first of every month send the popular protips from the previous month.
every(1.day, 'protip_mailer:popular_protips', if: ->(t){ t.day == 1 }) do
last_month = 1.month.ago
ProtipMailerPopularProtipsWorker.perform_async(last_month.beginning_of_month, last_month.end_of_month)
end

every(1.day, 'cleanup:protips:associate_zombie_upvotes', at: '00:00') {}
every(1.day, 'clear_expired_sessions', at: '00:00') {}
every(1.day, 'facts:system', at: '00:00') {}
Expand Down
41 changes: 18 additions & 23 deletions app/helpers/protips_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -294,36 +294,35 @@ def user_upvoted?(protip)
current_user && current_user_upvotes.include?(protip.public_id)
end

def protip_stat_class(protip)
class_name = best_stat_name(protip)
#class_name << " " << (user_upvoted?(protip) ? "upvoted" : "")
end

def formatted_best_stat_value(protip)
value =
case best_stat_name(protip).to_sym
when :views
views_stat_value(protip)
else
best_stat_value(protip)
end
number_to_human(value, units: {unit: "", thousand: "k"})
value = case best_stat_name(protip).to_sym
when :views
views_stat_value(protip)
else
best_stat_value(protip)
end

number_to_human(value, units: { unit: '', thousand: 'k' })
end

def blur_protips?
params[:show_all].nil? && !signed_in?
def best_stat_name(protip)
protip.best_stat.is_a?(Tire::Results::Item) ? protip.best_stat.name : protip.best_stat[0]
end

def followings_fragment_cache_key(user_id)
['v1', 'followings_panel', user_id]
def views_stat_value(protip)
best_stat_value(protip) * Protip::COUNTABLE_VIEWS_CHUNK
end

def best_stat_value(protip)
protip.best_stat.is_a?(Tire::Results::Item) ? protip.best_stat.value.to_i : protip.best_stat[1]
end

def best_stat_name(protip)
protip.best_stat.is_a?(Tire::Results::Item) ? protip.best_stat.name : protip.best_stat[0]
def blur_protips?
params[:show_all].nil? && !signed_in?
end

def followings_fragment_cache_key(user_id)
['v1', 'followings_panel', user_id]
end

def protip_networks(protip)
Expand Down Expand Up @@ -354,10 +353,6 @@ def protip_display_mode
mobile_device? ? "fullpage" : "popup"
end

def views_stat_value(protip)
best_stat_value(protip) * Protip::COUNTABLE_VIEWS_CHUNK
end

def display_protip_stats?(protip)
stat_name = best_stat_name(protip)
# if stat is present, and the stat we're displaying is views over 50, display.
Expand Down
1 change: 1 addition & 0 deletions app/helpers/users_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ def users_image_tag(user, options = {})

#TODO Remove
def users_image_path(user)
return ''
user.avatar.url
end

Expand Down
15 changes: 15 additions & 0 deletions app/mailers/mail_preview.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
class MailPreview < MailView
USERNAME = 'just3ws'

def popular_protips
from = 60.days.ago
to = 0.days.ago
user = User.with_username(USERNAME)
protips = ProtipMailer::Queries.popular_protips(from, to)
ProtipMailer.popular_protips(user, protips, from, to).deliver
end

def old_weekly_digest
WeeklyDigestMailer.weekly_digest(USERNAME)
end
end
134 changes: 134 additions & 0 deletions app/mailers/protip_mailer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
class ProtipMailer < ActionMailer::Base
include ActionView::Helpers::TextHelper

add_template_helper(UsersHelper)
add_template_helper(ProtipsHelper)
add_template_helper(ApplicationHelper)

default_url_options[:host] = 'coderwall.com'
default_url_options[:only_path] = false
default from: '"Coderwall" <support@coderwall.com>'

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%"
STARS = {
protip_upvotes: 'pro tip upvotes',
followers: 'followers',
endorsements: 'endorsements',
protips_count: 'protips'
}
ACTIVITY_SUBJECT_PREFIX = '[Coderwall]'

#################################################################################
def popular_protips(user, protips, from, to)
fail 'Protips are required.' if protips.nil? || protips.empty?
fail 'User is required.' unless user
fail 'From date is required.' unless from
fail 'To date is required.' unless to

headers['X-Mailgun-Campaign-Id'] = 'protip_mailer-popular_protips'

@user = user
@protips = protips
@team, @job = get_team_and_job_for(@user)
@issue = campaign_params

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 do |star|
-star[@star_stat]
end.first
@most = nil if @most && (@most[@star_stat] <= 0)

mail(to: @user.email, subject: "#{ACTIVITY_SUBJECT_PREFIX} Popular Protips on Coderwall")
rescue Exception => ex
abort_delivery(ex)
end
#################################################################################

def abort_delivery(ex)
Rails.logger.error("[ProtipMailer.popular_protips] Aborted email '#{ex}' >>\n#{ex.backtrace.join("\n ")}")
end

def campaign_params
{
utm_campaign: 'coderwall-popular_protips',
utm_content: Date.today.midnight,
utm_medium: 'email'
}
end

def star_stat_for_this_week
STARS.keys[week_of_the_month % 4]
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 week_of_the_month
Date.today.cweek - Date.today.at_beginning_of_month.cweek
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 do |job|
job.team_document_id == user.team_document_id
end
return [team, best_job] unless best_job.nil?
end
end
[nil, nil]
end

def teams_for_user(user)
Team.most_relevant_featured_for(user).select do |team|
team.hiring?
end
end

module Queries
def self.popular_protips(from, to)
search_results = ProtipMailer::Queries.search_for_popular_protips(from, to)
public_ids = search_results.map { |protip| protip['public_id'] }

Protip.eager_load(:user, :comments).where('public_id in (?)', public_ids)
end

def self.search_for_popular_protips(from, to, max_results=10)
url = "#{ENV['ELASTICSEARCH_URL']}/#{ENV['ELASTICSEARCH_PROTIPS_INDEX']}/_search"
query = {
'query' => {
'bool' => {
'must' => [
{
'range' => {
'protip.created_at' => {
'from' => from.strftime('%Y-%m-%d'),
'to' => to.strftime('%Y-%m-%d')
}
}
}
]
}
},
'size' => max_results,
'sort' => [
{
'protip.popular_score' => {
'order' => 'desc'
}
}
]
}
response = RestClient.post(url, MultiJson.dump(query), content_type: :json, accept: :json)
# TODO: check for response code
MultiJson.load(response.body)['hits']['hits'].map { |protip| protip['_source'] }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WTF ?

end
end
end
47 changes: 23 additions & 24 deletions app/mailers/weekly_digest_mailer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
class WeeklyDigestMailer < ActionMailer::Base
include ActionView::Helpers::TextHelper
include ActiveSupport::Benchmarkable

add_template_helper(UsersHelper)
add_template_helper(ProtipsHelper)
add_template_helper(ApplicationHelper)
Expand All @@ -17,54 +18,52 @@ def self.queue

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'
ACTIVITY_SUBJECT_PREFIX = "[Coderwall]"

#################################################################################
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) }
end
# 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)
end
#
# 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)
end
# 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)
end
# benchmark "digest:team" do
@team, @job = get_team_and_job_for(@user)

benchmark "digest:mark_sent" do
mark_sent(@job) unless @job.nil?
end
# 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.message)
abort_delivery(e)
end
#################################################################################

def abort_delivery(message="")
def abort_delivery(error=nil)
#self.perform_deliveries = false
Rails.logger.error "sending bad email:#{message}"
Rails.logger.error "sending bad email:#{error.message}"
end

private
Expand All @@ -91,7 +90,7 @@ def protips_for(user, how_many=6)
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_for_user(user).results.first(how_many)
protips +=Protip.hawt.results.first(how_many) if protips.count < how_many
end
protips
Expand Down
Loading