devise_invitable 1.5.5 → 1.6.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
- ---
2
- SHA1:
3
- metadata.gz: c73f548d678402b25124902905d122de26316161
4
- data.tar.gz: 39b1f217bf6a01ab772a462f5488f75a519b15fb
5
- SHA512:
6
- metadata.gz: 6150c3a9debc6a2974662801bff49a4bc3ab5ef1c6c24ca9a31d355d5633f48b591c99d80349a3feb4319b6bddf33ad5ae6159e2131fcd03b17aeed52b593f15
7
- data.tar.gz: a6e3025090643913f77bcbb4d20c8a31db17573eb62e26a13256d6ffc83bc4812f0b84182c2e75456575761192a22b8f637be0f0c859e5dc315641491dd00b5f
1
+ ---
2
+ SHA1:
3
+ metadata.gz: babfb02e4177cd88fe44772401f61014f8b462ea
4
+ data.tar.gz: 1302cfd7ca394b79ed9f250fe49e9753c4ea0ac8
5
+ SHA512:
6
+ metadata.gz: ec68260bfce3d59a7365e60e14d756815b85f8c65260cc5df7f74cdd5cc0cf443176a4ec8468e91c667150d88e7676bf5acbea6a5c7b30211e2dc76d5d6d9d56
7
+ data.tar.gz: d4213cdfc200c4ba8fd5fee2eb0251cf2b892b6663caa0a9a7e307d62f2819307fcb00f43193d92815e8196277208994471f2a329c95931766cb13e5ef6f2cdb
data/CHANGELOG CHANGED
@@ -1,3 +1,24 @@
1
+ = 1.6.1
2
+
3
+ - Support 2 arguments on after_invite_path_for, inviter and invitee
4
+ - Support mongoid 6.0 (use :optional on invited_by relation)
5
+ - Support devise 4.1
6
+
7
+ = 1.6.0
8
+
9
+ - Support devise 4.0 and rails 5.0
10
+ - Add before/after invitation_created callbacks
11
+ - Fix invitation_due_at when invite_for is 0
12
+ - Add plain text mailer template
13
+ - Ruby 1.9 not supported anymore
14
+ - Adds :require_password_on_accepting config option, and ensure invitation is not accepted if password is required and removed from form
15
+
16
+ = 1.5.5
17
+
18
+ - Add optional options hash to invite! methods, they will be used for send_devise_notification call
19
+
20
+ = 1.5.4
21
+
1
22
  - Ensure that all invited user passwords conform to a format
2
23
  - Call set_minimum_password_length (if exists) on accept invitation as devise does
3
24
  - Controllers inheriting from Devise::InvitationsController will now use 'devise.invitations' translations
data/README.rdoc CHANGED
@@ -1,11 +1,13 @@
1
1
  = DeviseInvitable
2
- {<img src="https://travis-ci.org/scambra/devise_invitable.png"/>}[https://travis-ci.org/scambra/devise_invitable] {<img src="https://codeclimate.com/github/scambra/devise_invitable/badges/gpa.svg"/}[https://codeclimate.com/github/scambra/devise_invitable]
2
+ {<img src="https://badge.fury.io/rb/devise_invitable.svg"/>}[http://badge.fury.io/rb/devise_invitable] {<img src="https://travis-ci.org/scambra/devise_invitable.png"/>}[https://travis-ci.org/scambra/devise_invitable] {<img src="https://codeclimate.com/github/scambra/devise_invitable/badges/gpa.svg"/}[https://codeclimate.com/github/scambra/devise_invitable]
3
3
 
4
4
  It adds support to devise[https://github.com/plataformatec/devise] for sending invitations by email (it requires to be authenticated) and accept the invitation setting the password.
5
5
 
6
6
  DeviseInvitable currently supports Rails 3 and 4, if you want to use it with Rails 2.3 you must install version {0.2.3}[https://rubygems.org/gems/devise_invitable/versions/0.2.3]
7
7
 
8
- If you want to use devise 3.0.x, you must use 1.2.1, newer versions require devise >= 3.1.0
8
+ It works with Devise >= 3.2
9
+ If you want to use devise 3.0.x, you must use 1.2.1 or lower
10
+ If you want to use devise 3.1.x, you must use 1.3.2 or lower
9
11
 
10
12
  == Installation
11
13
 
@@ -16,7 +18,7 @@ Install DeviseInvitable gem, it will also install dependencies (such as devise a
16
18
  Add DeviseInvitable to your Gemfile (and Devise if you weren't using them):
17
19
 
18
20
  gem 'devise', '~> 3.5.2'
19
- gem 'devise_invitable', '~> 1.5.2'
21
+ gem 'devise_invitable', '~> 1.6.0'
20
22
 
21
23
  === Automatic installation
22
24
 
@@ -130,12 +132,16 @@ or directly as parameters to the <tt>devise</tt> method:
130
132
 
131
133
  * resend_invitation: resend invitation if user with invited status is invited again. Enabled by default.
132
134
 
133
- * invited_by_class_name: The class name of the inviting model. If this is nil, polymorphic association is used.
135
+ * invited_by_class_name: the class name of the inviting model. If this is nil, polymorphic association is used.
134
136
 
135
- * invited_by_foreign_key: The foreign key to the inviting model (only used if invited_by_class_name is set, otherwise :invited_by_id)
137
+ * invited_by_foreign_key: the foreign key to the inviting model (only used if invited_by_class_name is set, otherwise :invited_by_id)
138
+
139
+ * invited_by_counter_cache: the column name used for counter_cache column. If this is nil (default value), the invited_by association is declared without counter_cache.
136
140
 
137
141
  * allow_insecure_sign_in_after_accept: automatically sign in the user after they set a password. Enabled by default.
138
142
 
143
+ * require_password_on_accepting: require password when user accepts the invitation. Enabled by default. Disable if you don't want to ask or enforce to set password while accepting, because is set when user is invited or it will be set later.
144
+
139
145
  For more details, see <tt>config/initializers/devise.rb</tt> (after you invoked the "devise_invitable:install" generator described above).
140
146
 
141
147
  == Configuring views
@@ -160,7 +166,7 @@ To change the controller's behavior, create a controller that inherits from <tt>
160
166
 
161
167
  class Users::InvitationsController < Devise::InvitationsController
162
168
  def update
163
- if this
169
+ if some_condition
164
170
  redirect_to root_path
165
171
  else
166
172
  super
@@ -174,7 +180,7 @@ Now just tell Devise that you want to use your controller, the controller above
174
180
 
175
181
  be sure that you generate the views and put them into the controller that you generated, so for this example it would be:
176
182
 
177
- rails generate devise_invitable:views users/invitations
183
+ rails generate devise_invitable:views users
178
184
 
179
185
  To change behaviour of inviting or accepting users, you can simply override two methods:
180
186
 
@@ -265,7 +271,7 @@ To check if a particular user is created by invitation, irrespective to state of
265
271
 
266
272
  **Warning**
267
273
 
268
- When using skip_invitation you must send the email with the user object instance that generated the tokens, as
274
+ When using skip_invitation you must send the email with the user object instance that generated the tokens, as
269
275
  user.raw_invitation_token is available only to the instance and is not persisted in the database.
270
276
 
271
277
  You can send an invitation to an existing user if your workflow creates them separately:
@@ -277,6 +283,11 @@ You can also set <tt>invited_by</tt> when using the <tt>invite!</tt> class metho
277
283
 
278
284
  User.invite!({:email => "new_user@example.com"}, current_user) # current_user will be set as invited_by
279
285
 
286
+ === Find by invitation token
287
+
288
+ To find by invitation token use the <tt>find_by_invitation_token</tt> class method.
289
+
290
+ user = User.find_by_invitation_token(params[:invitation_token], true)
280
291
 
281
292
 
282
293
  === Accept an invitation
@@ -287,12 +298,17 @@ To accept an invitation with a token use the <tt>accept_invitation!</tt> class m
287
298
 
288
299
  === Callbacks
289
300
 
290
- A callback event is fired before and after an invitation is accepted (User#accept_invitation!). For example, in your resource model you can add:
301
+ A callback event is fired before and after an invitation is created (User#invite!) or accepted (User#accept_invitation!). For example, in your resource model you can add:
291
302
 
303
+ before_invitation_created :email_admins
292
304
  after_invitation_accepted :email_invited_by
293
305
 
306
+ def email_admins
307
+ # ...
308
+ end
309
+
294
310
  def email_invited_by
295
- # ...
311
+ # ...
296
312
  end
297
313
 
298
314
  The callbacks support all options and arguments available to the standard callbacks provided by AR.
@@ -303,14 +319,14 @@ A pair of scopes to find those users that have accepted, and those that have not
303
319
 
304
320
  User.invitation_accepted # => returns all Users for whom the invitation_accepted_at attribute is not nil
305
321
  User.invitation_not_accepted # => returns all Users for whom the invitation_accepted_at attribute is nil
306
- User.created_by_invite # => returns all Users who are created by invitations, irrespective to invitation status
322
+ User.created_by_invite # => returns all Users who are created by invitations, irrespective to invitation status
307
323
 
308
324
  == Integration in a Rails application
309
325
 
310
326
  Since the invitations controller take care of all the creation/acceptation of an invitation, in most cases you wouldn't call the <tt>invite!</tt> and <tt>accept_invitation!</tt> methods directly.
311
327
  Instead, in your views, put a link to <tt>new_user_invitation_path</tt> or <tt>new_invitation_path(:user)</tt> or even <tt>/users/invitation/new</tt> to prepare and send an invitation (to a user in this example).
312
328
 
313
- After an invitation is created and sent, the inviter will be redirected to after_invite_path_for(resource_name), which is stored path or the same path as after_sign_in_path_for by default.
329
+ After an invitation is created and sent, the inviter will be redirected to after_invite_path_for(inviter, invitee), which is stored path or the same path as after_sign_in_path_for by default.
314
330
 
315
331
  After an invitation is accepted, the invitee will be redirected to after_accept_path_for(resource), which is the same path as after_sign_in_path_for by default. If you want to override the path, override invitations controller and define after_accept_path_for method. This is useful in the common case that a user is invited to a specific location in your application. More on {Devise's README}[https://github.com/plataformatec/devise], "Controller filters and helpers" section.
316
332
 
@@ -386,6 +402,8 @@ The DeviseInvitable mailer uses the same pattern as Devise to create mail subjec
386
402
 
387
403
  Take a look at the generated locale file (in <tt>config/locales/devise_invitable.en.yml</tt>) to check all available messages.
388
404
 
405
+ Translations are not included in gem (and they won't), they are available at wiki[https://github.com/scambra/devise_invitable/wiki/I18n].
406
+
389
407
  == Other ORMs
390
408
 
391
409
  DeviseInvitable supports ActiveRecord and Mongoid, like Devise.
@@ -398,9 +416,9 @@ https://github.com/scambra/devise_invitable/wiki
398
416
 
399
417
  == Testing
400
418
 
401
- To test DeviseInvitable for the ActiveRecord ORM with RVM, Ruby 1.9.2, and Rubygems 1.8.17:
419
+ To test DeviseInvitable for the ActiveRecord ORM with RVM, Ruby 2.0.0:
402
420
 
403
- rvm use 1.9.2
421
+ rvm use 2.0.0
404
422
  rvm gemset create devise_invitable
405
423
  rvm gemset use devise_invitable
406
424
  gem install bundler
@@ -1,10 +1,19 @@
1
1
  class Devise::InvitationsController < DeviseController
2
+ if Rails::VERSION::MAJOR >= 5
3
+ prepend_before_action :authenticate_inviter!, :only => [:new, :create]
4
+ prepend_before_action :has_invitations_left?, :only => [:create]
5
+ prepend_before_action :require_no_authentication, :only => [:edit, :update, :destroy]
6
+ prepend_before_action :resource_from_invitation_token, :only => [:edit, :destroy]
7
+ else
8
+ prepend_before_filter :authenticate_inviter!, :only => [:new, :create]
9
+ prepend_before_filter :has_invitations_left?, :only => [:create]
10
+ prepend_before_filter :require_no_authentication, :only => [:edit, :update, :destroy]
11
+ prepend_before_filter :resource_from_invitation_token, :only => [:edit, :destroy]
12
+ end
2
13
 
3
- prepend_before_filter :authenticate_inviter!, :only => [:new, :create]
4
- prepend_before_filter :has_invitations_left?, :only => [:create]
5
- prepend_before_filter :require_no_authentication, :only => [:edit, :update, :destroy]
6
- prepend_before_filter :resource_from_invitation_token, :only => [:edit, :destroy]
7
- helper_method :after_sign_in_path_for
14
+ if respond_to? :helper_method
15
+ helper_method :after_sign_in_path_for
16
+ end
8
17
 
9
18
  # GET /resource/invitation/new
10
19
  def new
@@ -23,7 +32,11 @@ class Devise::InvitationsController < DeviseController
23
32
  if is_flashing_format? && self.resource.invitation_sent_at
24
33
  set_flash_message :notice, :send_instructions, :email => self.resource.email
25
34
  end
26
- respond_with resource, :location => after_invite_path_for(current_inviter)
35
+ if self.method(:after_invite_path_for).arity == 1
36
+ respond_with resource, :location => after_invite_path_for(current_inviter)
37
+ else
38
+ respond_with resource, :location => after_invite_path_for(current_inviter, resource)
39
+ end
27
40
  else
28
41
  respond_with_navigational(resource) { render :new }
29
42
  end
@@ -108,4 +121,3 @@ class Devise::InvitationsController < DeviseController
108
121
  'devise.invitations'
109
122
  end
110
123
  end
111
-
@@ -4,11 +4,13 @@
4
4
  <%= devise_error_messages! %>
5
5
  <%= f.hidden_field :invitation_token %>
6
6
 
7
+ <% if f.object.class.require_password_on_accepting %>
7
8
  <p><%= f.label :password %><br />
8
9
  <%= f.password_field :password %></p>
9
10
 
10
11
  <p><%= f.label :password_confirmation %><br />
11
12
  <%= f.password_field :password_confirmation %></p>
13
+ <% end %>
12
14
 
13
15
  <p><%= f.submit t("devise.invitations.edit.submit_button") %></p>
14
16
  <% end %>
@@ -0,0 +1,11 @@
1
+ <%= t("devise.mailer.invitation_instructions.hello", email: @resource.email) %>
2
+
3
+ <%= t("devise.mailer.invitation_instructions.someone_invited_you", url: root_url) %>
4
+
5
+ <%= accept_invitation_url(@resource, :invitation_token => @token) %>
6
+
7
+ <% if @resource.invitation_due_at %>
8
+ <%= t("devise.mailer.invitation_instructions.accept_until", due_date: l(@resource.invitation_due_at, format: :'devise.mailer.invitation_instructions.accept_until_format')) %>
9
+ <% end %>
10
+
11
+ <%= strip_tags t("devise.mailer.invitation_instructions.ignore") %>
@@ -22,7 +22,7 @@ en:
22
22
  someone_invited_you: "Someone has invited you to %{url}, you can accept it through the link below."
23
23
  accept: "Accept invitation"
24
24
  accept_until: "This invitation will be due in %{due_date}."
25
- ignore: "If you don't want to accept the invitation, please ignore this email.<br />Your account won't be created until you access the link above and set your password."
25
+ ignore: "If you don't want to accept the invitation, please ignore this email.<br />\nYour account won't be created until you access the link above and set your password."
26
26
  time:
27
27
  formats:
28
28
  devise:
@@ -4,8 +4,8 @@ module DeviseInvitable::Controllers::Helpers
4
4
  included do
5
5
  end
6
6
 
7
- def after_invite_path_for(resource)
8
- after_sign_in_path_for(resource)
7
+ def after_invite_path_for(inviter, invitee = nil)
8
+ after_sign_in_path_for(inviter)
9
9
  end
10
10
 
11
11
  def after_accept_path_for(resource)
@@ -1,14 +1,10 @@
1
1
  module DeviseInvitable
2
2
  module Mapping
3
- def self.included(base)
4
- base.alias_method_chain :default_controllers, :invitable
5
- end
6
-
7
3
  private
8
- def default_controllers_with_invitable(options)
4
+ def default_controllers(options)
9
5
  options[:controllers] ||= {}
10
6
  options[:controllers][:registrations] ||= "devise_invitable/registrations"
11
- default_controllers_without_invitable(options)
7
+ super
12
8
  end
13
9
  end
14
- end
10
+ end
@@ -40,11 +40,15 @@ module Devise
40
40
  if defined?(ActiveRecord) && defined?(ActiveRecord::Base) && self < ActiveRecord::Base
41
41
  counter_cache = Devise.invited_by_counter_cache
42
42
  belongs_to_options.merge! :counter_cache => counter_cache if counter_cache
43
+ belongs_to_options.merge! :optional => true if ActiveRecord::VERSION::MAJOR >= 5
44
+ elsif defined?(Mongoid) && defined?(Mongoid::Document) && self < Mongoid::Document && Mongoid::VERSION >= '6.0.0'
45
+ belongs_to_options.merge! :optional => true
43
46
  end
44
47
  belongs_to :invited_by, belongs_to_options
45
48
 
46
- include ActiveSupport::Callbacks
47
- define_callbacks :invitation_accepted
49
+ extend ActiveModel::Callbacks
50
+ define_model_callbacks :invitation_created
51
+ define_model_callbacks :invitation_accepted
48
52
 
49
53
  scope :no_active_invitation, lambda { where(:invitation_token => nil) }
50
54
  if defined?(Mongoid) && defined?(Mongoid::Document) && self < Mongoid::Document
@@ -56,7 +60,14 @@ module Devise
56
60
  scope :invitation_not_accepted, lambda { where(arel_table[:invitation_token].not_eq(nil)).where(:invitation_accepted_at => nil) }
57
61
  scope :invitation_accepted, lambda { where(arel_table[:invitation_accepted_at].not_eq(nil)) }
58
62
 
59
- [:before_invitation_accepted, :after_invitation_accepted].each do |callback_method|
63
+ callbacks = [
64
+ :before_invitation_created,
65
+ :after_invitation_created,
66
+ :before_invitation_accepted,
67
+ :after_invitation_accepted,
68
+ ]
69
+
70
+ callbacks.each do |callback_method|
60
71
  send callback_method
61
72
  end
62
73
  end
@@ -79,11 +90,12 @@ module Devise
79
90
  # Accept an invitation by clearing invitation token and and setting invitation_accepted_at
80
91
  # Saves the model and confirms it if model is confirmable, running invitation_accepted callbacks
81
92
  def accept_invitation!
82
- if self.invited_to_sign_up? && self.valid?
93
+ if self.invited_to_sign_up?
94
+ @accepting_invitation = true
83
95
  run_callbacks :invitation_accepted do
84
96
  self.accept_invitation
85
97
  self.confirmed_at = self.invitation_accepted_at if self.respond_to?(:confirmed_at)
86
- self.save(:validate => false)
98
+ self.save
87
99
  end
88
100
  end
89
101
  end
@@ -95,15 +107,20 @@ module Devise
95
107
 
96
108
  # Verifies whether a user has been invited or not
97
109
  def invited_to_sign_up?
98
- persisted? && invitation_token.present?
110
+ accepting_invitation? || (persisted? && invitation_token.present?)
111
+ end
112
+
113
+ # Returns true if accept_invitation! was called
114
+ def accepting_invitation?
115
+ @accepting_invitation
99
116
  end
100
117
 
101
- # Verifies whether a user accepted an invitation (or is accepting it)
118
+ # Verifies whether a user accepted an invitation (false when user is accepting it)
102
119
  def invitation_accepted?
103
- invitation_accepted_at.present?
120
+ !accepting_invitation? && invitation_accepted_at.present?
104
121
  end
105
122
 
106
- # Verifies whether a user has accepted an invitation (or is accepting it), or was never invited
123
+ # Verifies whether a user has accepted an invitation (false when user is accepting it), or was never invited
107
124
  def accepted_or_not_invited?
108
125
  invitation_accepted? || !invited_to_sign_up?
109
126
  end
@@ -121,17 +138,20 @@ module Devise
121
138
 
122
139
  yield self if block_given?
123
140
  generate_invitation_token if no_token_present_or_skip_invitation?
124
- self.invitation_created_at = Time.now.utc
125
- self.invitation_sent_at = self.invitation_created_at unless skip_invitation
126
- self.invited_by = invited_by if invited_by
127
141
 
128
- # Call these before_validate methods since we aren't validating on save
129
- self.downcase_keys if new_record_and_responds_to?(:downcase_keys)
130
- self.strip_whitespace if new_record_and_responds_to?(:strip_whitespace)
142
+ run_callbacks :invitation_created do
143
+ self.invitation_created_at = Time.now.utc
144
+ self.invitation_sent_at = self.invitation_created_at unless skip_invitation
145
+ self.invited_by = invited_by if invited_by
131
146
 
132
- if save(:validate => false)
133
- self.invited_by.decrement_invitation_limit! if !was_invited and self.invited_by.present?
134
- deliver_invitation(options) unless skip_invitation
147
+ # Call these before_validate methods since we aren't validating on save
148
+ self.downcase_keys if new_record_and_responds_to?(:downcase_keys)
149
+ self.strip_whitespace if new_record_and_responds_to?(:strip_whitespace)
150
+
151
+ if save(:validate => false)
152
+ self.invited_by.decrement_invitation_limit! if !was_invited and self.invited_by.present?
153
+ deliver_invitation(options) unless skip_invitation
154
+ end
135
155
  end
136
156
  end
137
157
 
@@ -144,7 +164,12 @@ module Devise
144
164
 
145
165
  # Only verify password when is not invited
146
166
  def valid_password?(password)
147
- super unless block_from_invitation?
167
+ super unless !accepting_invitation? && block_from_invitation?
168
+ end
169
+
170
+ # Enforce password when invitation is being accepted
171
+ def password_required?
172
+ (accepting_invitation? && self.class.require_password_on_accepting) || super
148
173
  end
149
174
 
150
175
  def unauthenticated_message
@@ -180,7 +205,8 @@ module Devise
180
205
  end
181
206
 
182
207
  def invitation_due_at
183
- return nil unless self.class.invite_for
208
+ return nil if (self.class.invite_for == 0 || self.class.invite_for.nil?)
209
+ #return nil unless self.class.invite_for
184
210
 
185
211
  time = self.invitation_created_at || self.invitation_sent_at
186
212
  time + self.class.invite_for
@@ -311,6 +337,14 @@ module Devise
311
337
  end
312
338
 
313
339
  # Callback convenience methods
340
+ def before_invitation_created(*args, &blk)
341
+ set_callback(:invitation_created, :before, *args, &blk)
342
+ end
343
+
344
+ def after_invitation_created(*args, &blk)
345
+ set_callback(:invitation_created, :after, *args, &blk)
346
+ end
347
+
314
348
  def before_invitation_accepted(*args, &blk)
315
349
  set_callback(:invitation_accepted, :before, *args, &blk)
316
350
  end
@@ -326,6 +360,7 @@ module Devise
326
360
  Devise::Models.config(self, :invite_key)
327
361
  Devise::Models.config(self, :resend_invitation)
328
362
  Devise::Models.config(self, :allow_insecure_sign_in_after_accept)
363
+ Devise::Models.config(self, :require_password_on_accepting)
329
364
 
330
365
  private
331
366
 
@@ -1,29 +1,37 @@
1
1
  module DeviseInvitable
2
2
  module ParameterSanitizer
3
- def invite
4
- permit self.for(:invite)
5
- end
6
-
7
- def accept_invitation
8
- permit self.for(:accept_invitation)
9
- end
3
+ if defined?(Devise::BaseSanitizer)
4
+ def invite
5
+ permit self.for(:invite)
6
+ end
10
7
 
11
- def self.included(base)
12
- base.alias_method_chain :attributes_for, :invitable
8
+ def accept_invitation
9
+ permit self.for(:accept_invitation)
10
+ end
13
11
  end
14
12
 
15
13
  private
16
- def permit(keys)
17
- default_params.permit(*Array(keys))
18
- end
19
14
 
20
- def attributes_for_with_invitable(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 attributes_for_without_invitable(kind)
15
+ if defined?(Devise::BaseSanitizer)
16
+ def permit(keys)
17
+ default_params.permit(*Array(keys))
18
+ end
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
27
+ super
28
+ end
29
+ 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] )
27
35
  end
28
36
  end
29
37
  end
@@ -16,8 +16,8 @@ module DeviseInvitable
16
16
  end
17
17
  # extend mapping with after_initialize because it's not reloaded
18
18
  config.after_initialize do
19
- Devise::Mapping.send :include, DeviseInvitable::Mapping
20
- Devise::ParameterSanitizer.send :include, DeviseInvitable::ParameterSanitizer
19
+ Devise::Mapping.send :prepend, DeviseInvitable::Mapping
20
+ Devise::ParameterSanitizer.send :prepend, DeviseInvitable::ParameterSanitizer
21
21
  end
22
22
  end
23
23
  end
@@ -1,3 +1,3 @@
1
1
  module DeviseInvitable
2
- VERSION = '1.5.5'
2
+ VERSION = '1.6.1'
3
3
  end
@@ -72,10 +72,16 @@ module Devise
72
72
  mattr_accessor :invited_by_counter_cache
73
73
  @@invited_by_counter_cache = nil
74
74
 
75
- # Public: Auto-login after the user accepts the invite. If this is false,
75
+ # Public: Auto-login after the user accepts the invitation. If this is false,
76
76
  # the user will need to manually log in after accepting the invite (default: true).
77
77
  mattr_accessor :allow_insecure_sign_in_after_accept
78
78
  @@allow_insecure_sign_in_after_accept = true
79
+
80
+ # Public: Require password when user accepts the invitation. Set to false if
81
+ # you don't want to ask or enforce to set password while accepting, because is
82
+ # set when user is invited or it will be set later (default: true).
83
+ mattr_accessor :require_password_on_accepting
84
+ @@require_password_on_accepting = true
79
85
  end
80
86
 
81
87
  Devise.add_module :invitable, :controller => :invitations, :model => 'devise_invitable/model', :route => {:invitation => [nil, :new, :accept]}
@@ -63,8 +63,8 @@ module DeviseInvitable
63
63
 
64
64
  # Auto-login after the user accepts the invite. If this is false,
65
65
  # the user will need to manually log in after accepting the invite.
66
- # Default: false
67
- # config.allow_insecure_sign_in_after_accept = true
66
+ # Default: true
67
+ # config.allow_insecure_sign_in_after_accept = false
68
68
 
69
69
  CONTENT
70
70
  end
@@ -6,32 +6,37 @@ class ControllerHelpersTest < ActionController::TestCase
6
6
  test "after invite path defaults to after sign in path" do
7
7
  assert_equal @controller.send(:after_sign_in_path_for, :user), @controller.after_invite_path_for(:user)
8
8
  end
9
-
9
+
10
10
  test "after accept path defaults to after sign in path" do
11
11
  assert_equal @controller.send(:after_sign_in_path_for, :user), @controller.after_accept_path_for(:user)
12
12
  end
13
-
13
+
14
14
  test 'after invite path is customizable from application controller' do
15
15
  custom_path = 'customized/after/invite/path'
16
16
  @controller.instance_eval "def after_invite_path_for(resource) '#{custom_path}' end"
17
17
  assert_equal @controller.after_invite_path_for(:user), custom_path
18
18
  end
19
-
19
+
20
+ test 'after invite path is customizable from application controller with invited' do
21
+ custom_path = 'customized/after/invite/path'
22
+ @controller.instance_eval "def after_invite_path_for(resource, invited) '#{custom_path}' end"
23
+ assert_equal @controller.after_invite_path_for(:user, :invited), custom_path
24
+ end
20
25
  test 'after accept path is customizable from application controller' do
21
26
  custom_path = 'customized/after/accept/path'
22
27
  @controller.instance_eval "def after_accept_path_for(resource) '#{custom_path}' end"
23
28
  assert_equal @controller.after_accept_path_for(:user), custom_path
24
29
  end
25
-
30
+
26
31
  test 'is not a devise controller' do
27
32
  assert !@controller.devise_controller?
28
33
  end
29
-
34
+
30
35
  test 'invitations controller respects definition for after invite path in application controller' do
31
36
  assert Devise::InvitationsController.method_defined? :after_invite_path_for
32
37
  assert !Devise::InvitationsController.instance_methods(false).include?(:after_invite_path_for)
33
38
  end
34
-
39
+
35
40
  test 'invitations controller respects definition for after accept path in application controller' do
36
41
  assert Devise::InvitationsController.method_defined? :after_accept_path_for
37
42
  assert !Devise::InvitationsController.instance_methods(false).include?(:after_accept_path_for)
@@ -23,8 +23,8 @@ class InvitationMailTest < ActionMailer::TestCase
23
23
  assert_not_nil mail
24
24
  end
25
25
 
26
- test 'content type should be set to html' do
27
- assert_equal 'text/html; charset=UTF-8', mail.content_type
26
+ test 'content type should be set to multipart' do
27
+ assert_match /^multipart\/alternative; boundary="[^"]+"; charset=UTF-8/, mail.content_type
28
28
  end
29
29
 
30
30
  test 'send invitation to the user email' do
@@ -48,30 +48,44 @@ class InvitationMailTest < ActionMailer::TestCase
48
48
  end
49
49
 
50
50
  test 'body should have user info' do
51
- assert_match /#{user.email}/, mail.body.decoded
51
+ assert_match /#{user.email}/, mail.html_part.body.decoded
52
+ assert_match /#{user.email}/, mail.text_part.body.decoded
52
53
  end
53
54
 
54
55
  test 'body should have link to confirm the account' do
55
56
  host = ActionMailer::Base.default_url_options[:host]
56
- body = mail.body.decoded
57
+ body = mail.html_part.body.decoded
57
58
  invitation_url_regexp = %r{<a href=\"http://#{host}/users/invitation/accept\?invitation_token=#{Thread.current[:token]}">}
58
59
  assert_match invitation_url_regexp, body
60
+
61
+ body = mail.text_part.body.decoded
62
+ invitation_url_regexp = %r{http://#{host}/users/invitation/accept\?invitation_token=#{Thread.current[:token]}}
63
+ assert_match invitation_url_regexp, body
59
64
  end
60
65
 
61
66
  test 'body should have link to confirm the account on resend' do
62
67
  host = ActionMailer::Base.default_url_options[:host]
63
68
  user
64
69
  @user = User.find(user.id).invite!
65
- body = mail.body.decoded
70
+ body = mail.html_part.body.decoded
66
71
  invitation_url_regexp = %r{<a href=\"http://#{host}/users/invitation/accept\?invitation_token=#{Thread.current[:token]}">}
67
72
  assert_match invitation_url_regexp, body
73
+
74
+ body = mail.text_part.body.decoded
75
+ invitation_url_regexp = %r{http://#{host}/users/invitation/accept\?invitation_token=#{Thread.current[:token]}}
76
+ assert_match invitation_url_regexp, body
68
77
  end
69
78
 
70
79
  test 'body should have invitation due date when it exists' do
80
+ User.stubs(:invite_for => 5)
81
+
71
82
  host = ActionMailer::Base.default_url_options[:host]
72
83
  user
73
- body = mail.body.decoded
84
+ body = mail.html_part.body.decoded
85
+ due_date_regexp = %r{#{I18n.l user.invitation_due_at, format: :'devise.mailer.invitation_instructions.accept_until_format' }}
86
+ assert_match due_date_regexp, body
74
87
 
88
+ body = mail.text_part.body.decoded
75
89
  due_date_regexp = %r{#{I18n.l user.invitation_due_at, format: :'devise.mailer.invitation_instructions.accept_until_format' }}
76
90
  assert_match due_date_regexp, body
77
91
  end