diff --git a/app/controllers/settings/hostings_controller.rb b/app/controllers/settings/hostings_controller.rb index dd4024d7b..02e61350e 100644 --- a/app/controllers/settings/hostings_controller.rb +++ b/app/controllers/settings/hostings_controller.rb @@ -46,6 +46,10 @@ class Settings::HostingsController < ApplicationController Setting.brand_fetch_client_id = hosting_params[:brand_fetch_client_id] end + if hosting_params.key?(:brand_fetch_high_res_logos) + Setting.brand_fetch_high_res_logos = hosting_params[:brand_fetch_high_res_logos] == "1" + end + if hosting_params.key?(:twelve_data_api_key) Setting.twelve_data_api_key = hosting_params[:twelve_data_api_key] end @@ -126,7 +130,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, :openai_json_mode, :exchange_rate_provider, :securities_provider, :syncs_include_pending, :auto_sync_enabled, :auto_sync_time) + params.require(:setting).permit(:onboarding_state, :require_email_confirmation, :brand_fetch_client_id, :brand_fetch_high_res_logos, :twelve_data_api_key, :openai_access_token, :openai_uri_base, :openai_model, :openai_json_mode, :exchange_rate_provider, :securities_provider, :syncs_include_pending, :auto_sync_enabled, :auto_sync_time) end def ensure_admin diff --git a/app/models/family/auto_merchant_detector.rb b/app/models/family/auto_merchant_detector.rb index c37a4f7b7..708553bba 100644 --- a/app/models/family/auto_merchant_detector.rb +++ b/app/models/family/auto_merchant_detector.rb @@ -126,7 +126,8 @@ class Family::AutoMerchantDetector def build_logo_url(business_url) return nil unless Setting.brand_fetch_client_id.present? && business_url.present? - "#{default_logo_provider_url}/#{business_url}/icon/fallback/lettermark/w/40/h/40?c=#{Setting.brand_fetch_client_id}" + size = Setting.brand_fetch_logo_size + "#{default_logo_provider_url}/#{business_url}/icon/fallback/lettermark/w/#{size}/h/#{size}?c=#{Setting.brand_fetch_client_id}" end def enhance_provider_merchant(merchant, auto_detection) @@ -138,7 +139,8 @@ class Family::AutoMerchantDetector # Add logo if BrandFetch is configured if Setting.brand_fetch_client_id.present? - updates[:logo_url] = "#{default_logo_provider_url}/#{auto_detection.business_url}/icon/fallback/lettermark/w/40/h/40?c=#{Setting.brand_fetch_client_id}" + size = Setting.brand_fetch_logo_size + updates[:logo_url] = "#{default_logo_provider_url}/#{auto_detection.business_url}/icon/fallback/lettermark/w/#{size}/h/#{size}?c=#{Setting.brand_fetch_client_id}" end end diff --git a/app/models/family_merchant.rb b/app/models/family_merchant.rb index 314ba1ebb..3baec76bb 100644 --- a/app/models/family_merchant.rb +++ b/app/models/family_merchant.rb @@ -21,7 +21,8 @@ class FamilyMerchant < Merchant def generate_logo_url_from_website if website_url.present? && Setting.brand_fetch_client_id.present? domain = extract_domain(website_url) - self.logo_url = "https://cdn.brandfetch.io/#{domain}/icon/fallback/lettermark/w/40/h/40?c=#{Setting.brand_fetch_client_id}" + size = Setting.brand_fetch_logo_size + self.logo_url = "https://cdn.brandfetch.io/#{domain}/icon/fallback/lettermark/w/#{size}/h/#{size}?c=#{Setting.brand_fetch_client_id}" elsif website_url.blank? self.logo_url = nil end diff --git a/app/models/security.rb b/app/models/security.rb index d9e67bcfa..35c2a3876 100644 --- a/app/models/security.rb +++ b/app/models/security.rb @@ -7,6 +7,7 @@ class Security < ApplicationRecord EXCHANGES = YAML.safe_load_file(Rails.root.join("config", "exchanges.yml")).freeze before_validation :upcase_symbols + before_save :generate_logo_url_from_brandfetch, if: :should_generate_logo? has_many :trades, dependent: :nullify, class_name: "Trade" has_many :prices, dependent: :destroy @@ -42,13 +43,18 @@ class Security < ApplicationRecord ) end - def brandfetch_icon_url(width: 40, height: 40) - return nil unless Setting.brand_fetch_client_id.present? && website_url.present? + def brandfetch_icon_url(width: nil, height: nil) + return nil unless Setting.brand_fetch_client_id.present? - domain = extract_domain(website_url) - return nil unless domain.present? + w = width || Setting.brand_fetch_logo_size + h = height || Setting.brand_fetch_logo_size - "https://cdn.brandfetch.io/#{domain}/icon/fallback/lettermark/w/#{width}/h/#{height}?c=#{Setting.brand_fetch_client_id}" + identifier = extract_domain(website_url) if website_url.present? + identifier ||= ticker + + return nil unless identifier.present? + + "https://cdn.brandfetch.io/#{identifier}/icon/fallback/lettermark/w/#{w}/h/#{h}?c=#{Setting.brand_fetch_client_id}" end private @@ -65,4 +71,18 @@ class Security < ApplicationRecord self.ticker = ticker.upcase self.exchange_operating_mic = exchange_operating_mic.upcase if exchange_operating_mic.present? end + + def should_generate_logo? + url = brandfetch_icon_url + return false unless url.present? + + return true if logo_url.blank? + return false unless logo_url.include?("cdn.brandfetch.io") + + website_url_changed? || ticker_changed? + end + + def generate_logo_url_from_brandfetch + self.logo_url = brandfetch_icon_url + end end diff --git a/app/models/setting.rb b/app/models/setting.rb index 4407d7293..857949b5a 100644 --- a/app/models/setting.rb +++ b/app/models/setting.rb @@ -11,6 +11,23 @@ class Setting < RailsSettings::Base field :openai_model, type: :string, default: ENV["OPENAI_MODEL"] field :openai_json_mode, type: :string, default: ENV["LLM_JSON_MODE"] field :brand_fetch_client_id, type: :string, default: ENV["BRAND_FETCH_CLIENT_ID"] + field :brand_fetch_high_res_logos, type: :boolean, default: ENV.fetch("BRAND_FETCH_HIGH_RES_LOGOS", "false") == "true" + + BRAND_FETCH_LOGO_SIZE_STANDARD = 40 + BRAND_FETCH_LOGO_SIZE_HIGH_RES = 120 + BRAND_FETCH_URL_PATTERN = %r{(https://cdn\.brandfetch\.io/[^/]+/icon/fallback/lettermark/)w/\d+/h/\d+(\?c=.+)} + + def self.brand_fetch_logo_size + brand_fetch_high_res_logos ? BRAND_FETCH_LOGO_SIZE_HIGH_RES : BRAND_FETCH_LOGO_SIZE_STANDARD + end + + # Transforms a stored Brandfetch URL to use the current logo size setting + def self.transform_brand_fetch_url(url) + return url unless url.present? && url.match?(BRAND_FETCH_URL_PATTERN) + + size = brand_fetch_logo_size + url.gsub(BRAND_FETCH_URL_PATTERN, "\\1w/#{size}/h/#{size}\\2") + end # Provider selection field :exchange_rate_provider, type: :string, default: ENV.fetch("EXCHANGE_RATE_PROVIDER", "twelve_data") diff --git a/app/views/accounts/_logo.html.erb b/app/views/accounts/_logo.html.erb index 2d609cf29..8c4d9c433 100644 --- a/app/views/accounts/_logo.html.erb +++ b/app/views/accounts/_logo.html.erb @@ -8,7 +8,8 @@ } %> <% if account.institution_domain.present? && Setting.brand_fetch_client_id.present? %> - <%= image_tag "https://cdn.brandfetch.io/#{account.institution_domain}/icon/fallback/lettermark/w/40/h/40?c=#{Setting.brand_fetch_client_id}", class: "shrink-0 rounded-full #{size_classes[size]}" %> + <% logo_size = Setting.brand_fetch_logo_size %> + <%= image_tag "https://cdn.brandfetch.io/#{account.institution_domain}/icon/fallback/lettermark/w/#{logo_size}/h/#{logo_size}?c=#{Setting.brand_fetch_client_id}", class: "shrink-0 rounded-full #{size_classes[size]}" %> <% elsif account.logo_url.present? %> <%= image_tag account.logo_url, class: "shrink-0 rounded-full #{size_classes[size]}", loading: "lazy" %> <% elsif account.logo.attached? %> diff --git a/app/views/family_merchants/_family_merchant.html.erb b/app/views/family_merchants/_family_merchant.html.erb index cb546e098..8e3306df7 100644 --- a/app/views/family_merchants/_family_merchant.html.erb +++ b/app/views/family_merchants/_family_merchant.html.erb @@ -5,7 +5,7 @@
<%= t(".high_res_label") %>
+<%= t(".high_res_description") %>
+