Store and retrieve avatars in/from LDAP exclusively
Some checks failed
continuous-integration/drone/push Build is failing

No need to keep them in two places at the same time. We can fetch them
from LDAP whenever we want to do something with them.
This commit is contained in:
Râu Cao 2023-09-06 20:42:26 +02:00
parent 50c63d5c38
commit d5ab532947
Signed by: raucao
GPG Key ID: 15E65F399D084BA9
8 changed files with 55 additions and 25 deletions

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
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" />
</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">