mirror of
https://github.com/we-promise/sure.git
synced 2026-04-19 12:04:08 +00:00
Implement a setting to retrieve high res logos (#725)
* Implement a setting to retrieve high res logos * Update _brand_fetch_settings.html.erb * Add fallback for stock tickers also to use Brandfetch * Update security.rb * Update toggle logic for high-res logos setting Signed-off-by: Juan José Mata <jjmata@jjmata.com> * Update security.rb * Update security.rb --------- Signed-off-by: Juan José Mata <jjmata@jjmata.com> Co-authored-by: Juan José Mata <jjmata@jjmata.com>
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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? %>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="flex w-full items-center gap-2.5">
|
||||
<% if family_merchant.logo_url %>
|
||||
<div class="w-8 h-8 rounded-full flex justify-center items-center">
|
||||
<%= image_tag family_merchant.logo_url, class: "w-8 h-8 rounded-full" %>
|
||||
<%= image_tag Setting.transform_brand_fetch_url(family_merchant.logo_url), class: "w-8 h-8 rounded-full" %>
|
||||
</div>
|
||||
<% else %>
|
||||
<%= render partial: "shared/color_avatar", locals: { name: family_merchant.name, color: family_merchant.color } %>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<div class="flex w-full items-center gap-2.5">
|
||||
<% if provider_merchant.logo_url %>
|
||||
<div class="w-8 h-8 rounded-full flex justify-center items-center">
|
||||
<%= image_tag provider_merchant.logo_url, class: "w-8 h-8 rounded-full" %>
|
||||
<%= image_tag Setting.transform_brand_fetch_url(provider_merchant.logo_url), class: "w-8 h-8 rounded-full" %>
|
||||
</div>
|
||||
<% else %>
|
||||
<div class="w-8 h-8 rounded-full flex items-center justify-center bg-container-inset text-secondary text-sm font-medium">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<%= content_tag :div, class: ["flex items-center gap-2"] do %>
|
||||
<% if recurring_transaction.merchant.present? %>
|
||||
<% if recurring_transaction.merchant.logo_url.present? %>
|
||||
<%= image_tag recurring_transaction.merchant.logo_url,
|
||||
<%= image_tag Setting.transform_brand_fetch_url(recurring_transaction.merchant.logo_url),
|
||||
class: "w-6 h-6 rounded-full",
|
||||
loading: "lazy" %>
|
||||
<% else %>
|
||||
|
||||
@@ -76,8 +76,10 @@
|
||||
<tr>
|
||||
<td class="px-4 py-3">
|
||||
<div class="flex items-center gap-3">
|
||||
<% if holding.security.logo_url.present? %>
|
||||
<img src="<%= holding.security.logo_url %>" alt="<%= holding.ticker %>" class="w-6 h-6 rounded-full">
|
||||
<% if holding.security.brandfetch_icon_url.present? %>
|
||||
<img src="<%= holding.security.brandfetch_icon_url %>" alt="<%= holding.ticker %>" class="w-6 h-6 rounded-full">
|
||||
<% elsif holding.security.logo_url.present? %>
|
||||
<img src="<%= Setting.transform_brand_fetch_url(holding.security.logo_url) %>" alt="<%= holding.ticker %>" class="w-6 h-6 rounded-full">
|
||||
<% else %>
|
||||
<div class="w-6 h-6 rounded-full bg-container flex items-center justify-center text-xs font-medium text-secondary">
|
||||
<%= holding.ticker[0..1] %>
|
||||
|
||||
@@ -39,4 +39,21 @@
|
||||
disabled: ENV["BRAND_FETCH_CLIENT_ID"].present?,
|
||||
data: { "auto-submit-form-target": "auto" } %>
|
||||
<% end %>
|
||||
|
||||
<div class="flex items-center justify-between mt-4">
|
||||
<div class="space-y-1">
|
||||
<p class="text-sm"><%= t(".high_res_label") %></p>
|
||||
<p class="text-secondary text-sm"><%= t(".high_res_description") %></p>
|
||||
</div>
|
||||
|
||||
<%= 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.toggle :brand_fetch_high_res_logos,
|
||||
checked: ENV["BRAND_FETCH_HIGH_RES_LOGOS"].present? ? ENV["BRAND_FETCH_HIGH_RES_LOGOS"] == "true" : Setting.brand_fetch_high_res_logos,
|
||||
disabled: ENV["BRAND_FETCH_HIGH_RES_LOGOS"].present?,
|
||||
data: { auto_submit_form_target: "auto" } %>
|
||||
<% end %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<%= content_tag :div, class: ["flex items-center gap-3 lg:gap-4"] do %>
|
||||
<div class="hidden lg:flex">
|
||||
<% if transaction.merchant&.logo_url.present? %>
|
||||
<%= image_tag transaction.merchant.logo_url,
|
||||
<%= image_tag Setting.transform_brand_fetch_url(transaction.merchant.logo_url),
|
||||
class: "w-9 h-9 rounded-full",
|
||||
loading: "lazy" %>
|
||||
<% else %>
|
||||
@@ -38,7 +38,7 @@
|
||||
<div class="flex md:hidden items-center gap-1 col-span-2 relative">
|
||||
<%= render "transactions/transaction_category", transaction: transaction, variant: "mobile" %>
|
||||
<% if transaction.merchant&.logo_url.present? %>
|
||||
<%= image_tag transaction.merchant.logo_url,
|
||||
<%= image_tag Setting.transform_brand_fetch_url(transaction.merchant.logo_url),
|
||||
class: "w-5 h-5 rounded-full absolute -bottom-1 -right-1 border border-secondary pointer-events-none",
|
||||
loading: "lazy" %>
|
||||
<% end %>
|
||||
|
||||
Reference in New Issue
Block a user