chore: Ability to Disable Gravatars (#5027)

fixes: #3853

- Introduced DISABLE_GRAVATAR Global Config, which will stop chatwoot from making API requests to gravatar
- Cleaned up avatar-related logic and centralized it into the avatarable concern
- Added specs for the missing cases
- Added migration for existing installations to move the avatar to attachment, rather than making the API that results in 404.
This commit is contained in:
Sojan Jose
2022-07-21 19:27:12 +02:00
committed by GitHub
parent 6105567238
commit 6a6a37a67b
25 changed files with 225 additions and 83 deletions

View File

@@ -104,7 +104,7 @@ class ContactIdentifyAction
# TODO: replace reject { |_k, v| v.blank? } with compact_blank when rails is upgraded
@contact.discard_invalid_attrs if discard_invalid_attrs
@contact.save!
ContactAvatarJob.perform_later(@contact, params[:avatar_url]) if params[:avatar_url].present?
Avatar::AvatarFromUrlJob.perform_later(@contact, params[:avatar_url]) if params[:avatar_url].present?
end
def merge_contact(base_contact, merge_contact)

View File

@@ -23,7 +23,7 @@ class ContactBuilder
end
def update_contact_avatar(contact)
::ContactAvatarJob.perform_later(contact, contact_attributes[:avatar_url]) if contact_attributes[:avatar_url]
::Avatar::AvatarFromUrlJob.perform_later(contact, contact_attributes[:avatar_url]) if contact_attributes[:avatar_url]
end
def create_contact

View File

@@ -58,7 +58,7 @@ class Messages::Facebook::MessageBuilder < Messages::Messenger::MessageBuilder
return if contact_params[:remote_avatar_url].blank?
return if @contact.avatar.attached?
ContactAvatarJob.perform_later(@contact, contact_params[:remote_avatar_url])
Avatar::AvatarFromUrlJob.perform_later(@contact, contact_params[:remote_avatar_url])
end
def conversation

View File

@@ -90,9 +90,7 @@ class Api::V1::Accounts::CallbacksController < Api::V1::Accounts::BaseController
end
def set_avatar(facebook_inbox, page_id)
avatar_file = Down.download(
"http://graph.facebook.com/#{page_id}/picture?type=large"
)
facebook_inbox.avatar.attach(io: avatar_file, filename: avatar_file.original_filename, content_type: avatar_file.content_type)
avatar_url = "https://graph.facebook.com/#{page_id}/picture?type=large"
Avatar::AvatarFromUrlJob.perform_later(facebook_inbox, avatar_url)
end
end

View File

@@ -166,13 +166,7 @@ class Api::V1::Accounts::ContactsController < Api::V1::Accounts::BaseController
end
def process_avatar
if permitted_params[:avatar].blank? && permitted_params[:avatar_url].present?
::ContactAvatarJob.perform_later(@contact, params[:avatar_url])
elsif permitted_params[:avatar].blank? && permitted_params[:email].present?
hash = Digest::MD5.hexdigest(params[:email])
gravatar_url = "https://www.gravatar.com/avatar/#{hash}?d=404"
::ContactAvatarJob.perform_later(@contact, gravatar_url)
end
::Avatar::AvatarFromUrlJob.perform_later(@contact, params[:avatar_url]) if params[:avatar_url].present?
end
def render_error(error, error_status)

View File

@@ -0,0 +1,13 @@
class Avatar::AvatarFromGravatarJob < ApplicationJob
queue_as :low
def perform(avatarable, email)
return if GlobalConfigService.load('DISABLE_GRAVATAR', '').present?
return if email.blank?
return if avatarable.avatar_url.present?
hash = Digest::MD5.hexdigest(email)
gravatar_url = "https://www.gravatar.com/avatar/#{hash}?d=404"
Avatar::AvatarFromUrlJob.perform_later(avatarable, gravatar_url)
end
end

View File

@@ -0,0 +1,15 @@
class Avatar::AvatarFromUrlJob < ApplicationJob
queue_as :default
def perform(avatarable, avatar_url)
return unless avatarable.respond_to?(:avatar)
avatar_file = Down.download(
avatar_url,
max_size: 15 * 1024 * 1024
)
avatarable.avatar.attach(io: avatar_file, filename: avatar_file.original_filename, content_type: avatar_file.content_type)
rescue Down::NotFound, Down::Error => e
Rails.logger.error "Exception: invalid avatar url #{avatar_url} : #{e.message}"
end
end

View File

@@ -1,15 +0,0 @@
class ContactAvatarJob < ApplicationJob
queue_as :default
def perform(contact, avatar_url)
avatar_file = Down.download(
avatar_url,
max_size: 15 * 1024 * 1024
)
contact.avatar.attach(io: avatar_file, filename: avatar_file.original_filename, content_type: avatar_file.content_type)
rescue Down::NotFound
contact.avatar.attachment.destroy! if contact.avatar.attached?
rescue Down::Error => e
Rails.logger.error "Exception: invalid avatar url #{avatar_url} : #{e.message}"
end
end

View File

@@ -7,19 +7,24 @@ module Avatarable
included do
has_one_attached :avatar
validate :acceptable_avatar, if: -> { avatar.changed? }
after_save :fetch_avatar_from_gravatar
end
def avatar_url
return url_for(avatar.representation(resize: '250x250')) if avatar.attached? && avatar.representable?
if [SuperAdmin, User, Contact].include?(self.class) && email.present?
hash = Digest::MD5.hexdigest(email)
return "https://www.gravatar.com/avatar/#{hash}?d=404"
end
''
end
def fetch_avatar_from_gravatar
return unless saved_changes.key?(:email)
return if email.blank?
# Incase avatar_url is supplied, we don't want to fetch avatar from gravatar
# So we will wait for it to be processed
Avatar::AvatarFromGravatarJob.set(wait: 30.seconds).perform_later(self, email)
end
def acceptable_avatar
return unless avatar.attached?

View File

@@ -16,6 +16,6 @@ class Instagram::WebhooksBaseService
)
@contact = @contact_inbox.contact
ContactAvatarJob.perform_later(@contact, user['profile_pic']) if user['profile_pic']
Avatar::AvatarFromUrlJob.perform_later(@contact, user['profile_pic']) if user['profile_pic']
end
end

View File

@@ -45,7 +45,7 @@ class Telegram::IncomingMessageService
return if @contact.avatar.attached?
avatar_url = inbox.channel.get_telegram_profile_image(params[:message][:from][:id])
::ContactAvatarJob.perform_later(@contact, avatar_url) if avatar_url
::Avatar::AvatarFromUrlJob.perform_later(@contact, avatar_url) if avatar_url
end
def conversation_params

View File

@@ -30,6 +30,6 @@ class Twitter::WebhooksBaseService
user['id'], user['name'], additional_contact_attributes(user)
)
@contact = @contact_inbox.contact
ContactAvatarJob.perform_later(@contact, user['profile_image_url']) if user['profile_image_url']
Avatar::AvatarFromUrlJob.perform_later(@contact, user['profile_image_url']) if user['profile_image_url']
end
end