canvas_sync 0.3.11 → 0.3.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|