Skip to content

Conversation

@louispt1
Copy link
Contributor

@louispt1 louispt1 commented Dec 29, 2025

Description

Implements a pass-through API that proxies SavedScenario user management requests to MyETM.
These changes, along with this Myetm PR allow users to manage roles on SavedScenarios via the Engine, and solidify the user coupling functionality so accounts are properly coupled based on the callback actions in MyETM.

Key changes:

  • SavedScenarioUsersController with full CRUD endpoints for bulk user operations (/api/v3/saved_scenarios/:id/users)
  • Scenario#copy_roles_from_saved_scenario to replicate user permissions when creating scenarios from presets
  • ETEngine::MyETM module for a pre-configured Faraday client (mimicking setup in MyETM --> We can re-use the my_etm_client for other similar Faraday calls)
  • Test coverage for the changes

Still to do

  • Document SavedScenarioUsers CRUD endpoints

Relevant for this pyetm PR

Closes #1687

@louispt1 louispt1 force-pushed the saved-scenario-users branch from ded041a to 2e950cc Compare December 29, 2025 14:12
@louispt1 louispt1 force-pushed the saved-scenario-users branch 2 times, most recently from 29cf8e2 to ec68d83 Compare December 30, 2025 13:29
@louispt1 louispt1 marked this pull request as draft December 30, 2025 13:36
@louispt1 louispt1 force-pushed the saved-scenario-users branch from ec68d83 to a180647 Compare December 30, 2025 14:08
Copy link
Member

@noracato noracato left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding all CRUD operations is a great idea.

Let's get a clear grip on who does what, and who holds the truth in the end. Like you said for SavedScenarios it should be myETM who's in control. Maybe we can draft a diagram about interactions and which app has which initiative.

Comment on lines +382 to +412
def copy_roles_from_saved_scenario
saved_scenario_id = fetch_saved_scenario_id_for(parent.id)
return false unless saved_scenario_id

users_data = fetch_saved_scenario_users(saved_scenario_id)
return false unless users_data

users_data.each do |user_data|
scenario_users.create(
user_id: user_data['user_id'],
user_email: user_data['user_email'],
role_id: user_data['role_id']
)
end

true
rescue StandardError
false
end

def fetch_saved_scenario_id_for(scenario_id)
scenario = Scenario.find_by(id: scenario_id)
scenario&.metadata&.dig('saved_scenario_id')
end

def fetch_saved_scenario_users(saved_scenario_id)
response = ETEngine::MyEtm.client.get("/api/v1/saved_scenarios/#{saved_scenario_id}/users")
response.success? ? response.body : nil
rescue Faraday::Error
nil
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's rethink this.

  1. This feels more like a service or job, not core to the model. Mainly because it includes an API call to a resource which is potentially not owned by the user.
  2. The scenario can possibly belong to multiple saved scenarios. Where lies the truth: like you said this should be dictated by myETM, and indications about roles should then come from myETM, not from within the engine.

Comment on lines +3 to +18
module ETEngine
# Handles communication with MyETM API.
module MyEtm
module_function

# Returns a Faraday client configured to communicate with MyETM.
def client
@client ||= Faraday.new(url: Settings.identity.issuer) do |conn|
conn.request(:json)
conn.response(:json)
conn.response(:raise_error)
conn.options.timeout = 5
end
end
end
end
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering about the use case of interacting with myETM not on behalf of the user.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Saved Scenario User Passthrough to myetm

3 participants