Class: PartyProfileImageLookupService

Inherits:
Object
  • Object
show all
Defined in:
app/services/party_profile_image_lookup_service.rb

Overview

Service to lookup and attach profile images for Customers and Contacts.

For Customers (companies):
Uses Logo.dev API to fetch company logos based on domain

For Contacts (people):

  1. Tries Gravatar based on email
  2. Falls back to parent customer's company logo

Requires a Logo.dev API key in encrypted credentials, accessed via
Heatwave::Configuration.fetch(:logo_dev, :publishable_key):
logo_dev:
publishable_key: pk_xxx...

Examples:

Basic usage

PartyProfileImageLookupService.new(customer).call

Force refresh

PartyProfileImageLookupService.new(customer, force: true).call

Constant Summary collapse

LOGO_DEV_URL =

URL for logo dev.

'https://img.logo.dev'
GRAVATAR_URL =

URL for gravatar.

'https://www.gravatar.com/avatar'
HTTP_TIMEOUT =

seconds

5
AVATAR_SOURCES =

Sources that produce per-party avatar images. Anything outside this
set is normalized to logo_dev so a caller passing a provider key
(e.g. 'linkedin') cannot bypass classification and end up tagged as
both a logo and a social-login avatar.

%w[gravatar social_login].freeze

Instance Method Summary collapse

Constructor Details

#initialize(party, force: false, logger: nil) ⇒ PartyProfileImageLookupService

Returns a new instance of PartyProfileImageLookupService.

Parameters:

  • party (Customer, Contact)

    The party to lookup an image for

  • force (Boolean) (defaults to: false)

    Force refresh even if image already exists

  • logger (Logger) (defaults to: nil)

    Optional logger for debugging



39
40
41
42
43
# File 'app/services/party_profile_image_lookup_service.rb', line 39

def initialize(party, force: false, logger: nil)
  @party = party
  @force = force
  @logger = logger || Rails.logger
end

Instance Method Details

#attach_from_url(image_url, source: 'social_login') ⇒ Image?

Attach a profile image from a known URL — used by the social-login flow
where the OmniAuth provider hands us a hosted profile picture URL
(Facebook, Google, LinkedIn). Apple does not provide one. Skips when
force is false and the party already has an image so a returning OAuth
user doesn't have their custom-uploaded avatar overwritten.

The URL is caller-controlled (the worker forwards whatever omniauth
produced), so validate scheme + host before handing it to the image
fetch path — defense against a compromised provider response or
man-in-the-middle that points us at internal/loopback services
(basic SSRF guard).

Parameters:

  • image_url (String)

    Direct URL to the profile image

  • source (String) (defaults to: 'social_login')

    Source tag for the image (default: 'social_login')

Returns:



72
73
74
75
76
77
78
# File 'app/services/party_profile_image_lookup_service.rb', line 72

def attach_from_url(image_url, source: 'social_login')
  return nil if image_url.blank?
  return nil unless should_lookup?
  return nil unless safe_remote_image_url?(image_url)

  attach_image(image_url, "#{source}-#{party.id}", source: source)
end

#callImage?

Perform the lookup and attach image if found

Returns:

  • (Image, nil)

    The attached image or nil if not found



47
48
49
50
51
52
53
54
55
# File 'app/services/party_profile_image_lookup_service.rb', line 47

def call
  return nil unless should_lookup?

  if party.is_a?(Contact)
    lookup_contact_image
  else
    
  end
end