ramon-devise 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. data/CHANGELOG.rdoc +109 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.rdoc +243 -0
  4. data/Rakefile +45 -0
  5. data/TODO +8 -0
  6. data/app/controllers/confirmations_controller.rb +33 -0
  7. data/app/controllers/passwords_controller.rb +41 -0
  8. data/app/controllers/sessions_controller.rb +33 -0
  9. data/app/models/devise_mailer.rb +53 -0
  10. data/app/views/confirmations/new.html.erb +16 -0
  11. data/app/views/devise_mailer/confirmation_instructions.html.erb +5 -0
  12. data/app/views/devise_mailer/reset_password_instructions.html.erb +8 -0
  13. data/app/views/passwords/edit.html.erb +20 -0
  14. data/app/views/passwords/new.html.erb +16 -0
  15. data/app/views/sessions/new.html.erb +23 -0
  16. data/generators/devise/USAGE +5 -0
  17. data/generators/devise/devise_generator.rb +25 -0
  18. data/generators/devise/lib/route_devise.rb +32 -0
  19. data/generators/devise/templates/README +22 -0
  20. data/generators/devise/templates/migration.rb +20 -0
  21. data/generators/devise/templates/model.rb +5 -0
  22. data/generators/devise_install/USAGE +3 -0
  23. data/generators/devise_install/devise_install_generator.rb +9 -0
  24. data/generators/devise_install/templates/devise.rb +40 -0
  25. data/generators/devise_views/USAGE +3 -0
  26. data/generators/devise_views/devise_views_generator.rb +24 -0
  27. data/init.rb +2 -0
  28. data/lib/devise.rb +79 -0
  29. data/lib/devise/controllers/filters.rb +111 -0
  30. data/lib/devise/controllers/helpers.rb +130 -0
  31. data/lib/devise/controllers/url_helpers.rb +49 -0
  32. data/lib/devise/failure.rb +38 -0
  33. data/lib/devise/hooks/confirmable.rb +11 -0
  34. data/lib/devise/hooks/rememberable.rb +27 -0
  35. data/lib/devise/locales/en.yml +18 -0
  36. data/lib/devise/mapping.rb +120 -0
  37. data/lib/devise/migrations.rb +51 -0
  38. data/lib/devise/models.rb +105 -0
  39. data/lib/devise/models/authenticatable.rb +97 -0
  40. data/lib/devise/models/confirmable.rb +156 -0
  41. data/lib/devise/models/recoverable.rb +88 -0
  42. data/lib/devise/models/rememberable.rb +95 -0
  43. data/lib/devise/models/validatable.rb +36 -0
  44. data/lib/devise/rails.rb +17 -0
  45. data/lib/devise/rails/routes.rb +109 -0
  46. data/lib/devise/rails/warden_compat.rb +26 -0
  47. data/lib/devise/strategies/authenticatable.rb +46 -0
  48. data/lib/devise/strategies/base.rb +24 -0
  49. data/lib/devise/strategies/rememberable.rb +35 -0
  50. data/lib/devise/version.rb +3 -0
  51. data/lib/devise/warden.rb +24 -0
  52. data/test/controllers/filters_test.rb +103 -0
  53. data/test/controllers/helpers_test.rb +55 -0
  54. data/test/controllers/url_helpers_test.rb +47 -0
  55. data/test/devise_test.rb +72 -0
  56. data/test/failure_test.rb +34 -0
  57. data/test/integration/authenticatable_test.rb +187 -0
  58. data/test/integration/confirmable_test.rb +89 -0
  59. data/test/integration/recoverable_test.rb +131 -0
  60. data/test/integration/rememberable_test.rb +65 -0
  61. data/test/mailers/confirmation_instructions_test.rb +59 -0
  62. data/test/mailers/reset_password_instructions_test.rb +62 -0
  63. data/test/mapping_test.rb +101 -0
  64. data/test/models/authenticatable_test.rb +118 -0
  65. data/test/models/confirmable_test.rb +237 -0
  66. data/test/models/recoverable_test.rb +141 -0
  67. data/test/models/rememberable_test.rb +130 -0
  68. data/test/models/validatable_test.rb +99 -0
  69. data/test/models_test.rb +111 -0
  70. data/test/rails_app/app/controllers/admins_controller.rb +6 -0
  71. data/test/rails_app/app/controllers/application_controller.rb +10 -0
  72. data/test/rails_app/app/controllers/home_controller.rb +4 -0
  73. data/test/rails_app/app/controllers/users_controller.rb +7 -0
  74. data/test/rails_app/app/helpers/application_helper.rb +3 -0
  75. data/test/rails_app/app/models/account.rb +3 -0
  76. data/test/rails_app/app/models/admin.rb +3 -0
  77. data/test/rails_app/app/models/organizer.rb +3 -0
  78. data/test/rails_app/app/models/user.rb +3 -0
  79. data/test/rails_app/config/boot.rb +110 -0
  80. data/test/rails_app/config/environment.rb +41 -0
  81. data/test/rails_app/config/environments/development.rb +17 -0
  82. data/test/rails_app/config/environments/production.rb +28 -0
  83. data/test/rails_app/config/environments/test.rb +28 -0
  84. data/test/rails_app/config/initializers/new_rails_defaults.rb +21 -0
  85. data/test/rails_app/config/initializers/session_store.rb +15 -0
  86. data/test/rails_app/config/routes.rb +18 -0
  87. data/test/routes_test.rb +79 -0
  88. data/test/support/assertions_helper.rb +22 -0
  89. data/test/support/integration_tests_helper.rb +66 -0
  90. data/test/support/model_tests_helper.rb +51 -0
  91. data/test/test_helper.rb +40 -0
  92. metadata +154 -0
@@ -0,0 +1,51 @@
1
+ module Devise
2
+ # Helpers to migration:
3
+ #
4
+ # create_table :accounts do |t|
5
+ # t.authenticatable
6
+ # t.confirmable
7
+ # t.recoverable
8
+ # t.rememberable
9
+ # t.timestamps
10
+ # end
11
+ #
12
+ # However this method does not add indexes. If you need them, here is the declaration:
13
+ #
14
+ # add_index "accounts", ["email"], :name => "email", :unique => true
15
+ # add_index "accounts", ["confirmation_token"], :name => "confirmation_token", :unique => true
16
+ # add_index "accounts", ["reset_password_token"], :name => "reset_password_token", :unique => true
17
+ #
18
+ module Migrations
19
+
20
+ # Creates email, encrypted_password and password_salt.
21
+ #
22
+ def authenticatable(options={})
23
+ null = options[:null] || false
24
+ string :email, :limit => 100, :null => null
25
+ string :encrypted_password, :limit => 40, :null => null
26
+ string :password_salt, :limit => 20, :null => null
27
+ end
28
+
29
+ # Creates confirmation_token, confirmed_at and confirmation_sent_at.
30
+ #
31
+ def confirmable
32
+ string :confirmation_token, :limit => 20
33
+ datetime :confirmed_at
34
+ datetime :confirmation_sent_at
35
+ end
36
+
37
+ # Creates reset_password_token.
38
+ #
39
+ def recoverable
40
+ string :reset_password_token, :limit => 20
41
+ end
42
+
43
+ # Creates remember_token and remember_created_at.
44
+ #
45
+ def rememberable
46
+ string :remember_token, :limit => 20
47
+ datetime :remember_created_at
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,105 @@
1
+ module Devise
2
+ module Models
3
+ # Creates configuration values for Devise and for the given module.
4
+ #
5
+ # Devise::Models.config(Devise::Authenticable, :stretches, 10)
6
+ #
7
+ # The line above creates:
8
+ #
9
+ # 1) An accessor called Devise.stretches, which value is used by default;
10
+ #
11
+ # 2) Some class methods for your model Model.stretches and Model.stretches=
12
+ # which have higher priority than Devise.stretches;
13
+ #
14
+ # 3) And an instance method stretches.
15
+ #
16
+ # To add the class methods you need to have a module ClassMethods defined
17
+ # inside the given class.
18
+ #
19
+ def self.config(mod, accessor, default=nil) #:nodoc:
20
+ Devise.send :"#{accessor}=", default
21
+
22
+ mod.class_eval <<-METHOD, __FILE__, __LINE__
23
+ def #{accessor}
24
+ self.class.#{accessor}
25
+ end
26
+ METHOD
27
+
28
+ mod.const_get(:ClassMethods).class_eval <<-METHOD, __FILE__, __LINE__
29
+ def #{accessor}
30
+ if defined?(@#{accessor})
31
+ @#{accessor}
32
+ elsif superclass.respond_to?(:#{accessor})
33
+ superclass.#{accessor}
34
+ else
35
+ Devise.#{accessor}
36
+ end
37
+ end
38
+
39
+ def #{accessor}=(value)
40
+ @#{accessor} = value
41
+ end
42
+ METHOD
43
+ end
44
+
45
+ # Shortcut method for including all devise modules inside your model.
46
+ # You can give some extra options while declaring devise in your model:
47
+ #
48
+ # * except: convenient option that allows you to add all devise modules,
49
+ # removing only the modules you setup here:
50
+ #
51
+ # devise :all, :except => :rememberable
52
+ #
53
+ # You can also give the following configuration values in a hash: :pepper,
54
+ # :stretches, :confirm_within and :remember_for. Please check your Devise
55
+ # initialiazer for a complete description on those values.
56
+ #
57
+ # Examples:
58
+ #
59
+ # # include only authenticatable module (default)
60
+ # devise
61
+ #
62
+ # # include authenticatable + confirmable modules
63
+ # devise :confirmable
64
+ #
65
+ # # include authenticatable + recoverable modules
66
+ # devise :recoverable
67
+ #
68
+ # # include authenticatable + rememberable modules
69
+ # devise :rememberable
70
+ #
71
+ # # include authenticatable + validatable modules
72
+ # devise :validatable
73
+ #
74
+ # # include authenticatable + confirmable + recoverable + rememberable + validatable
75
+ # devise :confirmable, :recoverable, :rememberable, :validatable
76
+ #
77
+ # # shortcut to include all modules (same as above)
78
+ # devise :all
79
+ #
80
+ # # include all except recoverable
81
+ # devise :all, :except => :recoverable
82
+ #
83
+ def devise(*modules)
84
+ options = modules.extract_options!
85
+
86
+ modules = Devise::ALL if modules.include?(:all)
87
+ modules -= Array(options.delete(:except))
88
+ modules = [:authenticatable] | modules
89
+
90
+ modules.each do |m|
91
+ devise_modules << m.to_sym
92
+ include Devise::Models.const_get(m.to_s.classify)
93
+ end
94
+
95
+ # Convert new keys to methods which overwrites Devise defaults
96
+ options.each { |key, value| send(:"#{key}=", value) }
97
+ end
98
+
99
+ # Stores all modules included inside the model, so we are able to verify
100
+ # which routes are needed.
101
+ def devise_modules
102
+ @devise_modules ||= []
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,97 @@
1
+ require 'digest/sha1'
2
+ require 'devise/strategies/authenticatable'
3
+
4
+ module Devise
5
+ module Models
6
+
7
+ # Authenticable Module, responsible for encrypting password and validating
8
+ # authenticity of a user while signing in.
9
+ #
10
+ # Configuration:
11
+ #
12
+ # You can overwrite configuration values by setting in globally in Devise,
13
+ # using devise method or overwriting the respective instance method.
14
+ #
15
+ # pepper: encryption key used for creating encrypted password. Each time
16
+ # password changes, it's gonna be encrypted again, and this key
17
+ # is added to the password and salt to create a secure hash.
18
+ # Always use `rake secret' to generate a new key.
19
+ #
20
+ # stretches: defines how many times the password will be encrypted.
21
+ #
22
+ # Examples:
23
+ #
24
+ # User.authenticate('email@test.com', 'password123') # returns authenticated user or nil
25
+ # User.find(1).valid_password?('password123') # returns true/false
26
+ #
27
+ module Authenticatable
28
+ def self.included(base)
29
+ base.class_eval do
30
+ extend ClassMethods
31
+
32
+ attr_reader :password
33
+ attr_accessor :password_confirmation
34
+ end
35
+ end
36
+
37
+ # Regenerates password salt and encrypted password each time password is
38
+ # setted.
39
+ def password=(new_password)
40
+ @password = new_password
41
+ self.password_salt = friendly_token
42
+ self.encrypted_password = password_digest(@password)
43
+ end
44
+
45
+ # Verifies whether an incoming_password (ie from login) is the user
46
+ # password.
47
+ def valid_password?(incoming_password)
48
+ password_digest(incoming_password) == encrypted_password
49
+ end
50
+
51
+ protected
52
+
53
+ # Gererates a default password digest based on salt, pepper and the
54
+ # incoming password.
55
+ def password_digest(password_to_digest)
56
+ digest = pepper
57
+ stretches.times { digest = secure_digest(password_salt, digest, password_to_digest, pepper) }
58
+ digest
59
+ end
60
+
61
+ # Generate a SHA1 digest joining args. Generated token is something like
62
+ #
63
+ # --arg1--arg2--arg3--argN--
64
+ def secure_digest(*tokens)
65
+ ::Digest::SHA1.hexdigest('--' << tokens.flatten.join('--') << '--')
66
+ end
67
+
68
+ # Generate a friendly string randomically to be used as token.
69
+ def friendly_token
70
+ ActiveSupport::SecureRandom.base64(15).tr('+/=', '-_ ').strip.delete("\n")
71
+ end
72
+
73
+ module ClassMethods
74
+ # Authenticate a user based on email and password. Returns the
75
+ # authenticated user if it's valid or nil.
76
+ # Attributes are :email and :password
77
+ def authenticate(attributes={})
78
+ authenticatable = find_by_email(attributes[:email])
79
+ authenticatable if authenticatable.try(:valid_password?, attributes[:password])
80
+ end
81
+
82
+ # Attempt to find a user by it's email. If not user is found, returns a
83
+ # new user with an email not found error.
84
+ def find_or_initialize_with_error_by_email(email)
85
+ perishable = find_or_initialize_by_email(email)
86
+ if perishable.new_record?
87
+ perishable.errors.add(:email, :not_found, :default => 'not found')
88
+ end
89
+ perishable
90
+ end
91
+ end
92
+
93
+ Devise::Models.config(self, :pepper)
94
+ Devise::Models.config(self, :stretches, 10)
95
+ end
96
+ end
97
+ end
@@ -0,0 +1,156 @@
1
+ require 'devise/hooks/confirmable'
2
+
3
+ module Devise
4
+ module Models
5
+
6
+ # Confirmable is responsible to verify if an account is already confirmed to
7
+ # sign in, and to send emails with confirmation instructions.
8
+ # Confirmation instructions are sent to the user email after creating a
9
+ # record, after updating it's email and also when manually requested by
10
+ # a new confirmation instruction request.
11
+ # Whenever the user update it's email, his account is automatically unconfirmed,
12
+ # it means it won't be able to sign in again without confirming the account
13
+ # again through the email that was sent.
14
+ #
15
+ # Configuration:
16
+ #
17
+ # confirm_within: the time you want the user will have to confirm it's account
18
+ # without blocking his access. When confirm_within is zero, the
19
+ # user won't be able to sign in without confirming. You can
20
+ # use this to let your user access some features of your
21
+ # application without confirming the account, but blocking it
22
+ # after a certain period (ie 7 days). By default confirm_within is
23
+ # zero, it means users always have to confirm to sign in.
24
+ #
25
+ # Examples:
26
+ #
27
+ # User.find(1).confirm! # returns true unless it's already confirmed
28
+ # User.find(1).confirmed? # true/false
29
+ # User.find(1).send_confirmation_instructions # manually send instructions
30
+ # User.find(1).reset_confirmation! # reset confirmation status and send instructions
31
+ module Confirmable
32
+
33
+ def self.included(base)
34
+ base.class_eval do
35
+ extend ClassMethods
36
+
37
+ before_create :generate_confirmation_token
38
+ after_create :send_confirmation_instructions
39
+ end
40
+ end
41
+
42
+ # Confirm a user by setting it's confirmed_at to actual time. If the user
43
+ # is already confirmed, add en error to email field
44
+ def confirm!
45
+ unless_confirmed do
46
+ self.confirmation_token = nil
47
+ self.confirmed_at = Time.now
48
+ save(false)
49
+ end
50
+ end
51
+
52
+ # Verifies whether a user is confirmed or not
53
+ def confirmed?
54
+ !new_record? && confirmed_at?
55
+ end
56
+
57
+ # Send confirmation instructions by email
58
+ def send_confirmation_instructions
59
+ ::DeviseMailer.deliver_confirmation_instructions(self)
60
+ end
61
+
62
+ # Remove confirmation date and send confirmation instructions, to ensure
63
+ # after sending these instructions the user won't be able to sign in without
64
+ # confirming it's account
65
+ def reset_confirmation!
66
+ unless_confirmed do
67
+ generate_confirmation_token
68
+ save(false)
69
+ send_confirmation_instructions
70
+ end
71
+ end
72
+
73
+ # Verify whether a user is active to sign in or not. If the user is
74
+ # already confirmed, it should never be blocked. Otherwise we need to
75
+ # calculate if the confirm time has not expired for this user, in other
76
+ # words, if the confirmation is still valid.
77
+ def active?
78
+ confirmed? || confirmation_period_valid?
79
+ end
80
+
81
+ protected
82
+
83
+ # Checks if the confirmation for the user is within the limit time.
84
+ # We do this by calculating if the difference between today and the
85
+ # confirmation sent date does not exceed the confirm in time configured.
86
+ # Confirm_in is a model configuration, must always be an integer value.
87
+ #
88
+ # Example:
89
+ #
90
+ # # confirm_within = 1.day and confirmation_sent_at = today
91
+ # confirmation_period_valid? # returns true
92
+ #
93
+ # # confirm_within = 5.days and confirmation_sent_at = 4.days.ago
94
+ # confirmation_period_valid? # returns true
95
+ #
96
+ # # confirm_within = 5.days and confirmation_sent_at = 5.days.ago
97
+ # confirmation_period_valid? # returns false
98
+ #
99
+ # # confirm_within = 0.days
100
+ # confirmation_period_valid? # will always return false
101
+ #
102
+ def confirmation_period_valid?
103
+ confirmation_sent_at? &&
104
+ (Time.now.utc - confirmation_sent_at.utc) < confirm_within
105
+ end
106
+
107
+ # Checks whether the record is confirmed or not, yielding to the block
108
+ # if it's already confirmed, otherwise adds an error to email.
109
+ def unless_confirmed
110
+ unless confirmed?
111
+ yield
112
+ else
113
+ errors.add(:email, :already_confirmed, :default => 'already confirmed')
114
+ false
115
+ end
116
+ end
117
+
118
+ # Generates a new random token for confirmation, and stores the time
119
+ # this token is being generated
120
+ def generate_confirmation_token
121
+ self.confirmed_at = nil
122
+ self.confirmation_token = friendly_token
123
+ self.confirmation_sent_at = Time.now.utc
124
+ end
125
+
126
+ module ClassMethods
127
+
128
+ # Attempt to find a user by it's email. If a record is found, send new
129
+ # confirmation instructions to it. If not user is found, returns a new user
130
+ # with an email not found error.
131
+ # Options must contain the user email
132
+ def send_confirmation_instructions(attributes={})
133
+ confirmable = find_or_initialize_with_error_by_email(attributes[:email])
134
+ confirmable.reset_confirmation! unless confirmable.new_record?
135
+ confirmable
136
+ end
137
+
138
+ # Find a user by it's confirmation token and try to confirm it.
139
+ # If no user is found, returns a new user with an error.
140
+ # If the user is already confirmed, create an error for the user
141
+ # Options must have the confirmation_token
142
+ def confirm!(attributes={})
143
+ confirmable = find_or_initialize_by_confirmation_token(attributes[:confirmation_token])
144
+ if confirmable.new_record?
145
+ confirmable.errors.add(:confirmation_token, :invalid)
146
+ else
147
+ confirmable.confirm!
148
+ end
149
+ confirmable
150
+ end
151
+ end
152
+
153
+ Devise::Models.config(self, :confirm_within, 0.days)
154
+ end
155
+ end
156
+ end
@@ -0,0 +1,88 @@
1
+ module Devise
2
+ module Models
3
+
4
+ # Recoverable takes care of reseting the user password and send reset instructions
5
+ # Examples:
6
+ #
7
+ # # resets the user password and save the record, true if valid passwords are given, otherwise false
8
+ # User.find(1).reset_password!('password123', 'password123')
9
+ # # only resets the user password, without saving the record
10
+ # user = User.find(1)
11
+ # user.reset_password('password123', 'password123')
12
+ # # creates a new token and send it with instructions about how to reset the password
13
+ # User.find(1).send_reset_password_instructions
14
+ module Recoverable
15
+ def self.included(base)
16
+ base.class_eval do
17
+ extend ClassMethods
18
+ end
19
+ end
20
+
21
+ # Update password
22
+ def reset_password(new_password, new_password_confirmation)
23
+ self.password = new_password
24
+ self.password_confirmation = new_password_confirmation
25
+ end
26
+
27
+ # Update password saving the record and clearing token. Returns true if
28
+ # the passwords are valid and the record was saved, false otherwise.
29
+ def reset_password!(new_password, new_password_confirmation)
30
+ reset_password(new_password, new_password_confirmation)
31
+ clear_reset_password_token if valid?
32
+ save
33
+ end
34
+
35
+ # Resets reset password token and send reset password instructions by email
36
+ def send_reset_password_instructions
37
+ generate_reset_password_token!
38
+ ::DeviseMailer.deliver_reset_password_instructions(self)
39
+ end
40
+
41
+ protected
42
+
43
+ # Generates a new random token for reset password
44
+ def generate_reset_password_token
45
+ self.reset_password_token = friendly_token
46
+ end
47
+
48
+ # Resets the reset password token with and save the record without
49
+ # validating
50
+ def generate_reset_password_token!
51
+ generate_reset_password_token && save(false)
52
+ end
53
+
54
+ # Removes reset_password token
55
+ def clear_reset_password_token
56
+ self.reset_password_token = nil
57
+ end
58
+
59
+ module ClassMethods
60
+
61
+ # Attempt to find a user by it's email. If a record is found, send new
62
+ # password instructions to it. If not user is found, returns a new user
63
+ # with an email not found error.
64
+ # Attributes must contain the user email
65
+ def send_reset_password_instructions(attributes={})
66
+ recoverable = find_or_initialize_with_error_by_email(attributes[:email])
67
+ recoverable.send_reset_password_instructions unless recoverable.new_record?
68
+ recoverable
69
+ end
70
+
71
+ # Attempt to find a user by it's reset_password_token to reset it's
72
+ # password. If a user is found, reset it's password and automatically
73
+ # try saving the record. If not user is found, returns a new user
74
+ # containing an error in reset_password_token attribute.
75
+ # Attributes must contain reset_password_token, password and confirmation
76
+ def reset_password!(attributes={})
77
+ recoverable = find_or_initialize_by_reset_password_token(attributes[:reset_password_token])
78
+ if recoverable.new_record?
79
+ recoverable.errors.add(:reset_password_token, :invalid)
80
+ else
81
+ recoverable.reset_password!(attributes[:password], attributes[:password_confirmation])
82
+ end
83
+ recoverable
84
+ end
85
+ end
86
+ end
87
+ end
88
+ end