quo_vadis 1.0.7 → 1.1.0

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.
data/CHANGELOG.md CHANGED
@@ -1,10 +1,31 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## 1.1.0 (7 October 2011)
4
+
5
+ * Correctly handle blank username in password reset.
6
+ * Allow configuration of cookie domain.
7
+ * Pass controller to signed_{in,out}_url to allow routes with options/parameters.
8
+ * Fix bug where `signed_in_url` config setting was overwritten.
9
+ * Harmonise bcrypt-ruby dependency with ActiveModel::SecurePassword.
10
+ * Allow conditional validation of authentication attributes.
11
+ * Allow authentication of any model.
12
+
13
+
14
+ ## 1.0.7 (4 October 2011)
15
+
16
+ * Allow more recent bcrypt-ruby versions.
17
+
18
+
19
+ ## 1.0.6 (4 October 2011)
20
+
21
+ * Fix sign-in hook when called outside Quo Vadis.
22
+
3
23
 
4
24
  ## 1.0.5 (23 February 2011)
5
25
 
6
26
  * Support blocking of sign-in process.
7
27
 
28
+
8
29
  ## 1.0.4 (22 February 2011)
9
30
 
10
31
  * Work with Rails' improved CSRF protection.
data/README.md CHANGED
@@ -12,14 +12,14 @@ Features:
12
12
  * Uses BCrypt to encrypt passwords.
13
13
  * Sign in, sign out, forgotten password, authenticate actions, remember user between browser sessions.
14
14
  * Block accounts.
15
+ * Let you choose which model(s) to authenticate (defaults to `User`).
15
16
 
16
17
  Forthcoming features:
17
18
 
18
19
  * Generate the views for you (for now, copy the examples given below).
19
- * Let you choose which model(s) to authenticate (currently `User`).
20
20
  * Let you choose the identification field (currently `username`).
21
21
  * HTTP basic/digest authentication (probably).
22
- * Generate (User) model plus migration if it doesn't exist.
22
+ * Generate model plus migration if it doesn't exist.
23
23
  * Detect presence of `has_secure_password` (see below) and adapt appropriately.
24
24
 
25
25
  What it doesn't and won't do:
@@ -37,11 +37,11 @@ What it doesn't and won't do:
37
37
 
38
38
  If this takes you more than 5 minutes, you can have your money back ;)
39
39
 
40
- Install and run the generator: add `gem 'quo_vadis'` to your Gemfile, run `bundle install`, then `rails generate quo_vadis:install`.
40
+ Install and run the generator: add `gem 'quo_vadis'` to your Gemfile, run `bundle install`, then `rails generate quo_vadis:install [MODEL_NAME]` (where model name is optional and defaults to `User`).
41
41
 
42
- Edit and run the generated migration to add the authentication columns: `rake db:migrate`. Note the migration (currently) assumes you already have a `User` model.
42
+ Edit and run the generated migration to add the authentication columns: `rake db:migrate`. Note the migration (currently) assumes you already have a table for your model.
43
43
 
44
- In your `User` model, add `authenticates`:
44
+ In your `User` (or whichever) model, add `authenticates`:
45
45
 
46
46
  class User < ActiveRecord::Base
47
47
  authenticates
@@ -114,6 +114,8 @@ You can customise the sign-in and sign-out redirects in `config/initializers/quo
114
114
 
115
115
  If you want to add other session management type features, go right ahead: create a `SessionsController` as normal and carry on.
116
116
 
117
+ You can skip the validation of authentication attributes (password etc) by overriding `should_authenticate?` in your model. Perhaps only some of the users should be able to sign in, so you don't want to force them to have a password.
118
+
117
119
 
118
120
  ## Sign up / user registration
119
121
 
@@ -1,72 +1,83 @@
1
1
  module ControllerMixin
2
2
  def self.included(base)
3
- base.helper_method :current_user
3
+ base.helper_method :"current_#{QuoVadis.model_instance_name}"
4
4
  end
5
5
 
6
6
  protected
7
7
 
8
8
  def handle_unverified_request
9
9
  super
10
- cookies.delete :remember_me
10
+ cookies.delete :remember_me, :domain => QuoVadis.cookie_domain
11
11
  end
12
12
 
13
13
  private
14
14
 
15
- # Remembers the authenticated <tt>user</tt> (in this session and future sessions).
16
- #
17
- # If you want to sign in a <tt>user</tt> you have just created, call <tt>sign_in</tt>
18
- # instead.
19
- def current_user=(user)
20
- remember_user_in_session user
21
- remember_user_between_sessions user
22
- end
15
+ class_eval <<-END, __FILE__, __LINE__ + 1
16
+ # Remembers the authenticated <tt>user</tt> (in this session and future sessions).
17
+ #
18
+ # If you want to sign in a <tt>user</tt> you have just created, call <tt>sign_in</tt>
19
+ # instead.
20
+ def current_#{QuoVadis.model_instance_name}=(user)
21
+ remember_user_in_session user
22
+ remember_user_between_sessions user
23
+ end
23
24
 
24
- # Returns the authenticated user.
25
- def current_user
26
- @current_user ||= find_authenticated_user
27
- end
25
+ # Returns the authenticated user.
26
+ def current_#{QuoVadis.model_instance_name}
27
+ @current_#{QuoVadis.model_instance_name} ||= find_authenticated_user
28
+ end
28
29
 
29
- # Does nothing if we already have an authenticated user. If we don't have an
30
- # authenticated user, it stores the desired URL and redirects to the sign in URL.
31
- def authenticate
32
- unless current_user
33
- session[:quo_vadis_original_url] = request.fullpath
34
- flash[:notice] = t('quo_vadis.flash.sign_in.before') unless t('quo_vadis.flash.sign_in.before').blank?
35
- redirect_to sign_in_url
30
+ # Does nothing if we already have an authenticated user. If we don't have an
31
+ # authenticated user, it stores the desired URL and redirects to the sign in URL.
32
+ def authenticate
33
+ unless current_#{QuoVadis.model_instance_name}
34
+ session[:quo_vadis_original_url] = request.fullpath
35
+ flash[:notice] = t('quo_vadis.flash.sign_in.before') unless t('quo_vadis.flash.sign_in.before').blank?
36
+ redirect_to sign_in_url
37
+ end
36
38
  end
37
- end
38
39
 
39
- # Signs in a user, i.e. remembers them in the session, runs the sign-in hook,
40
- # and redirects appropriately.
41
- #
42
- # This method should be called when you have just authenticated a <tt>user</tt>
43
- # and you need to sign them in. For example, if a new user has just signed up,
44
- # you should call this method to sign them in.
45
- def sign_in(user)
46
- prevent_session_fixation
47
- self.current_user = user
48
- QuoVadis.signed_in_hook user, self
49
- redirect_to QuoVadis.signed_in_url(user, original_url)
50
- end
40
+ # Signs in a user, i.e. remembers them in the session, runs the sign-in hook,
41
+ # and redirects appropriately.
42
+ #
43
+ # This method should be called when you have just authenticated a <tt>user</tt>
44
+ # and you need to sign them in. For example, if a new user has just signed up,
45
+ # you should call this method to sign them in.
46
+ def sign_in(user)
47
+ prevent_session_fixation
48
+ self.current_#{QuoVadis.model_instance_name} = user
49
+ QuoVadis.signed_in_hook user, self
50
+ redirect_to QuoVadis.signed_in_url(user, original_url, self)
51
+ end
52
+
53
+ def remember_user_in_session(user) # :nodoc:
54
+ session[:current_#{QuoVadis.model_instance_name}_id] = user ? user.id : nil
55
+ end
56
+
57
+ def find_user_by_cookie # :nodoc:
58
+ #{QuoVadis.model}.find_by_salt(*cookies.signed[:remember_me]) if cookies.signed[:remember_me]
59
+ end
60
+
61
+ def find_user_by_session # :nodoc:
62
+ #{QuoVadis.model}.find(session[:current_#{QuoVadis.model_instance_name}_id]) if session[:current_#{QuoVadis.model_instance_name}_id]
63
+ end
64
+ END
51
65
 
52
66
  # Returns true if the sign-in process is blocked to the user, false otherwise.
53
67
  def blocked?
54
68
  QuoVadis.blocked?(self)
55
69
  end
56
70
 
57
- def remember_user_in_session(user) # :nodoc:
58
- session[:current_user_id] = user ? user.id : nil
59
- end
60
-
61
71
  def remember_user_between_sessions(user) # :nodoc:
62
72
  if user && QuoVadis.remember_for
63
73
  cookies.signed[:remember_me] = {
64
74
  :value => [user.id, user.password_salt],
65
75
  :expires => QuoVadis.remember_for.from_now,
66
- :httponly => true
76
+ :httponly => true,
77
+ :domain => QuoVadis.cookie_domain
67
78
  }
68
79
  else
69
- cookies.delete :remember_me
80
+ cookies.delete :remember_me, :domain => QuoVadis.cookie_domain
70
81
  end
71
82
  end
72
83
 
@@ -74,14 +85,6 @@ module ControllerMixin
74
85
  find_user_by_session || find_user_by_cookie
75
86
  end
76
87
 
77
- def find_user_by_cookie # :nodoc:
78
- User.find_by_salt(*cookies.signed[:remember_me]) if cookies.signed[:remember_me]
79
- end
80
-
81
- def find_user_by_session # :nodoc:
82
- User.find(session[:current_user_id]) if session[:current_user_id]
83
- end
84
-
85
88
  # Returns the URL if any which the user tried to visit before being forced to authenticate.
86
89
  def original_url
87
90
  url = session[:quo_vadis_original_url]
@@ -1,4 +1,5 @@
1
1
  class QuoVadis::SessionsController < ApplicationController
2
+ skip_filter :authenticate, :except => [:destroy]
2
3
  layout :quo_vadis_layout
3
4
 
4
5
  # GET sign_in_path
@@ -9,24 +10,24 @@ class QuoVadis::SessionsController < ApplicationController
9
10
  # POST sign_in_path
10
11
  def create
11
12
  if blocked?
12
- flash.now[:alert] = t('quo_vadis.flash.sign_in.blocked') unless t('quo_vadis.flash.sign_in.blocked').blank?
13
+ flash_if_present :alert, 'quo_vadis.flash.sign_in.blocked', :now
13
14
  render 'sessions/new'
14
- elsif user = User.authenticate(params[:username], params[:password])
15
- flash[:notice] = t('quo_vadis.flash.sign_in.after') unless t('quo_vadis.flash.sign_in.after').blank?
15
+ elsif user = QuoVadis.model_class.authenticate(params[:username], params[:password])
16
+ flash_if_present :notice, 'quo_vadis.flash.sign_in.after'
16
17
  sign_in user
17
18
  else
18
19
  QuoVadis.failed_sign_in_hook self
19
- flash.now[:alert] = t('quo_vadis.flash.sign_in.failed') unless t('quo_vadis.flash.sign_in.failed').blank?
20
+ flash_if_present :alert, 'quo_vadis.flash.sign_in.failed', :now
20
21
  render 'sessions/new'
21
22
  end
22
23
  end
23
24
 
24
25
  # GET sign_out_path
25
26
  def destroy
26
- QuoVadis.signed_out_hook current_user, self
27
- self.current_user = nil
28
- flash[:notice] = t('quo_vadis.flash.sign_out') unless t('quo_vadis.flash.sign_out').blank?
29
- redirect_to QuoVadis.signed_out_url
27
+ QuoVadis.signed_out_hook send(:"current_#{QuoVadis.model_instance_name}"), self
28
+ self.send :"current_#{QuoVadis.model_instance_name}=", nil
29
+ flash_if_present :notice, 'quo_vadis.flash.sign_out'
30
+ redirect_to QuoVadis.signed_out_url(self)
30
31
  end
31
32
 
32
33
  # GET forgotten_sign_in_path
@@ -35,18 +36,19 @@ class QuoVadis::SessionsController < ApplicationController
35
36
  if request.get?
36
37
  render 'sessions/forgotten'
37
38
  elsif request.post?
38
- if (user = User.where(:username => params[:username]).first)
39
+ if params[:username].present? &&
40
+ (user = QuoVadis.model_class.where(:username => params[:username]).first)
39
41
  if user.email.present?
40
42
  user.generate_token
41
43
  QuoVadis::Notifier.change_password(user).deliver
42
- flash[:notice] = t('quo_vadis.flash.forgotten.sent_email') unless t('quo_vadis.flash.forgotten.sent_email').blank?
44
+ flash_if_present :notice, 'quo_vadis.flash.forgotten.sent_email'
43
45
  redirect_to :root
44
46
  else
45
- flash.now[:alert] = t('quo_vadis.flash.forgotten.no_email') unless t('quo_vadis.flash.forgotten.no_email').blank?
47
+ flash_if_present :alert, 'quo_vadis.flash.forgotten.no_email', :now
46
48
  render 'sessions/forgotten'
47
49
  end
48
50
  else
49
- flash.now[:alert] = t('quo_vadis.flash.forgotten.unknown') unless t('quo_vadis.flash.forgotten.unknown').blank?
51
+ flash_if_present :alert, 'quo_vadis.flash.forgotten.unknown', :now
50
52
  render 'sessions/forgotten'
51
53
  end
52
54
  end
@@ -54,7 +56,7 @@ class QuoVadis::SessionsController < ApplicationController
54
56
 
55
57
  # GET change_password_path /sign-in/change-password/:token
56
58
  def edit
57
- if User.valid_token(params[:token]).first
59
+ if QuoVadis.model_class.valid_token(params[:token]).first
58
60
  render 'sessions/edit'
59
61
  else
60
62
  invalid_token
@@ -63,11 +65,11 @@ class QuoVadis::SessionsController < ApplicationController
63
65
 
64
66
  # PUT change_password_path /sign-in/change-password/:token
65
67
  def update
66
- if (user = User.valid_token(params[:token]).first)
68
+ if (user = QuoVadis.model_class.valid_token(params[:token]).first)
67
69
  user.password = params[:password]
68
70
  if user.save
69
71
  user.clear_token
70
- flash[:notice] = t('quo_vadis.flash.forgotten.password_changed') unless t('quo_vadis.flash.forgotten.password_changed').blank?
72
+ flash_if_present :notice, 'quo_vadis.flash.forgotten.password_changed'
71
73
  sign_in user
72
74
  else
73
75
  render 'sessions/edit'
@@ -80,7 +82,7 @@ class QuoVadis::SessionsController < ApplicationController
80
82
  private
81
83
 
82
84
  def invalid_token # :nodoc:
83
- flash[:alert] = t('quo_vadis.flash.forgotten.invalid_token') unless t('quo_vadis.flash.forgotten.invalid_token').blank?
85
+ flash_if_present :alert, 'quo_vadis.flash.forgotten.invalid_token'
84
86
  redirect_to forgotten_sign_in_url
85
87
  end
86
88
 
@@ -88,4 +90,12 @@ class QuoVadis::SessionsController < ApplicationController
88
90
  QuoVadis.layout
89
91
  end
90
92
 
93
+ def flash_if_present(key, i18n_key, now = false)
94
+ if now
95
+ flash.now[key] = t(i18n_key) if t(i18n_key).present?
96
+ else
97
+ flash[key] = t(i18n_key) if t(i18n_key).present?
98
+ end
99
+ end
100
+
91
101
  end
@@ -16,13 +16,13 @@ module ModelMixin
16
16
  attr_reader :password
17
17
  attr_protected :password_digest
18
18
 
19
- validates :username, :presence => true, :uniqueness => true
20
- validates :password, :presence => true, :if => Proc.new { |u| u.changed.include?('password_digest') }
21
- validates :password_digest, :presence => true
19
+ validates :username, :presence => true, :uniqueness => true, :if => :should_authenticate?
20
+ validates :password, :presence => true, :if => Proc.new { |u| u.should_authenticate? && u.changed.include?('password_digest') }
21
+ validates :password_digest, :presence => true, :if => :should_authenticate?
22
22
 
23
23
  scope :valid_token, lambda { |token| where("token = ? AND token_created_at > ?", token, 3.hours.ago) }
24
24
 
25
- instance_eval <<-END
25
+ instance_eval <<-END, __FILE__, __LINE__ + 1
26
26
  # Returns the user with the given <tt>username</tt> if the given password is
27
27
  # correct, and <tt>nil</tt> otherwise.
28
28
  def authenticate(username, plain_text_password)
@@ -35,7 +35,7 @@ module ModelMixin
35
35
  end
36
36
 
37
37
  def find_by_salt(id, salt) # :nodoc:
38
- user = User.find_by_id id
38
+ user = find_by_id id
39
39
  if user && user.has_matching_salt?(salt)
40
40
  user
41
41
  else
@@ -47,6 +47,11 @@ module ModelMixin
47
47
  end
48
48
 
49
49
  module InstanceMethodsOnActivation
50
+ # Override this in your model if you need to bypass the Quo Vadis validations.
51
+ def should_authenticate?
52
+ true
53
+ end
54
+
50
55
  def password=(plain_text_password) # :nodoc:
51
56
  @password = plain_text_password
52
57
  self.password_digest = BCrypt::Password.create plain_text_password
@@ -8,6 +8,7 @@ module QuoVadis
8
8
  extend ActiveRecord::Generators::Migration
9
9
 
10
10
  source_root File.expand_path('../templates', __FILE__)
11
+ argument :model_name, :type => :string, :default => 'User'
11
12
 
12
13
  desc 'Copies an initializer, a locale file, and a migration to your application.'
13
14
 
@@ -17,11 +18,11 @@ module QuoVadis
17
18
  end
18
19
 
19
20
  def copy_initializer_file
20
- copy_file '../../../../config/initializers/quo_vadis.rb', 'config/initializers/quo_vadis.rb'
21
+ template 'quo_vadis.rb.erb', 'config/initializers/quo_vadis.rb'
21
22
  end
22
23
 
23
24
  def create_migration_file
24
- migration_template 'migration.rb', 'db/migrate/add_authentication_to_users.rb'
25
+ migration_template 'migration.rb.erb', "db/migrate/add_authentication_to_#{model_name.tableize}.rb"
25
26
  end
26
27
 
27
28
  end
@@ -0,0 +1,18 @@
1
+ class AddAuthenticationTo<%= model_name.pluralize.camelize %> < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :<%= model_name.tableize %>, :username, :string # for user identification
4
+ add_column :<%= model_name.tableize %>, :password_digest, :string
5
+
6
+ add_column :<%= model_name.tableize %>, :email, :string # for forgotten-credentials
7
+ add_column :<%= model_name.tableize %>, :token, :string # for forgotten-credentials
8
+ add_column :<%= model_name.tableize %>, :token_created_at, :string # for forgotten-credentials
9
+ end
10
+
11
+ def self.down
12
+ remove_column :<%= model_name.tableize %>, :username
13
+ remove_column :<%= model_name.tableize %>, :password_digest
14
+ remove_column :<%= model_name.tableize %>, :email
15
+ remove_column :<%= model_name.tableize %>, :token
16
+ remove_column :<%= model_name.tableize %>, :token_created_at
17
+ end
18
+ end
@@ -1,13 +1,17 @@
1
1
  QuoVadis.configure do |config|
2
2
 
3
+ # The model we want to authenticate.
4
+ config.model = '<%= model_name.pluralize.classify %>'
5
+
6
+
3
7
  #
4
8
  # Sign in
5
9
  #
6
10
 
7
11
  # The URL to redirect the user to after s/he signs in.
8
- # Use a proc if the URL depends on the user. E.g.:
12
+ # Use a proc if the URL depends on the user on controller. E.g.:
9
13
  #
10
- # config.signed_in_url = Proc.new do |user|
14
+ # config.signed_in_url = Proc.new do |user, controller|
11
15
  # user.admin? ? :admin : :root
12
16
  # end
13
17
  #
@@ -36,6 +40,9 @@ QuoVadis.configure do |config|
36
40
  # Set to <tt>nil</tt> to never remember user.
37
41
  config.remember_for = 2.weeks
38
42
 
43
+ # The domain to use for remember-me cookies.
44
+ config.cookie_domain = :all
45
+
39
46
  # Code to run to determine whether the sign-in process is blocked to the user. E.g.:
40
47
  #
41
48
  # config.blocked = Proc.new do |controller|
@@ -50,6 +57,11 @@ QuoVadis.configure do |config|
50
57
  #
51
58
 
52
59
  # The URL to redirect the user to after s/he signs out.
60
+ # Use a proc if the URL depends on the controller. E.g.:
61
+ #
62
+ # config.signed_out_url = Proc.new do |controller|
63
+ # controller.root_url(:subdomain => nil)
64
+ # end
53
65
  config.signed_out_url = :root
54
66
 
55
67
  # Code to run just before the user has signed out. E.g.:
@@ -1,3 +1,3 @@
1
1
  module QuoVadis
2
- VERSION = '1.0.7'
2
+ VERSION = '1.1.0'
3
3
  end
data/lib/quo_vadis.rb CHANGED
@@ -3,6 +3,19 @@ require 'active_support/core_ext/numeric/time'
3
3
 
4
4
  module QuoVadis
5
5
 
6
+ # The model we want to authenticate.
7
+ mattr_accessor :model # :nodoc:
8
+ @@model = 'User'
9
+
10
+ def self.model_class # :nodoc
11
+ @@model.constantize
12
+ end
13
+
14
+ def self.model_instance_name # :nodoc
15
+ @@model.tableize.singularize # e.g. 'user'
16
+ end
17
+
18
+
6
19
  #
7
20
  # Sign in
8
21
  #
@@ -16,11 +29,11 @@ module QuoVadis
16
29
  mattr_accessor :override_original_url
17
30
  @@override_original_url = false
18
31
 
19
- def self.signed_in_url(user, original_url) # :nodoc:
32
+ def self.signed_in_url(user, original_url, controller) # :nodoc:
20
33
  if original_url && !@@override_original_url
21
34
  original_url
22
35
  else
23
- @@signed_in_url.respond_to?(:call) ? @@signed_in_url.call(user) : @@signed_in_url
36
+ @@signed_in_url.respond_to?(:call) ? @@signed_in_url.call(user, controller) : @@signed_in_url
24
37
  end
25
38
  end
26
39
 
@@ -44,6 +57,10 @@ module QuoVadis
44
57
  mattr_accessor :remember_for
45
58
  @@remember_for = 2.weeks
46
59
 
60
+ # The domain to use for remember-me cookies.
61
+ mattr_accessor :cookie_domain
62
+ @@cookie_domain = :all
63
+
47
64
 
48
65
  # Whether the sign-in process is blocked to the user.
49
66
  mattr_writer :blocked
@@ -60,7 +77,11 @@ module QuoVadis
60
77
 
61
78
  # The URL to redirect the user to after s/he signs out.
62
79
  mattr_accessor :signed_out_url
63
- @@signed_in_url = :root
80
+ @@signed_out_url = :root
81
+
82
+ def self.signed_out_url(controller) # :nodoc:
83
+ @@signed_out_url.respond_to?(:call) ? @@signed_out_url.call(controller) : @@signed_out_url
84
+ end
64
85
 
65
86
 
66
87
  # Code to run just before the user has signed out.
data/quo_vadis.gemspec CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
20
20
  s.require_paths = ['lib']
21
21
 
22
22
  s.add_dependency 'rails', '~>3.0'
23
- s.add_dependency 'bcrypt-ruby', '>= 2.1.4'
23
+ s.add_dependency 'bcrypt-ruby', '~> 3.0.0'
24
24
 
25
25
  s.add_development_dependency 'rails', '>=3.0.4' # so we can test CSRF protection
26
26
  s.add_development_dependency 'sqlite3-ruby'
@@ -1 +1,2 @@
1
1
  db/*.sqlite3
2
+ tmp
@@ -0,0 +1,3 @@
1
+ class Person < ActiveRecord::Base
2
+ authenticates
3
+ end
@@ -9,11 +9,17 @@
9
9
  <body>
10
10
 
11
11
  <div id='topnav'>
12
- <% if current_user %>
12
+ <% if defined?(current_user) && current_user %>
13
13
  You are signed in as <%= current_user.name %>.
14
14
  <%= link_to 'Sign out', sign_out_path %>
15
+
16
+ <% elsif defined?(current_person) && current_person %>
17
+ You are signed in as <%= current_person.name %>.
18
+ <%= link_to 'Sign out', sign_out_path %>
19
+
15
20
  <% else %>
16
21
  <%= link_to 'Sign in', sign_in_path %>
22
+
17
23
  <% end %>
18
24
  </div>
19
25
 
@@ -0,0 +1,13 @@
1
+ class CreatePeople < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :people do |t|
4
+ t.string :name
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+
10
+ def self.down
11
+ drop_table :people
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ class AddAuthenticationToPeople < ActiveRecord::Migration
2
+ def self.up
3
+ add_column :people, :username, :string # for user identification
4
+ add_column :people, :password_digest, :string
5
+
6
+ add_column :people, :email, :string # for forgotten-credentials
7
+ add_column :people, :token, :string # for forgotten-credentials
8
+ add_column :people, :token_created_at, :string # for forgotten-credentials
9
+ end
10
+
11
+ def self.down
12
+ remove_column :people, :username
13
+ remove_column :people, :password_digest
14
+ remove_column :people, :email
15
+ remove_column :people, :token
16
+ remove_column :people, :token_created_at
17
+ end
18
+ end
@@ -18,13 +18,13 @@ class ConfigTest < ActiveSupport::IntegrationCase
18
18
  end
19
19
 
20
20
  test 'signed_in_url proc config' do
21
- QuoVadis.signed_in_url = Proc.new do |user|
21
+ QuoVadis.signed_in_url = Proc.new do |user, controller|
22
22
  user.name == 'Bob' ? :articles : :root
23
23
  end
24
24
  sign_in_as 'bob', 'secret'
25
25
  assert_equal articles_path, current_path
26
26
 
27
- QuoVadis.signed_in_url = Proc.new do |user|
27
+ QuoVadis.signed_in_url = Proc.new do |user, controller|
28
28
  user.name != 'Bob' ? :articles : :root
29
29
  end
30
30
  sign_in_as 'bob', 'secret'
@@ -6,6 +6,16 @@ class ForgottenTest < ActiveSupport::IntegrationCase
6
6
  Capybara.reset_sessions!
7
7
  end
8
8
 
9
+ test 'user fills in forgotten-password form with blank username' do
10
+ u = user_factory 'Bob', 'bob', 'secret'
11
+ u.update_attribute :username, ''
12
+ submit_forgotten_details ''
13
+ assert_equal forgotten_sign_in_path, current_path
14
+ within '.flash.alert' do
15
+ assert page.has_content?("Sorry, we did not recognise you.")
16
+ end
17
+ end
18
+
9
19
  test 'user fills in forgotten-password form with invalid username' do
10
20
  submit_forgotten_details 'bob'
11
21
  assert_equal forgotten_sign_in_path, current_path
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ class SignInPersonTest < ActiveSupport::IntegrationCase
4
+
5
+ # NOTE: it would be great if I could figure out how to re-initialise the method's
6
+ # mixed into the controller with the new model.
7
+ test 'successful sign in for a non-user model' do
8
+ puts <<-END
9
+ NOTE: this test (#{__FILE__}) has to be run individually like this:
10
+
11
+ 1. Change lib/quo_vadis.rb's @@model to 'Person'.
12
+ 2. Uncomment the test code.
13
+ 3. bundle exec ruby -Ilib:test #{__FILE__}
14
+
15
+ END
16
+
17
+ # person_factory 'James', 'jim', 'secret'
18
+ # sign_in_as 'jim', 'secret'
19
+
20
+ # assert_equal root_path, current_path
21
+ # within '.flash.notice' do
22
+ # assert page.has_content?('You have successfully signed in.')
23
+ # end
24
+ end
25
+
26
+ end
data/test/test_helper.rb CHANGED
@@ -42,8 +42,13 @@ def user_factory(name, username, password, email = nil)
42
42
  User.create! :name => name, :username => username, :password => password, :email => email
43
43
  end
44
44
 
45
+ def person_factory(name, username, password, email = nil)
46
+ Person.create! :name => name, :username => username, :password => password, :email => email
47
+ end
48
+
45
49
  def reset_quo_vadis_configuration
46
50
  QuoVadis.signed_in_url = :root
51
+ QuoVadis.cookie_domain = :all
47
52
  QuoVadis.override_original_url = false
48
53
  QuoVadis.signed_out_url = :root
49
54
  QuoVadis.signed_in_hook = nil
@@ -28,4 +28,21 @@ class UserTest < ActiveSupport::TestCase
28
28
  assert user.has_matching_password?('secret')
29
29
  end
30
30
 
31
+ test 'conditional validation' do
32
+ user = User.new
33
+ user.class_eval <<-END
34
+ def should_authenticate?
35
+ username == 'bob'
36
+ end
37
+ END
38
+ user.username = 'bob'
39
+ assert !user.valid?
40
+
41
+ user.username = 'robert'
42
+ assert user.valid?
43
+
44
+ user.username = nil
45
+ assert user.valid?
46
+ end
47
+
31
48
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quo_vadis
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 19
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
+ - 1
8
9
  - 0
9
- - 7
10
- version: 1.0.7
10
+ version: 1.1.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Andy Stewart
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-10-03 00:00:00 +02:00
18
+ date: 2011-10-07 00:00:00 +02:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -39,14 +39,14 @@ dependencies:
39
39
  version_requirements: &id002 !ruby/object:Gem::Requirement
40
40
  none: false
41
41
  requirements:
42
- - - ">="
42
+ - - ~>
43
43
  - !ruby/object:Gem::Version
44
- hash: 3
44
+ hash: 7
45
45
  segments:
46
- - 2
47
- - 1
48
- - 4
49
- version: 2.1.4
46
+ - 3
47
+ - 0
48
+ - 0
49
+ version: 3.0.0
50
50
  type: :runtime
51
51
  requirement: *id002
52
52
  - !ruby/object:Gem::Dependency
@@ -128,11 +128,11 @@ files:
128
128
  - app/controllers/quo_vadis/sessions_controller.rb
129
129
  - app/mailers/quo_vadis/notifier.rb
130
130
  - app/models/model_mixin.rb
131
- - config/initializers/quo_vadis.rb
132
131
  - config/locales/quo_vadis.en.yml
133
132
  - config/routes.rb
134
133
  - lib/generators/quo_vadis/install_generator.rb
135
- - lib/generators/quo_vadis/templates/migration.rb
134
+ - lib/generators/quo_vadis/templates/migration.rb.erb
135
+ - lib/generators/quo_vadis/templates/quo_vadis.rb.erb
136
136
  - lib/quo_vadis.rb
137
137
  - lib/quo_vadis/engine.rb
138
138
  - lib/quo_vadis/version.rb
@@ -145,6 +145,7 @@ files:
145
145
  - test/dummy/app/helpers/application_helper.rb
146
146
  - test/dummy/app/helpers/articles_helper.rb
147
147
  - test/dummy/app/models/article.rb
148
+ - test/dummy/app/models/person.rb
148
149
  - test/dummy/app/models/user.rb
149
150
  - test/dummy/app/views/articles/index.html.erb
150
151
  - test/dummy/app/views/articles/new.html.erb
@@ -175,6 +176,8 @@ files:
175
176
  - test/dummy/db/migrate/20110124125037_create_users.rb
176
177
  - test/dummy/db/migrate/20110124131535_create_articles.rb
177
178
  - test/dummy/db/migrate/20110127094709_add_authentication_to_users.rb
179
+ - test/dummy/db/migrate/20111004112209_create_people.rb
180
+ - test/dummy/db/migrate/20111004132342_add_authentication_to_people.rb
178
181
  - test/dummy/db/schema.rb
179
182
  - test/dummy/public/404.html
180
183
  - test/dummy/public/422.html
@@ -188,11 +191,6 @@ files:
188
191
  - test/dummy/public/javascripts/rails.js
189
192
  - test/dummy/public/stylesheets/.gitkeep
190
193
  - test/dummy/script/rails
191
- - test/dummy/tmp/capybara/capybara-20110124133149.html
192
- - test/dummy/tmp/capybara/capybara-20110124133340.html
193
- - test/dummy/tmp/capybara/capybara-20110124134001.html
194
- - test/dummy/tmp/capybara/capybara-20110124134214.html
195
- - test/dummy/tmp/capybara/capybara-20110124135435.html
196
194
  - test/integration/authenticate_test.rb
197
195
  - test/integration/blocked_test.rb
198
196
  - test/integration/config_test.rb
@@ -202,6 +200,7 @@ files:
202
200
  - test/integration/helper_test.rb
203
201
  - test/integration/locale_test.rb
204
202
  - test/integration/navigation_test.rb
203
+ - test/integration/sign_in_person_test.rb
205
204
  - test/integration/sign_in_test.rb
206
205
  - test/integration/sign_out_test.rb
207
206
  - test/integration/sign_up_test.rb
@@ -252,6 +251,7 @@ test_files:
252
251
  - test/dummy/app/helpers/application_helper.rb
253
252
  - test/dummy/app/helpers/articles_helper.rb
254
253
  - test/dummy/app/models/article.rb
254
+ - test/dummy/app/models/person.rb
255
255
  - test/dummy/app/models/user.rb
256
256
  - test/dummy/app/views/articles/index.html.erb
257
257
  - test/dummy/app/views/articles/new.html.erb
@@ -282,6 +282,8 @@ test_files:
282
282
  - test/dummy/db/migrate/20110124125037_create_users.rb
283
283
  - test/dummy/db/migrate/20110124131535_create_articles.rb
284
284
  - test/dummy/db/migrate/20110127094709_add_authentication_to_users.rb
285
+ - test/dummy/db/migrate/20111004112209_create_people.rb
286
+ - test/dummy/db/migrate/20111004132342_add_authentication_to_people.rb
285
287
  - test/dummy/db/schema.rb
286
288
  - test/dummy/public/404.html
287
289
  - test/dummy/public/422.html
@@ -295,11 +297,6 @@ test_files:
295
297
  - test/dummy/public/javascripts/rails.js
296
298
  - test/dummy/public/stylesheets/.gitkeep
297
299
  - test/dummy/script/rails
298
- - test/dummy/tmp/capybara/capybara-20110124133149.html
299
- - test/dummy/tmp/capybara/capybara-20110124133340.html
300
- - test/dummy/tmp/capybara/capybara-20110124134001.html
301
- - test/dummy/tmp/capybara/capybara-20110124134214.html
302
- - test/dummy/tmp/capybara/capybara-20110124135435.html
303
300
  - test/integration/authenticate_test.rb
304
301
  - test/integration/blocked_test.rb
305
302
  - test/integration/config_test.rb
@@ -309,6 +306,7 @@ test_files:
309
306
  - test/integration/helper_test.rb
310
307
  - test/integration/locale_test.rb
311
308
  - test/integration/navigation_test.rb
309
+ - test/integration/sign_in_person_test.rb
312
310
  - test/integration/sign_in_test.rb
313
311
  - test/integration/sign_out_test.rb
314
312
  - test/integration/sign_up_test.rb
@@ -1,18 +0,0 @@
1
- class AddAuthenticationToUsers < ActiveRecord::Migration
2
- def self.up
3
- add_column :users, :username, :string # for user identification
4
- add_column :users, :password_digest, :string
5
-
6
- add_column :users, :email, :string # for forgotten-credentials
7
- add_column :users, :token, :string # for forgotten-credentials
8
- add_column :users, :token_created_at, :string # for forgotten-credentials
9
- end
10
-
11
- def self.down
12
- remove_column :users, :username
13
- remove_column :users, :password_digest
14
- remove_column :users, :email
15
- remove_column :users, :token
16
- remove_column :users, :token_created_at
17
- end
18
- end
@@ -1,27 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Dummy</title>
5
-
6
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/prototype.js?1295870562" type="text/javascript"></script>
7
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/effects.js?1295870562" type="text/javascript"></script>
8
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/dragdrop.js?1295870562" type="text/javascript"></script>
9
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/controls.js?1295870562" type="text/javascript"></script>
10
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/rails.js?1295870562" type="text/javascript"></script>
11
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/application.js?1295870562" type="text/javascript"></script>
12
-
13
- </head>
14
- <body>
15
-
16
- <div id='topnav'>
17
- You are signed in as Bob.
18
- <a href="/sign-out">Sign out</a>
19
- </div>
20
-
21
- <div class='flash notice'>You have successfully signed in.</div>
22
-
23
- <h1>Articles</h1>
24
-
25
-
26
- </body>
27
- </html>
@@ -1,27 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Dummy</title>
5
-
6
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/prototype.js?1295870562" type="text/javascript"></script>
7
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/effects.js?1295870562" type="text/javascript"></script>
8
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/dragdrop.js?1295870562" type="text/javascript"></script>
9
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/controls.js?1295870562" type="text/javascript"></script>
10
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/rails.js?1295870562" type="text/javascript"></script>
11
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/application.js?1295870562" type="text/javascript"></script>
12
-
13
- </head>
14
- <body>
15
-
16
- <div id='topnav'>
17
- You are signed in as Bob.
18
- <a href="/sign-out">Sign out</a>
19
- </div>
20
-
21
- <div class='flash notice'>You have successfully signed in.</div>
22
-
23
- <h1>Articles</h1>
24
-
25
-
26
- </body>
27
- </html>
@@ -1,27 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Dummy</title>
5
-
6
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/prototype.js?1295870562" type="text/javascript"></script>
7
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/effects.js?1295870562" type="text/javascript"></script>
8
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/dragdrop.js?1295870562" type="text/javascript"></script>
9
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/controls.js?1295870562" type="text/javascript"></script>
10
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/rails.js?1295870562" type="text/javascript"></script>
11
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/application.js?1295870562" type="text/javascript"></script>
12
-
13
- </head>
14
- <body>
15
-
16
- <div id='topnav'>
17
- You are signed in as Bob.
18
- <a href="/sign-out">Sign out</a>
19
- </div>
20
-
21
- <div class='flash notice'>You have successfully signed in.</div>
22
-
23
- <h1>Articles</h1>
24
-
25
-
26
- </body>
27
- </html>
@@ -1,27 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Dummy</title>
5
-
6
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/prototype.js?1295870562" type="text/javascript"></script>
7
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/effects.js?1295870562" type="text/javascript"></script>
8
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/dragdrop.js?1295870562" type="text/javascript"></script>
9
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/controls.js?1295870562" type="text/javascript"></script>
10
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/rails.js?1295870562" type="text/javascript"></script>
11
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/application.js?1295870562" type="text/javascript"></script>
12
-
13
- </head>
14
- <body>
15
-
16
- <div id='topnav'>
17
- You are signed in as Bob.
18
- <a href="/sign-out">Sign out</a>
19
- </div>
20
-
21
- <div class='flash notice'>You have successfully signed in.</div>
22
-
23
- <h1>Articles</h1>
24
-
25
-
26
- </body>
27
- </html>
@@ -1,39 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <title>Dummy</title>
5
-
6
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/prototype.js?1295870562" type="text/javascript"></script>
7
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/effects.js?1295870562" type="text/javascript"></script>
8
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/dragdrop.js?1295870562" type="text/javascript"></script>
9
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/controls.js?1295870562" type="text/javascript"></script>
10
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/rails.js?1295870562" type="text/javascript"></script>
11
- <script src="/Users/andy/code/src/quo_vadis/test/dummy/public/javascripts/application.js?1295870562" type="text/javascript"></script>
12
-
13
- </head>
14
- <body>
15
-
16
- <div id='topnav'>
17
- <a href="/sign-in">Sign in</a>
18
- </div>
19
-
20
- <div class='flash notice'>Please sign in first.</div>
21
-
22
- <h1>Sign in</h1>
23
-
24
- <form accept-charset="UTF-8" action="/sign-in" method="post"><div style="margin:0;padding:0;display:inline"><input name="utf8" type="hidden" value="&#x2713;" /></div>
25
- <p>
26
- <label for="username">Username</label>
27
- <input id="username" name="username" type="text" />
28
- </p>
29
- <p>
30
- <label for="password">Password</label>
31
- <input id="password" name="password" type="password" />
32
- </p>
33
- <p>
34
- <input name="commit" type="submit" value="Sign in" />
35
- </p>
36
- </form>
37
-
38
- </body>
39
- </html>