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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f5aacd90f1c55b16e6cd1faac3695c27d102a026
4
- data.tar.gz: 537204f3c66ab4f9a639afbdc23abbabb31e7b52
3
+ metadata.gz: 8f7a480e67851b3de7f12b0df8569aa09aa36431
4
+ data.tar.gz: 51923b6e9707be4f3969160cfa495d1bb75c19c0
5
5
  SHA512:
6
- metadata.gz: 9681ea9b57ea44cfdb2676192515ff7992efcdbf9af34b46619bc3af680774bf8792efbafe29a7f151d522ae18d41e7fe4e23f15e2bb0945d988c22d1dbccc2e
7
- data.tar.gz: 6e8d2dc6ba412e169cdf4a0b204b1893647773b62264e59d655a2dd87bd522e36b620976c9169e9b8590112284b6872b7c77ca00503cccb839f0854f5108e841
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.
@@ -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
@@ -1,3 +1,3 @@
1
1
  module CanvasSync
2
- VERSION = "0.8.1".freeze
2
+ VERSION = "0.8.2".freeze
3
3
  end
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.1
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-05 00:00:00.000000000 Z
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