canvas-lms/app/models/assessment_question_bank.rb

136 lines
4.8 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/>.
#
class AssessmentQuestionBank < ActiveRecord::Base
include Workflow
attr_accessible :context, :title, :user, :outcomes
belongs_to :context, :polymorphic => true
has_many :assessment_questions, :order => 'name, position, created_at'
has_many :assessment_question_bank_users
has_many :learning_outcome_tags, :as => :content, :class_name => 'ContentTag', :conditions => ['content_tags.tag_type = ? AND content_tags.workflow_state != ?', 'learning_outcome', 'deleted'], :include => :learning_outcome
has_many :quiz_groups
before_save :infer_defaults
validates_length_of :title, :maximum => maximum_string_length, :allow_nil => true
workflow do
state :active
state :deleted
end
set_policy do
given{|user, session| cached_context_grants_right?(user, session, :manage_assignments) }
can :read and can :create and can :update and can :delete and can :manage
given{|user, session| user && self.assessment_question_bank_users.exists?(:user_id => user.id) }
can :read
end
def self.default_imported_title
t :default_imported_title, 'Imported Questions'
end
def self.default_unfiled_title
t :default_unfiled_title, 'Unfiled Questions'
end
def self.unfiled_for_context(context)
context.assessment_question_banks.find_by_title_and_workflow_state(default_unfiled_title, 'active') || context.assessment_question_banks.create(:title => default_unfiled_title) rescue nil
end
def cached_context_short_name
@cached_context_name ||= Rails.cache.fetch(['short_name_lookup', self.context_code].cache_key) do
self.context.short_name rescue ""
end
end
def assessment_question_count
self.assessment_questions.active.count
end
def context_code
"#{self.context_type.underscore}_#{self.context_id}"
end
def infer_defaults
self.title = t(:default_title, "No Name - %{course}", :course => self.context.name) if self.title.blank?
end
def bookmark_for(user, do_bookmark=true)
if do_bookmark
question_bank_user = self.assessment_question_bank_users.find_by_user_id(user.id)
question_bank_user ||= self.assessment_question_bank_users.create(:user => user)
else
AssessmentQuestionBankUser.delete_all({:user_id => user.id, :assessment_question_bank_id => self.id})
end
end
def bookmarked_for?(user)
user && self.assessment_question_bank_users.map(&:user_id).include?(user.id)
end
def select_for_submission(count, exclude_ids=[])
ids = AssessmentQuestion.connection.select_all("SELECT id FROM assessment_questions WHERE workflow_state != 'deleted' AND assessment_question_bank_id = #{self.id}")
ids = (ids.map{|i|i['id'].to_i} - exclude_ids).sort_by{rand}[0...count]
ids.empty? ? [] : AssessmentQuestion.find_all_by_id(ids)
end
def outcomes=(hash)
raise "Can't set outcomes on unsaved bank" if new_record?
hash = {} if hash.blank?
ids = []
hash.each do |key, val|
ids.push(key) if !key.blank? && key.to_i != 0
end
ids.uniq!
tags = self.learning_outcome_tags
tag_outcome_ids = tags.map(&:learning_outcome_id).compact.uniq
outcomes = LearningOutcome.available_in_context(self.context, tag_outcome_ids)
missing_ids = ids.select{|id| !tag_outcome_ids.include?(id) }
tags.each do |tag|
if hash[tag.learning_outcome_id.to_s]
tag.update_attribute(:mastery_score, hash[tag.learning_outcome_id.to_s].to_f)
end
end
tags_to_delete = tags.select{|t| !ids.include?(t.learning_outcome_id) }
missing_ids.each do |id|
lot = self.learning_outcome_tags.build(:context => self.context, :tag_type => 'learning_outcome', :mastery_score => hash[id].to_f)
lot.learning_outcome_id = id.to_i
lot.save!
end
tags_to_delete.each{|t| t.destroy }
true
end
alias_method :destroy!, :destroy
def destroy
self.workflow_state = 'deleted'
self.save
end
# clear out all questions so that the bank can be replaced. this is currently
# used by the respondus API.
def clear_for_replacement
assessment_questions.destroy_all
quiz_groups.destroy_all
end
named_scope :active, lambda {
{:conditions => ['assessment_question_banks.workflow_state != ?', 'deleted'] }
}
end