module Senkyoshi
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <www.gnu.org/licenses/>.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <www.gnu.org/licenses/>.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <www.gnu.org/licenses/>.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <www.gnu.org/licenses/>.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <www.gnu.org/licenses/>.
You should have received a copy of the GNU Affero General Public License along with this program. If not, see <www.gnu.org/licenses/>.
Constants
- DIR_BASE
- FILE_BASE
- MAIN_CANVAS_MODULE
- MASTER_MODULE
- PRE_RESOURCE_TYPE
- RESOURCE_TYPE
- VERSION
Attributes
Public Class Methods
# File lib/senkyoshi.rb, line 90 def self.build_file(course, imscc_path, resources) file = CanvasCc::CanvasCC::CartridgeCreator.new(course).create(Dir.tmpdir) FileUtils.mv(file, imscc_path, force: true) cleanup resources puts "Created a file #{imscc_path}" end
# File lib/senkyoshi/xml_parser.rb, line 170 def self.build_heirarchy(organizations, resources, course_toc) discussion_boards = resources. search("resource[type=\"resource/x-bb-discussionboard\"]") organizations.at("organization").children.flat_map do |item| Heirarchy.item_iterator(item, course_toc, discussion_boards) end end
Perform any necessary cleanup from creating canvas cartridge
# File lib/senkyoshi.rb, line 100 def self.cleanup(resources) resources.each(&:cleanup) end
# File lib/senkyoshi.rb, line 44 def self.configuration @configuration ||= Configuration.new end
# File lib/senkyoshi.rb, line 52 def self.configure yield configuration end
# File lib/senkyoshi/xml_parser.rb, line 142 def self.connect_content(pre_data) pre_data["content"].each do |content| if pre_data["gradebook"] gradebook = pre_data["gradebook"].first. detect { |g| g[:content_id] == content[:file_name] } content.merge!(gradebook) if gradebook end if pre_data["courseassessment"] course_assessment = pre_data["courseassessment"]. detect { |ca| ca[:original_file_name] == content[:assignment_id] } content.merge!(course_assessment) if course_assessment end if pre_data["link"] matching_link = pre_data["link"].detect do |link| link[:referrer] == content[:file_name] end if matching_link content[:referred_to_title] = matching_link[:referred_to_title] end end end pre_data["content"] end
# File lib/senkyoshi.rb, line 104 def self.create_canvas_course(resources, zip_name, pre_data) course = CanvasCc::CanvasCC::Models::Course.new course.course_code = zip_name # Wait until after we set modules to convert Rules resources.find_instances_not_of([Rule]).each do |resource| course = resource.canvas_conversion(course, resources) end course = ModuleConverter.set_modules(course, pre_data) resources.find_instances_of(Rule).each do |rule| course = rule.canvas_conversion(course, resources) end course end
Create a random hex prepended with aj_ This is because the instructure qti migration tool requires the first character to be a letter.
# File lib/senkyoshi/xml_parser.rb, line 202 def self.create_random_hex "aj_" + SecureRandom.hex(32) end
# File lib/senkyoshi/xml_parser.rb, line 206 def self.get_attribute_value(xml_data, type) value = "" if xml_data.children.at(type).attributes["value"] value = xml_data.children.at(type).attributes["value"].value end value end
# File lib/senkyoshi/xml_parser.rb, line 222 def self.get_description(xml_data) value = "" if xml_data.children.at("DESCRIPTION") value = xml_data.children.at("DESCRIPTION").text end value end
# File lib/senkyoshi/xml_parser.rb, line 107 def self.get_single_pre_data(pre_data, file) pre_data.detect do |data_item| data_item[:file_name] == file || data_item[:assignment_id] == file end || { file_name: file } end
# File lib/senkyoshi/xml_parser.rb, line 214 def self.get_text(xml_data, type) value = "" if xml_data.children.at(type) value = xml_data.children.at(type).text end value end
# File lib/senkyoshi.rb, line 121 def self.initialize_course(canvas_file_path, blackboard_file_path) metadata = Senkyoshi::CanvasCourse.metadata_from_file(canvas_file_path) Zip::File.open(blackboard_file_path, "rb") do |bb_zip| course = Senkyoshi::CanvasCourse.from_metadata(metadata, bb_zip) course.upload_content(canvas_file_path) cleanup course.scorm_packages end end
Iterate through course files and create new SenkyoshiFile
for each non-metadata file.
# File lib/senkyoshi/xml_parser.rb, line 182 def self.iterate_files(zipfile) files = zipfile.entries.select(&:file?) dir_names = zipfile.entries.map { |entry| File.dirname(entry.name) }.uniq file_names = files.map(&:name) entry_names = dir_names + file_names scorm_paths = ScormPackage.find_scorm_paths(zipfile) files.select do |file| SenkyoshiFile.valid_file?(entry_names, scorm_paths, file) end. map { |file| SenkyoshiFile.new(file) } end
# File lib/senkyoshi/xml_parser.rb, line 91 def self.iterate_xml(resources, zip_file, resource_xids, pre_data) staff_info = StaffInfo.new iterator_master(resources, zip_file) do |xml_data, type, file| if RESOURCE_TYPE[type.to_sym] single_pre_data = get_single_pre_data(pre_data, file) || {} res_class = Senkyoshi.const_get RESOURCE_TYPE[type.to_sym] case type when "staffinfo" staff_info.iterate_xml(xml_data, single_pre_data) else res_class.from(xml_data, single_pre_data, resource_xids) end end end.flatten - ["", nil] end
# File lib/senkyoshi/xml_parser.rb, line 113 def self.iterator_master(resources, zip_file) resources.children.map do |resource| file_name = resource.attributes["file"].value file = File.basename(file_name, ".dat") if zip_file.find_entry(file_name) data_file = Senkyoshi.read_file(zip_file, file_name) xml_data = Nokogiri::XML.parse(data_file).children.first type = xml_data ? xml_data.name.downcase : "empty" yield xml_data, type, file end end end
# File lib/senkyoshi.rb, line 56 def self.parse(zip_path, imscc_path) Zip::File.open(zip_path) do |file| manifest = read_file(file, "imsmanifest.xml") resources = Senkyoshi::Collection.new resources.add(Senkyoshi.iterate_files(file)) resource_xids = resources.resources. map(&:xid). select { |r| r.include?("xid-") } xml = Nokogiri::XML.parse(manifest) xml_resources = xml.at("resources") xml_organizations = xml.at("organizations") pre_data = Senkyoshi.pre_iterator(xml_organizations, xml_resources, file) resources.add( Senkyoshi.iterate_xml(xml_resources, file, resource_xids, pre_data), ) course = create_canvas_course(resources, zip_path, pre_data) build_file(course, imscc_path, resources) end end
# File lib/senkyoshi.rb, line 80 def self.parse_and_process_single(zip_path, imscc_path) Senkyoshi.parse(zip_path, imscc_path) end
# File lib/senkyoshi/xml_parser.rb, line 127 def self.pre_iterator(organizations, resources, zip_file) pre_data = {} iterator_master(resources, zip_file) do |xml_data, type, file| if PRE_RESOURCE_TYPE[type.to_sym] res_class = Senkyoshi.const_get PRE_RESOURCE_TYPE[type.to_sym] pre_data[type] ||= [] data = res_class.get_pre_data(xml_data, file) pre_data[type].push(data) if data end end pre_data["content"] = build_heirarchy(organizations, resources, pre_data["coursetoc"]) - ["", nil] pre_data = connect_content(pre_data) end
# File lib/senkyoshi.rb, line 84 def self.read_file(zip_file, file_name) zip_file.find_entry(file_name).get_input_stream.read rescue NoMethodError raise Exceptions::MissingFileError end
# File lib/senkyoshi.rb, line 48 def self.reset @configuration = Configuration.new end
# File lib/senkyoshi.rb, line 130 def self.true?(obj) obj.to_s == "true" end