panda_pal 5.8.4 → 5.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +28 -1
- data/app/controllers/panda_pal/lti_v1_p3_controller.rb +0 -6
- data/app/models/panda_pal/organization.rb +1 -0
- data/app/models/panda_pal/organization_concerns/organization_builder.rb +163 -0
- data/app/models/panda_pal/organization_concerns/settings_validation.rb +69 -1
- data/app/models/panda_pal/platform/canvas.rb +7 -2
- data/lib/panda_pal/helpers/console_helpers.rb +129 -0
- data/lib/panda_pal/helpers/route_helper.rb +2 -0
- data/lib/panda_pal/version.rb +1 -1
- data/lib/tasks/panda_pal_tasks.rake +37 -0
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3cef6069ef4d4c36af2ff4d665e9ae08d712198ea8422b1f60353e117753aec
|
4
|
+
data.tar.gz: 4cce12d864ebbab515d5f496dc2371550dd986b920f9fbb6763b9c77db527e95
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0102ced164298cd5c56d9bd62bfbad019301fbc78d150eca69c0b90c142c038febe13a04c7d801a3d357a91cef3533110af26f537fba61725a0033bf5a42b9bd
|
7
|
+
data.tar.gz: d188c8bfcbe5cfc73b3d5570c8a5252c0589f4443e3dd364e182f7252a09495c5888d87b515e00e5cd6907f392dda15e10ef14e346c5f7507cefedeff1812bfc
|
data/README.md
CHANGED
@@ -275,11 +275,38 @@ and a custom implementation can be supplemented.
|
|
275
275
|
|
276
276
|
### Session cleanup
|
277
277
|
Over time, the sessions table will become bloated with sessions that are no longer active.
|
278
|
-
|
278
|
+
If `sidekiq-scheduler` and `TaskScheduling` are enabled, cleanup will be performed automatically. Otherwise you should schedule, `rake panda_pal:clean_sessions` to run periodically (recommend weekly).
|
279
279
|
|
280
280
|
## Organizations and `current_organization`
|
281
281
|
Similar to `current_session`, `current_organization` can be returned with a number of methods, shown below
|
282
282
|
|
283
|
+
## Rake Tasks
|
284
|
+
|
285
|
+
### `panda_pal:org:new`
|
286
|
+
Opens `$EDITOR` and creates a new `Organization`. The opened editor is prefilled with all of the available Settings with optional settings pre-commented.
|
287
|
+
|
288
|
+
### `panda_pal:org:dev`
|
289
|
+
Similar to `panda_pal:org:new`, but is somewhat preconfigured for development environments.
|
290
|
+
|
291
|
+
You can create a `~/pandapalrc.yml` file to specify additional defaults:
|
292
|
+
```yml
|
293
|
+
lti_host: http://localhost:5000
|
294
|
+
settings:
|
295
|
+
canvas:
|
296
|
+
base_url: http://localhost:3000
|
297
|
+
api_token: Uo5yckRQuPl96qVxgt2IVxDAa5oSUo1dqbb2dBVOnpId18aTmjSXdYkn4BN9JF2k
|
298
|
+
```
|
299
|
+
NB: `settings` entries present in `~/pandapalrc.yml` that are not defined in the `settings_structure` will be ignored.
|
300
|
+
|
301
|
+
### `panda_pal:org:edit[name]`
|
302
|
+
Similar to `panda_pal:org:new` but for editing an existing Organization.
|
303
|
+
|
304
|
+
### `panda_pal:org:install[orgname, http://url.of.lti]`
|
305
|
+
Install the LTI into Canvas. Must specify the Organization and the host of the LTI
|
306
|
+
|
307
|
+
### `panda_pal:org:reinstall[orgname, http://url.of.lti]`
|
308
|
+
Same as `panda_pal:org:install`, but first deletes an existing installation
|
309
|
+
|
283
310
|
## Security
|
284
311
|
|
285
312
|
### Tool Launches
|
@@ -49,12 +49,6 @@ module PandaPal
|
|
49
49
|
|
50
50
|
redirect_with_session_to(:"#{LaunchUrlHelpers.launch_route(ltype)}_url", route_context: main_app)
|
51
51
|
end
|
52
|
-
# render json: {
|
53
|
-
# launch_type: params[:launch_type],
|
54
|
-
# final_url: LaunchUrlHelpers.launch_url(params[:launch_type]),
|
55
|
-
# final_route: LaunchUrlHelpers.launch_route(params[:launch_type]),
|
56
|
-
# decoded_jwt: @decoded_lti_jwt,
|
57
|
-
# }
|
58
52
|
end
|
59
53
|
|
60
54
|
def tool_config
|
@@ -38,6 +38,7 @@ module PandaPal
|
|
38
38
|
include SkipSymmetricEncAttrEncrypted if defined?(SkipSymmetricEncAttrEncrypted)
|
39
39
|
|
40
40
|
include OrganizationConcerns::SettingsValidation
|
41
|
+
include OrganizationConcerns::OrganizationBuilder if $stdin&.tty?
|
41
42
|
include OrganizationConcerns::TaskScheduling if defined?(Sidekiq.schedule)
|
42
43
|
|
43
44
|
attr_encrypted :settings, marshal: true, key: :encryption_key, marshaler: SettingsMarshaler
|
@@ -0,0 +1,163 @@
|
|
1
|
+
module PandaPal
|
2
|
+
module OrganizationConcerns
|
3
|
+
module OrganizationBuilder
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
include OrganizationConcerns::SettingsValidation
|
6
|
+
|
7
|
+
class InteractiveSessionError < StandardError
|
8
|
+
attr_reader :source_code
|
9
|
+
|
10
|
+
def initialize(message, source_code)
|
11
|
+
super(message)
|
12
|
+
@source_code = source_code
|
13
|
+
end
|
14
|
+
|
15
|
+
def print
|
16
|
+
puts cause&.message, cause&.backtrace
|
17
|
+
puts ""
|
18
|
+
puts message
|
19
|
+
puts "Code is below for tweaking and/or using it in a Rails console"
|
20
|
+
puts ""
|
21
|
+
puts source_code
|
22
|
+
puts ""
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class_methods do
|
27
|
+
def _interactive_save!(org)
|
28
|
+
code = org.generate_orgbuilder_ruby
|
29
|
+
|
30
|
+
tries = 0
|
31
|
+
result = nil
|
32
|
+
|
33
|
+
loop do
|
34
|
+
begin
|
35
|
+
code = ConsoleHelpers.open_string_editor(code, name: "organization.rb", require_save: tries == 0)
|
36
|
+
rescue => ex
|
37
|
+
raise InteractiveSessionError.new("Failed to open interactive editor", code)
|
38
|
+
end
|
39
|
+
|
40
|
+
if code == :aborted
|
41
|
+
puts "Aborted"
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
begin
|
46
|
+
result = eval(code, TOPLEVEL_BINDING)
|
47
|
+
break
|
48
|
+
rescue => ex
|
49
|
+
puts "Failed to save Organization: #{ex}"
|
50
|
+
if !ConsoleHelpers.prompt_yes_no("Retry?")
|
51
|
+
raise InteractiveSessionError.new("Failed to save Organization", code)
|
52
|
+
end
|
53
|
+
tries += 1
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
result
|
58
|
+
end
|
59
|
+
|
60
|
+
def interactive_create!(org = PandaPal::Organization.new)
|
61
|
+
result = _interactive_save!(org)
|
62
|
+
|
63
|
+
if result&.persisted? && ConsoleHelpers.prompt_yes_no("Organization created. Install in Canvas?", default: false)
|
64
|
+
result.interactive_install!
|
65
|
+
end
|
66
|
+
|
67
|
+
result
|
68
|
+
end
|
69
|
+
|
70
|
+
if Rails.env.development?
|
71
|
+
def development_create!
|
72
|
+
if PandaPal::Organization.count > 0
|
73
|
+
return unless ConsoleHelpers.prompt_yes_no("An Organization is already set up. Continue?")
|
74
|
+
end
|
75
|
+
|
76
|
+
org = PandaPal::Organization.new(
|
77
|
+
name: "local",
|
78
|
+
canvas_account_id: "1",
|
79
|
+
key: "#{_panda_pal_console_app_name}-local",
|
80
|
+
secret: "#{_panda_pal_console_app_name}-local",
|
81
|
+
salesforce_id: "1",
|
82
|
+
)
|
83
|
+
|
84
|
+
rcsettings = ConsoleHelpers.pandapalrc["settings"] || {}
|
85
|
+
cleaned_settings = PandaPal::Organization.remove_undeclared_settings(rcsettings)
|
86
|
+
org.settings = cleaned_settings
|
87
|
+
|
88
|
+
result = interactive_create!(org)
|
89
|
+
|
90
|
+
return unless result
|
91
|
+
|
92
|
+
puts "Created Development Organization: #{result.name}"
|
93
|
+
|
94
|
+
result.switch_tenant
|
95
|
+
end
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def interactive_update!
|
100
|
+
saved = self.class._interactive_save!(self)
|
101
|
+
puts "Organization Updated" if saved
|
102
|
+
saved
|
103
|
+
end
|
104
|
+
|
105
|
+
def interactive_install!(host: nil, exists: :error)
|
106
|
+
first = true
|
107
|
+
loop do
|
108
|
+
# If a host is explicitly passed, don't prompt for it on the first try
|
109
|
+
unless first && host.present?
|
110
|
+
if Rails.env.development?
|
111
|
+
host ||= ConsoleHelpers.pandapalrc["lti_host"].presence || "http://localhost:5000"
|
112
|
+
end
|
113
|
+
host = ConsoleHelpers.prompt("Specify LTI host:", default: host)
|
114
|
+
end
|
115
|
+
|
116
|
+
begin
|
117
|
+
install_lti(host: host, exists: exists)
|
118
|
+
break
|
119
|
+
rescue => ex
|
120
|
+
puts "Failed to install in Canvas: #{ex}"
|
121
|
+
raise ex unless ConsoleHelpers.prompt_pry_retry
|
122
|
+
first = false
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
def generate_orgbuilder_ruby
|
128
|
+
code = ConsoleHelpers::CodeBuilder.new
|
129
|
+
|
130
|
+
columns = %w[
|
131
|
+
canvas_account_id
|
132
|
+
key
|
133
|
+
secret
|
134
|
+
salesforce_id
|
135
|
+
]
|
136
|
+
|
137
|
+
if self.persisted?
|
138
|
+
code << "PandaPal::Organization.find_by(name: \"#{self.name}\").update!("
|
139
|
+
else
|
140
|
+
code << "PandaPal::Organization.create!("
|
141
|
+
columns.unshift("name")
|
142
|
+
end
|
143
|
+
|
144
|
+
code << "\n"
|
145
|
+
|
146
|
+
code.block do
|
147
|
+
columns.each do |col|
|
148
|
+
code << "#{col}: \"#{self.send(col)}\","
|
149
|
+
code << "\n"
|
150
|
+
end
|
151
|
+
|
152
|
+
code << "settings: "
|
153
|
+
code << PandaPal::Organization.generate_settings_ruby(value: settings)
|
154
|
+
code << ",\n"
|
155
|
+
end
|
156
|
+
|
157
|
+
code << ")"
|
158
|
+
|
159
|
+
code.to_s
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
@@ -65,8 +65,76 @@ module PandaPal
|
|
65
65
|
nstruc[:required] = struc.delete(:is_required) if struc.key?(:is_required)
|
66
66
|
nstruc[:properties] = struc.map { |k, sub| [k, normalize_settings_structure(sub)] }.to_h if struc.present?
|
67
67
|
|
68
|
+
nstruc[:type] = "Hash" if !nstruc[:type] && nstruc.key?(:properties)
|
69
|
+
|
68
70
|
nstruc
|
69
71
|
end
|
72
|
+
|
73
|
+
def remove_undeclared_settings(value, setting: settings_structure)
|
74
|
+
if setting[:type] == "Hash"
|
75
|
+
value.dup.tap do |value|
|
76
|
+
value.keys.each do |key|
|
77
|
+
if setting[:properties].key?(key.to_sym)
|
78
|
+
value[key] = remove_undeclared_settings(value[key], setting: setting[:properties][key.to_sym])
|
79
|
+
elsif !setting[:allow_additional]
|
80
|
+
value.delete(key)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
else
|
85
|
+
value
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def generate_settings_ruby(indent: 0, setting: settings_structure, value: { }, exclude_extra: false)
|
90
|
+
builder = ConsoleHelpers::CodeBuilder.new(indent: indent)
|
91
|
+
|
92
|
+
value = setting[:default] || setting.dig(:json_schema, :default) if value == :not_given
|
93
|
+
|
94
|
+
if setting[:type] == "Hash"
|
95
|
+
builder << "{"
|
96
|
+
builder << "\n"
|
97
|
+
builder.indent!
|
98
|
+
setting[:properties].each do |key, sub|
|
99
|
+
if sub[:description]
|
100
|
+
builder << sub[:description].lines.map{|l| "# #{l}"}
|
101
|
+
builder.ensure_line
|
102
|
+
end
|
103
|
+
|
104
|
+
sub_val = value&.key?(key) ? value[key] : :not_given
|
105
|
+
commented = sub_val == :not_given && !sub[:required]
|
106
|
+
|
107
|
+
builder.indent!("# ") if commented
|
108
|
+
builder << "#{key}: "
|
109
|
+
builder << generate_settings_ruby(setting: sub, value: sub_val)
|
110
|
+
builder << ",\n"
|
111
|
+
builder.dedent! if commented
|
112
|
+
end
|
113
|
+
|
114
|
+
# If we're editing an existing org, we may have extra keys that aren't in the schema
|
115
|
+
# But if we're creating a new org, we don't want to include undocumented entries from pandapalrc.yml
|
116
|
+
unless exclude_extra
|
117
|
+
extra_keys = (value&.keys || []) - setting[:properties].keys.map(&:to_s)
|
118
|
+
extra_keys.each do |key|
|
119
|
+
builder << "# Undocumented\n" unless setting[:allow_additional]
|
120
|
+
builder << "#{key}: #{value[key].inspect},\n"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
builder.dedent!
|
125
|
+
builder << "}"
|
126
|
+
elsif setting[:type] == "Array"
|
127
|
+
builder << "#{value&.inspect || '[]'}"
|
128
|
+
elsif setting[:type] == "Integer"
|
129
|
+
builder << "#{value || 0}"
|
130
|
+
elsif setting[:type] == "Numeric"
|
131
|
+
builder << "#{value || 1.0}"
|
132
|
+
else setting[:type] == "String"
|
133
|
+
builder << "\"#{value}\""
|
134
|
+
end
|
135
|
+
|
136
|
+
builder.to_s
|
137
|
+
end
|
70
138
|
end
|
71
139
|
|
72
140
|
def settings_structure
|
@@ -75,7 +143,7 @@ module PandaPal
|
|
75
143
|
|
76
144
|
def validate_settings
|
77
145
|
validate_settings_level(settings || {}, settings_structure).each do |err|
|
78
|
-
errors
|
146
|
+
errors.add(:settings, err)
|
79
147
|
end
|
80
148
|
end
|
81
149
|
|
@@ -74,7 +74,7 @@ module PandaPal
|
|
74
74
|
[ctype, cid]
|
75
75
|
end
|
76
76
|
|
77
|
-
def
|
77
|
+
def _install_lti(host: nil, context: :root_account, version: nil, exists: :error, dedicated_deployment: false)
|
78
78
|
raise "Automatically installing this LTI requires Bearcat." unless defined?(Bearcat)
|
79
79
|
|
80
80
|
version = version || PandaPal.lti_options[:lti_spec_version] || 'v1p0'
|
@@ -138,6 +138,12 @@ module PandaPal
|
|
138
138
|
save!
|
139
139
|
end
|
140
140
|
|
141
|
+
def install_lti(*args, **kwargs)
|
142
|
+
switch_tenant do
|
143
|
+
_install_lti(*args, **kwargs)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
141
147
|
def _ensure_lti_v1p3_key(exists:, host:)
|
142
148
|
current_client_id = self.key.split('/')[0]
|
143
149
|
|
@@ -323,7 +329,6 @@ module PandaPal
|
|
323
329
|
Bearcat::Client.new(
|
324
330
|
prefix: canvas_url,
|
325
331
|
token: canvas_token,
|
326
|
-
master_rate_limit: (Rails.env.production? && !!defined?(Redis) && ENV['REDIS_URL'].present?),
|
327
332
|
)
|
328
333
|
end
|
329
334
|
end
|
@@ -23,5 +23,134 @@ module PandaPal
|
|
23
23
|
"\033[1;#{30 + value}m#{text}\033[0m"
|
24
24
|
end
|
25
25
|
end
|
26
|
+
|
27
|
+
def pandapalrc
|
28
|
+
# TODO Consider searching app and parent dirs before ~/
|
29
|
+
@pandapalrc ||= YAML.load(File.read(File.expand_path("~/pandapalrc.yml"))) rescue {}
|
30
|
+
end
|
31
|
+
|
32
|
+
def prompt(prompt = "", default: nil)
|
33
|
+
prompt = prompt + " (#{default})" if default.present?
|
34
|
+
puts prompt
|
35
|
+
print "> "
|
36
|
+
v = gets.chomp.downcase
|
37
|
+
return default if v == ""
|
38
|
+
v
|
39
|
+
end
|
40
|
+
|
41
|
+
def prompt_options(options, prompt = "", default: nil)
|
42
|
+
options = options.map(&:to_s)
|
43
|
+
prompt = prompt + " (" + options.map { |o| o == default ? o.capitalize : o }.join("/") + ")"
|
44
|
+
i = 0
|
45
|
+
loop do
|
46
|
+
puts prompt
|
47
|
+
print "> "
|
48
|
+
i += 1
|
49
|
+
v = gets.chomp.downcase
|
50
|
+
return v if options.include?(v)
|
51
|
+
return default if v == ""
|
52
|
+
return nil if i > 3
|
53
|
+
puts "Invalid Input."
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def prompt_yes_no(prompt = "", default: true)
|
58
|
+
result = prompt_options(["y", "n"], prompt, default: default ? "y" : "n")
|
59
|
+
return true if result == "y"
|
60
|
+
return false if result == "n"
|
61
|
+
result
|
62
|
+
end
|
63
|
+
|
64
|
+
def prompt_pry_retry(prompt = "Retry?", default: false)
|
65
|
+
default = default ? "y" : "n" unless default.is_a?(String)
|
66
|
+
result = prompt_options(["y", "n", "pry"], prompt, default: default ? "y" : "n")
|
67
|
+
if result == "pry"
|
68
|
+
binding.pry
|
69
|
+
return true
|
70
|
+
end
|
71
|
+
return true if result == "y"
|
72
|
+
return false if result == "n"
|
73
|
+
result
|
74
|
+
end
|
75
|
+
|
76
|
+
def open_editor(file_path)
|
77
|
+
raise "EDITOR environment variable not set" unless ENV["EDITOR"].present?
|
78
|
+
|
79
|
+
args = Shellwords.shellwords(ENV['EDITOR'])
|
80
|
+
args << file_path
|
81
|
+
Kernel::system(*args)
|
82
|
+
end
|
83
|
+
|
84
|
+
def open_string_editor(string, file: nil, name: nil, require_save: true)
|
85
|
+
file_obj = file.present? ? File.new(file) : Tempfile.new([File.basename(name, File.extname(name)), File.extname(name)])
|
86
|
+
File.open(file_obj.path, 'w') { |f| f.write(string) }
|
87
|
+
|
88
|
+
mtime = File.stat(file_obj.path).mtime
|
89
|
+
|
90
|
+
path = file_obj.path
|
91
|
+
file_obj.close rescue nil
|
92
|
+
open_editor(path)
|
93
|
+
|
94
|
+
return :aborted unless !require_save || mtime < File.stat(file_obj.path).mtime
|
95
|
+
|
96
|
+
File.read(path)
|
97
|
+
end
|
98
|
+
|
99
|
+
class CodeBuilder
|
100
|
+
def initialize(indent: 0)
|
101
|
+
@code = ""
|
102
|
+
@line_prefix = [" "] * indent
|
103
|
+
end
|
104
|
+
|
105
|
+
def <<(line)
|
106
|
+
if line.is_a?(Array)
|
107
|
+
line.each do |l|
|
108
|
+
self << l
|
109
|
+
end
|
110
|
+
else
|
111
|
+
bits = line.split("\n", -1)
|
112
|
+
|
113
|
+
push_bit(bits.shift)
|
114
|
+
|
115
|
+
bits.each do |bit|
|
116
|
+
@code << "\n"
|
117
|
+
push_bit(bit)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
def ensure_line
|
123
|
+
return if @code.ends_with?("\n")
|
124
|
+
@code << "\n"
|
125
|
+
end
|
126
|
+
|
127
|
+
def block(char = nil)
|
128
|
+
indent!(char)
|
129
|
+
yield
|
130
|
+
ensure
|
131
|
+
dedent!
|
132
|
+
end
|
133
|
+
|
134
|
+
def indent!(char = nil)
|
135
|
+
@line_prefix << (char || " ")
|
136
|
+
end
|
137
|
+
|
138
|
+
def dedent!
|
139
|
+
@line_prefix.pop
|
140
|
+
end
|
141
|
+
|
142
|
+
def to_s
|
143
|
+
@code
|
144
|
+
end
|
145
|
+
|
146
|
+
protected
|
147
|
+
|
148
|
+
def push_bit(bit)
|
149
|
+
return unless bit.present?
|
150
|
+
|
151
|
+
@code << @line_prefix.join if @code.ends_with?("\n")
|
152
|
+
@code << bit
|
153
|
+
end
|
154
|
+
end
|
26
155
|
end
|
27
156
|
end
|
@@ -9,7 +9,9 @@ module PandaPal::Helpers::RouteHelper
|
|
9
9
|
path = "#{base_path}/#{nav.to_s}"
|
10
10
|
|
11
11
|
lti_options = options.delete(:lti_options) || {}
|
12
|
+
|
12
13
|
lti_options[:auto_launch] = options.delete(:auto_launch)
|
14
|
+
# NB if lti_nav is outside an :organization_id scope, auto_launch defaults differently between 1.1 and 1.3 - 1.1 defaults off, 1.3 defaults on
|
13
15
|
lti_options[:auto_launch] = true if lti_options[:auto_launch].nil? && (@scope[:path] || '').include?(':organization_id')
|
14
16
|
|
15
17
|
lti_options[:route_helper_key] = path.split('/').reject(&:empty?).join('_')
|
data/lib/panda_pal/version.rb
CHANGED
@@ -3,4 +3,41 @@ namespace :panda_pal do
|
|
3
3
|
task clean_sessions: :environment do
|
4
4
|
PandaPal::Session.where('updated_at < ?', 1.week.ago).delete_all
|
5
5
|
end
|
6
|
+
|
7
|
+
namespace :org do
|
8
|
+
desc "Interactively Create a new PandaPal::Organization"
|
9
|
+
task :new, [:name] => :environment do |t, args|
|
10
|
+
org = PandaPal::Organization.new(name: args[:name])
|
11
|
+
PandaPal::Organization.interactive_create!(org)
|
12
|
+
rescue PandaPal::OrganizationConcerns::OrganizationBuilder::InteractiveSessionError => ex
|
13
|
+
ex.print
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "Interactively Update a PandaPal::Organization"
|
17
|
+
task :edit, [:name] => :environment do |t, args|
|
18
|
+
org = PandaPal::Organization.find_by!(name: args[:name])
|
19
|
+
org.interactive_update!
|
20
|
+
rescue PandaPal::OrganizationConcerns::OrganizationBuilder::InteractiveSessionError => ex
|
21
|
+
ex.print
|
22
|
+
end
|
23
|
+
|
24
|
+
desc "Install/update the LTI in Canvas for the given Organization"
|
25
|
+
task :install, [:name, :host] => :environment do |t, args|
|
26
|
+
org = PandaPal::Organization.find_by!(name: args[:name])
|
27
|
+
org.interactive_install!(host: args[:host], exists: :update)
|
28
|
+
end
|
29
|
+
|
30
|
+
desc "Reinstall the LTI in Canvas for the given Organization"
|
31
|
+
task :reinstall, [:name, :host] => :environment do |t, args|
|
32
|
+
org = PandaPal::Organization.find_by!(name: args[:name])
|
33
|
+
org.interactive_install!(host: args[:host], exists: :replace)
|
34
|
+
end
|
35
|
+
|
36
|
+
if Rails.env.development?
|
37
|
+
desc "Creates a new PandaPal::Organization for development"
|
38
|
+
task dev: :environment do
|
39
|
+
PandaPal::Organization.development_create!
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
6
43
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: panda_pal
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 5.
|
4
|
+
version: 5.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Instructure CustomDev
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-11-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -282,7 +282,7 @@ dependencies:
|
|
282
282
|
- - '='
|
283
283
|
- !ruby/object:Gem::Version
|
284
284
|
version: 2.7.1
|
285
|
-
description:
|
285
|
+
description:
|
286
286
|
email:
|
287
287
|
- pseng@instructure.com
|
288
288
|
executables: []
|
@@ -311,6 +311,7 @@ files:
|
|
311
311
|
- app/lib/panda_pal/lti_jwt_validator.rb
|
312
312
|
- app/models/panda_pal/api_call.rb
|
313
313
|
- app/models/panda_pal/organization.rb
|
314
|
+
- app/models/panda_pal/organization_concerns/organization_builder.rb
|
314
315
|
- app/models/panda_pal/organization_concerns/settings_validation.rb
|
315
316
|
- app/models/panda_pal/organization_concerns/task_scheduling.rb
|
316
317
|
- app/models/panda_pal/panda_pal_record.rb
|
@@ -394,7 +395,7 @@ homepage: http://instructure.com
|
|
394
395
|
licenses:
|
395
396
|
- MIT
|
396
397
|
metadata: {}
|
397
|
-
post_install_message:
|
398
|
+
post_install_message:
|
398
399
|
rdoc_options: []
|
399
400
|
require_paths:
|
400
401
|
- lib
|
@@ -410,7 +411,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
410
411
|
version: '0'
|
411
412
|
requirements: []
|
412
413
|
rubygems_version: 3.1.6
|
413
|
-
signing_key:
|
414
|
+
signing_key:
|
414
415
|
specification_version: 4
|
415
416
|
summary: LTI mountable engine
|
416
417
|
test_files:
|