canvas_sync 0.1.1 → 0.1.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: d6178b9db26d809e2e35b5c4d38187d2ceb14018
4
- data.tar.gz: ec84b34894e5b40e27666cdb0946053a355cf422
3
+ metadata.gz: 1489eac6e822527f27f73828fbe9bcccad401e55
4
+ data.tar.gz: e91a8c75620d6006dc935a2f7774e2cce04b4922
5
5
  SHA512:
6
- metadata.gz: 4ee7ea65f6c785d05559f52b841483ea2a316509373feedc7c29a35599bfe99d20214ca3a2b2116d1ef503d366a03ec6382d59eb0636e361138cb6378ef6afe1
7
- data.tar.gz: aaf71eaaf57f0ff80e7c5e92a22f3a3340e57358ab9a1042f1e821ad15dacbd0b401fd93199bbd0c0e9bbb3ff5540c223ce512be15315b5ad71dd43591e92875
6
+ metadata.gz: 3a8bb596f0e3c59b5318c1cb79927ca74fc08733a0e4db1733dc9ba45b6c2613ae13d1732a3b79dd8c99e3ec0f55be69c0740b44a3beced935c1a0c390f8e9ba
7
+ data.tar.gz: 163a3abc8abcba6f3406bcc0feb31fdb5b71fed6648d730bb716af112aa4fa8fddfd6487f1f4c860ed0117c9fad7f813400fb9bcfcb67601f05bf599eed7352c
data/README.md CHANGED
@@ -34,16 +34,27 @@ The yard server will give you a URL you can visit to view the docs.
34
34
 
35
35
  ## Basic Usage
36
36
 
37
- Your tool must have an `ActiveJob` compatible job queue adapter configured, such as DelayedJob or Sidekiq. Once that's done and you've used the generator to create your models and migrations you can run the standard provisioning sync:
37
+ Your tool must have an `ActiveJob` compatible job queue adapter configured, such as DelayedJob or Sidekiq. Additionally, you must have a method called `canvas_sync_client` defined in an initializer that returns a Bearcat client for the Canvas instance you are syncing against. Example:
38
38
 
39
39
  ```ruby
40
- CanvasSync.provisioning_sync(<canvas base url>, <canvas api token>, <array of models to sync>, <optional term scope>)
40
+ # config/initializers/canvas_sync.rb
41
+ def canvas_sync_client
42
+ Bearcat::Client.new(token: current_organization.settings[:api_token], prefix: current_organization.settings[:base_url])
43
+ end
44
+ ```
45
+
46
+ (Having the client defined here means the sensitive API token doesn't have to be passed in plain text between jobs.)
47
+
48
+ Once that's done and you've used the generator to create your models and migrations you can run the standard provisioning sync:
49
+
50
+ ```ruby
51
+ CanvasSync.provisioning_sync(<array of models to sync>, <optional term scope>)
41
52
  ```
42
53
 
43
54
  Example:
44
55
 
45
56
  ```ruby
46
- CanvasSync.provisioning_sync("https://pseng.instructure.com", "12345", ['users', 'courses'], :active)
57
+ CanvasSync.provisioning_sync(['users', 'courses'], :active)
47
58
  ```
48
59
 
49
60
  This will kick off a string of jobs to sync your specified models.
@@ -76,14 +87,12 @@ end
76
87
 
77
88
  You must implement a job that will enqueue a report starter for your report. (TODO: would be nice to make some sort of builder for this, so you just define the report and its params and then the gem runs it in a pre-defined job.)
78
89
 
79
- Let's say we have a custom Canvas report called "my_really_cool_report_csv". First, we would need to create a job class that will enqueue a report starter. To work with the `CanvasSync` interface, your class must accept 4 parameters: `canvas_base_url`, `canvas_api_token`, `job_chain`, and `options`.
90
+ Let's say we have a custom Canvas report called "my_really_cool_report_csv". First, we would need to create a job class that will enqueue a report starter. To work with the `CanvasSync` interface, your class must accept 2 parameters: `job_chain`, and `options`.
80
91
 
81
92
  ```ruby
82
93
  class MyReallyCoolReportJob < CanvasSync::Jobs::ReportStarter
83
- def perform(canvas_base_url, canvas_api_token, job_chain, options)
94
+ def perform(job_chain, options)
84
95
  super(
85
- canvas_base_url,
86
- canvas_api_token,
87
96
  job_chain,
88
97
  'my_really_cool_report_csv', # Report name
89
98
  { "parameters[param1]" => true }, # Report parameters
@@ -121,7 +130,7 @@ job_chain = {
121
130
  options: {}
122
131
  }
123
132
 
124
- CanvasSync.process_jobs("https://pseng.instructure.com", "my-api-token", job_chain)
133
+ CanvasSync.process_jobs(job_chain)
125
134
  ```
126
135
 
127
136
  What if you've got some other job that you want run that doesn't deal with a report? No problem! Just make sure you call `CanvasSync.invoke_next` at the end of your job. Example:
@@ -129,10 +138,10 @@ What if you've got some other job that you want run that doesn't deal with a rep
129
138
 
130
139
  ```
131
140
  class SomeRandomJob < CanvasSync::Jobs::ApplicationJob
132
- def perform(canvas_base_url, canvas_api_token, job_chain, options)
141
+ def perform(job_chain, options)
133
142
  i_dunno_do_something!
134
143
 
135
- CanvasSync.invoke_next(canvas_base_url, canvas_api_token, job_chain)
144
+ CanvasSync.invoke_next(job_chain)
136
145
  end
137
146
  end
138
147
 
@@ -144,7 +153,7 @@ job_chain = {
144
153
  options: {}
145
154
  }
146
155
 
147
- CanvasSync.process_jobs("https://pseng.instructure.com", "my-api-token", job_chain)
156
+ CanvasSync.process_jobs(job_chain)
148
157
  ```
149
158
 
150
159
  ### Batching
data/lib/canvas_sync.rb CHANGED
@@ -21,36 +21,30 @@ module CanvasSync
21
21
  # and have also specified a Term scope, Users will by synced first, before
22
22
  # every other model (as Users are never scoped to Term).
23
23
  #
24
- # @param canvas_base_url [String] e.g., "https://pseng.instructure.com"
25
- # @param canvas_api_token [String] A Canvas API token for the specified Canvas instance
26
24
  # @param models [Array<String>] A list of models to sync. e.g., ['users', 'courses'].
27
25
  # must be one of SUPPORTED_MODELS
28
26
  # @param term_scope [Symbol, nil] An optional symbol representing a scope that exists on the Term model.
29
27
  # The provisioning report will be run for each of the terms contained in that scope.
30
- def self.provisioning_sync(canvas_base_url, canvas_api_token, models, term_scope=nil)
28
+ def self.provisioning_sync(models, term_scope=nil)
31
29
  validate_models!(models)
32
- invoke_next(canvas_base_url, canvas_api_token, default_provisioning_report_chain(models, term_scope))
30
+ invoke_next(default_provisioning_report_chain(models, term_scope))
33
31
  end
34
32
 
35
33
  # Runs a chain of ordered jobs
36
34
  #
37
35
  # See the README for usage and examples
38
36
  #
39
- # @param canvas_base_url [String]
40
- # @param canvas_api_token [String]
41
37
  # @param job_chain [Hash]
42
- def self.process_jobs(canvas_base_url, canvas_api_token, job_chain)
43
- invoke_next(canvas_base_url, canvas_api_token, job_chain)
38
+ def self.process_jobs(job_chain)
39
+ invoke_next(job_chain)
44
40
  end
45
41
 
46
42
  # Invokes the next job in a chain of jobs.
47
43
  #
48
44
  # This should typically be called automatically by the gem where necessary.
49
45
  #
50
- # @param canvas_base_url [String] e.g., "https://pseng.instructure.com"
51
- # @param canvas_api_token [String] A Canvas API token for the specified Canvas instance
52
46
  # @param job_chain [Hash] A chain of jobs to execute
53
- def self.invoke_next(canvas_base_url, canvas_api_token, job_chain)
47
+ def self.invoke_next(job_chain)
54
48
  return if job_chain[:jobs].empty?
55
49
 
56
50
  # Make sure all job classes are serialized as strings
@@ -60,7 +54,7 @@ module CanvasSync
60
54
  jobs = duped_job_chain[:jobs]
61
55
  next_job = jobs.shift
62
56
  next_job_class = next_job[:job].constantize
63
- next_job_class.perform_later(canvas_base_url, canvas_api_token, duped_job_chain, next_job[:options])
57
+ next_job_class.perform_later(duped_job_chain, next_job[:options])
64
58
  end
65
59
 
66
60
  # Syncs terms, users if necessary, then the rest of the specified models.
@@ -5,15 +5,6 @@ module CanvasSync
5
5
  # Inherit from this class to build a Job that integrates
6
6
  # well with this gem.
7
7
  class ApplicationJob < ActiveJob::Base
8
- # Generates a Bearcat::Client used for Canvas API calls
9
- #
10
- # @param canvas_base_url [String]
11
- # @param canvas_api_token [String]
12
- # @return [Bearcat::Client]
13
- def canvas_client(canvas_base_url, canvas_api_token)
14
- Bearcat::Client.new(token: canvas_api_token, prefix: canvas_base_url)
15
- end
16
-
17
8
  # Returns the amount of time to wait between report status checks
18
9
  #
19
10
  # @return [Integer]
@@ -4,22 +4,18 @@ module CanvasSync
4
4
  # Re-enqueues itself if the report is still processing on Canvas.
5
5
  # Enqueues the ReportProcessor when the report has completed.
6
6
  class ReportChecker < ApplicationJob
7
- # @param canvas_base_url [String]
8
- # @param canvas_api_token [String]
9
7
  # @param job_chain [Hash]
10
8
  # @param report_name [Hash] e.g., 'provisioning_csv'
11
9
  # @param report_id [Integer]
12
10
  # @param processor [String] a stringified report processor class name
13
11
  # @param options [Hash] hash of options that will be passed to the job processor
14
12
  # @return [nil]
15
- def perform(canvas_base_url, canvas_api_token, job_chain, report_name, report_id, processor, options)
16
- report_status = canvas_client(canvas_base_url, canvas_api_token).report_status('self', report_name, report_id)
13
+ def perform(job_chain, report_name, report_id, processor, options)
14
+ report_status = canvas_sync_client.report_status('self', report_name, report_id)
17
15
 
18
16
  case report_status['status'].downcase
19
17
  when 'complete'
20
18
  CanvasSync::Jobs::ReportProcessorJob.perform_later(
21
- canvas_base_url,
22
- canvas_api_token,
23
19
  job_chain,
24
20
  report_name,
25
21
  report_status['attachment']['url'],
@@ -33,8 +29,6 @@ module CanvasSync
33
29
  else
34
30
  CanvasSync::Jobs::ReportChecker.set(wait: report_checker_wait_time)
35
31
  .perform_later(
36
- canvas_base_url,
37
- canvas_api_token,
38
32
  job_chain,
39
33
  report_name,
40
34
  report_id,
@@ -6,20 +6,18 @@ module CanvasSync
6
6
  # download the report, and then pass the file path and options into the
7
7
  # process method on the processor.
8
8
  class ReportProcessorJob < ApplicationJob
9
- # @param canvas_base_url [String]
10
- # @param canvas_api_token [String]
11
9
  # @param job_chain [Hash]
12
10
  # @param report_name [Hash] e.g., 'provisioning_csv'
13
11
  # @param report_url [String]
14
12
  # @param processor [String] a stringified report processor class name
15
13
  # @param options [Hash] hash of options that will be passed to the job processor
16
14
  # @return [nil]
17
- def perform(canvas_base_url, canvas_api_token, job_chain, report_name, report_url, processor, options)
15
+ def perform(job_chain, report_name, report_url, processor, options)
18
16
  download(report_name, report_url) do |file_path|
19
17
  processor.constantize.process(file_path, options)
20
18
  end
21
19
 
22
- CanvasSync.invoke_next(canvas_base_url, canvas_api_token, job_chain)
20
+ CanvasSync.invoke_next(job_chain)
23
21
  end
24
22
 
25
23
  private
@@ -2,21 +2,16 @@ module CanvasSync
2
2
  module Jobs
3
3
  # Starts a Canvas report and enqueues a ReportChecker
4
4
  class ReportStarter < ApplicationJob
5
- # @param canvas_base_url [String]
6
- # @param canvas_api_token [String]
7
5
  # @param job_chain [Hash]
8
6
  # @param report_name [Hash] e.g., 'provisioning_csv'
9
7
  # @param report_params [Hash] The Canvas report parameters
10
8
  # @param processor [String] a stringified report processor class name
11
9
  # @param options [Hash] hash of options that will be passed to the job processor
12
10
  # @return [nil]
13
- def perform(canvas_base_url, canvas_api_token, job_chain, report_name, report_params, processor, options)
14
- client = canvas_client(canvas_base_url, canvas_api_token)
15
- report = client.start_report('self', report_name, report_params)
11
+ def perform(job_chain, report_name, report_params, processor, options)
12
+ report = canvas_sync_client.start_report('self', report_name, report_params)
16
13
 
17
14
  CanvasSync::Jobs::ReportChecker.set(wait: report_checker_wait_time).perform_later(
18
- canvas_base_url,
19
- canvas_api_token,
20
15
  job_chain,
21
16
  report_name,
22
17
  report['id'],
@@ -2,15 +2,11 @@ module CanvasSync
2
2
  module Jobs
3
3
  # ActiveJob class that starts a Canvas provisioning report
4
4
  class SyncProvisioningReportJob < ApplicationJob
5
- # @param canvas_base_url [String]
6
- # @param canvas_api_token [String]
7
5
  # @param job_chain [Hash]
8
6
  # @param options [Hash] If options contains a :term_scope a seperate provisioning report
9
7
  # will be started for each term in that scope. :models should be an array of
10
8
  # models to sync.
11
- def perform(canvas_base_url, canvas_api_token, job_chain, options)
12
- @canvas_base_url = canvas_base_url
13
- @canvas_api_token = canvas_api_token
9
+ def perform(job_chain, options)
14
10
  @job_chain = job_chain
15
11
 
16
12
  if options[:term_scope]
@@ -30,8 +26,6 @@ module CanvasSync
30
26
 
31
27
  def start_report(report_params, options)
32
28
  CanvasSync::Jobs::ReportStarter.perform_later(
33
- @canvas_base_url,
34
- @canvas_api_token,
35
29
  @job_chain,
36
30
  'proservices_provisioning_csv',
37
31
  report_params,
@@ -5,18 +5,14 @@ module CanvasSync
5
5
  #
6
6
  # Terms are pre-synced so that provisioning reports can be scoped to term.
7
7
  #
8
- # @param canvas_base_url [String]
9
- # @param canvas_api_token [String]
10
8
  # @param job_chain [Hash]
11
9
  # @param options [Hash]
12
- def perform(canvas_base_url, canvas_api_token, job_chain, options)
13
- client = canvas_client(canvas_base_url, canvas_api_token)
14
-
15
- client.terms('self').all_pages!.each do |term_params|
10
+ def perform(job_chain, options)
11
+ canvas_sync_client.terms('self').all_pages!.each do |term_params|
16
12
  Term.create_or_update(term_params)
17
13
  end
18
14
 
19
- CanvasSync.invoke_next(canvas_base_url, canvas_api_token, job_chain)
15
+ CanvasSync.invoke_next(job_chain)
20
16
  end
21
17
  end
22
18
  end
@@ -12,14 +12,10 @@ module CanvasSync
12
12
  # running provisioning by term we sync users first so we don't duplicate
13
13
  # the work of syncing all users for each term.
14
14
  #
15
- # @param canvas_base_url [String]
16
- # @param canvas_api_token [String]
17
15
  # @param job_chain [Hash]
18
16
  # @param options [Hash]
19
- def perform(canvas_base_url, canvas_api_token, job_chain, options)
17
+ def perform(job_chain, options)
20
18
  super(
21
- canvas_base_url,
22
- canvas_api_token,
23
19
  job_chain,
24
20
  'proservices_provisioning_csv',
25
21
  REPORT_PARAMS,
@@ -1,3 +1,3 @@
1
1
  module CanvasSync
2
- VERSION = "0.1.1"
2
+ VERSION = "0.1.2"
3
3
  end
@@ -2,28 +2,23 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.describe CanvasSync do
4
4
  describe '.provisioning_sync' do
5
- let(:canvas_base_url) { 'https://test.instructure.com' }
6
- let(:canvas_api_token) { 'cool-api-token' }
7
-
8
5
  it 'invokes the first job in the queue and passes on the rest of the job chain' do
9
6
  expected_job_chain = CanvasSync.default_provisioning_report_chain(['courses'], nil)
10
7
  first_job = expected_job_chain[:jobs].shift
11
8
 
12
9
  expect(CanvasSync::Jobs::SyncTermsJob).to receive(:perform_later)
13
10
  .with(
14
- canvas_base_url,
15
- canvas_api_token,
16
11
  expected_job_chain,
17
12
  first_job[:options]
18
13
  )
19
14
 
20
- CanvasSync.provisioning_sync(canvas_base_url, canvas_api_token, ['courses'])
15
+ CanvasSync.provisioning_sync(['courses'])
21
16
  end
22
17
 
23
18
  context 'an invalid model is passed in' do
24
19
  it 'raises a helpful exception' do
25
20
  expect {
26
- CanvasSync.provisioning_sync(canvas_base_url, canvas_api_token, ['courses', 'cheeses'])
21
+ CanvasSync.provisioning_sync(['courses', 'cheeses'])
27
22
  }.to raise_error("Invalid model(s) specified: cheeses. Only #{CanvasSync::SUPPORTED_MODELS.join(', ')} are supported.")
28
23
  end
29
24
  end
@@ -1,8 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe CanvasSync::Jobs::ReportChecker do
4
- let(:canvas_base_url) { 'https://test.instructure.com' }
5
- let(:canvas_api_token) { 'cool-api-token' }
6
4
  let(:client_double) { double('client') }
7
5
  let(:report_id) { 1 }
8
6
  let(:report_name) { 'provisioning_csv' }
@@ -11,8 +9,6 @@ RSpec.describe CanvasSync::Jobs::ReportChecker do
11
9
  describe '#perform' do
12
10
  def start_job
13
11
  CanvasSync::Jobs::ReportChecker.perform_now(
14
- canvas_base_url,
15
- canvas_api_token,
16
12
  [],
17
13
  'provisioning_csv',
18
14
  report_id,
@@ -28,7 +24,7 @@ RSpec.describe CanvasSync::Jobs::ReportChecker do
28
24
  .and_return({ 'status' => 'complete', 'attachment' => { 'url' => 'blah' } })
29
25
 
30
26
  expect(CanvasSync::Jobs::ReportProcessorJob).to receive(:perform_later)
31
- .with(canvas_base_url, canvas_api_token, [], report_name, 'blah', processor, {})
27
+ .with([], report_name, 'blah', processor, {})
32
28
 
33
29
  start_job
34
30
  end
@@ -3,8 +3,6 @@ require 'spec_helper'
3
3
  class FakeProcessor; end;
4
4
 
5
5
  RSpec.describe CanvasSync::Jobs::ReportProcessorJob do
6
- let(:canvas_base_url) { 'https://test.instructure.com' }
7
- let(:canvas_api_token) { 'cool-api-token' }
8
6
  let(:report_name) { 'provisioning_csv' }
9
7
  let(:report_url) { 'https://test.instructure.com/sample_report_download' }
10
8
  let(:processor) { FakeProcessor.to_s }
@@ -14,11 +12,9 @@ RSpec.describe CanvasSync::Jobs::ReportProcessorJob do
14
12
  it 'downloads the report to a file and then calls the process method on the processor, and then invokes the next job' do
15
13
  expect(IO).to receive(:copy_stream)
16
14
  expect(FakeProcessor).to receive(:process)
17
- expect(CanvasSync).to receive(:invoke_next).with(canvas_base_url, canvas_api_token, job_chain)
15
+ expect(CanvasSync).to receive(:invoke_next).with(job_chain)
18
16
 
19
17
  CanvasSync::Jobs::ReportProcessorJob.perform_now(
20
- canvas_base_url,
21
- canvas_api_token,
22
18
  job_chain,
23
19
  report_name,
24
20
  report_url,
@@ -1,8 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe CanvasSync::Jobs::ReportStarter do
4
- let(:canvas_base_url) { 'https://test.instructure.com' }
5
- let(:canvas_api_token) { 'cool-api-token' }
6
4
  let(:report_params) { { 'parameters[users]' => true } }
7
5
  let(:report_name) { 'provisioning_csv' }
8
6
  let(:processor) { 'CoolProcessor' }
@@ -15,8 +13,7 @@ RSpec.describe CanvasSync::Jobs::ReportStarter do
15
13
 
16
14
  expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
17
15
 
18
- CanvasSync::Jobs::ReportStarter.perform_now(canvas_base_url,
19
- canvas_api_token,
16
+ CanvasSync::Jobs::ReportStarter.perform_now(
20
17
  [],
21
18
  report_name,
22
19
  report_params,
@@ -1,9 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
4
- let(:canvas_base_url) { 'https://test.instructure.com' }
5
- let(:canvas_api_token) { 'cool-api-token' }
6
-
7
4
  describe '#perform' do
8
5
  context 'a term scope is specified' do
9
6
  let!(:active_term_1) { FactoryGirl.create(:term) }
@@ -13,8 +10,6 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
13
10
  it 'enqueues a ReportStarter for a provisioning report for the specified models for each term' do
14
11
  expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
15
12
  .with(
16
- canvas_base_url,
17
- canvas_api_token,
18
13
  [],
19
14
  'proservices_provisioning_csv',
20
15
  {
@@ -29,8 +24,6 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
29
24
 
30
25
  expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
31
26
  .with(
32
- canvas_base_url,
33
- canvas_api_token,
34
27
  [],
35
28
  'proservices_provisioning_csv',
36
29
  {
@@ -44,8 +37,6 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
44
37
  )
45
38
 
46
39
  CanvasSync::Jobs::SyncProvisioningReportJob.perform_now(
47
- canvas_base_url,
48
- canvas_api_token,
49
40
  [],
50
41
  { models: ['users', 'courses'], term_scope: 'active' }
51
42
  )
@@ -56,8 +47,6 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
56
47
  it 'enqueues a single ReportStarter for a provisioning report across all terms for the specified models' do
57
48
  expect(CanvasSync::Jobs::ReportStarter).to receive(:perform_later)
58
49
  .with(
59
- canvas_base_url,
60
- canvas_api_token,
61
50
  [],
62
51
  'proservices_provisioning_csv',
63
52
  {
@@ -70,8 +59,6 @@ RSpec.describe CanvasSync::Jobs::SyncProvisioningReportJob do
70
59
  )
71
60
 
72
61
  CanvasSync::Jobs::SyncProvisioningReportJob.perform_now(
73
- canvas_base_url,
74
- canvas_api_token,
75
62
  [],
76
63
  { models: ['users', 'courses'] }
77
64
  )