Last active
March 29, 2016 04:42
-
-
Save data-doge/7b06d01e6b05d1181c9b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ./lib/tasks/cobudget.rake | |
# scheduled to run every 10 minutes on our heroku server | |
namespace :cobudget do | |
desc "delivers recent activity digest emails to users" | |
task deliver_recent_activity_digest: :environment do | |
DeliverRecentActivityDigest.run! | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ./app/extras/deliver_recent_activity_digest.rb | |
# goes through every user with active memberships, and | |
# 1. sends them an email containing recent activity for their groups | |
# 2. sets the time range for the next, scheduled fetch of recent activity | |
class DeliverRecentActivityDigest | |
def self.run! | |
current_time = DateTime.now.utc | |
User.with_active_memberships.each do |user| | |
if user.subscription_tracker.ready_to_fetch?(current_time: current_time) | |
UserService.send_recent_activity_email(user: user) | |
user.subscription_tracker.update_next_fetch_time_range! | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ./spec/extras/deliver_recent_activity_digest_spec.rb | |
require 'rails_helper' | |
describe "DeliverRecentActivityDigest" do | |
after { Timecop.return } | |
describe "#run!" do | |
before do | |
allow(UserService).to receive(:send_recent_activity_email) | |
end | |
context "user has no active memberships" do | |
before do | |
create(:user) | |
end | |
it "does nothing" do | |
expect(UserService).not_to receive(:send_recent_activity_email) | |
DeliverRecentActivityDigest.run! | |
end | |
end | |
context "user has at least one active membership" do | |
before do | |
make_user_group_member | |
end | |
context "current_time is before user's next scheduled fetch" do | |
it "does nothing" do | |
time = (user.subscription_tracker.next_recent_activity_fetch_scheduled_at - 1.minute).utc | |
Timecop.freeze(time) do | |
expect(UserService).not_to receive(:send_recent_activity_email) | |
DeliverRecentActivityDigest.run! | |
end | |
end | |
end | |
context "current_time is after user's next scheduled fetch" do | |
it "calls fetches activity for user and updates their subscription_tracker's next fetch_time_range" do | |
old_next_recent_activity_scheduled_at = user.subscription_tracker.next_recent_activity_fetch_scheduled_at | |
time = (old_next_recent_activity_scheduled_at + 1.minute).utc | |
Timecop.freeze(time) do | |
expect(UserService).to receive(:send_recent_activity_email) | |
DeliverRecentActivityDigest.run! | |
expect(user.subscription_tracker.reload.recent_activity_last_fetched_at).to eq(old_next_recent_activity_scheduled_at) | |
end | |
end | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ./app/models/subscription_tracker.rb | |
class SubscriptionTracker < ActiveRecord::Base | |
belongs_to :user | |
after_update :update_recent_activity_last_fetched_at | |
def next_recent_activity_fetch_scheduled_at | |
interval = case notification_frequency | |
when "hourly" then 1.hour | |
when "daily" then 1.day | |
when "weekly" then 1.week | |
end | |
recent_activity_last_fetched_at + interval if interval | |
end | |
def ready_to_fetch?(current_time: ) | |
notification_frequency != "never" && current_time >= next_recent_activity_fetch_scheduled_at | |
end | |
def subscribed_to_any_activity? | |
comment_on_your_bucket || comment_on_bucket_you_participated_in || bucket_idea_created || bucket_started_funding || bucket_fully_funded || funding_for_your_bucket || funding_for_a_bucket_you_participated_in || your_bucket_fully_funded || recent_activity_last_fetched_at | |
end | |
def last_fetched_at_formatted | |
case notification_frequency | |
when "hourly" then recent_activity_last_fetched_at.in_time_zone((user.utc_offset || 0) / 60).strftime("%l:%M%P").strip | |
when "daily" then "yesterday" | |
when "weekly" then "last week" | |
end | |
end | |
def next_fetch_time_range | |
if recent_activity_last_fetched_at && next_recent_activity_fetch_scheduled_at | |
recent_activity_last_fetched_at..next_recent_activity_fetch_scheduled_at | |
end | |
end | |
def update_next_fetch_time_range! | |
update(recent_activity_last_fetched_at: next_recent_activity_fetch_scheduled_at) | |
end | |
private | |
def update_recent_activity_last_fetched_at | |
if self.notification_frequency_changed? | |
time_now = DateTime.now.utc | |
datetime = case self.notification_frequency | |
when "hourly" then time_now.beginning_of_hour.utc | |
when "daily" then (time_now.in_time_zone((self.user.utc_offset || 0) / 60).beginning_of_day + 6.hours).utc | |
when "weekly" then (time_now.in_time_zone((self.user.utc_offset || 0) / 60).beginning_of_week + 6.hours).utc | |
end | |
self.update_columns(recent_activity_last_fetched_at: datetime) | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ./spec/models/subscription_tracker.rb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# ./app/models/user.rb | |
require 'securerandom' | |
class User < ActiveRecord::Base | |
devise :database_authenticatable, :registerable, | |
:recoverable, :rememberable, :trackable, :validatable | |
include DeviseTokenAuth::Concerns::User | |
... | |
after_create :create_default_subscription_tracker | |
has_many :groups, through: :memberships | |
has_many :memberships, foreign_key: "member_id", dependent: :destroy | |
has_one :subscription_tracker, dependent: :destroy | |
has_many :allocations, dependent: :destroy | |
has_many :comments, dependent: :destroy | |
has_many :contributions, dependent: :destroy | |
has_many :buckets, dependent: :destroy | |
scope :with_active_memberships, -> { joins(:memberships).where(memberships: {archived_at: nil}) } | |
validates :name, presence: true | |
validates_format_of :email, :with => /\A[^@]+@([^@\.]+\.)+[^@\.]+\z/ | |
def name_and_email | |
"#{name} <#{email}>" | |
end | |
... | |
def membership_for(group) | |
memberships.find_by(group_id: group.id) | |
end | |
... | |
def active_groups | |
Group.joins(:memberships).where(memberships: {member: self, archived_at: nil}) | |
end | |
private | |
... | |
def create_default_subscription_tracker | |
SubscriptionTracker.create( | |
user: self, | |
notification_frequency: "hourly", | |
recent_activity_last_fetched_at: DateTime.now.utc.beginning_of_hour | |
) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment