Store avatars as binary instead of base64
All checks were successful
continuous-integration/drone/push Build is passing

This commit is contained in:
Râu Cao 2024-01-24 15:56:34 +03:00
parent 6d7d722c5d
commit 9e2210c45b
Signed by: raucao
GPG Key ID: 37036C356E56CC51
5 changed files with 35 additions and 24 deletions

View File

@ -159,6 +159,15 @@ class User < ApplicationRecord
@display_name ||= ldap_entry[:display_name] @display_name ||= ldap_entry[:display_name]
end end
def avatar
@avatar ||= LdapManager::FetchAvatar.call(cn: cn)
end
def avatar_base64
return nil if avatar.nil?
@avatar_base64 ||= Base64.strict_encode64(avatar)
end
def nostr_pubkey def nostr_pubkey
@nostr_pubkey ||= ldap_entry[:nostr_key] @nostr_pubkey ||= ldap_entry[:nostr_key]
end end
@ -186,10 +195,6 @@ class User < ApplicationRecord
ZBase32.encode(Digest::SHA1.digest(cn)) ZBase32.encode(Digest::SHA1.digest(cn))
end end
def avatar
@avatar_base64 ||= LdapManager::FetchAvatar.call(cn: cn)
end
def services_enabled def services_enabled
ldap_entry[:services_enabled] || [] ldap_entry[:services_enabled] || []
end end

View File

@ -10,7 +10,7 @@ module LdapManager
filter = Net::LDAP::Filter.eq("cn", @cn) filter = Net::LDAP::Filter.eq("cn", @cn)
entry = client.search(base: treebase, filter: filter, attributes: attributes).first entry = client.search(base: treebase, filter: filter, attributes: attributes).first
entry.try(:jpegPhoto) ? entry.jpegPhoto.first : nil entry&.jpegPhoto ? entry.jpegPhoto.first : nil
end end
end end
end end

View File

@ -8,20 +8,20 @@ module LdapManager
end end
def call def call
replace_attribute @dn, :jpegPhoto, @img_data result = replace_attribute @dn, :jpegPhoto, @img_data
result
end end
private private
def process(file) def process(file)
processed = ImageProcessing::Vips processed = ImageProcessing::Vips
.resize_to_fill(512, 512) .resize_to_fill(256, 256)
.source(file) .source(file)
.convert("jpeg") .convert("jpeg")
.saver(strip: true) .saver(strip: true)
.call .call
processed.read
Base64.strict_encode64 processed.read
end end
end end
end end

View File

@ -20,7 +20,7 @@
</button> </button>
</p> </p>
<p class="text-sm text-gray-500"> <p class="text-sm text-gray-500">
Your user address for Chat and Lightning Network. Your account's address on the Internet
</p> </p>
</div> </div>
<%= form_for(@user, url: setting_path(:profile), html: { :method => :put }) do |f| %> <%= form_for(@user, url: setting_path(:profile), html: { :method => :put }) do |f| %>
@ -40,9 +40,10 @@
Default profile picture Default profile picture
</p> </p>
<div class="flex items-center gap-6"> <div class="flex items-center gap-6">
<% if current_user.avatar.present? %> <% unless current_user.avatar.nil? %>
<p class="flex-none"> <p class="flex-none">
<%= image_tag "data:image/jpeg;base64,#{current_user.avatar}", class: "h-24 w-24 rounded-lg" %> <%= image_tag "data:image/jpeg;base64,#{current_user.avatar_base64}",
class: "h-24 w-24 rounded-lg" %>
</p> </p>
<% end %> <% end %>
<div class="grow"> <div class="grow">

View File

@ -2,18 +2,22 @@ require 'rails_helper'
RSpec.describe 'Profile settings', type: :feature do RSpec.describe 'Profile settings', type: :feature do
let(:user) { create :user, cn: "mwahlberg" } let(:user) { create :user, cn: "mwahlberg" }
let(:avatar_base64) { File.read("#{Rails.root}/spec/fixtures/files/avatar-base64.txt") } let(:avatar_jpeg) { File.binread("#{Rails.root}/spec/fixtures/files/taipei.jpg") }
before do before do
Flipper.enable "avatar_upload"
login_as user, :scope => :user login_as user, :scope => :user
allow(user).to receive(:display_name).and_return("Mark") allow(user).to receive(:display_name).and_return("Mark")
allow_any_instance_of(User).to receive(:dn).and_return("cn=mwahlberg,ou=kosmos.org,cn=users,dc=kosmos,dc=org")
allow_any_instance_of(User).to receive(:ldap_entry).and_return({ allow_any_instance_of(User).to receive(:dn)
.and_return("cn=mwahlberg,ou=kosmos.org,cn=users,dc=kosmos,dc=org")
allow_any_instance_of(User).to receive(:ldap_entry)
.and_return({
uid: user.cn, ou: user.ou, display_name: "Mark", pgp_key: nil uid: user.cn, ou: user.ou, display_name: "Mark", pgp_key: nil
}) })
allow_any_instance_of(User).to receive(:avatar).and_return(avatar_base64) allow_any_instance_of(User).to receive(:avatar)
.and_return(avatar_jpeg)
Flipper.enable "avatar_upload"
end end
feature "Update display name" do feature "Update display name" do
@ -70,8 +74,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_any_instance_of(LdapManager::UpdateAvatar).to receive(:replace_attribute) expect_any_instance_of(LdapManager::UpdateAvatar)
.with(user.dn, :jpegPhoto, avatar_base64).and_return(true) .to receive(:replace_attribute).and_return(true)
visit setting_path(:profile) visit setting_path(:profile)
attach_file "Avatar", file_path attach_file "Avatar", file_path
@ -86,7 +90,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).to receive(:call).and_return(true) expect_any_instance_of(LdapManager::UpdateAvatar)
.to receive(:replace_attribute).and_return(true)
visit setting_path(:profile) visit setting_path(:profile)
attach_file "Avatar", file_path attach_file "Avatar", file_path