coalescing_panda 5.1.13 → 5.2.0.beta1
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.
- 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
|