lib/models/phone.rb in devise_phone-0.0.17 vs lib/models/phone.rb in devise_phone-0.0.161
- old
+ new
@@ -1,114 +1,215 @@
require "devise_phone/hooks"
module Devise
module Models
+ # SmsActivable is responsible to verify if an account is already confirmed to
+ # sign in, and to send sms with confirmation instructions.
+ # Confirmation instructions are sent to the user phone after creating a
+ # record and when manually requested by a new confirmation instruction request.
+ #
+ # == Options
+ #
+ # Confirmable adds the following options to devise_for:
+ #
+ # * +sms_confirm_within+: the time you want to allow the user to access his account
+ # before confirming it. After this period, the user access is denied. You can
+ # use this to let your user access some features of your application without
+ # confirming the account, but blocking it after a certain period (ie 7 days).
+ # By default confirm_within is 0 days, so the user must confirm before entering.
+ # If you want to allow user to use parts of the site and block others override
+ # sms_confirmation_required? and check manually on selected pages using the
+ # require_sms_activated! helper or sms_confirmed? property on record
+ #
+ # == Examples
+ #
+ # User.find(1).sms_confirm! # returns true unless it's already confirmed
+ # User.find(1).sms_confirmed? # true/false
+ # User.find(1).send_sms_token # manually send token
+ #
module Phone
extend ActiveSupport::Concern
included do
- before_create :set_unverified_phone_attributes, :if => :phone_verification_needed?
- # after_create :private_generate_verification_code_and_send_sms, :if => :phone_verification_needed?
- # before_save :remember_old_phone_number
- after_save :private_generate_verification_code_and_send_sms, :if => :regenerate_phone_verification_needed?
+ before_create :set_phone_attributes, :if => :phone_verification_needed?
+ after_create :generate_verification_code_and_send_sms, :if => :phone_verification_needed?
end
- def generate_verification_code_and_send_sms
- if(phone_verification_needed?)
- private_generate_verification_code_and_send_sms
- end
- self.save!
- end
+ # # Confirm a user by setting it's sms_confirmed_at to actual time. If the user
+ # # is already confirmed, add en error to email field
+ # def confirm_sms!
+ # unless_sms_confirmed do
+ # self.sms_confirmation_token = nil
+ # self.sms_confirmed_at = Time.now
+ # save(:validate => false)
+ # end
+ # end
- def verify_phone_number_with_code_entered(code_entered)
- if phone_verification_needed? && (code_entered == self.phone_verification_code)
- mark_phone_as_verified!
- true
+ # # Verifies whether a user is sms-confirmed or not
+ # def confirmed_sms?
+ # !!sms_confirmed_at
+ # end
+
+ # Send confirmation token by sms
+ def generate_verification_code_and_send_sms
+ if(self.phone_number?)
+ self.phone_verification_code = generate_phone_verification_code
+ ::Devise.sms_sender.send_sms_verification_code_to(self)
else
+ # self.errors.add(:sms_confirmation_token, :no_phone_associated)
false
end
end
- private
+ # # Resend sms confirmation token. This method does not need to generate a new token.
+ # def resend_sms_token
+ # unless_sms_confirmed { send_sms_token }
+ # end
- def private_generate_verification_code_and_send_sms
- self.phone_verification_code = generate_phone_verification_code
- set_unverified_phone_attributes
- if phone_number.present?
- send_sms_verification_code
- end
- end
+ # Overwrites active? from Devise::Models::Activatable for sms confirmation
+ # by verifying whether a user is active to sign in or not. If the user
+ # is already confirmed, it should never be blocked. Otherwise we need to
+ # calculate if the confirm time has not expired for this user.
+ # def active?
+ # !sms_confirmation_required? || confirmed_sms? || confirmation_sms_period_valid?
+ # end
- def mark_phone_as_verified!
- update!(phone_number_verified: true,
- phone_verification_code: nil,
- phone_verification_code_sent_at: nil,
- phone_verified_at: DateTime.now)
- end
+ # # The message to be shown if the account is inactive.
+ # def inactive_message
+ # !confirmed_sms? ? I18n.t(:"devise.sms_activations.unconfirmed_sms") : super
+ # end
- # check if phone verification is needed and set errors here
+ # # If you don't want confirmation to be sent on create, neither a code
+ # # to be generated, call skip_sms_confirmation!
+ # def skip_sms_confirmation!
+ # self.sms_confirmed_at = Time.now
+ # end
+
+ protected
+
+ # Callback to overwrite if an sms confirmation is required or not.
def phone_verification_needed?
- if phone_number.blank?
- self.errors.add(:phone_verification_code, :empty_phone_number_field)
- false
- elsif phone_number_verified
- self.errors.add(:phone_verification_code, :phone_verification_not_needed)
- false
- else
- true
- end
+ phone_number.present? && !phone_number_verified
end
- def regenerate_phone_verification_needed?
- if phone_number.present?
- if phone_number_changed?
- true
- else
- false
- end
- # self.errors.add(:phone_verification_code, :empty_phone_number_field)
- # false
- else
- false
- end
- end
+ # def sms_confirmation_required?
+ # !confirmed_sms?
+ # end
- # set attributes to user indicating the phone number is unverified
- def set_unverified_phone_attributes
+ # Checks if the confirmation for the user is within the limit time.
+ # We do this by calculating if the difference between today and the
+ # confirmation sent date does not exceed the confirm in time configured.
+ # Confirm_in is a model configuration, must always be an integer value.
+ #
+ # Example:
+ #
+ # # sms_confirm_within = 1.day and sms_confirmation_sent_at = today
+ # confirmation_period_valid? # returns true
+ #
+ # # sms_confirm_within = 5.days and sms_confirmation_sent_at = 4.days.ago
+ # confirmation_period_valid? # returns true
+ #
+ # # sms_confirm_within = 5.days and sms_confirmation_sent_at = 5.days.ago
+ # confirmation_period_valid? # returns false
+ #
+ # # sms_confirm_within = 0.days
+ # confirmation_period_valid? # will always return false
+ #
+ # def confirmation_sms_period_valid?
+ # sms_confirmation_sent_at && sms_confirmation_sent_at.utc >= self.class.sms_confirm_within.ago
+ # end
+
+ # # Checks whether the record is confirmed or not, yielding to the block
+ # # if it's already confirmed, otherwise adds an error to email.
+ # def unless_sms_confirmed
+ # unless confirmed_sms?
+ # yield
+ # else
+ # self.errors.add(:sms_confirmation_token, :sms_already_confirmed)
+ # false
+ # end
+ # end
+
+ # Generates a new random token for confirmation, and stores the time
+ # this token is being generated
+ def set_phone_attributes
+
self.phone_number_verified = false
self.phone_verification_code_sent_at = DateTime.now
self.phone_verified_at = nil
# removes all white spaces, hyphens, and parenthesis
- if self.phone_number
- self.phone_number.gsub!(/[\s\-\(\)]+/, '')
- end
+ self.phone_number.gsub!(/[\s\-\(\)]+/, '')
end
- # return 4 digits random code 0-9
def generate_phone_verification_code
- verification_code = SecureRandom.random_number(10 ** 4).to_s.rjust(4,'0')
+ # begin
+ verification_code = SecureRandom.hex(3)
+ # end while self.class.exists?(phone_verification_code: verification_code)
verification_code
end
- # sends a message to number indicated in the secrets.yml
- def send_sms_verification_code
- number_to_send_to = self.phone_number
- verification_code = self.phone_verification_code
+ # def generate_sms_token!
+ # generate_sms_token && save(:validate => false)
+ # end
- twilio_sid = Rails.application.config.twilio[:sid]
- twilio_token = Rails.application.config.twilio[:token]
- twilio_phone_number = Rails.application.config.twilio[:phone_number]
- twilio_message_body = I18n.t("devise.phone.message_body", :verification_code => verification_code)
+ module ClassMethods
+ # # Attempt to find a user by it's email. If a record is found, send a new
+ # # sms token instructions to it. If not user is found, returns a new user
+ # # with an email not found error.
+ # # Options must contain the user email
+ # def send_sms_token(attributes={})
+ # sms_confirmable = find_or_initialize_with_errors(sms_confirmation_keys, attributes, :not_found)
+ # sms_confirmable.resend_sms_token if sms_confirmable.persisted?
+ # sms_confirmable
+ # end
- @twilio_client = Twilio::REST::Client.new twilio_sid, twilio_token
-
- @twilio_client.account.messages.create(
- :from => "+1#{twilio_phone_number}",
- :to => number_to_send_to,
- :body => twilio_message_body
- )
- end
+ # # Find a user by it's sms confirmation token and try to confirm it.
+ # # If no user is found, returns a new user with an error.
+ # # If the user is already confirmed, create an error for the user
+ # # Options must have the sms_confirmation_token
+ # def confirm_by_sms_token(sms_confirmation_token)
+ # sms_confirmable = find_or_initialize_with_error_by(:sms_confirmation_token, sms_confirmation_token)
+ # sms_confirmable.confirm_sms! if sms_confirmable.persisted?
+ # sms_confirmable
+ # end
+ def mark_phone_as_verified!
+ update!(phone_number_verified: true,
+ phone_verification_code: nil,
+ phone_verification_code_sent_at: nil,
+ phone_verified_at: DateTime.now)
+ end
+
+ def verify_phone_number_with_code_entered(code_entered)
+ if self.phone_verification_code == code_entered
+ mark_phone_as_verified!
+ end
+ end
+
+ def send_verification_code
+ self.set_phone_attributes
+ if self.save!
+ send_sms_for_phone_verification
+ end
+ end
+
+ # # Generates a small token that can be used conveniently on SMS's.
+ # # The token is 5 chars long and uppercased.
+
+ # def generate_small_token(column)
+ # loop do
+ # token = Devise.friendly_token[0,5].upcase
+ # break token unless to_adapter.find_first({ column => token })
+ # end
+ # end
+
+ # # Generate an sms token checking if one does not already exist in the database.
+ # def sms_confirmation_token
+ # generate_small_token(:sms_confirmation_token)
+ # end
+
+ # Devise::Models.config(self, :sms_confirm_within, :sms_confirmation_keys)
+ end
end
end
end