require 'digest' require "image_processing/vips" class XmppSetAvatarJob < ApplicationJob queue_as :default def perform(user:, overwrite: false) return if Rails.env.development? @user = user unless overwrite current_avatar = get_current_avatar Rails.logger.info { "User #{user.cn} already has an avatar set" } return if current_avatar.present? end Rails.logger.debug { "Setting XMPP avatar for user #{user.cn}" } stanzas = build_xep0084_stanzas stanzas.each do |stanza| payload = { from: @user.address, to: @user.address, stanza: stanza } res = ejabberd.send_stanza payload raise res.inspect if res.status != 200 end end private def ejabberd @ejabberd ||= EjabberdApiClient.new end def get_current_avatar res = ejabberd.get_vcard2 @user, "PHOTO", "BINVAL" if res.status == 200 # VCARD PHOTO/BINVAL prop exists res.body elsif res.status == 400 # VCARD or PHOTO/BINVAL prop does not exist nil else # Unexpected error, let job fail raise res.inspect end end def process_avatar @user.avatar.blob.open do |file| processed = ImageProcessing::Vips .source(file) .resize_to_fill(256, 256) .convert("png") .call processed.read end end # See https://xmpp.org/extensions/xep-0084.html def build_xep0084_stanzas img_data = process_avatar sha1_hash = Digest::SHA1.hexdigest(img_data) base64_data = Base64.strict_encode64(img_data) [ """ #{base64_data} """.strip, """ """.strip, ] end end