# 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