diff --git a/Gemfile b/Gemfile index 67a9c765e..f7550c3a0 100644 --- a/Gemfile +++ b/Gemfile @@ -29,7 +29,7 @@ gem "strong_password" gem "ims-lti", "~> 2.1.5" # IMS LTI tool consumers and providers gem "json-jwt" gem "jwt" -gem "lms-api", "~>1.12.0" +gem "lms-api", "~>1.15.0" gem "lms-graphql-api", ">=0.5.3" gem "omniauth" gem "omniauth-canvas", "~>1.0.2" diff --git a/Gemfile.lock b/Gemfile.lock index 16ce90d68..cdee707ef 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -62,7 +62,7 @@ GEM tzinfo (~> 1.1) addressable (2.7.0) public_suffix (>= 2.0.2, < 5.0) - aes_key_wrap (1.0.1) + aes_key_wrap (1.1.0) apartment (2.2.1) activerecord (>= 3.1.2, < 6.0) parallel (>= 0.7.1) @@ -72,26 +72,26 @@ GEM activesupport apartment arel (9.0.0) - ast (2.4.0) + ast (2.4.1) attr_encrypted (3.1.0) encryptor (~> 3.0.0) - autoprefixer-rails (9.7.4) + autoprefixer-rails (9.8.5) execjs bcrypt (3.1.13) - better_errors (2.5.1) + better_errors (2.7.1) coderay (>= 1.0.0) erubi (>= 1.0.0) rack (>= 0.9.0) - bindata (2.4.4) + bindata (2.4.7) bindex (0.8.1) binding_of_caller (0.8.0) debug_inspector (>= 0.0.1) - bootsnap (1.4.5) + bootsnap (1.4.6) msgpack (~> 1.0) builder (3.2.4) - byebug (11.1.1) - cancancan (3.0.2) - capybara (3.31.0) + byebug (11.1.3) + cancancan (3.1.0) + capybara (3.33.0) addressable mini_mime (>= 0.1.3) nokogiri (~> 1.8) @@ -100,57 +100,57 @@ GEM regexp_parser (~> 1.5) xpath (~> 3.2) childprocess (3.0.0) - coderay (1.1.2) + coderay (1.1.3) composite_primary_keys (11.2.0) activerecord (~> 5.2.1) concurrent-ruby (1.1.6) crack (0.4.3) safe_yaml (~> 1.0.0) crass (1.0.6) - database_cleaner (1.7.0) + database_cleaner (1.8.5) debase (0.2.4.1) debase-ruby_core_source (>= 0.10.2) debase-ruby_core_source (0.10.9) debug_inspector (0.0.3) - devise (4.7.1) + devise (4.7.2) bcrypt (~> 3.0) orm_adapter (~> 0.1) railties (>= 4.1.0) responders warden (~> 1.2.3) - diff-lcs (1.3) - dotenv (2.7.5) - dotenv-rails (2.7.5) - dotenv (= 2.7.5) - railties (>= 3.2, < 6.1) + diff-lcs (1.4.4) + dotenv (2.7.6) + dotenv-rails (2.7.6) + dotenv (= 2.7.6) + railties (>= 3.2) encryptor (3.0.0) erubi (1.9.0) execjs (2.7.0) - factory_bot (5.1.1) - activesupport (>= 4.2.0) - factory_bot_rails (5.1.1) - factory_bot (~> 5.1.0) - railties (>= 4.2.0) - faker (2.10.1) + factory_bot (6.1.0) + activesupport (>= 5.0.0) + factory_bot_rails (6.1.0) + factory_bot (~> 6.1.0) + railties (>= 5.0.0) + faker (2.13.0) i18n (>= 1.6, < 2) faraday (0.17.3) multipart-post (>= 1.2, < 3) faraday_middleware (0.14.0) faraday (>= 0.7.4, < 1.0) - ffi (1.12.1) + ffi (1.13.1) formatador (0.2.5) - gitlab (4.15.0) + gitlab (4.16.1) httparty (~> 0.14, >= 0.14.0) terminal-table (~> 1.5, >= 1.5.1) globalid (0.4.2) activesupport (>= 4.2.0) - graphql (1.9.19) + graphql (1.9.21) graphql-batch (0.3.10) graphql (>= 0.8, < 2) promise.rb (~> 0.7.2) graphql-guard (1.3.1) graphql (>= 1.6.0, < 2) - guard (2.16.1) + guard (2.16.2) formatador (>= 0.2.4) listen (>= 2.7, < 4.0) lumberjack (>= 1.0.12, < 2.0) @@ -164,8 +164,8 @@ GEM guard (~> 2.1) guard-compat (~> 1.1) rspec (>= 2.99.0, < 4.0) - hashdiff (1.0.0) - hashie (3.6.0) + hashdiff (1.0.1) + hashie (4.1.0) httparty (0.18.1) mime-types (~> 3.0) multi_xml (>= 0.5.2) @@ -179,49 +179,48 @@ GEM faraday_middleware (~> 0.8) json-jwt (~> 1.7) simple_oauth (= 0.2) - jaro_winkler (1.5.4) - json (2.3.0) - json-jwt (1.11.0) + json (2.3.1) + json-jwt (1.13.0) activesupport (>= 4.2) aes_key_wrap bindata jwt (2.2.1) - launchy (2.4.3) - addressable (~> 2.3) + launchy (2.5.0) + addressable (~> 2.7) listen (3.2.1) rb-fsevent (~> 0.10, >= 0.10.3) rb-inotify (~> 0.9, >= 0.9.10) - lms-api (1.12.1) + lms-api (1.15.0) activesupport (>= 3.0) httparty lms-graphql-api (1.1.1) graphql (>= 1.8.2) lms-api (>= 1.5.0) - loofah (2.4.0) + loofah (2.6.0) crass (~> 1.0.2) nokogiri (>= 1.5.9) - lumberjack (1.2.1) + lumberjack (1.2.6) mail (2.7.1) mini_mime (>= 0.1.1) mail_view (2.0.4) tilt marcel (0.3.3) mimemagic (~> 0.3.2) - method_source (0.9.2) + method_source (1.0.0) mime-types (3.3.1) mime-types-data (~> 3.2015) mime-types-data (3.2020.0512) - mimemagic (0.3.4) + mimemagic (0.3.5) mini_mime (1.0.2) mini_portile2 (2.4.0) minitest (5.14.1) - msgpack (1.3.1) - multi_json (1.14.1) + msgpack (1.3.3) + multi_json (1.15.0) multi_xml (0.6.0) multipart-post (2.1.1) nenv (0.3.0) nio4r (2.5.2) - nokogiri (1.10.8) + nokogiri (1.10.10) mini_portile2 (~> 2.4.0) non-stupid-digest-assets (1.0.9) sprockets (>= 2.0) @@ -230,7 +229,7 @@ GEM shellany (~> 0.0) nuclear_secrets (1.0.5) rails (>= 5.0.0) - oauth2 (1.4.2) + oauth2 (1.4.4) faraday (>= 0.8, < 2.0) jwt (>= 1.0, < 3.0) multi_json (~> 1.3) @@ -239,8 +238,8 @@ GEM octokit (4.18.0) faraday (>= 0.9) sawyer (~> 0.8.0, >= 0.5.3) - omniauth (1.9.0) - hashie (>= 3.4.6, < 3.7.0) + omniauth (1.9.1) + hashie (>= 3.4.6) rack (>= 1.6.2, < 3) omniauth-canvas (1.0.2) omniauth (~> 1.3) @@ -249,20 +248,20 @@ GEM oauth2 (~> 1.1) omniauth (~> 1.9) orm_adapter (0.5.0) - parallel (1.19.1) - parser (2.7.0.2) - ast (~> 2.4.0) - pg (1.2.2) + parallel (1.19.2) + parser (2.7.1.4) + ast (~> 2.4.1) + pg (1.2.3) promise.rb (0.7.4) pronto-eslint_npm (0.10.1) pronto (~> 0.10.0) pronto-rubocop (0.10.0) pronto (~> 0.10.0) rubocop (~> 0.50, >= 0.49.1) - pry (0.12.2) - coderay (~> 1.1.0) - method_source (~> 0.9.0) - public_suffix (4.0.3) + pry (0.13.1) + coderay (~> 1.1) + method_source (~> 1.0) + public_suffix (4.0.5) puma (4.3.5) nio4r (~> 2.0) que (0.14.3) @@ -286,10 +285,10 @@ GEM bundler (>= 1.3.0) railties (= 5.2.3) sprockets-rails (>= 2.0.0) - rails-controller-testing (1.0.4) - actionpack (>= 5.0.1.x) - actionview (>= 5.0.1.x) - activesupport (>= 5.0.1.x) + rails-controller-testing (1.0.5) + actionpack (>= 5.0.1.rc1) + actionview (>= 5.0.1.rc1) + activesupport (>= 5.0.1.rc1) rails-dom-testing (2.0.3) activesupport (>= 4.2.0) nokogiri (>= 1.6) @@ -313,55 +312,61 @@ GEM rake (13.0.1) rb-fchange (0.0.6) ffi - rb-fsevent (0.10.3) + rb-fsevent (0.10.4) rb-inotify (0.10.1) ffi (~> 1.0) - regexp_parser (1.6.0) - responders (3.0.0) + regexp_parser (1.7.1) + responders (3.0.1) actionpack (>= 5.0) railties (>= 5.0) - rolify (5.2.0) - rollbar (2.23.2) + rexml (3.2.4) + rolify (5.3.0) + rollbar (2.26.0) rspec (3.9.0) rspec-core (~> 3.9.0) rspec-expectations (~> 3.9.0) rspec-mocks (~> 3.9.0) - rspec-core (3.9.1) - rspec-support (~> 3.9.1) - rspec-expectations (3.9.0) + rspec-core (3.9.2) + rspec-support (~> 3.9.3) + rspec-expectations (3.9.2) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.9.0) rspec-mocks (3.9.1) diff-lcs (>= 1.2.0, < 2.0) rspec-support (~> 3.9.0) - rspec-rails (3.9.0) - actionpack (>= 3.0) - activesupport (>= 3.0) - railties (>= 3.0) - rspec-core (~> 3.9.0) - rspec-expectations (~> 3.9.0) - rspec-mocks (~> 3.9.0) - rspec-support (~> 3.9.0) - rspec-support (3.9.2) - rubocop (0.79.0) - jaro_winkler (~> 1.5.1) + rspec-rails (4.0.1) + actionpack (>= 4.2) + activesupport (>= 4.2) + railties (>= 4.2) + rspec-core (~> 3.9) + rspec-expectations (~> 3.9) + rspec-mocks (~> 3.9) + rspec-support (~> 3.9) + rspec-support (3.9.3) + rubocop (0.88.0) parallel (~> 1.10) - parser (>= 2.7.0.1) + parser (>= 2.7.1.1) rainbow (>= 2.2.2, < 4.0) + regexp_parser (>= 1.7) + rexml + rubocop-ast (>= 0.1.0, < 1.0) ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 1.7) - rubocop-performance (1.5.2) - rubocop (>= 0.71.0) - rubocop-rails (2.4.2) + unicode-display_width (>= 1.4.0, < 2.0) + rubocop-ast (0.1.0) + parser (>= 2.7.0.1) + rubocop-performance (1.7.0) + rubocop (>= 0.82.0) + rubocop-rails (2.6.0) + activesupport (>= 4.2.0) rack (>= 1.1) - rubocop (>= 0.72.0) - ruby-debug-ide (0.7.0) + rubocop (>= 0.82.0) + ruby-debug-ide (0.7.2) rake (>= 0.8.1) ruby-progressbar (1.10.1) - rubyzip (2.1.0) + rubyzip (2.3.0) rugged (1.0.1) safe_yaml (1.0.5) - sassc (2.2.1) + sassc (2.4.0) ffi (~> 1.9) sassc-rails (2.1.2) railties (>= 4.0.0) @@ -375,10 +380,11 @@ GEM selenium-webdriver (3.142.7) childprocess (>= 0.5, < 4.0) rubyzip (>= 1.2.2) + semantic_range (2.3.0) sendgrid (1.2.4) json shellany (0.0.1) - shoulda-matchers (4.2.0) + shoulda-matchers (4.3.0) activesupport (>= 4.2.0) simple_oauth (0.2.0) spring (2.1.0) @@ -394,17 +400,17 @@ GEM actionpack (>= 4.0) activesupport (>= 4.0) sprockets (>= 3.0.0) - strong_password (0.0.8) + strong_password (0.0.9) terminal-table (1.8.0) unicode-display_width (~> 1.1, >= 1.1.1) - thor (0.20.3) + thor (1.0.1) thread_safe (0.3.6) tilt (2.0.10) tzinfo (1.2.7) thread_safe (~> 0.1) uglifier (4.2.0) execjs (>= 0.3.0, < 3) - unicode-display_width (1.6.1) + unicode-display_width (1.7.0) warden (1.2.8) rack (>= 2.0.6) web-console (3.7.0) @@ -412,18 +418,19 @@ GEM activemodel (>= 5.0) bindex (>= 0.4.0) railties (>= 5.0) - webmock (3.8.0) + webmock (3.8.3) addressable (>= 2.3.6) crack (>= 0.3.2) hashdiff (>= 0.4.0, < 2.0.0) - webpacker (4.2.2) - activesupport (>= 4.2) + webpacker (5.1.1) + activesupport (>= 5.2) rack-proxy (>= 0.6.1) - railties (>= 4.2) - websocket-driver (0.7.1) + railties (>= 5.2) + semantic_range (>= 2.3.0) + websocket-driver (0.7.3) websocket-extensions (>= 0.1.0) websocket-extensions (0.1.5) - will_paginate (3.2.1) + will_paginate (3.3.0) xpath (3.2.0) nokogiri (~> 1.8) yajl-ruby (1.4.1) @@ -461,7 +468,7 @@ DEPENDENCIES jwt launchy listen - lms-api (~> 1.12.0) + lms-api (~> 1.15.0) lms-graphql-api (>= 0.5.3) mail_view non-stupid-digest-assets diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index d6ac586b8..a1f2d3ec7 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -68,6 +68,15 @@ def handle_canvas_exception(exception) render_error 500, "Error while accessing Canvas: #{exception.message}.", { exception: exception } end + # Raised when Canvas returned a 500 when trying to refresh the token - this + # usually means Canvas is down or something is wrong with the config. Check + # the oauth key and secret. + rescue_from LMS::Canvas::RefreshToken500Exception, with: :handle_canvas_token_refresh_500 + def handle_canvas_token_refresh_500(exception) + record_exception(exception) + render_error 500, "Error while refreshing Canvas token: #{exception.message}.", { exception: exception } + end + # Raised when a new token cannot be retrieved using the refresh token rescue_from LMS::Canvas::RefreshTokenFailedException, with: :handle_canvas_token_expired diff --git a/app/models/canvas_course.rb b/app/models/canvas_course.rb index 0ec155479..638edd5eb 100644 --- a/app/models/canvas_course.rb +++ b/app/models/canvas_course.rb @@ -1,3 +1,3 @@ class CanvasCourse < ApplicationRecord - has_many :authentications, dependent: :destroy, inverse_of: :canvas_course + has_many :authentications, inverse_of: :canvas_course, dependent: :nullify end diff --git a/app/models/user.rb b/app/models/user.rb index 179fbbdff..5a8f8a4e4 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -5,7 +5,7 @@ class User < ApplicationRecord devise :database_authenticatable, :registerable, :confirmable, :recoverable, :rememberable, :trackable, :validatable, :omniauthable - has_many :authentications, dependent: :destroy, inverse_of: :user + has_many :authentications, inverse_of: :user, dependent: :nullify has_many :permissions, dependent: :destroy has_many :roles, through: :permissions diff --git a/spec/controllers/application_controller_spec.rb b/spec/controllers/application_controller_spec.rb index 0b47e0125..c639250dd 100644 --- a/spec/controllers/application_controller_spec.rb +++ b/spec/controllers/application_controller_spec.rb @@ -119,6 +119,24 @@ def index end end + describe "LMS::Canvas::RefreshToken500Exception" do + controller do + def index + raise LMS::Canvas::RefreshToken500Exception.new("Canvas returned a 500") + end + end + it "renders an error page" do + get :index + expect(response).to have_http_status(500) + end + it "renders error json" do + get :index, format: :json + expect(response).to have_http_status(500) + result = JSON.parse(response.body) + expect(result["message"]).to eq("Error while refreshing Canvas token: Canvas returned a 500.") + end + end + describe "LMS::Canvas::RefreshTokenFailedException" do controller do def index