devise_invitable 2.0.0 → 2.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +18 -0
  3. data/README.rdoc +27 -33
  4. data/app/controllers/devise/invitations_controller.rb +31 -30
  5. data/app/controllers/devise_invitable/registrations_controller.rb +11 -11
  6. data/app/views/devise/invitations/edit.html.erb +1 -1
  7. data/app/views/devise/mailer/invitation_instructions.html.erb +1 -1
  8. data/app/views/devise/mailer/invitation_instructions.text.erb +1 -1
  9. data/config/locales/ar.yml +23 -0
  10. data/config/locales/da.yml +41 -0
  11. data/config/locales/de.yml +31 -0
  12. data/config/locales/es.yml +31 -0
  13. data/config/locales/et.yml +23 -0
  14. data/config/locales/fa.yml +31 -0
  15. data/config/locales/fr.yml +34 -0
  16. data/config/locales/it.yml +31 -0
  17. data/config/locales/ja.yml +31 -0
  18. data/config/locales/ko.yml +24 -0
  19. data/config/locales/nl.yml +32 -0
  20. data/config/locales/no.yml +17 -0
  21. data/config/locales/pl.yml +31 -0
  22. data/config/locales/pt-BR.yml +23 -0
  23. data/config/locales/pt.yml +23 -0
  24. data/config/locales/ru.yml +23 -0
  25. data/config/locales/tr.yml +24 -0
  26. data/config/locales/ua.yml +31 -0
  27. data/config/locales/vi.yml +25 -0
  28. data/config/locales/zh-HK.yml +31 -0
  29. data/config/locales/zh-TW.yml +31 -0
  30. data/lib/devise_invitable.rb +2 -1
  31. data/lib/devise_invitable/controllers/helpers.rb +3 -4
  32. data/lib/devise_invitable/inviter.rb +4 -3
  33. data/lib/devise_invitable/mapping.rb +6 -5
  34. data/lib/devise_invitable/models.rb +13 -11
  35. data/lib/devise_invitable/models/authenticatable.rb +7 -1
  36. data/lib/devise_invitable/parameter_sanitizer.rb +18 -18
  37. data/lib/devise_invitable/routes.rb +1 -1
  38. data/lib/devise_invitable/version.rb +1 -1
  39. data/lib/generators/active_record/templates/migration.rb +0 -1
  40. data/lib/generators/devise_invitable/install_generator.rb +4 -3
  41. data/test/generators/views_generator_test.rb +7 -6
  42. data/test/generators_test.rb +3 -2
  43. data/test/integration_tests_helper.rb +0 -1
  44. data/test/models/invitable_test.rb +16 -0
  45. data/test/rails_app/app/controllers/admins_controller.rb +4 -3
  46. data/test/rails_app/app/controllers/application_controller.rb +10 -9
  47. data/test/rails_app/app/controllers/free_invitations_controller.rb +12 -9
  48. data/test/rails_app/config/initializers/devise.rb +4 -3
  49. data/test/rails_app/config/initializers/secret_token.rb +9 -0
  50. data/test/rails_app/db/migrate/20100401102949_create_tables.rb +0 -2
  51. data/test/test_helper.rb +4 -17
  52. metadata +31 -9
@@ -22,7 +22,8 @@ module Devise
22
22
  mattr_accessor :invite_for
23
23
  @@invite_for = 0
24
24
 
25
- # Public: Flag that force a record to be valid before being actually invited
25
+ # Public: Ensure that invited record is valid.
26
+ # The invitation won't be sent if this check fails.
26
27
  # (default: false).
27
28
  #
28
29
  # Examples (in config/initializers/devise.rb)
@@ -14,9 +14,8 @@ module DeviseInvitable::Controllers::Helpers
14
14
 
15
15
  protected
16
16
 
17
- def authenticate_inviter!
18
- send(:"authenticate_#{resource_name}!", force: true)
19
- end
20
-
17
+ def authenticate_inviter!
18
+ send(:"authenticate_#{resource_name}!", force: true)
19
+ end
21
20
  end
22
21
 
@@ -25,6 +25,7 @@ module DeviseInvitable
25
25
  end
26
26
 
27
27
  protected
28
+
28
29
  def decrement_invitation_limit!
29
30
  if self.class.invitation_limit.present?
30
31
  self.invitation_limit ||= self.class.invitation_limit
@@ -32,8 +33,8 @@ module DeviseInvitable
32
33
  end
33
34
  end
34
35
 
35
- module ClassMethods
36
- Devise::Models.config(self, :invitation_limit)
37
- end
36
+ module ClassMethods
37
+ Devise::Models.config(self, :invitation_limit)
38
+ end
38
39
  end
39
40
  end
@@ -1,10 +1,11 @@
1
1
  module DeviseInvitable
2
2
  module Mapping
3
3
  private
4
- def default_controllers(options)
5
- options[:controllers] ||= {}
6
- options[:controllers][:registrations] ||= 'devise_invitable/registrations'
7
- super
8
- end
4
+
5
+ def default_controllers(options)
6
+ options[:controllers] ||= {}
7
+ options[:controllers][:registrations] ||= 'devise_invitable/registrations'
8
+ super
9
+ end
9
10
  end
10
11
  end
@@ -10,8 +10,8 @@ module Devise
10
10
  #
11
11
  # Configuration:
12
12
  #
13
- # invite_for: The period the generated invitation token is valid, after
14
- # this period, the invited resource won't be able to accept the invitation.
13
+ # invite_for: The period the generated invitation token is valid.
14
+ # After this period, the invited resource won't be able to accept the invitation.
15
15
  # When invite_for is 0 (the default), the invitation won't expire.
16
16
  #
17
17
  # Examples:
@@ -45,7 +45,7 @@ module Devise
45
45
  elsif defined?(Mongoid) && defined?(Mongoid::Document) && self < Mongoid::Document && Mongoid::VERSION >= '6.0.0'
46
46
  belongs_to_options.merge! optional: true
47
47
  end
48
- belongs_to :invited_by, belongs_to_options
48
+ belongs_to :invited_by, **belongs_to_options
49
49
 
50
50
  extend ActiveModel::Callbacks
51
51
  define_model_callbacks :invitation_created
@@ -391,15 +391,17 @@ module Devise
391
391
 
392
392
  private
393
393
 
394
- # The random password, as set after an invitation, must conform
395
- # to any password format validation rules of the application.
396
- # This default fixes the most common scenarios: Passwords must contain
397
- # lower + upper case, a digit and a symbol.
398
- # For more unusual rules, this method can be overridden.
399
- def random_password
400
- 'aA1!' + Devise.friendly_token[0, 20]
401
- end
394
+ # The random password, as set after an invitation, must conform
395
+ # to any password format validation rules of the application.
396
+ # This default fixes the most common scenarios: Passwords must contain
397
+ # lower + upper case, a digit and a symbol.
398
+ # For more unusual rules, this method can be overridden.
399
+ def random_password
400
+ length = respond_to?(:password_length) ? password_length : Devise.password_length
402
401
 
402
+ prefix = 'aA1!'
403
+ prefix + Devise.friendly_token(length.last - prefix.length)
404
+ end
403
405
  end
404
406
  end
405
407
  end
@@ -1,11 +1,17 @@
1
1
  module Devise
2
2
  module Models
3
3
  module Authenticatable
4
- BLACKLIST_FOR_SERIALIZATION.concat %i[
4
+ list = %i[
5
5
  invitation_token invitation_created_at invitation_sent_at
6
6
  invitation_accepted_at invitation_limit invited_by_type
7
7
  invited_by_id invitations_count
8
8
  ]
9
+
10
+ if defined?(UNSAFE_ATTRIBUTES_FOR_SERIALIZATION)
11
+ UNSAFE_ATTRIBUTES_FOR_SERIALIZATION.concat(list)
12
+ else
13
+ BLACKLIST_FOR_SERIALIZATION.concat(list)
14
+ end
9
15
  end
10
16
  end
11
17
  end
@@ -12,27 +12,27 @@ module DeviseInvitable
12
12
 
13
13
  private
14
14
 
15
- if defined?(Devise::BaseSanitizer)
16
- def permit(keys)
17
- default_params.permit(*Array(keys))
18
- end
15
+ if defined?(Devise::BaseSanitizer)
16
+ def permit(keys)
17
+ default_params.permit(*Array(keys))
18
+ end
19
19
 
20
- def attributes_for(kind)
21
- case kind
22
- when :invite
23
- resource_class.respond_to?(:invite_key_fields) ? resource_class.invite_key_fields : []
24
- when :accept_invitation
25
- [:password, :password_confirmation, :invitation_token]
26
- else
20
+ def attributes_for(kind)
21
+ case kind
22
+ when :invite
23
+ resource_class.respond_to?(:invite_key_fields) ? resource_class.invite_key_fields : []
24
+ when :accept_invitation
25
+ [:password, :password_confirmation, :invitation_token]
26
+ else
27
+ super
28
+ end
29
+ end
30
+ else
31
+ def initialize(resource_class, resource_name, params)
27
32
  super
33
+ permit(:invite, keys: (resource_class.respond_to?(:invite_key_fields) ? resource_class.invite_key_fields : []) )
34
+ permit(:accept_invitation, keys: [:password, :password_confirmation, :invitation_token] )
28
35
  end
29
36
  end
30
- else
31
- def initialize(resource_class, resource_name, params)
32
- super
33
- permit(:invite, keys: (resource_class.respond_to?(:invite_key_fields) ? resource_class.invite_key_fields : []) )
34
- permit(:accept_invitation, keys: [:password, :password_confirmation, :invitation_token] )
35
- end
36
- end
37
37
  end
38
38
  end
@@ -2,6 +2,7 @@ module ActionDispatch::Routing
2
2
  class Mapper
3
3
 
4
4
  protected
5
+
5
6
  def devise_invitation(mapping, controllers)
6
7
  resource :invitation, only: [:new, :create, :update],
7
8
  path: mapping.path_names[:invitation], controller: controllers[:invitations] do
@@ -9,6 +10,5 @@ module ActionDispatch::Routing
9
10
  get :destroy, path: mapping.path_names[:remove], as: :remove
10
11
  end
11
12
  end
12
-
13
13
  end
14
14
  end
@@ -1,3 +1,3 @@
1
1
  module DeviseInvitable
2
- VERSION = '2.0.0'
2
+ VERSION = '2.0.5'.freeze
3
3
  end
@@ -8,7 +8,6 @@ class DeviseInvitableAddTo<%= table_name.camelize %> < ActiveRecord::Migration<%
8
8
  t.integer :invitation_limit
9
9
  t.references :invited_by, polymorphic: true
10
10
  t.integer :invitations_count, default: 0
11
- t.index :invitations_count
12
11
  t.index :invitation_token, unique: true # for invitable
13
12
  t.index :invited_by_id
14
13
  end
@@ -15,8 +15,8 @@ module DeviseInvitable
15
15
  inject_into_file(devise_initializer_path, before: " # ==> Configuration for :confirmable\n") do
16
16
  <<-CONTENT
17
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.
18
+ # The period the generated invitation token is valid.
19
+ # After this period, the invited resource won't be able to accept the invitation.
20
20
  # When invite_for is 0 (the default), the invitation won't expire.
21
21
  # config.invite_for = 2.weeks
22
22
 
@@ -35,7 +35,8 @@ module DeviseInvitable
35
35
  # config.invite_key = { email: /\\A[^@]+@[^@]+\\z/ }
36
36
  # config.invite_key = { email: /\\A[^@]+@[^@]+\\z/, username: nil }
37
37
 
38
- # Flag that force a record to be valid before being actually invited
38
+ # Ensure that invited record is valid.
39
+ # The invitation won't be sent if this check fails.
39
40
  # Default: false
40
41
  # config.validate_on_invite = true
41
42
 
@@ -28,13 +28,14 @@ class ViewsGeneratorTest < ::Rails::Generators::TestCase
28
28
  end
29
29
 
30
30
  private
31
- def assert_files
32
- assert views = { @invitations_path => %w/edit.html.erb new.html.erb/, @mailer_path => %w/invitation_instructions.html.erb/ }
33
31
 
34
- views.each do |path, files|
35
- files.each do |file|
36
- assert_file File.join path, file
32
+ def assert_files
33
+ assert views = { @invitations_path => %w/edit.html.erb new.html.erb/, @mailer_path => %w/invitation_instructions.html.erb/ }
34
+
35
+ views.each do |path, files|
36
+ files.each do |file|
37
+ assert_file File.join path, file
38
+ end
37
39
  end
38
40
  end
39
- end
40
41
  end
@@ -17,13 +17,14 @@ class GeneratorsTest < ActiveSupport::TestCase
17
17
 
18
18
  test "rails g devise_invitable:install" do
19
19
  @output = `cd #{RAILS_APP_PATH} && rails g devise_invitable:install -p`
20
- assert @output.match(%r{(inject|insert).* config/initializers/devise\.rb\n})
20
+ puts @output
21
+ assert @output.match(%r{(inject|insert|File unchanged! The supplied flag value not found!).* config/initializers/devise\.rb\n})
21
22
  assert @output.match(%r|create.* config/locales/devise_invitable\.en\.yml\n|)
22
23
  end
23
24
 
24
25
  test "rails g devise_invitable Octopussy" do
25
26
  @output = `cd #{RAILS_APP_PATH} && rails g devise_invitable Octopussy -p`
26
- assert @output.match(%r{(inject|insert).* app/models/octopussy\.rb\n})
27
+ assert @output.match(%r{(inject|insert|File unchanged! The supplied flag value not found!).* app/models/octopussy\.rb\n})
27
28
  assert @output.match(%r|invoke.* #{DEVISE_ORM}\n|)
28
29
  if DEVISE_ORM == :active_record
29
30
  assert @output.match(%r|create.* db/migrate/\d{14}_devise_invitable_add_to_octopussies\.rb\n|)
@@ -29,7 +29,6 @@ class ActionDispatch::IntegrationTest
29
29
 
30
30
  # Fix assert_redirect_to in integration sessions because they don't take into
31
31
  # account Middleware redirects.
32
- #
33
32
  def assert_redirected_to(url)
34
33
  assert [301, 302].include?(@integration_session.status),
35
34
  "Expected status to be 301 or 302, got #{@integration_session.status}"
@@ -1,6 +1,10 @@
1
1
  require 'test_helper'
2
2
  require 'model_tests_helper'
3
3
 
4
+ class Validatable < User
5
+ devise :validatable, password_length: 10..20
6
+ end
7
+
4
8
  class InvitableTest < ActiveSupport::TestCase
5
9
 
6
10
  def setup
@@ -760,4 +764,16 @@ class InvitableTest < ActiveSupport::TestCase
760
764
  assert user.persisted?
761
765
  assert user.errors.empty?
762
766
  end
767
+
768
+ test 'should set initial password following Devise.password_length' do
769
+ user = User.invite!(email: 'valid@email.com')
770
+ assert_empty user.errors
771
+ assert_equal Devise.password_length.last, user.password.length
772
+ end
773
+
774
+ test 'should set initial passsword using :validatable with custom password_length' do
775
+ user = Validatable.invite!(email: 'valid@email.com')
776
+ assert_empty user.errors
777
+ assert_equal Validatable.password_length.last, user.password.length
778
+ end
763
779
  end
@@ -1,6 +1,7 @@
1
1
  class AdminsController < Devise::InvitationsController
2
2
  protected
3
- def authenticate_inviter!
4
- authenticate_admin!(force: true)
5
- end
3
+
4
+ def authenticate_inviter!
5
+ authenticate_admin!(force: true)
6
+ end
6
7
  end
@@ -3,15 +3,16 @@ class ApplicationController < ActionController::Base
3
3
  before_action :configure_permitted_parameters, if: :devise_controller?
4
4
 
5
5
  protected
6
- def after_sign_in_path_for(resource)
7
- if resource.is_a? Admin
8
- edit_admin_registration_path(resource)
9
- else
10
- super
6
+
7
+ def after_sign_in_path_for(resource)
8
+ if resource.is_a? Admin
9
+ edit_admin_registration_path(resource)
10
+ else
11
+ super
12
+ end
11
13
  end
12
- end
13
14
 
14
- def configure_permitted_parameters
15
- devise_parameter_sanitizer.permit(:sign_up, keys: [:email, :password, :bio])
16
- end
15
+ def configure_permitted_parameters
16
+ devise_parameter_sanitizer.permit(:sign_up, keys: [:email, :password, :bio])
17
+ end
17
18
  end
@@ -1,12 +1,15 @@
1
1
  class FreeInvitationsController < Devise::InvitationsController
2
2
  protected
3
- def authenticate_inviter!
4
- # everyone can invite
5
- end
6
- def current_inviter
7
- current_admin || current_user
8
- end
9
- def after_invite_path_for(resource)
10
- resource ? super : root_path
11
- end
3
+
4
+ def authenticate_inviter!
5
+ # everyone can invite
6
+ end
7
+
8
+ def current_inviter
9
+ current_admin || current_user
10
+ end
11
+
12
+ def after_invite_path_for(resource)
13
+ resource ? super : root_path
14
+ end
12
15
  end
@@ -91,8 +91,8 @@ Devise.setup do |config|
91
91
  # config.pepper = "e31589192aeea8807cb7d8686b0f8484d6cbfaaa65443d45144519ed1d4ffbc6ccb73b21a69ece276d94f2cac95d83990d824f36f301d6f585ededd1bf90d67d"
92
92
 
93
93
  # ==> Configuration for :invitable
94
- # The period the generated invitation token is valid, after
95
- # this period, the invited resource won't be able to accept the invitation.
94
+ # The period the generated invitation token is valid.
95
+ # After this period, the invited resource won't be able to accept the invitation.
96
96
  # When invite_for is 0 (the default), the invitation won't expire.
97
97
  # config.invite_for = 2.weeks
98
98
 
@@ -111,7 +111,8 @@ Devise.setup do |config|
111
111
  # config.invite_key = {:email => /\\A[^@]+@[^@]+\\z/}
112
112
  # config.invite_key = {:email => /\\A[^@]+@[^@]+\\z/, :username => nil}
113
113
 
114
- # Flag that force a record to be valid before being actually invited
114
+ # Ensure that invited record is valid.
115
+ # The invitation won't be sent if this check fails.
115
116
  # Default: false
116
117
  # config.validate_on_invite = true
117
118
 
@@ -0,0 +1,9 @@
1
+ # Be sure to restart your server when you modify this file.
2
+
3
+ # Your secret key for verifying the integrity of signed cookies.
4
+ # If you change this key, all old signed cookies will become invalid!
5
+ # Make sure the secret is at least 30 characters and all random,
6
+ # no regular words or you'll be exposed to dictionary attacks.
7
+ if Rails.version < '5.2.0'
8
+ RailsApp::Application.config.secret_token = 'e997edf9d7eba5cf89a76a046fa53f5d66261d22cfcf29e3f538c75ad2d175b106bd5d099f44f6ce34ad3b3162d71cfaa37d2d4f4b38645288331427b4c2a607'
9
+ end
@@ -32,7 +32,6 @@ class CreateTables < (Rails.version < '5.1' ? ActiveRecord::Migration : ActiveRe
32
32
  t.timestamps :null => false
33
33
  end
34
34
  add_index :users, :invitation_token, :unique => true
35
- add_index :users, :invitations_count
36
35
 
37
36
  create_table :admins do |t|
38
37
  ## Database authenticatable
@@ -41,6 +40,5 @@ class CreateTables < (Rails.version < '5.1' ? ActiveRecord::Migration : ActiveRe
41
40
 
42
41
  t.integer :invitations_count, :default => 0
43
42
  end
44
- add_index :admins, :invitations_count
45
43
  end
46
44
  end
data/test/test_helper.rb CHANGED
@@ -11,7 +11,7 @@ require 'mocha/setup'
11
11
 
12
12
  ActionMailer::Base.delivery_method = :test
13
13
  ActionMailer::Base.perform_deliveries = true
14
- ActionMailer::Base.default_url_options[:host] = 'test.com'
14
+ ActionMailer::Base.default_url_options[:host] = 'example.com'
15
15
 
16
16
  ActiveSupport::Deprecation.silenced = true
17
17
  $VERBOSE = false
@@ -19,28 +19,15 @@ $VERBOSE = false
19
19
  class ActionDispatch::IntegrationTest
20
20
  include Capybara::DSL
21
21
  end
22
+
22
23
  class ActionController::TestCase
23
24
  if defined? Devise::Test
24
25
  include Devise::Test::ControllerHelpers
25
26
  else
26
27
  include Devise::TestHelpers
27
28
  end
29
+
28
30
  if defined? ActiveRecord
29
- if Rails.version >= '5.0.0'
30
- self.use_transactional_tests = true
31
- else
32
- begin
33
- require 'test_after_commit'
34
- self.use_transactional_fixtures = true
35
- rescue LoadError
36
- end
37
- end
38
- end
39
-
40
- if Rails.version < '5.0.0'
41
- def post(action, *args)
42
- hash = args[0] || {}
43
- super action, hash[:params], hash[:session], hash[:flash]
44
- end
31
+ self.use_transactional_tests = true
45
32
  end
46
33
  end