forked from instructure/canvas-lms
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsection_importer.rb
More file actions
142 lines (128 loc) · 6.3 KB
/
Copy pathsection_importer.rb
File metadata and controls
142 lines (128 loc) · 6.3 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#
# Copyright (C) 2011 - 2015 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/>.
#
module SIS
class SectionImporter < BaseImporter
def process
start = Time.now
importer = Work.new(@batch, @root_account, @logger)
CourseSection.suspend_callbacks(:delete_enrollments_later_if_deleted) do
Course.skip_updating_account_associations do
CourseSection.process_as_sis(@sis_options) do
yield importer
end
end
end
Course.update_account_associations(importer.course_ids_to_update_associations.to_a) unless importer.course_ids_to_update_associations.empty?
importer.sections_to_update_sis_batch_ids.in_groups_of(1000, false) do |batch|
CourseSection.where(:id => batch).update_all(:sis_batch_id => @batch.id)
end if @batch
# there could be a ton of deleted sections, and it would be really slow to do a normal find_each
# that would order by id. So do it on the slave, to force a cursor that avoids the sort so that
# it can run really fast
Shackles.activate(:slave) do
# ideally we change this to find_in_batches, and call (the currently non-existent) Enrollment.destroy_batch
Enrollment.where(course_section_id: importer.deleted_section_ids.to_a).active.find_each do |enrollment|
Shackles.activate(:master) do
enrollment.destroy
end
end
end
@logger.debug("Sections took #{Time.now - start} seconds")
return importer.success_count
end
class Work
attr_accessor(
:success_count,
:sections_to_update_sis_batch_ids,
:course_ids_to_update_associations,
:deleted_section_ids
)
def initialize(batch, root_account, logger)
@batch = batch
@root_account = root_account
@logger = logger
@success_count = 0
@sections_to_update_sis_batch_ids = []
@course_ids_to_update_associations = Set.new
@deleted_section_ids = Set.new
end
def add_section(section_id, course_id, name, status, start_date=nil, end_date=nil, integration_id=nil)
@logger.debug("Processing Section #{[section_id, course_id, name, status, start_date, end_date].inspect}")
raise ImportError, "No section_id given for a section in course #{course_id}" if section_id.blank?
raise ImportError, "No course_id given for a section #{section_id}" if course_id.blank?
raise ImportError, "No name given for section #{section_id} in course #{course_id}" if name.blank?
raise ImportError, "Improper status \"#{status}\" for section #{section_id} in course #{course_id}" unless status =~ /\Aactive|\Adeleted/i
course = @root_account.all_courses.where(sis_source_id: course_id).take
raise ImportError, "Section #{section_id} references course #{course_id} which doesn't exist" unless course
section = @root_account.course_sections.where(sis_source_id: section_id).take
section ||= course.course_sections.where(sis_source_id: section_id).first_or_initialize
section.root_account = @root_account
# this is an easy way to load up the cache with data we already have
section.course = course if course.id == section.course_id
# only update the name on new records, and ones that haven't been changed since the last sis import
section.name = name if section.new_record? || !section.stuck_sis_fields.include?(:name)
# update the course id if necessary
if section.course_id != course.id
if section.nonxlist_course_id
# this section is crosslisted
if (section.nonxlist_course_id != course.id && !section.stuck_sis_fields.include?(:course_id)) || (section.course.workflow_state == 'deleted' && !!(status =~ /\Aactive/))
# but the course id we were given didn't match the crosslist info
# we have, so, uncrosslist and move
@course_ids_to_update_associations.merge [course.id, section.course_id, section.nonxlist_course_id]
section.uncrosslist(:run_jobs_immediately)
section.move_to_course(course, :run_jobs_immediately)
end
elsif !section.stuck_sis_fields.include?(:course_id)
# this section isn't crosslisted and lives on the wrong course. move
@course_ids_to_update_associations.merge [section.course_id, course.id]
section.move_to_course(course, :run_jobs_immediately)
end
end
if section.course_id_changed?
@course_ids_to_update_associations.merge [section.course_id, section.course_id_was].compact
end
section.integration_id = integration_id
if status =~ /active/i
section.workflow_state = 'active'
elsif status =~ /deleted/i
section.workflow_state = 'deleted'
deleted_section_ids << section.id
end
if (section.stuck_sis_fields & [:start_at, :end_at]).empty?
section.start_at = start_date
section.end_at = end_date
end
section.restrict_enrollments_to_section_dates = (section.start_at.present? || section.end_at.present?) unless section.stuck_sis_fields.include?(:restrict_enrollments_to_section_dates)
if section.changed?
section.sis_batch_id = @batch.id if @batch
if section.valid?
section.save
else
msg = "A section did not pass validation "
msg += "(" + "section: #{section_id} / #{name}, course: #{course_id}, error: "
msg += section.errors.full_messages.join(", ") + ")"
raise ImportError, msg
end
elsif @batch
@sections_to_update_sis_batch_ids << section.id
end
@success_count += 1
end
end
end
end