198 lines
7.1 KiB
Ruby
198 lines
7.1 KiB
Ruby
#
|
|
# Copyright (C) 2011 Instructure, Inc.
|
|
#
|
|
# This file is part of Canvas.
|
|
#
|
|
# Canvas is free software: you can redistribute it and/or modify it under
|
|
# the terms of the GNU Affero General Public License as published by the Free
|
|
# Software Foundation, version 3 of the License.
|
|
#
|
|
# Canvas is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
# WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
|
|
# A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
|
|
# details.
|
|
#
|
|
# You should have received a copy of the GNU Affero General Public License along
|
|
# with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
#
|
|
|
|
# asset_code is used to specify the 'asset' or idea being accessed
|
|
# asset_group_code is for the group
|
|
# so, for example, the asset could be an assignment, the group would be the assignment_group
|
|
class AssetUserAccess < ActiveRecord::Base
|
|
belongs_to :context, :polymorphic => true
|
|
belongs_to :user
|
|
has_many :page_views
|
|
has_many :asset_access_ranges
|
|
before_save :infer_defaults
|
|
attr_accessible :user, :asset_code
|
|
|
|
named_scope :for_context, lambda{|context|
|
|
{:conditions => ["asset_user_accesses.context_id = ? AND asset_user_accesses.context_type = ?", context.id, context.class.to_s]}
|
|
}
|
|
named_scope :for_user, lambda{ |user|
|
|
{ :conditions => {:user_id => user} }
|
|
}
|
|
named_scope :participations, {:conditions => { :action_level => 'participate' }}
|
|
named_scope :most_recent, {:order => 'updated_at DESC'}
|
|
|
|
def category
|
|
self.asset_category
|
|
end
|
|
|
|
def infer_defaults
|
|
self.display_name ||= asset_display_name
|
|
end
|
|
|
|
def category=(val)
|
|
self.asset_category = val
|
|
end
|
|
|
|
def self.by_category(list, old_list=[])
|
|
res = {}.with_indifferent_access
|
|
res[:categories] = {}
|
|
res[:totals] = {}
|
|
res[:prior_totals] = {}
|
|
Rails.cache.fetch(['access_by_category', list.first, list.last, list.length].cache_key) do
|
|
list.each{|a|
|
|
a.category ||= 'unknown'
|
|
cat = res[:categories][a.category] || {}
|
|
cat[:view_tally] ||= 0
|
|
cat[:view_tally] += a.view_score || 0
|
|
cat[:participate_tally] ||= 0
|
|
cat[:participate_tally] += a.participate_score || 0
|
|
cat[:interaction_seconds] = (cat[:interaction_seconds] || 0) + ((a.interaction_seconds || 30) * a.view_score)
|
|
cat[:user_ids] ||= {}
|
|
cat[:user_ids][a.user_id] = (cat[:user_ids][a.user_id] || 0) + 1
|
|
cat[:membership_types] ||= {}
|
|
cat[:membership_types][a.membership_type || "Other"] = (cat[:membership_types][a.membership_type || "Other"] || 0) + (a.view_score || 0)
|
|
cat[:assets] ||= {}
|
|
cat[:assets][a.asset_code] ||= {}
|
|
cat[:assets][a.asset_code][:view_tally] ||= 0
|
|
cat[:assets][a.asset_code][:view_tally] += a.view_score || 0
|
|
cat[:assets][a.asset_code][:participate_tally] ||= 0
|
|
cat[:assets][a.asset_code][:participate_tally] += a.participate_score || 0
|
|
cat[:assets][a.asset_code][:display_name] ||= a.display_name
|
|
res[:categories][a.category] = cat
|
|
res[:totals][:view_tally] ||= 0
|
|
res[:totals][:view_tally] += a.view_score || 0
|
|
res[:totals][:participate_tally] ||= 0
|
|
res[:totals][:participate_tally] += a.participate_score || 0
|
|
}
|
|
(old_list || []).each{|a|
|
|
a.category ||= 'unknown'
|
|
cat = res[:categories][a.category] || {}
|
|
cat[:prior_view_tally] ||= 0
|
|
cat[:prior_view_tally] += a.view_score || 0
|
|
cat[:participate_tally] ||= 0
|
|
cat[:participate_tally] += a.participate_score || 0
|
|
cat[:prior_assets] ||= {}
|
|
cat[:prior_assets][a.asset_code] ||= {}
|
|
cat[:prior_assets][a.asset_code][:view_tally] ||= 0
|
|
cat[:prior_assets][a.asset_code][:view_tally] += a.view_score || 0
|
|
cat[:prior_assets][a.asset_code][:participate_tally] ||= 0
|
|
cat[:prior_assets][a.asset_code][:participate_tally] += a.participate_score || 0
|
|
cat[:prior_assets][a.asset_code][:display_name] ||= a.display_name
|
|
res[:categories][a.category] = cat
|
|
res[:prior_totals][:view_tally] ||= 0
|
|
res[:prior_totals][:view_tally] += a.view_score || 0
|
|
res[:prior_totals][:participate_tally] ||= 0
|
|
res[:prior_totals][:participate_tally] += a.participate_score || 0
|
|
}
|
|
res[:categories].each{|key, val|
|
|
res[:categories][key][:participate_average] = (res[:categories][key][:participate_tally].to_f / res[:totals][:participate_tally].to_f * 100).round / 100.0 rescue 0
|
|
res[:categories][key][:view_average] = (res[:categories][key][:view_tally].to_f / res[:totals][:view_tally].to_f * 100).round rescue 0
|
|
res[:categories][key][:interaction_seconds_average] = (res[:categories][key][:interaction_seconds].to_f / res[:categories][key][:view_tally].to_f * 100).round / 100.0 rescue 0
|
|
}
|
|
res
|
|
end
|
|
end
|
|
|
|
def display_name
|
|
# repair existing AssetUserAccesses that have bad display_names
|
|
if read_attribute(:display_name) == asset_code
|
|
better_display_name = asset_display_name
|
|
if better_display_name != asset_code
|
|
update_attribute(:display_name, better_display_name)
|
|
end
|
|
end
|
|
read_attribute(:display_name)
|
|
end
|
|
|
|
def asset_display_name
|
|
if self.asset.respond_to?(:title) && !self.asset.title.nil?
|
|
asset.title
|
|
elsif self.asset.is_a? Enrollment
|
|
asset.user.name
|
|
else
|
|
self.asset_code
|
|
end
|
|
end
|
|
|
|
def context_code
|
|
"#{self.context_type.underscore}_#{self.context_id}" rescue nil
|
|
end
|
|
|
|
def readable_name
|
|
if self.asset_code && self.asset_code.match(/\:/)
|
|
split = self.asset_code.split(/\:/)
|
|
if split[1] == self.context_code
|
|
# TODO: i18n
|
|
"#{self.context_type} #{split[0].titleize}"
|
|
else
|
|
self.display_name
|
|
end
|
|
else
|
|
re = Regexp.new("#{self.asset_code} - ")
|
|
self.display_name.nil? ? "" : self.display_name.gsub(re, "")
|
|
end
|
|
end
|
|
|
|
def asset
|
|
asset_code, general = self.asset_code.split(":").reverse
|
|
code_split = asset_code.split("_")
|
|
asset = Context.find_asset_by_asset_string(asset_code, context)
|
|
asset
|
|
end
|
|
memoize :asset
|
|
|
|
def asset_class_name
|
|
self.asset.class.name.underscore if self.asset
|
|
end
|
|
|
|
def log( kontext, accessed )
|
|
self.asset_category ||= accessed[:category]
|
|
self.asset_group_code ||= accessed[:group_code]
|
|
self.membership_type ||= accessed[:membership_type]
|
|
self.context = kontext
|
|
self.summarized_at = nil
|
|
self.last_access = Time.now.utc
|
|
log_action(accessed[:level])
|
|
save
|
|
end
|
|
|
|
def log_action(level)
|
|
increment(:view_score) if %w{view participate}.include?( level )
|
|
increment(:participate_score) if %w{participate submit}.include?( level )
|
|
|
|
if self.action_level != 'participate'
|
|
self.action_level = (level == 'submit') ? 'participate' : level
|
|
end
|
|
end
|
|
|
|
def self.infer_asset(code)
|
|
asset_code, general = code.split(":").reverse
|
|
code_split = asset_code.split("_")
|
|
asset = Context.find_asset_by_asset_string(asset_code)
|
|
asset
|
|
end
|
|
|
|
private
|
|
|
|
def increment(attribute)
|
|
incremented_value = (self.send(attribute) || 0) + 1
|
|
self.send("#{attribute}=", incremented_value)
|
|
end
|
|
|
|
end
|