coalescing_panda 4.0.11 → 4.1.0

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.
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