Initial commit

This commit is contained in:
Yaser
2026-08-13 19:56:46 +03:30
commit de1d57a67b
474 changed files with 43185 additions and 0 deletions

182
app/models/profile.rb Normal file
View File

@@ -0,0 +1,182 @@
# frozen_string_literal: true
# Profile model
# in original version user has only one drafted or submitted at time but can has many verified and rejected
# but in my version user can only one verified profile too
# only drafted profile editable, so dont send confirm param in creation or update time
class Profile < ApplicationRecord
include Encryptable
# acts_as_eventable prefix: 'profile', on: %i[create update]
belongs_to :user
belongs_to :city, required: false
enum state: { drafted: 0, submitted: 1, verified: 3, rejected: 4 }
EDITABLE_PARAMS = { drafted: %w[first_name last_name dob address postcode city country metadata national_code] }.freeze
OPTIONAL_PARAMS = %w[first_name last_name dob address postcode city country national_code].freeze
attr_encrypted :first_name
attr_encrypted :last_name
attr_encrypted :dob
attr_encrypted :address
attr_encrypted :national_code
validates :first_name, presence: true,
length: 1..255,
format: {
with: /\A[[:word:]\s\-']+\z/,
message: 'only allows letters, digits "-", "\'", and space'
},
if: proc { |a| a.first_name.present? }
validates :last_name, presence: true,
length: 1..255,
format: {
with: /\A[[:word:]\s\-']+\z/,
message: 'only allows letters, digits "-", "\'", and space'
},
if: proc { |a| a.last_name.present? }
validates :city, presence: false
validate :validate_country_format, if: ->(p) { p.country.present? }
validates :postcode, length: 2..255,
format: {
with: /\A[[:word:]\s\-]+\z/,
message: 'only allows letters, digits, "-" and space'
},
if: proc { |a| a.postcode.present? }
validates :address, length: 1..255,
format: {
with: /\A[[:word:]\s\-\\,\.~;\/:\#"\\&\')\(]+\z/,
message: 'only allows letters, digits "-", "", "\'", ".", ",", "#", ":", ";", "&" and space'
},
if: proc { |a| a.address.present? }
validates :national_code, length: { is: 10 },
format: { with: /\A\d+\z/, message: 'Ten Integer only. No sign allowed.' }
validates :metadata, data_is_json: true
validate :profile_state!, on: :create
# validate :profile_update!, on: :update
validate :dob_not_in_the_future
after_commit :start_profile_kyc_verification
scope :kept, -> { joins(:user).where(users: { discarded_at: nil }) }
before_validation do
squish_spaces
end
def full_name
"#{first_name} #{last_name}"
end
def reverse_full_name
"#{last_name} #{first_name}"
end
def sub_masked_last_name
last_name.sub(/(?<=\A.{1})(.*)/) { |match| '*' * match.length } if last_name
end
def sub_masked_national_code
national_code.sub(/(?<=\A.{5})(.*)/) { |match| '*' * match.length } if national_code
end
def sub_masked_dob
dob.to_s.sub(/(?<=\A.{8})(.*)/) { |match| '*' * match.length } if dob
end
def as_json_for_event_api
{
user: user.as_json_for_event_api,
first_name: first_name,
last_name: last_name,
dob: format_iso8601_time(dob),
address: address,
postcode: postcode,
city: city,
country: country,
metadata: metadata,
created_at: format_iso8601_time(created_at),
updated_at: format_iso8601_time(updated_at)
}
end
private
def validate_country_format
return if ISO3166::Country.find_country_by_alpha2(country) ||
ISO3166::Country.find_country_by_alpha3(country)
errors.add(:country, 'must have alpha2 or alpha3 format')
end
def squish_spaces
self.first_name = first_name&.squish
self.last_name = last_name&.squish
self.postcode = postcode&.squish
end
def profile_state!
# No limits for storing drafted and rejected profiles
# return if state.in?(%w[drafted rejected])
return if state.in?(%w[drafted rejected])
# This check is actual for profile states [drafted submitted]
# User cant create submitted or verified profile, when already had one of them
user_profiles_states = user.profiles.pluck(:state)
errors.add(:state, :exists, message: 'already exists') unless (user_profiles_states & %w[submitted verified]).empty?
end
def profile_update!
# we cant update rejected or verified profile
errors.add(:state, :exists, message: 'just edit submitted') if %w[rejected verified].include?(state_was)
end
def start_profile_kyc_verification
KycService.profile_step(self)
end
def dob_not_in_the_future
return if dob.nil?
self.dob = dob.to_date
return errors.add(:dob, :invalid_format, message: 'invalid date format') unless dob.is_a?(Date)
return errors.add(:dob, :invalid, message: 'cant be in future') if dob > Date.current
end
end
# == Schema Information
# Schema version: 20210425062048
#
# Table name: profiles
#
# id :bigint not null, primary key
# user_id :bigint
# author :string(255)
# applicant_id :string(255)
# first_name_encrypted :string(1024)
# last_name_encrypted :string(1024)
# dob_encrypted :string(255)
# address_encrypted :string(1024)
# postcode :string(255)
# city :string(255)
# country :string(255)
# state :integer default("drafted"), unsigned
# metadata :text(65535)
# created_at :datetime not null
# updated_at :datetime not null
# national_code_encrypted :string(255)
# city_id :bigint
#
# Indexes
#
# index_profiles_on_city_id (city_id)
# index_profiles_on_user_id (user_id)
#