aihs_devise_invitable 0.4.rc
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +27 -0
- data/Gemfile +8 -0
- data/Gemfile.lock +117 -0
- data/LICENSE +20 -0
- data/README.rdoc +187 -0
- data/Rakefile +57 -0
- data/app/controllers/devise/invitations_controller.rb +47 -0
- data/app/views/devise/invitations/edit.html.erb +14 -0
- data/app/views/devise/invitations/new.html.erb +12 -0
- data/app/views/devise/mailer/invitation.html.erb +8 -0
- data/app/views/devise/mailer/invitation_instructions.html.erb +8 -0
- data/config/locales/en.yml +9 -0
- data/devise_invitable.gemspec +143 -0
- data/lib/devise_invitable.rb +16 -0
- data/lib/devise_invitable/controllers/helpers.rb +7 -0
- data/lib/devise_invitable/controllers/url_helpers.rb +24 -0
- data/lib/devise_invitable/mailer.rb +14 -0
- data/lib/devise_invitable/model.rb +130 -0
- data/lib/devise_invitable/rails.rb +13 -0
- data/lib/devise_invitable/routes.rb +13 -0
- data/lib/devise_invitable/schema.rb +33 -0
- data/lib/devise_invitable/version.rb +3 -0
- data/lib/generators/active_record/devise_invitable_generator.rb +13 -0
- data/lib/generators/active_record/templates/migration.rb +20 -0
- data/lib/generators/devise_invitable/devise_invitable_generator.rb +16 -0
- data/lib/generators/devise_invitable/install_generator.rb +35 -0
- data/lib/generators/devise_invitable/views_generator.rb +10 -0
- data/test/generators_test.rb +45 -0
- data/test/integration/invitation_test.rb +107 -0
- data/test/integration_tests_helper.rb +58 -0
- data/test/mailers/invitation_mail_test.rb +63 -0
- data/test/model_tests_helper.rb +41 -0
- data/test/models/invitable_test.rb +213 -0
- data/test/models_test.rb +32 -0
- data/test/rails_app/app/controllers/admins_controller.rb +6 -0
- data/test/rails_app/app/controllers/application_controller.rb +3 -0
- data/test/rails_app/app/controllers/home_controller.rb +4 -0
- data/test/rails_app/app/controllers/users_controller.rb +12 -0
- data/test/rails_app/app/helpers/application_helper.rb +2 -0
- data/test/rails_app/app/models/octopussy.rb +11 -0
- data/test/rails_app/app/models/user.rb +4 -0
- data/test/rails_app/app/views/home/index.html.erb +0 -0
- data/test/rails_app/app/views/layouts/application.html.erb +16 -0
- data/test/rails_app/app/views/users/invitations/new.html.erb +15 -0
- data/test/rails_app/config.ru +4 -0
- data/test/rails_app/config/application.rb +46 -0
- data/test/rails_app/config/boot.rb +14 -0
- data/test/rails_app/config/database.yml +22 -0
- data/test/rails_app/config/environment.rb +5 -0
- data/test/rails_app/config/environments/development.rb +26 -0
- data/test/rails_app/config/environments/production.rb +49 -0
- data/test/rails_app/config/environments/test.rb +35 -0
- data/test/rails_app/config/initializers/backtrace_silencers.rb +7 -0
- data/test/rails_app/config/initializers/devise.rb +174 -0
- data/test/rails_app/config/initializers/inflections.rb +10 -0
- data/test/rails_app/config/initializers/mime_types.rb +5 -0
- data/test/rails_app/config/initializers/secret_token.rb +7 -0
- data/test/rails_app/config/initializers/session_store.rb +8 -0
- data/test/rails_app/config/locales/en.yml +5 -0
- data/test/rails_app/config/routes.rb +4 -0
- data/test/rails_app/script/rails +6 -0
- data/test/routes_test.rb +20 -0
- data/test/test_helper.rb +31 -0
- metadata +222 -0
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rails/generators/active_record'
|
2
|
+
|
3
|
+
module ActiveRecord
|
4
|
+
module Generators
|
5
|
+
class DeviseInvitableGenerator < ActiveRecord::Generators::Base
|
6
|
+
source_root File.expand_path("../templates", __FILE__)
|
7
|
+
|
8
|
+
def copy_devise_migration
|
9
|
+
migration_template "migration.rb", "db/migrate/devise_invitable_add_to_#{table_name}"
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class DeviseInvitableAddTo<%= table_name.camelize %> < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
change_table :<%= table_name %> do |t|
|
4
|
+
t.string :invitation_token, :limit => 60
|
5
|
+
t.datetime :invitation_sent_at
|
6
|
+
t.index :invitation_token # for invitable
|
7
|
+
end
|
8
|
+
|
9
|
+
# And allow null encrypted_password and password_salt:
|
10
|
+
change_column_null :<%= table_name %>, :encrypted_password, true
|
11
|
+
<% if class_name.constantize.columns_hash['password_salt'] -%>
|
12
|
+
change_column_null :<%= table_name %>, :password_salt, true
|
13
|
+
<% end -%>
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.down
|
17
|
+
remove_column :<%= table_name %>, :invitation_sent_at
|
18
|
+
remove_column :<%= table_name %>, :invitation_token
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module DeviseInvitable
|
2
|
+
module Generators
|
3
|
+
class DeviseInvitableGenerator < Rails::Generators::NamedBase
|
4
|
+
namespace "devise_invitable"
|
5
|
+
|
6
|
+
desc "Add :invitable directive in the given model. Also generate migration for ActiveRecord"
|
7
|
+
|
8
|
+
def inject_devise_invitable_content
|
9
|
+
path = File.join("app", "models", "#{file_path}.rb")
|
10
|
+
inject_into_file(path, "invitable, :", :after => "devise :") if File.exists?(path)
|
11
|
+
end
|
12
|
+
|
13
|
+
hook_for :orm
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module DeviseInvitable
|
2
|
+
module Generators
|
3
|
+
class InstallGenerator < Rails::Generators::Base
|
4
|
+
source_root File.expand_path("../../templates", __FILE__)
|
5
|
+
desc "Add DeviseInvitable config variables to the Devise initializer and copy DeviseInvitable locale files to your application."
|
6
|
+
|
7
|
+
def add_config_options_to_initializer
|
8
|
+
devise_initializer_path = "config/initializers/devise.rb"
|
9
|
+
if File.exist?(devise_initializer_path)
|
10
|
+
old_content = File.read(devise_initializer_path)
|
11
|
+
|
12
|
+
if old_content.match(Regexp.new(/^\s# ==> Configuration for :invitable\n/))
|
13
|
+
false
|
14
|
+
else
|
15
|
+
inject_into_file(devise_initializer_path, :before => " # ==> Configuration for :confirmable\n") do
|
16
|
+
<<-CONTENT
|
17
|
+
# ==> Configuration for :invitable
|
18
|
+
# The period the generated invitation token is valid, after
|
19
|
+
# this period, the invited resource won't be able to accept the invitation.
|
20
|
+
# When invite_for is 0 (the default), the invitation won't expire.
|
21
|
+
# config.invite_for = 2.weeks
|
22
|
+
|
23
|
+
CONTENT
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def copy_locale
|
30
|
+
copy_file "../../../config/locales/en.yml", "config/locales/devise_invitable.en.yml"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'generators/devise/views_generator'
|
2
|
+
|
3
|
+
module DeviseInvitable
|
4
|
+
module Generators
|
5
|
+
class ViewsGenerator < Devise::Generators::ViewsGenerator
|
6
|
+
source_root File.expand_path("../../../../app/views", __FILE__)
|
7
|
+
desc 'Copies all DeviseInvitable views to your application.'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
require 'rails/generators'
|
3
|
+
require 'generators/devise_invitable/devise_invitable_generator'
|
4
|
+
|
5
|
+
class GeneratorsTest < ActiveSupport::TestCase
|
6
|
+
RAILS_APP_PATH = File.expand_path("../rails_app", __FILE__)
|
7
|
+
|
8
|
+
test "rails g should include the 3 generators" do
|
9
|
+
output = `cd #{RAILS_APP_PATH} && rails g`
|
10
|
+
assert output.match(%r|DeviseInvitable:\n devise_invitable\n devise_invitable:install\n devise_invitable:views|)
|
11
|
+
end
|
12
|
+
|
13
|
+
test "rails g devise_invitable:install" do
|
14
|
+
output = `cd #{RAILS_APP_PATH} && rails g devise_invitable:install -p`
|
15
|
+
assert output.match(%r|inject.+ config/initializers/devise\.rb\n|)
|
16
|
+
assert output.match(%r|create.+ config/locales/devise_invitable\.en\.yml\n|)
|
17
|
+
end
|
18
|
+
|
19
|
+
test "rails g devise_invitable:views not scoped" do
|
20
|
+
output = `cd #{RAILS_APP_PATH} && rails g devise_invitable:views -p`
|
21
|
+
assert output.match(%r|create.+ app/views/devise\n|)
|
22
|
+
assert output.match(%r|create.+ app/views/devise/invitations/edit\.html\.erb\n|)
|
23
|
+
assert output.match(%r|create.+ app/views/devise/invitations/new\.html\.erb\n|)
|
24
|
+
assert output.match(%r|create.+ app/views/devise/mailer/invitation_instructions\.html\.erb\n|)
|
25
|
+
end
|
26
|
+
|
27
|
+
test "rails g devise_invitable:views scoped" do
|
28
|
+
output = `cd #{RAILS_APP_PATH} && rails g devise_invitable:views octopussies -p`
|
29
|
+
assert output.match(%r|create.+ app/views/octopussies\n|)
|
30
|
+
assert output.match(%r|create.+ app/views/octopussies/invitations/edit\.html\.erb\n|)
|
31
|
+
assert output.match(%r|create.+ app/views/octopussies/invitations/new\.html\.erb\n|)
|
32
|
+
assert output.match(%r|create.+ app/views/octopussies/mailer/invitation_instructions\.html\.erb\n|)
|
33
|
+
end
|
34
|
+
|
35
|
+
test "rails g devise_invitable Octopussy" do
|
36
|
+
output = `cd #{RAILS_APP_PATH} && rails g devise_invitable Octopussy -p`
|
37
|
+
assert output.match(%r|inject.+ app/models/octopussy\.rb\n|)
|
38
|
+
assert output.match(%r|invoke.+ #{DEVISE_ORM}\n|)
|
39
|
+
if DEVISE_ORM == :active_record
|
40
|
+
assert output.match(%r|create.+ db/migrate/\d{14}_devise_invitable_add_to_octopussies\.rb\n|)
|
41
|
+
elsif DEVISE_ORM == :mongoid
|
42
|
+
assert !output.match(%r|create.+ db/migrate/\d{14}_devise_invitable_add_to_octopussies\.rb\n|)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
require 'test/integration_tests_helper'
|
3
|
+
|
4
|
+
class InvitationTest < ActionDispatch::IntegrationTest
|
5
|
+
def teardown
|
6
|
+
Capybara.reset_sessions!
|
7
|
+
end
|
8
|
+
|
9
|
+
def send_invitation(&block)
|
10
|
+
visit new_user_invitation_path
|
11
|
+
|
12
|
+
fill_in 'user_email', :with => 'user@test.com'
|
13
|
+
yield if block_given?
|
14
|
+
click_button 'Send an invitation'
|
15
|
+
end
|
16
|
+
|
17
|
+
def set_password(options={}, &block)
|
18
|
+
unless options[:visit] == false
|
19
|
+
visit accept_user_invitation_path(:invitation_token => options[:invitation_token])
|
20
|
+
end
|
21
|
+
|
22
|
+
fill_in 'user_password', :with => '987654321'
|
23
|
+
fill_in 'user_password_confirmation', :with => '987654321'
|
24
|
+
yield if block_given?
|
25
|
+
click_button 'Set my password'
|
26
|
+
end
|
27
|
+
|
28
|
+
test 'not authenticated user should not be able to send an invitation' do
|
29
|
+
get new_user_invitation_path
|
30
|
+
assert_redirected_to new_user_session_path
|
31
|
+
end
|
32
|
+
|
33
|
+
test 'authenticated user should be able to send an invitation' do
|
34
|
+
sign_in_as_user
|
35
|
+
|
36
|
+
send_invitation
|
37
|
+
assert_equal root_path, current_path
|
38
|
+
assert page.has_css?('p#notice', :text => 'An invitation email has been sent to user@test.com.')
|
39
|
+
end
|
40
|
+
|
41
|
+
test 'authenticated user with invalid email should receive an error message' do
|
42
|
+
user = create_full_user
|
43
|
+
sign_in_as_user(user)
|
44
|
+
send_invitation do
|
45
|
+
fill_in 'user_email', :with => user.email
|
46
|
+
end
|
47
|
+
|
48
|
+
assert_equal user_invitation_path, current_path
|
49
|
+
assert page.has_css?("input[type=text][value='#{user.email}']")
|
50
|
+
assert page.has_css?('#error_explanation li', :text => 'Email has already been taken')
|
51
|
+
end
|
52
|
+
|
53
|
+
test 'authenticated user should not be able to visit edit invitation page' do
|
54
|
+
sign_in_as_user
|
55
|
+
|
56
|
+
visit accept_user_invitation_path
|
57
|
+
|
58
|
+
assert_equal root_path, current_path
|
59
|
+
end
|
60
|
+
|
61
|
+
test 'not authenticated user with invalid invitation token should not be able to set his password' do
|
62
|
+
user = create_user
|
63
|
+
visit accept_user_invitation_path(:invitation_token => 'invalid_token')
|
64
|
+
|
65
|
+
assert_equal root_path, current_path
|
66
|
+
assert page.has_css?('p#alert', :text => 'The invitation token provided is not valid!')
|
67
|
+
end
|
68
|
+
|
69
|
+
test 'not authenticated user with valid invitation token but invalid password should not be able to set his password' do
|
70
|
+
user = create_user(false)
|
71
|
+
set_password :invitation_token => user.invitation_token do
|
72
|
+
fill_in 'Password confirmation', :with => 'other_password'
|
73
|
+
end
|
74
|
+
assert_equal user_invitation_path, current_path
|
75
|
+
assert page.has_css?('#error_explanation li', :text => 'Password doesn\'t match confirmation')
|
76
|
+
assert_nil user.encrypted_password
|
77
|
+
end
|
78
|
+
|
79
|
+
test 'not authenticated user with valid data should be able to change his password' do
|
80
|
+
user = create_user(false)
|
81
|
+
set_password :invitation_token => user.invitation_token
|
82
|
+
|
83
|
+
assert_equal root_path, current_path
|
84
|
+
assert page.has_css?('p#notice', :text => 'Your password was set successfully. You are now signed in.')
|
85
|
+
assert user.reload.valid_password?('987654321')
|
86
|
+
end
|
87
|
+
|
88
|
+
test 'after entering invalid data user should still be able to set his password' do
|
89
|
+
user = create_user(false)
|
90
|
+
set_password :invitation_token => user.invitation_token do
|
91
|
+
fill_in 'Password confirmation', :with => 'other_password'
|
92
|
+
end
|
93
|
+
assert_equal user_invitation_path, current_path
|
94
|
+
assert page.has_css?('#error_explanation')
|
95
|
+
assert_nil user.encrypted_password
|
96
|
+
|
97
|
+
set_password :visit => false
|
98
|
+
assert page.has_css?('p#notice', :text => 'Your password was set successfully. You are now signed in.')
|
99
|
+
assert user.reload.valid_password?('987654321')
|
100
|
+
end
|
101
|
+
|
102
|
+
test 'sign in user automatically after setting it\'s password' do
|
103
|
+
user = create_user(false)
|
104
|
+
set_password :invitation_token => user.invitation_token
|
105
|
+
assert_equal root_path, current_path
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
class ActionController::IntegrationTest
|
2
|
+
|
3
|
+
def warden
|
4
|
+
request.env['warden']
|
5
|
+
end
|
6
|
+
|
7
|
+
def create_full_user
|
8
|
+
@user ||= begin
|
9
|
+
user = User.create!(
|
10
|
+
:username => 'usertest',
|
11
|
+
:email => 'fulluser@test.com',
|
12
|
+
:password => '123456',
|
13
|
+
:password_confirmation => '123456',
|
14
|
+
:created_at => Time.now.utc
|
15
|
+
)
|
16
|
+
user.confirm!
|
17
|
+
user
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def sign_in_as_user(user = nil)
|
22
|
+
user ||= create_full_user
|
23
|
+
visit new_user_session_path
|
24
|
+
fill_in 'user_email', :with => user.email
|
25
|
+
fill_in 'user_password', :with => '123456'
|
26
|
+
fill_in 'user_password', :with => user.password
|
27
|
+
click_button 'Sign in'
|
28
|
+
end
|
29
|
+
|
30
|
+
def create_user(accept_invitation = true)
|
31
|
+
user = User.new :email => 'newuser@test.com'
|
32
|
+
user.skip_confirmation!
|
33
|
+
user.invitation_token = 'token'
|
34
|
+
user.invitation_sent_at = Time.now.utc
|
35
|
+
user.save(:validate => false)
|
36
|
+
user.accept_invitation! if accept_invitation
|
37
|
+
user
|
38
|
+
end
|
39
|
+
|
40
|
+
# Fix assert_redirect_to in integration sessions because they don't take into
|
41
|
+
# account Middleware redirects.
|
42
|
+
#
|
43
|
+
def assert_redirected_to(url)
|
44
|
+
assert [301, 302].include?(@integration_session.status),
|
45
|
+
"Expected status to be 301 or 302, got #{@integration_session.status}"
|
46
|
+
|
47
|
+
url = prepend_host(url)
|
48
|
+
location = prepend_host(@integration_session.headers["Location"])
|
49
|
+
assert_equal url, location
|
50
|
+
end
|
51
|
+
|
52
|
+
protected
|
53
|
+
|
54
|
+
def prepend_host(url)
|
55
|
+
url = "http://#{request.host}#{url}" if url[0] == ?/
|
56
|
+
url
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
require 'test/model_tests_helper'
|
3
|
+
|
4
|
+
class InvitationMailTest < ActionMailer::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
setup_mailer
|
8
|
+
Devise.mailer_sender = 'test@example.com'
|
9
|
+
end
|
10
|
+
|
11
|
+
def user
|
12
|
+
@user ||= begin
|
13
|
+
user = create_user_with_invitation('token')
|
14
|
+
user.invite!
|
15
|
+
user
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def mail
|
20
|
+
@mail ||= begin
|
21
|
+
user
|
22
|
+
ActionMailer::Base.deliveries.last
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
test 'email sent after reseting the user password' do
|
27
|
+
assert_not_nil mail
|
28
|
+
end
|
29
|
+
|
30
|
+
test 'content type should be set to html' do
|
31
|
+
assert_equal 'text/html; charset=UTF-8', mail.content_type
|
32
|
+
end
|
33
|
+
|
34
|
+
test 'send invitation to the user email' do
|
35
|
+
assert_equal [user.email], mail.to
|
36
|
+
end
|
37
|
+
|
38
|
+
test 'setup sender from configuration' do
|
39
|
+
assert_equal ['test@example.com'], mail.from
|
40
|
+
end
|
41
|
+
|
42
|
+
test 'setup subject from I18n' do
|
43
|
+
store_translations :en, :devise => { :mailer => { :invitation_instructions => { :subject => 'Localized Invitation' } } } do
|
44
|
+
assert_equal 'Localized Invitation', mail.subject
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
test 'subject namespaced by model' do
|
49
|
+
store_translations :en, :devise => { :mailer => { :invitation_instructions => { :user_subject => 'User Invitation' } } } do
|
50
|
+
assert_equal 'User Invitation', mail.subject
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
test 'body should have user info' do
|
55
|
+
assert_match /#{user.email}/, mail.body
|
56
|
+
end
|
57
|
+
|
58
|
+
test 'body should have link to confirm the account' do
|
59
|
+
host = ActionMailer::Base.default_url_options[:host]
|
60
|
+
invitation_url_regexp = %r{<a href=\"http://#{host}/users/invitation/accept\?invitation_token=#{user.invitation_token}">}
|
61
|
+
assert_match invitation_url_regexp, mail.body
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
class ActiveSupport::TestCase
|
2
|
+
def setup_mailer
|
3
|
+
ActionMailer::Base.deliveries = []
|
4
|
+
end
|
5
|
+
|
6
|
+
def store_translations(locale, translations, &block)
|
7
|
+
begin
|
8
|
+
I18n.backend.store_translations locale, translations
|
9
|
+
yield
|
10
|
+
ensure
|
11
|
+
I18n.reload!
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Helpers for creating new users
|
16
|
+
#
|
17
|
+
def generate_unique_email
|
18
|
+
@@email_count ||= 0
|
19
|
+
@@email_count += 1
|
20
|
+
"test#{@@email_count}@email.com"
|
21
|
+
end
|
22
|
+
|
23
|
+
def valid_attributes(attributes={})
|
24
|
+
{ :email => generate_unique_email,
|
25
|
+
:password => '123456',
|
26
|
+
:password_confirmation => '123456' }.update(attributes)
|
27
|
+
end
|
28
|
+
|
29
|
+
def new_user(attributes={})
|
30
|
+
User.new(valid_attributes(attributes))
|
31
|
+
end
|
32
|
+
|
33
|
+
def create_user_with_invitation(invitation_token, attributes={})
|
34
|
+
user = new_user({:password => nil, :password_confirmation => nil}.update(attributes))
|
35
|
+
user.skip_confirmation!
|
36
|
+
user.invitation_token = invitation_token
|
37
|
+
user.invitation_sent_at = Time.now.utc
|
38
|
+
user.save(:validate => false)
|
39
|
+
user
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
require 'test/test_helper'
|
2
|
+
require 'test/model_tests_helper'
|
3
|
+
|
4
|
+
class InvitableTest < ActiveSupport::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
setup_mailer
|
8
|
+
end
|
9
|
+
|
10
|
+
test 'should not generate invitation token after creating a record' do
|
11
|
+
assert_nil new_user.invitation_token
|
12
|
+
end
|
13
|
+
|
14
|
+
test 'should not regenerate invitation token each time' do
|
15
|
+
user = new_user
|
16
|
+
user.invite!
|
17
|
+
token = user.invitation_token
|
18
|
+
assert_not_nil user.invitation_token
|
19
|
+
assert_not_nil user.invitation_sent_at
|
20
|
+
3.times do
|
21
|
+
user.invite!
|
22
|
+
assert_equal token, user.invitation_token
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
test 'should set invitation sent at each time' do
|
27
|
+
user = new_user
|
28
|
+
user.invite!
|
29
|
+
old_invitation_sent_at = 3.days.ago
|
30
|
+
user.update_attribute :invitation_sent_at, old_invitation_sent_at
|
31
|
+
3.times do
|
32
|
+
user.invite!
|
33
|
+
assert_not_equal old_invitation_sent_at, user.invitation_sent_at
|
34
|
+
user.update_attribute :invitation_sent_at, old_invitation_sent_at
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
test 'should not regenerate invitation token even after the invitation token is not valid' do
|
39
|
+
User.invite_for = 1.day
|
40
|
+
user = new_user
|
41
|
+
user.invite!
|
42
|
+
token = user.invitation_token
|
43
|
+
user.invitation_sent_at = 3.days.ago
|
44
|
+
user.save
|
45
|
+
user.invite!
|
46
|
+
assert_equal token, user.invitation_token
|
47
|
+
end
|
48
|
+
|
49
|
+
test 'should test invitation sent at with invite_for configuration value' do
|
50
|
+
user = create_user_with_invitation('token')
|
51
|
+
|
52
|
+
User.stubs(:invite_for).returns(nil)
|
53
|
+
user.invitation_sent_at = Time.now.utc
|
54
|
+
assert user.valid_invitation?
|
55
|
+
|
56
|
+
User.stubs(:invite_for).returns(nil)
|
57
|
+
user.invitation_sent_at = 1.year.ago
|
58
|
+
assert user.valid_invitation?
|
59
|
+
|
60
|
+
User.stubs(:invite_for).returns(0)
|
61
|
+
user.invitation_sent_at = Time.now.utc
|
62
|
+
assert user.valid_invitation?
|
63
|
+
|
64
|
+
User.stubs(:invite_for).returns(0)
|
65
|
+
user.invitation_sent_at = 1.day.ago
|
66
|
+
assert user.valid_invitation?
|
67
|
+
|
68
|
+
User.stubs(:invite_for).returns(1.day)
|
69
|
+
user.invitation_sent_at = Time.now.utc
|
70
|
+
assert user.valid_invitation?
|
71
|
+
|
72
|
+
User.stubs(:invite_for).returns(1.day)
|
73
|
+
user.invitation_sent_at = 1.day.ago
|
74
|
+
assert !user.valid_invitation?
|
75
|
+
end
|
76
|
+
|
77
|
+
test 'should never generate the same invitation token for different users' do
|
78
|
+
invitation_tokens = []
|
79
|
+
3.times do
|
80
|
+
user = new_user
|
81
|
+
user.invite!
|
82
|
+
token = user.invitation_token
|
83
|
+
assert !invitation_tokens.include?(token)
|
84
|
+
invitation_tokens << token
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
test 'should set password and password confirmation from params' do
|
89
|
+
create_user_with_invitation('valid_token', :password => nil, :password_confirmation => nil)
|
90
|
+
user = User.accept_invitation!(:invitation_token => 'valid_token', :password => '123456789', :password_confirmation => '123456789')
|
91
|
+
assert user.valid_password?('123456789')
|
92
|
+
end
|
93
|
+
|
94
|
+
test 'should set password and save the record' do
|
95
|
+
user = create_user_with_invitation('valid_token', :password => nil, :password_confirmation => nil)
|
96
|
+
old_encrypted_password = user.encrypted_password
|
97
|
+
user = User.accept_invitation!(:invitation_token => 'valid_token', :password => '123456789', :password_confirmation => '123456789')
|
98
|
+
assert_not_equal old_encrypted_password, user.encrypted_password
|
99
|
+
end
|
100
|
+
|
101
|
+
test 'should clear invitation token while setting the password' do
|
102
|
+
user = new_user
|
103
|
+
user.skip_confirmation!
|
104
|
+
user.update_attribute(:invitation_token, 'valid_token')
|
105
|
+
assert_present user.invitation_token
|
106
|
+
assert user.accept_invitation!
|
107
|
+
assert_nil user.invitation_token
|
108
|
+
end
|
109
|
+
|
110
|
+
test 'should not clear invitation token if record is invalid' do
|
111
|
+
user = new_user
|
112
|
+
user.skip_confirmation!
|
113
|
+
user.update_attribute(:invitation_token, 'valid_token')
|
114
|
+
assert_present user.invitation_token
|
115
|
+
User.accept_invitation!(:invitation_token => 'valid_token', :password => '123456789', :password_confirmation => '987654321')
|
116
|
+
user.reload
|
117
|
+
assert_present user.invitation_token
|
118
|
+
end
|
119
|
+
|
120
|
+
test 'should reset invitation token and send invitation by email' do
|
121
|
+
user = new_user
|
122
|
+
assert_difference('ActionMailer::Base.deliveries.size') do
|
123
|
+
token = user.invitation_token
|
124
|
+
user.invite!
|
125
|
+
assert_not_equal token, user.invitation_token
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
test 'should return a record with invitation token and no errors to send invitation by email' do
|
130
|
+
invited_user = User.invite!(:email => "valid@email.com")
|
131
|
+
assert invited_user.errors.blank?
|
132
|
+
assert_present invited_user.invitation_token
|
133
|
+
assert_equal 'valid@email.com', invited_user.email
|
134
|
+
assert invited_user.persisted?
|
135
|
+
end
|
136
|
+
|
137
|
+
test 'should set all attributes with no errors' do
|
138
|
+
invited_user = User.invite!(:email => "valid@email.com", :username => 'first name')
|
139
|
+
assert invited_user.errors.blank?
|
140
|
+
assert_equal 'first name', invited_user.username
|
141
|
+
assert invited_user.persisted?
|
142
|
+
end
|
143
|
+
|
144
|
+
test 'should return a record with errors if user was found by e-mail' do
|
145
|
+
user = create_user_with_invitation('')
|
146
|
+
user.update_attribute(:invitation_token, nil)
|
147
|
+
invited_user = User.invite!(:email => user.email)
|
148
|
+
assert_equal invited_user, user
|
149
|
+
assert_equal ['has already been taken'], invited_user.errors[:email]
|
150
|
+
end
|
151
|
+
|
152
|
+
test 'should return a new record with errors if e-mail is blank' do
|
153
|
+
invited_user = User.invite!(:email => '')
|
154
|
+
assert invited_user.new_record?
|
155
|
+
assert_equal ["can't be blank"], invited_user.errors[:email]
|
156
|
+
end
|
157
|
+
|
158
|
+
test 'should return a new record with errors if e-mail is invalid' do
|
159
|
+
invited_user = User.invite!(:email => 'invalid_email')
|
160
|
+
assert invited_user.new_record?
|
161
|
+
assert_equal ["is invalid"], invited_user.errors[:email]
|
162
|
+
end
|
163
|
+
|
164
|
+
test 'should set all attributes with errors if e-mail is invalid' do
|
165
|
+
invited_user = User.invite!(:email => "invalid_email.com", :username => 'first name')
|
166
|
+
assert invited_user.new_record?
|
167
|
+
assert_equal 'first name', invited_user.username
|
168
|
+
assert invited_user.errors.present?
|
169
|
+
end
|
170
|
+
|
171
|
+
test 'should find a user to set his password based on invitation_token' do
|
172
|
+
user = new_user
|
173
|
+
user.invite!
|
174
|
+
|
175
|
+
invited_user = User.accept_invitation!(:invitation_token => user.invitation_token)
|
176
|
+
assert_equal invited_user, user
|
177
|
+
end
|
178
|
+
|
179
|
+
test 'should return a new record with errors if no invitation_token is found' do
|
180
|
+
invited_user = User.accept_invitation!(:invitation_token => 'invalid_token')
|
181
|
+
assert invited_user.new_record?
|
182
|
+
assert_equal ['is invalid'], invited_user.errors[:invitation_token]
|
183
|
+
end
|
184
|
+
|
185
|
+
test 'should return a new record with errors if invitation_token is blank' do
|
186
|
+
invited_user = User.accept_invitation!(:invitation_token => '')
|
187
|
+
assert invited_user.new_record?
|
188
|
+
assert_equal ["can't be blank"], invited_user.errors[:invitation_token]
|
189
|
+
end
|
190
|
+
|
191
|
+
test 'should return record with errors if invitation_token has expired' do
|
192
|
+
user = create_user_with_invitation('valid_token')
|
193
|
+
user.update_attribute(:invitation_sent_at, 1.day.ago)
|
194
|
+
User.stubs(:invite_for).returns(10.hours)
|
195
|
+
invited_user = User.accept_invitation!(:invitation_token => 'valid_token')
|
196
|
+
assert_equal user, invited_user
|
197
|
+
assert_equal ["is invalid"], invited_user.errors[:invitation_token]
|
198
|
+
end
|
199
|
+
|
200
|
+
test 'should set successfully user password given the new password and confirmation' do
|
201
|
+
user = new_user(:password => nil, :password_confirmation => nil)
|
202
|
+
user.invite!
|
203
|
+
|
204
|
+
invited_user = User.accept_invitation!(
|
205
|
+
:invitation_token => user.invitation_token,
|
206
|
+
:password => 'new_password',
|
207
|
+
:password_confirmation => 'new_password'
|
208
|
+
)
|
209
|
+
user.reload
|
210
|
+
|
211
|
+
assert user.valid_password?('new_password')
|
212
|
+
end
|
213
|
+
end
|