coalescing_panda 4.0.11 → 4.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/coalescing_panda/canvas_batch.js.coffee +7 -5
  3. data/app/assets/stylesheets/coalescing_panda/application.css.scss +1 -0
  4. data/app/controllers/coalescing_panda/canvas_batches_controller.rb +0 -10
  5. data/app/controllers/coalescing_panda/lti_controller.rb +2 -2
  6. data/app/controllers/coalescing_panda/oauth2_controller.rb +1 -3
  7. data/app/models/coalescing_panda/assignment.rb +0 -2
  8. data/app/models/coalescing_panda/canvas_batch.rb +0 -4
  9. data/app/models/coalescing_panda/course.rb +0 -2
  10. data/app/models/coalescing_panda/group.rb +2 -3
  11. data/app/models/coalescing_panda/lti_account.rb +0 -1
  12. data/app/models/coalescing_panda/user.rb +0 -1
  13. data/app/models/coalescing_panda/workers/course_miner.rb +58 -141
  14. data/app/models/concerns/single_table_polymorphic.rb +1 -1
  15. data/app/views/coalescing_panda/canvas_batches/_canvas_batch.html.haml +10 -22
  16. data/app/views/coalescing_panda/canvas_batches/_canvas_batch_flash.html.haml +1 -1
  17. data/config/routes.rb +1 -3
  18. data/lib/coalescing_panda/controller_helpers.rb +25 -22
  19. data/lib/coalescing_panda/version.rb +1 -1
  20. data/spec/dummy/db/development.sqlite3 +0 -0
  21. data/spec/dummy/db/schema.rb +82 -120
  22. data/spec/dummy/db/test.sqlite3 +0 -0
  23. data/spec/dummy/log/development.log +229 -589
  24. data/spec/dummy/log/test.log +60790 -39979
  25. data/spec/models/coalescing_panda/assignment_spec.rb +0 -1
  26. data/spec/models/coalescing_panda/course_spec.rb +0 -5
  27. data/spec/models/coalescing_panda/workers/course_miner_spec.rb +10 -57
  28. metadata +57 -80
  29. data/app/assets/javascripts/bootstrap/bootstrap-datepicker.js +0 -1247
  30. data/app/assets/javascripts/bootstrap/bootstrap.js +0 -6
  31. data/app/assets/stylesheets/bootstrap/bootstrap-datepicker.css +0 -449
  32. data/app/assets/stylesheets/bootstrap/bootstrap-overrides.css.scss +0 -61
  33. data/app/assets/stylesheets/bootstrap/bootstrap-responsive.css +0 -9
  34. data/app/assets/stylesheets/bootstrap/bootstrap.css.scss +0 -9
  35. data/app/assets/stylesheets/coalescing_panda/application.css +0 -16
  36. data/app/assets/stylesheets/coalescing_panda/oauth2.css +0 -0
  37. data/app/assets/stylesheets/coalescing_panda/progress.css.scss +0 -97
  38. data/app/models/coalescing_panda/assignment_group.rb +0 -11
  39. data/app/models/coalescing_panda/group_category.rb +0 -11
  40. data/db/migrate/20150506183335_create_coalescing_panda_assignment_groups.rb +0 -18
  41. data/db/migrate/20150506192717_add_assignment_group_id_to_assignments.rb +0 -5
  42. data/db/migrate/20150526144713_add_account_to_canvas_batches.rb +0 -5
  43. data/db/migrate/20150602205257_add_option_to_canvas_batches.rb +0 -5
  44. data/db/migrate/20150708192717_add_group_moderator_to_group_memberships.rb +0 -5
  45. data/db/migrate/20150709192717_add_leader_id_to_groups.rb +0 -6
  46. data/db/migrate/20150714205405_create_coalescing_panda_group_categories.rb +0 -16
  47. data/db/migrate/20160521205405_add_graded_at_to_coalescing_panda_submissions.rb +0 -5
  48. data/lib/coalescing_panda/bearcat_uri.rb +0 -20
  49. data/spec/factories/assignment_groups.rb +0 -14
  50. data/spec/models/coalescing_panda/assignment_group_spec.rb +0 -32
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1f20aad0bed2643617b47a4f4463343ac04a6ceb
4
- data.tar.gz: 04b60e3b78c5922fea7c5b9271a3d3c9da98ab7a
3
+ metadata.gz: 049b4be87e2a94883db4321af5513b3de1292d95
4
+ data.tar.gz: 18cb2a2a9965e4d80e96e8bb5c2d342c4a1e7911
5
5
  SHA512:
6
- metadata.gz: c0fab58d0a71779b9f32c8f9ae6b7e91a5d46e765353ca3692ffe8be162a4fcee5221a6538a022d6a03a27dbe8cfc0c69a3edfbfe8d516418b41043583f1927f
7
- data.tar.gz: 0811856f48b94fa5777506f82385b6b1c6036f9d1514a0c29ae0aaae838917721dd073775b430275538f66153968b85614c6997a438c691791a1f60c9e36a2a2
6
+ metadata.gz: a71dcd02c993571e306894b3ba2a19ece4877ef108fb7475811a113d7c1442d38f2dfea109c94fb17dd43f5a63e18300dcfd805fc5411cc302fc3118858ade05
7
+ data.tar.gz: 38e4fc6d47585987d5611fa1544ca6792d357de01c9c8b18d169cd9fca210635434c4f161410de7c04ef367454d3642e77f16667927550805e4c383e108c3f06
@@ -7,7 +7,7 @@ window.CoalescingPanda.CanvasBatchProgress = class CanvasBatchProgress
7
7
  batch = $('#batch-progress').data('batch')
8
8
  url = $('#batch-progress').data('url')
9
9
  window.clearPath = $('#batch-progress').data('clear-path')
10
- if batch && (batch.status != "Completed" || batch.status != "Error")
10
+ if batch && batch.status != "Completed" || batch.status != "Error"
11
11
  window.batchInterval = setInterval(getBatchStatus, 3000, batch.id, url, successCallback, errorCallback)
12
12
 
13
13
  getBatchStatus = (id, url, successCallback, errorCallback) ->
@@ -17,14 +17,12 @@ window.CoalescingPanda.CanvasBatchProgress = class CanvasBatchProgress
17
17
  $('#batch-progress').html(data)
18
18
  setFlashMessages()
19
19
  batch = $('#batch-info').data('batch')
20
- if batch && batch.status == "Completed"
20
+ if batch.status == "Completed"
21
21
  clearIntervalAndBatch(data, batch)
22
22
  successCallback() if successCallback != undefined
23
- else if batch && batch.status == 'Error'
23
+ else if batch.status == 'Error'
24
24
  clearIntervalAndBatch(data, batch)
25
25
  errorCallback() if errorCallback != undefined
26
- else if batch && batch.status == "Canceled"
27
- clearIntervalAndBatch(data, batch)
28
26
 
29
27
  error: (message) ->
30
28
  $('#batch-progress').html('Batch status request failed')
@@ -47,3 +45,7 @@ window.CoalescingPanda.CanvasBatchProgress = class CanvasBatchProgress
47
45
  if window.messages != undefined
48
46
  for key of window.messages
49
47
  $(".batch-message-#{key}").text("#{window.messages[key]}")
48
+
49
+ $ ->
50
+ $("#batch-container").unbind().bind "batchStarted", (event, data) ->
51
+ new CanvasBatchProgress()
@@ -0,0 +1 @@
1
+ @import "launch";
@@ -7,16 +7,6 @@ module CoalescingPanda
7
7
  render @batch
8
8
  end
9
9
 
10
- def retrigger
11
- @batch = CanvasBatch.find(params[:id])
12
- @batch.status = 'Queued'
13
- @batch.save
14
- worker = CoalescingPanda::Workers::CourseMiner.new(@batch.context, @batch.options)
15
- session[:canvas_batch_id] = worker.batch.id
16
- worker.start(true)
17
- redirect_to :back
18
- end
19
-
20
10
  def clear_batch_session
21
11
  session[:canvas_batch_id] = nil
22
12
  render nothing: true
@@ -51,12 +51,12 @@ module CoalescingPanda
51
51
  if %w(course account user).include?(name)
52
52
  tail = '_navigation' unless name.include? '_navigation'
53
53
  end
54
- ([name, tail].join).to_sym
54
+ (name+tail).to_sym
55
55
  end
56
56
 
57
57
  def ext_params(options)
58
58
  url = options.delete(:url)
59
- options[:url] = main_app.send([url,'_url'].join)
59
+ options[:url] = main_app.send(url+'_url')
60
60
  options
61
61
  end
62
62
 
@@ -13,9 +13,7 @@ module CoalescingPanda
13
13
  client_key = lti_account.oauth2_client_key
14
14
  user_id = params[:user_id]
15
15
  api_domain = params[:api_domain]
16
- prefix = [oauth2_protocol, '://', api_domain].join
17
- Rails.logger.info "Creating Bearcat client for auth token retrieval pointed to: #{prefix}"
18
- client = Bearcat::Client.new(prefix: prefix)
16
+ client = Bearcat::Client.new(prefix: oauth2_protocol+'://'+api_domain)
19
17
  token = client.retrieve_token(client_id, coalescing_panda.oauth2_redirect_url, client_key, params['code'])
20
18
  CanvasApiAuth.where('user_id = ? and api_domain = ?', user_id, api_domain).first_or_create do |auth|
21
19
  auth.api_token = token
@@ -1,8 +1,6 @@
1
1
  module CoalescingPanda
2
2
  class Assignment < ActiveRecord::Base
3
3
  belongs_to :course, foreign_key: :coalescing_panda_course_id, class_name: 'CoalescingPanda::Course'
4
- belongs_to :assignment_group, foreign_key: :coalescing_panda_assignment_group_id, class_name: 'CoalescingPanda::AssignmentGroup'
5
- belongs_to :group_category, foreign_key: :coalescing_panda_group_category_id, class_name: 'CoalescingPanda::GroupCategory'
6
4
  has_many :submissions, foreign_key: :coalescing_panda_assignment_id, class_name: 'CoalescingPanda::Submission', dependent: :destroy
7
5
 
8
6
  delegate :account, to: :course
@@ -1,10 +1,6 @@
1
1
  module CoalescingPanda
2
2
  class CanvasBatch < ActiveRecord::Base
3
- serialize :options
4
-
5
- belongs_to :account, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::LtiAccount'
6
3
  belongs_to :context, polymorphic: true
7
-
8
4
  default_scope { order('created_at DESC') }
9
5
  end
10
6
  end
@@ -8,10 +8,8 @@ module CoalescingPanda
8
8
  has_many :submissions, through: :assignments, dependent: :destroy
9
9
  has_many :users, through: :sections, source: :users, class_name: 'CoalescingPanda::User'
10
10
  has_many :groups, :as => :context, class_name: 'CoalescingPanda::Group', dependent: :destroy
11
- has_many :group_categories, :as => :context, class_name: 'CoalescingPanda::GroupCategory', dependent: :destroy
12
11
  has_many :group_memberships, through: :groups, source: :group_memberships, class_name: 'CoalescingPanda::GroupMembership', dependent: :destroy
13
12
  has_many :canvas_batches, as: :context, dependent: :destroy
14
- has_many :assignment_groups, foreign_key: :coalescing_panda_course_id, class_name: 'CoalescingPanda::AssignmentGroup', dependent: :destroy
15
13
 
16
14
  validates :coalescing_panda_lti_account_id, presence: true
17
15
  validates :canvas_course_id, presence: true
@@ -3,10 +3,9 @@ module CoalescingPanda
3
3
  belongs_to :context, :polymorphic => true
4
4
  include SingleTablePolymorphic
5
5
 
6
- belongs_to :leader, foreign_key: :leader_id, class_name: 'CoalescingPanda::User'
7
- belongs_to :group_category, foreign_key: :coalescing_panda_group_category_id, class_name: 'CoalescingPanda::GroupCategory'
8
- has_many :group_memberships, foreign_key: :coalescing_panda_group_id, class_name: 'CoalescingPanda::GroupMembership', dependent: :destroy
6
+ has_many :group_memberships, dependent: :destroy, foreign_key: :coalescing_panda_group_id, class_name: 'CoalescingPanda::GroupMembership', dependent: :destroy
9
7
  validates :group_category_id, presence: true
10
8
  validates :canvas_group_id, presence: true
9
+ validates :coalescing_panda_user_id, presence: true
11
10
  end
12
11
  end
@@ -6,7 +6,6 @@ module CoalescingPanda
6
6
  has_many :terms, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::Term'
7
7
  has_many :courses, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::Course'
8
8
  has_many :users, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::User'
9
- has_many :canvas_batches, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::CanvasBatch'
10
9
  has_many :sections, through: :courses
11
10
  has_many :enrollments, through: :sections
12
11
  has_many :assignments, through: :courses
@@ -3,7 +3,6 @@ module CoalescingPanda
3
3
  belongs_to :account, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::LtiAccount'
4
4
  has_many :enrollments, foreign_key: :coalescing_panda_user_id, class_name: 'CoalescingPanda::Enrollment', dependent: :destroy
5
5
  has_many :submissions, foreign_key: :coalescing_panda_user_id, class_name: 'CoalescingPanda::Submission', dependent: :destroy
6
- has_many :leader_groups, foreign_key: :leader_id, class_name: 'CoalescingPanda::Group'
7
6
  has_many :sections, through: :enrollments
8
7
  has_many :courses, through: :sections
9
8
 
@@ -1,54 +1,32 @@
1
1
  class CoalescingPanda::Workers::CourseMiner
2
- SUPPORTED_MODELS = [:sections, :users, :enrollments, :assignment_groups, :group_categories, :assignments, :submissions, :groups, :group_memberships] #ORDER MATTERS!!
3
- COMPLETED_STATUSES = ['Completed', 'Error']
4
- RUNNING_STATUSES = ['Queued', 'Started']
2
+ SUPPORTED_MODELS = [:sections, :users, :enrollments, :assignments, :submissions, :groups, :group_memberships] #ORDER MATTERS!!
5
3
 
6
- attr_accessor :options, :account, :course, :batch, :course_section_ids, :enrollment_ids, :assignment_ids, :assignment_group_ids, :group_ids, :group_membership_ids, :user_ids
4
+ attr_accessor :options, :account, :course, :batch, :course_section_ids, :enrollment_ids, :assignment_ids, :group_ids, :user_ids
7
5
 
8
6
  def initialize(course, options = [])
9
7
  @course = course
10
8
  @account = course.account
11
9
  @options = options
12
- @batch = setup_batch
10
+ @batch = CoalescingPanda::CanvasBatch.create(context: course, status: "Queued")
13
11
  @course_section_ids = []
14
12
  @enrollment_ids = []
15
13
  @assignment_ids = []
16
- @assignment_group_ids = []
17
14
  @group_ids = []
18
- @group_membership_ids = []
19
15
  @user_ids = []
20
16
  end
21
17
 
22
- def setup_batch
23
- batch = account.canvas_batches.where(context: course).first
24
- if batch.present? and RUNNING_STATUSES.include?(batch.status)
25
- batch
26
- else
27
- batch = account.canvas_batches.create(context: course, status: "Queued")
28
- end
29
- batch.update_attributes(options: options)
30
- batch
31
- end
32
-
33
18
  def api_client
34
19
  @api_client ||= Bearcat::Client.new(prefix: account.settings[:base_url], token: account.settings[:account_admin_api_token])
35
20
  end
36
21
 
37
- def start(forced = false)
38
- unless forced
39
- return unless batch.status == 'Queued' # don't start if there is already a running job
40
- return unless should_download?
41
- end
42
-
22
+ def start
43
23
  begin
44
24
  batch.update_attributes(status: "Started", percent_complete: 0)
45
- index = 1
46
- SUPPORTED_MODELS.each do |model_key|
47
- next unless options.include?(model_key)
48
- process_api_data(model_key.to_sym)
25
+ SUPPORTED_MODELS.each_with_index do |model_key, index|
26
+ index += 1
27
+ process_api_data(model_key.to_sym) if options.include?(model_key)
49
28
  percent_complete = (index/(options.count.nonzero? || 1).to_f * 100).round(1)
50
29
  batch.update_attributes(percent_complete: percent_complete)
51
- index += 1
52
30
  end
53
31
  batch.update_attributes(status: "Completed", percent_complete: 100)
54
32
  rescue => e
@@ -57,19 +35,8 @@ class CoalescingPanda::Workers::CourseMiner
57
35
  end
58
36
  handle_asynchronously :start
59
37
 
60
- def should_download?
61
- return true unless account.settings[:canvas_download_interval].present?
62
- return true unless last_completed_batch = account.canvas_batches.where(context: course, status: 'Completed').order('updated_at ASC').first
63
- should_download = last_completed_batch.updated_at < Time.zone.now - account.settings[:canvas_download_interval].minutes
64
- batch.update_attributes(status: 'Canceled') unless should_download
65
- should_download
66
- end
67
-
68
38
  def process_api_data(key)
69
39
  case key
70
- when :assignment_groups
71
- collection = api_client.list_assignment_groups(course.canvas_course_id).all_pages!
72
- sync_assignment_groups(collection)
73
40
  when :sections
74
41
  collection = api_client.course_sections(course.canvas_course_id).all_pages!
75
42
  sync_sections(collection)
@@ -85,21 +52,14 @@ class CoalescingPanda::Workers::CourseMiner
85
52
  when :submissions
86
53
  collection = []
87
54
  course.assignments.each do |assignment|
88
- begin
89
- api_client.get_course_submissions(course.canvas_course_id, assignment.canvas_assignment_id).all_pages!.each do |submissions|
90
- collection << submissions
91
- end
92
- rescue StandardError => e
93
- Rails.logger.info("Failed to retrieve submissions for course #{course.id} and assignment #{assignment.id}: #{e}")
55
+ api_client.get_course_submissions(course.canvas_course_id, assignment.canvas_assignment_id).all_pages!.each do |submissions|
56
+ collection << submissions
94
57
  end
95
58
  end
96
59
  sync_submissions(collection)
97
60
  when :groups
98
61
  collection = api_client.course_groups(course.canvas_course_id).all_pages!
99
62
  sync_groups(collection)
100
- when :group_categories
101
- collection = api_client.list_group_categories('courses', course.canvas_course_id).all_pages!
102
- sync_group_categories(collection)
103
63
  when :group_memberships
104
64
  collection = []
105
65
  course.groups.each do |group|
@@ -113,40 +73,25 @@ class CoalescingPanda::Workers::CourseMiner
113
73
  end
114
74
  end
115
75
 
116
- def sync_assignment_groups(collection)
117
- collection.each do |values|
118
- begin
119
- values['canvas_assignment_group_id'] = values['id'].to_s
120
- assignment_group = course.assignment_groups.where(canvas_assignment_group_id: values['canvas_assignment_group_id']).first_or_initialize
121
- assignment_group.assign_attributes(standard_attributes(assignment_group, values))
122
- assignment_group.save(validate: false)
123
- assignment_group_ids << assignment_group.id
124
- rescue => e
125
- Rails.logger.error "Error syncing assignment group: #{values} Error: #{e}"
126
- end
127
- end
128
- course.assignment_groups.where.not(id: assignment_group_ids).destroy_all
129
- end
130
-
131
76
  def sync_sections(collection)
132
- collection.each do |values|
133
- begin
77
+ begin
78
+ collection.each do |values|
134
79
  values['course_section_id'] = values['id'].to_s
135
80
  section = course.sections.where(canvas_section_id: values['course_section_id']).first_or_initialize
136
81
  section.assign_attributes(standard_attributes(section, values))
137
82
  section.sis_id = values['sis_section_id']
138
83
  section.save(validate: false)
139
84
  course_section_ids << section.id
140
- rescue => e
141
- Rails.logger.error "Error syncing section: #{values} Error: #{e}"
142
85
  end
86
+ course.sections.where.not(id: course_section_ids).destroy_all
87
+ rescue => e
88
+ Rails.logger.error "Error syncing sections: #{e}"
143
89
  end
144
- course.sections.where.not(id: course_section_ids).destroy_all
145
90
  end
146
91
 
147
92
  def sync_users(collection)
148
- collection.each do |values|
149
- begin
93
+ begin
94
+ collection.each do |values|
150
95
  values['canvas_user_id'] = values["id"].to_s
151
96
  user = account.users.where(canvas_user_id: values['canvas_user_id']).first_or_initialize
152
97
  user.coalescing_panda_lti_account_id = account.id
@@ -154,132 +99,104 @@ class CoalescingPanda::Workers::CourseMiner
154
99
  user.sis_id = values['sis_user_id'].to_s
155
100
  user_ids << user.id
156
101
  user.save(validate: false)
157
- rescue => e
158
- Rails.logger.error "Error syncing user: #{values} Error: #{e}"
159
102
  end
160
- end
161
- removed_users = course.users.where.not(id: user_ids)
162
- removed_users.each do |user|
163
- user.enrollments.each do |enrollment|
164
- course.submissions.where(coalescing_panda_user_id: enrollment.user.id).destroy_all
165
- enrollment.destroy
103
+ removed_users = course.users.where.not(id: user_ids)
104
+ removed_users.each do |user|
105
+ user.enrollments.each do |enrollment|
106
+ course.submissions.where(coalescing_panda_user_id: enrollment.user.id).destroy_all
107
+ enrollment.destroy
108
+ end
166
109
  end
110
+ removed_users.destroy_all
111
+ rescue => e
112
+ Rails.logger.error "Error syncing users: #{e}"
167
113
  end
168
- removed_users.destroy_all
169
114
  end
170
115
 
171
116
  def sync_enrollments(collection)
172
- collection.each do |values|
173
- begin
117
+ begin
118
+ collection.each do |values|
174
119
  values['canvas_enrollment_id'] = values['id'].to_s
175
- section = course.sections.find_by(canvas_section_id: values['course_section_id'].to_s)
176
- enrollment = section.enrollments.where(canvas_enrollment_id: values['canvas_enrollment_id']).first_or_initialize
120
+ enrollment = course.enrollments.where(canvas_enrollment_id: values['canvas_enrollment_id']).first_or_initialize
177
121
  enrollment.section = course.sections.find_by(canvas_section_id: values['course_section_id'].to_s)
178
122
  enrollment.user = account.users.find_by(canvas_user_id: values['user_id'].to_s)
179
123
  values['workflow_state'] = values["enrollment_state"]
180
124
  values['enrollment_type'] = values['type']
181
125
  enrollment.assign_attributes(standard_attributes(enrollment, values))
182
- enrollment.save!(validate: false)
126
+ enrollment.save(validate: false)
183
127
  enrollment_ids << enrollment.id
184
- rescue => e
185
- Rails.logger.error "Error syncing enrollment: #{values} Error: #{e}"
186
128
  end
129
+ removed_enrollments = course.enrollments.where.not(id: enrollment_ids)
130
+ removed_enrollments.each do |enrollment|
131
+ course.submissions.where(coalescing_panda_user_id: enrollment.user.id).destroy_all
132
+ end
133
+ removed_enrollments.destroy_all
134
+ rescue => e
135
+ Rails.logger.error "Error syncing enrollments: #{e}"
187
136
  end
188
- removed_enrollments = course.enrollments.where.not(id: enrollment_ids)
189
- removed_enrollments.each do |enrollment|
190
- course.submissions.where(coalescing_panda_user_id: enrollment.user.id).destroy_all
191
- end
192
- removed_enrollments.destroy_all
193
137
  end
194
138
 
195
139
  def sync_assignments(collection)
196
- collection.each do |values|
197
- begin
140
+ begin
141
+ collection.each do |values|
198
142
  values['canvas_assignment_id'] = values['id'].to_s
199
143
  assignment = course.assignments.where(canvas_assignment_id: values['canvas_assignment_id']).first_or_initialize
200
- assignment_group = course.assignment_groups.find_by(canvas_assignment_group_id: values['assignment_group_id'].to_s)
201
- group_category = course.group_categories.find_by(canvas_group_category_id: values['group_category_id'])
202
- assignment.coalescing_panda_assignment_group_id = assignment_group.id if assignment_group
203
- assignment.coalescing_panda_group_category_id = group_category.id if group_category
204
144
  assignment.assign_attributes(standard_attributes(assignment, values))
205
145
  assignment.save(validate: false)
206
146
  assignment_ids << assignment.id
207
- rescue => e
208
- Rails.logger.error "Error syncing assignment: #{values} Error: #{e}"
209
147
  end
210
- end
211
- course.assignments.includes(:submissions).where.not(id: assignment_ids).each do |assignment|
212
- assignment.submissions.each { |s| s.destroy }
213
- assignment.destroy
148
+ course.assignments.where.not(id: assignment_ids).each do |assignment|
149
+ assignment.submissions.destroy_all
150
+ assignment.destroy!
151
+ end
152
+ rescue => e
153
+ Rails.logger.error "Error syncing assignments: #{e}"
214
154
  end
215
155
  end
216
156
 
217
157
  def sync_submissions(collection)
218
- collection.each do |values|
219
- begin
158
+ begin
159
+ collection.each do |values|
220
160
  values['canvas_submission_id'] = values['id'].to_s
221
161
  submission = course.submissions.where(canvas_submission_id: values['canvas_submission_id']).first_or_initialize
222
162
  submission.user = course.users.find_by(canvas_user_id: values['user_id'].to_s)
223
163
  submission.assignment = course.assignments.find_by(canvas_assignment_id: values['assignment_id'].to_s)
224
164
  submission.assign_attributes(standard_attributes(submission, values))
225
165
  submission.save(validate: false)
226
- rescue => e
227
- Rails.logger.error "Error syncing submission: #{values} Error: #{e}"
228
- end
229
- end
230
- end
231
-
232
- def sync_group_categories(collection)
233
- collection.each do |values|
234
- begin
235
- values['canvas_group_category_id'] = values['id'].to_s
236
- values.delete('context_type') #assume only course for now
237
- category = course.group_categories.where(canvas_group_category_id: values['canvas_group_category_id']).first_or_initialize
238
- category.assign_attributes(standard_attributes(category, values))
239
- category.save(validate: false)
240
- rescue => e
241
- Rails.logger.error "Error syncing group categories: #{values} Error: #{e.message} - #{e.backtrace}"
242
166
  end
167
+ rescue => e
168
+ Rails.logger.error "Error syncing submissions: #{e}"
243
169
  end
244
170
  end
245
171
 
246
172
  def sync_groups(collection)
247
- collection.each do |values|
248
- begin
173
+ begin
174
+ collection.each do |values|
249
175
  values['canvas_group_id'] = values['id'].to_s
250
176
  group = course.groups.where(canvas_group_id: values['canvas_group_id']).first_or_initialize
251
- group_category = course.group_categories.find_by(canvas_group_category_id: values['group_category_id'])
252
- if values['leader']
253
- group.leader = course.users.find_by(canvas_user_id: values['leader']['id'].to_s)
254
- else
255
- group.leader = nil
256
- end
257
- group.coalescing_panda_group_category_id = group_category.id if group_category
258
177
  group.assign_attributes(standard_attributes(group, values))
259
178
  group.save(validate: false)
260
179
  group_ids << group.id
261
- rescue => e
262
- Rails.logger.error "Error syncing group: #{values} Error: #{e}"
263
180
  end
181
+ course.groups.where.not(id: group_ids).destroy_all
182
+ rescue => e
183
+ Rails.logger.error "Error syncing groups: #{e}"
264
184
  end
265
- course.groups.where.not(id: group_ids).destroy_all
266
185
  end
267
186
 
268
187
  def sync_group_memberships(collection)
269
- collection.each do |values|
270
- begin
188
+ begin
189
+ collection.each do |values|
271
190
  values['canvas_group_membership_id'] = values['id'].to_s
272
191
  group_membership = course.group_memberships.where(canvas_group_membership_id: values['canvas_group_membership_id']).first_or_initialize
273
192
  group_membership.group = course.groups.find_by(canvas_group_id: values['group_id'].to_s)
274
193
  group_membership.user = course.users.find_by(canvas_user_id: values['user_id'].to_s)
275
194
  group_membership.assign_attributes(standard_attributes(group_membership, values))
276
195
  group_membership.save(validate: false)
277
- group_membership_ids << group_membership.id
278
- rescue => e
279
- Rails.logger.error "Error syncing group memebership: #{values} Error: #{e}"
280
196
  end
197
+ rescue => e
198
+ Rails.logger.error "Error syncing group memberships: #{e}"
281
199
  end
282
- course.group_memberships.where.not(id: group_membership_ids).destroy_all
283
200
  end
284
201
 
285
202
  def standard_attributes(record, attributes)
@@ -287,4 +204,4 @@ class CoalescingPanda::Workers::CourseMiner
287
204
  new_attributes.delete('id')
288
205
  new_attributes.delete_if { |key, value| !record.attributes.include?(key) }
289
206
  end
290
- end
207
+ end
@@ -8,4 +8,4 @@ module SingleTablePolymorphic
8
8
  end
9
9
  end
10
10
  end
11
- end
11
+ end
@@ -1,32 +1,20 @@
1
1
  #batch-info{data: {batch: @batch.to_json}}
2
- - if @batch.status == "Queued"
3
- %span.batch-message-queued Data is queued for download from Canvas.
2
+ -if @batch.status == "Queued"
3
+ %h6.batch-message-queued Data is queued for download from Canvas.
4
4
 
5
- - if @batch.status == "Completed"
5
+ -if @batch.status == "Completed"
6
6
  .alert.alert-success
7
7
  %button.close{"data-dismiss" => "alert", :type => "button"} ×
8
8
  %span.batch-message-completed
9
9
  Data successfully downloaded from Canvas.
10
10
 
11
- - if @batch.status == "Started"
12
- %h6.batch-message-started
13
- Downloading data from Canvas
14
- .progress.progress-striped.active
15
- .bar{:style => "width: #{@batch.percent_complete}%;"}
11
+ -if @batch.status == "Started"
12
+ %h6.batch-message-started Downloading data from Canvas
13
+ .progress.progress-striped.active
14
+ .bar{:style => "width: #{@batch.percent_complete}%;"}
16
15
 
17
-
18
- - if @batch.status == "Error"
16
+ -if @batch.status == "Error"
19
17
  .alert.alert-block.alert-error
20
18
  %button.close{"data-dismiss" => "alert", :type => "button"} ×
21
- %span.batch-message-error Data failed to download from Canvas
22
- = @batch.message
23
-
24
- - if @batch.status == "Canceled"
25
- .alert.alert-block.alert-info
26
- %button.close{"data-dismiss" => "alert", :type => "button"} ×
27
- %span.batch-message-retrigger
28
- Canvas data last downloaded
29
- = @batch.updated_at
30
- .pull-right
31
- = link_to "Retrigger", retrigger_canvas_batch_path(@batch), method: :post, class: "btn btn-default"
32
- .clearfix
19
+ %h6.batch-message-error Data failed to download from Canvas
20
+ = @batch.message
@@ -1,4 +1,4 @@
1
1
  - if current_batch.present?
2
2
  - path = CoalescingPanda::Engine.routes.url_helpers.canvas_batch_path(current_batch)
3
- - clear_path = CoalescingPanda::Engine.routes.url_helpers.clear_batch_session_path
3
+ -clear_path = CoalescingPanda::Engine.routes.url_helpers.clear_batch_session_path
4
4
  #batch-progress{data: {batch: current_batch.try(:to_json), url: path, clear_path: clear_path} }
data/config/routes.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  CoalescingPanda::Engine.routes.draw do
2
- resources :canvas_batches, only: [:show, :update] do
3
- post :retrigger, on: :member
4
- end
2
+ resources :canvas_batches, only: [:show]
5
3
  post '/canvas_batches/clear_batch_session', as: :clear_batch_session
6
4
 
7
5
  get '/oauth2/redirect' => 'oauth2#redirect'
@@ -7,21 +7,27 @@ module CoalescingPanda
7
7
  if lti_authorize!(*roles)
8
8
  user_id = params['user_id']
9
9
  launch_presentation_return_url = @lti_account.settings[:launch_presentation_return_url] || params['launch_presentation_return_url']
10
- launch_presentation_return_url = [BearcatUri.new(request.env["HTTP_REFERER"]).prefix, launch_presentation_return_url].join unless launch_presentation_return_url.include?('http')
11
- uri = BearcatUri.new(launch_presentation_return_url)
12
- set_session(launch_presentation_return_url)
10
+ uri = URI.parse(launch_presentation_return_url)
11
+ api_domain = uri.host
12
+ api_domain = "#{api_domain}:#{uri.port.to_s}" if uri.port
13
+ scheme = uri.scheme + '://'
14
+ @lti_params = params.to_hash
15
+ session['user_id'] = user_id
16
+ session['uri'] = launch_presentation_return_url
17
+ session['lis_person_sourcedid'] = params['lis_person_sourcedid']
18
+ session['oauth_consumer_key'] = params['oauth_consumer_key']
19
+ session['custom_canvas_account_id'] = params['custom_canvas_account_id']
13
20
 
14
- if token = CanvasApiAuth.where('user_id = ? and api_domain = ?', user_id, uri.api_domain).pluck(:api_token).first
15
- @client = Bearcat::Client.new(token: token, prefix: uri.prefix)
21
+ if token = CanvasApiAuth.where('user_id = ? and api_domain = ?', user_id, api_domain).pluck(:api_token).first
22
+ @client = Bearcat::Client.new(token: token, prefix: scheme+api_domain)
16
23
  elsif @lti_account = params['oauth_consumer_key'] && LtiAccount.find_by_key(params['oauth_consumer_key'])
17
24
  client_id = @lti_account.oauth2_client_id
18
- client = Bearcat::Client.new(prefix: uri.prefix)
25
+ client = Bearcat::Client.new(prefix: scheme+api_domain)
19
26
  session['state'] = SecureRandom.hex(32)
20
- redirect_url = [coalescing_panda_url, coalescing_panda.oauth2_redirect_path({key: params['oauth_consumer_key'], user_id: user_id, api_domain: uri.api_domain, state: session['state']})].join
21
- @canvas_url = client.auth_redirect_url(client_id, redirect_url)
22
-
27
+ @canvas_url = client.auth_redirect_url(client_id,
28
+ coalescing_panda.oauth2_redirect_url({key: params['oauth_consumer_key'],
29
+ user_id: user_id, api_domain: api_domain, state: session['state']}))
23
30
  #delete the added params so the original oauth sig still works
24
- @lti_params = params.to_hash
25
31
  @lti_params.delete('action')
26
32
  @lti_params.delete('controller')
27
33
  render 'coalescing_panda/oauth2/oauth2', layout: 'coalescing_panda/application'
@@ -29,14 +35,6 @@ module CoalescingPanda
29
35
  end
30
36
  end
31
37
 
32
- def set_session(launch_presentation_return_url)
33
- session['user_id'] = params['user_id']
34
- session['uri'] = launch_presentation_return_url
35
- session['lis_person_sourcedid'] = params['lis_person_sourcedid']
36
- session['oauth_consumer_key'] = params['oauth_consumer_key']
37
- session['custom_canvas_account_id'] = params['custom_canvas_account_id']
38
- end
39
-
40
38
  def have_session?
41
39
  if params['tool_consumer_instance_guid'] && session['user_id'] != params['user_id']
42
40
  reset_session
@@ -45,9 +43,12 @@ module CoalescingPanda
45
43
  end
46
44
 
47
45
  if (session['user_id'] && session['uri'])
48
- uri = BearcatUri.new(session['uri'])
49
- token = CanvasApiAuth.where('user_id = ? and api_domain = ?', session['user_id'], uri.api_domain).pluck(:api_token).first
50
- @client = Bearcat::Client.new(token: token, prefix: uri.prefix) if token
46
+ uri = URI.parse(session['uri'])
47
+ api_domain = uri.host
48
+ api_domain = "#{api_domain}:#{uri.port.to_s}" if uri.port
49
+ scheme = uri.scheme + '://'
50
+ token = CanvasApiAuth.where('user_id = ? and api_domain = ?', session['user_id'], api_domain).pluck(:api_token).first
51
+ @client = Bearcat::Client.new(token: token, prefix: scheme+api_domain) if token
51
52
  end
52
53
 
53
54
  @lti_account = LtiAccount.find_by_key(session['oauth_consumer_key']) if session['oauth_consumer_key']
@@ -66,7 +67,9 @@ module CoalescingPanda
66
67
  logger.info 'not authorized on roles' if !authorized
67
68
  authorized = authorized && @lti_account.validate_nonce(params['oauth_nonce'], DateTime.strptime(params['oauth_timestamp'], '%s'))
68
69
  logger.info 'not authorized on nonce' if !authorized
69
- render :text => 'Invalid Credentials, please contact your Administrator.', :status => :unauthorized unless authorized
70
+ if !authorized
71
+ render :text => 'Invalid Credentials, please contact your Administrator.', :status => :unauthorized
72
+ end
70
73
  authorized
71
74
  end
72
75
 
@@ -1,3 +1,3 @@
1
1
  module CoalescingPanda
2
- VERSION = '4.0.11'
2
+ VERSION = '4.1.0'
3
3
  end