222 lines
7.9 KiB
Ruby
222 lines
7.9 KiB
Ruby
require 'date'
|
|
|
|
class Cohort < ActiveRecord::Base
|
|
|
|
KEY_SET_TOTAL = [:registered_users, :first_downloaded_client_at, :first_certified_gear_at, :music_sessions_user_history, 'play_jamtr', :jam_track_rights, :recorded_tracks, :friendships, :invited_users]
|
|
|
|
TOTAL_LABELS = {
|
|
registered_users: 'Registered Users',
|
|
first_downloaded_client_at: 'Downloaded app',
|
|
first_certified_gear_at: 'Certified Gear',
|
|
music_sessions_user_history: 'Played Online',
|
|
play_jamtr: 'Played JamTrack',
|
|
jam_track_rights: 'Purchased JamTrack',
|
|
recorded_tracks: 'Made Recording',
|
|
friendships: 'Connected w/Friend',
|
|
invited_users: 'Invite Others',
|
|
}
|
|
|
|
# KEY_SET_TOTAL = [:registered_users, :first_downloaded_client_at, :first_certified_gear_at, :music_session_histories, 'play_jamtr', :jam_track_rights, :recordings, :friendships, :invited_users]
|
|
KEY_SET_MONTH = [:registered_users, :first_downloaded_client_at, :first_certified_gear_at, :visit_1, :visit_2_5, :visit_6_, :play_online_1, :play_online_2_5, :play_online_6_, :play_jamtr_1, :play_jamtr_2_5, :play_jamtr_6_, :jam_track_rights_redeemed, :jam_track_rights, :recorded_tracks, :friendships, :invited_users]
|
|
|
|
MONTHLY_LABELS = {
|
|
registered_users: 'Registered Users',
|
|
first_downloaded_client_at: 'Downloaded app',
|
|
first_certified_gear_at: 'Certified Gear',
|
|
music_sessions_user_history_1: 'Played Online 1',
|
|
music_sessions_user_history_2_5: 'Played Online 2-5',
|
|
music_sessions_user_history_6_: 'Played Online 6+',
|
|
play_jamtr: 'Played JamTrack',
|
|
jam_track_rights: 'Purchased JamTrack',
|
|
recorded_tracks: 'Made Recording',
|
|
friendships: 'Connected w/Friend',
|
|
invited_users: 'Invite Others',
|
|
}
|
|
|
|
serialize :data_set, JSON
|
|
|
|
before_create do
|
|
self.data_set ||= {}
|
|
end
|
|
|
|
def self.date_tuples(from,to)
|
|
prec = from.size
|
|
start = Date.new(*from)
|
|
finish = Date.new(*to)
|
|
|
|
filter_on = [:day,:mon].first(3-prec)
|
|
filter = ->(d) { filter_on.all? {|attr| d.send(attr) == 1 } }
|
|
|
|
(start..finish)
|
|
.select(&filter)
|
|
.map { |d| [d.year,d.mon,d.day].first(prec) }
|
|
end
|
|
|
|
def self.cohort_date_ranges(starting=nil, ending=nil)
|
|
starting ||= User.where(admin: false).order(:created_at).first.created_at
|
|
ending ||= Time.now
|
|
dates = self.date_tuples([starting.year, starting.month],
|
|
[ending.year, ending.month])
|
|
ranges = []
|
|
dates.each_with_index do |d1, idx|
|
|
d2 = dates[idx+1] || [Time.now.next_month.year,Time.now.next_month.month]
|
|
rr = Time.parse("#{d1[0]}-#{d1[1]}-1")..(Time.parse("#{d2[0]}-#{d2[1]}-1") - 1.second)
|
|
ranges << rr
|
|
end
|
|
ranges
|
|
end
|
|
|
|
def self.monthly_cohorts(start_date, end_date)
|
|
self.cohort_date_ranges(start_date, end_date).collect do |range|
|
|
unless cc = Cohort.where(start_date: range.first).where(cumulative: true).limit(1).first
|
|
cc = Cohort.new
|
|
cc.start_date = range.first
|
|
cc.end_date = range.last
|
|
cc.save!
|
|
end
|
|
cc
|
|
end
|
|
end
|
|
|
|
def self.cumulative_cohorts
|
|
self.cohort_date_ranges.collect do |range|
|
|
unless cc = Cohort.where(start_date: range.first).where(cumulative: true).limit(1).first
|
|
cc = Cohort.new
|
|
cc.start_date = range.first
|
|
cc.end_date = range.last
|
|
cc.cumulative = true
|
|
cc.save!
|
|
end
|
|
cc
|
|
end
|
|
end
|
|
|
|
def _join_user_all_time(assoc_ref)
|
|
assoc_ref.active_record
|
|
.joins("INNER JOIN users AS uu ON uu.id = #{assoc_ref.foreign_key}")
|
|
.where(created_at: self.start_date..self.end_date)
|
|
.where(['uu.created_at >= ? AND uu.created_at <= ?',
|
|
self.start_date, self.end_date])
|
|
end
|
|
|
|
def _attribute_within_monthly(active_record, attrib)
|
|
active_record.where(attrib => self.start_date..self.end_date)
|
|
end
|
|
|
|
def _put_data_set(key, count, num_user)
|
|
self.data_set[key] = count
|
|
self.data_set["#{key}%"] = 100.0 * (count.to_f / num_user.to_f)
|
|
end
|
|
|
|
def self.user_attribute_within(attrib, cohort)
|
|
User.where(attrib => cohort.start_date..cohort.end_date)
|
|
end
|
|
|
|
def _monthly_played_online_count(constraint)
|
|
where = if constraint.is_a?(Range)
|
|
"played.cnt >= #{constraint.first} AND played.cnt <= #{constraint.last}"
|
|
else
|
|
"played.cnt = #{constraint}"
|
|
end
|
|
sql =<<SQL
|
|
SELECT COUNT(*) FROM
|
|
(SELECT COUNT(*) cnt FROM #{MusicSessionUserHistory.table_name}
|
|
WHERE
|
|
created_at >= '#{self.start_date}' AND created_at <= '#{self.end_date}' AND
|
|
EXTRACT(EPOCH FROM (session_removed_at - created_at)) >= 900
|
|
GROUP BY user_id
|
|
) played
|
|
WHERE #{where}
|
|
SQL
|
|
MusicSessionUserHistory.connection.execute(sql)[0]['count'].to_i
|
|
end
|
|
|
|
def _monthly!
|
|
unless 0 < num_user = self.class.user_attribute_within(:created_at, self).count
|
|
self.update_attribute(:data_set, {})
|
|
return
|
|
end
|
|
|
|
self.data_set['registered_users'] = num_user
|
|
num_user = num_user.to_f
|
|
|
|
count = self.class.user_attribute_within(:first_downloaded_client_at, self).count
|
|
_put_data_set('first_downloaded_client_at', count, num_user)
|
|
|
|
count = self.class.user_attribute_within(:first_certified_gear_at, self).count
|
|
_put_data_set('first_certified_gear_at', count, num_user)
|
|
|
|
count = _attribute_within_monthly(InvitedUser, :created_at).count
|
|
_put_data_set('invited_users', count, num_user)
|
|
|
|
count = _attribute_within_monthly(RecordedTrack, :created_at).count
|
|
_put_data_set('recorded_tracks', count, num_user)
|
|
|
|
count = _attribute_within_monthly(JamTrackRight, :created_at).count
|
|
_put_data_set('jam_track_rights', count, num_user)
|
|
|
|
count = _attribute_within_monthly(JamTrackRight, :created_at)
|
|
.where(redeemed: true)
|
|
.count
|
|
_put_data_set('jam_track_rights_redeemed', count, num_user)
|
|
|
|
count = _attribute_within_monthly(Friendship, :created_at)
|
|
.joins("INNER JOIN friendships AS fff ON fff.friend_id = friendships.user_id")
|
|
.where(['fff.created_at >= ? AND fff.created_at <= ?',
|
|
self.start_date, self.end_date]).count
|
|
count /= 2
|
|
_put_data_set('friendships', count, num_user)
|
|
|
|
count = self._monthly_played_online_count(1)
|
|
_put_data_set('music_sessions_user_history_1', count, num_user)
|
|
|
|
end
|
|
|
|
def _all_time!
|
|
unless 0 < num_user = self.class.user_attribute_within_monthly(:created_at, self).count
|
|
self.update_attribute(:data_set, {})
|
|
return
|
|
end
|
|
|
|
self.data_set['registered_users'] = num_user
|
|
num_user = num_user.to_f
|
|
|
|
count = self.class.user_attribute_within(:first_downloaded_client_at, self)
|
|
.where(created_at: self.start_date..self.end_date)
|
|
.count
|
|
_put_data_set('first_downloaded_client_at', count, num_user)
|
|
|
|
count = self.class.user_attribute_within(:first_certified_gear_at, self)
|
|
.where(created_at: self.start_date..self.end_date)
|
|
.count
|
|
_put_data_set('first_certified_gear_at', count, num_user)
|
|
|
|
count = _join_user_all_time(InvitedUser.reflections[:sender]).count
|
|
_put_data_set('invited_users', count, num_user)
|
|
|
|
count = _join_user_all_time(RecordedTrack.reflections[:user]).count
|
|
_put_data_set('recorded_tracks', count, num_user)
|
|
|
|
count = _join_user_all_time(Friendship.reflections[:user])
|
|
.joins("INNER JOIN friendships AS fff ON fff.friend_id = uu.id")
|
|
.where(['fff.created_at >= ? AND fff.created_at <= ?',
|
|
self.start_date, self.end_date]).count
|
|
count /= 2
|
|
_put_data_set('friendships', count, num_user)
|
|
|
|
count = _join_user_all_time(JamTrackRight.reflections[:user]).count
|
|
_put_data_set('jam_track_rights', count, num_user)
|
|
|
|
count = _join_user_all_time(MusicSessionUserHistory.reflections[:user]).count
|
|
_put_data_set('music_sessions_user_history', count, num_user)
|
|
|
|
self.save!
|
|
end
|
|
|
|
def populate!
|
|
self.cumulative ? _all_time! : _monthly!
|
|
end
|
|
|
|
end
|
|
|