canvas-lms/lib/must_view_module_progressor.rb

115 lines
3.0 KiB
Ruby

# frozen_string_literal: true
#
# Copyright (C) 2016 - present 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 MustViewModuleProgressor
def initialize(user, course)
@user = user
@course = course
end
attr_reader :user, :course
def modules
course.context_modules
end
def make_progress
modules.each do |mod|
mod.evaluate_for(user)
if mod.require_sequential_progress
progress_sequential_module(mod)
else
progress_random_access_module(mod)
end
end
end
def current_progress
progress = {}
modules.each do |mod|
progress[mod.id] =
if (progression = mod.find_or_create_progression(user)&.evaluate)
{ status: progression.workflow_state }
elsif mod.grants_right?(user, :read)
{ status: 'unlocked' }
else
{ status: 'locked' }
end
progress[mod.id][:items] = items_current_progress(mod, progression)
end
progress
end
private
def always_skippable?(item)
return true unless item.visible_to_user?(user)
progression = item.context_module.find_or_create_progression(user)
# unenrolled users don't have progressions and can always skip
return true if progression.nil?
return true if progression.finished_item?(item)
content = item.content
return true if content.respond_to?(:published?) && !content.published?
false
end
def random_access_should_skip?(item)
always_skippable?(item) || sequential_access_should_stop?(item)
end
def sequential_access_should_stop?(item)
content = item.content
return true if content.respond_to?(:locked_for?) && content.locked_for?(user, deep_check_if_needed: true)
return true unless item.context_module.completion_requirement_for(:read, item)
false
end
def progress_random_access_module(mod)
items = mod.content_tags
items.each do |item|
next if random_access_should_skip?(item)
progress_item(item)
end
end
def progress_sequential_module(mod)
mod.content_tags.each do |item|
next if always_skippable?(item)
break if sequential_access_should_stop?(item)
progress_item(item)
end
end
def progress_item(item)
item.context_module_action(user, :read)
end
def items_current_progress(mod, progression)
progress = {}
mod.content_tags.each do |item|
progress[item.id] = (progression&.finished_item?(item) || false)
end
progress
end
end