Implements targets and campaigns for conference

This commit is contained in:
Chrisbr 2014-06-26 09:08:26 +02:00
parent 678fe38a25
commit 857ac43e74
40 changed files with 1086 additions and 44 deletions

10
app/models/ahoy/event.rb Normal file
View file

@ -0,0 +1,10 @@
module Ahoy
class Event < ActiveRecord::Base
self.table_name = "ahoy_events"
belongs_to :visit
belongs_to :user
serialize :properties, JSON
end
end

77
app/models/campaign.rb Normal file
View file

@ -0,0 +1,77 @@
class Campaign < ActiveRecord::Base
attr_accessible :name, :utm_source, :utm_medium, :utm_term,
:utm_content, :utm_campaign, :target_ids
validates :name, :utm_campaign, presence: true
has_many :targets
belongs_to :conference
##
# Returns the utm parameters formatted as url.
#
# ====Returns
# * +String+ -> url parameters e.g. ?utm_source=facebook
def url_parameters
kv = []
get_parameters.each_pair do |k, v|
kv += ["#{k}=#{v}"]
end
'?' + kv.join('&') unless kv.empty?
end
##
# Returns the counted visits generated by this campaign.
#
# ====Returns
# * +Fixnum+ -> visits
def visits_count
Visit.where(get_parameters).where('started_at > ?', created_at).count
end
##
# Returns the counted registrations generated by this campaign.
#
# ====Returns
# * +Fixnum+ -> visits
def registrations_count
events_by_name('Registered')
end
##
# Returns the counted event submissions generated by this campaign.
#
# ====Returns
# * +Fixnum+ -> visits
def submissions_count
events_by_name('Event submission')
end
private
##
# Helper method for submissions and registrations.
#
# ====Returns
# * +Fixnum+ -> registrations / submissions
def events_by_name(event_name)
parameters = get_parameters
parameters['ahoy_events.name'] = event_name
Visit.joins(:ahoy_events).where(parameters).where('started_at > ?', created_at).count
end
##
# Helper method to get the parameters for queries.
#
# ====Returns
# * +Hash+ -> parameter => value
def get_parameters
conditions = {}
conditions[:utm_source] = self[:utm_source] unless self[:utm_source].blank?
conditions[:utm_medium] = self[:utm_medium] unless self[:utm_medium].blank?
conditions[:utm_term] = self[:utm_term] unless self[:utm_term].blank?
conditions[:utm_content] = self[:utm_content] unless self[:utm_content].blank?
conditions[:utm_campaign] = self[:utm_campaign] unless self[:utm_campaign].blank?
conditions
end
end

View file

@ -21,7 +21,8 @@ class Conference < ActiveRecord::Base
:include_tickets_in_splash, :include_social_media_in_splash,
:include_program_in_splash, :make_conference_public,
:photos_attributes, :banner_photo,
:include_banner_in_splash
:include_banner_in_splash,
:targets, :targets_attributes, :campaigns, :campaigns_attributes
has_paper_trail
@ -45,6 +46,8 @@ class Conference < ActiveRecord::Base
has_many :sponsorship_levels, dependent: :destroy
has_many :sponsors, dependent: :destroy
has_many :photos, dependent: :destroy
has_many :targets, dependent: :destroy
has_many :campaigns, dependent: :destroy
belongs_to :venue
accepts_nested_attributes_for :rooms, :reject_if => proc {|r| r["name"].blank?}, :allow_destroy => true
@ -62,6 +65,8 @@ class Conference < ActiveRecord::Base
accepts_nested_attributes_for :vdays, :allow_destroy => true
accepts_nested_attributes_for :vpositions, :allow_destroy => true
accepts_nested_attributes_for :photos, allow_destroy: true
accepts_nested_attributes_for :targets, allow_destroy: true
accepts_nested_attributes_for :campaigns, allow_destroy: true
has_attached_file :logo,
styles: { thumb: '100x100>', large: '300x300>' }
@ -457,6 +462,35 @@ class Conference < ActiveRecord::Base
result
end
##
# A map with all conference targets with progress in percent of a certain unit.
#
# ====Returns
# * +Map+ -> target => progress
def get_targets(target_unit)
conference_target = targets.where('unit = ?', target_unit)
result = {}
conference_target.each do |target|
result[target.to_s] = target.get_progress
end
result
end
##
# A map with all conference campaigns associated with targets.
#
# ====Returns
# * +Map+ -> campaign => {actual, target, progress}
def get_campaigns
result = {}
campaigns.each do |campaign|
campaign.targets.each do |target|
result["#{target} from #{campaign.name}"] = target.get_campaign
end
end
result
end
private
##
@ -655,12 +689,12 @@ class Conference < ActiveRecord::Base
#
# ====Returns
# * +hash+ -> person: submissions
def self.calculate_person_submission_hash(submitter, counter)
def self.calculate_person_submission_hash(submitters, counter)
result = ActiveSupport::OrderedHash.new
counter.each do |key, value|
submitter = submitter.find_by_id(key)
submitter = submitters.where(person_id: key).first
if submitter
result[submitter] = value
result[submitter.person] = value
end
end
result

79
app/models/target.rb Normal file
View file

@ -0,0 +1,79 @@
class Target < ActiveRecord::Base
include ActionView::Helpers::TextHelper
attr_accessible :due_date, :target_count, :unit
default_scope { order('due_date ASC') }
def self.units
{
registrations: 'Registration',
submissions: 'Submission',
program_minutes: 'Program minute'
}
end
validates :due_date, :target_count, :unit, presence: true
validates :target_count,
allow_nil: false,
numericality: { only_integer: true, greater_than: 0 }
validates :unit, allow_nil: false, inclusion: { in: Target.units.values }
belongs_to :conference
belongs_to :campaign
##
# Returns the actual progress of the target in percent.
#
# ====Returns
# * +String+ -> progress in percent
def get_progress
numerator = 0
if unit == Target.units[:submissions]
numerator = conference.events.where('created_at < ?', due_date).count
elsif unit == Target.units[:registrations]
numerator = conference.registrations.where('created_at < ?', due_date).count
elsif unit == Target.units[:program_minutes]
numerator = conference.current_program_hours
end
(numerator / target_count.to_f * 100).round(0).to_s
end
##
# Returns a hash with values of the corresponding campaign.
#
# ====Returns
# * +Hash+ -> target_name, campaign_name, value, unit, created_at, progress, days_left
def get_campaign
numerator = 0
if unit == Target.units[:submissions]
numerator = campaign.submissions_count
elsif unit == Target.units[:registrations]
numerator = campaign.registrations_count
elsif unit == Target.units[:program_minutes]
numerator = campaign.current_program_hours
end
progress = (numerator / target_count.to_f * 100).round(0).to_s
result = {
'target_name' => to_s,
'campaign_name' => campaign.name,
'value' => numerator,
'unit' => unit,
'created_at' => created_at,
'progress' => progress,
'days_left' => days_left,
}
result
end
def to_s
"#{pluralize(target_count, unit)} by #{due_date}"
end
private
def days_left
(due_date - Date.today).to_i
end
end

4
app/models/visit.rb Normal file
View file

@ -0,0 +1,4 @@
class Visit < ActiveRecord::Base
has_many :ahoy_events, class_name: "Ahoy::Event"
belongs_to :user
end