Commit df2f3c3675d596abd61cbb44fdca02afce38f111

Authored by Nathan Broadbent
1 parent 9c3b6ba9
Exists in master and in 1 other branch production

Added an optional username field to User model. Mongo makes this easy without an…

…y need for migrations, and I made my implementation as unintrusive as possible. Some organizations (such as ours) will find the "username" field useful when implementing an alternative authentication strategy. (Default is off, and this is fully backwards compatible.)
README.md
... ... @@ -100,11 +100,13 @@ for you. Checkout [Hoptoad](http://hoptoadapp.com) from the guys over at
100 100  
101 101 **Configuring LDAP authentication:**
102 102  
103   -Follow the instructions at https://github.com/cschiewek/devise_ldap_authenticatable
  103 + 1. In `config/config.yml`, set `user_has_username` to `true`
  104 + 2. Follow the instructions at https://github.com/cschiewek/devise_ldap_authenticatable
  105 + to set up the devise_ldap_authenticatable gem.
104 106  
105   -If you want to authenticate via `username`, add the following lines to `app/models/user.rb`:
  107 + 3. If you are authenticating by `username`, you will need to set the user's email
  108 + after authentication. You can do this by adding the following lines to `app/models/user.rb`:
106 109  
107   - field :username
108 110 before_save :set_ldap_email
109 111 def set_ldap_email
110 112 self.email = Devise::LdapAdapter.get_ldap_param(self.username, "mail")
... ...
app/models/user.rb
... ... @@ -19,6 +19,11 @@ class User
19 19  
20 20 attr_protected :admin
21 21  
  22 + if Errbit::Config.user_has_username
  23 + field :username
  24 + validates_presence_of :username
  25 + end
  26 +
22 27 # Mongoid doesn't seem to currently support
23 28 # referencing embedded documents
24 29 def watchers
... ...
app/views/users/_fields.html.haml
... ... @@ -3,7 +3,12 @@
3 3 .required
4 4 = f.label :name
5 5 = f.text_field :name
6   -
  6 +
  7 +- if Errbit::Config.user_has_username
  8 + .required
  9 + = f.label :username
  10 + = f.text_field :username
  11 +
7 12 .required
8 13 = f.label :email
9 14 = f.text_field :email
... ... @@ -11,11 +16,11 @@
11 16 .required
12 17 = f.label 'Entries per page'
13 18 = f.select :per_page, [10, 20, 30, 50, 75, 100]
14   -
  19 +
15 20 .required
16 21 = f.label :password
17 22 = f.password_field :password
18   -
  23 +
19 24 .required
20 25 = f.label :password_confirmation
21 26 = f.password_field :password_confirmation
... ... @@ -23,4 +28,5 @@
23 28 - if current_user.admin?
24 29 .checkbox
25 30 = f.check_box :admin
26   - = f.label :admin, 'Admin?'
27 31 \ No newline at end of file
  32 + = f.label :admin, 'Admin?'
  33 +
... ...
app/views/users/index.html.haml
... ... @@ -6,13 +6,17 @@
6 6 %thead
7 7 %tr
8 8 %th Name
  9 + - if Errbit::Config.user_has_username
  10 + %th Username
9 11 %th.main Email
10 12 %th Admin?
11 13 %tbody
12 14 - @users.each do |user|
13 15 %tr
14 16 %td.nowrap= link_to user.name, user_path(user)
  17 + - if Errbit::Config.user_has_username
  18 + %td= user.username
15 19 %td= user.email
16 20 %td= user.admin? ? 'Y' : 'N'
17 21 = will_paginate @users, :previous_label => '« Previous', :next_label => 'Next »'
18   -
19 22 \ No newline at end of file
  23 +
... ...
app/views/users/show.html.haml
... ... @@ -8,6 +8,10 @@
8 8 %tr
9 9 %th Email
10 10 %td.main= @user.email
  11 + - if Errbit::Config.user_has_username
  12 + %tr
  13 + %th Username
  14 + %td.main= @user.username
11 15 %tr
12 16 %th Admin?
13 17 %td= @user.admin? ? 'Y' : 'N'
... ...
config/config.example.yml
... ... @@ -6,6 +6,7 @@
6 6 # be copied to shared/config on the server when
7 7 # `cap deploy:setup` is ran the first time. Be sure
8 8 # to place production specific settings there
  9 +# You will need to restart the server after changing any settings.
9 10  
10 11 # The host of your errbit server
11 12 host: errbit.example.com
... ... @@ -26,3 +27,7 @@ email_at_notices: [1, 10, 100]
26 27 # Configure whether or not the user should be prompted before resolving an error.
27 28 confirm_resolve_err: true
28 29  
  30 +# Add an optional 'username' field to Users.
  31 +# Helpful if you want to plug in your own authentication strategy.
  32 +user_has_username: false
  33 +
... ...
config/initializers/devise.rb
... ... @@ -20,7 +20,7 @@ Devise.setup do |config|
20 20 # authenticating an user, both parameters are required. Remember that those
21 21 # parameters are used only when authenticating and not when retrieving from
22 22 # session. If you need permissions, you should implement that in a before filter.
23   - # config.authentication_keys = [ :email ]
  23 + config.authentication_keys = [ Errbit::Config.user_has_username ? :username : :email ]
24 24  
25 25 # Tell if authentication through request.params is enabled. True by default.
26 26 # config.params_authenticatable = true
... ... @@ -140,3 +140,4 @@ Devise.setup do |config|
140 140 # manager.default_strategies(:scope => :user).unshift :twitter_oauth
141 141 # end
142 142 end
  143 +
... ...
config/initializers/overrides.rb
1 1 require Rails.root.join('lib/overrides/mongoid/relations/builder.rb')
  2 +require Rails.root.join('lib/overrides/devise/failure_app.rb')
  3 +
... ...
config/locales/devise.en.yml
... ... @@ -10,7 +10,10 @@ en:
10 10 unauthenticated: 'You need to sign in before continuing.'
11 11 unconfirmed: 'You have to confirm your account before continuing.'
12 12 locked: 'Your account is locked.'
13   - invalid: 'Invalid email or password.'
  13 + invalid: 'Invalid login details.'
  14 + user:
  15 + email_invalid: 'Invalid email or password.'
  16 + username_invalid: 'Invalid username or password.'
14 17 invalid_token: 'Invalid authentication token.'
15 18 timeout: 'Your session expired, please sign in again to continue.'
16 19 inactive: 'Your account was not activated yet.'
... ... @@ -37,3 +40,4 @@ en:
37 40 subject: 'Reset password instructions'
38 41 unlock_instructions:
39 42 subject: 'Unlock Instructions'
  43 +
... ...
db/seeds.rb
... ... @@ -2,10 +2,12 @@ puts "Seeding database"
2 2 puts "-------------------------------"
3 3  
4 4 # Create an initial Admin User
  5 +admin_username = "errbit"
5 6 admin_email = "errbit@#{Errbit::Config.host}"
6 7 admin_pass = 'password'
7 8  
8 9 puts "Creating an initial admin user:"
  10 +puts "-- username: #{admin_username}" if Errbit::Config.user_has_username
9 11 puts "-- email: #{admin_email}"
10 12 puts "-- password: #{admin_pass}"
11 13 puts ""
... ... @@ -16,6 +18,8 @@ user = User.where(:email => admin_email).first || User.new({
16 18 :password => admin_pass,
17 19 :password_confirmation => admin_pass
18 20 })
  21 +user.username = admin_username if Errbit::Config.user_has_username
19 22  
20 23 user.admin = true
21 24 user.save!
  25 +
... ...
lib/overrides/devise/failure_app.rb 0 → 100644
... ... @@ -0,0 +1,15 @@
  1 +Devise::FailureApp.class_eval do
  2 + protected
  3 + # Handles both 'email_invalid' and 'username_invalid' messages.
  4 + def i18n_message(default = nil)
  5 + message = warden.message || warden_options[:message] || default || :unauthenticated
  6 +
  7 + if message.is_a?(Symbol)
  8 + I18n.t(:"#{scope}.#{Devise.authentication_keys.first}_#{message}", :resource_name => scope,
  9 + :scope => "devise.failure", :default => [message, message.to_s])
  10 + else
  11 + message.to_s
  12 + end
  13 + end
  14 +end
  15 +
... ...