coalescing_panda 5.1.13 → 5.2.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/app/controllers/coalescing_panda/oauth2_controller.rb +3 -11
- data/app/models/coalescing_panda/group.rb +1 -1
- data/app/views/coalescing_panda/oauth2/oauth2.html.haml +3 -1
- data/lib/coalescing_panda/controller_helpers.rb +92 -79
- data/lib/coalescing_panda/version.rb +1 -1
- data/spec/dummy/db/development.sqlite3 +0 -0
- data/spec/dummy/db/schema.rb +136 -151
- data/spec/dummy/db/test.sqlite3 +0 -0
- metadata +66 -63
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: bee89db63211898d79a2be426960cb091d7d4b9c384b848587c45744e40471e9
|
4
|
+
data.tar.gz: 06b1367659b15e63d7811a0a4ed6385f8f8925c3fac3767b9b0283bd00bd78b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c902f68f0ed0685039be21864520fe6c80bc199f74afc897b5a38a38e6ea72b335463c0de6498024871e335cb515a7b68c9fa952a384fdf8cb10da12df5e6f23
|
7
|
+
data.tar.gz: 6cc22dcad22c6c77a9734b818969356e5600eedef854057d06320b05e1692631e4c814106ac8179a83bb39d2bef1e5396a02df95a6f1144046b09b5eaa739b64
|
@@ -15,10 +15,12 @@ module CoalescingPanda
|
|
15
15
|
client_key = lti_account.oauth2_client_key
|
16
16
|
user_id = @oauth_state.data[:user_id]
|
17
17
|
api_domain = @oauth_state.data[:api_domain]
|
18
|
+
prefix = @oauth_state.data[:api_url]
|
18
19
|
@oauth_state.destroy
|
19
|
-
|
20
|
+
|
20
21
|
Rails.logger.info "Creating Bearcat client for auth token retrieval pointed to: #{prefix}"
|
21
22
|
client = Bearcat::Client.new(prefix: prefix)
|
23
|
+
|
22
24
|
token_body = client.retrieve_token(client_id, coalescing_panda.oauth2_redirect_url, client_key, params['code'])
|
23
25
|
auth = CanvasApiAuth.where('user_id = ? and api_domain = ?', user_id, api_domain).first_or_initialize
|
24
26
|
auth.api_token = token_body['access_token']
|
@@ -30,20 +32,10 @@ module CoalescingPanda
|
|
30
32
|
end
|
31
33
|
end
|
32
34
|
|
33
|
-
|
34
35
|
private
|
35
36
|
|
36
|
-
def oauth2_protocol
|
37
|
-
ENV['OAUTH_PROTOCOL'] || (Rails.env.development? ? 'http' : 'https')
|
38
|
-
end
|
39
|
-
|
40
37
|
def retrieve_oauth_state
|
41
38
|
@oauth_state ||= params[:state].present? && OauthState.find_by(state_key: params[:state])
|
42
39
|
end
|
43
|
-
|
44
|
-
def valid_state_token
|
45
|
-
return false unless params['state'].present? && session['state'].present?
|
46
|
-
params['state'] == session['state']
|
47
|
-
end
|
48
40
|
end
|
49
41
|
end
|
@@ -3,7 +3,7 @@ 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'
|
6
|
+
belongs_to :leader, optional: true, foreign_key: :leader_id, class_name: 'CoalescingPanda::User'
|
7
7
|
belongs_to :group_category, foreign_key: :coalescing_panda_group_category_id, class_name: 'CoalescingPanda::GroupCategory'
|
8
8
|
has_many :group_memberships, foreign_key: :coalescing_panda_group_id, class_name: 'CoalescingPanda::GroupMembership', dependent: :destroy
|
9
9
|
validates :group_category_id, presence: true
|
@@ -3,7 +3,9 @@
|
|
3
3
|
%h2 Canvas Authentication Required
|
4
4
|
%button.btn-canvas#oauth_btn Authenticate
|
5
5
|
|
6
|
-
%form{id: 'lti_form', action: "#{request.original_url}", method:
|
6
|
+
%form{id: 'lti_form', action: "#{request.original_url}", method: request.method}
|
7
|
+
- unless @lti_params.include?(:session_token) || @lti_params.include?(:session_key)
|
8
|
+
%input{:type =>"hidden", :value=>link_nonce, :name=>"session_token"}
|
7
9
|
- @lti_params.each do |k,v|
|
8
10
|
%input{:type =>"hidden", :value=>"#{v}", :name=>"#{k}"}
|
9
11
|
|
@@ -15,96 +15,77 @@ module CoalescingPanda
|
|
15
15
|
def current_organization; current_lti_account; end
|
16
16
|
|
17
17
|
def canvas_oauth2(*roles)
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
api_auth = CanvasApiAuth.find_by('user_id = ? and api_domain = ?', user_id, uri.api_domain)
|
27
|
-
if api_auth
|
28
|
-
begin
|
29
|
-
refresh_token(uri, api_auth) if api_auth.expired?
|
30
|
-
@client = Bearcat::Client.new(token: api_auth.api_token, prefix: uri.prefix)
|
31
|
-
@client.user_profile 'self'
|
32
|
-
rescue Footrest::HttpError::BadRequest, Footrest::HttpError::Unauthorized
|
33
|
-
# If we can't retrieve our own user profile, or the token refresh fails, something is awry on the canvas end
|
34
|
-
# and we'll need to go through the oauth flow again
|
35
|
-
render_oauth2_page uri, user_id
|
36
|
-
end
|
37
|
-
else
|
38
|
-
render_oauth2_page uri, user_id
|
39
|
-
end
|
18
|
+
unless valid_session?
|
19
|
+
lti_authorize!(*roles)
|
20
|
+
|
21
|
+
current_session_data['user_id'] = params['user_id']
|
22
|
+
current_session_data['lis_person_sourcedid'] = params['lis_person_sourcedid']
|
23
|
+
current_session_data['oauth_consumer_key'] = params['oauth_consumer_key']
|
24
|
+
current_session_data['custom_canvas_account_id'] = params['custom_canvas_account_id']
|
40
25
|
end
|
26
|
+
|
27
|
+
@lti_account = LtiAccount.find_by_key(current_session_data['oauth_consumer_key']) if current_session_data['oauth_consumer_key']
|
28
|
+
|
29
|
+
require_user_api_client
|
41
30
|
end
|
42
31
|
|
43
|
-
def render_oauth2_page
|
44
|
-
|
45
|
-
|
32
|
+
def render_oauth2_page
|
33
|
+
client_id = current_lti_account.oauth2_client_id
|
34
|
+
client = Bearcat::Client.new(prefix: canvas_api_uri)
|
46
35
|
|
47
|
-
client_id = @lti_account.oauth2_client_id
|
48
|
-
client = Bearcat::Client.new(prefix: uri.prefix)
|
49
36
|
state = SecureRandom.hex(32)
|
50
|
-
OauthState.create! state_key: state, data: {
|
37
|
+
OauthState.create! state_key: state, data: {
|
38
|
+
key: current_session_data.dig(:launch_params, :oauth_consumer_key),
|
39
|
+
user_id: current_session_data.dig(:launch_params, :user_id),
|
40
|
+
api_domain: URI.parse(canvas_api_uri).host,
|
41
|
+
api_url: canvas_api_uri,
|
42
|
+
}
|
43
|
+
|
51
44
|
@canvas_url = client.auth_redirect_url(client_id, resolve_coalescing_panda_url(:oauth2_redirect_url), { state: state })
|
52
45
|
|
53
|
-
#delete the added params so the original oauth sig still works
|
54
46
|
@lti_params = params.to_unsafe_h
|
55
47
|
@lti_params.delete('action')
|
56
48
|
@lti_params.delete('controller')
|
49
|
+
|
57
50
|
render 'coalescing_panda/oauth2/oauth2', layout: 'coalescing_panda/application'
|
58
51
|
end
|
59
52
|
|
60
|
-
def refresh_token(
|
61
|
-
refresh_client = Bearcat::Client.new(prefix:
|
62
|
-
refresh_body = refresh_client.retrieve_token(
|
63
|
-
|
53
|
+
def refresh_token(api_auth)
|
54
|
+
refresh_client = Bearcat::Client.new(prefix: canvas_api_uri)
|
55
|
+
refresh_body = refresh_client.retrieve_token(
|
56
|
+
current_lti_account.oauth2_client_id,
|
57
|
+
resolve_coalescing_panda_url(:oauth2_redirect_url),
|
58
|
+
current_lti_account.oauth2_client_key,
|
59
|
+
api_auth.refresh_token,
|
60
|
+
'refresh_token'
|
61
|
+
)
|
64
62
|
api_auth.update({ api_token: refresh_body['access_token'], expires_at: (Time.now + refresh_body['expires_in']) })
|
65
63
|
end
|
66
64
|
|
67
|
-
def
|
68
|
-
|
69
|
-
|
70
|
-
api_auth = CanvasApiAuth.find_by(user_id: current_session_data['user_id'], api_domain: uri.api_domain)
|
71
|
-
@lti_account = LtiAccount.find_by(key: current_session_data['oauth_consumer_key'])
|
72
|
-
return if @lti_account.nil? || api_auth.nil? # Not all tools use oauth
|
73
|
-
|
74
|
-
refresh_token(uri, api_auth) if api_auth.expired?
|
75
|
-
rescue Footrest::HttpError::BadRequest
|
76
|
-
render_oauth2_page uri, current_session_data['user_id']
|
77
|
-
end
|
78
|
-
|
79
|
-
def set_session(launch_presentation_return_url)
|
80
|
-
current_session_data['user_id'] = params['user_id']
|
81
|
-
current_session_data['uri'] = launch_presentation_return_url
|
82
|
-
current_session_data['lis_person_sourcedid'] = params['lis_person_sourcedid']
|
83
|
-
current_session_data['oauth_consumer_key'] = params['oauth_consumer_key']
|
84
|
-
current_session_data['custom_canvas_account_id'] = params['custom_canvas_account_id']
|
85
|
-
end
|
86
|
-
|
87
|
-
def have_session?
|
88
|
-
if params['tool_consumer_instance_guid'] && current_session_data['user_id'] != params['user_id']
|
89
|
-
reset_session
|
90
|
-
logger.info("resetting session params")
|
91
|
-
current_session_data['user_id'] = params['user_id']
|
65
|
+
def require_user_api_client
|
66
|
+
if user_api_client.nil?
|
67
|
+
render_oauth2_page
|
92
68
|
end
|
69
|
+
end
|
93
70
|
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
71
|
+
def user_api_client
|
72
|
+
@user_api_client ||= begin
|
73
|
+
user_id = current_session_data.dig(:launch_params, :user_id)
|
74
|
+
puri = URI.parse(canvas_api_uri)
|
75
|
+
api_auth = CanvasApiAuth.find_by('user_id = ? and api_domain = ?', user_id, puri.host)
|
76
|
+
if api_auth
|
77
|
+
begin
|
78
|
+
refresh_token(api_auth) if api_auth.expired?
|
79
|
+
client = Bearcat::Client.new(token: api_auth.api_token, prefix: canvas_api_uri)
|
80
|
+
client.user_profile('self')
|
81
|
+
client
|
82
|
+
rescue Footrest::HttpError::BadRequest, Footrest::HttpError::Unauthorized
|
83
|
+
# If we can't retrieve our own user profile, or the token refresh fails, something is awry on the canvas end
|
84
|
+
# and we'll need to go through the oauth flow again
|
85
|
+
nil
|
86
|
+
end
|
100
87
|
end
|
101
88
|
end
|
102
|
-
|
103
|
-
@lti_account = LtiAccount.find_by_key(current_session_data['oauth_consumer_key']) if current_session_data['oauth_consumer_key']
|
104
|
-
|
105
|
-
!!@client
|
106
|
-
rescue Footrest::HttpError::Unauthorized
|
107
|
-
false
|
108
89
|
end
|
109
90
|
|
110
91
|
def validate_launch!
|
@@ -112,23 +93,39 @@ module CoalescingPanda
|
|
112
93
|
end
|
113
94
|
|
114
95
|
def lti_authorize!(*roles)
|
96
|
+
return true if valid_session?
|
97
|
+
|
115
98
|
authorized = false
|
116
99
|
if (@lti_account = params['oauth_consumer_key'] && LtiAccount.find_by_key(params['oauth_consumer_key']))
|
117
100
|
sanitized_params = sanitize_params
|
118
101
|
@tp = IMS::LTI::ToolProvider.new(@lti_account.key, @lti_account.secret, sanitized_params)
|
119
102
|
authorized = @tp.valid_request?(request)
|
120
103
|
end
|
104
|
+
|
121
105
|
logger.info 'not authorized on tp valid request' unless authorized
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
106
|
+
|
107
|
+
if authorized && !(authorized = (roles.count == 0 || (roles & lti_roles).count > 0))
|
108
|
+
logger.info 'not authorized on roles'
|
109
|
+
end
|
110
|
+
|
111
|
+
if authorized && !(authorized = @lti_account.validate_nonce(params['oauth_nonce'], DateTime.strptime(params['oauth_timestamp'], '%s')))
|
112
|
+
logger.info 'not authorized on nonce'
|
113
|
+
end
|
114
|
+
|
126
115
|
render :text => 'Invalid Credentials, please contact your Administrator.', :status => :unauthorized unless authorized
|
116
|
+
|
127
117
|
# create session on first launch
|
128
118
|
current_session
|
129
119
|
authorized
|
130
120
|
end
|
131
121
|
|
122
|
+
def valid_session?
|
123
|
+
return false unless current_session(create_missing: false)&.persisted?
|
124
|
+
true
|
125
|
+
rescue SessionNonceMismatch
|
126
|
+
false
|
127
|
+
end
|
128
|
+
|
132
129
|
# code for method taken from panda_pal v 4.0.8
|
133
130
|
# used for safari workaround
|
134
131
|
def sanitize_params
|
@@ -162,11 +159,27 @@ module CoalescingPanda
|
|
162
159
|
end
|
163
160
|
end
|
164
161
|
|
165
|
-
def
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
162
|
+
def canvas_api_uri
|
163
|
+
@canvas_api_uri ||= begin
|
164
|
+
launch_params = current_session_data[:launch_params] || {}
|
165
|
+
uri = 'canvas.instructure.com'
|
166
|
+
if launch_params[:custom_canvas_api_domain].present?
|
167
|
+
uri = launch_params[:custom_canvas_api_domain]
|
168
|
+
else
|
169
|
+
uri = current_lti_account.settings[:launch_presentation_return_url] || launch_params[:launch_presentation_return_url]
|
170
|
+
unless uri.include?('://')
|
171
|
+
referrer = URI.parse(request.env["HTTP_REFERER"])
|
172
|
+
referrer.path = ''
|
173
|
+
uri = [referrer.to_s, uri].join
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
uri = ((Rails.env.test? or Rails.env.development?) ? 'http' : 'https') + '://' + uri unless uri.include?('://')
|
178
|
+
|
179
|
+
uri = URI.parse(uri)
|
180
|
+
uri.path = ''
|
181
|
+
uri.to_s
|
182
|
+
end
|
170
183
|
end
|
171
184
|
|
172
185
|
private
|
Binary file
|
data/spec/dummy/db/schema.rb
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: UTF-8
|
2
1
|
# This file is auto-generated from the current state of the database. Instead
|
3
2
|
# of editing this file, please use the migrations feature of Active Record to
|
4
3
|
# incrementally modify your database, and then regenerate this schema definition.
|
@@ -11,263 +10,249 @@
|
|
11
10
|
#
|
12
11
|
# It's strongly recommended that you check this file into your version control system.
|
13
12
|
|
14
|
-
ActiveRecord::Schema.define(version:
|
13
|
+
ActiveRecord::Schema.define(version: 2020_05_28_224505) do
|
15
14
|
|
16
15
|
create_table "coalescing_panda_assignment_groups", force: :cascade do |t|
|
17
|
-
t.integer
|
18
|
-
t.
|
19
|
-
t.
|
20
|
-
t.string
|
21
|
-
t.string
|
22
|
-
t.integer
|
23
|
-
t.float
|
24
|
-
t.string
|
16
|
+
t.integer "coalescing_panda_course_id", null: false
|
17
|
+
t.string "context_type"
|
18
|
+
t.integer "context_id"
|
19
|
+
t.string "canvas_assignment_group_id"
|
20
|
+
t.string "name"
|
21
|
+
t.integer "position"
|
22
|
+
t.float "group_weight"
|
23
|
+
t.string "workflow_state"
|
25
24
|
t.datetime "created_at"
|
26
25
|
t.datetime "updated_at"
|
26
|
+
t.index ["canvas_assignment_group_id", "context_id", "context_type"], name: "index_assignment_group_context", unique: true
|
27
|
+
t.index ["coalescing_panda_course_id", "canvas_assignment_group_id"], name: "index_assignment_group_course", unique: true
|
27
28
|
end
|
28
29
|
|
29
|
-
add_index "coalescing_panda_assignment_groups", ["canvas_assignment_group_id", "context_id", "context_type"], name: "index_assignment_group_context", unique: true
|
30
|
-
add_index "coalescing_panda_assignment_groups", ["coalescing_panda_course_id", "canvas_assignment_group_id"], name: "index_assignment_group_course", unique: true
|
31
|
-
|
32
30
|
create_table "coalescing_panda_assignments", force: :cascade do |t|
|
33
|
-
t.integer
|
34
|
-
t.string
|
35
|
-
t.text
|
36
|
-
t.string
|
37
|
-
t.string
|
38
|
-
t.float
|
31
|
+
t.integer "coalescing_panda_course_id", null: false
|
32
|
+
t.string "name"
|
33
|
+
t.text "description"
|
34
|
+
t.string "canvas_assignment_id", null: false
|
35
|
+
t.string "workflow_state"
|
36
|
+
t.float "points_possible"
|
39
37
|
t.datetime "due_at"
|
40
38
|
t.datetime "unlock_at"
|
41
39
|
t.datetime "lock_at"
|
42
40
|
t.datetime "created_at"
|
43
41
|
t.datetime "updated_at"
|
44
|
-
t.text
|
45
|
-
t.integer
|
46
|
-
t.boolean
|
47
|
-
t.boolean
|
48
|
-
t.integer
|
49
|
-
t.integer
|
42
|
+
t.text "submission_types"
|
43
|
+
t.integer "group_category_id"
|
44
|
+
t.boolean "grade_group_students_individually"
|
45
|
+
t.boolean "published"
|
46
|
+
t.integer "coalescing_panda_assignment_group_id"
|
47
|
+
t.integer "coalescing_panda_group_category_id"
|
48
|
+
t.index ["coalescing_panda_course_id", "canvas_assignment_id"], name: "index_assignments_course", unique: true
|
50
49
|
end
|
51
50
|
|
52
|
-
add_index "coalescing_panda_assignments", ["coalescing_panda_course_id", "canvas_assignment_id"], name: "index_assignments_course", unique: true
|
53
|
-
|
54
51
|
create_table "coalescing_panda_canvas_api_auths", force: :cascade do |t|
|
55
|
-
t.string
|
56
|
-
t.string
|
57
|
-
t.string
|
52
|
+
t.string "user_id"
|
53
|
+
t.string "api_domain"
|
54
|
+
t.string "api_token"
|
58
55
|
t.datetime "created_at"
|
59
56
|
t.datetime "updated_at"
|
60
|
-
t.string
|
57
|
+
t.string "refresh_token"
|
61
58
|
t.datetime "expires_at"
|
62
59
|
end
|
63
60
|
|
64
61
|
create_table "coalescing_panda_canvas_batches", force: :cascade do |t|
|
65
|
-
t.float
|
66
|
-
t.string
|
67
|
-
t.text
|
62
|
+
t.float "percent_complete", default: 0.0
|
63
|
+
t.string "status"
|
64
|
+
t.text "message"
|
68
65
|
t.datetime "created_at"
|
69
66
|
t.datetime "updated_at"
|
70
|
-
t.integer
|
71
|
-
t.string
|
72
|
-
t.integer
|
73
|
-
t.text
|
67
|
+
t.integer "context_id"
|
68
|
+
t.string "context_type"
|
69
|
+
t.integer "coalescing_panda_lti_account_id"
|
70
|
+
t.text "options"
|
74
71
|
end
|
75
72
|
|
76
73
|
create_table "coalescing_panda_courses", force: :cascade do |t|
|
77
|
-
t.integer
|
78
|
-
t.integer
|
79
|
-
t.string
|
80
|
-
t.string
|
81
|
-
t.string
|
74
|
+
t.integer "coalescing_panda_lti_account_id", null: false
|
75
|
+
t.integer "coalescing_panda_term_id"
|
76
|
+
t.string "name"
|
77
|
+
t.string "canvas_course_id", null: false
|
78
|
+
t.string "sis_id"
|
82
79
|
t.datetime "start_at"
|
83
80
|
t.datetime "conclude_at"
|
84
|
-
t.string
|
85
|
-
t.string
|
81
|
+
t.string "workflow_state"
|
82
|
+
t.string "course_code"
|
86
83
|
t.datetime "created_at"
|
87
84
|
t.datetime "updated_at"
|
85
|
+
t.index ["coalescing_panda_lti_account_id", "canvas_course_id"], name: "index_courses_account", unique: true
|
86
|
+
t.index ["coalescing_panda_term_id", "canvas_course_id"], name: "index_courses_term", unique: true
|
87
|
+
t.index ["sis_id"], name: "index_coalescing_panda_courses_on_sis_id"
|
88
88
|
end
|
89
89
|
|
90
|
-
add_index "coalescing_panda_courses", ["coalescing_panda_lti_account_id", "canvas_course_id"], name: "index_courses_account", unique: true
|
91
|
-
add_index "coalescing_panda_courses", ["coalescing_panda_term_id", "canvas_course_id"], name: "index_courses_term", unique: true
|
92
|
-
add_index "coalescing_panda_courses", ["sis_id"], name: "index_coalescing_panda_courses_on_sis_id"
|
93
|
-
|
94
90
|
create_table "coalescing_panda_enrollments", force: :cascade do |t|
|
95
|
-
t.integer
|
96
|
-
t.integer
|
97
|
-
t.string
|
98
|
-
t.string
|
99
|
-
t.string
|
100
|
-
t.string
|
91
|
+
t.integer "coalescing_panda_user_id", null: false
|
92
|
+
t.integer "coalescing_panda_section_id", null: false
|
93
|
+
t.string "workflow_state"
|
94
|
+
t.string "sis_id"
|
95
|
+
t.string "canvas_enrollment_id", null: false
|
96
|
+
t.string "enrollment_type"
|
101
97
|
t.datetime "start_at"
|
102
98
|
t.datetime "end_at"
|
103
99
|
t.datetime "created_at"
|
104
100
|
t.datetime "updated_at"
|
101
|
+
t.index ["coalescing_panda_user_id", "coalescing_panda_section_id", "enrollment_type"], name: "index_enrollments_user_and_section", unique: true
|
102
|
+
t.index ["sis_id"], name: "index_coalescing_panda_enrollments_on_sis_id"
|
105
103
|
end
|
106
104
|
|
107
|
-
add_index "coalescing_panda_enrollments", ["coalescing_panda_user_id", "coalescing_panda_section_id", "enrollment_type"], name: "index_enrollments_user_and_section", unique: true
|
108
|
-
add_index "coalescing_panda_enrollments", ["sis_id"], name: "index_coalescing_panda_enrollments_on_sis_id"
|
109
|
-
|
110
105
|
create_table "coalescing_panda_group_categories", force: :cascade do |t|
|
111
|
-
t.
|
112
|
-
t.
|
113
|
-
t.integer
|
114
|
-
t.string
|
106
|
+
t.string "context_type"
|
107
|
+
t.integer "context_id"
|
108
|
+
t.integer "canvas_group_category_id"
|
109
|
+
t.string "name"
|
115
110
|
t.datetime "created_at"
|
116
111
|
t.datetime "updated_at"
|
112
|
+
t.index ["context_id", "context_type"], name: "index_group_categories_context_and_context_type"
|
117
113
|
end
|
118
114
|
|
119
|
-
add_index "coalescing_panda_group_categories", ["context_id", "context_type"], name: "index_group_categories_context_and_context_type"
|
120
|
-
|
121
115
|
create_table "coalescing_panda_group_memberships", force: :cascade do |t|
|
122
|
-
t.integer
|
123
|
-
t.integer
|
124
|
-
t.string
|
125
|
-
t.string
|
116
|
+
t.integer "coalescing_panda_group_id"
|
117
|
+
t.integer "coalescing_panda_user_id"
|
118
|
+
t.string "canvas_group_membership_id"
|
119
|
+
t.string "workflow_state"
|
126
120
|
t.datetime "created_at"
|
127
121
|
t.datetime "updated_at"
|
128
|
-
t.boolean
|
122
|
+
t.boolean "moderator"
|
123
|
+
t.index ["coalescing_panda_group_id", "coalescing_panda_user_id"], name: "index_group_memberships_user_and_group", unique: true
|
129
124
|
end
|
130
125
|
|
131
|
-
add_index "coalescing_panda_group_memberships", ["coalescing_panda_group_id", "coalescing_panda_user_id"], name: "index_group_memberships_user_and_group", unique: true
|
132
|
-
|
133
126
|
create_table "coalescing_panda_groups", force: :cascade do |t|
|
134
|
-
t.
|
135
|
-
t.
|
136
|
-
t.string
|
137
|
-
t.string
|
138
|
-
t.string
|
139
|
-
t.string
|
140
|
-
t.integer
|
127
|
+
t.string "context_type"
|
128
|
+
t.integer "context_id"
|
129
|
+
t.string "description"
|
130
|
+
t.string "group_category_id"
|
131
|
+
t.string "canvas_group_id"
|
132
|
+
t.string "name"
|
133
|
+
t.integer "members_count"
|
141
134
|
t.datetime "created_at"
|
142
135
|
t.datetime "updated_at"
|
143
|
-
t.integer
|
144
|
-
t.integer
|
136
|
+
t.integer "leader_id"
|
137
|
+
t.integer "coalescing_panda_group_category_id"
|
138
|
+
t.index ["context_id", "canvas_group_id"], name: "index_groups_context_and_group_id", unique: true
|
145
139
|
end
|
146
140
|
|
147
|
-
add_index "coalescing_panda_groups", ["context_id", "canvas_group_id"], name: "index_groups_context_and_group_id", unique: true
|
148
|
-
|
149
141
|
create_table "coalescing_panda_lti_accounts", force: :cascade do |t|
|
150
|
-
t.string
|
151
|
-
t.string
|
152
|
-
t.string
|
153
|
-
t.string
|
154
|
-
t.string
|
155
|
-
t.string
|
156
|
-
t.text
|
142
|
+
t.string "name"
|
143
|
+
t.string "key"
|
144
|
+
t.string "secret"
|
145
|
+
t.string "oauth2_client_id"
|
146
|
+
t.string "oauth2_client_key"
|
147
|
+
t.string "canvas_account_id"
|
148
|
+
t.text "settings"
|
157
149
|
t.datetime "created_at"
|
158
150
|
t.datetime "updated_at"
|
159
151
|
end
|
160
152
|
|
161
153
|
create_table "coalescing_panda_lti_nonces", force: :cascade do |t|
|
162
|
-
t.integer
|
163
|
-
t.string
|
154
|
+
t.integer "coalescing_panda_lti_account_id"
|
155
|
+
t.string "nonce"
|
164
156
|
t.datetime "timestamp"
|
165
157
|
end
|
166
158
|
|
167
159
|
create_table "coalescing_panda_oauth_states", force: :cascade do |t|
|
168
|
-
t.string
|
169
|
-
t.text
|
160
|
+
t.string "state_key"
|
161
|
+
t.text "data"
|
170
162
|
t.datetime "created_at"
|
171
163
|
t.datetime "updated_at"
|
164
|
+
t.index ["state_key"], name: "index_coalescing_panda_oauth_states_on_state_key", unique: true
|
172
165
|
end
|
173
166
|
|
174
|
-
add_index "coalescing_panda_oauth_states", ["state_key"], name: "index_coalescing_panda_oauth_states_on_state_key", unique: true
|
175
|
-
|
176
167
|
create_table "coalescing_panda_persistent_sessions", force: :cascade do |t|
|
177
|
-
t.string
|
178
|
-
t.text
|
179
|
-
t.integer
|
180
|
-
t.datetime "created_at",
|
181
|
-
t.datetime "updated_at",
|
168
|
+
t.string "session_key"
|
169
|
+
t.text "data"
|
170
|
+
t.integer "coalescing_panda_lti_account_id"
|
171
|
+
t.datetime "created_at", null: false
|
172
|
+
t.datetime "updated_at", null: false
|
173
|
+
t.index ["coalescing_panda_lti_account_id"], name: "index_persistent_session_on_lti_account_id"
|
174
|
+
t.index ["session_key"], name: "index_coalescing_panda_persistent_sessions_on_session_key", unique: true
|
182
175
|
end
|
183
176
|
|
184
|
-
add_index "coalescing_panda_persistent_sessions", ["coalescing_panda_lti_account_id"], name: "index_persistent_session_on_lti_account_id", using: :btree
|
185
|
-
add_index "coalescing_panda_persistent_sessions", ["session_key"], name: "index_coalescing_panda_persistent_sessions_on_session_key", unique: true, using: :btree
|
186
|
-
|
187
177
|
create_table "coalescing_panda_sections", force: :cascade do |t|
|
188
|
-
t.integer
|
189
|
-
t.string
|
190
|
-
t.string
|
191
|
-
t.string
|
192
|
-
t.string
|
178
|
+
t.integer "coalescing_panda_course_id", null: false
|
179
|
+
t.string "name"
|
180
|
+
t.string "canvas_section_id", null: false
|
181
|
+
t.string "sis_id"
|
182
|
+
t.string "workflow_state"
|
193
183
|
t.datetime "start_at"
|
194
184
|
t.datetime "end_at"
|
195
185
|
t.datetime "created_at"
|
196
186
|
t.datetime "updated_at"
|
187
|
+
t.index ["coalescing_panda_course_id", "canvas_section_id"], name: "index_sections_course", unique: true
|
188
|
+
t.index ["sis_id"], name: "index_coalescing_panda_sections_on_sis_id"
|
197
189
|
end
|
198
190
|
|
199
|
-
add_index "coalescing_panda_sections", ["coalescing_panda_course_id", "canvas_section_id"], name: "index_sections_course", unique: true
|
200
|
-
add_index "coalescing_panda_sections", ["sis_id"], name: "index_coalescing_panda_sections_on_sis_id"
|
201
|
-
|
202
191
|
create_table "coalescing_panda_sessions", force: :cascade do |t|
|
203
|
-
t.string
|
204
|
-
t.text
|
192
|
+
t.string "token"
|
193
|
+
t.text "data"
|
205
194
|
t.datetime "created_at"
|
206
195
|
t.datetime "updated_at"
|
207
196
|
end
|
208
197
|
|
209
198
|
create_table "coalescing_panda_submissions", force: :cascade do |t|
|
210
|
-
t.integer
|
211
|
-
t.integer
|
212
|
-
t.string
|
213
|
-
t.string
|
214
|
-
t.string
|
199
|
+
t.integer "coalescing_panda_user_id", null: false
|
200
|
+
t.integer "coalescing_panda_assignment_id", null: false
|
201
|
+
t.string "url"
|
202
|
+
t.string "grade"
|
203
|
+
t.string "score"
|
215
204
|
t.datetime "submitted_at"
|
216
|
-
t.string
|
217
|
-
t.string
|
205
|
+
t.string "workflow_state"
|
206
|
+
t.string "canvas_submission_id", null: false
|
218
207
|
t.datetime "created_at"
|
219
208
|
t.datetime "updated_at"
|
209
|
+
t.index ["canvas_submission_id"], name: "index_coalescing_panda_submissions_on_canvas_submission_id"
|
210
|
+
t.index ["coalescing_panda_user_id", "coalescing_panda_assignment_id", "canvas_submission_id"], name: "index_submissions_user_and_assignment", unique: true
|
220
211
|
end
|
221
212
|
|
222
|
-
add_index "coalescing_panda_submissions", ["canvas_submission_id"], name: "index_coalescing_panda_submissions_on_canvas_submission_id"
|
223
|
-
add_index "coalescing_panda_submissions", ["coalescing_panda_user_id", "coalescing_panda_assignment_id", "canvas_submission_id"], name: "index_submissions_user_and_assignment", unique: true
|
224
|
-
|
225
213
|
create_table "coalescing_panda_terms", force: :cascade do |t|
|
226
|
-
t.integer
|
227
|
-
t.string
|
228
|
-
t.string
|
229
|
-
t.string
|
230
|
-
t.string
|
214
|
+
t.integer "coalescing_panda_lti_account_id", null: false
|
215
|
+
t.string "name"
|
216
|
+
t.string "code"
|
217
|
+
t.string "sis_id"
|
218
|
+
t.string "canvas_term_id", null: false
|
231
219
|
t.datetime "start_at"
|
232
220
|
t.datetime "end_at"
|
233
|
-
t.string
|
221
|
+
t.string "workflow_state"
|
234
222
|
t.datetime "created_at"
|
235
223
|
t.datetime "updated_at"
|
224
|
+
t.index ["canvas_term_id", "coalescing_panda_lti_account_id"], name: "index_terms_account", unique: true
|
225
|
+
t.index ["sis_id"], name: "index_coalescing_panda_terms_on_sis_id"
|
236
226
|
end
|
237
227
|
|
238
|
-
add_index "coalescing_panda_terms", ["canvas_term_id", "coalescing_panda_lti_account_id"], name: "index_terms_account", unique: true
|
239
|
-
add_index "coalescing_panda_terms", ["sis_id"], name: "index_coalescing_panda_terms_on_sis_id"
|
240
|
-
|
241
228
|
create_table "coalescing_panda_users", force: :cascade do |t|
|
242
|
-
t.integer
|
243
|
-
t.string
|
244
|
-
t.string
|
245
|
-
t.string
|
246
|
-
t.string
|
247
|
-
t.string
|
248
|
-
t.string
|
229
|
+
t.integer "coalescing_panda_lti_account_id", null: false
|
230
|
+
t.string "name"
|
231
|
+
t.string "email"
|
232
|
+
t.string "roles"
|
233
|
+
t.string "workflow_state"
|
234
|
+
t.string "sis_id"
|
235
|
+
t.string "canvas_user_id", null: false
|
249
236
|
t.datetime "created_at"
|
250
237
|
t.datetime "updated_at"
|
251
|
-
t.string
|
238
|
+
t.string "login_id"
|
239
|
+
t.index ["coalescing_panda_lti_account_id", "canvas_user_id"], name: "index_users_account", unique: true
|
240
|
+
t.index ["sis_id"], name: "index_coalescing_panda_users_on_sis_id"
|
252
241
|
end
|
253
242
|
|
254
|
-
add_index "coalescing_panda_users", ["coalescing_panda_lti_account_id", "canvas_user_id"], name: "index_users_account", unique: true
|
255
|
-
add_index "coalescing_panda_users", ["sis_id"], name: "index_coalescing_panda_users_on_sis_id"
|
256
|
-
|
257
243
|
create_table "delayed_jobs", force: :cascade do |t|
|
258
|
-
t.integer
|
259
|
-
t.integer
|
260
|
-
t.text
|
261
|
-
t.text
|
244
|
+
t.integer "priority", default: 0, null: false
|
245
|
+
t.integer "attempts", default: 0, null: false
|
246
|
+
t.text "handler", null: false
|
247
|
+
t.text "last_error"
|
262
248
|
t.datetime "run_at"
|
263
249
|
t.datetime "locked_at"
|
264
250
|
t.datetime "failed_at"
|
265
|
-
t.string
|
266
|
-
t.string
|
251
|
+
t.string "locked_by"
|
252
|
+
t.string "queue"
|
267
253
|
t.datetime "created_at"
|
268
254
|
t.datetime "updated_at"
|
255
|
+
t.index ["priority", "run_at"], name: "delayed_jobs_priority"
|
269
256
|
end
|
270
257
|
|
271
|
-
add_index "delayed_jobs", ["priority", "run_at"], name: "delayed_jobs_priority"
|
272
|
-
|
273
258
|
end
|
Binary file
|
metadata
CHANGED
@@ -1,16 +1,16 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: coalescing_panda
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.2.0.beta1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Mills
|
8
8
|
- Cody Tanner
|
9
9
|
- Jake Sorce
|
10
|
-
autorequire:
|
10
|
+
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2021-
|
13
|
+
date: 2021-11-15 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: rails
|
@@ -410,7 +410,7 @@ dependencies:
|
|
410
410
|
- - ">="
|
411
411
|
- !ruby/object:Gem::Version
|
412
412
|
version: '0'
|
413
|
-
description:
|
413
|
+
description:
|
414
414
|
email:
|
415
415
|
- nathanm@instructure.com
|
416
416
|
- ctanner@instructure.com
|
@@ -540,7 +540,9 @@ files:
|
|
540
540
|
- spec/dummy/config/initializers/wrap_parameters.rb
|
541
541
|
- spec/dummy/config/locales/en.yml
|
542
542
|
- spec/dummy/config/routes.rb
|
543
|
+
- spec/dummy/db/development.sqlite3
|
543
544
|
- spec/dummy/db/schema.rb
|
545
|
+
- spec/dummy/db/test.sqlite3
|
544
546
|
- spec/dummy/public/404.html
|
545
547
|
- spec/dummy/public/422.html
|
546
548
|
- spec/dummy/public/500.html
|
@@ -577,7 +579,7 @@ files:
|
|
577
579
|
homepage: http://www.instructure.com
|
578
580
|
licenses: []
|
579
581
|
metadata: {}
|
580
|
-
post_install_message:
|
582
|
+
post_install_message:
|
581
583
|
rdoc_options: []
|
582
584
|
require_paths:
|
583
585
|
- lib
|
@@ -588,80 +590,81 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
588
590
|
version: '0'
|
589
591
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
590
592
|
requirements:
|
591
|
-
- - "
|
593
|
+
- - ">"
|
592
594
|
- !ruby/object:Gem::Version
|
593
|
-
version:
|
595
|
+
version: 1.3.1
|
594
596
|
requirements: []
|
595
|
-
|
596
|
-
|
597
|
-
signing_key:
|
597
|
+
rubygems_version: 3.0.3
|
598
|
+
signing_key:
|
598
599
|
specification_version: 4
|
599
600
|
summary: Canvas LTI and OAUTH2 mountable engine
|
600
601
|
test_files:
|
602
|
+
- spec/rails_helper.rb
|
603
|
+
- spec/models/coalescing_panda/canvas_api_auth_spec.rb
|
604
|
+
- spec/models/coalescing_panda/assignment_spec.rb
|
605
|
+
- spec/models/coalescing_panda/group_membership_spec.rb
|
606
|
+
- spec/models/coalescing_panda/lti_account_spec.rb
|
607
|
+
- spec/models/coalescing_panda/section_spec.rb
|
608
|
+
- spec/models/coalescing_panda/workers/course_miner_spec.rb
|
609
|
+
- spec/models/coalescing_panda/workers/account_miner_spec.rb
|
610
|
+
- spec/models/coalescing_panda/group_spec.rb
|
611
|
+
- spec/models/coalescing_panda/lti_nonce_spec.rb
|
612
|
+
- spec/models/coalescing_panda/submission_spec.rb
|
613
|
+
- spec/models/coalescing_panda/term_spec.rb
|
614
|
+
- spec/models/coalescing_panda/canvas_batch_spec.rb
|
615
|
+
- spec/models/coalescing_panda/enrollment_spec.rb
|
616
|
+
- spec/models/coalescing_panda/course_spec.rb
|
617
|
+
- spec/models/coalescing_panda/user_spec.rb
|
618
|
+
- spec/models/coalescing_panda/assignment_group_spec.rb
|
619
|
+
- spec/controllers/coalescing_panda/oauth2_controller_spec.rb
|
620
|
+
- spec/controllers/coalescing_panda/lti_controller_spec.rb
|
621
|
+
- spec/controllers/coalescing_panda/canvas_batches_controller_spec.rb
|
601
622
|
- spec/spec_helper.rb
|
623
|
+
- spec/dummy/db/schema.rb
|
624
|
+
- spec/dummy/db/test.sqlite3
|
625
|
+
- spec/dummy/db/development.sqlite3
|
626
|
+
- spec/dummy/public/422.html
|
627
|
+
- spec/dummy/public/favicon.ico
|
628
|
+
- spec/dummy/public/404.html
|
629
|
+
- spec/dummy/public/500.html
|
630
|
+
- spec/dummy/Rakefile
|
631
|
+
- spec/dummy/app/views/layouts/application.html.erb
|
602
632
|
- spec/dummy/app/models/account.rb
|
603
633
|
- spec/dummy/app/models/course.rb
|
604
634
|
- spec/dummy/app/controllers/application_controller.rb
|
605
|
-
- spec/dummy/app/views/layouts/application.html.erb
|
606
|
-
- spec/dummy/app/assets/javascripts/application.js
|
607
|
-
- spec/dummy/app/assets/stylesheets/application.css
|
608
635
|
- spec/dummy/app/helpers/application_helper.rb
|
609
|
-
- spec/dummy/
|
610
|
-
- spec/dummy/
|
611
|
-
- spec/dummy/bin/rails
|
612
|
-
- spec/dummy/config/routes.rb
|
613
|
-
- spec/dummy/config/locales/en.yml
|
614
|
-
- spec/dummy/config/environments/production.rb
|
615
|
-
- spec/dummy/config/environments/development.rb
|
616
|
-
- spec/dummy/config/environments/test.rb
|
617
|
-
- spec/dummy/config/environment.rb
|
636
|
+
- spec/dummy/app/assets/stylesheets/application.css
|
637
|
+
- spec/dummy/app/assets/javascripts/application.js
|
618
638
|
- spec/dummy/config/application.rb
|
619
|
-
- spec/dummy/config/database.yml
|
620
|
-
- spec/dummy/config/boot.rb
|
621
639
|
- spec/dummy/config/initializers/lti_initializer.rb
|
622
|
-
- spec/dummy/config/initializers/backtrace_silencers.rb
|
623
|
-
- spec/dummy/config/initializers/mime_types.rb
|
624
|
-
- spec/dummy/config/initializers/filter_parameter_logging.rb
|
625
640
|
- spec/dummy/config/initializers/session_store.rb
|
626
|
-
- spec/dummy/config/initializers/wrap_parameters.rb
|
627
641
|
- spec/dummy/config/initializers/secret_token.rb
|
642
|
+
- spec/dummy/config/initializers/wrap_parameters.rb
|
628
643
|
- spec/dummy/config/initializers/inflections.rb
|
629
|
-
- spec/dummy/config.
|
630
|
-
- spec/dummy/
|
631
|
-
- spec/dummy/
|
632
|
-
- spec/dummy/
|
633
|
-
- spec/dummy/
|
634
|
-
- spec/dummy/
|
635
|
-
- spec/dummy/
|
644
|
+
- spec/dummy/config/initializers/filter_parameter_logging.rb
|
645
|
+
- spec/dummy/config/initializers/mime_types.rb
|
646
|
+
- spec/dummy/config/initializers/backtrace_silencers.rb
|
647
|
+
- spec/dummy/config/environments/development.rb
|
648
|
+
- spec/dummy/config/environments/test.rb
|
649
|
+
- spec/dummy/config/environments/production.rb
|
650
|
+
- spec/dummy/config/database.yml
|
651
|
+
- spec/dummy/config/boot.rb
|
652
|
+
- spec/dummy/config/routes.rb
|
653
|
+
- spec/dummy/config/environment.rb
|
654
|
+
- spec/dummy/config/locales/en.yml
|
636
655
|
- spec/dummy/README.rdoc
|
637
|
-
- spec/
|
638
|
-
- spec/
|
639
|
-
- spec/
|
640
|
-
- spec/
|
641
|
-
- spec/
|
642
|
-
- spec/models/coalescing_panda/term_spec.rb
|
643
|
-
- spec/models/coalescing_panda/assignment_spec.rb
|
644
|
-
- spec/models/coalescing_panda/submission_spec.rb
|
645
|
-
- spec/models/coalescing_panda/assignment_group_spec.rb
|
646
|
-
- spec/models/coalescing_panda/group_spec.rb
|
647
|
-
- spec/models/coalescing_panda/workers/account_miner_spec.rb
|
648
|
-
- spec/models/coalescing_panda/workers/course_miner_spec.rb
|
649
|
-
- spec/models/coalescing_panda/canvas_api_auth_spec.rb
|
650
|
-
- spec/models/coalescing_panda/group_membership_spec.rb
|
651
|
-
- spec/models/coalescing_panda/user_spec.rb
|
652
|
-
- spec/models/coalescing_panda/course_spec.rb
|
653
|
-
- spec/factories/courses.rb
|
654
|
-
- spec/factories/submissions.rb
|
655
|
-
- spec/factories/assignment_groups.rb
|
656
|
-
- spec/factories/assignments.rb
|
657
|
-
- spec/factories/canvas_api_auths.rb
|
656
|
+
- spec/dummy/config.ru
|
657
|
+
- spec/dummy/bin/bundle
|
658
|
+
- spec/dummy/bin/rake
|
659
|
+
- spec/dummy/bin/rails
|
660
|
+
- spec/factories/accounts.rb
|
658
661
|
- spec/factories/enrollments.rb
|
659
|
-
- spec/factories/
|
662
|
+
- spec/factories/terms.rb
|
660
663
|
- spec/factories/sections.rb
|
661
|
-
- spec/factories/
|
664
|
+
- spec/factories/canvas_batches.rb
|
665
|
+
- spec/factories/assignment_groups.rb
|
666
|
+
- spec/factories/submissions.rb
|
667
|
+
- spec/factories/courses.rb
|
668
|
+
- spec/factories/assignments.rb
|
662
669
|
- spec/factories/users.rb
|
663
|
-
- spec/factories/
|
664
|
-
- spec/controllers/coalescing_panda/canvas_batches_controller_spec.rb
|
665
|
-
- spec/controllers/coalescing_panda/oauth2_controller_spec.rb
|
666
|
-
- spec/controllers/coalescing_panda/lti_controller_spec.rb
|
667
|
-
- spec/rails_helper.rb
|
670
|
+
- spec/factories/canvas_api_auths.rb
|