Add job for setting avatar via XMPP
This commit is contained in:
parent
382c5ad10e
commit
fc9b471a10
97
app/jobs/xmpp_set_avatar_job.rb
Normal file
97
app/jobs/xmpp_set_avatar_job.rb
Normal file
@ -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)
|
||||||
|
|
||||||
|
[
|
||||||
|
"""
|
||||||
|
<iq type='set' from='#{@user.address}' id='avatar-data-#{rand(101)}'>
|
||||||
|
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
||||||
|
<publish node='urn:xmpp:avatar:data'>
|
||||||
|
<item id='#{sha1_hash}'>
|
||||||
|
<data xmlns='urn:xmpp:avatar:data'>#{base64_data}</data>
|
||||||
|
</item>
|
||||||
|
</publish>
|
||||||
|
</pubsub>
|
||||||
|
</iq>
|
||||||
|
""".strip,
|
||||||
|
"""
|
||||||
|
<iq type='set' from='#{@user.address}' id='avatar-metadata-#{rand(101)}'>
|
||||||
|
<pubsub xmlns='http://jabber.org/protocol/pubsub'>
|
||||||
|
<publish node='urn:xmpp:avatar:metadata'>
|
||||||
|
<item id='#{sha1_hash}'>
|
||||||
|
<metadata xmlns='urn:xmpp:avatar:metadata'>
|
||||||
|
<info bytes='#{img_data.size}'
|
||||||
|
id='#{sha1_hash}'
|
||||||
|
height='256'
|
||||||
|
type='image/png'
|
||||||
|
width='256'/>
|
||||||
|
</metadata>
|
||||||
|
</item>
|
||||||
|
</publish>
|
||||||
|
</pubsub>
|
||||||
|
</iq>
|
||||||
|
""".strip,
|
||||||
|
]
|
||||||
|
end
|
||||||
|
end
|
@ -4,16 +4,8 @@ class EjabberdApiClient
|
|||||||
end
|
end
|
||||||
|
|
||||||
def post(endpoint, payload)
|
def post(endpoint, payload)
|
||||||
res = Faraday.post("#{@base_url}/#{endpoint}", payload.to_json,
|
Faraday.post "#{@base_url}/#{endpoint}", payload.to_json,
|
||||||
"Content-Type" => "application/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
|
|
||||||
end
|
end
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -24,6 +16,14 @@ class EjabberdApiClient
|
|||||||
post "add_rosteritem", payload
|
post "add_rosteritem", payload
|
||||||
end
|
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)
|
def get_vcard2(user, name, subname)
|
||||||
payload = {
|
payload = {
|
||||||
user: user.cn, host: user.ou,
|
user: user.cn, host: user.ou,
|
||||||
@ -47,8 +47,4 @@ class EjabberdApiClient
|
|||||||
}
|
}
|
||||||
post "private_set", payload
|
post "private_set", payload
|
||||||
end
|
end
|
||||||
|
|
||||||
def send_message(payload)
|
|
||||||
post "send_message", payload
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user