From ff468a7dd3b9e60c44b543252eddac083e0f215d Mon Sep 17 00:00:00 2001 From: louispt1 Date: Fri, 20 Dec 2024 09:21:36 +0100 Subject: [PATCH 1/3] Updated OAuth logic to account for versions --- app/controllers/api/v1/base_controller.rb | 10 ++++- .../api/v1/saved_scenarios_controller.rb | 2 +- app/controllers/application_controller.rb | 13 +++++- .../users/registrations_controller.rb | 2 +- app/helpers/application_helper.rb | 4 +- app/models/version.rb | 41 ++++++++++++++----- app/services/create_staff_application.rb | 2 +- app/views/layouts/_sidebar.html.haml | 2 +- config/initializers/doorkeeper.rb | 2 +- lib/myetm/auth.rb | 14 +++---- .../api/v1/versions_controller_spec.rb | 3 +- 11 files changed, 67 insertions(+), 28 deletions(-) diff --git a/app/controllers/api/v1/base_controller.rb b/app/controllers/api/v1/base_controller.rb index e0fc7e0..adce383 100644 --- a/app/controllers/api/v1/base_controller.rb +++ b/app/controllers/api/v1/base_controller.rb @@ -4,6 +4,7 @@ class BaseController < ActionController::API include ActionController::MimeResponds before_action :authenticate_request! + before_action :set_version_tag rescue_from ActionController::ParameterMissing do |e| render json: { errors: [ e.message ] }, status: :bad_request @@ -35,7 +36,6 @@ class BaseController < ActionController::API private - def decoded_token return @decoded_token if defined?(@decoded_token) @@ -117,7 +117,13 @@ def require_user false end - private + def set_version_tag + @version_tag = params[:version] || Version::DEFAULT_TAG + end + + def current_version_tag + @version_tag + end def find_user_from_token return unless decoded_token diff --git a/app/controllers/api/v1/saved_scenarios_controller.rb b/app/controllers/api/v1/saved_scenarios_controller.rb index 16710f6..0dcbafa 100644 --- a/app/controllers/api/v1/saved_scenarios_controller.rb +++ b/app/controllers/api/v1/saved_scenarios_controller.rb @@ -68,7 +68,7 @@ def saved_scenario_params end def engine_client - MyEtm::Auth.engine_client(current_user)#, scopes: doorkeeper_token.scopes) + MyEtm::Auth.engine_client(current_user, current_version_tag) end end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index f140b25..1e03aac 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -8,6 +8,9 @@ class ApplicationController < ActionController::Base before_action :configure_sentry before_action :store_user_location!, if: :storable_location? before_action :store_redirect_url + before_action :set_version_tag + + helper_method :current_version_tag rescue_from CanCan::AccessDenied do |_exception| if current_user @@ -75,7 +78,7 @@ def configure_sentry end def engine_client - MyEtm::Auth.engine_client(current_user) + MyEtm::Auth.engine_client(current_user, current_version_tag) end # Internal: Renders a 404 page. @@ -141,4 +144,12 @@ def store_redirect_url session[:redirect_url] = params[:redirect_url] end end + + def set_version_tag + @version_tag = params[:version] || Version::DEFAULT_TAG + end + + def current_version_tag + @version_tag + end end diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb index c151d94..67592f1 100644 --- a/app/controllers/users/registrations_controller.rb +++ b/app/controllers/users/registrations_controller.rb @@ -71,7 +71,7 @@ def stats_for_destroy personal_access_tokens: current_user.personal_access_tokens.not_expired.count, oauth_applications: current_user.oauth_applications.count, collections: 0 - # collections: current_user.collections.count + # collections: current_user.collections.count # TODO: Re-Implement } end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 78ebdf8..2b0e55e 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -30,11 +30,11 @@ def format_staff_config(config, app) etengine_url = Settings.etengine.uri || "http://YOUR_ETENGINE_URL" format(config, app.attributes.symbolize_keys.merge( - myetm_url: root_url.chomp("/root"), + myetm_url: root_url.chomp("/"), etengine_url: etengine_url, etmodel_url: Settings.etmodel.uri || "http://YOUR_ETMODEL_URL", collections_url: Settings.collections.uri || "http://YOUR_COLLECTIONS_URL", - etengine_uid: Doorkeeper::Application.find_by(uri: etengine_url)&.uid || "YOUR_ETEngine_ID_HERE" + etengine_uid: Doorkeeper::Application.find_by(uri: etengine_url)&.uid || "YOUR_ETEngine_ID" )) end diff --git a/app/models/version.rb b/app/models/version.rb index 45a021e..854d3f0 100644 --- a/app/models/version.rb +++ b/app/models/version.rb @@ -3,14 +3,22 @@ # A valid version of the ETM class Version URL = "energytransitionmodel.com".freeze + DEFAULT_TAG = Rails.env.development? ? "local" : "latest" # Default to "local" in development # Tag => prefix LIST = { + "local" => "", "latest" => "", "stable.01" => "stable.", "stable.02" => "stable2." }.freeze + LOCAL_URLS = { + "collections" => Settings.collections.uri, + "model" => Settings.etmodel.uri, + "engine" => Settings.etengine.uri + }.freeze + # All available versions. Uses ActiveRecord syntax 'all' to # make future porting to db easier def self.all @@ -21,26 +29,39 @@ def self.tags LIST.keys end - def self.model_url(tag) - "https://#{LIST[tag]}#{Version::URL}" + def self.collections_url(tag = nil) + build_url("collections", tag) end - def self.engine_url(tag) - "https://#{LIST[tag]}engine.#{Version::URL}" + def self.model_url(tag = nil) + build_url("model", tag) end - # TODO: Collections url - - # TODO: urls for local development => Add a local version and - # exceptions for the urls + def self.engine_url(tag = nil) + build_url("engine", tag) + end def self.as_json(*) Version.tags.map do |tag| { tag: tag, - url: Version.model_url(tag), - engine_url: Version.engine_url(tag) + model_url: model_url(tag), + engine_url: engine_url(tag), + collections_url: collections_url(tag) } end end + + private + + def self.build_url(context, tag) + tag ||= DEFAULT_TAG + raise ArgumentError, "Invalid version tag: #{tag}" unless LIST.key?(tag) + + if tag == "local" + LOCAL_URLS[context] + else + "https://#{LIST[tag]}#{context == 'model' ? '' : "#{context}."}#{URL}" + end + end end diff --git a/app/services/create_staff_application.rb b/app/services/create_staff_application.rb index 20d93e2..704f555 100644 --- a/app/services/create_staff_application.rb +++ b/app/services/create_staff_application.rb @@ -25,7 +25,7 @@ def self.call(user, app_config, uri: nil) # Update application attributes app.attributes = app_config.to_model_attributes.merge( - owner: user, + owner_id: user.id, uri: parsed_uri.to_s, redirect_uri: redirect_uri.to_s ) diff --git a/app/views/layouts/_sidebar.html.haml b/app/views/layouts/_sidebar.html.haml index 1faf8c2..a7d9000 100644 --- a/app/views/layouts/_sidebar.html.haml +++ b/app/views/layouts/_sidebar.html.haml @@ -1,6 +1,6 @@ .sidebar.fixed.top-0.bottom-0.overflow-y-auto.bg-midnight-300{class: 'lg:left-0 w-[300px]'} -# Where does the logo refer to? REMEMBER LAST VERSION IN COOKIE - %a.logo.p-5.mb-3.inline-block.w-full.text-midnight-800 + %a.logo.p-5.mb-3.inline-block.w-full.text-midnight-800{href: Version.model_url(current_version_tag || "latest")} = image_tag 'header/logo-round.png', class: 'h-8 inline mb-1 mr-2 hover:animate-spin' %span Energy Transition Model diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb index 8e160c4..f7cac85 100644 --- a/config/initializers/doorkeeper.rb +++ b/config/initializers/doorkeeper.rb @@ -41,7 +41,7 @@ # # access_token_class "Doorkeeper::AccessToken" # access_grant_class "Doorkeeper::AccessGrant" - application_class 'OAuthApplication' + application_class "OAuthApplication" # # Don't forget to include Doorkeeper ORM mixins into your custom models: # diff --git a/lib/myetm/auth.rb b/lib/myetm/auth.rb index 96f8ac6..cf1e66c 100644 --- a/lib/myetm/auth.rb +++ b/lib/myetm/auth.rb @@ -65,19 +65,19 @@ def client_app_client(user, client_app) end end - # TODO: use the uri's generated by Version to dynamiclly pick the correct - # model and engine - def engine_client(user) - engine = OAuthApplication.find_by(uri: Settings.etengine.uri) + # TODO: Refactor usage to include the version_tag + def engine_client(user, version_tag = Version::DEFAULT_TAG) + uri = Version.engine_url(version_tag) + engine = OAuthApplication.find_by(uri: uri) client_app_client(user, engine) end - def model_client(user) - model = OAuthApplication.find_by(uri: Settings.etmodel.uri) + def model_client(user, version_tag = Version::DEFAULT_TAG) + uri = Version.model_url(version_tag) + model = OAuthApplication.find_by(uri: uri) client_app_client(user, model) end - # Checks if the token is in JWT format def jwt_format?(token) token.count(".") == 2 diff --git a/spec/controllers/api/v1/versions_controller_spec.rb b/spec/controllers/api/v1/versions_controller_spec.rb index 5c63390..37ef1b9 100644 --- a/spec/controllers/api/v1/versions_controller_spec.rb +++ b/spec/controllers/api/v1/versions_controller_spec.rb @@ -19,8 +19,9 @@ expect(parsed_response['versions']).to be_present expect(parsed_response['versions'].map { |v| v['tag'] }).to match_array(Version.tags) - expect(parsed_response['versions'].first).to have_key('url') + expect(parsed_response['versions'].first).to have_key('model_url') expect(parsed_response['versions'].first).to have_key('engine_url') + expect(parsed_response['versions'].first).to have_key('collections_url') end end end From 7528354fd817b95321d087f05a1fd1186b7dfc8a Mon Sep 17 00:00:00 2001 From: noracato Date: Thu, 9 Jan 2025 16:16:31 +0100 Subject: [PATCH 2/3] Clients for different versions work based on resource version and fixes for local development --- app/controllers/api/v1/base_controller.rb | 9 ------ .../api/v1/saved_scenarios_controller.rb | 10 +++++- app/controllers/application_controller.rb | 32 ++++++++----------- app/controllers/collections_controller.rb | 8 ++--- app/controllers/passthru_controller.rb | 5 +++ .../saved_scenario_history_controller.rb | 7 ++-- .../saved_scenario_users_controller.rb | 13 ++++++-- app/controllers/saved_scenarios_controller.rb | 4 +-- .../users/registrations_controller.rb | 1 - app/models/version.rb | 6 ++-- app/views/layouts/_buttons.html.haml | 4 +-- app/views/layouts/_sidebar.html.haml | 3 +- config/routes.rb | 2 +- lib/myetm/auth.rb | 26 +++++++-------- .../collections_controller_spec.rb | 2 +- spec/requests/saved_scenarios_spec.rb | 2 +- 16 files changed, 71 insertions(+), 63 deletions(-) create mode 100644 app/controllers/passthru_controller.rb diff --git a/app/controllers/api/v1/base_controller.rb b/app/controllers/api/v1/base_controller.rb index adce383..6c74396 100644 --- a/app/controllers/api/v1/base_controller.rb +++ b/app/controllers/api/v1/base_controller.rb @@ -4,7 +4,6 @@ class BaseController < ActionController::API include ActionController::MimeResponds before_action :authenticate_request! - before_action :set_version_tag rescue_from ActionController::ParameterMissing do |e| render json: { errors: [ e.message ] }, status: :bad_request @@ -117,14 +116,6 @@ def require_user false end - def set_version_tag - @version_tag = params[:version] || Version::DEFAULT_TAG - end - - def current_version_tag - @version_tag - end - def find_user_from_token return unless decoded_token user_data = decoded_token[:user] diff --git a/app/controllers/api/v1/saved_scenarios_controller.rb b/app/controllers/api/v1/saved_scenarios_controller.rb index 0dcbafa..8cd59de 100644 --- a/app/controllers/api/v1/saved_scenarios_controller.rb +++ b/app/controllers/api/v1/saved_scenarios_controller.rb @@ -68,7 +68,15 @@ def saved_scenario_params end def engine_client - MyEtm::Auth.engine_client(current_user, current_version_tag) + MyEtm::Auth.engine_client(current_user, active_version_tag) + end + + def active_version_tag + if Version.tags.include?(saved_scenario_params[:version].to_s) + saved_scenario_params[:version] + else + Version::DEFAULT_TAG + end end end end diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 1e03aac..bbd39ff 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -7,10 +7,9 @@ class ApplicationController < ActionController::Base before_action :set_locale before_action :configure_sentry before_action :store_user_location!, if: :storable_location? - before_action :store_redirect_url - before_action :set_version_tag + before_action :set_active_version_tag - helper_method :current_version_tag + helper_method :active_version_tag rescue_from CanCan::AccessDenied do |_exception| if current_user @@ -39,8 +38,8 @@ def set_locale session[:locale] || http_accept_language.preferred_language_from(I18n.available_locales) end - def last_visited_page - redirect_to cookies[:last_visited_page] || root_path + def active_version_tag + session[:active_version_tag] || Version::DEFAULT_TAG end private @@ -77,8 +76,8 @@ def configure_sentry end end - def engine_client - MyEtm::Auth.engine_client(current_user, current_version_tag) + def engine_client(version_tag) + MyEtm::Auth.engine_client(current_user, version_tag) end # Internal: Renders a 404 page. @@ -139,17 +138,14 @@ def turbo_alert(message = nil) ) end - def store_redirect_url - if params[:redirect_url].present? - session[:redirect_url] = params[:redirect_url] - end - end - - def set_version_tag - @version_tag = params[:version] || Version::DEFAULT_TAG - end + # Validates the version tag passed from the latest request and sets it in the + # session, so we can redirect back to that version later. + # + # TODO: somebody has to set this! + def set_active_version_tag + return unless params[:active_version] + return unless Version.tags.include?(params[:active_version].to_s) - def current_version_tag - @version_tag + session[:active_version_tag] = params[:active_version] end end diff --git a/app/controllers/collections_controller.rb b/app/controllers/collections_controller.rb index af573eb..8a1a455 100644 --- a/app/controllers/collections_controller.rb +++ b/app/controllers/collections_controller.rb @@ -75,7 +75,7 @@ def show # POST /collections/create_transition def create_transition result = CreateInterpolatedCollection.call( - engine_client, + engine_client(create_transition_params[:version]), current_user.saved_scenarios.find(create_transition_params[:saved_scenario_ids]), current_user ) @@ -120,8 +120,8 @@ def confirm_destroy # DELETE /collections/:id def destroy DeleteCollection.call( - engine_client, - current_user.collections.find(params.require(:id)) + engine_client(@collection.version), + @collection ) redirect_to collections_path @@ -178,7 +178,7 @@ def create_collection_params end def create_transition_params - params.require(:collection).permit(:saved_scenario_ids) + params.require(:collection).permit(:version, :saved_scenario_ids) end def filter_params diff --git a/app/controllers/passthru_controller.rb b/app/controllers/passthru_controller.rb new file mode 100644 index 0000000..1b63a25 --- /dev/null +++ b/app/controllers/passthru_controller.rb @@ -0,0 +1,5 @@ +class PassthruController < ApplicationController + def last + redirect_to cookies[:etm_last_visited_page] || root_path + end +end \ No newline at end of file diff --git a/app/controllers/saved_scenario_history_controller.rb b/app/controllers/saved_scenario_history_controller.rb index 70448a2..4a79852 100644 --- a/app/controllers/saved_scenario_history_controller.rb +++ b/app/controllers/saved_scenario_history_controller.rb @@ -12,7 +12,10 @@ class SavedScenarioHistoryController < ApplicationController # GET /saved_scenarios/:id/history def index - version_tags_result = ApiScenario::VersionTags::FetchAll.call(engine_client, @saved_scenario) + version_tags_result = ApiScenario::VersionTags::FetchAll.call( + engine_client(@saved_scenario.version), + @saved_scenario + ) if version_tags_result.successful? @history = SavedScenarioHistoryPresenter.present(@saved_scenario, version_tags_result.value) @@ -32,7 +35,7 @@ def index # PUT /saved_scenarios/:id/history/:scenario_id def update result = ApiScenario::VersionTags::Update.call( - engine_client, + engine_client(@saved_scenario.version), params[:scenario_id], update_params[:description] ) diff --git a/app/controllers/saved_scenario_users_controller.rb b/app/controllers/saved_scenario_users_controller.rb index af78896..3cba662 100644 --- a/app/controllers/saved_scenario_users_controller.rb +++ b/app/controllers/saved_scenario_users_controller.rb @@ -37,7 +37,10 @@ def new # POST /saved_scenarios/:saved_scenario_id/users def create result = CreateSavedScenarioUser.call( - engine_client, @saved_scenario, current_user.name, scenario_user_params + engine_client(@saved_scenario.version), + @saved_scenario, + current_user.name, + scenario_user_params ) if result.successful? @@ -71,7 +74,7 @@ def create # PUT /saved_scenarios/:saved_scenario_id/users/:id def update result = UpdateSavedScenarioUser.call( - engine_client, + engine_client(@saved_scenario.version), @saved_scenario, @saved_scenario_user, scenario_user_params[:role_id]&.to_i @@ -110,7 +113,11 @@ def confirm_destroy # # PUT /saved_scenarios/:saved_scenario_id/users/:id def destroy - result = DestroySavedScenarioUser.call(engine_client, @saved_scenario, @saved_scenario_user) + result = DestroySavedScenarioUser.call( + engine_client(@saved_scenario.version), + @saved_scenario, + @saved_scenario_user + ) if result.successful? @saved_scenario.reload diff --git a/app/controllers/saved_scenarios_controller.rb b/app/controllers/saved_scenarios_controller.rb index 17d3c9a..8a17a8c 100644 --- a/app/controllers/saved_scenarios_controller.rb +++ b/app/controllers/saved_scenarios_controller.rb @@ -114,7 +114,7 @@ def publish @saved_scenario.update(private: false) ApiScenario::UpdatePrivacy.call_with_ids( - engine_client, + engine_client(@saved_scenario.version), @saved_scenario.all_scenario_ids, private: false ) @@ -127,7 +127,7 @@ def unpublish @saved_scenario.update(private: true) ApiScenario::UpdatePrivacy.call_with_ids( - engine_client, + engine_client(@saved_scenario.version), @saved_scenario.all_scenario_ids, private: true ) diff --git a/app/controllers/users/registrations_controller.rb b/app/controllers/users/registrations_controller.rb index 67592f1..abdfa66 100644 --- a/app/controllers/users/registrations_controller.rb +++ b/app/controllers/users/registrations_controller.rb @@ -57,7 +57,6 @@ def configure_account_update_params # Check if the user is already signed in and redirect back to client or to root. def check_already_authenticated return unless user_signed_in? - redirect_uri = session[:redirect_url].chomp('/') token = MyEtm::Auth.user_jwt(current_user, client_id: params[:client_id]) redirect_url = URI(params[:redirect_url] || root_path) redirect_url.query = URI.encode_www_form(token: token) diff --git a/app/models/version.rb b/app/models/version.rb index 854d3f0..ff5151c 100644 --- a/app/models/version.rb +++ b/app/models/version.rb @@ -1,13 +1,13 @@ # frozen_string_literal: true +# TODO: port to db and hook into OAuth apps. This is a mess and not nice to keep up for beta and pro! # A valid version of the ETM class Version URL = "energytransitionmodel.com".freeze - DEFAULT_TAG = Rails.env.development? ? "local" : "latest" # Default to "local" in development + DEFAULT_TAG = "latest" # Tag => prefix LIST = { - "local" => "", "latest" => "", "stable.01" => "stable.", "stable.02" => "stable2." @@ -58,7 +58,7 @@ def self.build_url(context, tag) tag ||= DEFAULT_TAG raise ArgumentError, "Invalid version tag: #{tag}" unless LIST.key?(tag) - if tag == "local" + if Rails.env.development? LOCAL_URLS[context] else "https://#{LIST[tag]}#{context == 'model' ? '' : "#{context}."}#{URL}" diff --git a/app/views/layouts/_buttons.html.haml b/app/views/layouts/_buttons.html.haml index c1df0c8..78ac6d2 100644 --- a/app/views/layouts/_buttons.html.haml +++ b/app/views/layouts/_buttons.html.haml @@ -1,5 +1,5 @@ .flex.py-5 .flex.basis-full{class: 'lg:basis-3/4'} - - if cookies[:last_visited_page].present? + - if cookies[:etm_last_visited_page].present? .bg-gray-100.p-2.px-5.mr-0.ml-auto.rounded-md - = link_to t('continue_working'), last_visited_page_path, class: 'continue-button' + = link_to t('continue_working'), back_to_etm_path, class: 'continue-button' diff --git a/app/views/layouts/_sidebar.html.haml b/app/views/layouts/_sidebar.html.haml index a7d9000..db0e301 100644 --- a/app/views/layouts/_sidebar.html.haml +++ b/app/views/layouts/_sidebar.html.haml @@ -1,6 +1,5 @@ .sidebar.fixed.top-0.bottom-0.overflow-y-auto.bg-midnight-300{class: 'lg:left-0 w-[300px]'} - -# Where does the logo refer to? REMEMBER LAST VERSION IN COOKIE - %a.logo.p-5.mb-3.inline-block.w-full.text-midnight-800{href: Version.model_url(current_version_tag || "latest")} + %a.logo.p-5.mb-3.inline-block.w-full.text-midnight-800{href: Version.model_url(active_version_tag)} = image_tag 'header/logo-round.png', class: 'h-8 inline mb-1 mr-2 hover:animate-spin' %span Energy Transition Model diff --git a/config/routes.rb b/config/routes.rb index 50cf62d..4cf8895 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -13,7 +13,7 @@ mount Sidekiq::Web => '/sidekiq' end - get '/last_visited_page', to: 'application#last_visited_page', as: :last_visited_page + get '/passthru/last', to: 'passthru#last', as: :back_to_etm namespace :identity do get '/', to: redirect('/identity/profile') diff --git a/lib/myetm/auth.rb b/lib/myetm/auth.rb index cf1e66c..f110f16 100644 --- a/lib/myetm/auth.rb +++ b/lib/myetm/auth.rb @@ -53,29 +53,29 @@ def user_jwt(user = nil, scopes: [], client_id: nil) end # Returns a Faraday client for a user, which will send requests to the specified client app. - def client_app_client(user, client_app) - client_app_client ||= begin - Faraday.new(client_app.uri) do |conn| - conn.request(:authorization, "Bearer", -> { - user_jwt(user, scopes: client_app.scopes, client_id: client_app.uid) }) - conn.request(:json) - conn.response(:json) - conn.response(:raise_error) - end + def client_for(user, client_app) + Faraday.new(client_app.uri) do |conn| + conn.request( + :authorization, + "Bearer", + -> { user_jwt(user, scopes: client_app.scopes, client_id: client_app.uid) } + ) + conn.request(:json) + conn.response(:json) + conn.response(:raise_error) end end - # TODO: Refactor usage to include the version_tag def engine_client(user, version_tag = Version::DEFAULT_TAG) uri = Version.engine_url(version_tag) engine = OAuthApplication.find_by(uri: uri) - client_app_client(user, engine) + client_for(user, engine) end def model_client(user, version_tag = Version::DEFAULT_TAG) uri = Version.model_url(version_tag) model = OAuthApplication.find_by(uri: uri) - client_app_client(user, model) + client_for(user, model) end # Checks if the token is in JWT format @@ -115,6 +115,6 @@ def verify_claims(decoded_token) end module_function :decode, :jwt_format?, :verify_claims, :signing_key_content, :user_jwt, - :signing_key, :model_client, :engine_client, :client_app_client + :signing_key, :model_client, :engine_client, :client_for end end diff --git a/spec/controllers/collections_controller_spec.rb b/spec/controllers/collections_controller_spec.rb index a547e81..5ff043d 100644 --- a/spec/controllers/collections_controller_spec.rb +++ b/spec/controllers/collections_controller_spec.rb @@ -26,7 +26,7 @@ end it 'redirects to the collection' do - post :create_transition, params: { collection: {saved_scenario_ids: scenario.id }} + post :create_transition, params: { collection: {saved_scenario_ids: scenario.id, version: Version.tags.last }} expect(response).to redirect_to( collection_path(Collection.last) diff --git a/spec/requests/saved_scenarios_spec.rb b/spec/requests/saved_scenarios_spec.rb index 5e1fff8..81d8cb5 100644 --- a/spec/requests/saved_scenarios_spec.rb +++ b/spec/requests/saved_scenarios_spec.rb @@ -38,7 +38,7 @@ let(:admin) { FactoryBot.create(:admin) } let!(:admin_scenario) { FactoryBot.create(:saved_scenario, user: admin, id: 648696) } - before { allow(MyEtm::Auth).to receive(:client_app_client).and_return(client) } + before { allow(MyEtm::Auth).to receive(:client_for).and_return(client) } describe "GET /index" do before do From ea313eb8202dc6b9c86c7aa8a3bd787efeecff9c Mon Sep 17 00:00:00 2001 From: noracato Date: Fri, 10 Jan 2025 09:56:28 +0100 Subject: [PATCH 3/3] Engine client should take scopes from accesstoken if provided --- .../api/v1/saved_scenarios_controller.rb | 2 +- lib/myetm/auth.rb | 18 ++++++++++++++---- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/app/controllers/api/v1/saved_scenarios_controller.rb b/app/controllers/api/v1/saved_scenarios_controller.rb index 8cd59de..2116f06 100644 --- a/app/controllers/api/v1/saved_scenarios_controller.rb +++ b/app/controllers/api/v1/saved_scenarios_controller.rb @@ -68,7 +68,7 @@ def saved_scenario_params end def engine_client - MyEtm::Auth.engine_client(current_user, active_version_tag) + MyEtm::Auth.engine_client(current_user, active_version_tag, scopes: doorkeeper_token.scopes) end def active_version_tag diff --git a/lib/myetm/auth.rb b/lib/myetm/auth.rb index f110f16..bd3c610 100644 --- a/lib/myetm/auth.rb +++ b/lib/myetm/auth.rb @@ -53,12 +53,17 @@ def user_jwt(user = nil, scopes: [], client_id: nil) end # Returns a Faraday client for a user, which will send requests to the specified client app. - def client_for(user, client_app) + # + # If scopes are specified (e.g. from an access token) these scopes are granted + # Otherwise the configured app scopes are used + def client_for(user, client_app, scopes: []) + scopes = scopes.empty? ? client_app.scopes : scopes + Faraday.new(client_app.uri) do |conn| conn.request( :authorization, "Bearer", - -> { user_jwt(user, scopes: client_app.scopes, client_id: client_app.uid) } + -> { user_jwt(user, scopes: scopes, client_id: client_app.uid) } ) conn.request(:json) conn.response(:json) @@ -66,12 +71,17 @@ def client_for(user, client_app) end end - def engine_client(user, version_tag = Version::DEFAULT_TAG) + # Returns a Faraday client for a version of ETEngine + # + # If scopes are specified (e.g. from an access token) these scopes are granted + # Otherwise the configured app scopes are used + def engine_client(user, version_tag = Version::DEFAULT_TAG, scopes: []) uri = Version.engine_url(version_tag) engine = OAuthApplication.find_by(uri: uri) - client_for(user, engine) + client_for(user, engine, scopes: scopes) end + # Returns a Faraday client for a version of ETModel def model_client(user, version_tag = Version::DEFAULT_TAG) uri = Version.model_url(version_tag) model = OAuthApplication.find_by(uri: uri)