diff --git a/app/controllers/settings/hostings_controller.rb b/app/controllers/settings/hostings_controller.rb index 07aaa5b10..2fb0c9df7 100644 --- a/app/controllers/settings/hostings_controller.rb +++ b/app/controllers/settings/hostings_controller.rb @@ -10,10 +10,26 @@ class Settings::HostingsController < ApplicationController [ "Home", root_path ], [ "Self-Hosting", nil ] ] - twelve_data_provider = Provider::Registry.get_provider(:twelve_data) - @twelve_data_usage = twelve_data_provider&.usage - @yahoo_finance_provider = Provider::Registry.get_provider(:yahoo_finance) + # Determine which providers are currently selected + exchange_rate_provider = ENV["EXCHANGE_RATE_PROVIDER"].presence || Setting.exchange_rate_provider + securities_provider = ENV["SECURITIES_PROVIDER"].presence || Setting.securities_provider + + # Show Twelve Data settings if either provider is set to twelve_data + @show_twelve_data_settings = exchange_rate_provider == "twelve_data" || securities_provider == "twelve_data" + + # Show Yahoo Finance settings if either provider is set to yahoo_finance + @show_yahoo_finance_settings = exchange_rate_provider == "yahoo_finance" || securities_provider == "yahoo_finance" + + # Only fetch provider data if we're showing the section + if @show_twelve_data_settings + twelve_data_provider = Provider::Registry.get_provider(:twelve_data) + @twelve_data_usage = twelve_data_provider&.usage + end + + if @show_yahoo_finance_settings + @yahoo_finance_provider = Provider::Registry.get_provider(:yahoo_finance) + end end def update @@ -34,6 +50,14 @@ class Settings::HostingsController < ApplicationController Setting.twelve_data_api_key = hosting_params[:twelve_data_api_key] end + if hosting_params.key?(:exchange_rate_provider) + Setting.exchange_rate_provider = hosting_params[:exchange_rate_provider] + end + + if hosting_params.key?(:securities_provider) + Setting.securities_provider = hosting_params[:securities_provider] + end + if hosting_params.key?(:openai_access_token) token_param = hosting_params[:openai_access_token].to_s.strip # Ignore blanks and redaction placeholders to prevent accidental overwrite @@ -71,7 +95,7 @@ class Settings::HostingsController < ApplicationController private def hosting_params - params.require(:setting).permit(:onboarding_state, :require_email_confirmation, :brand_fetch_client_id, :twelve_data_api_key, :openai_access_token, :openai_uri_base, :openai_model) + params.require(:setting).permit(:onboarding_state, :require_email_confirmation, :brand_fetch_client_id, :twelve_data_api_key, :openai_access_token, :openai_uri_base, :openai_model, :exchange_rate_provider, :securities_provider) end def ensure_admin diff --git a/app/models/exchange_rate/provided.rb b/app/models/exchange_rate/provided.rb index 4235bba83..6eadf92b8 100644 --- a/app/models/exchange_rate/provided.rb +++ b/app/models/exchange_rate/provided.rb @@ -3,7 +3,7 @@ module ExchangeRate::Provided class_methods do def provider - provider = ENV["EXCHANGE_RATE_PROVIDER"] || "twelve_data" + provider = ENV["EXCHANGE_RATE_PROVIDER"].presence || Setting.exchange_rate_provider registry = Provider::Registry.for_concept(:exchange_rates) registry.get_provider(provider.to_sym) end diff --git a/app/models/security/provided.rb b/app/models/security/provided.rb index 4ff84425e..58b7f50e6 100644 --- a/app/models/security/provided.rb +++ b/app/models/security/provided.rb @@ -5,7 +5,7 @@ module Security::Provided class_methods do def provider - provider = ENV["SECURITIES_PROVIDER"] || "twelve_data" + provider = ENV["SECURITIES_PROVIDER"].presence || Setting.securities_provider registry = Provider::Registry.for_concept(:securities) registry.get_provider(provider.to_sym) end diff --git a/app/models/setting.rb b/app/models/setting.rb index 4a1139704..94a2bdfc1 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -11,6 +11,10 @@ class Setting < RailsSettings::Base field :openai_model, type: :string, default: ENV["OPENAI_MODEL"] field :brand_fetch_client_id, type: :string, default: ENV["BRAND_FETCH_CLIENT_ID"] + # Provider selection + field :exchange_rate_provider, type: :string, default: ENV.fetch("EXCHANGE_RATE_PROVIDER", "twelve_data") + field :securities_provider, type: :string, default: ENV.fetch("SECURITIES_PROVIDER", "twelve_data") + # Dynamic fields are now stored as individual entries with "dynamic:" prefix # This prevents race conditions and ensures each field is independently managed diff --git a/app/views/settings/hostings/_provider_selection.html.erb b/app/views/settings/hostings/_provider_selection.html.erb new file mode 100644 index 000000000..55dde1e88 --- /dev/null +++ b/app/views/settings/hostings/_provider_selection.html.erb @@ -0,0 +1,51 @@ +
+
+

<%= t(".title") %>

+

<%= t(".description") %>

+
+ + <%= styled_form_with model: Setting.new, + url: settings_hosting_path, + method: :patch, + data: { + controller: "auto-submit-form", + "auto-submit-form-trigger-event-value": "change" + } do |form| %> +
+ <%= form.select :exchange_rate_provider, + [ + [t(".providers.twelve_data"), "twelve_data"], + [t(".providers.yahoo_finance"), "yahoo_finance"] + ], + { label: t(".exchange_rate_provider_label") }, + { + value: ENV.fetch("EXCHANGE_RATE_PROVIDER", Setting.exchange_rate_provider), + disabled: ENV["EXCHANGE_RATE_PROVIDER"].present?, + data: { "auto-submit-form-target": "auto" } + } %> + + <%= form.select :securities_provider, + [ + [t(".providers.twelve_data"), "twelve_data"], + [t(".providers.yahoo_finance"), "yahoo_finance"] + ], + { label: t(".securities_provider_label") }, + { + value: ENV.fetch("SECURITIES_PROVIDER", Setting.securities_provider), + disabled: ENV["SECURITIES_PROVIDER"].present?, + data: { "auto-submit-form-target": "auto" } + } %> +
+ + <% if ENV["EXCHANGE_RATE_PROVIDER"].present? || ENV["SECURITIES_PROVIDER"].present? %> +
+
+ <%= icon("alert-circle", class: "w-5 h-5 text-warning-600 mt-0.5 shrink-0") %> +

+ <%= t(".env_configured_message") %> +

+
+
+ <% end %> + <% end %> +
diff --git a/app/views/settings/hostings/_yahoo_finance_settings.html.erb b/app/views/settings/hostings/_yahoo_finance_settings.html.erb index 4bd496945..33676f547 100644 --- a/app/views/settings/hostings/_yahoo_finance_settings.html.erb +++ b/app/views/settings/hostings/_yahoo_finance_settings.html.erb @@ -6,7 +6,7 @@ <% if @yahoo_finance_provider&.healthy? %>
-
+

<%= t(".status_active") %>

@@ -15,18 +15,19 @@ <% else %>
-
+

<%= t(".status_inactive") %>

-
-
-
-

+
+
+ <%= icon("alert-circle", class: "w-5 h-5 text-destructive-600 mt-0.5 shrink-0") %> +
+

<%= t(".connection_failed") %>

-
+

<%= t(".troubleshooting") %>

diff --git a/app/views/settings/hostings/show.html.erb b/app/views/settings/hostings/show.html.erb index b406d67d3..0d67f4436 100644 --- a/app/views/settings/hostings/show.html.erb +++ b/app/views/settings/hostings/show.html.erb @@ -7,8 +7,13 @@ <% end %> <%= settings_section title: t(".financial_data_providers") do %>
- <%= render "settings/hostings/yahoo_finance_settings" %> - <%= render "settings/hostings/twelve_data_settings" %> + <%= render "settings/hostings/provider_selection" %> + <% if @show_yahoo_finance_settings %> + <%= render "settings/hostings/yahoo_finance_settings" %> + <% end %> + <% if @show_twelve_data_settings %> + <%= render "settings/hostings/twelve_data_settings" %> + <% end %>
<% end %> <%= settings_section title: t(".invites") do %> diff --git a/config/locales/views/settings/hostings/en.yml b/config/locales/views/settings/hostings/en.yml index 1751c79cf..1e7c83059 100644 --- a/config/locales/views/settings/hostings/en.yml +++ b/config/locales/views/settings/hostings/en.yml @@ -25,6 +25,15 @@ en: confirm_clear_cache: title: Clear data cache? body: Are you sure you want to clear the data cache? This will remove all exchange rates, security prices, account balances, and other data. This action cannot be undone. + provider_selection: + title: Provider Selection + description: Choose which service to use for fetching exchange rates and security prices. Yahoo Finance is free and doesn't require an API key. Twelve Data requires a free API key but may offer more data coverage. + exchange_rate_provider_label: Exchange Rate Provider + securities_provider_label: Securities (Stock Prices) Provider + env_configured_message: Provider selection is disabled because environment variables (EXCHANGE_RATE_PROVIDER or SECURITIES_PROVIDER) are set. To enable selection here, remove these environment variables from your configuration. + providers: + twelve_data: Twelve Data + yahoo_finance: Yahoo Finance brand_fetch_settings: description: Enter the Client ID provided by Brand Fetch label: Client ID