quo_vadis 1.0.7 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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>