require 'csv' require 'activerecord-import' require 'zip' require 'yaml' module CanvasSync module Processors class ProvisioningReportProcessor # Processes a provisioning report using the bulk importer. # # options must contain a models key. If there is only one model # Canvas downloads the single report directly as a CSV. If it's # more than one model Canvas downloads a ZIP file, so we have to # extract that and iterate through it for processing. # # @param report_file_path [String] # @param options [Hash] def self.process(report_file_path, options) self.new(report_file_path, options) end def initialize(report_file_path, options) @options = options if options[:models].length == 1 run_import(options[:models][0], report_file_path) else unzipped_file_path = extract(report_file_path) Dir[unzipped_file_path + "/*.csv"].each do |file_path| model_name = file_path.split("/").last.split(".").first run_import(model_name, file_path) end end end private def extract(file_path) unzipped_file_path = "#{file_path}_unzipped" Zip::File.open(file_path) do |zip_file| zip_file.each do |f| f_path = File.join(unzipped_file_path, f.name) FileUtils.mkdir_p(File.dirname(f_path)) zip_file.extract(f, f_path) unless File.exist?(f_path) end end unzipped_file_path end def run_import(model_name, report_file_path) if @options[:legacy_support] CanvasSync::Importers::LegacyImporter.import(report_file_path, model_name.singularize.capitalize.constantize, @options[:account_id]) else send("bulk_process_#{model_name}", report_file_path) end end def bulk_process_users(report_file_path) CanvasSync::Importers::BulkImporter.import( report_file_path, mapping[:users][:report_columns], User, mapping[:users][:conflict_target].to_sym ) end def bulk_process_courses(report_file_path) CanvasSync::Importers::BulkImporter.import( report_file_path, mapping[:courses][:report_columns], Course, mapping[:courses][:conflict_target].to_sym ) end def bulk_process_enrollments(report_file_path) CanvasSync::Importers::BulkImporter.import( report_file_path, mapping[:enrollments][:report_columns], Enrollment, mapping[:enrollments][:conflict_target].to_sym ) end def bulk_process_sections(report_file_path) CanvasSync::Importers::BulkImporter.import( report_file_path, mapping[:sections][:report_columns], Section, mapping[:sections][:conflict_target].to_sym ) end def bulk_process_xlist(report_file_path) CanvasSync::Importers::BulkImporter.import( report_file_path, mapping[:xlist][:report_columns], Section, mapping[:xlist][:conflict_target].to_sym ) end def mapping @mapping ||= begin mapping = YAML::load_file(File.join(__dir__, 'model_mappings.yml')).deep_symbolize_keys! override_filepath = Rails.root.join("config/canvas_sync_provisioning_mapping.yml") if File.file?(override_filepath) override = YAML::load_file(override_filepath).deep_symbolize_keys! mapping = mapping.merge(override) end mapping end end end end end