devise_invitable 1.3.2 → 1.4.0
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 +7 -0
- data/CHANGELOG +4 -0
- data/README.rdoc +45 -3
- data/app/controllers/devise/invitations_controller.rb +21 -13
- data/app/views/devise/mailer/invitation_instructions.html.erb +4 -5
- data/config/locales/en.yml +6 -0
- data/lib/devise_invitable/model.rb +19 -24
- data/lib/devise_invitable/rails.rb +6 -4
- data/lib/devise_invitable/version.rb +1 -1
- data/lib/devise_invitable.rb +5 -0
- data/lib/generators/active_record/devise_invitable_generator.rb +1 -1
- data/lib/generators/active_record/templates/migration.rb +7 -1
- data/lib/generators/devise_invitable/install_generator.rb +14 -0
- data/lib/generators/devise_invitable/templates/simple_form_for/invitations/edit.html.erb +1 -1
- data/lib/generators/devise_invitable/templates/simple_form_for/invitations/new.html.erb +1 -1
- data/test/functional/registrations_controller_test.rb +6 -6
- data/test/generators_test.rb +6 -6
- data/test/integration/invitation_test.rb +2 -2
- data/test/integration_tests_helper.rb +3 -3
- data/test/models/invitable_test.rb +67 -20
- data/test/rails_app/app/models/user.rb +4 -4
- data/test/rails_app/config/initializers/devise.rb +39 -0
- data/test/rails_app/db/migrate/20100401102949_create_tables.rb +5 -0
- metadata +15 -23
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 49059f27df2618f9c0491fd1b7578b33619f2ef5
|
|
4
|
+
data.tar.gz: da0b1ff3962cba2784b8c082c013fb483ee0517e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 56e5cc31bd011a67887ea3338ee66682dc398008f4a18f094fec9084b0635efc8684d5251aca72a9d7daecf228ea06aeec84bca49a8dd24bd3750c063f7b2e56
|
|
7
|
+
data.tar.gz: 162bc6c70f81f0b65ca73233a5ebb5ac53895b5e6c57f4085d522807592feccb29ce93c113e1d67d974fa95ebf026054d137a6a5c01c1af3913bf84df14d2f7a
|
data/CHANGELOG
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
= 1.4.0
|
|
2
|
+
Override active_for_authentication? and inactive_message instead of valid_password?
|
|
3
|
+
To use counter_cache, invited_by_counter_cache must be set, no more checking of invitations_count to enable counter cache
|
|
4
|
+
|
|
1
5
|
= 1.3.0
|
|
2
6
|
Now devise 3.1 compatible, @token must be used instead of @resource.invitation_token in mail views
|
|
3
7
|
|
data/README.rdoc
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
= DeviseInvitable
|
|
2
2
|
{<img src="https://travis-ci.org/scambra/devise_invitable.png"/>}[http://travis-ci.org/scambra/devise_invitable]
|
|
3
3
|
|
|
4
|
-
It adds support to devise[http://github.com/plataformatec/devise] for
|
|
4
|
+
It adds support to devise[http://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}[http://rubygems.org/gems/devise_invitable/versions/0.2.3]
|
|
7
7
|
|
|
@@ -16,7 +16,7 @@ Install DeviseInvitable gem, it will also install dependencies (such as devise a
|
|
|
16
16
|
Add DeviseInvitable to your Gemfile (and Devise if you weren't using them):
|
|
17
17
|
|
|
18
18
|
gem 'devise', '>= 2.0.0'
|
|
19
|
-
gem 'devise_invitable', '~> 1.
|
|
19
|
+
gem 'devise_invitable', '~> 1.3.4'
|
|
20
20
|
|
|
21
21
|
=== Automatic installation
|
|
22
22
|
|
|
@@ -172,6 +172,30 @@ be sure that you generate the views and put them into the controller that you ge
|
|
|
172
172
|
|
|
173
173
|
rails generate devise_invitable:views users/invitations
|
|
174
174
|
|
|
175
|
+
To change behaviour of inviting or accepting users, you can simply override two methods:
|
|
176
|
+
|
|
177
|
+
class Users::InvitationsController < Devise::InvitationsController
|
|
178
|
+
private
|
|
179
|
+
|
|
180
|
+
# this is called when creating invitation
|
|
181
|
+
# should return an instance of resource class
|
|
182
|
+
def invite_resource
|
|
183
|
+
## skip sending emails on invite
|
|
184
|
+
resource_class.invite!(invite_params, current_inviter) do |u|
|
|
185
|
+
u.skip_invitation = true
|
|
186
|
+
end
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# this is called when accepting invitation
|
|
190
|
+
# should return an instance of resource class
|
|
191
|
+
def accept_resource
|
|
192
|
+
resource = resource_class.accept_invitation!(update_resource_params)
|
|
193
|
+
## Report accepting invitation to analytics
|
|
194
|
+
Analytics.report('invite.accept', resource.id)
|
|
195
|
+
resource
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
175
199
|
== Strong Parameters
|
|
176
200
|
|
|
177
201
|
When you customize your own views, you may end up adding new attributes to forms. Rails 4 moved the parameter sanitization from the model to the controller, causing DeviseInvitable to handle this concern at the controller as well. Read about it in {devise README}[http://github.com/plataformatec/devise#strong-parameters]
|
|
@@ -209,11 +233,16 @@ To send an invitation to a user, use the <tt>invite!</tt> class method. <tt>:ema
|
|
|
209
233
|
|
|
210
234
|
If you want to create the invitation but not send it, you can set <tt>skip_invitation</tt> to true.
|
|
211
235
|
|
|
212
|
-
User.invite!(:email => "new_user@example.com", :name => "John Doe") do |u|
|
|
236
|
+
user = User.invite!(:email => "new_user@example.com", :name => "John Doe") do |u|
|
|
213
237
|
u.skip_invitation = true
|
|
214
238
|
end
|
|
215
239
|
# => the record will be created, but the invitation email will not be sent
|
|
216
240
|
|
|
241
|
+
When generating the <tt>accept_user_invitation_url</tt> yourself, you must use the <tt>raw_invitation_token</tt>
|
|
242
|
+
the value is temporarily available when you invite a user and will be decrypted when recieved.
|
|
243
|
+
|
|
244
|
+
accept_user_invitation_url(:invitation_token => user.raw_invitation_token)
|
|
245
|
+
|
|
217
246
|
When skip_invitation is used, you must also then set the invitation_sent_at field when the user is sent their
|
|
218
247
|
token. Failure to do so will yield "Invalid invitation token" errors when the user attempts to accept the invite.
|
|
219
248
|
You can set it like so:
|
|
@@ -228,6 +257,11 @@ You can add :skip_invitation to attributes hash if skip_invitation is added to a
|
|
|
228
257
|
Skip_invitation skips sending the email, but sets invitation_token, so invited_to_sign_up? on the
|
|
229
258
|
resulting user returns true.
|
|
230
259
|
|
|
260
|
+
**Warning**
|
|
261
|
+
|
|
262
|
+
When using skip_invitation you must send the email with the user object instance that generated the tokens, as
|
|
263
|
+
user.raw_invitation_token is available only to the instance and is not persisted in the database.
|
|
264
|
+
|
|
231
265
|
You can send an invitation to an existing user if your workflow creates them separately:
|
|
232
266
|
|
|
233
267
|
user = User.find(42)
|
|
@@ -237,6 +271,8 @@ You can also set <tt>invited_by</tt> when using the <tt>invite!</tt> class metho
|
|
|
237
271
|
|
|
238
272
|
User.invite!({:email => "new_user@example.com"}, current_user) # current_user will be set as invited_by
|
|
239
273
|
|
|
274
|
+
|
|
275
|
+
|
|
240
276
|
=== Accept an invitation
|
|
241
277
|
|
|
242
278
|
To accept an invitation with a token use the <tt>accept_invitation!</tt> class method. <tt>:invitation_token</tt> must be present in the parameters hash. You can also include other attributes in the hash.
|
|
@@ -345,6 +381,12 @@ Take a look at the generated locale file (in <tt>config/locales/devise_invitable
|
|
|
345
381
|
|
|
346
382
|
DeviseInvitable supports ActiveRecord and Mongoid, like Devise.
|
|
347
383
|
|
|
384
|
+
== Wiki
|
|
385
|
+
|
|
386
|
+
It's possible to find additional information about DeviseInvitable on the Wiki:
|
|
387
|
+
|
|
388
|
+
https://github.com/scambra/devise_invitable/wiki
|
|
389
|
+
|
|
348
390
|
== Testing
|
|
349
391
|
|
|
350
392
|
To test DeviseInvitable for the ActiveRecord ORM with RVM, Ruby 1.9.2, and Rubygems 1.8.17:
|
|
@@ -17,7 +17,10 @@ class Devise::InvitationsController < DeviseController
|
|
|
17
17
|
self.resource = invite_resource
|
|
18
18
|
|
|
19
19
|
if resource.errors.empty?
|
|
20
|
-
|
|
20
|
+
yield resource if block_given?
|
|
21
|
+
if is_flashing_format? && self.resource.invitation_sent_at
|
|
22
|
+
set_flash_message :notice, :send_instructions, :email => self.resource.email
|
|
23
|
+
end
|
|
21
24
|
respond_with resource, :location => after_invite_path_for(resource)
|
|
22
25
|
else
|
|
23
26
|
respond_with_navigational(resource) { render :new }
|
|
@@ -32,46 +35,51 @@ class Devise::InvitationsController < DeviseController
|
|
|
32
35
|
|
|
33
36
|
# PUT /resource/invitation
|
|
34
37
|
def update
|
|
35
|
-
self.resource =
|
|
38
|
+
self.resource = accept_resource
|
|
36
39
|
|
|
37
40
|
if resource.errors.empty?
|
|
38
|
-
|
|
39
|
-
|
|
41
|
+
yield resource if block_given?
|
|
42
|
+
flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
|
|
43
|
+
set_flash_message :notice, flash_message if is_flashing_format?
|
|
40
44
|
sign_in(resource_name, resource)
|
|
41
45
|
respond_with resource, :location => after_accept_path_for(resource)
|
|
42
46
|
else
|
|
43
47
|
respond_with_navigational(resource){ render :edit }
|
|
44
48
|
end
|
|
45
49
|
end
|
|
46
|
-
|
|
50
|
+
|
|
47
51
|
# GET /resource/invitation/remove?invitation_token=abcdef
|
|
48
52
|
def destroy
|
|
49
53
|
resource.destroy
|
|
50
|
-
set_flash_message :notice, :invitation_removed
|
|
54
|
+
set_flash_message :notice, :invitation_removed if is_flashing_format?
|
|
51
55
|
redirect_to after_sign_out_path_for(resource_name)
|
|
52
56
|
end
|
|
53
57
|
|
|
54
58
|
protected
|
|
55
59
|
|
|
56
|
-
def invite_resource
|
|
57
|
-
resource_class.invite!(invite_params, current_inviter)
|
|
60
|
+
def invite_resource(&block)
|
|
61
|
+
resource_class.invite!(invite_params, current_inviter, &block)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def accept_resource
|
|
65
|
+
resource_class.accept_invitation!(update_resource_params)
|
|
58
66
|
end
|
|
59
67
|
|
|
60
68
|
def current_inviter
|
|
61
|
-
|
|
69
|
+
authenticate_inviter!
|
|
62
70
|
end
|
|
63
71
|
|
|
64
72
|
def has_invitations_left?
|
|
65
73
|
unless current_inviter.nil? || current_inviter.has_invitations_left?
|
|
66
74
|
self.resource = resource_class.new
|
|
67
|
-
set_flash_message :alert, :no_invitations_remaining
|
|
75
|
+
set_flash_message :alert, :no_invitations_remaining if is_flashing_format?
|
|
68
76
|
respond_with_navigational(resource) { render :new }
|
|
69
77
|
end
|
|
70
78
|
end
|
|
71
|
-
|
|
79
|
+
|
|
72
80
|
def resource_from_invitation_token
|
|
73
81
|
unless params[:invitation_token] && self.resource = resource_class.find_by_invitation_token(params[:invitation_token], true)
|
|
74
|
-
set_flash_message(:alert, :invitation_token_invalid)
|
|
82
|
+
set_flash_message(:alert, :invitation_token_invalid) if is_flashing_format?
|
|
75
83
|
redirect_to after_sign_out_path_for(resource_name)
|
|
76
84
|
end
|
|
77
85
|
end
|
|
@@ -83,6 +91,6 @@ class Devise::InvitationsController < DeviseController
|
|
|
83
91
|
def update_resource_params
|
|
84
92
|
devise_parameter_sanitizer.sanitize(:accept_invitation)
|
|
85
93
|
end
|
|
86
|
-
|
|
94
|
+
|
|
87
95
|
end
|
|
88
96
|
|
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
<p
|
|
1
|
+
<p><%= t("devise.mailer.invitation_instructions.hello", email: @resource.email) %></p>
|
|
2
2
|
|
|
3
|
-
<p
|
|
3
|
+
<p><%= t("devise.mailer.invitation_instructions.someone_invited_you", url: root_url) %></p>
|
|
4
4
|
|
|
5
|
-
<p><%= link_to
|
|
5
|
+
<p><%= link_to t("devise.mailer.invitation_instructions.accept"), accept_invitation_url(@resource, :invitation_token => @token) %></p>
|
|
6
6
|
|
|
7
|
-
<p
|
|
8
|
-
Your account won't be created until you access the link above and set your password.</p>
|
|
7
|
+
<p><%= t("devise.mailer.invitation_instructions.ignore").html_safe %></p>
|
data/config/locales/en.yml
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
en:
|
|
2
2
|
devise:
|
|
3
|
+
failure:
|
|
4
|
+
invited: 'You have a pending invitation, accept it to finish creating your account.'
|
|
3
5
|
invitations:
|
|
4
6
|
send_instructions: 'An invitation email has been sent to %{email}.'
|
|
5
7
|
invitation_token_invalid: 'The invitation token provided is not valid!'
|
|
@@ -15,3 +17,7 @@ en:
|
|
|
15
17
|
mailer:
|
|
16
18
|
invitation_instructions:
|
|
17
19
|
subject: 'Invitation instructions'
|
|
20
|
+
hello: 'Hello %{email}'
|
|
21
|
+
someone_invited_you: 'Someone has invited you to %{url}, you can accept it through the link below.'
|
|
22
|
+
accept: 'Accept invitation'
|
|
23
|
+
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."
|
|
@@ -29,18 +29,23 @@ module Devise
|
|
|
29
29
|
|
|
30
30
|
included do
|
|
31
31
|
include ::DeviseInvitable::Inviter
|
|
32
|
-
if Devise.invited_by_class_name
|
|
33
|
-
|
|
32
|
+
belongs_to_options = if Devise.invited_by_class_name
|
|
33
|
+
{:class_name => Devise.invited_by_class_name}
|
|
34
34
|
else
|
|
35
|
-
|
|
35
|
+
{:polymorphic => true}
|
|
36
36
|
end
|
|
37
|
+
if defined?(ActiveRecord) && defined?(ActiveRecord::Base) && self < ActiveRecord::Base
|
|
38
|
+
counter_cache = Devise.invited_by_counter_cache
|
|
39
|
+
belongs_to_options.merge! :counter_cache => counter_cache if counter_cache
|
|
40
|
+
end
|
|
41
|
+
belongs_to :invited_by, belongs_to_options
|
|
37
42
|
|
|
38
43
|
include ActiveSupport::Callbacks
|
|
39
44
|
define_callbacks :invitation_accepted
|
|
40
45
|
|
|
41
46
|
attr_writer :skip_password
|
|
42
47
|
|
|
43
|
-
scope :
|
|
48
|
+
scope :no_active_invitation, lambda { where(:invitation_token => nil) }
|
|
44
49
|
if defined?(Mongoid) && defined?(Mongoid::Document) && self < Mongoid::Document
|
|
45
50
|
scope :invitation_not_accepted, lambda { where(:invitation_accepted_at => nil, :invitation_token.ne => nil) }
|
|
46
51
|
scope :invitation_accepted, lambda { where(:invitation_accepted_at.ne => nil) }
|
|
@@ -57,9 +62,8 @@ module Devise
|
|
|
57
62
|
def self.required_fields(klass)
|
|
58
63
|
fields = [:invitation_token, :invitation_created_at, :invitation_sent_at, :invitation_accepted_at,
|
|
59
64
|
:invitation_limit, :invited_by_id, :invited_by_type]
|
|
60
|
-
if
|
|
61
|
-
|
|
62
|
-
end
|
|
65
|
+
fields << :invitations_count if defined?(ActiveRecord) && self < ActiveRecord::Base
|
|
66
|
+
fields -= [:invited_by_type] if Devise.invited_by_class_name
|
|
63
67
|
fields
|
|
64
68
|
end
|
|
65
69
|
|
|
@@ -81,12 +85,6 @@ module Devise
|
|
|
81
85
|
end
|
|
82
86
|
end
|
|
83
87
|
|
|
84
|
-
# Verifies whether a user has accepted an invitation (or is accepting it), or was never invited
|
|
85
|
-
def accepting_or_not_invited?
|
|
86
|
-
ActiveSupport::Deprecation.warn "accepting_or_not_invited? is deprecated and will be removed from DeviseInvitable 1.1.0 (use accepted_or_not_invited? instead)"
|
|
87
|
-
accepted_or_not_invited?
|
|
88
|
-
end
|
|
89
|
-
|
|
90
88
|
# Verifies whether a user has been invited or not
|
|
91
89
|
def invited_to_sign_up?
|
|
92
90
|
persisted? && invitation_token.present?
|
|
@@ -112,7 +110,8 @@ module Devise
|
|
|
112
110
|
def self.confirmation_required?; false; end
|
|
113
111
|
end
|
|
114
112
|
|
|
115
|
-
|
|
113
|
+
yield self if block_given?
|
|
114
|
+
generate_invitation_token if self.invitation_token.nil? || (!@skip_invitation || @raw_invitation_token.nil?)
|
|
116
115
|
self.invitation_created_at = Time.now.utc
|
|
117
116
|
self.invitation_sent_at = self.invitation_created_at unless @skip_invitation
|
|
118
117
|
self.invited_by = invited_by if invited_by
|
|
@@ -135,10 +134,14 @@ module Devise
|
|
|
135
134
|
end
|
|
136
135
|
|
|
137
136
|
# Only verify password when is not invited
|
|
138
|
-
def
|
|
137
|
+
def active_for_authentication?
|
|
139
138
|
super unless invited_to_sign_up?
|
|
140
139
|
end
|
|
141
140
|
|
|
141
|
+
def inactive_message
|
|
142
|
+
invited_to_sign_up? ? :invited : super
|
|
143
|
+
end
|
|
144
|
+
|
|
142
145
|
def after_password_reset
|
|
143
146
|
super
|
|
144
147
|
accept_invitation! if invited_to_sign_up?
|
|
@@ -172,7 +175,7 @@ module Devise
|
|
|
172
175
|
!@skip_password && super
|
|
173
176
|
end
|
|
174
177
|
|
|
175
|
-
|
|
178
|
+
|
|
176
179
|
# Checks if the invitation for the user is within the limit time.
|
|
177
180
|
# We do this by calculating if the difference between today and the
|
|
178
181
|
# invitation sent date does not exceed the invite for time configured.
|
|
@@ -279,19 +282,11 @@ module Devise
|
|
|
279
282
|
invitation_token = Devise.token_generator.digest(self, :invitation_token, original_token)
|
|
280
283
|
|
|
281
284
|
invitable = find_or_initialize_with_error_by(:invitation_token, invitation_token)
|
|
282
|
-
if !invitable.persisted? && Devise.allow_insecure_token_lookup
|
|
283
|
-
invitable = find_or_initialize_with_error_by(:invitation_token, original_token)
|
|
284
|
-
end
|
|
285
285
|
invitable.errors.add(:invitation_token, :invalid) if invitable.invitation_token && invitable.persisted? && !invitable.valid_invitation?
|
|
286
286
|
invitable.invitation_token = original_token
|
|
287
287
|
invitable unless only_valid && invitable.errors.present?
|
|
288
288
|
end
|
|
289
289
|
|
|
290
|
-
# Generate a token checking if one does not already exist in the database.
|
|
291
|
-
def invitation_token
|
|
292
|
-
generate_token(:invitation_token)
|
|
293
|
-
end
|
|
294
|
-
|
|
295
290
|
# Callback convenience methods
|
|
296
291
|
def before_invitation_accepted(*args, &blk)
|
|
297
292
|
set_callback(:invitation_accepted, :before, *args, &blk)
|
|
@@ -7,12 +7,14 @@ module DeviseInvitable
|
|
|
7
7
|
|
|
8
8
|
# We use to_prepare instead of after_initialize here because Devise is a Rails engine; its
|
|
9
9
|
# mailer is reloaded like the rest of the user's app. Got to make sure that our mailer methods
|
|
10
|
-
# are included each time Devise
|
|
10
|
+
# are included each time Devise.mailer is (re)loaded.
|
|
11
11
|
config.to_prepare do
|
|
12
|
-
|
|
13
|
-
Devise
|
|
12
|
+
Devise.mailer.send :include, DeviseInvitable::Mailer
|
|
13
|
+
unless Devise.mailer.ancestors.include?(Devise::Mailers::Helpers)
|
|
14
|
+
Devise.mailer.send :include, Devise::Mailers::Helpers
|
|
15
|
+
end
|
|
14
16
|
end
|
|
15
|
-
# extend mapping with after_initialize
|
|
17
|
+
# extend mapping with after_initialize because it's not reloaded
|
|
16
18
|
config.after_initialize do
|
|
17
19
|
Devise::Mapping.send :include, DeviseInvitable::Mapping
|
|
18
20
|
Devise::ParameterSanitizer.send :include, DeviseInvitable::ParameterSanitizer
|
data/lib/devise_invitable.rb
CHANGED
|
@@ -61,6 +61,11 @@ module Devise
|
|
|
61
61
|
# the #invited_by association is declared to be polymorphic. (default: nil)
|
|
62
62
|
mattr_accessor :invited_by_class_name
|
|
63
63
|
@@invited_by_class_name = nil
|
|
64
|
+
|
|
65
|
+
# Public: The column name used for counter_cache column. If this is nil,
|
|
66
|
+
# the #invited_by association is declared without counter_cache. (default: nil)
|
|
67
|
+
mattr_accessor :invited_by_counter_cache
|
|
68
|
+
@@invited_by_counter_cache = nil
|
|
64
69
|
end
|
|
65
70
|
|
|
66
71
|
Devise.add_module :invitable, :controller => :invitations, :model => 'devise_invitable/model', :route => {:invitation => [nil, :new, :accept]}
|
|
@@ -6,7 +6,7 @@ module ActiveRecord
|
|
|
6
6
|
source_root File.expand_path("../templates", __FILE__)
|
|
7
7
|
|
|
8
8
|
def copy_devise_migration
|
|
9
|
-
migration_template "migration.rb", "db/migrate/devise_invitable_add_to_#{table_name}"
|
|
9
|
+
migration_template "migration.rb", "db/migrate/devise_invitable_add_to_#{table_name}.rb"
|
|
10
10
|
end
|
|
11
11
|
end
|
|
12
12
|
end
|
|
@@ -7,6 +7,8 @@ class DeviseInvitableAddTo<%= table_name.camelize %> < ActiveRecord::Migration
|
|
|
7
7
|
t.datetime :invitation_accepted_at
|
|
8
8
|
t.integer :invitation_limit
|
|
9
9
|
t.references :invited_by, :polymorphic => true
|
|
10
|
+
t.integer :invitations_count, default: 0
|
|
11
|
+
t.index :invitations_count
|
|
10
12
|
t.index :invitation_token, :unique => true # for invitable
|
|
11
13
|
t.index :invited_by_id
|
|
12
14
|
end
|
|
@@ -21,7 +23,11 @@ class DeviseInvitableAddTo<%= table_name.camelize %> < ActiveRecord::Migration
|
|
|
21
23
|
def down
|
|
22
24
|
change_table :<%= table_name %> do |t|
|
|
23
25
|
t.remove_references :invited_by, :polymorphic => true
|
|
24
|
-
t.remove :invitation_limit, :invitation_sent_at, :invitation_accepted_at, :invitation_token, :invitation_created_at
|
|
26
|
+
t.remove :invitations_count, :invitation_limit, :invitation_sent_at, :invitation_accepted_at, :invitation_token, :invitation_created_at
|
|
25
27
|
end
|
|
28
|
+
change_column_null :<%= table_name %>, :encrypted_password, false
|
|
29
|
+
<% if class_name.constantize.columns_hash['password_salt'] -%>
|
|
30
|
+
change_column_null :<%= table_name %>, :password_salt,false
|
|
31
|
+
<% end -%>
|
|
26
32
|
end
|
|
27
33
|
end
|
|
@@ -43,6 +43,20 @@ module DeviseInvitable
|
|
|
43
43
|
# Default: false
|
|
44
44
|
# config.validate_on_invite = true
|
|
45
45
|
|
|
46
|
+
# Resend invitation if user with invited status is invited again
|
|
47
|
+
# Default: true
|
|
48
|
+
# config.resend_invitation = false
|
|
49
|
+
|
|
50
|
+
# The class name of the inviting model. If this is nil,
|
|
51
|
+
# the #invited_by association is declared to be polymorphic.
|
|
52
|
+
# Default: nil
|
|
53
|
+
# config.invited_by_class_name = 'User'
|
|
54
|
+
|
|
55
|
+
# The column name used for counter_cache column. If this is nil,
|
|
56
|
+
# the #invited_by association is declared without counter_cache.
|
|
57
|
+
# Default: nil
|
|
58
|
+
# config.invited_by_counter_cache = :invitations_count
|
|
59
|
+
|
|
46
60
|
CONTENT
|
|
47
61
|
end
|
|
48
62
|
end
|
|
@@ -25,7 +25,7 @@ class DeviseInvitable::RegistrationsControllerTest < ActionController::TestCase
|
|
|
25
25
|
sign_out @issuer
|
|
26
26
|
|
|
27
27
|
@invitee = User.where(:email => invitee_email).first
|
|
28
|
-
|
|
28
|
+
assert @invitee.encrypted_password.blank?, "the password should be unset"
|
|
29
29
|
|
|
30
30
|
# sign_up the invitee
|
|
31
31
|
assert_difference('ActionMailer::Base.deliveries.size') do
|
|
@@ -42,13 +42,13 @@ class DeviseInvitable::RegistrationsControllerTest < ActionController::TestCase
|
|
|
42
42
|
@invitee.save!
|
|
43
43
|
end
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
assert @invitee.encrypted_password.present?
|
|
46
46
|
assert_not_nil @invitee.invitation_accepted_at
|
|
47
47
|
assert_nil @invitee.invitation_token
|
|
48
|
-
|
|
49
|
-
|
|
48
|
+
assert @invitee.invited_by_id.present?
|
|
49
|
+
assert @invitee.invited_by_type.present?
|
|
50
50
|
assert !@invitee.confirmed?
|
|
51
|
-
|
|
51
|
+
assert @invitee.confirmation_token.present?
|
|
52
52
|
end
|
|
53
53
|
|
|
54
54
|
test "not invitable resources can register" do
|
|
@@ -58,7 +58,7 @@ class DeviseInvitable::RegistrationsControllerTest < ActionController::TestCase
|
|
|
58
58
|
post :create, :admin => {:email => invitee_email, :password => "1password"}
|
|
59
59
|
|
|
60
60
|
@invitee = Admin.where(:email => invitee_email).first
|
|
61
|
-
|
|
61
|
+
assert @invitee.encrypted_password.present?
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
test "missing params on a create should not cause an error" do
|
data/test/generators_test.rb
CHANGED
|
@@ -17,18 +17,18 @@ 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)
|
|
21
|
-
assert @output.match(%r|create
|
|
20
|
+
assert @output.match(%r{(inject|insert).* config/initializers/devise\.rb\n})
|
|
21
|
+
assert @output.match(%r|create.* config/locales/devise_invitable\.en\.yml\n|)
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
test "rails g devise_invitable Octopussy" do
|
|
25
25
|
@output = `cd #{RAILS_APP_PATH} && rails g devise_invitable Octopussy -p`
|
|
26
|
-
assert @output.match(%r{(inject|insert)
|
|
27
|
-
assert @output.match(%r|invoke
|
|
26
|
+
assert @output.match(%r{(inject|insert).* app/models/octopussy\.rb\n})
|
|
27
|
+
assert @output.match(%r|invoke.* #{DEVISE_ORM}\n|)
|
|
28
28
|
if DEVISE_ORM == :active_record
|
|
29
|
-
assert @output.match(%r|create
|
|
29
|
+
assert @output.match(%r|create.* db/migrate/\d{14}_devise_invitable_add_to_octopussies\.rb\n|)
|
|
30
30
|
elsif DEVISE_ORM == :mongoid
|
|
31
|
-
assert !@output.match(%r|create
|
|
31
|
+
assert !@output.match(%r|create.* db/migrate/\d{14}_devise_invitable_add_to_octopussies\.rb\n|)
|
|
32
32
|
end
|
|
33
33
|
end
|
|
34
34
|
end
|
|
@@ -80,7 +80,7 @@ class InvitationTest < ActionDispatch::IntegrationTest
|
|
|
80
80
|
end
|
|
81
81
|
assert_equal user_invitation_path, current_path
|
|
82
82
|
assert page.has_css?('#error_explanation li', :text => /Password .*doesn\'t match/)
|
|
83
|
-
|
|
83
|
+
assert user.encrypted_password.blank?
|
|
84
84
|
end
|
|
85
85
|
|
|
86
86
|
test 'not authenticated user with valid data should be able to change his password' do
|
|
@@ -99,7 +99,7 @@ class InvitationTest < ActionDispatch::IntegrationTest
|
|
|
99
99
|
end
|
|
100
100
|
assert_equal user_invitation_path, current_path
|
|
101
101
|
assert page.has_css?('#error_explanation')
|
|
102
|
-
|
|
102
|
+
assert user.encrypted_password.blank?
|
|
103
103
|
|
|
104
104
|
set_password :visit => false
|
|
105
105
|
assert page.has_css?('p#notice', :text => 'Your password was set successfully. You are now signed in.')
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
class
|
|
1
|
+
class ActionDispatch::IntegrationTest
|
|
2
2
|
|
|
3
3
|
def warden
|
|
4
4
|
request.env['warden']
|
|
5
5
|
end
|
|
6
|
-
|
|
6
|
+
|
|
7
7
|
def create_full_user
|
|
8
8
|
@user ||= begin
|
|
9
9
|
user = User.create!(
|
|
@@ -24,7 +24,7 @@ class ActionController::IntegrationTest
|
|
|
24
24
|
visit send("new_#{resource_name}_session_path")
|
|
25
25
|
fill_in "#{resource_name}_email", :with => user.email
|
|
26
26
|
fill_in "#{resource_name}_password", :with => user.password
|
|
27
|
-
click_button '
|
|
27
|
+
click_button 'Log in'
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
# Fix assert_redirect_to in integration sessions because they don't take into
|
|
@@ -11,6 +11,16 @@ class InvitableTest < ActiveSupport::TestCase
|
|
|
11
11
|
assert_nil new_user.invitation_token
|
|
12
12
|
end
|
|
13
13
|
|
|
14
|
+
test 'should update the invitations count counter cache' do
|
|
15
|
+
if defined?(ActiveRecord)
|
|
16
|
+
current_user = new_user
|
|
17
|
+
2.times do |index|
|
|
18
|
+
User.invite!({:email => "valid#{index}@email.com"}, current_user)
|
|
19
|
+
end
|
|
20
|
+
assert_equal current_user.reload.invitations_count, 2
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
14
24
|
test 'should not generate the raw invitation token after creating a record' do
|
|
15
25
|
assert_nil new_user.raw_invitation_token
|
|
16
26
|
end
|
|
@@ -18,14 +28,40 @@ class InvitableTest < ActiveSupport::TestCase
|
|
|
18
28
|
test 'should regenerate invitation token each time' do
|
|
19
29
|
user = new_user
|
|
20
30
|
user.invite!
|
|
21
|
-
|
|
31
|
+
|
|
22
32
|
assert_not_nil user.invitation_token
|
|
33
|
+
assert_not_nil user.raw_invitation_token
|
|
23
34
|
assert_not_nil user.invitation_created_at
|
|
35
|
+
|
|
24
36
|
3.times do
|
|
25
37
|
user = User.find(user.id)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
|
|
39
|
+
assert_not_same user.invitation_token, lambda {
|
|
40
|
+
user.invite!
|
|
41
|
+
user.invitation_token
|
|
42
|
+
}.call
|
|
43
|
+
assert_not_nil user.raw_invitation_token
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
test 'should regenerate invitation token each time even if "skip_invitation" was true' do
|
|
48
|
+
user = new_user
|
|
49
|
+
user.skip_invitation = true
|
|
50
|
+
user.invite!
|
|
51
|
+
|
|
52
|
+
assert_not_nil user.invitation_token
|
|
53
|
+
assert_not_nil user.invitation_created_at
|
|
54
|
+
|
|
55
|
+
3.times do
|
|
56
|
+
user = User.find(user.id)
|
|
57
|
+
user.skip_invitation = true
|
|
58
|
+
|
|
59
|
+
assert_not_same user.invitation_token, lambda {
|
|
60
|
+
user.invite!
|
|
61
|
+
user.invitation_token
|
|
62
|
+
}.call
|
|
63
|
+
assert_not_nil user.invitation_token
|
|
64
|
+
assert_not_nil user.raw_invitation_token
|
|
29
65
|
end
|
|
30
66
|
end
|
|
31
67
|
|
|
@@ -147,21 +183,21 @@ class InvitableTest < ActiveSupport::TestCase
|
|
|
147
183
|
|
|
148
184
|
test 'should clear invitation token and set invitation_accepted_at while accepting the password' do
|
|
149
185
|
user = User.invite!(:email => "valid@email.com")
|
|
150
|
-
|
|
186
|
+
assert user.invitation_token.present?
|
|
151
187
|
assert_nil user.invitation_accepted_at
|
|
152
188
|
user.accept_invitation!
|
|
153
189
|
user.reload
|
|
154
190
|
assert_nil user.invitation_token
|
|
155
|
-
|
|
191
|
+
assert user.invitation_accepted_at.present?
|
|
156
192
|
end
|
|
157
193
|
|
|
158
194
|
test 'should not clear invitation token or set accepted_at if record is invalid' do
|
|
159
195
|
user = User.invite!(:email => "valid@email.com")
|
|
160
|
-
|
|
196
|
+
assert user.invitation_token.present?
|
|
161
197
|
assert_nil user.invitation_accepted_at
|
|
162
198
|
User.accept_invitation!(:invitation_token => user.invitation_token, :password => '123456789', :password_confirmation => '987654321')
|
|
163
199
|
user.reload
|
|
164
|
-
|
|
200
|
+
assert user.invitation_token.present?
|
|
165
201
|
assert_nil user.invitation_accepted_at
|
|
166
202
|
end
|
|
167
203
|
|
|
@@ -172,8 +208,8 @@ class InvitableTest < ActiveSupport::TestCase
|
|
|
172
208
|
user.reset_password_sent_at = Time.now.utc
|
|
173
209
|
user.save
|
|
174
210
|
|
|
175
|
-
|
|
176
|
-
|
|
211
|
+
assert user.reset_password_token.present?
|
|
212
|
+
assert user.invitation_token.present?
|
|
177
213
|
User.reset_password_by_token(:reset_password_token => token, :password => '123456789', :password_confirmation => '123456789')
|
|
178
214
|
assert_nil user.reload.reset_password_token
|
|
179
215
|
assert_nil user.reload.invitation_token
|
|
@@ -187,11 +223,11 @@ class InvitableTest < ActiveSupport::TestCase
|
|
|
187
223
|
user.reset_password_sent_at = Time.now.utc
|
|
188
224
|
user.save
|
|
189
225
|
|
|
190
|
-
|
|
191
|
-
|
|
226
|
+
assert user.reset_password_token.present?
|
|
227
|
+
assert user.invitation_token.present?
|
|
192
228
|
User.reset_password_by_token(:reset_password_token => token, :password => '123456789', :password_confirmation => '12345678')
|
|
193
|
-
|
|
194
|
-
|
|
229
|
+
assert user.reload.reset_password_token.present?
|
|
230
|
+
assert user.reload.invitation_token.present?
|
|
195
231
|
assert user.invited_to_sign_up?
|
|
196
232
|
end
|
|
197
233
|
|
|
@@ -202,7 +238,7 @@ class InvitableTest < ActiveSupport::TestCase
|
|
|
202
238
|
user.reset_password_sent_at = Time.now.utc
|
|
203
239
|
user.save
|
|
204
240
|
|
|
205
|
-
|
|
241
|
+
assert user.reset_password_token.present?
|
|
206
242
|
assert_nil user.invitation_token
|
|
207
243
|
User.reset_password_by_token(:reset_password_token => token, :password => '123456789', :password_confirmation => '123456789')
|
|
208
244
|
assert_nil user.reload.invitation_token
|
|
@@ -221,7 +257,7 @@ class InvitableTest < ActiveSupport::TestCase
|
|
|
221
257
|
test 'should return a record with invitation token and no errors to send invitation by email' do
|
|
222
258
|
invited_user = User.invite!(:email => "valid@email.com")
|
|
223
259
|
assert invited_user.errors.blank?
|
|
224
|
-
|
|
260
|
+
assert invited_user.invitation_token.present?
|
|
225
261
|
assert_equal 'valid@email.com', invited_user.email
|
|
226
262
|
assert invited_user.persisted?
|
|
227
263
|
end
|
|
@@ -462,7 +498,18 @@ class InvitableTest < ActiveSupport::TestCase
|
|
|
462
498
|
assert_no_difference('ActionMailer::Base.deliveries.size') do
|
|
463
499
|
user.invite!
|
|
464
500
|
end
|
|
465
|
-
|
|
501
|
+
assert user.invitation_created_at.present?
|
|
502
|
+
assert_nil user.invitation_sent_at
|
|
503
|
+
end
|
|
504
|
+
|
|
505
|
+
test 'user.invite! should not send an invitation if we want to skip the invitation with block' do
|
|
506
|
+
user = new_user
|
|
507
|
+
assert_no_difference('ActionMailer::Base.deliveries.size') do
|
|
508
|
+
user.invite! do |u|
|
|
509
|
+
u.skip_invitation = true
|
|
510
|
+
end
|
|
511
|
+
end
|
|
512
|
+
assert user.invitation_created_at.present?
|
|
466
513
|
assert_nil user.invitation_sent_at
|
|
467
514
|
end
|
|
468
515
|
|
|
@@ -538,13 +585,13 @@ class InvitableTest < ActiveSupport::TestCase
|
|
|
538
585
|
|
|
539
586
|
test 'should pass validation before accept if field is required in post-invited instance' do
|
|
540
587
|
user = User.invite!(:email => "valid@email.com")
|
|
541
|
-
user.
|
|
588
|
+
user.testing_accepted_or_not_invited = true
|
|
542
589
|
assert_equal true, user.valid?
|
|
543
590
|
end
|
|
544
591
|
|
|
545
592
|
test 'should fail validation after accept if field is required in post-invited instance' do
|
|
546
593
|
user = User.invite!(:email => "valid@email.com")
|
|
547
|
-
user.
|
|
594
|
+
user.testing_accepted_or_not_invited = true
|
|
548
595
|
user.accept_invitation!
|
|
549
596
|
assert_equal false, user.valid?
|
|
550
597
|
end
|
|
@@ -552,7 +599,7 @@ class InvitableTest < ActiveSupport::TestCase
|
|
|
552
599
|
test 'should pass validation after accept if field is required in post-invited instance' do
|
|
553
600
|
user = User.invite!(:email => "valid@email.com")
|
|
554
601
|
user.username = 'test'
|
|
555
|
-
user.
|
|
602
|
+
user.testing_accepted_or_not_invited = true
|
|
556
603
|
user.bio = "Test"
|
|
557
604
|
user.accept_invitation!
|
|
558
605
|
assert_equal true, user.valid?
|
|
@@ -39,12 +39,12 @@ class User < PARENT_MODEL_CLASS
|
|
|
39
39
|
attr_accessor :callback_works, :bio, :token
|
|
40
40
|
validates :username, :length => { :maximum => 20 }
|
|
41
41
|
|
|
42
|
-
attr_accessor :
|
|
43
|
-
validates :username, :presence => true, :if => :
|
|
42
|
+
attr_accessor :testing_accepted_or_not_invited
|
|
43
|
+
validates :username, :presence => true, :if => :testing_accepted_or_not_invited_validator?
|
|
44
44
|
validates :bio, :presence => true, :if => :invitation_accepted?
|
|
45
45
|
|
|
46
|
-
def
|
|
47
|
-
|
|
46
|
+
def testing_accepted_or_not_invited_validator?
|
|
47
|
+
testing_accepted_or_not_invited && accepted_or_not_invited?
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
after_invitation_accepted do |object|
|
|
@@ -90,6 +90,45 @@ Devise.setup do |config|
|
|
|
90
90
|
# Setup a pepper to generate the encrypted password.
|
|
91
91
|
# config.pepper = "e31589192aeea8807cb7d8686b0f8484d6cbfaaa65443d45144519ed1d4ffbc6ccb73b21a69ece276d94f2cac95d83990d824f36f301d6f585ededd1bf90d67d"
|
|
92
92
|
|
|
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.
|
|
96
|
+
# When invite_for is 0 (the default), the invitation won't expire.
|
|
97
|
+
# config.invite_for = 2.weeks
|
|
98
|
+
|
|
99
|
+
# Number of invitations users can send.
|
|
100
|
+
# - If invitation_limit is nil, there is no limit for invitations, users can
|
|
101
|
+
# send unlimited invitations, invitation_limit column is not used.
|
|
102
|
+
# - If invitation_limit is 0, users can't send invitations by default.
|
|
103
|
+
# - If invitation_limit n > 0, users can send n invitations.
|
|
104
|
+
# You can change invitation_limit column for some users so they can send more
|
|
105
|
+
# or less invitations, even with global invitation_limit = 0
|
|
106
|
+
# Default: nil
|
|
107
|
+
# config.invitation_limit = 5
|
|
108
|
+
|
|
109
|
+
# The key to be used to check existing users when sending an invitation
|
|
110
|
+
# and the regexp used to test it when validate_on_invite is not set.
|
|
111
|
+
# config.invite_key = {:email => /\\A[^@]+@[^@]+\\z/}
|
|
112
|
+
# config.invite_key = {:email => /\\A[^@]+@[^@]+\\z/, :username => nil}
|
|
113
|
+
|
|
114
|
+
# Flag that force a record to be valid before being actually invited
|
|
115
|
+
# Default: false
|
|
116
|
+
# config.validate_on_invite = true
|
|
117
|
+
|
|
118
|
+
# Resend invitation if user with invited status is invited again
|
|
119
|
+
# Default: true
|
|
120
|
+
# config.resend_invitation = false
|
|
121
|
+
|
|
122
|
+
# The class name of the inviting model. If this is nil,
|
|
123
|
+
# the #invited_by association is declared to be polymorphic.
|
|
124
|
+
# Default: nil
|
|
125
|
+
# config.invited_by_class_name = 'User'
|
|
126
|
+
|
|
127
|
+
# The column name used for counter_cache column. If this is nil,
|
|
128
|
+
# the #invited_by association is declared without counter_cache.
|
|
129
|
+
# Default: nil
|
|
130
|
+
config.invited_by_counter_cache = :invitations_count
|
|
131
|
+
|
|
93
132
|
# ==> Configuration for :confirmable
|
|
94
133
|
# A period that the user is allowed to access the website even without
|
|
95
134
|
# confirming his account. For instance, if set to 2.days, the user will be
|
|
@@ -27,15 +27,20 @@ class CreateTables < ActiveRecord::Migration
|
|
|
27
27
|
t.integer :invitation_limit
|
|
28
28
|
t.integer :invited_by_id
|
|
29
29
|
t.string :invited_by_type
|
|
30
|
+
t.integer :invitations_count, :default => 0
|
|
30
31
|
|
|
31
32
|
t.timestamps
|
|
32
33
|
end
|
|
33
34
|
add_index :users, :invitation_token, :unique => true
|
|
35
|
+
add_index :users, :invitations_count
|
|
34
36
|
|
|
35
37
|
create_table :admins do |t|
|
|
36
38
|
## Database authenticatable
|
|
37
39
|
t.string :email, :null => true, :default => ""
|
|
38
40
|
t.string :encrypted_password, :null => true, :default => ""
|
|
41
|
+
|
|
42
|
+
t.integer :invitations_count, :default => 0
|
|
39
43
|
end
|
|
44
|
+
add_index :admins, :invitations_count
|
|
40
45
|
end
|
|
41
46
|
end
|
metadata
CHANGED
|
@@ -1,38 +1,34 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: devise_invitable
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
5
|
-
prerelease:
|
|
4
|
+
version: 1.4.0
|
|
6
5
|
platform: ruby
|
|
7
6
|
authors:
|
|
8
7
|
- Sergio Cambra
|
|
9
8
|
autorequire:
|
|
10
9
|
bindir: bin
|
|
11
10
|
cert_chain: []
|
|
12
|
-
date: 2014-
|
|
11
|
+
date: 2014-10-21 00:00:00.000000000 Z
|
|
13
12
|
dependencies:
|
|
14
13
|
- !ruby/object:Gem::Dependency
|
|
15
14
|
name: bundler
|
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
|
17
|
-
none: false
|
|
18
16
|
requirements:
|
|
19
|
-
- -
|
|
17
|
+
- - '>='
|
|
20
18
|
- !ruby/object:Gem::Version
|
|
21
19
|
version: 1.1.0
|
|
22
20
|
type: :development
|
|
23
21
|
prerelease: false
|
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
25
|
-
none: false
|
|
26
23
|
requirements:
|
|
27
|
-
- -
|
|
24
|
+
- - '>='
|
|
28
25
|
- !ruby/object:Gem::Version
|
|
29
26
|
version: 1.1.0
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
|
31
28
|
name: actionmailer
|
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
|
33
|
-
none: false
|
|
34
30
|
requirements:
|
|
35
|
-
- -
|
|
31
|
+
- - '>='
|
|
36
32
|
- !ruby/object:Gem::Version
|
|
37
33
|
version: 3.2.6
|
|
38
34
|
- - <
|
|
@@ -41,9 +37,8 @@ dependencies:
|
|
|
41
37
|
type: :runtime
|
|
42
38
|
prerelease: false
|
|
43
39
|
version_requirements: !ruby/object:Gem::Requirement
|
|
44
|
-
none: false
|
|
45
40
|
requirements:
|
|
46
|
-
- -
|
|
41
|
+
- - '>='
|
|
47
42
|
- !ruby/object:Gem::Version
|
|
48
43
|
version: 3.2.6
|
|
49
44
|
- - <
|
|
@@ -52,19 +47,17 @@ dependencies:
|
|
|
52
47
|
- !ruby/object:Gem::Dependency
|
|
53
48
|
name: devise
|
|
54
49
|
requirement: !ruby/object:Gem::Requirement
|
|
55
|
-
none: false
|
|
56
50
|
requirements:
|
|
57
|
-
- -
|
|
51
|
+
- - '>='
|
|
58
52
|
- !ruby/object:Gem::Version
|
|
59
|
-
version: 3.
|
|
53
|
+
version: 3.2.0
|
|
60
54
|
type: :runtime
|
|
61
55
|
prerelease: false
|
|
62
56
|
version_requirements: !ruby/object:Gem::Requirement
|
|
63
|
-
none: false
|
|
64
57
|
requirements:
|
|
65
|
-
- -
|
|
58
|
+
- - '>='
|
|
66
59
|
- !ruby/object:Gem::Version
|
|
67
|
-
version: 3.
|
|
60
|
+
version: 3.2.0
|
|
68
61
|
description: It adds support for send invitations by email (it requires to be authenticated)
|
|
69
62
|
and accept the invitation by setting a password.
|
|
70
63
|
email:
|
|
@@ -154,6 +147,7 @@ files:
|
|
|
154
147
|
homepage: https://github.com/scambra/devise_invitable
|
|
155
148
|
licenses:
|
|
156
149
|
- MIT
|
|
150
|
+
metadata: {}
|
|
157
151
|
post_install_message:
|
|
158
152
|
rdoc_options:
|
|
159
153
|
- --main
|
|
@@ -162,22 +156,20 @@ rdoc_options:
|
|
|
162
156
|
require_paths:
|
|
163
157
|
- lib
|
|
164
158
|
required_ruby_version: !ruby/object:Gem::Requirement
|
|
165
|
-
none: false
|
|
166
159
|
requirements:
|
|
167
|
-
- -
|
|
160
|
+
- - '>='
|
|
168
161
|
- !ruby/object:Gem::Version
|
|
169
162
|
version: 1.8.6
|
|
170
163
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
171
|
-
none: false
|
|
172
164
|
requirements:
|
|
173
|
-
- -
|
|
165
|
+
- - '>='
|
|
174
166
|
- !ruby/object:Gem::Version
|
|
175
167
|
version: 1.3.6
|
|
176
168
|
requirements: []
|
|
177
169
|
rubyforge_project:
|
|
178
|
-
rubygems_version: 1.
|
|
170
|
+
rubygems_version: 2.1.11
|
|
179
171
|
signing_key:
|
|
180
|
-
specification_version:
|
|
172
|
+
specification_version: 4
|
|
181
173
|
summary: An invitation strategy for Devise
|
|
182
174
|
test_files:
|
|
183
175
|
- test/functional/controller_helpers_test.rb
|