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

View File

@@ -0,0 +1,267 @@
# frozen_string_literal: true
module API::V2
module Resource
class Phones < Grape::API
rescue_from(Twilio::REST::RestError) do |error|
Rails.logger.error "Twilio Client Error: #{error.message}"
error!({ errors: [twilio_dictionary_error(error.code)] }, 422)
end
helpers do
def validate_phone!(phone_number, landline = nil)
phone_number = Phone.international(phone_number)
error!({ errors: ['resource.phone.invalid_num'] }, 400) \
unless Phone.valid?(phone_number)
error!({ errors: ['resource.phone.number_exist'] }, 400) \
if Phone.verified.find_by_number(phone_number) && landline.blank?
# check phone is landline
error!({ errors: ['resource.phone.number_not_landline'] }, 400) \
if landline.present? && phone_number[2] == '9'
end
end
desc 'mobile related routes'
resource :mobiles do
desc 'Returns list of user\'s phones',
failure: [
{ code: 401, message: 'Invalid bearer token' },
],
success: Entities::Phone
get do
present current_user.phones, with: Entities::Phone
end
desc 'Add new mobile',
failure: [
{ code: 400, message: 'Required params are empty' },
{ code: 401, message: 'Invalid bearer token' },
{ code: 404, message: 'Record is not found' },
{ code: 422, message: 'Validation errors' }
],
success: { code: 200, message: 'New phone was added' }
params do
requires :phone_number,
type: String,
allow_blank: false,
desc: 'Phone number with country code(in iran +98)'
optional :channel,
type: String,
default: 'sms',
values: { value: -> { Phone::TWILIO_CHANNELS }, message: 'resource.phone.invalid_channel'},
desc: 'The verification method to use(this param is for legacy structure must be sms)'
end
post do
error!({ errors: ['kyc_follow_steps'] }, 403) if current_user.kyc_info.dig(:step) < 2
error!({ errors: ['resource.phone.code_doesnt_expired'] }, 422) if current_user.read_cache('register-mobile')
declared_params = declared(params)
validate_phone!(declared_params[:phone_number])
phone_number = Phone.international(declared_params[:phone_number])
# label = current_user.labels.find_by(key: 'access_phone', value: 'verified')
# error!({ errors: ['resource.phone.exists'] }, 422) if label.present?
if current_user.mobile('pending').present?
current_user.mobile('pending').update(number: phone_number)
else
current_user.phones.create(number: phone_number, category: 'mobile')
end
# code_error!(phone.errors.details, 422) if phone.errors.any?
error!({ errors: ['resource.phone.cant_send_message'] }, 422) unless KaveNegarSmsService.send_confirmation(current_user)
status 200
end
desc 'Resend activation code for mobile sms',
failure: [
{ code: 400, message: 'Required params are empty' },
{ code: 401, message: 'Invalid bearer token' },
{ code: 404, message: 'Record is not found' },
{ code: 422, message: 'Validation errors' }
],
success: { code: 200, message: 'Activation code was resend' }
params do
requires :phone_number,
type: String,
allow_blank: false,
desc: 'Phone number with country code( in iran +98 )'
optional :channel,
type: String,
default: 'sms',
values: { value: -> { Phone::TWILIO_CHANNELS }, message: 'resource.phone.invalid_channel'},
desc: 'The verification method to use(this param is for legacy structure must be sms)'
end
# TODO you can delete this api and use above
post '/send_code' do
error!({ errors: ['resource.phone.code_doesnt_expired'] }, 422) if current_user.read_cache('register-mobile')
declared_params = declared(params)
validate_phone!(declared_params[:phone_number])
phone_number = Phone.international(declared_params[:phone_number])
phone = current_user.phones.find_by_number(phone_number)
error!({ errors: ['resource.phone.doesnt_exist'] }, 404) unless phone
KaveNegarSmsService.send_confirmation(current_user)
status 200
end
desc 'Verify a mobile(enter code and verify number)',
failure: [
{ code: 400, message: 'Required params are empty' },
{ code: 401, message: 'Invalid bearer token' },
{ code: 404, message: 'Record is not found' }
],
success: API::V2::Entities::UserWithFullInfo
params do
requires :phone_number,
type: String,
allow_blank: false,
desc: 'phone number with country code(in iran with +98)'
requires :verification_code,
type: String,
allow_blank: false,
desc: 'Verification code from sms(this param is for legacy structure must be sms)'
end
post '/verify' do
declared_params = declared(params)
validate_phone!(declared_params[:phone_number])
error!({ errors: ['resource.phone.doesnt_exist'] }, 404) unless current_user.mobile('pending')
unless TOTPServiceAction.new('register-mobile').validate?(current_user.uid, declared(params)[:verification_code])
error!({ errors: ['resource.phone.verification_invalid'] }, 400)
end
current_user.delete_cache('register-mobile')
pending_mobile = current_user.mobile('pending')
last_verified_mobile = current_user.mobile('verified')
if last_verified_mobile&.step == 'owner_phone'
if pending_mobile.check_owner_ship
last_verified_mobile.update(state: 'replaced')
pending_mobile.update(validated_at: Time.current, state: 'verified', step: 'owner_phone')
else
pending_mobile.update(state: 'rejected')
end
elsif last_verified_mobile&.step == 'access_phone'
last_verified_mobile.update(state: 'replaced')
pending_mobile.update(validated_at: Time.current, step: 'access_phone', state: 'verified')
else
pending_mobile.update(validated_at: Time.current, step: 'access_phone', state: 'verified')
end
present current_user, with: API::V2::Entities::UserWithFullInfo
end
end
desc 'landline related routes'
resource :phones do
desc 'Add new phone',
failure: [
{ code: 400, message: 'Required params are empty' },
{ code: 401, message: 'Invalid bearer token' },
{ code: 404, message: 'Record is not found' },
{ code: 422, message: 'Validation errors' }
],
success: { code: 200, message: 'New phone was added' }
params do
requires :phone_number,
type: String,
allow_blank: false,
desc: 'Phone number with country code(in iran +98)'
optional :channel,
type: String,
default: 'call',
values: { value: -> { Phone::TWILIO_CHANNELS }, message: 'resource.phone.invalid_channel'},
desc: 'The verification method to use'
end
post do
error!({ errors: ['resource.phone.code_doesnt_expired'] }, 422) if current_user.read_cache('register-phone')
error!({ errors: ['kyc_follow_steps'] }, 403) if current_user.kyc_info.dig(:step) < 6
declared_params = declared(params)
validate_phone!(declared_params[:phone_number], true)
phone_number = Phone.international(declared_params[:phone_number])
phone = current_user.phones.find_by(category: :landline, step: 'telephone', state: 'pending')
label = current_user.labels.find_by(key: 'telephone', value: 'verified')
# TODO can edit for updating feature
error!({ errors: ['resource.phone.exists'] }, 422) if label.present?
if phone.present?
phone.update(number: phone_number)
else
current_user.phones.create(number: phone_number, category: :landline, step: 'telephone')
end
# code_error!(phone.errors.details, 422) if phone.errors.any?
KaveNegarSmsService.send_call_confirmation(current_user)
end
desc 'Resend activation code in call',
failure: [
{ code: 400, message: 'Required params are empty' },
{ code: 401, message: 'Invalid bearer token' },
{ code: 404, message: 'Record is not found' },
{ code: 422, message: 'Validation errors' }
],
success: { code: 200, message: 'Activation code was resend' }
params do
requires :phone_number,
type: String,
allow_blank: false,
desc: 'Phone number with country code'
optional :channel,
type: String,
default: 'call',
values: { value: -> { Phone::TWILIO_CHANNELS }, message: 'resource.phone.invalid_channel'},
desc: 'The verification method to use'
end
# TODO you can delete this api and use above
post '/send_code' do
error!({ errors: ['resource.phone.code_doesnt_expired'] }, 422) if current_user.read_cache('register-phone')
declared_params = declared(params)
validate_phone!(declared_params[:phone_number], true)
phone_number = Phone.international(declared_params[:phone_number])
phone = current_user.phones.find_by_number(phone_number)
error!({ errors: ['resource.phone.doesnt_exist'] }, 404) unless phone
KaveNegarSmsService.send_call_confirmation(current_user)
end
desc 'Verify a phone (enter code and verify number)',
failure: [
{ code: 400, message: 'Required params are empty' },
{ code: 401, message: 'Invalid bearer token' },
{ code: 404, message: 'Record is not found' }
],
success: API::V2::Entities::UserWithFullInfo
params do
requires :phone_number,
type: String,
allow_blank: false,
desc: 'Phone number with country code(in iran with +98)'
requires :verification_code,
type: String,
allow_blank: false,
desc: 'Verification code from call'
end
post '/verify' do
declared_params = declared(params)
validate_phone!(declared_params[:phone_number], true)
# phone_number = Phone.international(declared_params[:phone_number])
phone = current_user.phones.find_by(step: 'telephone', category: 'landline')
error!({ errors: ['resource.phone.doesnt_exist'] }, 404) unless phone
error!({ errors: ['resource.phone.verification_invalid'] }, 404) unless TOTPServiceAction.new('register-phone').validate?(current_user.uid, declared(params)[:verification_code])
current_user.delete_cache('register-phone')
phone.update(validated_at: Time.current, state: 'verified')
present current_user, with: API::V2::Entities::UserWithFullInfo
end
end
end
end
end