canvas_sync 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +178 -0
- data/Rakefile +23 -0
- data/lib/canvas_sync.rb +96 -0
- data/lib/canvas_sync/generators/install_generator.rb +54 -0
- data/lib/canvas_sync/generators/templates/course.rb +8 -0
- data/lib/canvas_sync/generators/templates/create_courses.rb +21 -0
- data/lib/canvas_sync/generators/templates/create_enrollments.rb +26 -0
- data/lib/canvas_sync/generators/templates/create_sections.rb +20 -0
- data/lib/canvas_sync/generators/templates/create_terms.rb +18 -0
- data/lib/canvas_sync/generators/templates/create_users.rb +18 -0
- data/lib/canvas_sync/generators/templates/enrollment.rb +8 -0
- data/lib/canvas_sync/generators/templates/section.rb +7 -0
- data/lib/canvas_sync/generators/templates/term.rb +28 -0
- data/lib/canvas_sync/generators/templates/user.rb +6 -0
- data/lib/canvas_sync/importers/bulk_importer.rb +54 -0
- data/lib/canvas_sync/jobs/application_job.rb +25 -0
- data/lib/canvas_sync/jobs/report_checker.rb +48 -0
- data/lib/canvas_sync/jobs/report_processor_job.rb +36 -0
- data/lib/canvas_sync/jobs/report_starter.rb +29 -0
- data/lib/canvas_sync/jobs/sync_provisioning_report_job.rb +58 -0
- data/lib/canvas_sync/jobs/sync_terms_job.rb +23 -0
- data/lib/canvas_sync/jobs/sync_users_job.rb +32 -0
- data/lib/canvas_sync/processors/provisioning_report_processor.rb +118 -0
- data/lib/canvas_sync/version.rb +3 -0
- data/spec/canvas_sync/canvas_sync_spec.rb +60 -0
- data/spec/canvas_sync/jobs/report_checker_spec.rb +62 -0
- data/spec/canvas_sync/jobs/report_processor_job_spec.rb +30 -0
- data/spec/canvas_sync/jobs/report_starter_spec.rb +27 -0
- data/spec/canvas_sync/jobs/sync_provisioning_report_job_spec.rb +81 -0
- data/spec/canvas_sync/jobs/sync_terms_job_spec.rb +18 -0
- data/spec/canvas_sync/jobs/sync_users_job_spec.rb +18 -0
- data/spec/canvas_sync/models/course_spec.rb +30 -0
- data/spec/canvas_sync/models/enrollment_spec.rb +30 -0
- data/spec/canvas_sync/models/section_spec.rb +24 -0
- data/spec/canvas_sync/models/term_spec.rb +71 -0
- data/spec/canvas_sync/models/user_spec.rb +18 -0
- data/spec/canvas_sync/processors/provisioning_report_processor_spec.rb +41 -0
- data/spec/dummy/README.rdoc +1 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/models/application_record.rb +3 -0
- data/spec/dummy/app/models/course.rb +14 -0
- data/spec/dummy/app/models/enrollment.rb +14 -0
- data/spec/dummy/app/models/section.rb +13 -0
- data/spec/dummy/app/models/term.rb +34 -0
- data/spec/dummy/app/models/user.rb +12 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +26 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +41 -0
- data/spec/dummy/config/environments/test.rb +42 -0
- data/spec/dummy/config/initializers/assets.rb +11 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/routes.rb +2 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/migrate/20170831220702_create_courses.rb +27 -0
- data/spec/dummy/db/migrate/20170831221129_create_users.rb +24 -0
- data/spec/dummy/db/migrate/20170905192509_create_enrollments.rb +32 -0
- data/spec/dummy/db/migrate/20170906193506_create_terms.rb +24 -0
- data/spec/dummy/db/migrate/20170906203438_create_sections.rb +26 -0
- data/spec/dummy/db/schema.rb +88 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +828 -0
- data/spec/dummy/log/test.log +14582 -0
- data/spec/factories/course_factory.rb +10 -0
- data/spec/factories/enrollment_factory.rb +5 -0
- data/spec/factories/section_factory.rb +5 -0
- data/spec/factories/term_factory.rb +10 -0
- data/spec/factories/user_factory.rb +9 -0
- data/spec/spec_helper.rb +46 -0
- data/spec/support/fake_canvas.rb +22 -0
- data/spec/support/fixtures/canvas_responses/terms.json +64 -0
- data/spec/support/fixtures/reports/courses.csv +3 -0
- data/spec/support/fixtures/reports/enrollments.csv +3 -0
- data/spec/support/fixtures/reports/provisioning_csv +0 -0
- data/spec/support/fixtures/reports/provisioning_csv_unzipped/courses.csv +3 -0
- data/spec/support/fixtures/reports/provisioning_csv_unzipped/users.csv +4 -0
- data/spec/support/fixtures/reports/sections.csv +3 -0
- data/spec/support/fixtures/reports/users.csv +4 -0
- metadata +423 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: d6178b9db26d809e2e35b5c4d38187d2ceb14018
|
4
|
+
data.tar.gz: ec84b34894e5b40e27666cdb0946053a355cf422
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4ee7ea65f6c785d05559f52b841483ea2a316509373feedc7c29a35599bfe99d20214ca3a2b2116d1ef503d366a03ec6382d59eb0636e361138cb6378ef6afe1
|
7
|
+
data.tar.gz: aaf71eaaf57f0ff80e7c5e92a22f3a3340e57358ab9a1042f1e821ad15dacbd0b401fd93199bbd0c0e9bbb3ff5540c223ce512be15315b5ad71dd43591e92875
|
data/README.md
ADDED
@@ -0,0 +1,178 @@
|
|
1
|
+
# CanvasSync
|
2
|
+
|
3
|
+
This gem is intended to facilitate fast and easy syncing of Canvas data.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'canvas_sync'
|
11
|
+
```
|
12
|
+
|
13
|
+
Models and migrations can be installed using the following generator:
|
14
|
+
|
15
|
+
```
|
16
|
+
bin/rails generate canvas_sync:install --models users,terms,courses
|
17
|
+
```
|
18
|
+
|
19
|
+
Use the `--models` option to specify what models you would like installed. This will add both the model files and their corresponding migrations. If you'd like to install all the models that `CanvasSync` supports then specify `--models all`.
|
20
|
+
|
21
|
+
For a list of currently supported models, see `CanvasSync::SUPPORTED_MODELS`.
|
22
|
+
|
23
|
+
Additionally, your Canvas instance must have the "Proserv Provisioning Report" enabled.
|
24
|
+
|
25
|
+
## Docs
|
26
|
+
|
27
|
+
Docs can be generated using [yard](https://yardoc.org/). To view the docs:
|
28
|
+
|
29
|
+
- Clone this gem's repository
|
30
|
+
- `bundle install`
|
31
|
+
- `yard server --reload`
|
32
|
+
|
33
|
+
The yard server will give you a URL you can visit to view the docs.
|
34
|
+
|
35
|
+
## Basic Usage
|
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:
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
CanvasSync.provisioning_sync(<canvas base url>, <canvas api token>, <array of models to sync>, <optional term scope>)
|
41
|
+
```
|
42
|
+
|
43
|
+
Example:
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
CanvasSync.provisioning_sync("https://pseng.instructure.com", "12345", ['users', 'courses'], :active)
|
47
|
+
```
|
48
|
+
|
49
|
+
This will kick off a string of jobs to sync your specified models.
|
50
|
+
|
51
|
+
If you pass in the optional `term_scope` the provisioning reports will be run for only the terms returned by that scope. The scope must be defined on your `Term` model. (A sample one is provided in the generated `Term`.)
|
52
|
+
|
53
|
+
Imports are inserted in bulk with [https://github.com/zdennis/activerecord-import](activerecord-import) so they should be very fast.
|
54
|
+
|
55
|
+
## Advanced Usage
|
56
|
+
|
57
|
+
This gem also helps with syncing and processing other reports if needed. In order to do so, you must:
|
58
|
+
|
59
|
+
- Define a `Processor` class that implements a `process` method for handling the results of the report
|
60
|
+
- Integrate your reports with the `ReportStarter`
|
61
|
+
- Tell the gem what jobs to run
|
62
|
+
|
63
|
+
### Processor
|
64
|
+
|
65
|
+
Your processor class must implement a `process` class method that receives a `report_file_path` and a hash of `options`. (See the `CanvasSync::Processors::ProvisioningReportProcessor` for an example.) The gem handles the work of enqueueing and downloading the report and then passes the file path to your class to process as needed. A simple example might be:
|
66
|
+
|
67
|
+
```ruby
|
68
|
+
class MyCoolProcessor
|
69
|
+
def self.process(report_file_path, options)
|
70
|
+
puts "I downloaded a report to #{report_file_path}! Isn't that neat!"
|
71
|
+
end
|
72
|
+
end
|
73
|
+
```
|
74
|
+
|
75
|
+
### Report starter
|
76
|
+
|
77
|
+
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
|
+
|
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`.
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
class MyReallyCoolReportJob < CanvasSync::Jobs::ReportStarter
|
83
|
+
def perform(canvas_base_url, canvas_api_token, job_chain, options)
|
84
|
+
super(
|
85
|
+
canvas_base_url,
|
86
|
+
canvas_api_token,
|
87
|
+
job_chain,
|
88
|
+
'my_really_cool_report_csv', # Report name
|
89
|
+
{ "parameters[param1]" => true }, # Report parameters
|
90
|
+
MyCoolProcessor, # Your processor class
|
91
|
+
options
|
92
|
+
)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
```
|
96
|
+
|
97
|
+
You can also see examples in `lib/canvas_sync/jobs/sync_users_job.rb` and `lib/canvas_sync/jobs/sync_provisioning_report.rb`.
|
98
|
+
|
99
|
+
### Start the jobs
|
100
|
+
|
101
|
+
The `CanvasSync.process_jobs` method allows you to pass in a chain of jobs to run. The job chain must be formatted like:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
{
|
105
|
+
jobs: [
|
106
|
+
{ job: JobClass, options: {} },
|
107
|
+
{ job: JobClass2, options: {} }
|
108
|
+
],
|
109
|
+
options: {}
|
110
|
+
}
|
111
|
+
```
|
112
|
+
|
113
|
+
Here is an example that runs our new report job first followed by the builtin provisioning job:
|
114
|
+
|
115
|
+
```
|
116
|
+
job_chain = {
|
117
|
+
jobs: [
|
118
|
+
{ job: MyReallyCoolReportJob, options: {} },
|
119
|
+
{ job: CanvasSync::Jobs::SyncProvisioningReportJob, options: { models: ['users', 'courses'] } }
|
120
|
+
],
|
121
|
+
options: {}
|
122
|
+
}
|
123
|
+
|
124
|
+
CanvasSync.process_jobs("https://pseng.instructure.com", "my-api-token", job_chain)
|
125
|
+
```
|
126
|
+
|
127
|
+
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:
|
128
|
+
|
129
|
+
|
130
|
+
```
|
131
|
+
class SomeRandomJob < CanvasSync::Jobs::ApplicationJob
|
132
|
+
def perform(canvas_base_url, canvas_api_token, job_chain, options)
|
133
|
+
i_dunno_do_something!
|
134
|
+
|
135
|
+
CanvasSync.invoke_next(canvas_base_url, canvas_api_token, job_chain)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
job_chain = {
|
140
|
+
jobs: [
|
141
|
+
{ job: SomeRandomJob, options: {} },
|
142
|
+
{ job: CanvasSync::Jobs::SyncProvisioningReportJob, options: { models: ['users', 'courses'] } }
|
143
|
+
],
|
144
|
+
options: {}
|
145
|
+
}
|
146
|
+
|
147
|
+
CanvasSync.process_jobs("https://pseng.instructure.com", "my-api-token", job_chain)
|
148
|
+
```
|
149
|
+
|
150
|
+
### Batching
|
151
|
+
|
152
|
+
The provisioning report uses the `CanvasSync::Importers::BulkImporter` class to bulk import rows with the activerecord-import gem. It inserts rows in batches of 10,000 by default. This can be customized by setting the `BULK_IMPORTER_BATCH_SIZE` environment variable if needed.
|
153
|
+
|
154
|
+
## Upgrading
|
155
|
+
|
156
|
+
Re-running the generator when there's been a gem change will give you several choices if it detects conflicts between your local files and the updated generators. You can either view a diff or allow the generator to overwrite your local file. In most cases you may just want to add the code from the diff yourself so as not to break any of your customizations.
|
157
|
+
|
158
|
+
TODO - if you make any breaking changes make sure you include upgrade instructions here.
|
159
|
+
|
160
|
+
## Integrating with existing applications
|
161
|
+
|
162
|
+
In order for this to work properly your database tables will need to have at least the columns defined in this gem. (Adding additional columns is fine.) As such, you may need to run some migrations to rename existing columns or add missing ones. The generator only works well in a situation where that table does not already exist. Take a look at the migration templates in `lib/canvas_sync/generators/templates` to see what you need.
|
163
|
+
|
164
|
+
## Development
|
165
|
+
|
166
|
+
When adding to or updating this gem, make sure you do the following:
|
167
|
+
|
168
|
+
- If you modify a table that's already in the released version of the gem please write *new migrations* rather than modifying the existing ones. This will allow people to more easily upgrade.
|
169
|
+
- Update the yardoc comments where necessary, and confirm the changes by running `yardoc --server`
|
170
|
+
- Write specs
|
171
|
+
- If you modify the model or migration templates, run `bundle exec rake update_test_schema` to update them in the Rails Dummy application (and commit those changes)
|
172
|
+
|
173
|
+
## TODO
|
174
|
+
|
175
|
+
Currently in a pre-alpha like state.
|
176
|
+
|
177
|
+
- Add better support for parallel job execution with job dependencies
|
178
|
+
- Add some sort of `JobLog` model for tracking parallel execution and job metadata
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require "rspec/core/rake_task"
|
3
|
+
require "open3"
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec)
|
6
|
+
|
7
|
+
task default: :spec
|
8
|
+
|
9
|
+
desc 'This updates the models and migrations used by the testing Rails Dummy app and should be run whenever those are updated.'
|
10
|
+
task :update_test_schema do
|
11
|
+
puts "Updating test models and migration files..."
|
12
|
+
stream_command("spec/dummy/bin/rails generate canvas_sync:install --models all --force")
|
13
|
+
puts "Updating the test database and schema..."
|
14
|
+
stream_command("cd spec/dummy; bundle exec rake db:drop; bundle exec rake db:migrate")
|
15
|
+
end
|
16
|
+
|
17
|
+
def stream_command(cmd)
|
18
|
+
Open3.popen2e(cmd) do |stdin, stdout_stderr, wait_thr|
|
19
|
+
while line = stdout_stderr.gets
|
20
|
+
puts line
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/canvas_sync.rb
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
require "bearcat"
|
2
|
+
require "canvas_sync/version"
|
3
|
+
|
4
|
+
require "canvas_sync/jobs/application_job"
|
5
|
+
require "canvas_sync/jobs/report_starter"
|
6
|
+
require "canvas_sync/jobs/report_checker"
|
7
|
+
require "canvas_sync/jobs/report_processor_job"
|
8
|
+
require "canvas_sync/jobs/sync_provisioning_report_job"
|
9
|
+
require "canvas_sync/jobs/sync_terms_job"
|
10
|
+
require "canvas_sync/jobs/sync_users_job"
|
11
|
+
|
12
|
+
Dir[File.dirname(__FILE__) + "/canvas_sync/processors/*.rb"].each {|file| require file }
|
13
|
+
Dir[File.dirname(__FILE__) + "/canvas_sync/importers/*.rb"].each {|file| require file }
|
14
|
+
Dir[File.dirname(__FILE__) + "/canvas_sync/generators/*.rb"].each {|file| require file }
|
15
|
+
|
16
|
+
module CanvasSync
|
17
|
+
SUPPORTED_MODELS = %w(users courses terms enrollments sections)
|
18
|
+
|
19
|
+
# Runs a standard provisioning sync job with no extra report types.
|
20
|
+
# Terms will be synced first using the API. If you are syncing users
|
21
|
+
# and have also specified a Term scope, Users will by synced first, before
|
22
|
+
# every other model (as Users are never scoped to Term).
|
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
|
+
# @param models [Array<String>] A list of models to sync. e.g., ['users', 'courses'].
|
27
|
+
# must be one of SUPPORTED_MODELS
|
28
|
+
# @param term_scope [Symbol, nil] An optional symbol representing a scope that exists on the Term model.
|
29
|
+
# 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)
|
31
|
+
validate_models!(models)
|
32
|
+
invoke_next(canvas_base_url, canvas_api_token, default_provisioning_report_chain(models, term_scope))
|
33
|
+
end
|
34
|
+
|
35
|
+
# Runs a chain of ordered jobs
|
36
|
+
#
|
37
|
+
# See the README for usage and examples
|
38
|
+
#
|
39
|
+
# @param canvas_base_url [String]
|
40
|
+
# @param canvas_api_token [String]
|
41
|
+
# @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)
|
44
|
+
end
|
45
|
+
|
46
|
+
# Invokes the next job in a chain of jobs.
|
47
|
+
#
|
48
|
+
# This should typically be called automatically by the gem where necessary.
|
49
|
+
#
|
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
|
+
# @param job_chain [Hash] A chain of jobs to execute
|
53
|
+
def self.invoke_next(canvas_base_url, canvas_api_token, job_chain)
|
54
|
+
return if job_chain[:jobs].empty?
|
55
|
+
|
56
|
+
# Make sure all job classes are serialized as strings
|
57
|
+
job_chain[:jobs].each { |job| job[:job] = job[:job].to_s }
|
58
|
+
|
59
|
+
duped_job_chain = Marshal.load(Marshal.dump(job_chain))
|
60
|
+
jobs = duped_job_chain[:jobs]
|
61
|
+
next_job = jobs.shift
|
62
|
+
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])
|
64
|
+
end
|
65
|
+
|
66
|
+
# Syncs terms, users if necessary, then the rest of the specified models.
|
67
|
+
#
|
68
|
+
# @param models [Array<String>]
|
69
|
+
# @param term_scope [String]
|
70
|
+
# @return [Hash]
|
71
|
+
def self.default_provisioning_report_chain(models, term_scope=nil)
|
72
|
+
term_scope = term_scope.to_s if term_scope
|
73
|
+
|
74
|
+
# Always sync Terms first
|
75
|
+
jobs = [{ job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} }]
|
76
|
+
|
77
|
+
if models.include?('users') && term_scope.present?
|
78
|
+
# Sync all users first when scoping by term, because users cannot be scoped to term
|
79
|
+
jobs.push({ job: CanvasSync::Jobs::SyncUsersJob.to_s, options: {} })
|
80
|
+
models = models - ['users']
|
81
|
+
end
|
82
|
+
|
83
|
+
jobs.push({ job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: term_scope, models: models } })
|
84
|
+
|
85
|
+
{ jobs: jobs, options: {} }
|
86
|
+
end
|
87
|
+
|
88
|
+
private
|
89
|
+
|
90
|
+
def self.validate_models!(models)
|
91
|
+
invalid = models - SUPPORTED_MODELS
|
92
|
+
if invalid.length > 0
|
93
|
+
raise "Invalid model(s) specified: #{invalid.join(', ')}. Only #{SUPPORTED_MODELS.join(', ')} are supported."
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "rails/generators"
|
2
|
+
require "rails/generators/migration"
|
3
|
+
|
4
|
+
module CanvasSync
|
5
|
+
class InstallGenerator < Rails::Generators::Base
|
6
|
+
include Rails::Generators::Migration
|
7
|
+
source_root File.expand_path('../templates', __FILE__)
|
8
|
+
class_option :models, type: :string, required: true
|
9
|
+
|
10
|
+
def self.next_migration_number(path)
|
11
|
+
next_migration_number = current_migration_number(path) + 1
|
12
|
+
ActiveRecord::Migration.next_migration_number(next_migration_number)
|
13
|
+
end
|
14
|
+
|
15
|
+
def autogenerated_model_warning
|
16
|
+
<<-HERE.strip_heredoc
|
17
|
+
#
|
18
|
+
# AUTO GENERATED MODEL
|
19
|
+
# This model was auto generated by the CanvasSync Gem.
|
20
|
+
# You can customize it as needed, but make sure you test
|
21
|
+
# any changes you make to the auto generated methods.
|
22
|
+
#
|
23
|
+
HERE
|
24
|
+
end
|
25
|
+
|
26
|
+
def autogenerated_migration_warning
|
27
|
+
<<-HERE.strip_heredoc
|
28
|
+
#
|
29
|
+
# AUTO GENERATED MIGRATION
|
30
|
+
# This migration was auto generated by the CanvasSync Gem.
|
31
|
+
# You can add new columns to this table, but removing or
|
32
|
+
# re-naming ones created here may break Canvas Syncing.
|
33
|
+
#
|
34
|
+
HERE
|
35
|
+
end
|
36
|
+
|
37
|
+
# Generates the specified models and migrations. Invoke with:
|
38
|
+
#
|
39
|
+
# bin/rails generate canvas_sync:install --models users,courses
|
40
|
+
#
|
41
|
+
# Install all models and migrations with:
|
42
|
+
#
|
43
|
+
# bin/rails generate canvas_sync:install --models all
|
44
|
+
def generate_migrations_and_models
|
45
|
+
models = options['models'] == 'all' ? CanvasSync::SUPPORTED_MODELS : options['models'].split(',')
|
46
|
+
CanvasSync.validate_models!(models)
|
47
|
+
|
48
|
+
models.each do |model|
|
49
|
+
migration_template "create_#{model}.rb", "db/migrate/create_#{model}.rb"
|
50
|
+
template "#{model.singularize}.rb", "app/models/#{model.singularize}.rb"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,8 @@
|
|
1
|
+
<%= autogenerated_model_warning %>
|
2
|
+
|
3
|
+
class Course < ApplicationRecord
|
4
|
+
validates :canvas_course_id, uniqueness: true, presence: true
|
5
|
+
belongs_to :term, foreign_key: :canvas_term_id, primary_key: :canvas_term_id, optional: true
|
6
|
+
has_many :enrollments, primary_key: :canvas_course_id, foreign_key: :canvas_course_id
|
7
|
+
has_many :sections, primary_key: :canvas_course_id, foreign_key: :canvas_course_id
|
8
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
<%= autogenerated_migration_warning %>
|
2
|
+
|
3
|
+
class CreateCourses < ActiveRecord::Migration[5.1]
|
4
|
+
def change
|
5
|
+
create_table :courses do |t|
|
6
|
+
t.bigint :canvas_course_id, null: false
|
7
|
+
t.string :sis_id
|
8
|
+
t.string :short_name
|
9
|
+
t.string :long_name
|
10
|
+
t.integer :canvas_account_id
|
11
|
+
t.integer :canvas_term_id
|
12
|
+
t.integer :term_sis_id
|
13
|
+
t.datetime :start_date
|
14
|
+
t.datetime :end_date
|
15
|
+
|
16
|
+
t.timestamps
|
17
|
+
end
|
18
|
+
|
19
|
+
add_index :courses, :canvas_course_id, unique: true
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<%= autogenerated_migration_warning %>
|
2
|
+
|
3
|
+
class CreateEnrollments < ActiveRecord::Migration[5.1]
|
4
|
+
def change
|
5
|
+
create_table :enrollments do |t|
|
6
|
+
t.bigint :canvas_enrollment_id, null: false
|
7
|
+
t.bigint :canvas_course_id
|
8
|
+
t.string :course_sis_id
|
9
|
+
t.bigint :canvas_user_id
|
10
|
+
t.string :user_sis_id
|
11
|
+
t.string :role
|
12
|
+
t.integer :role_id
|
13
|
+
t.bigint :canvas_section_id
|
14
|
+
t.string :section_sis_id
|
15
|
+
t.string :status
|
16
|
+
t.string :base_role_type
|
17
|
+
|
18
|
+
|
19
|
+
t.timestamps
|
20
|
+
end
|
21
|
+
|
22
|
+
add_index :enrollments, :canvas_enrollment_id, unique: true
|
23
|
+
add_index :enrollments, :canvas_course_id
|
24
|
+
add_index :enrollments, :canvas_user_id
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
<%= autogenerated_migration_warning %>
|
2
|
+
|
3
|
+
class CreateSections < ActiveRecord::Migration[5.1]
|
4
|
+
def change
|
5
|
+
create_table :sections do |t|
|
6
|
+
t.bigint :canvas_section_id, null: false
|
7
|
+
t.string :sis_id
|
8
|
+
t.bigint :canvas_course_id
|
9
|
+
t.string :name
|
10
|
+
t.string :status
|
11
|
+
t.datetime :start_date
|
12
|
+
t.datetime :end_date
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
|
17
|
+
add_index :sections, :canvas_section_id, unique: true
|
18
|
+
add_index :sections, :canvas_course_id
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
<%= autogenerated_migration_warning %>
|
2
|
+
|
3
|
+
class CreateTerms < ActiveRecord::Migration[5.1]
|
4
|
+
def change
|
5
|
+
create_table :terms do |t|
|
6
|
+
t.integer :canvas_term_id, null: false
|
7
|
+
t.string :name
|
8
|
+
t.datetime :start_at
|
9
|
+
t.datetime :end_at
|
10
|
+
t.string :workflow_state
|
11
|
+
t.integer :grading_period_group_id
|
12
|
+
t.string :sis_id
|
13
|
+
|
14
|
+
t.timestamps
|
15
|
+
end
|
16
|
+
add_index :terms, :canvas_term_id, unique: true
|
17
|
+
end
|
18
|
+
end
|