canvas_sync 0.3.11 → 0.3.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +1 -1
- data/lib/canvas_sync.rb +11 -6
- data/lib/canvas_sync/generators/templates/models/assignment.rb +6 -0
- data/lib/canvas_sync/generators/templates/models/course.rb +1 -0
- data/lib/canvas_sync/generators/templates/models/create_assignments.rb +31 -0
- data/lib/canvas_sync/jobs/sync_assignments_job.rb +28 -0
- data/lib/canvas_sync/processors/assignments_processor.rb +24 -0
- data/lib/canvas_sync/processors/model_mappings.yml +58 -0
- data/lib/canvas_sync/processors/provisioning_report_processor.rb +5 -19
- data/lib/canvas_sync/processors/report_processor.rb +22 -0
- data/lib/canvas_sync/version.rb +1 -1
- data/spec/canvas_sync/canvas_sync_spec.rb +15 -0
- data/spec/canvas_sync/jobs/sync_assignments_job_spec.rb +29 -0
- data/spec/canvas_sync/models/assignments_spec.rb +25 -0
- data/spec/canvas_sync/models/course_spec.rb +5 -0
- data/spec/canvas_sync/processors/assignments_processor_spec.rb +13 -0
- data/spec/dummy/app/models/assignment.rb +12 -0
- data/spec/dummy/app/models/course.rb +1 -0
- data/spec/dummy/db/migrate/20180212204530_create_assignments.rb +37 -0
- data/spec/dummy/db/schema.rb +26 -1
- data/spec/dummy/log/development.log +551 -0
- data/spec/dummy/log/test.log +13186 -0
- data/spec/factories/assignment_factory.rb +9 -0
- data/spec/support/fixtures/reports/assignments.csv +3 -0
- metadata +35 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c6eec06420fbb476e980bf7c1aae7d9f8679eb6b98558de1cb7765f5df13a12
|
4
|
+
data.tar.gz: 60963185f828d72df3e2a24d3bb3d1d4cf4dde73c0e2a9ce38f0c2147c178d70
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 45c726b97e96b370c84fa2393d4d4378a22f145bf3b7f4544c4f78f1aff2a0a0b40b76e3b9d5c5e920e3ff423f6da0e5b8893f6744f05de69dcbfdabe5ea42d4
|
7
|
+
data.tar.gz: 02d4f57c81e21724da088b3bf877b88a507895da1fd595335a0f42581d82e3875646084ce229f0d58d6c5ad72b4e13e68712e1befab589bea2673193b3e7c9de
|
data/Rakefile
CHANGED
@@ -11,7 +11,7 @@ task :update_test_schema do
|
|
11
11
|
puts "Updating test models and migration files..."
|
12
12
|
stream_command("spec/dummy/bin/rails generate canvas_sync:install --models all --force")
|
13
13
|
puts "Updating the test database and schema..."
|
14
|
-
stream_command("cd spec/dummy; bundle exec rake db:drop; bundle exec rake db:migrate")
|
14
|
+
stream_command("cd spec/dummy; bundle exec rake db:drop; bundle exec rake db:create; bundle exec rake db:migrate")
|
15
15
|
end
|
16
16
|
|
17
17
|
def stream_command(cmd)
|
data/lib/canvas_sync.rb
CHANGED
@@ -7,18 +7,19 @@ require "canvas_sync/jobs/report_starter"
|
|
7
7
|
require "canvas_sync/jobs/report_checker"
|
8
8
|
require "canvas_sync/jobs/report_processor_job"
|
9
9
|
require "canvas_sync/jobs/sync_provisioning_report_job"
|
10
|
+
require "canvas_sync/jobs/sync_assignments_job"
|
10
11
|
require "canvas_sync/jobs/sync_terms_job"
|
11
12
|
require "canvas_sync/jobs/sync_users_job"
|
12
13
|
require "canvas_sync/jobs/sync_roles_job"
|
13
14
|
require "canvas_sync/jobs/sync_admins_job"
|
14
15
|
|
15
|
-
Dir[File.dirname(__FILE__) + "/canvas_sync/processors/*.rb"].each {|file| require file }
|
16
|
-
Dir[File.dirname(__FILE__) + "/canvas_sync/importers/*.rb"].each {|file| require file }
|
17
|
-
Dir[File.dirname(__FILE__) + "/canvas_sync/generators/*.rb"].each {|file| require file }
|
16
|
+
Dir[File.dirname(__FILE__) + "/canvas_sync/processors/*.rb"].each { |file| require file }
|
17
|
+
Dir[File.dirname(__FILE__) + "/canvas_sync/importers/*.rb"].each { |file| require file }
|
18
|
+
Dir[File.dirname(__FILE__) + "/canvas_sync/generators/*.rb"].each { |file| require file }
|
18
19
|
|
19
20
|
module CanvasSync
|
20
|
-
SUPPORTED_MODELS = %w
|
21
|
-
SUPPORTED_LIVE_EVENTS = %w
|
21
|
+
SUPPORTED_MODELS = %w[users courses terms enrollments sections assignments roles admins xlist].freeze
|
22
|
+
SUPPORTED_LIVE_EVENTS = %w[course enrollment submission assignment user syllabus grade].freeze
|
22
23
|
|
23
24
|
# Runs a standard provisioning sync job with no extra report types.
|
24
25
|
# Terms will be synced first using the API. If you are syncing users/roles/admins
|
@@ -101,7 +102,11 @@ module CanvasSync
|
|
101
102
|
models = models - ['admins']
|
102
103
|
end
|
103
104
|
|
104
|
-
jobs.push(
|
105
|
+
jobs.push(job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: term_scope, models: models })
|
106
|
+
|
107
|
+
if models.include?("assignments")
|
108
|
+
jobs.push(job: CanvasSync::Jobs::SyncAssignmentsJob.to_s, options: {})
|
109
|
+
end
|
105
110
|
|
106
111
|
global_options = { legacy_support: legacy_support }
|
107
112
|
global_options[:account_id] = account_id if account_id.present?
|
@@ -5,4 +5,5 @@ class Course < ApplicationRecord
|
|
5
5
|
belongs_to :term, foreign_key: :canvas_term_id, primary_key: :canvas_term_id, optional: true
|
6
6
|
has_many :enrollments, primary_key: :canvas_course_id, foreign_key: :canvas_course_id
|
7
7
|
has_many :sections, primary_key: :canvas_course_id, foreign_key: :canvas_course_id
|
8
|
+
has_many :assignments, as: :context, primary_key: :canvas_course_id
|
8
9
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
<%= autogenerated_migration_warning %>
|
2
|
+
|
3
|
+
class CreateAssignments < ActiveRecord::Migration[5.1]
|
4
|
+
def change
|
5
|
+
create_table :assignments do |t|
|
6
|
+
t.bigint :canvas_assignment_id, null: false
|
7
|
+
t.string :title
|
8
|
+
t.text :description
|
9
|
+
t.datetime :due_at
|
10
|
+
t.datetime :unlock_at
|
11
|
+
t.datetime :lock_at
|
12
|
+
t.integer :points_possible
|
13
|
+
t.integer :min_score
|
14
|
+
t.integer :max_score
|
15
|
+
t.integer :mastery_score
|
16
|
+
t.string :grading_type
|
17
|
+
t.string :submission_types
|
18
|
+
t.string :workflow_state
|
19
|
+
t.integer :context_id
|
20
|
+
t.string :context_type
|
21
|
+
t.integer :assignment_group_id
|
22
|
+
t.integer :grading_scheme_id
|
23
|
+
t.integer :grading_standard_id
|
24
|
+
|
25
|
+
t.timestamps
|
26
|
+
end
|
27
|
+
|
28
|
+
add_index :assignments, :canvas_assignment_id, unique: true
|
29
|
+
add_index :assignments, [:context_id, :context_type]
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module CanvasSync
|
2
|
+
module Jobs
|
3
|
+
class SyncAssignmentsJob < ReportStarter
|
4
|
+
# Syncs Assignments
|
5
|
+
#
|
6
|
+
# Starts a report processor for the assignment report
|
7
|
+
# (the proserv_assignment_export_csv report must be enabled)
|
8
|
+
#
|
9
|
+
# @param job_chain [Hash]
|
10
|
+
# @param options [Hash]
|
11
|
+
def perform(job_chain, _options)
|
12
|
+
report_params = if job_chain[:global_options][:term_id].present?
|
13
|
+
{ enrollment_term_id: job_chain[:global_options][:term_id] }
|
14
|
+
else
|
15
|
+
{}
|
16
|
+
end
|
17
|
+
|
18
|
+
super(
|
19
|
+
job_chain,
|
20
|
+
"proserv_assignment_export_csv",
|
21
|
+
report_params,
|
22
|
+
CanvasSync::Processors::AssignmentsProcessor.to_s,
|
23
|
+
{},
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require_relative "./report_processor"
|
2
|
+
|
3
|
+
module CanvasSync
|
4
|
+
module Processors
|
5
|
+
# Processes an assignments report using the bulk importer.
|
6
|
+
#
|
7
|
+
# @param report_file_path [String]
|
8
|
+
# @param options [Hash]
|
9
|
+
class AssignmentsProcessor < ReportProcessor
|
10
|
+
def self.process(report_file_path, _options)
|
11
|
+
new(report_file_path)
|
12
|
+
end
|
13
|
+
|
14
|
+
def initialize(report_file_path)
|
15
|
+
CanvasSync::Importers::BulkImporter.import(
|
16
|
+
report_file_path,
|
17
|
+
mapping[:assignments][:report_columns],
|
18
|
+
Assignment,
|
19
|
+
mapping[:assignments][:conflict_target].to_sym,
|
20
|
+
)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -128,3 +128,61 @@ xlist:
|
|
128
128
|
canvas_nonxlist_course_id:
|
129
129
|
database_column_name: canvas_nonxlist_course_id
|
130
130
|
type: integer
|
131
|
+
|
132
|
+
assignments:
|
133
|
+
conflict_target: id
|
134
|
+
report_columns:
|
135
|
+
id:
|
136
|
+
database_column_name: :canvas_assignment_id
|
137
|
+
type: integer
|
138
|
+
title:
|
139
|
+
database_column_name: title
|
140
|
+
type: string
|
141
|
+
description:
|
142
|
+
database_column_name: description
|
143
|
+
type: text
|
144
|
+
due_at:
|
145
|
+
database_column_name: due_at
|
146
|
+
type: datetime
|
147
|
+
unlock_at:
|
148
|
+
database_column_name: unlock_at
|
149
|
+
type: datetime
|
150
|
+
lock_at:
|
151
|
+
database_column_name: lock_at
|
152
|
+
type: datetime
|
153
|
+
points_possible:
|
154
|
+
database_column_name: points_possible
|
155
|
+
type: integer
|
156
|
+
min_score:
|
157
|
+
database_column_name: min_score
|
158
|
+
type: integer
|
159
|
+
max_score:
|
160
|
+
database_column_name: max_score
|
161
|
+
type: integer
|
162
|
+
mastery_score:
|
163
|
+
database_column_name: mastery_score
|
164
|
+
type: integer
|
165
|
+
grading_type:
|
166
|
+
database_column_name: grading_type
|
167
|
+
type: string
|
168
|
+
submission_types:
|
169
|
+
database_column_name: submission_types
|
170
|
+
type: string
|
171
|
+
workflow_state:
|
172
|
+
database_column_name: workflow_state
|
173
|
+
type: string
|
174
|
+
context_id:
|
175
|
+
database_column_name: context_id
|
176
|
+
type: integer
|
177
|
+
context_type:
|
178
|
+
database_column_name: context_type
|
179
|
+
type: string
|
180
|
+
assignment_group_id:
|
181
|
+
database_column_name: assignment_group_id
|
182
|
+
type: integer
|
183
|
+
grading_scheme_id:
|
184
|
+
database_column_name: grading_scheme_id
|
185
|
+
type: integer
|
186
|
+
grading_standard_id:
|
187
|
+
database_column_name: grading_standard_id
|
188
|
+
type: integer
|
@@ -1,11 +1,11 @@
|
|
1
|
-
require
|
2
|
-
require
|
3
|
-
require
|
4
|
-
|
1
|
+
require "csv"
|
2
|
+
require "activerecord-import"
|
3
|
+
require "zip"
|
4
|
+
require_relative "./report_processor"
|
5
5
|
|
6
6
|
module CanvasSync
|
7
7
|
module Processors
|
8
|
-
class ProvisioningReportProcessor
|
8
|
+
class ProvisioningReportProcessor < ReportProcessor
|
9
9
|
# Processes a provisioning report using the bulk importer.
|
10
10
|
#
|
11
11
|
# options must contain a models key. If there is only one model
|
@@ -101,20 +101,6 @@ module CanvasSync
|
|
101
101
|
mapping[:xlist][:conflict_target].to_sym
|
102
102
|
)
|
103
103
|
end
|
104
|
-
|
105
|
-
def mapping
|
106
|
-
@mapping ||= begin
|
107
|
-
mapping = YAML::load_file(File.join(__dir__, 'model_mappings.yml')).deep_symbolize_keys!
|
108
|
-
override_filepath = Rails.root.join("config/canvas_sync_provisioning_mapping.yml")
|
109
|
-
|
110
|
-
if File.file?(override_filepath)
|
111
|
-
override = YAML::load_file(override_filepath).deep_symbolize_keys!
|
112
|
-
mapping = mapping.merge(override)
|
113
|
-
end
|
114
|
-
|
115
|
-
mapping
|
116
|
-
end
|
117
|
-
end
|
118
104
|
end
|
119
105
|
end
|
120
106
|
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
3
|
+
module CanvasSync
|
4
|
+
module Processors
|
5
|
+
# Base report processing class
|
6
|
+
class ReportProcessor
|
7
|
+
def mapping
|
8
|
+
@mapping ||= begin
|
9
|
+
mapping = YAML.load_file(File.join(__dir__, "model_mappings.yml")).deep_symbolize_keys!
|
10
|
+
override_filepath = Rails.root.join("config/canvas_sync_provisioning_mapping.yml")
|
11
|
+
|
12
|
+
if File.file?(override_filepath)
|
13
|
+
override = YAML.load_file(override_filepath).deep_symbolize_keys!
|
14
|
+
mapping = mapping.merge(override)
|
15
|
+
end
|
16
|
+
|
17
|
+
mapping
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/canvas_sync/version.rb
CHANGED
@@ -106,6 +106,21 @@ RSpec.describe CanvasSync do
|
|
106
106
|
})
|
107
107
|
end
|
108
108
|
end
|
109
|
+
|
110
|
+
context "we are syncing assignments" do
|
111
|
+
it "appends the SyncAssignmentsJob" do
|
112
|
+
chain = CanvasSync.default_provisioning_report_chain(%w[users enrollments assignments])
|
113
|
+
|
114
|
+
expect(chain).to eq(
|
115
|
+
jobs: [
|
116
|
+
{ job: CanvasSync::Jobs::SyncTermsJob.to_s, options: {} },
|
117
|
+
{ job: CanvasSync::Jobs::SyncProvisioningReportJob.to_s, options: { term_scope: nil, models: %w[users enrollments assignments] } },
|
118
|
+
{ job: CanvasSync::Jobs::SyncAssignmentsJob.to_s, options: {} },
|
119
|
+
],
|
120
|
+
global_options: { legacy_support: false },
|
121
|
+
)
|
122
|
+
end
|
123
|
+
end
|
109
124
|
end
|
110
125
|
end
|
111
126
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CanvasSync::Jobs::SyncAssignmentsJob do
|
4
|
+
describe "#perform" do
|
5
|
+
context "a term id is in the global_options" do
|
6
|
+
it "enqueues a ReportStarter for the proserv_assignment_export_csv for the given term" do
|
7
|
+
expect_any_instance_of(Bearcat::Client).to receive(:start_report)
|
8
|
+
.with("self", "proserv_assignment_export_csv", enrollment_term_id: 1)
|
9
|
+
.and_return("id" => 1)
|
10
|
+
|
11
|
+
expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
|
12
|
+
|
13
|
+
CanvasSync::Jobs::SyncAssignmentsJob.perform_now({ jobs: [], global_options: { term_id: 1 } }, {})
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "no term id is specified" do
|
18
|
+
it "enqueues a ReportStarter for the proserv_assignment_export_csv for all terms" do
|
19
|
+
expect_any_instance_of(Bearcat::Client).to receive(:start_report)
|
20
|
+
.with("self", "proserv_assignment_export_csv", {})
|
21
|
+
.and_return("id" => 1)
|
22
|
+
|
23
|
+
expect(CanvasSync::Jobs::ReportChecker).to receive(:set).and_call_original
|
24
|
+
|
25
|
+
CanvasSync::Jobs::SyncAssignmentsJob.perform_now({ jobs: [], global_options: {} }, {})
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe Assignment, type: :model do
|
4
|
+
let(:subject) { FactoryGirl.create(:assignment) }
|
5
|
+
|
6
|
+
describe "validations" do
|
7
|
+
it { should validate_presence_of(:canvas_assignment_id) }
|
8
|
+
it { should validate_uniqueness_of(:canvas_assignment_id) }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "associations" do
|
12
|
+
describe "context" do
|
13
|
+
let!(:other_course) { FactoryGirl.create(:course) }
|
14
|
+
let!(:matching_course) { FactoryGirl.create(:course) }
|
15
|
+
|
16
|
+
before do
|
17
|
+
subject.update_attributes(context_type: "Course", context_id: matching_course.canvas_course_id)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should belong to courses where the context_type is Course and context_id is the canvas_course_id" do
|
21
|
+
expect(subject.context).to eq(matching_course)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
RSpec.describe CanvasSync::Processors::AssignmentsProcessor do
|
4
|
+
let(:subject) { CanvasSync::Processors::AssignmentsProcessor }
|
5
|
+
|
6
|
+
describe "#process" do
|
7
|
+
it "inserts assignments" do
|
8
|
+
expect {
|
9
|
+
subject.process("spec/support/fixtures/reports/assignments.csv", {})
|
10
|
+
}.to change { Assignment.count }.by(2)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
#
|
2
|
+
# AUTO GENERATED MODEL
|
3
|
+
# This model was auto generated by the CanvasSync Gem.
|
4
|
+
# You can customize it as needed, but make sure you test
|
5
|
+
# any changes you make to the auto generated methods.
|
6
|
+
#
|
7
|
+
|
8
|
+
|
9
|
+
class Assignment < ApplicationRecord
|
10
|
+
validates :canvas_assignment_id, uniqueness: true, presence: true
|
11
|
+
belongs_to :context, polymorphic: true, optional: true, primary_key: :canvas_course_id
|
12
|
+
end
|
@@ -11,4 +11,5 @@ class Course < ApplicationRecord
|
|
11
11
|
belongs_to :term, foreign_key: :canvas_term_id, primary_key: :canvas_term_id, optional: true
|
12
12
|
has_many :enrollments, primary_key: :canvas_course_id, foreign_key: :canvas_course_id
|
13
13
|
has_many :sections, primary_key: :canvas_course_id, foreign_key: :canvas_course_id
|
14
|
+
has_many :assignments, as: :context, primary_key: :canvas_course_id
|
14
15
|
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
#
|
2
|
+
# AUTO GENERATED MIGRATION
|
3
|
+
# This migration was auto generated by the CanvasSync Gem.
|
4
|
+
# You can add new columns to this table, but removing or
|
5
|
+
# re-naming ones created here may break Canvas Syncing.
|
6
|
+
#
|
7
|
+
|
8
|
+
|
9
|
+
class CreateAssignments < ActiveRecord::Migration[5.1]
|
10
|
+
def change
|
11
|
+
create_table :assignments do |t|
|
12
|
+
t.bigint :canvas_assignment_id, null: false
|
13
|
+
t.string :title
|
14
|
+
t.text :description
|
15
|
+
t.datetime :due_at
|
16
|
+
t.datetime :unlock_at
|
17
|
+
t.datetime :lock_at
|
18
|
+
t.integer :points_possible
|
19
|
+
t.integer :min_score
|
20
|
+
t.integer :max_score
|
21
|
+
t.integer :mastery_score
|
22
|
+
t.string :grading_type
|
23
|
+
t.string :submission_types
|
24
|
+
t.string :workflow_state
|
25
|
+
t.integer :context_id
|
26
|
+
t.string :context_type
|
27
|
+
t.integer :assignment_group_id
|
28
|
+
t.integer :grading_scheme_id
|
29
|
+
t.integer :grading_standard_id
|
30
|
+
|
31
|
+
t.timestamps
|
32
|
+
end
|
33
|
+
|
34
|
+
add_index :assignments, :canvas_assignment_id, unique: true
|
35
|
+
add_index :assignments, [:context_id, :context_type]
|
36
|
+
end
|
37
|
+
end
|