coalescing_panda 2.0.0 → 3.0.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 (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/coalescing_panda/lti_controller.rb +1 -0
  3. data/app/models/coalescing_panda/assignment.rb +8 -0
  4. data/app/models/coalescing_panda/canvas_api_auth.rb +0 -2
  5. data/app/models/coalescing_panda/course.rb +11 -0
  6. data/app/models/coalescing_panda/enrollment.rb +8 -0
  7. data/app/models/coalescing_panda/lti_account.rb +10 -6
  8. data/app/models/coalescing_panda/lti_nonce.rb +0 -2
  9. data/app/models/coalescing_panda/section.rb +9 -0
  10. data/app/models/coalescing_panda/session.rb +0 -1
  11. data/app/models/coalescing_panda/submission.rb +8 -0
  12. data/app/models/coalescing_panda/term.rb +6 -0
  13. data/app/models/coalescing_panda/user.rb +9 -0
  14. data/app/models/coalescing_panda/workers/course_miner.rb +91 -0
  15. data/db/migrate/20131118211442_create_coalescing_panda_lti_accounts.rb +0 -1
  16. data/db/migrate/20141119225319_create_coalescing_panda_terms.rb +19 -0
  17. data/db/migrate/20141119225721_create_coalescing_panda_courses.rb +22 -0
  18. data/db/migrate/20141120151432_create_coalescing_panda_sections.rb +19 -0
  19. data/db/migrate/20141120151940_create_coalescing_panda_assignments.rb +22 -0
  20. data/db/migrate/20141120152458_create_coalescing_panda_users.rb +19 -0
  21. data/db/migrate/20141120152546_create_coalescing_panda_submissions.rb +19 -0
  22. data/db/migrate/20141120153135_create_coalescing_panda_enrollments.rb +19 -0
  23. data/db/migrate/20141120205729_add_canvas_account_id_to_lti_account.rb +5 -0
  24. data/lib/coalescing_panda/engine.rb +5 -0
  25. data/lib/coalescing_panda/version.rb +1 -1
  26. data/spec/controllers/coalescing_panda/lti_controller_spec.rb +1 -6
  27. data/spec/controllers/coalescing_panda/oauth2_controller_spec.rb +1 -1
  28. data/spec/dummy/config/application.rb +3 -0
  29. data/spec/dummy/db/schema.rb +120 -1
  30. data/spec/factories/accounts.rb +19 -0
  31. data/spec/factories/assignments.rb +9 -0
  32. data/spec/factories/courses.rb +7 -0
  33. data/spec/factories/enrollments.rb +7 -0
  34. data/spec/factories/submissions.rb +8 -0
  35. data/spec/factories/users.rb +29 -0
  36. data/spec/models/coalescing_panda/assignment_spec.rb +18 -0
  37. data/spec/models/coalescing_panda/course_spec.rb +37 -0
  38. data/spec/models/coalescing_panda/enrollment_spec.rb +17 -0
  39. data/spec/models/coalescing_panda/lti_account_spec.rb +17 -0
  40. data/spec/models/coalescing_panda/lti_nonce_spec.rb +5 -0
  41. data/spec/models/coalescing_panda/section_spec.rb +22 -0
  42. data/spec/models/coalescing_panda/submission_spec.rb +18 -0
  43. data/spec/models/coalescing_panda/term_spec.rb +17 -0
  44. data/spec/models/coalescing_panda/user_spec.rb +27 -0
  45. data/spec/rails_helper.rb +45 -0
  46. data/spec/spec_helper.rb +82 -29
  47. metadata +59 -11
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8ec1b5c9bfc79b28575ac9681953bc1589aaec58
4
- data.tar.gz: 9cae9d48dbb29ed1ccaeab79498b293caee9653a
3
+ metadata.gz: e1fe754bf45b22224fa5d6800b9e70fd6aa3b262
4
+ data.tar.gz: e9fefae84355b40fa9f737901a691d8a3967021c
5
5
  SHA512:
6
- metadata.gz: 35b2bde2067e5ce0e3c2eb863caa36c047ec88c6892b4a9590a9affbd34fc4199433759096f55c03d84b47710b8ad435f69f1ffb62e583a3a81d68edb3981d13
7
- data.tar.gz: 855909206eebdcc7625cc2a0e21fce3966f6015b4bd441433cd7e59716489c75226982a44ee6e60fd408da655e6f68934e29995cea13ae4cf39201b5fc05dc75
6
+ metadata.gz: 8225718e3d84b9b558810dd44e689cb782398b38c6e7a3cb9716a2ada0ac74472eb9d3c9481da2c6ff54521000ffc0d5537eb61ae9e4a701fe6f9a7b97a6b0c0
7
+ data.tar.gz: 5dfc9a3752d0324076328907b059fe95a2af957e90bbf665808bdfac339c6e3535b8355de4b1ec352adf14e0cacd991206a01ed517d28dd3d0cb1a152dfc51f9
@@ -13,6 +13,7 @@ module CoalescingPanda
13
13
  tc = IMS::LTI::ToolConfig.new(:title => lti_options[:title], :launch_url => ("#{host}#{lti_options[:launch_route]}") || 'ABC')
14
14
  tc.set_ext_param(platform, :domain, request.host)
15
15
  tc.set_ext_param(platform, :privacy_level, 'public')
16
+ tc.set_custom_param(:custom_canvas_role, '$Canvas.membership.roles')
16
17
  if lti_options.has_key?(:custom_fields)
17
18
  tc.set_ext_param(platform, :custom_fields, lti_options[:custom_fields])
18
19
  lti_options[:custom_fields].each do |k, v|
@@ -0,0 +1,8 @@
1
+ module CoalescingPanda
2
+ class Assignment < ActiveRecord::Base
3
+ belongs_to :course, foreign_key: :coalescing_panda_course_id, class_name: 'CoalescingPanda::Course'
4
+ has_many :submissions, foreign_key: :coalescing_panda_assignment_id, class_name: 'CoalescingPanda::Submission'
5
+
6
+ delegate :account, to: :course
7
+ end
8
+ end
@@ -2,8 +2,6 @@ module CoalescingPanda
2
2
  class CanvasApiAuth < ActiveRecord::Base
3
3
  validates :user_id, :api_domain, presence: true
4
4
  validates :user_id, uniqueness: {scope: :api_domain}
5
-
6
- attr_accessible :user_id, :api_domain
7
5
  end
8
6
 
9
7
  end
@@ -0,0 +1,11 @@
1
+ module CoalescingPanda
2
+ class Course < ActiveRecord::Base
3
+ belongs_to :account, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::LtiAccount'
4
+ belongs_to :term, foreign_key: :coalescing_panda_term_id, class_name: 'CoalescingPanda::Term'
5
+ has_many :sections, foreign_key: :coalescing_panda_course_id, class_name: 'CoalescingPanda::Section'
6
+ has_many :enrollments, through: :sections
7
+ has_many :assignments, foreign_key: :coalescing_panda_course_id, class_name: 'CoalescingPanda::Assignment'
8
+ has_many :submissions, through: :assignments
9
+ has_many :users, through: :sections, source: :users, class_name: 'CoalescingPanda::User'
10
+ end
11
+ end
@@ -0,0 +1,8 @@
1
+ module CoalescingPanda
2
+ class Enrollment < ActiveRecord::Base
3
+ belongs_to :user, foreign_key: :coalescing_panda_user_id, class_name: 'CoalescingPanda::User'
4
+ belongs_to :section, foreign_key: :coalescing_panda_section_id, class_name: 'CoalescingPanda::Section'
5
+
6
+ delegate :account, to: :section
7
+ end
8
+ end
@@ -2,24 +2,28 @@ module CoalescingPanda
2
2
  class LtiAccount < ActiveRecord::Base
3
3
  validates :name, :key, uniqueness: true
4
4
  validates :name, :key, :secret, presence: true
5
- has_many :coalescing_panda_lti_nonces,
6
- :foreign_key => :coalescing_panda_lti_account_id,
7
- :class_name => 'CoalescingPanda::LtiNonce'
5
+ has_many :lti_nonces, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::LtiNonce'
6
+ has_many :terms, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::Term'
7
+ has_many :courses, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::Course'
8
+ has_many :users, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::User'
9
+ has_many :sections, through: :courses
10
+ has_many :enrollments, through: :sections
11
+ has_many :assignments, through: :courses
12
+ has_many :submissions, through: :assignments
8
13
 
9
- attr_accessible :name, :key, :secret, :oauth2_client_id, :oauth2_client_key, :settings
10
14
  serialize :settings
11
15
 
12
16
  def validate_nonce(nonce, timestamp)
13
17
  cleanup_nonce
14
18
  if timestamp > 15.minutes.ago
15
- coalescing_panda_lti_nonces.create(nonce: nonce, timestamp: timestamp).persisted?
19
+ lti_nonces.create(nonce: nonce, timestamp: timestamp).persisted?
16
20
  end
17
21
  end
18
22
 
19
23
  private
20
24
 
21
25
  def cleanup_nonce
22
- coalescing_panda_lti_nonces.where('timestamp > ?', 15.minutes.ago).delete_all
26
+ lti_nonces.where('timestamp > ?', 15.minutes.ago).delete_all
23
27
  end
24
28
 
25
29
  end
@@ -3,8 +3,6 @@ module CoalescingPanda
3
3
  validates :coalescing_panda_lti_account, :nonce, :timestamp, :presence => true
4
4
  validates :nonce, uniqueness: {scope: :coalescing_panda_lti_account}
5
5
  belongs_to :coalescing_panda_lti_account, :class_name => 'CoalescingPanda::LtiAccount'
6
-
7
- attr_accessible :nonce, :timestamp
8
6
  end
9
7
 
10
8
  def cleanup
@@ -0,0 +1,9 @@
1
+ module CoalescingPanda
2
+ class Section < ActiveRecord::Base
3
+ belongs_to :course, foreign_key: :coalescing_panda_course_id, class_name: 'CoalescingPanda::Course'
4
+ has_many :enrollments, foreign_key: :coalescing_panda_section_id, class_name: 'CoalescingPanda::Enrollment'
5
+ has_many :users, through: :enrollments, class_name: 'CoalescingPanda::User'
6
+
7
+ delegate :account, to: :course
8
+ end
9
+ end
@@ -1,6 +1,5 @@
1
1
  module CoalescingPanda
2
2
  class Session < ActiveRecord::Base
3
- attr_accessible :token, :data
4
3
  serialize :data, Hash
5
4
 
6
5
  def self.create_from_session(session)
@@ -0,0 +1,8 @@
1
+ module CoalescingPanda
2
+ class Submission < ActiveRecord::Base
3
+ belongs_to :user, foreign_key: :coalescing_panda_user_id, class_name: 'CoalescingPanda::User'
4
+ belongs_to :assignment, foreign_key: :coalescing_panda_assignment_id, class_name: 'CoalescingPanda::Assignment'
5
+
6
+ delegate :account, to: :assignment
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ module CoalescingPanda
2
+ class Term < ActiveRecord::Base
3
+ belongs_to :account, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::LtiAccount'
4
+ has_many :courses, foreign_key: :coalescing_panda_term_id, class_name: 'CoalescingPanda::Course'
5
+ end
6
+ end
@@ -0,0 +1,9 @@
1
+ module CoalescingPanda
2
+ class User < ActiveRecord::Base
3
+ belongs_to :account, foreign_key: :coalescing_panda_lti_account_id, class_name: 'CoalescingPanda::LtiAccount'
4
+ has_many :enrollments, foreign_key: :coalescing_panda_user_id, class_name: 'CoalescingPanda::Enrollment'
5
+ has_many :submissions, foreign_key: :coalescing_panda_user_id, class_name: 'CoalescingPanda::Submission'
6
+ has_many :sections, through: :enrollments
7
+ has_many :courses, through: :sections
8
+ end
9
+ end
@@ -0,0 +1,91 @@
1
+ class CoalescingPanda::Workers::CourseMiner
2
+ SUPPORTED_MODELS = [:sections, :users, :enrollments, :assignments, :submissions] #ORDER MATTERS!!
3
+
4
+ attr_accessor :api_client, :options, :account, :course, :canvas_account_id
5
+
6
+ def initialize(course, options = [])
7
+ @course = course
8
+ @account = course.account
9
+ @canvas_account_id = course.account.canvas_account_id
10
+ @api_client = Bearcat::Client.new(prefix: account.settings[:base_url], token: account.settings[:account_admin_api_token])
11
+ @options = options
12
+ end
13
+
14
+ def start
15
+ SUPPORTED_MODELS.each do |model_key|
16
+ canvas_model_data(api_method(model_key.to_sym), model_key) if options.include?(model_key)
17
+ end
18
+ end
19
+
20
+ def api_method(key)
21
+ case key
22
+ when :users
23
+ :list_course_users
24
+ when :sections
25
+ :course_sections
26
+ when :enrollments
27
+ :course_enrollments
28
+ when :assignments
29
+ :assignments
30
+ when :submissions
31
+ :get_course_submission
32
+ else
33
+ raise "API METHOD DOESN'T EXIST"
34
+ end
35
+ end
36
+
37
+ def canvas_model_data(method, model_key)
38
+ if model_key == :submissions
39
+ collection = []
40
+ course.assignments.each do |assignment|
41
+ api_client.get_course_submissions(course.canvas_course_id, assignment.canvas_assignment_id).all_pages!.each do |submissions|
42
+ collection << submissions
43
+ end
44
+ end
45
+ create_records(collection, model_key)
46
+ else
47
+ collection = api_client.send(method, course.canvas_course_id).all_pages!
48
+ create_records(collection, model_key)
49
+ end
50
+ end
51
+
52
+ def create_records(collection, model_key)
53
+ model = "CoalescingPanda::#{model_key.to_s.singularize.titleize}".constantize
54
+ collection.each do |values|
55
+ canvas_id_key = "canvas_#{model_key.to_s.singularize}_id"
56
+ values[canvas_id_key] = values["id"]
57
+ record = course.send(model_key).where("#{canvas_id_key} = ?", values['id'].to_s).first_or_initialize
58
+ record.coalescing_panda_lti_account_id = account.id if record.respond_to?(:coalescing_panda_lti_account_id)
59
+ record.assign_attributes(standard_attributes(record, values))
60
+ record.sis_id = sis_id(model_key, values) if record.respond_to?(:sis_id)
61
+ create_associations(record, model_key, values)
62
+ record.save
63
+ end
64
+ end
65
+
66
+ def standard_attributes(record, attributes)
67
+ new_attributes = attributes.dup
68
+ new_attributes.delete('id')
69
+ new_attributes.delete_if { |key, value| !record.attributes.include?(key) }
70
+ end
71
+
72
+ def sis_id(model_key, values)
73
+ return values['sis_source_id'] if values.has_key?('sis_source_id')
74
+ return values['sis_section_id'] if model_key == :sections
75
+ end
76
+
77
+ def create_associations(record, model_key, values)
78
+ case model_key
79
+ when :users
80
+ record.account = account
81
+ when :enrollments
82
+ record.user = account.users.where(canvas_user_id: values['user_id'].to_s).first
83
+ record.section = course.sections.where(canvas_section_id: values['course_section_id'].to_s).first
84
+ when :assignments
85
+ record.course = course
86
+ when :submissions
87
+ record.user = account.users.where(canvas_user_id: values['user_id'].to_s).first
88
+ record.assignment = course.assignments.where(canvas_assignment_id: values['assignment_id'].to_s).first
89
+ end
90
+ end
91
+ end
@@ -7,7 +7,6 @@ class CreateCoalescingPandaLtiAccounts < ActiveRecord::Migration
7
7
  t.string :oauth2_client_id
8
8
  t.string :oauth2_client_key
9
9
 
10
-
11
10
  t.timestamps
12
11
  end
13
12
  end
@@ -0,0 +1,19 @@
1
+ class CreateCoalescingPandaTerms < ActiveRecord::Migration
2
+ def change
3
+ create_table :coalescing_panda_terms do |t|
4
+ t.belongs_to :coalescing_panda_lti_account
5
+ t.string :name
6
+ t.string :code
7
+ t.string :sis_id
8
+ t.string :canvas_term_id
9
+ t.datetime :start_at
10
+ t.datetime :end_at
11
+ t.string :workflow_state
12
+
13
+ t.timestamps
14
+ end
15
+
16
+ add_index :coalescing_panda_terms, :canvas_term_id
17
+ add_index :coalescing_panda_terms, :sis_id
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ class CreateCoalescingPandaCourses < ActiveRecord::Migration
2
+ def change
3
+ create_table :coalescing_panda_courses do |t|
4
+ t.belongs_to :coalescing_panda_lti_account
5
+ t.belongs_to :coalescing_panda_term
6
+ t.string :name
7
+ t.string :canvas_course_id
8
+ t.string :sis_id
9
+ t.datetime :start_at
10
+ t.datetime :conclude_at
11
+ t.string :workflow_state
12
+ t.string :course_code
13
+
14
+ t.timestamps
15
+ end
16
+
17
+ add_index :coalescing_panda_courses, :coalescing_panda_lti_account_id, name: :index_courses_account
18
+ add_index :coalescing_panda_courses, :coalescing_panda_term_id, name: :index_courses_term
19
+ add_index :coalescing_panda_courses, :canvas_course_id
20
+ add_index :coalescing_panda_courses, :sis_id
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ class CreateCoalescingPandaSections < ActiveRecord::Migration
2
+ def change
3
+ create_table :coalescing_panda_sections do |t|
4
+ t.belongs_to :coalescing_panda_course
5
+ t.string :name
6
+ t.string :canvas_section_id
7
+ t.string :sis_id
8
+ t.string :workflow_state
9
+ t.datetime :start_at
10
+ t.datetime :end_at
11
+
12
+ t.timestamps
13
+ end
14
+
15
+ add_index :coalescing_panda_sections, :coalescing_panda_course_id
16
+ add_index :coalescing_panda_sections, :canvas_section_id
17
+ add_index :coalescing_panda_sections, :sis_id
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ class CreateCoalescingPandaAssignments < ActiveRecord::Migration
2
+ def change
3
+ create_table :coalescing_panda_assignments do |t|
4
+ t.belongs_to :coalescing_panda_course
5
+ t.string :name
6
+ t.string :description
7
+ t.string :canvas_assignment_id
8
+ t.string :sis_id
9
+ t.string :workflow_state
10
+ t.float :points_possible
11
+ t.datetime :due_at
12
+ t.datetime :unlock_at
13
+ t.datetime :lock_at
14
+
15
+ t.timestamps
16
+ end
17
+
18
+ add_index :coalescing_panda_assignments, :coalescing_panda_course_id, name: :index_assignments_course
19
+ add_index :coalescing_panda_assignments, :canvas_assignment_id
20
+ add_index :coalescing_panda_assignments, :sis_id
21
+ end
22
+ end
@@ -0,0 +1,19 @@
1
+ class CreateCoalescingPandaUsers < ActiveRecord::Migration
2
+ def change
3
+ create_table :coalescing_panda_users do |t|
4
+ t.belongs_to :coalescing_panda_lti_account
5
+ t.string :name
6
+ t.string :email
7
+ t.string :roles
8
+ t.string :workflow_state
9
+ t.string :sis_id
10
+ t.string :canvas_user_id
11
+
12
+ t.timestamps
13
+ end
14
+
15
+ add_index :coalescing_panda_users, :coalescing_panda_lti_account_id, name: :index_users_account
16
+ add_index :coalescing_panda_users, :canvas_user_id
17
+ add_index :coalescing_panda_users, :sis_id
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ class CreateCoalescingPandaSubmissions < ActiveRecord::Migration
2
+ def change
3
+ create_table :coalescing_panda_submissions do |t|
4
+ t.belongs_to :coalescing_panda_user
5
+ t.belongs_to :coalescing_panda_assignment
6
+ t.string :url
7
+ t.string :grade
8
+ t.string :score
9
+ t.datetime :submitted_at
10
+ t.string :workflow_state
11
+ t.string :canvas_submission_id
12
+
13
+ t.timestamps
14
+ end
15
+
16
+ add_index :coalescing_panda_submissions, [:coalescing_panda_user_id, :coalescing_panda_assignment_id], name: :index_submissions_user_and_assignment
17
+ add_index :coalescing_panda_submissions, :canvas_submission_id
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ class CreateCoalescingPandaEnrollments < ActiveRecord::Migration
2
+ def change
3
+ create_table :coalescing_panda_enrollments do |t|
4
+ t.belongs_to :coalescing_panda_user
5
+ t.belongs_to :coalescing_panda_section
6
+ t.string :workflow_state
7
+ t.string :sis_id
8
+ t.string :canvas_enrollment_id
9
+ t.datetime :start_at
10
+ t.datetime :end_at
11
+
12
+ t.timestamps
13
+ end
14
+
15
+ add_index :coalescing_panda_enrollments, [:coalescing_panda_user_id, :coalescing_panda_section_id], name: :index_enrollments_user_and_assignment
16
+ add_index :coalescing_panda_enrollments, :canvas_enrollment_id
17
+ add_index :coalescing_panda_enrollments, :sis_id
18
+ end
19
+ end
@@ -0,0 +1,5 @@
1
+ class AddCanvasAccountIdToLtiAccount < ActiveRecord::Migration
2
+ def change
3
+ add_column :coalescing_panda_lti_accounts, :canvas_account_id, :string
4
+ end
5
+ end
@@ -3,6 +3,11 @@ module CoalescingPanda
3
3
  config.autoload_once_paths += Dir["#{config.root}/lib/**/"]
4
4
  isolate_namespace CoalescingPanda
5
5
 
6
+ config.generators do |g|
7
+ g.test_framework :rspec
8
+ g.fixture_replacement :factory_girl, :dir => 'spec/factories'
9
+ end
10
+
6
11
  initializer :append_migrations do |app|
7
12
  unless app.root.to_s.match root.to_s
8
13
  config.paths["db/migrate"].expanded.each do |expanded_path|
@@ -1,3 +1,3 @@
1
1
  module CoalescingPanda
2
- VERSION = '2.0.0'
2
+ VERSION = '3.0.0'
3
3
  end
@@ -1,12 +1,11 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe CoalescingPanda::LtiController do
3
+ describe CoalescingPanda::LtiController, :type => :controller do
4
4
  routes { CoalescingPanda::Engine.routes }
5
5
 
6
6
  describe '#lti_config' do
7
7
 
8
8
  it 'generates lti xml config'do
9
- controller.main_app.stub(:test_action_url) {'foo'}
10
9
  get(:lti_config)
11
10
  xml = Nokogiri::XML(response.body)
12
11
  xml.at_xpath('//blti:title').text.should == 'LTI Tool'
@@ -15,7 +14,6 @@ describe CoalescingPanda::LtiController do
15
14
  end
16
15
 
17
16
  it 'generates lti nav config' do
18
- controller.main_app.stub(:test_action_url) {'foo'}
19
17
  CoalescingPanda.stage_navigation(:account, {
20
18
  url: 'test_action',
21
19
  text: 'My Title',
@@ -33,12 +31,9 @@ describe CoalescingPanda::LtiController do
33
31
 
34
32
  end
35
33
 
36
-
37
34
  it 'get the url, from the action string' do
38
- controller.main_app.stub(:test_action_url) {'foo'}
39
35
  options = controller.send(:ext_params, {url:'test_action'})
40
36
  options[:url].should == 'foo'
41
37
  end
42
38
 
43
-
44
39
  end