From 80f3f30704cd4b80827f372da916e361fbdb7ec7 Mon Sep 17 00:00:00 2001 From: "Carlos A. da Silva" Date: Tue, 20 Oct 2009 21:32:30 -0200 Subject: [PATCH] Creating confirm_in configuration to confirmable and verifying whether the user is active during the configured time without confirming. --- lib/devise/models/confirmable.rb | 37 +++++++++++++++++--- test/models/confirmable_test.rb | 58 ++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 5 deletions(-) diff --git a/lib/devise/models/confirmable.rb b/lib/devise/models/confirmable.rb index 444a3037..ef107725 100644 --- a/lib/devise/models/confirmable.rb +++ b/lib/devise/models/confirmable.rb @@ -16,6 +16,7 @@ module Devise # User.find(1).send_confirmation_instructions # manually send instructions # User.find(1).reset_confirmation! # reset confirmation status and send instructions module Confirmable + Devise.model_config(self, :confirm_in, 0) def self.included(base) base.class_eval do @@ -56,13 +57,32 @@ module Devise end end + # Verify 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, in other + # words, if the confirmation is still valid. + def active? + confirmed? || confirmation_period_valid? + end + protected - # Remove confirmation date from the user, ensuring after a user update - # it's email, it won't be able to sign in without confirming it. - def reset_confirmation - generate_confirmation_token - self.confirmed_at = nil + # 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: + # # confirm_in = 1 and confirmation_sent_at = today + # confirmation_period_valid? # returns true + # # confirm_in = 5 and confirmation_sent_at = 4.days.ago + # confirmation_period_valid? # returns true + # # confirm_in = 5 and confirmation_sent_at = 5.days.ago + # confirmation_period_valid? # returns false + # # confirm_in = 0 + # confirmation_period_valid? # will always return false + def confirmation_period_valid? + confirmation_sent_at? && + (Date.today - confirmation_sent_at.to_date).days.to_i < confirm_in end # Checks whether the record is confirmed or not, yielding to the block @@ -76,6 +96,13 @@ module Devise end end + # Remove confirmation date from the user, ensuring after a user update + # it's email, it won't be able to sign in without confirming it. + def reset_confirmation + generate_confirmation_token + self.confirmed_at = nil + end + # Generates a new random token for confirmation, and stores the time # this token is being generated def generate_confirmation_token diff --git a/test/models/confirmable_test.rb b/test/models/confirmable_test.rb index 782c17d5..153e510b 100644 --- a/test/models/confirmable_test.rb +++ b/test/models/confirmable_test.rb @@ -203,4 +203,62 @@ class ConfirmableTest < ActiveSupport::TestCase assert user.errors[:email].present? assert_equal 'already confirmed', user.errors[:email] end + + test 'confirm time should fallback to devise confirm in default configuration' do + begin + confirm_in = Devise.confirm_in + Devise.confirm_in = 1.day + user = new_user + user.confirmation_sent_at = 2.day.ago + assert_not user.active? + Devise.confirm_in = 3.days + assert user.active? + ensure + Devise.confirm_in = confirm_in + end + end + + test 'should be active when confirmation sent at is not overpast' do + Devise.confirm_in = 5.days + user = create_user + user.confirmation_sent_at = 4.days.ago + assert user.active? + end + + test 'should be active when already confirmed' do + user = create_user + assert_not user.confirmed? + assert_not user.active? + user.confirm! + assert user.confirmed? + assert user.active? + end + + test 'should not be active when confirmation was sent within the limit' do + Devise.confirm_in = 5.days + user = create_user + user.confirmation_sent_at = 5.days.ago + assert_not user.active? + end + + test 'should be active when confirm in is zero' do + Devise.confirm_in = 0.days + user = create_user + user.confirmation_sent_at = Date.today + assert_not user.active? + end + + test 'should not be active when confirmation was sent before confirm in time' do + Devise.confirm_in = 4.days + user = create_user + user.confirmation_sent_at = 5.days.ago + assert_not user.active? + end + + test 'should not be active without confirmation' do + user = create_user + user.update_attribute(:confirmation_sent_at, nil) + assert_not user.reload.active? + end + end