devise_invitable 1.5.3 → 1.5.5

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of devise_invitable might be problematic. Click here for more details.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
- ---
2
- SHA1:
3
- metadata.gz: 34b7a909db3f99e89240bf2b81107b5981e656cb
4
- data.tar.gz: 47f3c423acd3c430232c028e130174c23720081e
5
- SHA512:
6
- metadata.gz: fb028f99d4fc760cdecc7f747b3070fa7c2373d3e5655cdb51c2526245a546f1c8b4b84175810b9b8c1df33f054a0b5b1c4190f2280eda5d31f6f7377e7cffbf
7
- data.tar.gz: e04a795483022a82a601790ad24d682934322e45348026bd6a3b387b8284b41ca8403e55afddaf57b51d630961cb2650e8fbcea15d9144c07d3e1fde8f23976f
1
+ ---
2
+ SHA1:
3
+ metadata.gz: c73f548d678402b25124902905d122de26316161
4
+ data.tar.gz: 39b1f217bf6a01ab772a462f5488f75a519b15fb
5
+ SHA512:
6
+ metadata.gz: 6150c3a9debc6a2974662801bff49a4bc3ab5ef1c6c24ca9a31d355d5633f48b591c99d80349a3feb4319b6bddf33ad5ae6159e2131fcd03b17aeed52b593f15
7
+ data.tar.gz: a6e3025090643913f77bcbb4d20c8a31db17573eb62e26a13256d6ffc83bc4812f0b84182c2e75456575761192a22b8f637be0f0c859e5dc315641491dd00b5f
data/CHANGELOG CHANGED
@@ -1,3 +1,14 @@
1
+ - Ensure that all invited user passwords conform to a format
2
+ - Call set_minimum_password_length (if exists) on accept invitation as devise does
3
+ - Controllers inheriting from Devise::InvitationsController will now use 'devise.invitations' translations
4
+ when using Devise >= 3.5. See https://github.com/plataformatec/devise/pull/3407 for more details.
5
+ - Add invitation due date to mailer
6
+
7
+ = 1.5.3
8
+
9
+ - Fix #585, avoid generating new password if there already is a encrypted one
10
+ - Give error if trying to register with a registered email
11
+
1
12
  = 1.5.2
2
13
 
3
14
  - Fix #571, accept invitation when password changes only if reset_password_token was present
@@ -185,7 +185,7 @@ To change behaviour of inviting or accepting users, you can simply override two
185
185
  # should return an instance of resource class
186
186
  def invite_resource
187
187
  ## skip sending emails on invite
188
- resource_class.invite!(invite_params, current_inviter) do |u|
188
+ super do |u|
189
189
  u.skip_invitation = true
190
190
  end
191
191
  end
@@ -247,21 +247,21 @@ the value is temporarily available when you invite a user and will be decrypted
247
247
 
248
248
  accept_user_invitation_url(:invitation_token => user.raw_invitation_token)
249
249
 
250
- When skip_invitation is used, you must also then set the invitation_sent_at field when the user is sent their
251
- token. Failure to do so will yield "Invalid invitation token" errors when the user attempts to accept the invite.
250
+ When <tt>skip_invitation</tt> is used, you must also then set the <tt>invitation_sent_at</tt> field when the user is sent their
251
+ token. Failure to do so will yield <tt>Invalid invitation token</tt> error when the user attempts to accept the invite.
252
252
  You can set it like so:
253
253
 
254
254
  user.deliver_invitation
255
255
 
256
- You can add :skip_invitation to attributes hash if skip_invitation is added to attr_accessible.
256
+ You can add <tt>:skip_invitation</tt> to attributes hash if <tt>skip_invitation</tt> is added to <tt>attr_accessible</tt>.
257
257
 
258
258
  User.invite!(:email => "new_user@example.com", :name => "John Doe", :skip_invitation => true)
259
259
  # => the record will be created, but the invitation email will not be sent
260
260
 
261
- Skip_invitation skips sending the email, but sets invitation_token, so <tt>invited_to_sign_up?</tt> on the
261
+ <tt>skip_invitation</tt> skips sending the email, but sets <tt>invitation_token</tt>, so <tt>invited_to_sign_up?</tt> on the
262
262
  resulting user returns true.
263
263
 
264
- To check if a perticular user is created by invitation, irrespective to state of invitation one can use <tt>created_by_invite?</tt>
264
+ To check if a particular user is created by invitation, irrespective to state of invitation one can use <tt>created_by_invite?</tt>
265
265
 
266
266
  **Warning**
267
267
 
@@ -31,6 +31,7 @@ class Devise::InvitationsController < DeviseController
31
31
 
32
32
  # GET /resource/invitation/accept?invitation_token=abcdef
33
33
  def edit
34
+ set_minimum_password_length if respond_to? :set_minimum_password_length
34
35
  resource.invitation_token = params[:invitation_token]
35
36
  render :edit
36
37
  end
@@ -103,5 +104,8 @@ class Devise::InvitationsController < DeviseController
103
104
  devise_parameter_sanitizer.sanitize(:accept_invitation)
104
105
  end
105
106
 
107
+ def translation_scope
108
+ 'devise.invitations'
109
+ end
106
110
  end
107
111
 
@@ -4,4 +4,8 @@
4
4
 
5
5
  <p><%= link_to t("devise.mailer.invitation_instructions.accept"), accept_invitation_url(@resource, :invitation_token => @token) %></p>
6
6
 
7
+ <% if @resource.invitation_due_at %>
8
+ <p><%= t("devise.mailer.invitation_instructions.accept_until", due_date: l(@resource.invitation_due_at, format: :'devise.mailer.invitation_instructions.accept_until_format')) %></p>
9
+ <% end %>
10
+
7
11
  <p><%= t("devise.mailer.invitation_instructions.ignore").html_safe %></p>
@@ -21,4 +21,11 @@ en:
21
21
  hello: "Hello %{email}"
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
+ accept_until: "This invitation will be due in %{due_date}."
24
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."
26
+ time:
27
+ formats:
28
+ devise:
29
+ mailer:
30
+ invitation_instructions:
31
+ accept_until_format: "%B %d, %Y %I:%M %p"
@@ -2,7 +2,6 @@ module DeviseInvitable::Controllers::Helpers
2
2
  extend ActiveSupport::Concern
3
3
 
4
4
  included do
5
- hide_action :after_invite_path_for, :after_accept_path_for
6
5
  end
7
6
 
8
7
  def after_invite_path_for(resource)
@@ -34,9 +34,9 @@ module Devise
34
34
  else
35
35
  {:polymorphic => true}
36
36
  end
37
- if fk = Devise.invited_by_foreign_key
38
- belongs_to_options[:foreign_key] = fk
39
- end
37
+ if fk = Devise.invited_by_foreign_key
38
+ belongs_to_options[:foreign_key] = fk
39
+ end
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
@@ -109,8 +109,8 @@ module Devise
109
109
  end
110
110
 
111
111
  # Reset invitation token and send invitation again
112
- def invite!(invited_by = nil)
113
- # This is an order-dependant assignment, this can't be moved
112
+ def invite!(invited_by = nil, options = {})
113
+ # This is an order-dependant assignment, this can't be moved
114
114
  was_invited = invited_to_sign_up?
115
115
 
116
116
  # Required to workaround confirmable model's confirmation_required? method
@@ -131,7 +131,7 @@ module Devise
131
131
 
132
132
  if save(:validate => false)
133
133
  self.invited_by.decrement_invitation_limit! if !was_invited and self.invited_by.present?
134
- deliver_invitation unless skip_invitation
134
+ deliver_invitation(options) unless skip_invitation
135
135
  end
136
136
  end
137
137
 
@@ -164,10 +164,10 @@ module Devise
164
164
  end
165
165
 
166
166
  # Deliver the invitation email
167
- def deliver_invitation
167
+ def deliver_invitation(options = {})
168
168
  generate_invitation_token! unless @raw_invitation_token
169
169
  self.update_attribute :invitation_sent_at, Time.now.utc unless self.invitation_sent_at
170
- send_devise_notification(:invitation_instructions, @raw_invitation_token)
170
+ send_devise_notification(:invitation_instructions, @raw_invitation_token, options)
171
171
  end
172
172
 
173
173
  # provide alias to the encrypted invitation_token stored by devise
@@ -179,6 +179,13 @@ module Devise
179
179
  respond_to?(:confirmation_required?, true) && confirmation_required?
180
180
  end
181
181
 
182
+ def invitation_due_at
183
+ return nil unless self.class.invite_for
184
+
185
+ time = self.invitation_created_at || self.invitation_sent_at
186
+ time + self.class.invite_for
187
+ end
188
+
182
189
  protected
183
190
 
184
191
  def block_from_invitation?
@@ -242,7 +249,7 @@ module Devise
242
249
  # email is resent unless resend_invitation is set to false.
243
250
  # Attributes must contain the user's email, other attributes will be
244
251
  # set in the record
245
- def _invite(attributes={}, invited_by=nil, &block)
252
+ def _invite(attributes={}, invited_by=nil, options = {}, &block)
246
253
  invite_key_array = invite_key_fields
247
254
  attributes_hash = {}
248
255
  invite_key_array.each do |k,v|
@@ -255,7 +262,7 @@ module Devise
255
262
  invitable.assign_attributes(attributes)
256
263
  invitable.invited_by = invited_by
257
264
  unless invitable.password || invitable.encrypted_password.present?
258
- invitable.password = Devise.friendly_token[0, 20]
265
+ invitable.password = random_password
259
266
  end
260
267
 
261
268
  invitable.valid? if self.validate_on_invite
@@ -268,16 +275,16 @@ module Devise
268
275
  end
269
276
 
270
277
  yield invitable if block_given?
271
- mail = invitable.invite! if invitable.errors.empty?
278
+ mail = invitable.invite!(nil, options) if invitable.errors.empty?
272
279
  [invitable, mail]
273
280
  end
274
281
 
275
- def invite!(attributes={}, invited_by=nil, &block)
276
- _invite(attributes.with_indifferent_access, invited_by, &block).first
282
+ def invite!(attributes={}, invited_by=nil, options = {}, &block)
283
+ _invite(attributes.with_indifferent_access, invited_by, options, &block).first
277
284
  end
278
285
 
279
- def invite_mail!(attributes={}, invited_by=nil, &block)
280
- _invite(attributes, invited_by, &block).last
286
+ def invite_mail!(attributes={}, invited_by=nil, options = {}, &block)
287
+ _invite(attributes, invited_by, options, &block).last
281
288
  end
282
289
 
283
290
  # Attempt to find a user by it's invitation_token to set it's password.
@@ -320,8 +327,18 @@ module Devise
320
327
  Devise::Models.config(self, :resend_invitation)
321
328
  Devise::Models.config(self, :allow_insecure_sign_in_after_accept)
322
329
 
330
+ private
331
+
332
+ # The random password, as set after an invitation, must conform
333
+ # to any password format validation rules of the application.
334
+ # This default fixes the most common scenarios: Passwords must contain
335
+ # lower + upper case, a digit and a symbol.
336
+ # For more unusual rules, this method can be overridden.
337
+ def random_password
338
+ "aA1!" + Devise.friendly_token[0, 20]
339
+ end
340
+
323
341
  end
324
342
  end
325
343
  end
326
344
  end
327
-
@@ -1,3 +1,3 @@
1
1
  module DeviseInvitable
2
- VERSION = '1.5.3'
2
+ VERSION = '1.5.5'
3
3
  end
@@ -66,4 +66,30 @@ class InvitationMailTest < ActionMailer::TestCase
66
66
  invitation_url_regexp = %r{<a href=\"http://#{host}/users/invitation/accept\?invitation_token=#{Thread.current[:token]}">}
67
67
  assert_match invitation_url_regexp, body
68
68
  end
69
+
70
+ test 'body should have invitation due date when it exists' do
71
+ host = ActionMailer::Base.default_url_options[:host]
72
+ user
73
+ body = mail.body.decoded
74
+
75
+ due_date_regexp = %r{#{I18n.l user.invitation_due_at, format: :'devise.mailer.invitation_instructions.accept_until_format' }}
76
+ assert_match due_date_regexp, body
77
+ end
78
+
79
+ test 'options are passed to the delivery method' do
80
+ class CustomMailer < Devise::Mailer
81
+ class << self
82
+ def invitation_instructions(record, name, options = {})
83
+ fail 'Options not as expected' unless options[:invited_at].is_a?(Time)
84
+ new(record, name, options)
85
+ end
86
+ end
87
+
88
+ def initialize(*args); end
89
+ def deliver; end
90
+ end
91
+ Devise.mailer = CustomMailer
92
+
93
+ User.invite!({ email: 'valid@email.com' }, nil, { invited_at: Time.now })
94
+ end
69
95
  end
@@ -1,5 +1,6 @@
1
1
  class ActiveSupport::TestCase
2
2
  def setup_mailer
3
+ Devise.mailer = Devise::Mailer
3
4
  ActionMailer::Base.deliveries = []
4
5
  end
5
6
 
@@ -122,6 +122,22 @@ class InvitableTest < ActiveSupport::TestCase
122
122
  assert !user.valid_invitation?
123
123
  end
124
124
 
125
+ test 'should return token validity when there is invite_for' do
126
+ User.stubs(:invite_for).returns(1.day)
127
+ user = User.invite!(:email => "valid@email.com")
128
+ sent_at = user.invitation_created_at || user.invitation_sent_at
129
+ valid_until = sent_at + User.invite_for
130
+
131
+ assert_equal user.invitation_due_at, valid_until
132
+ end
133
+
134
+ test 'should return nil as token validity when there is not invite_for' do
135
+ User.stubs(:invite_for).returns(nil)
136
+ user = User.invite!(:email => "valid@email.com")
137
+
138
+ assert_equal user.invitation_due_at, nil
139
+ end
140
+
125
141
  test 'should never generate the same invitation token for different users' do
126
142
  invitation_tokens = []
127
143
  3.times do
@@ -657,4 +673,18 @@ class InvitableTest < ActiveSupport::TestCase
657
673
  retval = user.reset_password!('anewpassword', 'anewpassword')
658
674
  assert_equal true, retval
659
675
  end
676
+
677
+ test 'should set initial password with variety of characters' do
678
+ PASSWORD_FORMAT = /\A
679
+ (?=.*\d) # Must contain a digit
680
+ (?=.*[a-z]) # Must contain a lower case character
681
+ (?=.*[A-Z]) # Must contain an upper case character
682
+ (?=.*[[:^alnum:]]) # Must contain a symbol
683
+ /x
684
+ User.stubs(:invite_key).returns(:password => PASSWORD_FORMAT)
685
+ Devise.stubs(:friendly_token).returns('onlylowercaseletters')
686
+ user = User.invite!(:email => "valid@email.com")
687
+ assert user.persisted?
688
+ assert user.errors.empty?
689
+ end
660
690
  end
@@ -3,6 +3,9 @@
3
3
 
4
4
  en:
5
5
  hello: "Hello world"
6
+ time:
7
+ formats:
8
+ short: "%b %d"
6
9
  devise:
7
10
  free_invitations:
8
11
  send_instructions: 'An invitation email has been sent to %{email}.'
metadata CHANGED
@@ -1,71 +1,59 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: devise_invitable
3
- version: !ruby/object:Gem::Version
4
- version: 1.5.3
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.5.5
5
5
  platform: ruby
6
- authors:
6
+ authors:
7
7
  - Sergio Cambra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-30 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
11
+
12
+ date: 2015-12-17 00:00:00 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
14
15
  name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - '>='
18
- - !ruby/object:Gem::Version
19
- version: 1.1.0
20
16
  type: :development
21
17
  prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - '>='
25
- - !ruby/object:Gem::Version
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ requirements:
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
26
22
  version: 1.1.0
27
- - !ruby/object:Gem::Dependency
23
+ version_requirements: *id001
24
+ - !ruby/object:Gem::Dependency
28
25
  name: actionmailer
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - '>='
32
- - !ruby/object:Gem::Version
33
- version: 3.2.6
34
- - - <
35
- - !ruby/object:Gem::Version
36
- version: '5'
37
26
  type: :runtime
38
27
  prerelease: false
39
- version_requirements: !ruby/object:Gem::Requirement
40
- requirements:
41
- - - '>='
42
- - !ruby/object:Gem::Version
28
+ requirement: &id002 !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
43
32
  version: 3.2.6
44
33
  - - <
45
- - !ruby/object:Gem::Version
46
- version: '5'
47
- - !ruby/object:Gem::Dependency
34
+ - !ruby/object:Gem::Version
35
+ version: "5"
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
48
38
  name: devise
49
- requirement: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - '>='
52
- - !ruby/object:Gem::Version
53
- version: 3.2.0
54
39
  type: :runtime
55
40
  prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - '>='
59
- - !ruby/object:Gem::Version
41
+ requirement: &id003 !ruby/object:Gem::Requirement
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
60
45
  version: 3.2.0
61
- description: It adds support for send invitations by email (it requires to be authenticated)
62
- and accept the invitation by setting a password.
63
- email:
46
+ version_requirements: *id003
47
+ description: It adds support for send invitations by email (it requires to be authenticated) and accept the invitation by setting a password.
48
+ email:
64
49
  - sergio@entrecables.com
65
50
  executables: []
51
+
66
52
  extensions: []
53
+
67
54
  extra_rdoc_files: []
68
- files:
55
+
56
+ files:
69
57
  - CHANGELOG
70
58
  - LICENSE
71
59
  - README.rdoc
@@ -146,33 +134,35 @@ files:
146
134
  - test/routes_test.rb
147
135
  - test/test_helper.rb
148
136
  homepage: https://github.com/scambra/devise_invitable
149
- licenses:
137
+ licenses:
150
138
  - MIT
151
139
  metadata: {}
140
+
152
141
  post_install_message:
153
- rdoc_options:
142
+ rdoc_options:
154
143
  - --main
155
144
  - README.rdoc
156
145
  - --charset=UTF-8
157
- require_paths:
146
+ require_paths:
158
147
  - lib
159
- required_ruby_version: !ruby/object:Gem::Requirement
160
- requirements:
161
- - - '>='
162
- - !ruby/object:Gem::Version
148
+ required_ruby_version: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
163
152
  version: 1.8.6
164
- required_rubygems_version: !ruby/object:Gem::Requirement
165
- requirements:
166
- - - '>='
167
- - !ruby/object:Gem::Version
153
+ required_rubygems_version: !ruby/object:Gem::Requirement
154
+ requirements:
155
+ - - ">="
156
+ - !ruby/object:Gem::Version
168
157
  version: 1.3.6
169
158
  requirements: []
159
+
170
160
  rubyforge_project:
171
- rubygems_version: 2.4.5
161
+ rubygems_version: 2.4.6
172
162
  signing_key:
173
163
  specification_version: 4
174
164
  summary: An invitation strategy for Devise
175
- test_files:
165
+ test_files:
176
166
  - test/functional/controller_helpers_test.rb
177
167
  - test/functional/registrations_controller_test.rb
178
168
  - test/generators/views_generator_test.rb