devise_invitable 1.1.5 → 1.1.6

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.

data/README.rdoc CHANGED
@@ -14,7 +14,7 @@ Install DeviseInvitable gem, it will also install dependencies (such as devise a
14
14
  Add DeviseInvitable to your Gemfile (and Devise if you weren't using them):
15
15
 
16
16
  gem 'devise', '>= 2.0.0'
17
- gem 'devise_invitable', '~> 1.0.0'
17
+ gem 'devise_invitable', '~> 1.1.0'
18
18
 
19
19
  === Automatic installation
20
20
 
@@ -67,8 +67,6 @@ or for a model that already exists, define a migration to add DeviseInvitable to
67
67
 
68
68
  # Allow null encrypted_password
69
69
  change_column :users, :encrypted_password, :string, :null => true
70
- # Allow null password_salt (add it if you are using Devise's encryptable module)
71
- change_column :users, :password_salt, :string, :null => true
72
70
 
73
71
  == Model configuration
74
72
 
@@ -230,7 +228,7 @@ If you want to get all records invited by a resource, you should define has_many
230
228
 
231
229
  For the default behavior, define it like this:
232
230
 
233
- has_many :invitations, :class_name => self.class.to_s, :as => :invited_by
231
+ has_many :invitations, :class_name => self.to_s, :as => :invited_by
234
232
 
235
233
  For the previous example, where admins send invitations to users, define it like this:
236
234
 
@@ -38,7 +38,8 @@ class Devise::InvitationsController < DeviseController
38
38
  self.resource = resource_class.accept_invitation!(resource_params)
39
39
 
40
40
  if resource.errors.empty?
41
- set_flash_message :notice, :updated
41
+ flash_message = resource.active_for_authentication? ? :updated : :updated_not_active
42
+ set_flash_message :notice, flash_message
42
43
  sign_in(resource_name, resource)
43
44
  respond_with resource, :location => after_accept_path_for(resource)
44
45
  else
@@ -0,0 +1,15 @@
1
+ class DeviseInvitable::RegistrationsController < Devise::RegistrationsController
2
+ protected
3
+
4
+ def build_resource(*args)
5
+ hash = args.pop || resource_params || {}
6
+ if hash[:email]
7
+ self.resource = resource_class.where(:email => hash[:email], :encrypted_password => '').first
8
+ if self.resource
9
+ self.resource.attributes = hash
10
+ self.resource.accept_invitation!
11
+ end
12
+ end
13
+ self.resource ||= super(hash, *args)
14
+ end
15
+ end
@@ -0,0 +1,65 @@
1
+ module DeviseInvitable
2
+ autoload :Inviter, 'devise_invitable/inviter'
3
+ autoload :Mailer, 'devise_invitable/mailer'
4
+ module Controllers
5
+ autoload :UrlHelpers, 'devise_invitable/controllers/url_helpers'
6
+ autoload :Registrations, 'devise_invitable/controllers/registrations'
7
+ autoload :Helpers, 'devise_invitable/controllers/helpers'
8
+ end
9
+ end
10
+
11
+ require 'devise'
12
+ require 'devise_invitable/routes'
13
+ require 'devise_invitable/rails'
14
+
15
+ module Devise
16
+ # Public: Validity period of the invitation token (default: 0). If
17
+ # invite_for is 0 or nil, the invitation will never expire.
18
+ # Set invite_for in the Devise configuration file (in config/initializers/devise.rb).
19
+ #
20
+ # config.invite_for = 2.weeks # => The invitation token will be valid 2 weeks
21
+ mattr_accessor :invite_for
22
+ @@invite_for = 0
23
+
24
+ # Public: Flag that force a record to be valid before being actually invited
25
+ # (default: false).
26
+ #
27
+ # Examples (in config/initializers/devise.rb)
28
+ #
29
+ # config.validate_on_invite = true
30
+ mattr_accessor :validate_on_invite
31
+ @@validate_on_invite = false
32
+
33
+ # Public: number of invitations the user is allowed to send
34
+ #
35
+ # Examples (in config/initializers/devise.rb)
36
+ #
37
+ # config.invitation_limit = nil
38
+ mattr_accessor :invitation_limit
39
+ @@invitation_limit = nil
40
+
41
+ # Public: The key to be used to check existing users when sending an invitation,
42
+ # and the regexp used to test it when validate_on_invite is not set.
43
+ #
44
+ # Examples (in config/initializers/devise.rb)
45
+ #
46
+ # config.invite_key = {:email => /\A[^@]+@[^@]+\z/}
47
+ mattr_accessor :invite_key
48
+ @@invite_key = {:email => Devise.email_regexp}
49
+
50
+ # Public: Resend invitation if user with invited status is invited again
51
+ # (default: true)
52
+ #
53
+ # Example (in config/initializers/devise.rb)
54
+ #
55
+ # config.resend_invitation = false
56
+ mattr_accessor :resend_invitation
57
+ @@resend_invitation = true
58
+
59
+ # Public: The class name of the inviting model. If this is nil,
60
+ # the #invited_by association is declared to be polymorphic. (default: nil)
61
+ mattr_accessor :invited_by_class_name
62
+ @@invited_by_class_name = nil
63
+ end
64
+
65
+ Devise.add_module :invitable, :controller => :invitations, :model => 'devise_invitable/model', :route => :invitation
@@ -0,0 +1,21 @@
1
+ module DeviseInvitable::Controllers::Helpers
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ hide_action :after_invite_path_for, :after_accept_path_for
6
+ end
7
+
8
+ def after_invite_path_for(resource)
9
+ after_sign_in_path_for(resource)
10
+ end
11
+
12
+ def after_accept_path_for(resource)
13
+ after_sign_in_path_for(resource)
14
+ end
15
+
16
+ protected
17
+ def authenticate_inviter!
18
+ send(:"authenticate_#{resource_name}!", :force => true)
19
+ end
20
+
21
+ end
@@ -0,0 +1,21 @@
1
+ module DeviseInvitable::Controllers::Registrations
2
+ def self.included(controller)
3
+ controller.alias_method_chain :build_resource, :invitation
4
+ end
5
+
6
+ protected
7
+
8
+ def build_resource_with_invitation(*args)
9
+ hash = args.pop || resource_params || {}
10
+ if hash[:email]
11
+ self.resource = resource_class.where(:email => hash[:email], :encrypted_password => '').first
12
+ if self.resource
13
+ puts self.resource.inspect
14
+ self.resource.attributes = hash
15
+ self.resource.accept_invitation!
16
+ puts self.resource.inspect
17
+ end
18
+ end
19
+ self.resource ||= build_resource_without_invitation(hash, *args)
20
+ end
21
+ end
@@ -218,7 +218,7 @@ module Devise
218
218
  invite_key_array = invite_key_fields
219
219
  attributes_hash = {}
220
220
  invite_key_array.each do |k,v|
221
- attributes_hash[k] = attributes.delete(k).try(:strip)
221
+ attributes_hash[k] = attributes.delete(k).to_s.strip
222
222
  end
223
223
 
224
224
  invitable = find_or_initialize_with_errors(invite_key_array, attributes_hash)
@@ -267,7 +267,7 @@ module Devise
267
267
  invitable = find_or_initialize_with_error_by(:invitation_token, attributes.delete(:invitation_token))
268
268
  invitable.errors.add(:invitation_token, :invalid) if invitable.invitation_token && invitable.persisted? && !invitable.valid_invitation?
269
269
  if invitable.errors.empty?
270
- invitable.attributes = attributes
270
+ invitable.assign_attributes(attributes, :as => inviter_role(self))
271
271
  invitable.accept_invitation!
272
272
  end
273
273
  invitable
@@ -0,0 +1,224 @@
1
+ require 'active_support/deprecation'
2
+
3
+ module Devise
4
+ module Models
5
+ # Invitable is responsible for sending invitation emails.
6
+ # When an invitation is sent to an email address, an account is created for it.
7
+ # Invitation email contains a link allowing the user to accept the invitation
8
+ # by setting a password (as reset password from Devise's recoverable module).
9
+ #
10
+ # Configuration:
11
+ #
12
+ # invite_for: The period the generated invitation token is valid, after
13
+ # this period, the invited resource won't be able to accept the invitation.
14
+ # When invite_for is 0 (the default), the invitation won't expire.
15
+ #
16
+ # Examples:
17
+ #
18
+ # User.find(1).invited_to_sign_up? # => true/false
19
+ # User.invite!(:email => 'someone@example.com') # => send invitation
20
+ # User.accept_invitation!(:invitation_token => '...') # => accept invitation with a token
21
+ # User.find(1).accept_invitation! # => accept invitation
22
+ # User.find(1).invite! # => reset invitation status and send invitation again
23
+ module Invitable
24
+ extend ActiveSupport::Concern
25
+
26
+ attr_accessor :skip_invitation
27
+ attr_accessor :completing_invite
28
+
29
+ included do
30
+ include ::DeviseInvitable::Inviter
31
+ belongs_to :invited_by, :polymorphic => true
32
+
33
+ include ActiveSupport::Callbacks
34
+ define_callbacks :invitation_accepted
35
+
36
+ attr_writer :skip_password
37
+ end
38
+
39
+ # Accept an invitation by clearing invitation token and and setting invitation_accepted_at
40
+ # Confirms it if model is confirmable
41
+ def accept_invitation!
42
+ self.completing_invite = true
43
+ if self.invited_to_sign_up? && self.valid?
44
+ run_callbacks :invitation_accepted do
45
+ self.invitation_token = nil
46
+ self.invitation_accepted_at = Time.now.utc if respond_to? :"invitation_accepted_at="
47
+ self.completing_invite = false
48
+ self.save(:validate => false)
49
+ end
50
+ end
51
+ end
52
+
53
+ # Verifies whether a user has accepted an invite, was never invited, or is in the process of accepting an invitation, or not
54
+ def accepting_or_not_invited?
55
+ !!completing_invite || invited_to_sign_up?
56
+ end
57
+
58
+ # Verifies whether a user has been invited or not
59
+ def invited_to_sign_up?
60
+ persisted? && invitation_token.present?
61
+ end
62
+
63
+ def invited?
64
+ invited_to_sign_up?
65
+ end
66
+ deprecate :invited?
67
+
68
+ # Reset invitation token and send invitation again
69
+ def invite!
70
+ was_invited = invited_to_sign_up?
71
+ self.skip_confirmation! if self.new_record? && self.respond_to?(:skip_confirmation!)
72
+ generate_invitation_token if self.invitation_token.nil?
73
+ self.invitation_sent_at = Time.now.utc
74
+
75
+ # Call these before_validate methods since we aren't validating on save
76
+ self.downcase_keys if self.new_record? && self.respond_to?(:downcase_keys)
77
+ self.strip_whitespace if self.new_record? && self.respond_to?(:strip_whitespace)
78
+
79
+ if save(:validate => false)
80
+ self.invited_by.decrement_invitation_limit! if !was_invited and self.invited_by.present?
81
+ deliver_invitation unless @skip_invitation
82
+ end
83
+ end
84
+
85
+ # Verify whether a invitation is active or not. If the user has been
86
+ # invited, we need to calculate if the invitation time has not expired
87
+ # for this user, in other words, if the invitation is still valid.
88
+ def valid_invitation?
89
+ invited_to_sign_up? && invitation_period_valid?
90
+ end
91
+
92
+ # Only verify password when is not invited
93
+ def valid_password?(password)
94
+ super unless invited_to_sign_up?
95
+ end
96
+
97
+ def reset_password!(new_password, new_password_confirmation)
98
+ super
99
+ accept_invitation!
100
+ end
101
+
102
+ protected
103
+ # Overriding the method in Devise's :validatable module so password is not required on inviting
104
+ def password_required?
105
+ !@skip_password && super
106
+ end
107
+
108
+ # Deliver the invitation email
109
+ def deliver_invitation
110
+ ::Devise.mailer.invitation_instructions(self).deliver
111
+ end
112
+
113
+ # Checks if the invitation for the user is within the limit time.
114
+ # We do this by calculating if the difference between today and the
115
+ # invitation sent date does not exceed the invite for time configured.
116
+ # Invite_for is a model configuration, must always be an integer value.
117
+ #
118
+ # Example:
119
+ #
120
+ # # invite_for = 1.day and invitation_sent_at = today
121
+ # invitation_period_valid? # returns true
122
+ #
123
+ # # invite_for = 5.days and invitation_sent_at = 4.days.ago
124
+ # invitation_period_valid? # returns true
125
+ #
126
+ # # invite_for = 5.days and invitation_sent_at = 5.days.ago
127
+ # invitation_period_valid? # returns false
128
+ #
129
+ # # invite_for = nil
130
+ # invitation_period_valid? # will always return true
131
+ #
132
+ def invitation_period_valid?
133
+ invitation_sent_at && (self.class.invite_for.to_i.zero? || invitation_sent_at.utc >= self.class.invite_for.ago)
134
+ end
135
+
136
+ # Generates a new random token for invitation, and stores the time
137
+ # this token is being generated
138
+ def generate_invitation_token
139
+ self.invitation_token = self.class.invitation_token
140
+ end
141
+
142
+ module ClassMethods
143
+ # Attempt to find a user by it's email. If a record is not found, create a new
144
+ # user and send invitation to it. If user is found, returns the user with an
145
+ # email already exists error.
146
+ # If user is found and still have pending invitation, email is resend unless
147
+ # resend_invitation is set to false
148
+ # Attributes must contain the user email, other attributes will be set in the record
149
+ def _invite(attributes={}, invited_by=nil, &block)
150
+ invitable = find_or_initialize_with_error_by(invite_key, attributes.delete(invite_key))
151
+ invitable.assign_attributes(attributes, :as => inviter_role(invited_by))
152
+ invitable.invited_by = invited_by
153
+
154
+ invitable.skip_password = true
155
+ invitable.valid? if self.validate_on_invite
156
+ if invitable.new_record?
157
+ invitable.errors.clear if !self.validate_on_invite and invitable.email.try(:match, Devise.email_regexp)
158
+ else
159
+ invitable.errors.add(invite_key, :taken) unless invitable.invited_to_sign_up? && self.resend_invitation
160
+ end
161
+
162
+ if invitable.errors.empty?
163
+ yield invitable if block_given?
164
+ mail = invitable.invite!
165
+ end
166
+ [invitable, mail]
167
+ end
168
+
169
+ # Override this method if the invitable is using Mass Assignment Security
170
+ # and the inviter has a non-default role.
171
+ def inviter_role(inviter)
172
+ :default
173
+ end
174
+
175
+ def invite!(attributes={}, invited_by=nil, &block)
176
+ invitable, mail = _invite(attributes, invited_by, &block)
177
+ invitable
178
+ end
179
+
180
+ def invite_mail!(attributes={}, invited_by=nil, &block)
181
+ invitable, mail = _invite(attributes, invited_by, &block)
182
+ mail
183
+ end
184
+
185
+ # Attempt to find a user by it's invitation_token to set it's password.
186
+ # If a user is found, reset it's password and automatically try saving
187
+ # the record. If not user is found, returns a new user containing an
188
+ # error in invitation_token attribute.
189
+ # Attributes must contain invitation_token, password and confirmation
190
+ def accept_invitation!(attributes={})
191
+ invitable = find_or_initialize_with_error_by(:invitation_token, attributes.delete(:invitation_token))
192
+ invitable.errors.add(:invitation_token, :invalid) if invitable.invitation_token && invitable.persisted? && !invitable.valid_invitation?
193
+ if invitable.errors.empty?
194
+ invitable.attributes = attributes
195
+ invitable.accept_invitation!
196
+ end
197
+ invitable
198
+ end
199
+
200
+ # Generate a token checking if one does not already exist in the database.
201
+ def invitation_token
202
+ generate_token(:invitation_token)
203
+ end
204
+
205
+ # Callback convenience methods
206
+ def before_invitation_accepted(*args, &blk)
207
+ set_callback(:invitation_accepted, :before, *args, &blk)
208
+ end
209
+
210
+ def after_invitation_accepted(*args, &blk)
211
+ set_callback(:invitation_accepted, :after, *args, &blk)
212
+ end
213
+
214
+
215
+ Devise::Models.config(self, :invite_for)
216
+ Devise::Models.config(self, :validate_on_invite)
217
+ Devise::Models.config(self, :invitation_limit)
218
+ Devise::Models.config(self, :invite_key)
219
+ Devise::Models.config(self, :resend_invitation)
220
+ end
221
+ end
222
+ end
223
+ end
224
+
@@ -0,0 +1,21 @@
1
+ module DeviseInvitable
2
+ class Engine < ::Rails::Engine
3
+
4
+ ActiveSupport.on_load(:action_controller) do
5
+ include DeviseInvitable::Controllers::UrlHelpers
6
+ include DeviseInvitable::Controllers::Helpers
7
+ end
8
+ ActiveSupport.on_load(:action_view) { include DeviseInvitable::Controllers::UrlHelpers }
9
+
10
+ # We use to_prepare instead of after_initialize here because Devise is a Rails engine; its
11
+ # mailer is reloaded like the rest of the user's app. Got to make sure that our mailer methods
12
+ # are included each time Devise::Mailer is (re)loaded.
13
+ config.to_prepare do
14
+ require 'devise/mailer'
15
+ Devise::Mailer.send :include, DeviseInvitable::Mailer
16
+ Devise::Mapping.send :include, DeviseInvitable::Mapping
17
+ end
18
+ config.after_initialize do
19
+ end
20
+ end
21
+ end
@@ -1,3 +1,3 @@
1
1
  module DeviseInvitable
2
- VERSION = '1.1.5'
2
+ VERSION = '1.1.6'
3
3
  end
@@ -36,8 +36,8 @@ module DeviseInvitable
36
36
 
37
37
  # The key to be used to check existing users when sending an invitation
38
38
  # and the regexp used to test it when validate_on_invite is not set.
39
- # config.invite_key = {:email => /\A[^@]+@[^@]+\z/}
40
- # config.invite_key = {:email => /\A[^@]+@[^@]+\z/, :username => nil}
39
+ # config.invite_key = {:email => /\\A[^@]+@[^@]+\\z/}
40
+ # config.invite_key = {:email => /\\A[^@]+@[^@]+\\z/, :username => nil}
41
41
 
42
42
  # Flag that force a record to be valid before being actually invited
43
43
  # Default: false
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: devise_invitable
3
3
  version: !ruby/object:Gem::Version
4
- hash: 25
4
+ hash: 31
5
5
  prerelease:
6
6
  segments:
7
7
  - 1
8
8
  - 1
9
- - 5
10
- version: 1.1.5
9
+ - 6
10
+ version: 1.1.6
11
11
  platform: ruby
12
12
  authors:
13
13
  - Sergio Cambra
@@ -15,10 +15,11 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2013-01-24 00:00:00 Z
18
+ date: 2013-02-21 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- type: :development
21
+ name: bundler
22
+ prerelease: false
22
23
  requirement: &id001 !ruby/object:Gem::Requirement
23
24
  none: false
24
25
  requirements:
@@ -30,27 +31,27 @@ dependencies:
30
31
  - 1
31
32
  - 0
32
33
  version: 1.1.0
34
+ type: :development
33
35
  version_requirements: *id001
34
- prerelease: false
35
- name: bundler
36
36
  - !ruby/object:Gem::Dependency
37
- type: :runtime
37
+ name: devise
38
+ prerelease: false
38
39
  requirement: &id002 !ruby/object:Gem::Requirement
39
40
  none: false
40
41
  requirements:
41
42
  - - ">="
42
43
  - !ruby/object:Gem::Version
43
- hash: 9
44
+ hash: 15
44
45
  segments:
45
46
  - 2
46
47
  - 1
47
- - 1
48
- version: 2.1.1
48
+ - 2
49
+ version: 2.1.2
50
+ type: :runtime
49
51
  version_requirements: *id002
50
- prerelease: false
51
- name: devise
52
52
  - !ruby/object:Gem::Dependency
53
- type: :runtime
53
+ name: railties
54
+ prerelease: false
54
55
  requirement: &id003 !ruby/object:Gem::Requirement
55
56
  none: false
56
57
  requirements:
@@ -61,11 +62,11 @@ dependencies:
61
62
  - 3
62
63
  - 0
63
64
  version: "3.0"
65
+ type: :runtime
64
66
  version_requirements: *id003
65
- prerelease: false
66
- name: actionmailer
67
67
  - !ruby/object:Gem::Dependency
68
- type: :runtime
68
+ name: actionmailer
69
+ prerelease: false
69
70
  requirement: &id004 !ruby/object:Gem::Requirement
70
71
  none: false
71
72
  requirements:
@@ -76,9 +77,8 @@ dependencies:
76
77
  - 3
77
78
  - 0
78
79
  version: "3.0"
80
+ type: :runtime
79
81
  version_requirements: *id004
80
- prerelease: false
81
- name: railties
82
82
  description: It adds support for send invitations by email (it requires to be authenticated) and accept the invitation by setting a password.
83
83
  email:
84
84
  - sergio@entrecables.com
@@ -91,28 +91,34 @@ extra_rdoc_files: []
91
91
  files:
92
92
  - app/controllers/devise/invitations_controller.rb
93
93
  - app/controllers/devise_invitable/registrations_controller.rb
94
- - app/views/devise/invitations/new.html.erb
94
+ - app/controllers/devise_invitable/registrations_controller.rb~
95
95
  - app/views/devise/invitations/edit.html.erb
96
+ - app/views/devise/invitations/new.html.erb
96
97
  - app/views/devise/mailer/invitation_instructions.html.erb
97
98
  - config/locales/en.yml
98
- - lib/generators/active_record/devise_invitable_generator.rb
99
- - lib/generators/active_record/templates/migration.rb
100
- - lib/generators/devise_invitable/install_generator.rb
101
- - lib/generators/devise_invitable/devise_invitable_generator.rb
102
- - lib/generators/devise_invitable/views_generator.rb
103
- - lib/generators/devise_invitable/templates/simple_form_for/invitations/new.html.erb
104
- - lib/generators/devise_invitable/templates/simple_form_for/invitations/edit.html.erb
105
- - lib/generators/mongoid/devise_invitable_generator.rb
106
99
  - lib/devise_invitable.rb
100
+ - lib/devise_invitable/mailer.rb
101
+ - lib/devise_invitable/model.rb
107
102
  - lib/devise_invitable/rails.rb
108
- - lib/devise_invitable/inviter.rb
109
- - lib/devise_invitable/mapping.rb
110
103
  - lib/devise_invitable/routes.rb
111
104
  - lib/devise_invitable/version.rb
112
- - lib/devise_invitable/mailer.rb
113
- - lib/devise_invitable/model.rb
114
105
  - lib/devise_invitable/controllers/helpers.rb
115
106
  - lib/devise_invitable/controllers/url_helpers.rb
107
+ - lib/devise_invitable/controllers/registrations.rb~
108
+ - lib/devise_invitable/controllers/helpers.rb~
109
+ - lib/devise_invitable/rails.rb~
110
+ - lib/devise_invitable/inviter.rb
111
+ - lib/devise_invitable/mapping.rb
112
+ - lib/devise_invitable/model.rb~
113
+ - lib/generators/active_record/devise_invitable_generator.rb
114
+ - lib/generators/active_record/templates/migration.rb
115
+ - lib/generators/devise_invitable/views_generator.rb
116
+ - lib/generators/devise_invitable/devise_invitable_generator.rb
117
+ - lib/generators/devise_invitable/install_generator.rb
118
+ - lib/generators/devise_invitable/templates/simple_form_for/invitations/edit.html.erb
119
+ - lib/generators/devise_invitable/templates/simple_form_for/invitations/new.html.erb
120
+ - lib/generators/mongoid/devise_invitable_generator.rb
121
+ - lib/devise_invitable.rb~
116
122
  - LICENSE
117
123
  - README.rdoc
118
124
  homepage: https://github.com/scambra/devise_invitable
@@ -150,7 +156,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
150
156
  requirements: []
151
157
 
152
158
  rubyforge_project:
153
- rubygems_version: 1.8.24
159
+ rubygems_version: 1.8.23
154
160
  signing_key:
155
161
  specification_version: 3
156
162
  summary: An invitation strategy for Devise