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.
207 lines
5.7 KiB
Ruby
207 lines
5.7 KiB
Ruby
class User < ApplicationRecord
|
|
include EmailValidatable
|
|
|
|
attr_accessor :display_name
|
|
attr_accessor :avatar_new
|
|
|
|
serialize :preferences, UserPreferences
|
|
|
|
#
|
|
# Relations
|
|
#
|
|
|
|
has_many :invitations, dependent: :destroy
|
|
has_one :invitation, inverse_of: :invitee, foreign_key: 'invited_user_id'
|
|
has_one :inviter, through: :invitation, source: :user
|
|
has_many :invitees, through: :invitations
|
|
|
|
has_many :donations, dependent: :nullify
|
|
|
|
has_one :lndhub_user, class_name: "LndhubUser", inverse_of: "user",
|
|
primary_key: "ln_account", foreign_key: "login"
|
|
|
|
has_many :accounts, through: :lndhub_user
|
|
|
|
has_many :remote_storage_authorizations
|
|
|
|
#
|
|
# Validations
|
|
#
|
|
|
|
validates_uniqueness_of :cn, scope: :ou
|
|
validates_length_of :cn, minimum: 3
|
|
validates_format_of :cn, with: /\A([a-z0-9\-])*\z/,
|
|
if: Proc.new{ |u| u.cn.present? },
|
|
message: "is invalid. Please use only letters, numbers and -"
|
|
validates_format_of :cn, without: /\A-/,
|
|
if: Proc.new{ |u| u.cn.present? },
|
|
message: "is invalid. Usernames need to start with a letter."
|
|
# FIXME This needs a server restart to apply values
|
|
validates_format_of :cn, without: /\A(#{Setting.reserved_usernames.join('|')})\z/i,
|
|
message: "has already been taken"
|
|
|
|
validates_uniqueness_of :email
|
|
validates :email, email: true
|
|
|
|
validates_length_of :display_name, minimum: 3, maximum: 35, allow_blank: true,
|
|
if: -> { defined?(@display_name) }
|
|
|
|
validates_uniqueness_of :nostr_pubkey, allow_blank: true
|
|
|
|
validate :acceptable_avatar
|
|
|
|
#
|
|
# Scopes
|
|
#
|
|
|
|
scope :confirmed, -> { where.not(confirmed_at: nil) }
|
|
scope :pending, -> { where(confirmed_at: nil) }
|
|
scope :all_except, -> (user) { where.not(id: user) }
|
|
|
|
#
|
|
# Encrypted database columns
|
|
#
|
|
|
|
has_encrypted :ln_login, :ln_password
|
|
|
|
# Include default devise modules. Others available are:
|
|
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
|
|
devise :ldap_authenticatable,
|
|
:confirmable,
|
|
:recoverable,
|
|
:validatable,
|
|
:timeoutable,
|
|
:rememberable
|
|
|
|
def ldap_before_save
|
|
self.email = Devise::LDAP::Adapter.get_ldap_param(self.cn, "mail").first
|
|
self.ou = dn.split(',')
|
|
.select{|e| e[0..1] == "ou"}.first
|
|
.delete_prefix("ou=")
|
|
|
|
if self.confirmed_at.blank? && self.confirmation_token.blank?
|
|
# User had an account with a trusted email address before akkounts was a thing
|
|
self.confirmed_at = DateTime.now
|
|
end
|
|
end
|
|
|
|
def devise_after_confirmation
|
|
if ldap_entry[:mail] != self.email
|
|
# E-Mail update confirmed
|
|
LdapManager::UpdateEmail.call(self.dn, self.email)
|
|
else
|
|
# TODO Make configurable
|
|
# E-Mail from signup confirmed (i.e. account activation)
|
|
enable_service %w[ discourse gitea mediawiki xmpp ]
|
|
|
|
#TODO enable in development when we have easy setup of ejabberd etc.
|
|
return if Rails.env.development? || !Setting.ejabberd_enabled?
|
|
|
|
XmppExchangeContactsJob.perform_later(inviter, self) if inviter.present?
|
|
XmppSetDefaultBookmarksJob.perform_later(self)
|
|
end
|
|
end
|
|
|
|
def send_devise_notification(notification, *args)
|
|
devise_mailer.send(notification, self, *args).deliver_later
|
|
end
|
|
|
|
def reset_password(new_password, new_password_confirmation)
|
|
self.password = new_password
|
|
self.password_confirmation = new_password_confirmation
|
|
return false unless valid?
|
|
|
|
Devise::LDAP::Adapter.update_password(login_with, new_password)
|
|
clear_reset_password_token
|
|
save
|
|
end
|
|
|
|
def is_admin?
|
|
admin ||= if admin = Devise::LDAP::Adapter.get_ldap_param(self.cn, :admin)
|
|
!!admin.first
|
|
else
|
|
false
|
|
end
|
|
end
|
|
|
|
def address
|
|
"#{self.cn}@#{self.ou}"
|
|
end
|
|
|
|
def mastodon_address
|
|
return nil unless Setting.mastodon_enabled?
|
|
"#{self.cn}@#{Setting.mastodon_address_domain}"
|
|
end
|
|
|
|
def valid_attribute?(attribute_name)
|
|
self.valid?
|
|
self.errors[attribute_name].blank?
|
|
end
|
|
|
|
def ln_create_invoice(payload)
|
|
lndhub = Lndhub.new
|
|
lndhub.authenticate self
|
|
lndhub.addinvoice payload
|
|
end
|
|
|
|
def dn
|
|
return @dn if defined?(@dn)
|
|
@dn = Devise::LDAP::Adapter.get_dn(self.cn)
|
|
end
|
|
|
|
def ldap_entry(reload: false)
|
|
return @ldap_entry if defined?(@ldap_entry) && !reload
|
|
@ldap_entry = ldap.fetch_users(uid: self.cn, ou: self.ou).first
|
|
end
|
|
|
|
def display_name
|
|
@display_name ||= ldap_entry[:display_name]
|
|
end
|
|
|
|
def avatar
|
|
@avatar_base64 ||= LdapManager::FetchAvatar.call(cn: cn, ou: ou)
|
|
end
|
|
|
|
def services_enabled
|
|
ldap_entry[:service] || []
|
|
end
|
|
|
|
def enable_service(service)
|
|
current_services = services_enabled
|
|
new_services = Array(service).map(&:to_s)
|
|
services = (current_services + new_services).uniq
|
|
ldap.replace_attribute(dn, :service, services)
|
|
end
|
|
|
|
def disable_service(service)
|
|
current_services = services_enabled
|
|
disabled_services = Array(service).map(&:to_s)
|
|
services = (current_services - disabled_services).uniq
|
|
ldap.replace_attribute(dn, :service, services)
|
|
end
|
|
|
|
def disable_all_services
|
|
ldap.delete_attribute(dn,:service)
|
|
end
|
|
|
|
private
|
|
|
|
def ldap
|
|
return @ldap_service if defined?(@ldap_service)
|
|
@ldap_service = LdapService.new
|
|
end
|
|
|
|
def acceptable_avatar
|
|
return unless avatar_new.present?
|
|
|
|
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_new.content_type)
|
|
errors.add(:avatar, "must be a JPEG or PNG file")
|
|
end
|
|
end
|
|
end
|