Skip to content

Commit 9437946

Browse files
authored
Added avatar support when passed through Keycloak (#5998)
1 parent 6165a5d commit 9437946

File tree

5 files changed

+82
-5
lines changed

5 files changed

+82
-5
lines changed

.rubocop.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ Metrics/ClassLength:
7373
# A calculated magnitude based on number of assignments,
7474
# branches, and conditions.
7575
Metrics/AbcSize:
76-
Max: 95
76+
Max: 105
7777

7878
Metrics/ParameterLists:
7979
CountKeywordArgs: false

app/controllers/api/v1/users_controller.rb

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ def show
3535
render_data data: user, status: :ok
3636
end
3737

38-
# rubocop:disable Metrics/AbcSize
3938
# POST /api/v1/users.json
4039
# Creates and saves a new user record in the database with the provided parameters
4140
def create
@@ -97,7 +96,6 @@ def create
9796
render_error errors: Rails.configuration.custom_error_msgs[:record_invalid], status: :bad_request
9897
end
9998
end
100-
# rubocop:enable Metrics/AbcSize
10199

102100
# PATCH /api/v1/users/:id.json
103101
# Updates the values of a user

app/controllers/external_controller.rb

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ def create_user
5454
# Create the user if they don't exist
5555
if new_user
5656
user = UserCreator.new(user_params: user_info, provider: current_provider, role: default_role).call
57+
handle_avatar(user, credentials['info']['image'])
5758
user.save!
5859
create_default_room(user)
5960

@@ -64,8 +65,9 @@ def create_user
6465
end
6566
end
6667

67-
if SettingGetter.new(setting_name: 'ResyncOnLogin', provider:).call
68+
if !new_user && SettingGetter.new(setting_name: 'ResyncOnLogin', provider:).call
6869
user.assign_attributes(user_info.except(:language)) # Don't reset the user's language
70+
handle_avatar(user, credentials['info']['image'])
6971
user.save! if user.changed?
7072
end
7173

@@ -177,6 +179,24 @@ def build_user_info(credentials)
177179
}
178180
end
179181

182+
# Downloads the image and correctly attaches it to the user
183+
def handle_avatar(user, image)
184+
return if image.blank? || !user.valid? # return if no image passed or user isnt valid
185+
186+
profile_file = URI.parse(image)
187+
188+
filename = File.basename(profile_file.path)
189+
return if user.avatar&.filename&.to_s == filename # return if the filename is the same
190+
191+
file = profile_file.open
192+
user.avatar.attach(
193+
io: file, filename:, content_type: file.content_type
194+
)
195+
rescue StandardError => e
196+
Rails.logger.error("Failed to upload avatar for #{user.id}: #{e}")
197+
nil
198+
end
199+
180200
def valid_domain?(email)
181201
allowed_domain_emails = SettingGetter.new(setting_name: 'AllowedDomains', provider: current_provider).call
182202
return true if allowed_domain_emails.blank?

app/models/user.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ class User < ApplicationRecord
5858
on: %i[create update], if: :password_digest_changed?, unless: :external_id?
5959

6060
validates :avatar,
61-
dimension: { width: 300, height: 300 },
61+
dimension: { width: { in: 1..300 }, height: { in: 1..300 } },
6262
content_type: Rails.configuration.uploads[:images][:formats],
6363
size: { less_than: Rails.configuration.uploads[:images][:max_size] }
6464

spec/controllers/external_controller_spec.rb

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -437,6 +437,65 @@
437437
expect(User.find_by(email: OmniAuth.config.mock_auth[:openid_connect][:info][:email]).role).to eq(role1)
438438
end
439439
end
440+
441+
context 'avatar' do
442+
before do
443+
OmniAuth.config.mock_auth[:openid_connect] = OmniAuth::AuthHash.new(
444+
uid: Faker::Internet.uuid,
445+
info: {
446+
email: Faker::Internet.email,
447+
name: Faker::Name.name,
448+
image: Faker::Avatar.image
449+
}
450+
)
451+
452+
request.env['omniauth.auth'] = OmniAuth.config.mock_auth[:openid_connect]
453+
stub_request(:get, OmniAuth.config.mock_auth[:openid_connect][:info][:image])
454+
.to_return(body: file_fixture('default-avatar.png'), headers: { 'Content-Type' => 'image/jpeg' }, status: 200)
455+
end
456+
457+
it 'attaches the avatar to the user' do
458+
get :create_user, params: { provider: 'openid_connect' }
459+
460+
expect(User.find_by(email: OmniAuth.config.mock_auth[:openid_connect][:info][:email]).avatar).to be_attached
461+
end
462+
463+
it 'does not re-attach the avatar if it hasnt changed' do
464+
reg_method = instance_double(SettingGetter)
465+
allow(SettingGetter).to receive(:new).with(setting_name: 'ResyncOnLogin', provider: 'greenlight').and_return(reg_method)
466+
allow(reg_method).to receive(:call).and_return(true)
467+
468+
profile_file = URI.parse(OmniAuth.config.mock_auth[:openid_connect][:info][:image])
469+
filename = File.basename(profile_file.path)
470+
471+
user = create(:user, email: OmniAuth.config.mock_auth[:openid_connect][:info][:email])
472+
user.avatar.attach(io: fixture_file_upload('default-avatar.png'), filename:, content_type: 'image/png')
473+
474+
expect(User.find_by(email: OmniAuth.config.mock_auth[:openid_connect][:info][:email]).avatar).not_to receive(:attach)
475+
get :create_user, params: { provider: 'openid_connect' }
476+
end
477+
478+
it 'does not prevent the user from being created if the avatar attaching fails' do
479+
allow(OmniAuth.config.mock_auth[:openid_connect][:info][:image]).to receive(:blank?).and_raise(StandardError, 'Some error')
480+
481+
expect { get :create_user, params: { provider: 'openid_connect' } }.not_to raise_error
482+
expect(User.find_by(email: OmniAuth.config.mock_auth[:openid_connect][:info][:email])).to be_present
483+
end
484+
485+
it 'does not try to attach the avatar if no image is passed' do
486+
OmniAuth.config.mock_auth[:openid_connect][:info][:image] = nil
487+
488+
get :create_user, params: { provider: 'openid_connect' }
489+
490+
expect(User.find_by(email: OmniAuth.config.mock_auth[:openid_connect][:info][:email]).avatar).not_to be_attached
491+
end
492+
493+
it 'does not try to attach the avatar if the user is invalid' do
494+
allow_any_instance_of(User).to receive(:valid?).and_return(false)
495+
expect_any_instance_of(User).not_to receive(:avatar)
496+
get :create_user, params: { provider: 'openid_connect' }
497+
end
498+
end
440499
end
441500

442501
describe '#recording_ready' do

0 commit comments

Comments
 (0)