288 lines
8.0 KiB
Ruby
288 lines
8.0 KiB
Ruby
# 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
|
|
#
|