devise_invitable 0.3.1 → 0.3.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/README.rdoc +24 -13
- data/VERSION +1 -1
- data/app/controllers/devise/invitations_controller.rb +2 -2
- data/app/views/devise/mailer/invitation.html.erb +5 -5
- data/devise_invitable.gemspec +3 -3
- data/lib/devise_invitable/model.rb +23 -17
- data/lib/devise_invitable/rails.rb +2 -4
- data/lib/generators/devise_invitable/views_generator.rb +10 -0
- data/test/models/invitable_test.rb +27 -11
- metadata +5 -5
- data/init.rb +0 -1
data/Gemfile.lock
CHANGED
data/README.rdoc
CHANGED
@@ -2,21 +2,18 @@
|
|
2
2
|
|
3
3
|
It adds support to devise[http://github.com/plataformatec/devise] for send invitations by email (it requires to be authenticated) and accept the invitation setting the password.
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
All gems are on gemcutter, so you need to add gemcutter to your sources if you haven’t yet:
|
5
|
+
DeviseInvitable currently only support rails 3, if you want to use it with rails 2.3 you must install version 0.2.3
|
8
6
|
|
9
|
-
|
7
|
+
== Installation
|
10
8
|
|
11
9
|
Install devise_invitable gem, it should install dependencies (such as devise and warden):
|
12
10
|
|
13
11
|
sudo gem install devise_invitable
|
14
12
|
|
15
|
-
Configure devise_invitable inside your app (and
|
13
|
+
Configure devise_invitable inside your app (and devise if you weren't using them):
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
config.gem 'devise_invitable'
|
15
|
+
gem 'devise'
|
16
|
+
gem 'devise_invitable'
|
20
17
|
|
21
18
|
== Basic Usage
|
22
19
|
|
@@ -48,6 +45,12 @@ If you are using devise :all, you can add :invitable to config.all in devise ini
|
|
48
45
|
|
49
46
|
DeviseInvitable adds a new configuration option, :invite_for. It's the time a invitation is valid for. Default value is nil, which means invitation doesn't expire.
|
50
47
|
|
48
|
+
== Configuring views
|
49
|
+
|
50
|
+
All of the views are packaged inside the gem. If you'd like to customize the views, invoke the the following generator and it will copy all views to your application:
|
51
|
+
|
52
|
+
# rails generate devise_invitable:views
|
53
|
+
|
51
54
|
== Controller filters
|
52
55
|
|
53
56
|
It adds authenticate_resource! filter to restrict who can send invitations. You can override this method in your ApplicationController. Default behavior is require authentication of the same resource_name, so if you only have a model with devise it will allow to all authenticated users to send invitations.
|
@@ -56,19 +59,19 @@ You have to configure mailer as it's required for confirmable and recoverable.
|
|
56
59
|
|
57
60
|
== I18n
|
58
61
|
|
59
|
-
It uses two flash messages, :
|
62
|
+
It uses two flash messages, :send_instructions and :updated, which are translated as other flash messages from devise.
|
60
63
|
|
61
64
|
== Sending an invitation
|
62
65
|
|
63
|
-
To
|
66
|
+
To invite a user use invite class model. You must set email in the attributes hash:
|
64
67
|
|
65
|
-
User.
|
68
|
+
User.invite!(:email => 'new_user@example.com')
|
66
69
|
|
67
|
-
To accept an invitation with a token use accept_invitation! class model. You must set invitiation_token attribute, and you can include other
|
70
|
+
To accept an invitation with a token use accept_invitation! class model. You must set invitiation_token attribute, and you can include other attributes in the hash, which will be updated in the record.
|
68
71
|
|
69
72
|
User.accept_invitation!(:invitation_token => params[:invitation_token])
|
70
73
|
|
71
|
-
Invitations controller implement this. You can go to /users/invitation/new to send an invitation and an email will be sent with a link to accept
|
74
|
+
Invitations controller implement this. You can go to /users/invitation/new to send an invitation and an email will be sent with a link to accept the invitation with a URL like /users/invitation/accept?invitation_token=...
|
72
75
|
|
73
76
|
== Adding Invitable to a running application
|
74
77
|
|
@@ -88,6 +91,14 @@ Add :invitable to the devise line of your model, or to config.all in devise init
|
|
88
91
|
|
89
92
|
Override authenticate_resource! filter if you need to customize who can send invitations as it's explained in controller filters section.
|
90
93
|
|
94
|
+
== Contributors
|
95
|
+
|
96
|
+
Check them all at:
|
97
|
+
|
98
|
+
http://github.com/scambra/devise_invitable/contributors
|
99
|
+
|
100
|
+
Special thanks to http://github.com/rymai:"rymai" for rails3 support, his fork was a great help.
|
101
|
+
|
91
102
|
== Note on Patches/Pull Requests
|
92
103
|
|
93
104
|
* Fork the project.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.3.
|
1
|
+
0.3.2
|
@@ -13,11 +13,11 @@ class Devise::InvitationsController < ApplicationController
|
|
13
13
|
|
14
14
|
# POST /resource/invitation
|
15
15
|
def create
|
16
|
-
self.resource = resource_class.
|
16
|
+
self.resource = resource_class.invite!(params[resource_name])
|
17
17
|
|
18
18
|
if resource.errors.empty?
|
19
19
|
set_flash_message :notice, :send_instructions
|
20
|
-
redirect_to
|
20
|
+
redirect_to after_update_path_for(resource_name)
|
21
21
|
else
|
22
22
|
render_with_scope :new
|
23
23
|
end
|
@@ -1,8 +1,8 @@
|
|
1
|
-
Hello <%= @resource.email
|
1
|
+
<p>Hello <%= @resource.email %>!</p>
|
2
2
|
|
3
|
-
Someone has invited you to <%= root_url %>, you can accept it through the link below
|
3
|
+
<p>Someone has invited you to <%= root_url %>, you can accept it through the link below.</p>
|
4
4
|
|
5
|
-
|
5
|
+
<p><%= link_to 'Accept invitation', accept_invitation_url(@resource, :invitation_token => @resource.invitation_token) %></p>
|
6
6
|
|
7
|
-
If you don't want to accept the invitation, please ignore this email
|
8
|
-
Your account won't be created until you access the link above and set your password
|
7
|
+
<p>If you don't want to accept the invitation, please ignore this email.<br />
|
8
|
+
Your account won't be created until you access the link above and set your password.</p>
|
data/devise_invitable.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{devise_invitable}
|
8
|
-
s.version = "0.3.
|
8
|
+
s.version = "0.3.2"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Sergio Cambra"]
|
12
|
-
s.date = %q{2010-09-
|
12
|
+
s.date = %q{2010-09-15}
|
13
13
|
s.description = %q{It adds support for send invitations by email (it requires to be authenticated) and accept the invitation setting the password}
|
14
14
|
s.email = %q{sergio@entrecables.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -31,7 +31,6 @@ Gem::Specification.new do |s|
|
|
31
31
|
"app/views/devise/mailer/invitation.html.erb",
|
32
32
|
"config/locales/en.yml",
|
33
33
|
"devise_invitable.gemspec",
|
34
|
-
"init.rb",
|
35
34
|
"lib/devise_invitable.rb",
|
36
35
|
"lib/devise_invitable/controllers/helpers.rb",
|
37
36
|
"lib/devise_invitable/controllers/url_helpers.rb",
|
@@ -40,6 +39,7 @@ Gem::Specification.new do |s|
|
|
40
39
|
"lib/devise_invitable/rails.rb",
|
41
40
|
"lib/devise_invitable/routes.rb",
|
42
41
|
"lib/devise_invitable/schema.rb",
|
42
|
+
"lib/generators/devise_invitable/views_generator.rb",
|
43
43
|
"test/integration/invitable_test.rb",
|
44
44
|
"test/integration_tests_helper.rb",
|
45
45
|
"test/mailers/invitation_test.rb",
|
@@ -13,29 +13,25 @@ module Devise
|
|
13
13
|
# Examples:
|
14
14
|
#
|
15
15
|
# User.find(1).invited? # true/false
|
16
|
-
# User.
|
16
|
+
# User.invite!(:email => 'someone@example.com') # send invitation
|
17
17
|
# User.accept_invitation!(:invitation_token => '...') # accept invitation with a token
|
18
18
|
# User.find(1).accept_invitation! # accept invitation
|
19
|
-
# User.find(1).
|
19
|
+
# User.find(1).invite! # reset invitation status and send invitation again
|
20
20
|
module Invitable
|
21
|
-
|
22
|
-
base.class_eval do
|
23
|
-
extend ClassMethods
|
24
|
-
end
|
25
|
-
end
|
21
|
+
extend ActiveSupport::Concern
|
26
22
|
|
27
23
|
# Accept an invitation by clearing invitation token and confirming it if model
|
28
24
|
# is confirmable
|
29
25
|
def accept_invitation!
|
30
26
|
if self.invited?
|
31
27
|
self.invitation_token = nil
|
32
|
-
self.save
|
28
|
+
self.save
|
33
29
|
end
|
34
30
|
end
|
35
31
|
|
36
32
|
# Verifies whether a user has been invited or not
|
37
33
|
def invited?
|
38
|
-
|
34
|
+
persisted? && invitation_token.present?
|
39
35
|
end
|
40
36
|
|
41
37
|
# Send invitation by email
|
@@ -44,7 +40,7 @@ module Devise
|
|
44
40
|
end
|
45
41
|
|
46
42
|
# Reset invitation token and send invitation again
|
47
|
-
def
|
43
|
+
def invite!
|
48
44
|
if new_record? || invited?
|
49
45
|
self.skip_confirmation! if self.new_record? and self.respond_to? :skip_confirmation!
|
50
46
|
generate_invitation_token
|
@@ -53,6 +49,11 @@ module Devise
|
|
53
49
|
end
|
54
50
|
end
|
55
51
|
|
52
|
+
def resend_invitation!
|
53
|
+
ActiveSupport::Deprecation.warn('resend_invitation! has been renamed to invite!')
|
54
|
+
self.invite!
|
55
|
+
end
|
56
|
+
|
56
57
|
# Verify whether a invitation is active or not. If the user has been
|
57
58
|
# invited, we need to calculate if the invitation time has not expired
|
58
59
|
# for this user, in other words, if the invitation is still valid.
|
@@ -96,21 +97,26 @@ module Devise
|
|
96
97
|
# Attempt to find a user by it's email. If a record is not found, create a new
|
97
98
|
# user and send invitation to it. If user is found, returns the user with an
|
98
99
|
# email already exists error.
|
99
|
-
#
|
100
|
-
def
|
101
|
-
invitable =
|
100
|
+
# Attributes must contain the user email, other attributes will be set in the record
|
101
|
+
def invite!(attributes={})
|
102
|
+
invitable = find_or_initialize_with_error_by(:email, attributes.delete(:email))
|
103
|
+
invitable.attributes = attributes
|
102
104
|
|
103
105
|
if invitable.new_record?
|
104
|
-
invitable.errors.
|
105
|
-
invitable.errors.add(:email, :invalid) unless invitable.email.match Devise.email_regexp
|
106
|
+
invitable.errors.clear if invitable.email.match Devise.email_regexp
|
106
107
|
else
|
107
108
|
invitable.errors.add(:email, :taken) unless invitable.invited?
|
108
109
|
end
|
109
110
|
|
110
|
-
invitable.
|
111
|
+
invitable.invite! if invitable.errors.empty?
|
111
112
|
invitable
|
112
113
|
end
|
113
114
|
|
115
|
+
def send_invitation(attributes = {})
|
116
|
+
ActiveSupport::Deprecation.warn('send_invitation has been renamed to invite!')
|
117
|
+
self.invite!(attributes)
|
118
|
+
end
|
119
|
+
|
114
120
|
# Attempt to find a user by it's invitation_token to set it's password.
|
115
121
|
# If a user is found, reset it's password and automatically try saving
|
116
122
|
# the record. If not user is found, returns a new user containing an
|
@@ -121,7 +127,7 @@ module Devise
|
|
121
127
|
invitable.errors.add(:invitation_token, :invalid) if attributes[:invitation_token] && !invitable.new_record? && !invitable.valid_invitation?
|
122
128
|
if invitable.errors.empty?
|
123
129
|
invitable.attributes = attributes
|
124
|
-
invitable.accept_invitation!
|
130
|
+
invitable.accept_invitation!
|
125
131
|
end
|
126
132
|
invitable
|
127
133
|
end
|
@@ -1,10 +1,8 @@
|
|
1
1
|
module DeviseInvitable
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
ActionView::Base.send :include, DeviseInvitable::Controllers::UrlHelpers
|
7
|
-
end
|
4
|
+
ActiveSupport.on_load(:action_controller) { include DeviseInvitable::Controllers::UrlHelpers }
|
5
|
+
ActiveSupport.on_load(:action_view) { include DeviseInvitable::Controllers::UrlHelpers }
|
8
6
|
|
9
7
|
config.after_initialize do
|
10
8
|
Devise::Mailer.send :include, DeviseInvitable::Mailer
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'generators/devise/views_generator'
|
2
|
+
|
3
|
+
module DeviseInvitable
|
4
|
+
module Generators
|
5
|
+
class ViewsGenerator < Devise::Generators::ViewsGenerator
|
6
|
+
source_root File.expand_path('../../../../app/views', __FILE__)
|
7
|
+
desc 'Copies all DeviseInvitable views to your application.'
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
@@ -15,13 +15,13 @@ class InvitableTest < ActiveSupport::TestCase
|
|
15
15
|
user = new_user
|
16
16
|
3.times do
|
17
17
|
token = user.invitation_token
|
18
|
-
user.
|
18
|
+
user.invite!
|
19
19
|
assert_not_equal token, user.invitation_token
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
23
23
|
test 'should test invitation sent at with invite_for configuration value' do
|
24
|
-
user = create_user_with_invitation('')
|
24
|
+
user = create_user_with_invitation('token')
|
25
25
|
|
26
26
|
User.stubs(:invite_for).returns(nil)
|
27
27
|
user.invitation_sent_at = Time.now.utc
|
@@ -52,7 +52,7 @@ class InvitableTest < ActiveSupport::TestCase
|
|
52
52
|
invitation_tokens = []
|
53
53
|
3.times do
|
54
54
|
user = new_user
|
55
|
-
user.
|
55
|
+
user.invite!
|
56
56
|
token = user.invitation_token
|
57
57
|
assert !invitation_tokens.include?(token)
|
58
58
|
invitation_tokens << token
|
@@ -96,40 +96,56 @@ class InvitableTest < ActiveSupport::TestCase
|
|
96
96
|
user = new_user
|
97
97
|
assert_difference('ActionMailer::Base.deliveries.size') do
|
98
98
|
token = user.invitation_token
|
99
|
-
user.
|
99
|
+
user.invite!
|
100
100
|
assert_not_equal token, user.invitation_token
|
101
101
|
end
|
102
102
|
end
|
103
103
|
|
104
104
|
test 'should return a record with invitation token and no errors to send invitation by email' do
|
105
|
-
invited_user = User.
|
105
|
+
invited_user = User.invite!(:email => "valid@email.com")
|
106
106
|
assert invited_user.errors.blank?
|
107
107
|
assert_present invited_user.invitation_token
|
108
|
+
assert_equal 'valid@email.com', invited_user.email
|
109
|
+
assert invited_user.persisted?
|
110
|
+
end
|
111
|
+
|
112
|
+
test 'should set all attributes with no errors' do
|
113
|
+
invited_user = User.invite!(:email => "valid@email.com", :username => 'first name')
|
114
|
+
assert invited_user.errors.blank?
|
115
|
+
assert_equal 'first name', invited_user.username
|
116
|
+
assert invited_user.persisted?
|
108
117
|
end
|
109
118
|
|
110
119
|
test 'should return a record with errors if user was found by e-mail' do
|
111
120
|
user = create_user_with_invitation('')
|
112
121
|
user.update_attribute(:invitation_token, nil)
|
113
|
-
invited_user = User.
|
122
|
+
invited_user = User.invite!(:email => user.email)
|
114
123
|
assert_equal invited_user, user
|
115
124
|
assert_equal ['has already been taken'], invited_user.errors[:email]
|
116
125
|
end
|
117
126
|
|
118
127
|
test 'should return a new record with errors if e-mail is blank' do
|
119
|
-
invited_user = User.
|
128
|
+
invited_user = User.invite!(:email => '')
|
120
129
|
assert invited_user.new_record?
|
121
|
-
assert_equal ["can't be blank"
|
130
|
+
assert_equal ["can't be blank"], invited_user.errors[:email]
|
122
131
|
end
|
123
132
|
|
124
133
|
test 'should return a new record with errors if e-mail is invalid' do
|
125
|
-
invited_user = User.
|
134
|
+
invited_user = User.invite!(:email => 'invalid_email')
|
126
135
|
assert invited_user.new_record?
|
127
136
|
assert_equal ["is invalid"], invited_user.errors[:email]
|
128
137
|
end
|
129
138
|
|
139
|
+
test 'should set all attributes with errors if e-mail is invalid' do
|
140
|
+
invited_user = User.invite!(:email => "invalid_email.com", :username => 'first name')
|
141
|
+
assert invited_user.new_record?
|
142
|
+
assert_equal 'first name', invited_user.username
|
143
|
+
assert invited_user.errors.present?
|
144
|
+
end
|
145
|
+
|
130
146
|
test 'should find a user to set his password based on invitation_token' do
|
131
147
|
user = new_user
|
132
|
-
user.
|
148
|
+
user.invite!
|
133
149
|
|
134
150
|
invited_user = User.accept_invitation!(:invitation_token => user.invitation_token)
|
135
151
|
assert_equal invited_user, user
|
@@ -158,7 +174,7 @@ class InvitableTest < ActiveSupport::TestCase
|
|
158
174
|
|
159
175
|
test 'should set successfully user password given the new password and confirmation' do
|
160
176
|
user = new_user(:password => nil, :password_confirmation => nil)
|
161
|
-
user.
|
177
|
+
user.invite!
|
162
178
|
|
163
179
|
invited_user = User.accept_invitation!(
|
164
180
|
:invitation_token => user.invitation_token,
|
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:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 3
|
9
|
-
-
|
10
|
-
version: 0.3.
|
9
|
+
- 2
|
10
|
+
version: 0.3.2
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Sergio Cambra
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2010-09-
|
18
|
+
date: 2010-09-15 00:00:00 +02:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -120,7 +120,6 @@ files:
|
|
120
120
|
- app/views/devise/mailer/invitation.html.erb
|
121
121
|
- config/locales/en.yml
|
122
122
|
- devise_invitable.gemspec
|
123
|
-
- init.rb
|
124
123
|
- lib/devise_invitable.rb
|
125
124
|
- lib/devise_invitable/controllers/helpers.rb
|
126
125
|
- lib/devise_invitable/controllers/url_helpers.rb
|
@@ -129,6 +128,7 @@ files:
|
|
129
128
|
- lib/devise_invitable/rails.rb
|
130
129
|
- lib/devise_invitable/routes.rb
|
131
130
|
- lib/devise_invitable/schema.rb
|
131
|
+
- lib/generators/devise_invitable/views_generator.rb
|
132
132
|
- test/integration/invitable_test.rb
|
133
133
|
- test/integration_tests_helper.rb
|
134
134
|
- test/mailers/invitation_test.rb
|
data/init.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'devise_invitable'
|