Add user avatars to LDAP, upload on profile settings page #148

Merged
raucao merged 11 commits from feature/123-user_avatars into master 2023-09-13 13:01:25 +00:00
8 changed files with 55 additions and 25 deletions
Showing only changes of commit d5ab532947 - Show all commits

View File

@ -20,6 +20,8 @@ class Admin::UsersController < Admin::BaseController
end
@services_enabled = @user.services_enabled
@avatar = LdapManager::FetchAvatar.call(cn: @user.cn, ou: @user.ou)
end
private

View File

@ -19,17 +19,15 @@ class SettingsController < ApplicationController
def update
@user.preferences.merge!(user_params[:preferences] || {})
@user.display_name = user_params[:display_name]
current_avatar_checksum = @user.avatar.attached? ? @user.avatar.blob.checksum : nil
@user.avatar = user_params[:avatar] if user_params[:avatar].present?
@user.avatar_new = user_params[:avatar]
if @user.save
if @user.display_name && (@user.display_name != @user.ldap_entry[:display_name])
LdapManager::UpdateDisplayName.call(@user.dn, @user.display_name)
end
if @user.avatar.attached? &&
(@user.avatar.blob.checksum != current_avatar_checksum)
LdapManager::UpdateAvatar.call(@user.dn, @user.avatar_base64)
if @user.avatar_new.present?
LdapManager::UpdateAvatar.call(@user.dn, @user.avatar_new)
end
redirect_to setting_path(@settings_section), flash: {

View File

@ -2,19 +2,10 @@ class User < ApplicationRecord
include EmailValidatable
attr_accessor :display_name
attr_accessor :avatar_new
serialize :preferences, UserPreferences
#
# File attachments
#
has_one_attached :avatar do |attachable|
attachable.variant :small, resize_to_fill: [64, 64], convert: :jpeg
attachable.variant :medium, resize_to_fill: [256, 256], convert: :jpeg
attachable.variant :large, resize_to_fill: [512, 512], convert: :jpeg
end
#
# Relations
#
@ -167,9 +158,8 @@ class User < ApplicationRecord
@display_name ||= ldap_entry[:display_name]
end
def avatar_base64(variant: :large)
Base64.strict_encode64 avatar.variant(variant).processed.download
def avatar
@avatar_base64 ||= LdapManager::FetchAvatar.call(cn: cn, ou: ou)
end
def services_enabled
@ -202,14 +192,14 @@ class User < ApplicationRecord
end
def acceptable_avatar
return unless avatar.attached?
return unless avatar_new.present?
if avatar.blob.byte_size > 1.megabyte
if avatar_new.size > 1.megabyte
errors.add(:avatar, "file size is too large")
end
acceptable_types = ["image/jpeg", "image/png"]
unless acceptable_types.include?(avatar.content_type)
unless acceptable_types.include?(avatar_new.content_type)
errors.add(:avatar, "must be a JPEG or PNG file")
end
end

View File

@ -0,0 +1,18 @@
module LdapManager
class FetchAvatar < LdapManagerService
def initialize(cn:, ou: nil)
@cn = cn
@ou = ou
end
def call
treebase = @ou ? "ou=#{@ou},cn=users,#{suffix}" : ldap_config["base"]
puts treebase.inspect
raucao marked this conversation as resolved
Review

✂️

✂️
attributes = %w{ jpegPhoto }
filter = Net::LDAP::Filter.eq("cn", @cn)
entry = ldap_client.search(base: treebase, filter: filter, attributes: attributes).first
entry.try(:jpegPhoto) ? entry.jpegPhoto.first : nil
end
end
end

View File

@ -1,12 +1,27 @@
require "image_processing/vips"
module LdapManager
class UpdateAvatar < LdapManagerService
def initialize(dn, img_data)
def initialize(dn, file)
@dn = dn
@img_data = img_data
@img_data = process(file)
end
def call
replace_attribute @dn, :jpegPhoto, @img_data
end
private
def process(file)
processed = ImageProcessing::Vips
.resize_to_fill(512, 512)
.source(file)
.convert("jpeg")
.saver(strip: true)
.call
Base64.strict_encode64 processed.read
end
end
end

View File

@ -1,2 +1,5 @@
class LdapManagerService < LdapService
def suffix
@suffix ||= ENV["LDAP_SUFFIX"] || "dc=kosmos,dc=org"
end
end

View File

@ -63,6 +63,10 @@
</section>
<section class="sm:flex-1 sm:pt-0">
<h3>LDAP<h3>
<p>
<img src="data:image/png;base64,<%= @avatar %>" class="h-48 w-48" />
raucao marked this conversation as resolved Outdated

Shouldn't this be image/jpeg?

Shouldn't this be `image/jpeg`?

Yes! Thanks.

Yes! Thanks.
</p>
<!-- <h3>Actions</h3> -->
</section>
</div>

View File

@ -39,9 +39,9 @@
Default profile picture
</p>
<div class="flex items-center gap-6">
<% if current_user.avatar.attached? %>
<% if current_user.avatar.present? %>
<p class="flex-none">
<%= image_tag current_user.reload.avatar.variant(:medium), class: "h-24 w-24 rounded-lg" %>
<%= image_tag "data:image/jpeg;base64,#{current_user.avatar}", class: "h-24 w-24 rounded-lg" %>
</p>
<% end %>
<div class="grow">