diff --git a/app/controllers/api/v3/scenarios_controller.rb b/app/controllers/api/v3/scenarios_controller.rb index 2a1afda70..6afd036d9 100644 --- a/app/controllers/api/v3/scenarios_controller.rb +++ b/app/controllers/api/v3/scenarios_controller.rb @@ -306,7 +306,8 @@ def update if final_params[:scenario].blank? authorize!(:read, @scenario) - elsif final_params[:scenario][:set_preset_roles].present? + elsif final_params[:scenario][:set_preset_roles].present? || + final_params[:scenario][:saved_scenario_users].present? authorize!(:destroy, @scenario) else authorize!(:update, @scenario) @@ -472,7 +473,8 @@ def scenario_params :set_preset_roles, :source, { user_values: {} }, - { metadata: {} } + { metadata: {} }, + { saved_scenario_users: %i[user_id user_email role_id] } ]) attrs = attrs[:scenario] || {} diff --git a/app/models/scenario.rb b/app/models/scenario.rb index 698c4e04f..ce6c5eb72 100644 --- a/app/models/scenario.rb +++ b/app/models/scenario.rb @@ -369,6 +369,25 @@ def copy_preset_roles copy_roles_from_parent end + # Upserts ScenarioUser records from an explicit list of user params. Used + # when MyETM pushes a SavedScenario's roles onto the underlying session. + def sync_users_from_params(user_params) + user_params.each do |entry| + entry = entry.with_indifferent_access + + if (existing = find_scenario_user_by(entry)) + existing.role_id = entry[:role_id] + existing.save(validate: false) + else + scenario_users.create!( + user_id: entry[:user_id].presence, + user_email: entry[:user_email].presence, + role_id: entry[:role_id] + ) + end + end + end + private def copy_roles_from_parent @@ -382,6 +401,12 @@ def copy_roles_from_parent end end + def find_scenario_user_by(entry) + return scenario_users.find_by(user_id: entry[:user_id]) if entry[:user_id] + + scenario_users.find_by(user_email: entry[:user_email]) if entry[:user_email] + end + # Validation method for when a user sets their metadata. def validate_metadata_size errors.add(:metadata, 'can not exceed 64Kb') if metadata.to_s.bytesize > 64.kilobytes diff --git a/app/models/scenario_updater.rb b/app/models/scenario_updater.rb index 8dd525072..cce2d9dae 100644 --- a/app/models/scenario_updater.rb +++ b/app/models/scenario_updater.rb @@ -74,8 +74,9 @@ def apply(scenario_data, (coupling_state, user_values, balanced_values)) # Post-save def post_save(scenario_data, persisted) - set_preset_roles = truthy?(scenario_data[:set_preset_roles]) - _post_saved = yield post_save_operations(set_preset_roles) + set_preset_roles = truthy?(scenario_data[:set_preset_roles]) + saved_scenario_users = scenario_data[:saved_scenario_users] + _post_saved = yield post_save_operations(set_preset_roles, saved_scenario_users) Success(persisted) end @@ -148,8 +149,8 @@ def persist_scenario(attributes) service(:PersistScenario).call(scenario, attributes, skip_validation) end - def post_save_operations(set_preset_roles) - service(:PostSaveOperations).call(scenario, set_preset_roles, current_user) + def post_save_operations(set_preset_roles, saved_scenario_users) + service(:PostSaveOperations).call(scenario, set_preset_roles, saved_scenario_users, current_user) end # Helper to instantiate services diff --git a/app/models/scenario_updater/services/post_save_operations.rb b/app/models/scenario_updater/services/post_save_operations.rb index 0cef220d9..800dac6a9 100644 --- a/app/models/scenario_updater/services/post_save_operations.rb +++ b/app/models/scenario_updater/services/post_save_operations.rb @@ -8,8 +8,9 @@ class PostSaveOperations TRUTHY_VALUES = Set.new([true, 'true', '1']).freeze - def call(scenario, set_preset_roles, current_user) + def call(scenario, set_preset_roles, saved_scenario_users, current_user) copy_preset_roles_if_requested(scenario, set_preset_roles) + sync_saved_scenario_users(scenario, saved_scenario_users) update_version_tag(scenario, current_user) Success(scenario) @@ -22,6 +23,12 @@ def copy_preset_roles_if_requested(scenario, set_preset_roles) scenario.copy_preset_roles if should_copy end + def sync_saved_scenario_users(scenario, saved_scenario_users) + return if saved_scenario_users.blank? + + scenario.sync_users_from_params(saved_scenario_users) + end + def update_version_tag(scenario, current_user) scenario.scenario_version_tag&.update(user: current_user) end diff --git a/app/models/scenario_updater/services/prepare_attributes.rb b/app/models/scenario_updater/services/prepare_attributes.rb index 93e2293a9..b54291b1c 100644 --- a/app/models/scenario_updater/services/prepare_attributes.rb +++ b/app/models/scenario_updater/services/prepare_attributes.rb @@ -18,7 +18,7 @@ def call(scenario, user_values, balanced_values, scenario_data) def filter_scenario_data(scenario, scenario_data) scenario_data - .except(:area_code, :end_year, :set_preset_roles, :user_values) + .except(:area_code, :end_year, :set_preset_roles, :saved_scenario_users, :user_values) .merge(metadata: metadata_to_apply(scenario, scenario_data)) end diff --git a/spec/models/scenario_updater/services/post_save_operations_spec.rb b/spec/models/scenario_updater/services/post_save_operations_spec.rb index 2ab46ac7a..5228d60ea 100644 --- a/spec/models/scenario_updater/services/post_save_operations_spec.rb +++ b/spec/models/scenario_updater/services/post_save_operations_spec.rb @@ -8,13 +8,13 @@ it 'copies preset roles if requested' do expect(scenario).to receive(:copy_preset_roles).with(no_args) - service.call(scenario, true, 'user') + service.call(scenario, true, '', 'user') end it 'updates version tag' do version_tag = double('VersionTag') allow(scenario).to receive(:scenario_version_tag).and_return(version_tag) expect(version_tag).to receive(:update).with(user: 'user') - service.call(scenario, false, 'user') + service.call(scenario, false, '', 'user') end end