Compare commits
No commits in common. "5f276ff3492b9e034eba7abf43ecbdb3b47d75b6" and "382c5ad10e7bb06a05268c4824c65b064576b1ee" have entirely different histories.
5f276ff349
...
382c5ad10e
@ -36,7 +36,6 @@ class SettingsController < ApplicationController
|
|||||||
if @user.avatar_new.present?
|
if @user.avatar_new.present?
|
||||||
if store_user_avatar
|
if store_user_avatar
|
||||||
LdapManager::UpdateAvatar.call(user: @user)
|
LdapManager::UpdateAvatar.call(user: @user)
|
||||||
XmppSetAvatarJob.perform_later(user: @user)
|
|
||||||
else
|
else
|
||||||
@validation_errors = @user.errors
|
@validation_errors = @user.errors
|
||||||
render :show, status: :unprocessable_entity and return
|
render :show, status: :unprocessable_entity and return
|
||||||
|
|||||||
@ -1,97 +0,0 @@
|
|||||||
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)
|
|
||||||
|
|
||||||
[
|
|
||||||
"""
|
|
||||||
<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,8 +4,16 @@ class EjabberdApiClient
|
|||||||
end
|
end
|
||||||
|
|
||||||
def post(endpoint, payload)
|
def post(endpoint, payload)
|
||||||
Faraday.post "#{@base_url}/#{endpoint}", payload.to_json,
|
res = 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
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -16,14 +24,6 @@ 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,4 +47,8 @@ class EjabberdApiClient
|
|||||||
}
|
}
|
||||||
post "private_set", payload
|
post "private_set", payload
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def send_message(payload)
|
||||||
|
post "send_message", payload
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@ -46,8 +46,6 @@ RSpec.describe 'Profile settings', type: :feature do
|
|||||||
|
|
||||||
feature "Update avatar" do
|
feature "Update avatar" do
|
||||||
scenario "fails with validation error for wrong content type" do
|
scenario "fails with validation error for wrong content type" do
|
||||||
expect(LdapManager::UpdateAvatar).not_to receive(:call)
|
|
||||||
|
|
||||||
visit setting_path(:profile)
|
visit setting_path(:profile)
|
||||||
attach_file "Avatar", "#{Rails.root}/spec/fixtures/files/bitcoin.pdf"
|
attach_file "Avatar", "#{Rails.root}/spec/fixtures/files/bitcoin.pdf"
|
||||||
click_button "Save"
|
click_button "Save"
|
||||||
@ -59,7 +57,8 @@ RSpec.describe 'Profile settings', type: :feature do
|
|||||||
end
|
end
|
||||||
|
|
||||||
scenario "fails with validation error for file size too large" do
|
scenario "fails with validation error for file size too large" do
|
||||||
expect(LdapManager::UpdateAvatar).not_to receive(:call)
|
expect_any_instance_of(LdapManager::UpdateAvatar)
|
||||||
|
.not_to receive(:replace_attribute).and_return(true)
|
||||||
|
|
||||||
visit setting_path(:profile)
|
visit setting_path(:profile)
|
||||||
attach_file "Avatar", "#{Rails.root}/spec/fixtures/files/fsociety-irc.png"
|
attach_file "Avatar", "#{Rails.root}/spec/fixtures/files/fsociety-irc.png"
|
||||||
@ -74,12 +73,8 @@ RSpec.describe 'Profile settings', type: :feature do
|
|||||||
scenario 'works with valid JPG file' do
|
scenario 'works with valid JPG file' do
|
||||||
file_path = "#{Rails.root}/spec/fixtures/files/taipei.jpg"
|
file_path = "#{Rails.root}/spec/fixtures/files/taipei.jpg"
|
||||||
|
|
||||||
expect(LdapManager::UpdateAvatar)
|
expect_any_instance_of(LdapManager::UpdateAvatar)
|
||||||
.to receive(:call).with(user: user)
|
.to receive(:replace_attribute).and_return(true)
|
||||||
.and_return(true)
|
|
||||||
expect(XmppSetAvatarJob)
|
|
||||||
.to receive(:perform_later).with(user: user)
|
|
||||||
.and_return(true)
|
|
||||||
|
|
||||||
visit setting_path(:profile)
|
visit setting_path(:profile)
|
||||||
attach_file "Avatar", file_path
|
attach_file "Avatar", file_path
|
||||||
@ -94,12 +89,8 @@ RSpec.describe 'Profile settings', type: :feature do
|
|||||||
scenario 'works with valid PNG file' do
|
scenario 'works with valid PNG file' do
|
||||||
file_path = "#{Rails.root}/spec/fixtures/files/bender.png"
|
file_path = "#{Rails.root}/spec/fixtures/files/bender.png"
|
||||||
|
|
||||||
expect(LdapManager::UpdateAvatar)
|
expect_any_instance_of(LdapManager::UpdateAvatar)
|
||||||
.to receive(:call).with(user: user)
|
.to receive(:replace_attribute).and_return(true)
|
||||||
.and_return(true)
|
|
||||||
expect(XmppSetAvatarJob)
|
|
||||||
.to receive(:perform_later).with(user: user)
|
|
||||||
.and_return(true)
|
|
||||||
|
|
||||||
visit setting_path(:profile)
|
visit setting_path(:profile)
|
||||||
attach_file "Avatar", file_path
|
attach_file "Avatar", file_path
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user