Add user avatars
This commit is contained in:
parent
86f85a90f4
commit
9e5aeaf572
@ -19,6 +19,7 @@ class SettingsController < ApplicationController
|
|||||||
def update
|
def update
|
||||||
@user.preferences.merge!(user_params[:preferences] || {})
|
@user.preferences.merge!(user_params[:preferences] || {})
|
||||||
@user.display_name = user_params[:display_name]
|
@user.display_name = user_params[:display_name]
|
||||||
|
@user.avatar = user_params[:avatar] if user_params[:avatar].present?
|
||||||
|
|
||||||
if @user.save
|
if @user.save
|
||||||
if @user.display_name && (@user.display_name != @user.ldap_entry[:display_name])
|
if @user.display_name && (@user.display_name != @user.ldap_entry[:display_name])
|
||||||
@ -117,7 +118,7 @@ class SettingsController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def user_params
|
def user_params
|
||||||
params.require(:user).permit(:display_name, preferences: [
|
params.require(:user).permit(:display_name, :avatar, preferences: [
|
||||||
:lightning_notify_sats_received,
|
:lightning_notify_sats_received,
|
||||||
:xmpp_exchange_contacts_with_invitees
|
:xmpp_exchange_contacts_with_invitees
|
||||||
])
|
])
|
||||||
|
@ -5,6 +5,12 @@ class User < ApplicationRecord
|
|||||||
|
|
||||||
serialize :preferences, UserPreferences
|
serialize :preferences, UserPreferences
|
||||||
|
|
||||||
|
#
|
||||||
|
# File attachments
|
||||||
|
#
|
||||||
|
|
||||||
|
has_one_attached :avatar
|
||||||
|
|
||||||
# Relations
|
# Relations
|
||||||
has_many :invitations, dependent: :destroy
|
has_many :invitations, dependent: :destroy
|
||||||
has_one :invitation, inverse_of: :invitee, foreign_key: 'invited_user_id'
|
has_one :invitation, inverse_of: :invitee, foreign_key: 'invited_user_id'
|
||||||
@ -40,6 +46,7 @@ class User < ApplicationRecord
|
|||||||
|
|
||||||
validates_uniqueness_of :nostr_pubkey, allow_blank: true
|
validates_uniqueness_of :nostr_pubkey, allow_blank: true
|
||||||
|
|
||||||
|
validate :acceptable_avatar
|
||||||
scope :confirmed, -> { where.not(confirmed_at: nil) }
|
scope :confirmed, -> { where.not(confirmed_at: nil) }
|
||||||
scope :pending, -> { where(confirmed_at: nil) }
|
scope :pending, -> { where(confirmed_at: nil) }
|
||||||
scope :all_except, -> (user) { where.not(id: user) }
|
scope :all_except, -> (user) { where.not(id: user) }
|
||||||
@ -140,6 +147,14 @@ class User < ApplicationRecord
|
|||||||
@display_name ||= ldap_entry[:display_name]
|
@display_name ||= ldap_entry[:display_name]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def avatar_64px
|
||||||
|
avatar.variant(resize_to_fill: [64, 64])
|
||||||
|
end
|
||||||
|
|
||||||
|
def avatar_256px
|
||||||
|
avatar.variant(resize_to_fill: [256, 256])
|
||||||
|
end
|
||||||
|
|
||||||
def services_enabled
|
def services_enabled
|
||||||
ldap_entry[:service] || []
|
ldap_entry[:service] || []
|
||||||
end
|
end
|
||||||
@ -168,4 +183,17 @@ class User < ApplicationRecord
|
|||||||
return @ldap_service if defined?(@ldap_service)
|
return @ldap_service if defined?(@ldap_service)
|
||||||
@ldap_service = LdapService.new
|
@ldap_service = LdapService.new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def acceptable_avatar
|
||||||
|
return unless avatar.attached?
|
||||||
|
|
||||||
|
if avatar.blob.byte_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)
|
||||||
|
errors.add(:avatar, "must be a JPEG or PNG file")
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -1,33 +1,62 @@
|
|||||||
<section>
|
<section>
|
||||||
<h3>Profile</h3>
|
<h3>Profile</h3>
|
||||||
<p class="mb-2">
|
<div class="mb-6">
|
||||||
<%= label :user_address, 'User address', class: 'font-bold' %>
|
<p class="mb-2">
|
||||||
</p>
|
<%= label :user_address, 'User address', class: 'font-bold' %>
|
||||||
<p data-controller="clipboard" class="flex gap-1 mb-2 sm:w-3/5">
|
</p>
|
||||||
<input type="text" id="user_address" class="grow"
|
<p data-controller="clipboard" class="flex gap-1 mb-2 sm:w-3/5">
|
||||||
value=<%= @user.address %> disabled="disabled"
|
<input type="text" id="user_address" class="grow"
|
||||||
data-clipboard-target="source" />
|
value=<%= @user.address %> disabled="disabled"
|
||||||
<button id="copy-user-address" class="btn-md btn-icon btn-outline shrink-0"
|
data-clipboard-target="source" />
|
||||||
data-clipboard-target="trigger" data-action="clipboard#copy"
|
<button id="copy-user-address" class="btn-md btn-icon btn-outline shrink-0"
|
||||||
title="Copy to clipboard">
|
data-clipboard-target="trigger" data-action="clipboard#copy"
|
||||||
<span class="content-initial">
|
title="Copy to clipboard">
|
||||||
<%= render partial: "icons/copy", locals: { custom_class: "text-blue-600 h-4 w-4 inline" } %>
|
<span class="content-initial">
|
||||||
</span>
|
<%= render partial: "icons/copy", locals: { custom_class: "text-blue-600 h-4 w-4 inline" } %>
|
||||||
<span class="content-active hidden">
|
</span>
|
||||||
<%= render partial: "icons/check", locals: { custom_class: "text-blue-600 h-4 w-4 inline" } %>
|
<span class="content-active hidden">
|
||||||
</span>
|
<%= render partial: "icons/check", locals: { custom_class: "text-blue-600 h-4 w-4 inline" } %>
|
||||||
</button>
|
</span>
|
||||||
</p>
|
</button>
|
||||||
<p class="text-sm text-gray-500">
|
</p>
|
||||||
Your user address for Chat and Lightning Network.
|
<p class="text-sm text-gray-500">
|
||||||
</p>
|
Your user address for Chat and Lightning Network.
|
||||||
|
</p>
|
||||||
|
</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| %>
|
||||||
<%= render FormElements::FieldsetComponent.new(tag: "div", title: "Display name") do %>
|
<%= render FormElements::FieldsetComponent.new(tag: "div", title: "Display name") do %>
|
||||||
<%= f.text_field :display_name, class: "w-full sm:w-3/5 mb-2" %>
|
<%= f.text_field :display_name, class: "w-full sm:w-3/5" %>
|
||||||
<% if @validation_errors.present? && @validation_errors[:display_name].present? %>
|
<% if @validation_errors.present? && @validation_errors[:display_name].present? %>
|
||||||
<p class="error-msg"><%= @validation_errors[:display_name].first %></p>
|
<p class="error-msg mt-2"><%= @validation_errors[:display_name].first %></p>
|
||||||
<% end %>
|
<% end %>
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
|
<label class="block">
|
||||||
|
<p class="font-bold mb-1">
|
||||||
|
Avatar
|
||||||
|
</p>
|
||||||
|
<p class="text-gray-500">
|
||||||
|
Default profile picture
|
||||||
|
</p>
|
||||||
|
<div class="flex items-center gap-6">
|
||||||
|
<% if current_user.avatar.attached? %>
|
||||||
|
<p class="flex-none">
|
||||||
|
<%= image_tag current_user.reload.avatar_256px, class: "h-24 w-24 rounded-lg" %>
|
||||||
|
</p>
|
||||||
|
<% end %>
|
||||||
|
<div class="grow">
|
||||||
|
<p class="mb-2">
|
||||||
|
<%= f.file_field :avatar, class: "" %>
|
||||||
|
<p class="text-sm text-gray-500">
|
||||||
|
JPEG or PNG image, not larger than 1 megabyte
|
||||||
|
</p>
|
||||||
|
<% if @validation_errors.present? && @validation_errors[:avatar].present? %>
|
||||||
|
<p class="error-msg mb-2"><%= @validation_errors[:avatar].first %></p>
|
||||||
|
<% end %>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
|
||||||
<p class="mt-8 pt-6 border-t border-gray-200 text-right">
|
<p class="mt-8 pt-6 border-t border-gray-200 text-right">
|
||||||
<%= f.submit 'Save', class: "btn-md btn-blue w-full md:w-auto" %>
|
<%= f.submit 'Save', class: "btn-md btn-blue w-full md:w-auto" %>
|
||||||
</p>
|
</p>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user