canvas_sync 0.8.1 → 0.8.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +20 -1
- data/lib/canvas_sync.rb +1 -0
- data/lib/canvas_sync/api_syncable.rb +65 -0
- data/lib/canvas_sync/generators/templates/models/account.rb +8 -0
- data/lib/canvas_sync/generators/templates/models/assignment.rb +21 -0
- data/lib/canvas_sync/generators/templates/models/course.rb +14 -0
- data/lib/canvas_sync/generators/templates/models/enrollment.rb +16 -0
- data/lib/canvas_sync/generators/templates/models/section.rb +12 -0
- data/lib/canvas_sync/generators/templates/models/submission.rb +11 -0
- data/lib/canvas_sync/generators/templates/models/user.rb +13 -0
- data/lib/canvas_sync/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8f7a480e67851b3de7f12b0df8569aa09aa36431
|
4
|
+
data.tar.gz: 51923b6e9707be4f3969160cfa495d1bb75c19c0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: '029af7cd4b8d5f277c5688c9439fe98435cf40dd2f8f88093b8c743a527d4864f3c3a7af4e4544bdd8ec0372fff954aea6f688a59dee6f3608e3fd4af3b4abe1'
|
7
|
+
data.tar.gz: 4d4825e66d7e8f2e3850c6422eba37fc0afcee18b9380039837c15238f25fc73aab8dda0c58784b4557f84360f2d4b5ee4492582ae568167d57ab208c3315613
|
data/README.md
CHANGED
@@ -189,7 +189,7 @@ Overrides are useful for two scenarios:
|
|
189
189
|
|
190
190
|
In order to create an override, place a file called `canvas_sync_provisioning_mapping.yml` in your Rails `config` directory. Define the tables and columns you want to override using the following format:
|
191
191
|
|
192
|
-
```
|
192
|
+
```ruby
|
193
193
|
users:
|
194
194
|
conflict_target: canvas_user_id # This must be a unique field that is present in the report and the database
|
195
195
|
report_columns: # The keys specified here are the column names in the report CSV
|
@@ -198,6 +198,25 @@ users:
|
|
198
198
|
type: integer
|
199
199
|
```
|
200
200
|
|
201
|
+
### API Sync
|
202
|
+
Several models implement the `ApiSyncable` Concern. This is done in the Model Templates so as to be customizable and tweakable.
|
203
|
+
Models that `include CanvasSync::ApiSyncable` should also call the `api_syncable` class method to configure the Synchronization.
|
204
|
+
`api_syncable` takes two arguments and an optional block callback:
|
205
|
+
```ruby
|
206
|
+
class CanvasSyncModel < ApplicationRecord
|
207
|
+
api_syncable(
|
208
|
+
{
|
209
|
+
local_field: :response_field, # api_response[:response_field] will be mapped to local_field on the model.
|
210
|
+
local_field: -> (api_response) { api_response[:some_field] + 5 }, # A calculated result will be mapped to local_field on the model. The lambda is executed in the context of the model instance.
|
211
|
+
},
|
212
|
+
-> (bearcat) { bearcat.some_request(some_model_getter) } # A lambda, executed in the context of the model instance, to actually make the API call. Should accept 0 or 1 parameters. Must accept 0 parameters if your `canvas_sync_client` requires an `account_id`
|
213
|
+
) do |api_response, mapped_fields| # Must accept 1-2 parameters
|
214
|
+
# Override behavior for actually applying the response to the model instance
|
215
|
+
end
|
216
|
+
end
|
217
|
+
```
|
218
|
+
|
219
|
+
|
201
220
|
## Legacy Support
|
202
221
|
|
203
222
|
If you have an old style tool that needs to sync data on a row by row basis, you can pass in the `legacy_support: true` option. In order for this to work, your models must have a `create_or_update_from_csv` class method defined that accepts a row argument. This method will get passed each row from the CSV, and it's up to you to persist it.
|
data/lib/canvas_sync.rb
CHANGED
@@ -3,6 +3,7 @@ require "canvas_sync/version"
|
|
3
3
|
require "canvas_sync/engine"
|
4
4
|
require "canvas_sync/job"
|
5
5
|
require "canvas_sync/sidekiq_job"
|
6
|
+
require "canvas_sync/api_syncable"
|
6
7
|
require "canvas_sync/jobs/report_starter"
|
7
8
|
require "canvas_sync/jobs/report_checker"
|
8
9
|
require "canvas_sync/jobs/report_processor_job"
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module CanvasSync::ApiSyncable
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
class_methods do
|
5
|
+
attr_accessor :api_sync_map, :api_sync_fetch, :api_sync_block
|
6
|
+
|
7
|
+
def api_syncable(map, fetch, &blk)
|
8
|
+
self.api_sync_map = map
|
9
|
+
self.api_sync_fetch = fetch
|
10
|
+
self.api_sync_block = blk
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def sync_from_api(retries: 3)
|
15
|
+
params = api_call_with_retry(retries || 3) {
|
16
|
+
blk = self.class.api_sync_fetch
|
17
|
+
case blk.arity
|
18
|
+
when 1
|
19
|
+
self.instance_exec(canvas_sync_client, &blk)
|
20
|
+
else
|
21
|
+
self.instance_exec(&blk)
|
22
|
+
end
|
23
|
+
}
|
24
|
+
update_from_api_params!(params)
|
25
|
+
end
|
26
|
+
|
27
|
+
def update_from_api_params!(api_params)
|
28
|
+
api_params = api_params.with_indifferent_access
|
29
|
+
apply_block = self.class.api_sync_block
|
30
|
+
map = self.class.api_sync_map
|
31
|
+
|
32
|
+
mapped_params = {}
|
33
|
+
if map.present?
|
34
|
+
map.each do |local_name, remote_name|
|
35
|
+
mapped_params[local_name] = remote_name.respond_to?(:call) ? self.instance_exec(api_params, &remote_name) : api_params[remote_name]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
if apply_block.present?
|
40
|
+
case apply_block.arity
|
41
|
+
when 1
|
42
|
+
self.instance_exec(api_params, &apply_block)
|
43
|
+
when 2
|
44
|
+
self.instance_exec(api_params, mapped_params, &apply_block)
|
45
|
+
end
|
46
|
+
else
|
47
|
+
mapped_params.each do |local_name, val|
|
48
|
+
send("#{local_name}=", val)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
save! if changed?
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def api_call_with_retry(retries=3)
|
58
|
+
tries ||= retries
|
59
|
+
yield
|
60
|
+
rescue Faraday::ConnectionFailed => e
|
61
|
+
raise e if (tries -= 1).zero?
|
62
|
+
sleep 5
|
63
|
+
retry
|
64
|
+
end
|
65
|
+
end
|
@@ -1,5 +1,13 @@
|
|
1
1
|
<%= autogenerated_model_warning %>
|
2
2
|
|
3
3
|
class Account < ApplicationRecord
|
4
|
+
include CanvasSync::ApiSyncable
|
5
|
+
|
4
6
|
validates :canvas_account_id, uniqueness: true, presence: true
|
7
|
+
|
8
|
+
api_syncable({
|
9
|
+
name: :name,
|
10
|
+
status: :status,
|
11
|
+
canvas_parent_id: :canvas_parent_id,
|
12
|
+
}, -> (api) { api.account(canvas_account_id) })
|
5
13
|
end
|
@@ -1,10 +1,31 @@
|
|
1
1
|
<%= autogenerated_model_warning %>
|
2
2
|
|
3
3
|
class Assignment < ApplicationRecord
|
4
|
+
include CanvasSync::ApiSyncable
|
5
|
+
|
4
6
|
validates :canvas_assignment_id, uniqueness: true, presence: true
|
5
7
|
belongs_to :context, polymorphic: true, optional: true, primary_key: :canvas_course_id
|
6
8
|
belongs_to :assignment_group, optional: true, primary_key: :canvas_assignment_group_id, foreign_key: :canvas_assignment_group_id
|
7
9
|
has_many :submissions, primary_key: :canvas_assignment_id, foreign_key: :canvas_assignment_id
|
8
10
|
has_many :context_module_items, primary_key: :canvas_assignment_id, foreign_key: :content_id, dependent: :destroy
|
9
11
|
has_many :context_modules, through: :context_module_items
|
12
|
+
|
13
|
+
api_syncable({
|
14
|
+
title: :tile,
|
15
|
+
description: :description,
|
16
|
+
due_at: :due_at,
|
17
|
+
unlock_at: :unlock_at,
|
18
|
+
points_posible: :points_posible,
|
19
|
+
min_score: :min_score,
|
20
|
+
max_score: :max_score,
|
21
|
+
mastery_score: :mastery_score,
|
22
|
+
grading_type: :grading_type,
|
23
|
+
submission_types: lambda { |_a, p| p["submission_types"].join(",") },
|
24
|
+
workflow_state: :workflow_state,
|
25
|
+
context_id: :course_id,
|
26
|
+
context_type: lambda { |_a, _p| "Course" },
|
27
|
+
canvas_assignment_group_id: :canvas_assignment_group_id,
|
28
|
+
grading_scheme_id: :grading_scheme_id,
|
29
|
+
grading_standard_id: :grading_standard_id,
|
30
|
+
}, -> (api) { api.assignment(context_id, canvas_assignment_id) })
|
10
31
|
end
|
@@ -1,6 +1,8 @@
|
|
1
1
|
<%= autogenerated_model_warning %>
|
2
2
|
|
3
3
|
class Course < ApplicationRecord
|
4
|
+
include CanvasSync::ApiSyncable
|
5
|
+
|
4
6
|
validates :canvas_course_id, uniqueness: true, presence: true
|
5
7
|
belongs_to :term, foreign_key: :canvas_term_id, primary_key: :canvas_term_id, optional: true
|
6
8
|
has_many :enrollments, primary_key: :canvas_course_id, foreign_key: :canvas_course_id
|
@@ -8,4 +10,16 @@ class Course < ApplicationRecord
|
|
8
10
|
has_many :assignments, as: :context, primary_key: :canvas_course_id
|
9
11
|
has_many :submissions, primary_key: :canvas_course_id, foreign_key: :canvas_course_id
|
10
12
|
has_many :assignment_groups, primary_key: :canvas_course_id, foreign_key: :canvas_course_id
|
13
|
+
|
14
|
+
api_syncable({
|
15
|
+
sis_id: :sis_id,
|
16
|
+
short_name: :short_name,
|
17
|
+
long_name: :long_name,
|
18
|
+
status: :status,
|
19
|
+
canvas_term_id: :canvas_term_id,
|
20
|
+
canvas_account_id: :canvas_account_id,
|
21
|
+
term_sis_id: :term_sis_id,
|
22
|
+
start_date: :start_date,
|
23
|
+
end_date: :end_date,
|
24
|
+
}, -> (api) { api.course(canvas_course_id) })
|
11
25
|
end
|
@@ -1,8 +1,24 @@
|
|
1
1
|
<%= autogenerated_model_warning %>
|
2
2
|
|
3
3
|
class Enrollment < ApplicationRecord
|
4
|
+
include CanvasSync::ApiSyncable
|
5
|
+
|
4
6
|
validates :canvas_enrollment_id, uniqueness: true, presence: true
|
5
7
|
belongs_to :user, primary_key: :canvas_user_id, foreign_key: :canvas_user_id, optional: true
|
6
8
|
belongs_to :course, primary_key: :canvas_course_id, foreign_key: :canvas_course_id, optional: true
|
7
9
|
belongs_to :section, primary_key: :canvas_section_id, foreign_key: :canvas_section_id, optional: true
|
10
|
+
|
11
|
+
api_syncable({
|
12
|
+
canvas_enrollment_id: :canvas_enrollment_id,
|
13
|
+
canvas_course_id: :canvas_course_id,
|
14
|
+
course_sis_id: :course_sis_id,
|
15
|
+
canvas_user_id: :canvas_user_id,
|
16
|
+
user_sis_id: :user_sis_id,
|
17
|
+
canvas_section_id: :canvas_section_id,
|
18
|
+
section_sis_id: :section_sis_id,
|
19
|
+
role: :role,
|
20
|
+
role_id: :role_id,
|
21
|
+
status: :status,
|
22
|
+
base_role_type: :base_role_type,
|
23
|
+
}, -> (api) { api.enrollment("self", canvas_enrollment_id) })
|
8
24
|
end
|
@@ -1,7 +1,19 @@
|
|
1
1
|
<%= autogenerated_model_warning %>
|
2
2
|
|
3
3
|
class Section < ApplicationRecord
|
4
|
+
include CanvasSync::ApiSyncable
|
5
|
+
|
4
6
|
validates :canvas_section_id, uniqueness: true, presence: true
|
5
7
|
belongs_to :course, primary_key: :canvas_course_id, foreign_key: :canvas_course_id, optional: true
|
6
8
|
has_many :enrollments, primary_key: :canvas_section_id, foreign_key: :canvas_section_id
|
9
|
+
|
10
|
+
api_syncable({
|
11
|
+
sis_id: :sis_id,
|
12
|
+
canvas_course_id: :canvas_course_id,
|
13
|
+
canvas_nonxlist_course_id: :canvas_nonxlist_course_id,
|
14
|
+
name: :name,
|
15
|
+
status: :status,
|
16
|
+
start_date: :start_at,
|
17
|
+
end_date: :end_at,
|
18
|
+
}, -> (api) { api.section(canvas_section_id) })
|
7
19
|
end
|
@@ -1,8 +1,19 @@
|
|
1
1
|
<%= autogenerated_model_warning %>
|
2
2
|
|
3
3
|
class Submission < ApplicationRecord
|
4
|
+
include CanvasSync::ApiSyncable
|
5
|
+
|
4
6
|
validates :canvas_submission_id, uniqueness: true, presence: true
|
5
7
|
belongs_to :assignment, primary_key: :canvas_assignment_id, foreign_key: :canvas_assignment_id, optional: true
|
6
8
|
belongs_to :user, primary_key: :canvas_user_id, foreign_key: :canvas_user_id, optional: true
|
7
9
|
belongs_to :course, primary_key: :canvas_course_id, foreign_key: :canvas_course_id, optional: true
|
10
|
+
|
11
|
+
api_syncable({
|
12
|
+
submitted_at: :submitted_at,
|
13
|
+
graded_at: :graded_at,
|
14
|
+
score: :score,
|
15
|
+
points_possible: :points_possible,
|
16
|
+
excused: :excused,
|
17
|
+
workflow_state: :workflow_state,
|
18
|
+
}, -> (api) { api.user_course_assignment_submission(assignment.context.canvas_course_id, canvas_assignment_id, canvas_user_id) })
|
8
19
|
end
|
@@ -1,9 +1,22 @@
|
|
1
1
|
<%= autogenerated_model_warning %>
|
2
2
|
|
3
3
|
class User < ApplicationRecord
|
4
|
+
include CanvasSync::ApiSyncable
|
5
|
+
|
4
6
|
validates :canvas_user_id, uniqueness: true, presence: true
|
5
7
|
has_many :enrollments, primary_key: :canvas_user_id, foreign_key: :canvas_user_id
|
6
8
|
has_many :admins, foreign_key: :canvas_user_id, primary_key: :canvas_user_id
|
7
9
|
has_many :admin_roles, through: :admins, source: :role
|
8
10
|
has_many :submissions, primary_key: :canvas_user_id, foreign_key: :canvas_user_id
|
11
|
+
|
12
|
+
api_syncable({
|
13
|
+
sis_id: :sis_id,
|
14
|
+
email: :email,
|
15
|
+
login_id: :login_id,
|
16
|
+
full_name: :name,
|
17
|
+
sortable_name: :sortable_name,
|
18
|
+
first_name: :first_name,
|
19
|
+
last_name: :last_name,
|
20
|
+
status: :status,
|
21
|
+
}, -> (api) { api.user_detail(canvas_user_id) })
|
9
22
|
end
|
data/lib/canvas_sync/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: canvas_sync
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.8.
|
4
|
+
version: 0.8.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nate Collings
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-02-
|
11
|
+
date: 2019-02-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -320,6 +320,7 @@ files:
|
|
320
320
|
- db/migrate/20170915210836_create_canvas_sync_job_log.rb
|
321
321
|
- db/migrate/20180725155729_add_job_id_to_canvas_sync_job_logs.rb
|
322
322
|
- lib/canvas_sync.rb
|
323
|
+
- lib/canvas_sync/api_syncable.rb
|
323
324
|
- lib/canvas_sync/config.rb
|
324
325
|
- lib/canvas_sync/engine.rb
|
325
326
|
- lib/canvas_sync/generators/install_generator.rb
|