coalescing_panda 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
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