Initial commit
This commit is contained in:
287
app/models/user.rb
Normal file
287
app/models/user.rb
Normal file
@@ -0,0 +1,287 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# User model
|
||||
class User < ApplicationRecord
|
||||
acts_as_eventable prefix: 'user', on: %i[create update]
|
||||
|
||||
include ModelCaching
|
||||
CHANGE_PASS_ATTEMPTS = 3
|
||||
has_secure_password
|
||||
|
||||
has_many :profiles, dependent: :destroy
|
||||
has_many :phones, dependent: :destroy
|
||||
has_many :data_storages, dependent: :destroy
|
||||
has_many :comments, dependent: :destroy
|
||||
has_many :documents, dependent: :destroy
|
||||
has_many :labels, dependent: :destroy
|
||||
has_many :activities, dependent: :destroy
|
||||
has_many :service_accounts, dependent: :destroy, foreign_key: 'owner_id'
|
||||
has_many :api_keys, dependent: :destroy, as: :key_holder_account, class_name: 'APIKey'
|
||||
has_many :treasuries, dependent: :destroy
|
||||
|
||||
validates_length_of :data, maximum: 1024
|
||||
validate :role_exists
|
||||
validate :referral_exists
|
||||
validates :data, data_is_json: true
|
||||
validates :email, email: true, presence: true, uniqueness: true
|
||||
validates :uid, presence: true, uniqueness: true
|
||||
validates :password, presence: true, if: :should_validate?
|
||||
validate :validate_pass!
|
||||
|
||||
scope :active, -> { where(state: 'active') }
|
||||
scope :with_pending_or_replaced_docs, -> { self.joins(:labels).where(labels:
|
||||
{ key: 'document', value: ['pending', 'replaced'], scope: 'private' }) }
|
||||
|
||||
before_validation :assign_uid
|
||||
before_validation :generate_password, on: :create
|
||||
after_update :disable_api_keys
|
||||
after_update :disable_service_accounts
|
||||
before_save :notfiy_new_level, if: :level_changed?
|
||||
before_save :notify_changed_otp, if: :otp_changed?
|
||||
|
||||
def notfiy_new_level
|
||||
::AMQP::Queue.enqueue_event("private" , self.uid, 'kyc', {msg: "new level is #{level}"})
|
||||
end
|
||||
|
||||
def notify_changed_otp
|
||||
::AMQP::Queue.enqueue_event("private" , self.uid, 'kyc', {msg: "otp state is #{otp}"})
|
||||
end
|
||||
|
||||
def generate_password
|
||||
self.password = SecureRandom.base64(30) unless password
|
||||
end
|
||||
|
||||
def validate_pass!
|
||||
return unless (new_record? && password.present?) || password.present?
|
||||
|
||||
validation_result = PasswordStrengthChecker.validate!(password)
|
||||
errors.add(:password, validation_result) unless validation_result == 'strong'
|
||||
end
|
||||
|
||||
def disable_service_accounts
|
||||
if state != 'active'
|
||||
service_accounts.each do |account|
|
||||
account.update(state: state)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def disable_api_keys
|
||||
if otp_previously_changed? && otp == false || state_previously_changed? && state != 'active'
|
||||
service_accounts.each do |service_account|
|
||||
service_account.api_keys.active.each do |key|
|
||||
key.update(state: 'inactive')
|
||||
end
|
||||
end
|
||||
api_keys.active.each do |key|
|
||||
key.update(state: 'inactive')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def active?
|
||||
self.state == 'active'
|
||||
end
|
||||
|
||||
def superadmin?
|
||||
self.role == 'superadmin'
|
||||
end
|
||||
|
||||
def role_exists
|
||||
return if Permission.pluck(:role).include?(role)
|
||||
|
||||
errors.add(:role, 'doesnt_exist')
|
||||
end
|
||||
|
||||
# Check if refferal exist for assignment
|
||||
def referral_exists
|
||||
errors.add(:referral_id, 'doesnt_exist') if referral_id.present? && User.find_by(id: referral_id).blank?
|
||||
end
|
||||
|
||||
def referral_uid
|
||||
user = User.find_by(id: referral_id)
|
||||
return if user.nil?
|
||||
|
||||
user.uid
|
||||
end
|
||||
|
||||
def role
|
||||
super.inquiry
|
||||
end
|
||||
|
||||
def should_validate?
|
||||
new_record? || password.present?
|
||||
end
|
||||
|
||||
def kyc_info
|
||||
user_points = 0
|
||||
last_level = 0
|
||||
tags = labels.with_private_scope.map { |l| [l.key, l.value].join ':' }
|
||||
levels = Level.all.order(id: :asc)
|
||||
levels.each do |lvl|
|
||||
# lvl.value always == 'verified'
|
||||
# so just verified label accepted
|
||||
break unless tags.include?(lvl.key + ':' + lvl.value)
|
||||
|
||||
user_points += lvl.id
|
||||
last_level = lvl.id
|
||||
end
|
||||
{ points: user_points.to_i, step: last_level.to_i, level: ::Level.what_level(user_points).to_i }
|
||||
end
|
||||
|
||||
def update_level
|
||||
update(level: Level.what_level(kyc_info.dig(:points))) unless level == kyc_info.dig(:level)
|
||||
end
|
||||
|
||||
def update_state
|
||||
@resulting_state = 'pending'
|
||||
|
||||
# check if user has all required labels for activation
|
||||
@resulting_state = 'active' if labels_include?(BarongConfig.list['activation_requirements'])
|
||||
|
||||
# FIXME BarongConfig should be a feature of Barong::App
|
||||
BarongConfig.list['state_triggers']&.each do |state, triggers|
|
||||
triggers.each { |trigger|
|
||||
# #TODO please fix it
|
||||
# if my key level is bank : user become banned
|
||||
labels.pluck(:key).each { |label| @resulting_state = state if label.start_with?(trigger) }
|
||||
}
|
||||
end
|
||||
update(state: @resulting_state) if @resulting_state != self.state
|
||||
end
|
||||
|
||||
# check if given key: values hash is a subset of private user labels
|
||||
def labels_include?(labels_hash)
|
||||
labels_hash <= private_labels_to_hash
|
||||
end
|
||||
|
||||
# Select all key-value pairs from user labels with private scope, merge in one hash
|
||||
def private_labels_to_hash
|
||||
key_value_arr = self.labels.with_private_scope.map do
|
||||
|l| { l.key => l.value }
|
||||
end
|
||||
key_value_hash = key_value_arr.inject(:merge)
|
||||
key_value_hash || {}
|
||||
end
|
||||
|
||||
def as_json_for_event_api
|
||||
{
|
||||
uid: uid,
|
||||
email: email,
|
||||
role: role,
|
||||
level: level,
|
||||
otp: otp,
|
||||
state: state,
|
||||
referral_uid: referral_uid,
|
||||
created_at: format_iso8601_time(created_at),
|
||||
updated_at: format_iso8601_time(updated_at)
|
||||
}
|
||||
end
|
||||
|
||||
def as_payload
|
||||
referral_uid = self.class.find_by(referral_id: referral_id).uid if referral_id.present?
|
||||
as_json(only: %i[uid email role level state otp]).merge(
|
||||
'referral_uid' => referral_uid,
|
||||
'last_change_pass' => change_pass_time,
|
||||
'cards' => cards&.pluck('data'),
|
||||
'ibans' => ibans&.pluck('data')
|
||||
)
|
||||
end
|
||||
|
||||
def language
|
||||
if data.blank?
|
||||
Barong::App.config.default_language.upcase
|
||||
else
|
||||
JSON.parse(data)['language'].upcase || Barong::App.config.default_language.upcase
|
||||
end
|
||||
end
|
||||
|
||||
def verified_profile
|
||||
profiles&.find_by(state: 'verified')
|
||||
end
|
||||
|
||||
def submitted_profile
|
||||
profiles&.find_by(state: 'submitted')
|
||||
end
|
||||
|
||||
def drafted_profile
|
||||
profiles&.where(state: 'drafted').last
|
||||
end
|
||||
|
||||
def front_icard
|
||||
documents.where(doc_type: 'Identity card', doc_category: 'front_side')&.last
|
||||
end
|
||||
|
||||
def selfie
|
||||
documents.where(doc_type: 'Selfie', doc_category: 'front_side')&.last
|
||||
end
|
||||
|
||||
def cards
|
||||
treasuries.where(kind: :card, state: :verified)
|
||||
end
|
||||
|
||||
def ibans
|
||||
treasuries.where(kind: :iban, state: :verified)
|
||||
end
|
||||
|
||||
def submitted_treasuries
|
||||
treasuries&.where(state: 'submitted')
|
||||
end
|
||||
|
||||
def last_password_activity
|
||||
activities.where(action: ['password reset', 'password change'], result: 'succeed', topic: 'password')
|
||||
.order('created_at DESC')&.last
|
||||
end
|
||||
|
||||
def change_pass_time
|
||||
last_password_activity&.created_at
|
||||
end
|
||||
|
||||
def access_phone
|
||||
phones.where(step: 'access_phone', category: 'mobile')&.last
|
||||
end
|
||||
|
||||
def mobile(state = nil)
|
||||
return phones.where(category: 'mobile').last unless state.present?
|
||||
|
||||
phones.where(category: 'mobile', state: state)&.last
|
||||
end
|
||||
|
||||
def landline
|
||||
return phones.where(category: 'landline').last unless step.present?
|
||||
|
||||
phones.where(category: 'landline', step: step).last
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assign_uid
|
||||
return unless uid.blank?
|
||||
|
||||
self.uid = UIDGenerator.generate(Barong::App.config.uid_prefix)
|
||||
end
|
||||
end
|
||||
|
||||
# == Schema Information
|
||||
# Schema version: 20210425062048
|
||||
#
|
||||
# Table name: users
|
||||
#
|
||||
# id :bigint not null, primary key
|
||||
# uid :string(255) not null
|
||||
# email :string(255) not null
|
||||
# password_digest :string(255) not null
|
||||
# role :string(255) default("member"), not null
|
||||
# data :text(65535)
|
||||
# level :integer default(0), not null
|
||||
# otp :boolean default(FALSE)
|
||||
# state :string(255) default("pending"), not null
|
||||
# referral_id :bigint
|
||||
# created_at :datetime not null
|
||||
# updated_at :datetime not null
|
||||
#
|
||||
# Indexes
|
||||
#
|
||||
# index_users_on_email (email) UNIQUE
|
||||
# index_users_on_uid (uid) UNIQUE
|
||||
#
|
||||
Reference in New Issue
Block a user