nulogy-authlogic 3.1.0.1

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 (129) hide show
  1. data/Gemfile +3 -0
  2. data/Gemfile.lock +62 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +250 -0
  5. data/Rakefile +50 -0
  6. data/VERSION.yml +5 -0
  7. data/authlogic.gemspec +192 -0
  8. data/generators/session/session_generator.rb +9 -0
  9. data/generators/session/templates/session.rb +2 -0
  10. data/init.rb +1 -0
  11. data/lib/authlogic.rb +64 -0
  12. data/lib/authlogic/acts_as_authentic/base.rb +109 -0
  13. data/lib/authlogic/acts_as_authentic/email.rb +110 -0
  14. data/lib/authlogic/acts_as_authentic/logged_in_status.rb +59 -0
  15. data/lib/authlogic/acts_as_authentic/login.rb +142 -0
  16. data/lib/authlogic/acts_as_authentic/magic_columns.rb +24 -0
  17. data/lib/authlogic/acts_as_authentic/password.rb +355 -0
  18. data/lib/authlogic/acts_as_authentic/perishable_token.rb +105 -0
  19. data/lib/authlogic/acts_as_authentic/persistence_token.rb +68 -0
  20. data/lib/authlogic/acts_as_authentic/restful_authentication.rb +61 -0
  21. data/lib/authlogic/acts_as_authentic/session_maintenance.rb +139 -0
  22. data/lib/authlogic/acts_as_authentic/single_access_token.rb +65 -0
  23. data/lib/authlogic/acts_as_authentic/validations_scope.rb +32 -0
  24. data/lib/authlogic/authenticates_many/association.rb +42 -0
  25. data/lib/authlogic/authenticates_many/base.rb +54 -0
  26. data/lib/authlogic/controller_adapters/abstract_adapter.rb +67 -0
  27. data/lib/authlogic/controller_adapters/merb_adapter.rb +30 -0
  28. data/lib/authlogic/controller_adapters/rails_adapter.rb +50 -0
  29. data/lib/authlogic/controller_adapters/sinatra_adapter.rb +61 -0
  30. data/lib/authlogic/crypto_providers/aes256.rb +43 -0
  31. data/lib/authlogic/crypto_providers/bcrypt.rb +90 -0
  32. data/lib/authlogic/crypto_providers/md5.rb +34 -0
  33. data/lib/authlogic/crypto_providers/sha1.rb +35 -0
  34. data/lib/authlogic/crypto_providers/sha256.rb +50 -0
  35. data/lib/authlogic/crypto_providers/sha512.rb +50 -0
  36. data/lib/authlogic/crypto_providers/wordpress.rb +43 -0
  37. data/lib/authlogic/i18n.rb +84 -0
  38. data/lib/authlogic/i18n/translator.rb +15 -0
  39. data/lib/authlogic/random.rb +33 -0
  40. data/lib/authlogic/regex.rb +25 -0
  41. data/lib/authlogic/session/activation.rb +58 -0
  42. data/lib/authlogic/session/active_record_trickery.rb +72 -0
  43. data/lib/authlogic/session/base.rb +37 -0
  44. data/lib/authlogic/session/brute_force_protection.rb +96 -0
  45. data/lib/authlogic/session/callbacks.rb +96 -0
  46. data/lib/authlogic/session/cookies.rb +182 -0
  47. data/lib/authlogic/session/existence.rb +93 -0
  48. data/lib/authlogic/session/foundation.rb +77 -0
  49. data/lib/authlogic/session/http_auth.rb +99 -0
  50. data/lib/authlogic/session/id.rb +41 -0
  51. data/lib/authlogic/session/klass.rb +69 -0
  52. data/lib/authlogic/session/magic_columns.rb +95 -0
  53. data/lib/authlogic/session/magic_states.rb +59 -0
  54. data/lib/authlogic/session/params.rb +101 -0
  55. data/lib/authlogic/session/password.rb +240 -0
  56. data/lib/authlogic/session/perishable_token.rb +18 -0
  57. data/lib/authlogic/session/persistence.rb +70 -0
  58. data/lib/authlogic/session/priority_record.rb +34 -0
  59. data/lib/authlogic/session/scopes.rb +101 -0
  60. data/lib/authlogic/session/session.rb +62 -0
  61. data/lib/authlogic/session/timeout.rb +82 -0
  62. data/lib/authlogic/session/unauthorized_record.rb +50 -0
  63. data/lib/authlogic/session/validation.rb +82 -0
  64. data/lib/authlogic/test_case.rb +120 -0
  65. data/lib/authlogic/test_case/mock_controller.rb +55 -0
  66. data/lib/authlogic/test_case/mock_cookie_jar.rb +14 -0
  67. data/lib/authlogic/test_case/mock_logger.rb +10 -0
  68. data/lib/authlogic/test_case/mock_request.rb +19 -0
  69. data/lib/authlogic/test_case/rails_request_adapter.rb +30 -0
  70. data/lib/generators/authlogic/USAGE +8 -0
  71. data/lib/generators/authlogic/session_generator.rb +14 -0
  72. data/lib/generators/authlogic/templates/session.rb +2 -0
  73. data/rails/init.rb +1 -0
  74. data/shoulda_macros/authlogic.rb +69 -0
  75. data/test/acts_as_authentic_test/base_test.rb +18 -0
  76. data/test/acts_as_authentic_test/email_test.rb +116 -0
  77. data/test/acts_as_authentic_test/logged_in_status_test.rb +50 -0
  78. data/test/acts_as_authentic_test/login_test.rb +116 -0
  79. data/test/acts_as_authentic_test/magic_columns_test.rb +27 -0
  80. data/test/acts_as_authentic_test/password_test.rb +236 -0
  81. data/test/acts_as_authentic_test/perishable_token_test.rb +90 -0
  82. data/test/acts_as_authentic_test/persistence_token_test.rb +55 -0
  83. data/test/acts_as_authentic_test/restful_authentication_test.rb +40 -0
  84. data/test/acts_as_authentic_test/session_maintenance_test.rb +84 -0
  85. data/test/acts_as_authentic_test/single_access_test.rb +44 -0
  86. data/test/authenticates_many_test.rb +16 -0
  87. data/test/crypto_provider_test/aes256_test.rb +14 -0
  88. data/test/crypto_provider_test/bcrypt_test.rb +14 -0
  89. data/test/crypto_provider_test/sha1_test.rb +23 -0
  90. data/test/crypto_provider_test/sha256_test.rb +14 -0
  91. data/test/crypto_provider_test/sha512_test.rb +14 -0
  92. data/test/fixtures/companies.yml +5 -0
  93. data/test/fixtures/employees.yml +17 -0
  94. data/test/fixtures/projects.yml +3 -0
  95. data/test/fixtures/users.yml +24 -0
  96. data/test/i18n_test.rb +33 -0
  97. data/test/libs/affiliate.rb +7 -0
  98. data/test/libs/company.rb +6 -0
  99. data/test/libs/employee.rb +7 -0
  100. data/test/libs/employee_session.rb +2 -0
  101. data/test/libs/ldaper.rb +3 -0
  102. data/test/libs/ordered_hash.rb +9 -0
  103. data/test/libs/project.rb +3 -0
  104. data/test/libs/user.rb +5 -0
  105. data/test/libs/user_session.rb +5 -0
  106. data/test/random_test.rb +42 -0
  107. data/test/session_test/activation_test.rb +43 -0
  108. data/test/session_test/active_record_trickery_test.rb +46 -0
  109. data/test/session_test/brute_force_protection_test.rb +101 -0
  110. data/test/session_test/callbacks_test.rb +54 -0
  111. data/test/session_test/cookies_test.rb +136 -0
  112. data/test/session_test/credentials_test.rb +0 -0
  113. data/test/session_test/existence_test.rb +64 -0
  114. data/test/session_test/http_auth_test.rb +57 -0
  115. data/test/session_test/id_test.rb +17 -0
  116. data/test/session_test/klass_test.rb +40 -0
  117. data/test/session_test/magic_columns_test.rb +62 -0
  118. data/test/session_test/magic_states_test.rb +60 -0
  119. data/test/session_test/params_test.rb +53 -0
  120. data/test/session_test/password_test.rb +106 -0
  121. data/test/session_test/perishability_test.rb +15 -0
  122. data/test/session_test/persistence_test.rb +21 -0
  123. data/test/session_test/scopes_test.rb +60 -0
  124. data/test/session_test/session_test.rb +59 -0
  125. data/test/session_test/timeout_test.rb +52 -0
  126. data/test/session_test/unauthorized_record_test.rb +13 -0
  127. data/test/session_test/validation_test.rb +23 -0
  128. data/test/test_helper.rb +168 -0
  129. metadata +252 -0
@@ -0,0 +1,9 @@
1
+ class SessionGenerator < Rails::Generator::NamedBase
2
+ def manifest
3
+ record do |m|
4
+ m.class_collisions class_name
5
+ m.directory File.join('app/models', class_path)
6
+ m.template 'session.rb', File.join('app/models', class_path, "#{file_name}.rb")
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,2 @@
1
+ class <%= class_name %> < Authlogic::Session::Base
2
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/rails/init.rb"
data/lib/authlogic.rb ADDED
@@ -0,0 +1,64 @@
1
+ require "active_record"
2
+
3
+ AUTHLOGIC_PATH = File.dirname(__FILE__) + "/authlogic/"
4
+
5
+ [
6
+ "i18n",
7
+ "random",
8
+ "regex",
9
+
10
+ "controller_adapters/abstract_adapter",
11
+
12
+ "crypto_providers/md5",
13
+ "crypto_providers/sha1",
14
+ "crypto_providers/sha256",
15
+ "crypto_providers/sha512",
16
+ "crypto_providers/bcrypt",
17
+ "crypto_providers/aes256",
18
+
19
+ "authenticates_many/base",
20
+ "authenticates_many/association",
21
+
22
+ "acts_as_authentic/email",
23
+ "acts_as_authentic/logged_in_status",
24
+ "acts_as_authentic/login",
25
+ "acts_as_authentic/magic_columns",
26
+ "acts_as_authentic/password",
27
+ "acts_as_authentic/perishable_token",
28
+ "acts_as_authentic/persistence_token",
29
+ "acts_as_authentic/restful_authentication",
30
+ "acts_as_authentic/session_maintenance",
31
+ "acts_as_authentic/single_access_token",
32
+ "acts_as_authentic/validations_scope",
33
+ "acts_as_authentic/base",
34
+
35
+ "session/activation",
36
+ "session/active_record_trickery",
37
+ "session/brute_force_protection",
38
+ "session/callbacks",
39
+ "session/cookies",
40
+ "session/existence",
41
+ "session/foundation",
42
+ "session/http_auth",
43
+ "session/id",
44
+ "session/klass",
45
+ "session/magic_columns",
46
+ "session/magic_states",
47
+ "session/params",
48
+ "session/password",
49
+ "session/perishable_token",
50
+ "session/persistence",
51
+ "session/priority_record",
52
+ "session/scopes",
53
+ "session/session",
54
+ "session/timeout",
55
+ "session/unauthorized_record",
56
+ "session/validation",
57
+ "session/base"
58
+ ].each do |library|
59
+ require AUTHLOGIC_PATH + library
60
+ end
61
+
62
+ require AUTHLOGIC_PATH + "controller_adapters/rails_adapter" if defined?( Rails )
63
+ require AUTHLOGIC_PATH + "controller_adapters/merb_adapter" if defined?( Merb )
64
+ require AUTHLOGIC_PATH + "controller_adapters/sinatra_adapter" if defined?( Sinatra )
@@ -0,0 +1,109 @@
1
+ module Authlogic
2
+ module ActsAsAuthentic
3
+ # Provides the base functionality for acts_as_authentic
4
+ module Base
5
+ def self.included(klass)
6
+ klass.class_eval do
7
+ class_attribute :acts_as_authentic_modules, :acts_as_authentic_config
8
+ self.acts_as_authentic_modules ||= []
9
+ self.acts_as_authentic_config ||= {}
10
+ extend Config
11
+ end
12
+ end
13
+
14
+ module Config
15
+ # This includes a lot of helpful methods for authenticating records which The Authlogic::Session module relies on.
16
+ # To use it just do:
17
+ #
18
+ # class User < ActiveRecord::Base
19
+ # acts_as_authentic
20
+ # end
21
+ #
22
+ # Configuration is easy:
23
+ #
24
+ # acts_as_authentic do |c|
25
+ # c.my_configuration_option = my_value
26
+ # end
27
+ #
28
+ # See the various sub modules for the configuration they provide.
29
+ def acts_as_authentic(unsupported_options = nil, &block)
30
+ # Stop all configuration if the DB is not set up
31
+ raise StandardError.new("You must establish a database connection before using acts_as_authentic") if !db_setup?
32
+
33
+ raise ArgumentError.new("You are using the old v1.X.X configuration method for Authlogic. Instead of " +
34
+ "passing a hash of configuration options to acts_as_authentic, pass a block: acts_as_authentic { |c| c.my_option = my_value }") if !unsupported_options.nil?
35
+
36
+ yield self if block_given?
37
+ acts_as_authentic_modules.each { |mod| include mod }
38
+ end
39
+
40
+ # Since this part of Authlogic deals with another class, ActiveRecord, we can't just start including things
41
+ # in ActiveRecord itself. A lot of these module includes need to be triggered by the acts_as_authentic method
42
+ # call. For example, you don't want to start adding in email validations and what not into a model that has
43
+ # nothing to do with Authlogic.
44
+ #
45
+ # That being said, this is your tool for extending Authlogic and "hooking" into the acts_as_authentic call.
46
+ def add_acts_as_authentic_module(mod, action = :append)
47
+ modules = acts_as_authentic_modules.clone
48
+ case action
49
+ when :append
50
+ modules << mod
51
+ when :prepend
52
+ modules = [mod] + modules
53
+ end
54
+ modules.uniq!
55
+ self.acts_as_authentic_modules = modules
56
+ end
57
+
58
+ # This is the same as add_acts_as_authentic_module, except that it removes the module from the list.
59
+ def remove_acts_as_authentic_module(mod)
60
+ modules = acts_as_authentic_modules.clone
61
+ modules.delete(mod)
62
+ self.acts_as_authentic_modules = modules
63
+ end
64
+
65
+ private
66
+ def db_setup?
67
+ begin
68
+ column_names
69
+ true
70
+ rescue Exception
71
+ false
72
+ end
73
+ end
74
+
75
+ def rw_config(key, value, default_value = nil, read_value = nil)
76
+ if value == read_value
77
+ acts_as_authentic_config.include?(key) ? acts_as_authentic_config[key] : default_value
78
+ else
79
+ config = acts_as_authentic_config.clone
80
+ config[key] = value
81
+ self.acts_as_authentic_config = config
82
+ value
83
+ end
84
+ end
85
+
86
+ def first_column_to_exist(*columns_to_check)
87
+ if db_setup?
88
+ columns_to_check.each { |column_name| return column_name.to_sym if column_names.include?(column_name.to_s) }
89
+ end
90
+ columns_to_check.first && columns_to_check.first.to_sym
91
+ end
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ ::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::Base
98
+ ::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::Email
99
+ ::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::LoggedInStatus
100
+ ::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::Login
101
+ ::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::MagicColumns
102
+ ::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::Password
103
+ ::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::PerishableToken
104
+ ::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::PersistenceToken
105
+ ::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::RestfulAuthentication
106
+ ::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::SessionMaintenance
107
+ ::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::SingleAccessToken
108
+ ::ActiveRecord::Base.send :include, Authlogic::ActsAsAuthentic::ValidationsScope
109
+
@@ -0,0 +1,110 @@
1
+ module Authlogic
2
+ module ActsAsAuthentic
3
+ # Sometimes models won't have an explicit "login" or "username" field. Instead they want to use the email field.
4
+ # In this case, authlogic provides validations to make sure the email submited is actually a valid email. Don't worry,
5
+ # if you do have a login or username field, Authlogic will still validate your email field. One less thing you have to
6
+ # worry about.
7
+ module Email
8
+ def self.included(klass)
9
+ klass.class_eval do
10
+ extend Config
11
+ add_acts_as_authentic_module(Methods)
12
+ end
13
+ end
14
+
15
+ # Configuration to modify how Authlogic handles the email field.
16
+ module Config
17
+ # The name of the field that stores email addresses.
18
+ #
19
+ # * <tt>Default:</tt> :email, if it exists
20
+ # * <tt>Accepts:</tt> Symbol
21
+ def email_field(value = nil)
22
+ rw_config(:email_field, value, first_column_to_exist(nil, :email, :email_address))
23
+ end
24
+ alias_method :email_field=, :email_field
25
+
26
+ # Toggles validating the email field or not.
27
+ #
28
+ # * <tt>Default:</tt> true
29
+ # * <tt>Accepts:</tt> Boolean
30
+ def validate_email_field(value = nil)
31
+ rw_config(:validate_email_field, value, true)
32
+ end
33
+ alias_method :validate_email_field=, :validate_email_field
34
+
35
+ # A hash of options for the validates_length_of call for the email field. Allows you to change this however you want.
36
+ #
37
+ # <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
38
+ # merge options into it. Checkout the convenience function merge_validates_length_of_email_field_options to merge
39
+ # options.</b>
40
+ #
41
+ # * <tt>Default:</tt> {:maximum => 100}
42
+ # * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
43
+ def validates_length_of_email_field_options(value = nil)
44
+ rw_config(:validates_length_of_email_field_options, value, {:maximum => 100})
45
+ end
46
+ alias_method :validates_length_of_email_field_options=, :validates_length_of_email_field_options
47
+
48
+ # A convenience function to merge options into the validates_length_of_email_field_options. So intead of:
49
+ #
50
+ # self.validates_length_of_email_field_options = validates_length_of_email_field_options.merge(:my_option => my_value)
51
+ #
52
+ # You can do this:
53
+ #
54
+ # merge_validates_length_of_email_field_options :my_option => my_value
55
+ def merge_validates_length_of_email_field_options(options = {})
56
+ self.validates_length_of_email_field_options = validates_length_of_email_field_options.merge(options)
57
+ end
58
+
59
+ # A hash of options for the validates_format_of call for the email field. Allows you to change this however you want.
60
+ #
61
+ # <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
62
+ # merge options into it. Checkout the convenience function merge_validates_format_of_email_field_options to merge
63
+ # options.</b>
64
+ #
65
+ # * <tt>Default:</tt> {:with => Authlogic::Regex.email, :message => lambda {I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}}
66
+ # * <tt>Accepts:</tt> Hash of options accepted by validates_format_of
67
+ def validates_format_of_email_field_options(value = nil)
68
+ rw_config(:validates_format_of_email_field_options, value, {:with => Authlogic::Regex.email, :message => Proc.new{I18n.t('error_messages.email_invalid', :default => "should look like an email address.")}})
69
+ end
70
+ alias_method :validates_format_of_email_field_options=, :validates_format_of_email_field_options
71
+
72
+ # See merge_validates_length_of_email_field_options. The same thing except for validates_format_of_email_field_options.
73
+ def merge_validates_format_of_email_field_options(options = {})
74
+ self.validates_format_of_email_field_options = validates_format_of_email_field_options.merge(options)
75
+ end
76
+
77
+ # A hash of options for the validates_uniqueness_of call for the email field. Allows you to change this however you want.
78
+ #
79
+ # <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
80
+ # merge options into it. Checkout the convenience function merge_validates_uniqueness_of_email_field_options to merge
81
+ # options.</b>
82
+ #
83
+ # * <tt>Default:</tt> {:case_sensitive => false, :scope => validations_scope, :if => "#{email_field}_changed?".to_sym}
84
+ # * <tt>Accepts:</tt> Hash of options accepted by validates_uniqueness_of
85
+ def validates_uniqueness_of_email_field_options(value = nil)
86
+ rw_config(:validates_uniqueness_of_email_field_options, value, {:case_sensitive => false, :scope => validations_scope, :if => "#{email_field}_changed?".to_sym})
87
+ end
88
+ alias_method :validates_uniqueness_of_email_field_options=, :validates_uniqueness_of_email_field_options
89
+
90
+ # See merge_validates_length_of_email_field_options. The same thing except for validates_uniqueness_of_email_field_options.
91
+ def merge_validates_uniqueness_of_email_field_options(options = {})
92
+ self.validates_uniqueness_of_email_field_options = validates_uniqueness_of_email_field_options.merge(options)
93
+ end
94
+ end
95
+
96
+ # All methods relating to the email field
97
+ module Methods
98
+ def self.included(klass)
99
+ klass.class_eval do
100
+ if validate_email_field && email_field
101
+ validates_length_of email_field, validates_length_of_email_field_options
102
+ validates_format_of email_field, validates_format_of_email_field_options
103
+ validates_uniqueness_of email_field, validates_uniqueness_of_email_field_options
104
+ end
105
+ end
106
+ end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,59 @@
1
+ module Authlogic
2
+ module ActsAsAuthentic
3
+ # Since web applications are stateless there is not sure fire way to tell if a user is logged in or not,
4
+ # from the database perspective. The best way to do this is to provide a "timeout" based on inactivity.
5
+ # So if that user is inactive for a certain amount of time we assume they are logged out. That's what this
6
+ # module is all about.
7
+ module LoggedInStatus
8
+ def self.included(klass)
9
+ klass.class_eval do
10
+ extend Config
11
+ add_acts_as_authentic_module(Methods)
12
+ end
13
+ end
14
+
15
+ # All configuration for the logged in status feature set.
16
+ module Config
17
+ # The timeout to determine when a user is logged in or not.
18
+ #
19
+ # * <tt>Default:</tt> 10.minutes
20
+ # * <tt>Accepts:</tt> Fixnum
21
+ def logged_in_timeout(value = nil)
22
+ rw_config(:logged_in_timeout, (!value.nil? && value.to_i) || value, 10.minutes.to_i)
23
+ end
24
+ alias_method :logged_in_timeout=, :logged_in_timeout
25
+ end
26
+
27
+ # All methods for the logged in status feature seat.
28
+ module Methods
29
+ def self.included(klass)
30
+ return if !klass.column_names.include?("last_request_at")
31
+
32
+ klass.class_eval do
33
+ include InstanceMethods
34
+ scope :logged_in, lambda{ where("last_request_at > ?", logged_in_timeout.seconds.ago) }
35
+ scope :logged_out, lambda{ where("last_request_at is NULL or last_request_at <= ?", logged_in_timeout.seconds.ago) }
36
+ end
37
+ end
38
+
39
+ module InstanceMethods
40
+ # Returns true if the last_request_at > logged_in_timeout.
41
+ def logged_in?
42
+ raise "Can not determine the records login state because there is no last_request_at column" if !respond_to?(:last_request_at)
43
+ !last_request_at.nil? && last_request_at > logged_in_timeout.seconds.ago
44
+ end
45
+
46
+ # Opposite of logged_in?
47
+ def logged_out?
48
+ !logged_in?
49
+ end
50
+
51
+ private
52
+ def logged_in_timeout
53
+ self.class.logged_in_timeout
54
+ end
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,142 @@
1
+ module Authlogic
2
+ module ActsAsAuthentic
3
+ # Handles everything related to the login field.
4
+ module Login
5
+ def self.included(klass)
6
+ klass.class_eval do
7
+ extend Config
8
+ add_acts_as_authentic_module(Methods)
9
+ end
10
+ end
11
+
12
+ # Configuration for the login field.
13
+ module Config
14
+ # The name of the login field in the database.
15
+ #
16
+ # * <tt>Default:</tt> :login or :username, if they exist
17
+ # * <tt>Accepts:</tt> Symbol
18
+ def login_field(value = nil)
19
+ rw_config(:login_field, value, first_column_to_exist(nil, :login, :username))
20
+ end
21
+ alias_method :login_field=, :login_field
22
+
23
+ # Whether or not to validate the login field
24
+ #
25
+ # * <tt>Default:</tt> true
26
+ # * <tt>Accepts:</tt> Boolean
27
+ def validate_login_field(value = nil)
28
+ rw_config(:validate_login_field, value, true)
29
+ end
30
+ alias_method :validate_login_field=, :validate_login_field
31
+
32
+ # A hash of options for the validates_length_of call for the login field. Allows you to change this however you want.
33
+ #
34
+ # <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
35
+ # merge options into it. Checkout the convenience function merge_validates_length_of_login_field_options to merge
36
+ # options.</b>
37
+ #
38
+ # * <tt>Default:</tt> {:within => 3..100}
39
+ # * <tt>Accepts:</tt> Hash of options accepted by validates_length_of
40
+ def validates_length_of_login_field_options(value = nil)
41
+ rw_config(:validates_length_of_login_field_options, value, {:within => 3..100})
42
+ end
43
+ alias_method :validates_length_of_login_field_options=, :validates_length_of_login_field_options
44
+
45
+ # A convenience function to merge options into the validates_length_of_login_field_options. So instead of:
46
+ #
47
+ # self.validates_length_of_login_field_options = validates_length_of_login_field_options.merge(:my_option => my_value)
48
+ #
49
+ # You can do this:
50
+ #
51
+ # merge_validates_length_of_login_field_options :my_option => my_value
52
+ def merge_validates_length_of_login_field_options(options = {})
53
+ self.validates_length_of_login_field_options = validates_length_of_login_field_options.merge(options)
54
+ end
55
+
56
+ # A hash of options for the validates_format_of call for the login field. Allows you to change this however you want.
57
+ #
58
+ # <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
59
+ # merge options into it. Checkout the convenience function merge_validates_format_of_login_field_options to merge
60
+ # options.</b>
61
+ #
62
+ # * <tt>Default:</tt> {:with => Authlogic::Regex.login, :message => lambda {I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")}}
63
+ # * <tt>Accepts:</tt> Hash of options accepted by validates_format_of
64
+ def validates_format_of_login_field_options(value = nil)
65
+ rw_config(:validates_format_of_login_field_options, value, {:with => Authlogic::Regex.login, :message => Proc.new{I18n.t('error_messages.login_invalid', :default => "should use only letters, numbers, spaces, and .-_@ please.")}})
66
+ end
67
+ alias_method :validates_format_of_login_field_options=, :validates_format_of_login_field_options
68
+
69
+ # See merge_validates_length_of_login_field_options. The same thing, except for validates_format_of_login_field_options
70
+ def merge_validates_format_of_login_field_options(options = {})
71
+ self.validates_format_of_login_field_options = validates_format_of_login_field_options.merge(options)
72
+ end
73
+
74
+ # A hash of options for the validates_uniqueness_of call for the login field. Allows you to change this however you want.
75
+ #
76
+ # <b>Keep in mind this is ruby. I wanted to keep this as flexible as possible, so you can completely replace the hash or
77
+ # merge options into it. Checkout the convenience function merge_validates_format_of_login_field_options to merge
78
+ # options.</b>
79
+ #
80
+ # * <tt>Default:</tt> {:case_sensitive => false, :scope => validations_scope, :if => "#{login_field}_changed?".to_sym}
81
+ # * <tt>Accepts:</tt> Hash of options accepted by validates_uniqueness_of
82
+ def validates_uniqueness_of_login_field_options(value = nil)
83
+ rw_config(:validates_uniqueness_of_login_field_options, value, {:case_sensitive => false, :scope => validations_scope, :if => "#{login_field}_changed?".to_sym})
84
+ end
85
+ alias_method :validates_uniqueness_of_login_field_options=, :validates_uniqueness_of_login_field_options
86
+
87
+ # See merge_validates_length_of_login_field_options. The same thing, except for validates_uniqueness_of_login_field_options
88
+ def merge_validates_uniqueness_of_login_field_options(options = {})
89
+ self.validates_uniqueness_of_login_field_options = validates_uniqueness_of_login_field_options.merge(options)
90
+ end
91
+
92
+ # This method allows you to find a record with the given login. If you notice, with Active Record you have the
93
+ # validates_uniqueness_of validation function. They give you a :case_sensitive option. I handle this in the same
94
+ # manner that they handle that. If you are using the login field and set false for the :case_sensitive option in
95
+ # validates_uniqueness_of_login_field_options this method will modify the query to look something like:
96
+ #
97
+ # where("#{quoted_table_name}.#{field} LIKE ?", login).first
98
+ #
99
+ # If you don't specify this it calls the good old find_by_* method:
100
+ #
101
+ # find_by_login(login)
102
+ #
103
+ # The above also applies for using email as your login, except that you need to set the :case_sensitive in
104
+ # validates_uniqueness_of_email_field_options to false.
105
+ #
106
+ # The only reason I need to do the above is for Postgres and SQLite since they perform case sensitive searches with the
107
+ # find_by_* methods.
108
+ def find_by_smart_case_login_field(login)
109
+ if login_field
110
+ find_with_case(login_field, login, validates_uniqueness_of_login_field_options[:case_sensitive] != false)
111
+ else
112
+ find_with_case(email_field, login, validates_uniqueness_of_email_field_options[:case_sensitive] != false)
113
+ end
114
+ end
115
+
116
+ private
117
+ def find_with_case(field, value, sensitivity = true)
118
+ if sensitivity
119
+ send("find_by_#{field}", value)
120
+ else
121
+ like_word = ::ActiveRecord::Base.connection.adapter_name == "PostgreSQL" ? "ILIKE" : "LIKE"
122
+ where("#{quoted_table_name}.#{field} #{like_word} ?", value.mb_chars).first
123
+ end
124
+ end
125
+ end
126
+
127
+ # All methods relating to the login field
128
+ module Methods
129
+ # Adds in various validations, modules, etc.
130
+ def self.included(klass)
131
+ klass.class_eval do
132
+ if validate_login_field && login_field
133
+ validates_length_of login_field, validates_length_of_login_field_options
134
+ validates_format_of login_field, validates_format_of_login_field_options
135
+ validates_uniqueness_of login_field, validates_uniqueness_of_login_field_options
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end