diff --git a/app/jobs/xmpp_set_avatar_job.rb b/app/jobs/xmpp_set_avatar_job.rb
new file mode 100644
index 0000000..745d04c
--- /dev/null
+++ b/app/jobs/xmpp_set_avatar_job.rb
@@ -0,0 +1,97 @@
+require 'digest'
+require "image_processing/vips"
+
+class XmppSetAvatarJob < ApplicationJob
+ queue_as :default
+
+ def perform(user:, overwrite: false)
+ @user = user
+
+ unless overwrite
+ current_avatar = get_current_avatar
+ Rails.logger.debug { "User #{user.cn} already has an avatar set. Nothing to do." }
+ return if current_avatar.present?
+ end
+
+ Rails.logger.debug { "Setting XMPP avatar for user #{user.cn}" }
+
+ stanzas = build_xep0084_stanzas
+
+ stanzas.each do |stanza|
+ res = ejabberd.send_stanza {
+ from: user.address, to: user.address, stanza: stanza
+ }
+
+ 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
+
+ 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
diff --git a/app/services/ejabberd_api_client.rb b/app/services/ejabberd_api_client.rb
index a002d7f..df22d25 100644
--- a/app/services/ejabberd_api_client.rb
+++ b/app/services/ejabberd_api_client.rb
@@ -4,16 +4,8 @@ class EjabberdApiClient
end
def post(endpoint, payload)
- res = Faraday.post("#{@base_url}/#{endpoint}", payload.to_json,
- "Content-Type" => "application/json")
-
- if res.status != 200
- #TODO Send custom event to Sentry
- Rails.logger.error "[ejabberd] API request failed:"
- Rails.logger.error res.body
- end
-
- res
+ Faraday.post "#{@base_url}/#{endpoint}", payload.to_json,
+ "Content-Type" => "application/json"
end
#
@@ -24,6 +16,14 @@ class EjabberdApiClient
post "add_rosteritem", payload
end
+ def send_message(payload)
+ post "send_message", payload
+ end
+
+ def send_stanza(payload)
+ post "send_stanza", payload
+ end
+
def get_vcard2(user, name, subname)
payload = {
user: user.cn, host: user.ou,
@@ -47,8 +47,4 @@ class EjabberdApiClient
}
post "private_set", payload
end
-
- def send_message(payload)
- post "send_message", payload
- end
end