canvas_sync 0.10.2 → 0.10.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/lib/canvas_sync/generators/install_live_events_generator.rb +5 -1
- data/lib/canvas_sync/generators/templates/migrations/create_accounts.rb +1 -1
- data/lib/canvas_sync/generators/templates/migrations/create_admins.rb +1 -1
- data/lib/canvas_sync/generators/templates/migrations/create_assignment_groups.rb +1 -1
- data/lib/canvas_sync/generators/templates/migrations/create_assignments.rb +1 -1
- data/lib/canvas_sync/generators/templates/migrations/create_context_module_items.rb +1 -1
- data/lib/canvas_sync/generators/templates/migrations/create_context_modules.rb +1 -1
- data/lib/canvas_sync/generators/templates/migrations/create_courses.rb +1 -1
- data/lib/canvas_sync/generators/templates/migrations/create_enrollments.rb +1 -1
- data/lib/canvas_sync/generators/templates/migrations/create_roles.rb +1 -1
- data/lib/canvas_sync/generators/templates/migrations/create_sections.rb +1 -1
- data/lib/canvas_sync/generators/templates/migrations/create_submissions.rb +1 -1
- data/lib/canvas_sync/generators/templates/migrations/create_terms.rb +1 -1
- data/lib/canvas_sync/generators/templates/migrations/create_users.rb +1 -1
- data/lib/canvas_sync/generators/templates/models/account.rb +1 -1
- data/lib/canvas_sync/generators/templates/models/admin.rb +1 -1
- data/lib/canvas_sync/generators/templates/models/assignment.rb +1 -1
- data/lib/canvas_sync/generators/templates/models/assignment_group.rb +1 -1
- data/lib/canvas_sync/generators/templates/models/context_module.rb +8 -1
- data/lib/canvas_sync/generators/templates/models/context_module_item.rb +8 -1
- data/lib/canvas_sync/generators/templates/models/course.rb +1 -1
- data/lib/canvas_sync/generators/templates/models/enrollment.rb +1 -1
- data/lib/canvas_sync/generators/templates/models/role.rb +1 -1
- data/lib/canvas_sync/generators/templates/models/section.rb +2 -1
- data/lib/canvas_sync/generators/templates/models/submission.rb +1 -1
- data/lib/canvas_sync/generators/templates/models/term.rb +1 -1
- data/lib/canvas_sync/generators/templates/models/user.rb +1 -1
- data/lib/canvas_sync/generators/templates/services/live_events/assignment_event.rb +33 -0
- data/lib/canvas_sync/generators/templates/services/live_events/assignment_group_event.rb +24 -0
- data/lib/canvas_sync/generators/templates/services/live_events/base_event.rb +22 -0
- data/lib/canvas_sync/generators/templates/services/live_events/course_event.rb +20 -0
- data/lib/canvas_sync/generators/templates/services/live_events/course_section_event.rb +18 -0
- data/lib/canvas_sync/generators/templates/services/live_events/enrollment_event.rb +20 -0
- data/lib/canvas_sync/generators/templates/services/live_events/grade_event.rb +26 -0
- data/lib/canvas_sync/generators/templates/services/live_events/module_event.rb +16 -0
- data/lib/canvas_sync/generators/templates/services/live_events/module_item_event.rb +15 -0
- data/lib/canvas_sync/generators/templates/services/live_events/submission_event.rb +18 -0
- data/lib/canvas_sync/generators/templates/services/live_events/syllabus_event.rb +21 -0
- data/lib/canvas_sync/generators/templates/services/live_events/user_event.rb +19 -0
- data/lib/canvas_sync/version.rb +1 -1
- data/spec/canvas_sync/services/module_event_spec.rb +2 -2
- data/spec/canvas_sync/services/module_item_event_spec.rb +2 -2
- data/spec/dummy/app/models/account.rb +1 -1
- data/spec/dummy/app/models/admin.rb +1 -1
- data/spec/dummy/app/models/assignment.rb +1 -1
- data/spec/dummy/app/models/assignment_group.rb +3 -2
- data/spec/dummy/app/models/context_module.rb +8 -1
- data/spec/dummy/app/models/context_module_item.rb +8 -1
- data/spec/dummy/app/models/course.rb +1 -1
- data/spec/dummy/app/models/enrollment.rb +1 -1
- data/spec/dummy/app/models/role.rb +1 -1
- data/spec/dummy/app/models/section.rb +2 -1
- data/spec/dummy/app/models/submission.rb +1 -1
- data/spec/dummy/app/models/term.rb +1 -1
- data/spec/dummy/app/models/user.rb +1 -1
- data/spec/dummy/app/services/live_events/assignment_event.rb +19 -36
- data/spec/dummy/app/services/live_events/base_event.rb +26 -0
- data/spec/dummy/app/services/live_events/course_event.rb +15 -27
- data/spec/dummy/app/services/live_events/course_section_event.rb +13 -39
- data/spec/dummy/app/services/live_events/enrollment_event.rb +17 -48
- data/spec/dummy/app/services/live_events/grade_event.rb +9 -34
- data/spec/dummy/app/services/live_events/module_event.rb +10 -29
- data/spec/dummy/app/services/live_events/module_item_event.rb +10 -28
- data/spec/dummy/app/services/live_events/submission_event.rb +12 -42
- data/spec/dummy/app/services/live_events/syllabus_event.rb +11 -20
- data/spec/dummy/app/services/live_events/user_event.rb +14 -25
- data/spec/dummy/db/migrate/{20190603215718_create_users.rb → 20190702203620_create_users.rb} +1 -1
- data/spec/dummy/db/migrate/{20190603220011_create_courses.rb → 20190702203621_create_courses.rb} +1 -1
- data/spec/dummy/db/migrate/{20190604193942_create_accounts.rb → 20190702203622_create_accounts.rb} +1 -1
- data/spec/dummy/db/migrate/{20190603215721_create_terms.rb → 20190702203623_create_terms.rb} +1 -1
- data/spec/dummy/db/migrate/{20190603220013_create_enrollments.rb → 20190702203624_create_enrollments.rb} +1 -1
- data/spec/dummy/db/migrate/{20190603215722_create_sections.rb → 20190702203625_create_sections.rb} +1 -1
- data/spec/dummy/db/migrate/{20190603192310_create_assignments.rb → 20190702203626_create_assignments.rb} +1 -1
- data/spec/dummy/db/migrate/{20190521003447_create_submissions.rb → 20190702203627_create_submissions.rb} +1 -1
- data/spec/dummy/db/migrate/{20190606161037_create_roles.rb → 20190702203628_create_roles.rb} +1 -1
- data/spec/dummy/db/migrate/{20190521003449_create_admins.rb → 20190702203629_create_admins.rb} +1 -1
- data/spec/dummy/db/migrate/{20190521003450_create_assignment_groups.rb → 20190702203630_create_assignment_groups.rb} +1 -1
- data/spec/dummy/db/migrate/{20190521003451_create_context_modules.rb → 20190702203631_create_context_modules.rb} +1 -1
- data/spec/dummy/db/migrate/{20190603193502_create_context_module_items.rb → 20190702203632_create_context_module_items.rb} +1 -1
- data/spec/dummy/db/schema.rb +1 -1
- metadata +41 -67
- data/lib/canvas_sync/generators/templates/services/live_events/assignment/assignment_created_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/assignment/assignment_event.rb +0 -54
- data/lib/canvas_sync/generators/templates/services/live_events/assignment/assignment_updated_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/course/course_created_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/course/course_event.rb +0 -36
- data/lib/canvas_sync/generators/templates/services/live_events/course/course_updated_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/course_section/course_section_created_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/course_section/course_section_event.rb +0 -48
- data/lib/canvas_sync/generators/templates/services/live_events/course_section/course_section_updated_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/enrollment/enrollment_created_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/enrollment/enrollment_event.rb +0 -55
- data/lib/canvas_sync/generators/templates/services/live_events/enrollment/enrollment_updated_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/grade/grade_changed_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/grade/grade_event.rb +0 -55
- data/lib/canvas_sync/generators/templates/services/live_events/module/module_created_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/module/module_event.rb +0 -39
- data/lib/canvas_sync/generators/templates/services/live_events/module/module_updated_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/module_item/module_item_created_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/module_item/module_item_event.rb +0 -37
- data/lib/canvas_sync/generators/templates/services/live_events/module_item/module_item_updated_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/submission/submission_created_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/submission/submission_event.rb +0 -52
- data/lib/canvas_sync/generators/templates/services/live_events/submission/submission_updated_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/syllabus/syllabus_event.rb +0 -34
- data/lib/canvas_sync/generators/templates/services/live_events/syllabus/syllabus_updated_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/user/user_created_event.rb +0 -6
- data/lib/canvas_sync/generators/templates/services/live_events/user/user_event.rb +0 -34
- data/lib/canvas_sync/generators/templates/services/live_events/user/user_updated_event.rb +0 -6
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +0 -1248
- data/spec/dummy/log/test.log +0 -43258
- data/spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv +0 -3
- data/spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f220a92d0d85cce6ff10b1ef1a10784039e93583
|
4
|
+
data.tar.gz: 0c305e04af7875261f6c36561b1b39e073f41c41
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ec6ceaf390ae8a814420d927b1294b66492bd855b62ef9d80042e973871aac7dfb45b061861d503b8ee5303371e67c3df1446be4b159f7f8991ec237684007ad
|
7
|
+
data.tar.gz: 83c67e7bdd93c2ac6e068309955c04a08e8f6204481f667049cb3ac6dc8ba5212c31f5e25febde46a788bc5582d18c893cf421718f7604a2399623289e9ff422
|
@@ -13,6 +13,10 @@ module CanvasSync
|
|
13
13
|
# You can customize it as needed, but make sure you test
|
14
14
|
# any changes you make to the auto generated methods.
|
15
15
|
#
|
16
|
+
# LiveEvent message formats can be found at https://canvas.instructure.com/doc/api/file.live_events.html
|
17
|
+
# In the general case, LiveEvent message content should not be trusted - it is highly possible that events may
|
18
|
+
# arrive out of order. Most of the CanvasSync LiveEvent templates solve this by always fetching the object from the API.
|
19
|
+
#
|
16
20
|
HERE
|
17
21
|
end
|
18
22
|
|
@@ -28,7 +32,7 @@ module CanvasSync
|
|
28
32
|
CanvasSync.validate_live_events!(events)
|
29
33
|
|
30
34
|
events.each do |event|
|
31
|
-
Dir.glob("#{File.dirname(__FILE__)}/templates/services/live_events/#{event}
|
35
|
+
Dir.glob("#{File.dirname(__FILE__)}/templates/services/live_events/#{event}_event.rb") do |rb_file|
|
32
36
|
template rb_file.to_s, "app/services/live_events/#{File.basename(rb_file)}"
|
33
37
|
end
|
34
38
|
end
|
@@ -1,10 +1,17 @@
|
|
1
|
-
<%= autogenerated_migration_warning %>
|
1
|
+
# # <%= autogenerated_migration_warning %>
|
2
2
|
|
3
3
|
# A ContextModule is the same as a Canvas Module. They're called ContextModules for 2 reasons:
|
4
4
|
# 1 - Module is a reserved word in Rails and you can't call a model a Module
|
5
5
|
# 2 - Canvas calls them ContextModules
|
6
6
|
class ContextModule < ApplicationRecord
|
7
|
+
include CanvasSync::ApiSyncable
|
8
|
+
|
7
9
|
belongs_to :context, polymorphic: true, optional: true, primary_key: :canvas_id, foreign_key: :canvas_context_id, foreign_type: :canvas_context_type
|
8
10
|
has_many :context_module_items, primary_key: :canvas_id, foreign_key: :canvas_context_module_id
|
9
11
|
has_many :assignments, through: :context_module_items
|
12
|
+
|
13
|
+
api_syncable({
|
14
|
+
# TODO If your tool Syncs ContextModules, please complete this and merge it into CanvasSync
|
15
|
+
}, -> (api) { api.course_module(canvas_context_id, canvas_id) })
|
16
|
+
|
10
17
|
end
|
@@ -1,7 +1,14 @@
|
|
1
|
-
# <%= autogenerated_migration_warning %>
|
1
|
+
# # <%= autogenerated_migration_warning %>
|
2
2
|
|
3
3
|
class ContextModuleItem < ApplicationRecord
|
4
|
+
include CanvasSync::ApiSyncable
|
5
|
+
|
4
6
|
belongs_to :context_module, primary_key: :canvas_id, foreign_key: :canvas_context_module_id, optional: true
|
5
7
|
belongs_to :content, polymorphic: true, optional: true, primary_key: :canvas_id, foreign_key: :canvas_content_id, foreign_type: :canvas_content_type
|
6
8
|
belongs_to :assignment, foreign_key: :canvas_assignment_id, primary_key: :canvas_id
|
9
|
+
|
10
|
+
api_syncable({
|
11
|
+
# TODO If your tool Syncs ContextModuleItems, please complete this and merge it into CanvasSync
|
12
|
+
}, -> (api) { api.module_item(context_module.context.canvas_id, context_module.canvas_id, canvas_id) })
|
13
|
+
|
7
14
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
<%= autogenerated_model_warning %>
|
1
|
+
# <%= autogenerated_model_warning %>
|
2
2
|
|
3
3
|
class Section < ApplicationRecord
|
4
4
|
include CanvasSync::ApiSyncable
|
@@ -14,5 +14,6 @@ class Section < ApplicationRecord
|
|
14
14
|
name: :name,
|
15
15
|
start_at: :start_at,
|
16
16
|
end_at: :end_at,
|
17
|
+
workflow_state: ->(r){ 'active' },
|
17
18
|
}, -> (api) { api.section(canvas_id) })
|
18
19
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# <%= autogenerated_event_warning %>
|
2
|
+
|
3
|
+
module LiveEvents
|
4
|
+
class AssignmentEvent < LiveEvents::BaseEvent
|
5
|
+
|
6
|
+
def process
|
7
|
+
canvas_assignment_id = local_canvas_id(payload[:assignment_id])
|
8
|
+
assignment = Assignment.where(canvas_id: canvas_assignment_id).first_or_initialize
|
9
|
+
assignment.context_id = canvas_course_id
|
10
|
+
assignment.sync_from_api
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# This could be nil if the context type for this assignment is not 'Course' of if a local course was not found
|
16
|
+
def canvas_course_id
|
17
|
+
payload[:context_type] == "Course" ? local_canvas_id(payload[:context_id]) : nil
|
18
|
+
end
|
19
|
+
|
20
|
+
# This could be nil if the context type for this assignment is not 'Course' of if a local course was not found
|
21
|
+
def course
|
22
|
+
@course ||= begin
|
23
|
+
course = Course.where(canvas_id: canvas_course_id).first_or_initialize
|
24
|
+
course.sync_from_api unless course.persisted?
|
25
|
+
course
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
class AssignmentCreatedEvent < LiveEvents::AssignmentEvent; end
|
32
|
+
class AssignmentUpdatedEvent < LiveEvents::AssignmentEvent; end
|
33
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# <%= autogenerated_event_warning %>
|
2
|
+
|
3
|
+
module LiveEvents
|
4
|
+
class AssignmentGroupEvent < LiveEvents::BaseEvent
|
5
|
+
|
6
|
+
def process
|
7
|
+
canvas_assignment_group_id = local_canvas_id(payload[:assignment_group_id])
|
8
|
+
assignment_group = AssignmentGroup.where(canvas_id: canvas_assignment_group_id).first_or_initialize
|
9
|
+
assignment_group.canvas_course_id = canvas_course_id
|
10
|
+
assignment_group.sync_from_api
|
11
|
+
end
|
12
|
+
|
13
|
+
private
|
14
|
+
|
15
|
+
# This could be nil if the context type for this assignment is not 'Course' of if a local course was not found
|
16
|
+
def canvas_course_id
|
17
|
+
payload[:context_type] == "Course" ? local_canvas_id(payload[:context_id]) : nil
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
class AssignmentGroupCreatedEvent < LiveEvents::AssignmentGroupEvent; end
|
23
|
+
class AssignmentGroupUpdatedEvent < LiveEvents::AssignmentGroupEvent; end
|
24
|
+
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
# <%= autogenerated_event_warning %>
|
2
2
|
|
3
3
|
module LiveEvents
|
4
|
+
class RetryLiveEventJob < StandardError; end
|
5
|
+
|
4
6
|
class BaseEvent < CanvasSync::Job
|
5
7
|
attr_accessor :raw_payload
|
6
8
|
attr_accessor :payload
|
@@ -10,11 +12,31 @@ module LiveEvents
|
|
10
12
|
@raw_payload = event_payload
|
11
13
|
@metadata = HashWithIndifferentAccess.new(event_payload["attributes"])
|
12
14
|
@payload = HashWithIndifferentAccess.new(event_payload["body"])
|
15
|
+
process_with_retry
|
16
|
+
end
|
17
|
+
|
18
|
+
def process
|
19
|
+
raise "process must be implemented in your subclass"
|
13
20
|
end
|
14
21
|
|
15
22
|
# Live events will use a canvas global ID (cross shard) for any ID's provided. This method will return the local ID.
|
16
23
|
def local_canvas_id(id)
|
17
24
|
id.to_i % 10_000_000_000_000
|
18
25
|
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Sometimes a creation and update event get sent by Canvas at almost the exact same time. This means
|
30
|
+
# that there is sometimes a race condition that causes them to both try to save a new record at the same time.
|
31
|
+
# If that happens, just wait a few seconds and try again -- the second try should be able to see that
|
32
|
+
# the save already occured, and it will just update the row..
|
33
|
+
def process_with_retry
|
34
|
+
tries ||= 5
|
35
|
+
process
|
36
|
+
rescue ActiveRecord::RecordNotUnique, ActiveRecord::RecordInvalid, RetryLiveEventJob => e
|
37
|
+
raise e if (tries -= 1).zero?
|
38
|
+
sleep 5
|
39
|
+
retry
|
40
|
+
end
|
19
41
|
end
|
20
42
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# <%= autogenerated_event_warning %>
|
2
|
+
|
3
|
+
module LiveEvents
|
4
|
+
class CourseEvent < LiveEvents::BaseEvent
|
5
|
+
|
6
|
+
def process
|
7
|
+
course = Course.where(canvas_id: local_canvas_id(payload[:course_id])).first_or_initialize
|
8
|
+
course.canvas_account_id = local_canvas_id(payload[:account_id])
|
9
|
+
if course.account.nil?
|
10
|
+
acc = Account.new(canvas_id: course.canvas_account_id)
|
11
|
+
acc.sync_from_api
|
12
|
+
end
|
13
|
+
course.sync_from_api
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
class CourseCreatedEvent < LiveEvents::CourseEvent; end
|
19
|
+
class CourseUpdatedEvent < LiveEvents::CourseEvent; end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# <%= autogenerated_event_warning %>
|
2
|
+
|
3
|
+
module LiveEvents
|
4
|
+
class CourseSectionEvent < LiveEvents::BaseEvent
|
5
|
+
|
6
|
+
def process
|
7
|
+
section = Section.where(canvas_id: local_canvas_id(payload[:course_section_id])).first_or_initialize
|
8
|
+
section.sync_from_api
|
9
|
+
# A section change could constitute a crosslisting change, which means
|
10
|
+
# we need to make sure all our enrollments are pointing to the correct course
|
11
|
+
section.enrollments.update_all(canvas_course_id: section.canvas_course_id)
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
class CourseSectionCreatedEvent < LiveEvents::CourseSectionEvent; end
|
17
|
+
class CourseSectionUpdatedEvent < LiveEvents::CourseSectionEvent; end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# <%= autogenerated_event_warning %>
|
2
|
+
|
3
|
+
module LiveEvents
|
4
|
+
class EnrollmentEvent < LiveEvents::BaseEvent
|
5
|
+
attr_accessor :enrollment
|
6
|
+
|
7
|
+
def process()
|
8
|
+
@enrollment = Enrollment.where(canvas_id: local_canvas_id(payload[:enrollment_id])).first_or_initialize
|
9
|
+
enrollment.canvas_course_id = local_canvas_id(payload[:course_id])
|
10
|
+
enrollment.sync_from_api
|
11
|
+
if enrollment.user.nil?
|
12
|
+
u = User.new(canvas_id: enrollment.canvas_user_id)
|
13
|
+
u.sync_from_api
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class EnrollmentCreatedEvent < LiveEvents::EnrollmentEvent; end
|
19
|
+
class EnrollmentUpdatedEvent < LiveEvents::EnrollmentEvent; end
|
20
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# <%= autogenerated_event_warning %>
|
2
|
+
|
3
|
+
module LiveEvents
|
4
|
+
class GradeEvent < LiveEvents::BaseEvent
|
5
|
+
|
6
|
+
def process
|
7
|
+
raise "process must be implemented in your subclass"
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def submission
|
13
|
+
Submission.find_by(canvas_submission_id: local_canvas_id(payload[:submission_id]))
|
14
|
+
end
|
15
|
+
|
16
|
+
def assignment
|
17
|
+
Assignment.find_by(canvas_assignment_id: local_canvas_id(payload[:assignment_id]))
|
18
|
+
end
|
19
|
+
|
20
|
+
def user
|
21
|
+
User.find_by(canvas_user_id: local_canvas_id(payload[:user_id]))
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class GradeChangedEvent < LiveEvents::GradeEvent; end
|
26
|
+
end
|