diff --git a/admin/app/models/cohort.rb b/admin/app/models/cohort.rb index 86966cdea..d1213fe53 100644 --- a/admin/app/models/cohort.rb +++ b/admin/app/models/cohort.rb @@ -1,4 +1,131 @@ +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 = ['reg_users', :first_downloaded_client_at, :first_certified_gear_at, 'visit0-1', 'visit2-5', 'visit6+', 'play_online0-1', 'play_online2-5', 'play_online6+', 'play_jamtr0-1', 'play_jamtr2-5', 'play_jamtr6+', 'redeem_jamtr', 'purch_jamtr', 'recordings', 'friendships', 'invited_users'] + + 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 = 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.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(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 _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 all_time! + num_user = self.class.user_attribute_within(:created_at, self).count + return unless 0 < num_user + + 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 = _join_user(InvitedUser.reflections[:sender]).count + _put_data_set('invited_users', count, num_user) + + count = _join_user(RecordedTrack.reflections[:user]).count + _put_data_set('recorded_tracks', count, num_user) + + count = _join_user(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(JamTrackRight.reflections[:user]).count + _put_data_set('jam_track_rights', count, num_user) + + count = _join_user(MusicSessionUserHistory.reflections[:user]).count + _put_data_set('music_sessions_user_history', count, num_user) + + self.save! + end + + def monthly! + count = JamTrackRight + .where(redeemed: true) + .where(updated_at: self.start_date..self.end_date) + .count + self.data_set['redeemed_jamtracks'] = count + self.data_set["redeemed_jamtracks%"] = 100.0 * (count.to_f / num_user.to_f) + + end + end diff --git a/db/manifest b/db/manifest index 9cc4e1fac..bd94ccb90 100755 --- a/db/manifest +++ b/db/manifest @@ -260,4 +260,5 @@ jam_track_jmep_data.sql add_jam_track_bitrates.sql jam_track_importer.sql jam_track_pro_licensing_update.sql -jam_track_redeemed.sql \ No newline at end of file +jam_track_redeemed.sql +cohorts.sql diff --git a/db/up/cohorts.sql b/db/up/cohorts.sql index a9598189d..2fae882ca 100644 --- a/db/up/cohorts.sql +++ b/db/up/cohorts.sql @@ -1,9 +1,13 @@ -CREATE TABLE cohorts { +CREATE TABLE cohorts ( id VARCHAR(64) PRIMARY KEY DEFAULT uuid_generate_v4(), start_date TIMESTAMP NOT NULL, end_date TIMESTAMP NOT NULL, - group_type VARCHAR(64) NOT NULL, + cumulative BOOLEAN NOT NULL DEFAULT FALSE, + data_set JSON NOT NULL DEFAULT '{}', created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, -}; + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP +); + +CREATE INDEX index_started_date ON cohorts USING btree (start_date);