FIX: download SSO avatars in a background job to prevent hangs when avatars are huge

This commit is contained in:
Régis Hanol 2016-10-24 19:55:30 +02:00
parent e79465a965
commit 750338954c
2 changed files with 76 additions and 61 deletions

View File

@ -119,13 +119,15 @@ class DiscourseSingleSignOn < SingleSignOn
sso_record.last_payload = unsigned_payload sso_record.last_payload = unsigned_payload
sso_record.external_id = external_id sso_record.external_id = external_id
else else
UserAvatar.import_url_for_user(avatar_url, user) if avatar_url.present? Jobs.enqueue(:download_avatar_from_url, url: avatar_url, user_id: user.id) if avatar_url.present?
user.create_single_sign_on_record(last_payload: unsigned_payload, user.create_single_sign_on_record(
external_id: external_id, last_payload: unsigned_payload,
external_username: username, external_id: external_id,
external_email: email, external_username: username,
external_name: name, external_email: email,
external_avatar_url: avatar_url) external_name: name,
external_avatar_url: avatar_url
)
end end
end end
@ -148,12 +150,11 @@ class DiscourseSingleSignOn < SingleSignOn
avatar_missing = user.uploaded_avatar_id.nil? || !Upload.exists?(user.uploaded_avatar_id) avatar_missing = user.uploaded_avatar_id.nil? || !Upload.exists?(user.uploaded_avatar_id)
if (avatar_missing || avatar_force_update || SiteSetting.sso_overrides_avatar) && avatar_url.present? if (avatar_missing || avatar_force_update || SiteSetting.sso_overrides_avatar) && avatar_url.present?
avatar_changed = sso_record.external_avatar_url != avatar_url
avatar_changed = sso_record.external_avatar_url != avatar_url if avatar_force_update || avatar_changed || avatar_missing
Jobs.enqueue(:download_avatar_from_url, url: avatar_url, user_id: user.id)
if avatar_force_update || avatar_changed || avatar_missing end
UserAvatar.import_url_for_user(avatar_url, user)
end
end end
# change external attributes for sso record # change external attributes for sso record

View File

@ -1,4 +1,5 @@
require "rails_helper" require "rails_helper"
require 'sidekiq/testing'
describe DiscourseSingleSignOn do describe DiscourseSingleSignOn do
before do before do
@ -279,60 +280,67 @@ describe DiscourseSingleSignOn do
it "correctly handles provided avatar_urls" do it "correctly handles provided avatar_urls" do
Sidekiq::Testing.inline! do
sso = DiscourseSingleSignOn.new
sso.external_id = 666
sso.email = "sam@sam.com"
sso.name = "sam"
sso.username = "sam"
sso.avatar_url = "http://awesome.com/image.png"
sso = DiscourseSingleSignOn.new FileHelper.stubs(:download).returns(file_from_fixtures("logo.png"))
sso.external_id = 666 user = sso.lookup_or_create_user(ip_address)
sso.email = "sam@sam.com" user.reload
sso.name = "sam" avatar_id = user.uploaded_avatar_id
sso.username = "sam"
sso.avatar_url = "http://awesome.com/image.png"
FileHelper.stubs(:download).returns(file_from_fixtures("logo.png")) # initial creation ...
user = sso.lookup_or_create_user(ip_address) expect(avatar_id).to_not eq(nil)
avatar_id = user.uploaded_avatar_id
# initial creation ... # junk avatar id should be updated
expect(avatar_id).to_not eq(nil) old_id = user.uploaded_avatar_id
Upload.destroy(old_id)
# junk avatar id should be updated user = sso.lookup_or_create_user(ip_address)
old_id = user.uploaded_avatar_id user.reload
Upload.destroy(old_id) avatar_id = user.uploaded_avatar_id
user = sso.lookup_or_create_user(ip_address) expect(avatar_id).to_not eq(nil)
avatar_id = user.uploaded_avatar_id expect(old_id).to_not eq(avatar_id)
expect(avatar_id).to_not eq(nil) FileHelper.stubs(:download) { raise "should not be called" }
expect(old_id).to_not eq(avatar_id) sso.avatar_url = "https://some.new/avatar.png"
user = sso.lookup_or_create_user(ip_address)
user.reload
FileHelper.stubs(:download) { raise "should not be called" } # avatar updated but no override specified ...
sso.avatar_url = "https://some.new/avatar.png" expect(user.uploaded_avatar_id).to eq(avatar_id)
user = sso.lookup_or_create_user(ip_address)
# avatar updated but no override specified ... sso.avatar_force_update = true
expect(user.uploaded_avatar_id).to eq(avatar_id) FileHelper.stubs(:download).returns(file_from_fixtures("logo-dev.png"))
user = sso.lookup_or_create_user(ip_address)
user.reload
sso.avatar_force_update = true # we better have a new avatar
FileHelper.stubs(:download).returns(file_from_fixtures("logo-dev.png")) expect(user.uploaded_avatar_id).not_to eq(avatar_id)
user = sso.lookup_or_create_user(ip_address) expect(user.uploaded_avatar_id).not_to eq(nil)
# we better have a new avatar avatar_id = user.uploaded_avatar_id
expect(user.uploaded_avatar_id).not_to eq(avatar_id)
expect(user.uploaded_avatar_id).not_to eq(nil)
avatar_id = user.uploaded_avatar_id sso.avatar_force_update = true
FileHelper.stubs(:download) { raise "not found" }
user = sso.lookup_or_create_user(ip_address)
user.reload
sso.avatar_force_update = true # we better have the same avatar
FileHelper.stubs(:download) { raise "not found" } expect(user.uploaded_avatar_id).to eq(avatar_id)
user = sso.lookup_or_create_user(ip_address) end
# we better have the same avatar
expect(user.uploaded_avatar_id).to eq(avatar_id)
end end
end end
context 'when sso_overrides_avatar is enabled' do context 'when sso_overrides_avatar is enabled' do
let!(:sso_record) { Fabricate(:single_sign_on_record, external_avatar_url: "http://example.com/an_image.png") } let!(:sso_record) { Fabricate(:single_sign_on_record, external_avatar_url: "http://example.com/an_image.png") }
let!(:sso) { let!(:sso) {
sso = DiscourseSingleSignOn.new sso = DiscourseSingleSignOn.new
sso.username = "test" sso.username = "test"
@ -341,6 +349,7 @@ describe DiscourseSingleSignOn do
sso.external_id = sso_record.external_id sso.external_id = sso_record.external_id
sso sso
} }
let(:logo) { file_from_fixtures("logo.png") } let(:logo) { file_from_fixtures("logo.png") }
before do before do
@ -348,27 +357,32 @@ describe DiscourseSingleSignOn do
end end
it "deal with no avatar url passed for an existing user with an avatar" do it "deal with no avatar url passed for an existing user with an avatar" do
# Deliberately not setting avatar_url so it should not update Sidekiq::Testing.inline! do
# Deliberately not setting avatar_url so it should not update
sso_record.user.update_columns(uploaded_avatar_id: -1)
user = sso.lookup_or_create_user(ip_address)
user.reload
sso_record.user.update_columns(uploaded_avatar_id: -1) expect(user).to_not be_nil
user = sso.lookup_or_create_user(ip_address) expect(user.uploaded_avatar_id).to eq(-1)
end
expect(user).to_not be_nil
expect(user.uploaded_avatar_id).to eq(-1)
end end
it "deal with no avatar_force_update passed as a boolean" do it "deal with no avatar_force_update passed as a boolean" do
FileHelper.stubs(:download).returns(logo) Sidekiq::Testing.inline! do
FileHelper.stubs(:download).returns(logo)
sso_record.user.update_columns(uploaded_avatar_id: -1) sso_record.user.update_columns(uploaded_avatar_id: -1)
sso.avatar_url = "http://example.com/a_different_image.png" sso.avatar_url = "http://example.com/a_different_image.png"
sso.avatar_force_update = false sso.avatar_force_update = false
user = sso.lookup_or_create_user(ip_address) user = sso.lookup_or_create_user(ip_address)
user.reload
expect(user).to_not be_nil expect(user).to_not be_nil
expect(user.uploaded_avatar_id).to_not eq(-1) expect(user.uploaded_avatar_id).to_not eq(-1)
end
end end
end end
end end