saucy 0.2.18 → 0.2.20
Sign up to get free protection for your applications and to get access to all the features.
@@ -22,17 +22,17 @@ class InvitationsController < ApplicationController
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def show
|
25
|
-
|
26
|
-
render
|
25
|
+
with_invitation { render }
|
27
26
|
end
|
28
27
|
|
29
28
|
def update
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
29
|
+
with_invitation do
|
30
|
+
if @invitation.accept(params[:invitation])
|
31
|
+
sign_in @invitation.user
|
32
|
+
redirect_to root_url
|
33
|
+
else
|
34
|
+
render :action => 'show'
|
35
|
+
end
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
@@ -41,4 +41,15 @@ class InvitationsController < ApplicationController
|
|
41
41
|
def assign_projects
|
42
42
|
@projects = current_account.projects_by_name
|
43
43
|
end
|
44
|
+
|
45
|
+
def with_invitation
|
46
|
+
@invitation = Invitation.find_by_code!(params[:id])
|
47
|
+
if @invitation.used?
|
48
|
+
flash[:error] = t("invitations.show.used",
|
49
|
+
:default => "That invitation has already been used.")
|
50
|
+
redirect_to root_url
|
51
|
+
else
|
52
|
+
yield
|
53
|
+
end
|
54
|
+
end
|
44
55
|
end
|
data/app/models/invitation.rb
CHANGED
@@ -4,13 +4,14 @@ class Invitation < ActiveRecord::Base
|
|
4
4
|
validates_presence_of :email
|
5
5
|
has_and_belongs_to_many :projects
|
6
6
|
|
7
|
+
before_create :generate_code
|
7
8
|
after_create :deliver_invitation
|
8
9
|
|
9
10
|
attr_accessor :new_user_name, :new_user_password,
|
10
11
|
:new_user_password_confirmation, :existing_user_password
|
11
12
|
attr_writer :new_user_email, :existing_user_email
|
12
13
|
attr_reader :user
|
13
|
-
attr_protected :account_id
|
14
|
+
attr_protected :account_id, :used
|
14
15
|
|
15
16
|
validate :validate_accepting_user, :on => :update
|
16
17
|
|
@@ -20,12 +21,16 @@ class Invitation < ActiveRecord::Base
|
|
20
21
|
|
21
22
|
def accept(attributes)
|
22
23
|
self.attributes = attributes
|
24
|
+
self.used = true
|
23
25
|
@user = existing_user || new_user
|
24
26
|
if valid?
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
27
|
+
transaction do
|
28
|
+
save!
|
29
|
+
@user.save!
|
30
|
+
@user.memberships.create!(:account => account,
|
31
|
+
:admin => admin,
|
32
|
+
:projects => projects)
|
33
|
+
end
|
29
34
|
end
|
30
35
|
end
|
31
36
|
|
@@ -37,6 +42,10 @@ class Invitation < ActiveRecord::Base
|
|
37
42
|
@existing_user_email ||= email
|
38
43
|
end
|
39
44
|
|
45
|
+
def to_param
|
46
|
+
code
|
47
|
+
end
|
48
|
+
|
40
49
|
private
|
41
50
|
|
42
51
|
def deliver_invitation
|
@@ -84,4 +93,8 @@ class Invitation < ActiveRecord::Base
|
|
84
93
|
errors.add(:existing_user_password, "is incorrect")
|
85
94
|
end
|
86
95
|
end
|
96
|
+
|
97
|
+
def generate_code
|
98
|
+
self.code = SecureRandom.hex(8)
|
99
|
+
end
|
87
100
|
end
|
@@ -101,11 +101,11 @@ describe InvitationsController, "invalid create", :as => :account_admin do
|
|
101
101
|
end
|
102
102
|
|
103
103
|
describe InvitationsController, "show" do
|
104
|
-
let(:invitation) { Factory.stub(:invitation) }
|
104
|
+
let(:invitation) { Factory.stub(:invitation, :code => 'abc') }
|
105
105
|
let(:account) { invitation.account }
|
106
106
|
|
107
107
|
before do
|
108
|
-
Invitation.stubs(:
|
108
|
+
Invitation.stubs(:find_by_code! => invitation)
|
109
109
|
get :show, :id => invitation.to_param, :account_id => account.to_param
|
110
110
|
end
|
111
111
|
|
@@ -115,19 +115,37 @@ describe InvitationsController, "show" do
|
|
115
115
|
end
|
116
116
|
|
117
117
|
it "assigns the invitation" do
|
118
|
-
Invitation.should have_received(:
|
118
|
+
Invitation.should have_received(:find_by_code!).with(invitation.to_param)
|
119
119
|
should assign_to(:invitation).with(invitation)
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
|
+
describe InvitationsController, "show for a used invitation" do
|
124
|
+
let(:invitation) { Factory.stub(:invitation, :code => 'abc', :used => true) }
|
125
|
+
let(:account) { invitation.account }
|
126
|
+
|
127
|
+
before do
|
128
|
+
Invitation.stubs(:find_by_code! => invitation)
|
129
|
+
get :show, :id => invitation.to_param, :account_id => account.to_param
|
130
|
+
end
|
131
|
+
|
132
|
+
it "redirects to the root url" do
|
133
|
+
should redirect_to("/")
|
134
|
+
end
|
135
|
+
|
136
|
+
it "sets a flash message" do
|
137
|
+
should set_the_flash.to(/used/i)
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
123
141
|
describe InvitationsController, "valid update" do
|
124
|
-
let(:invitation) { Factory.stub(:invitation) }
|
142
|
+
let(:invitation) { Factory.stub(:invitation, :code => 'abc') }
|
125
143
|
let(:account) { invitation.account }
|
126
144
|
let(:attributes) { 'attributes' }
|
127
145
|
let(:user) { Factory.stub(:user) }
|
128
146
|
|
129
147
|
before do
|
130
|
-
Invitation.stubs(:
|
148
|
+
Invitation.stubs(:find_by_code! => invitation)
|
131
149
|
invitation.stubs(:accept => true)
|
132
150
|
invitation.stubs(:user => user)
|
133
151
|
put :update, :id => invitation.to_param,
|
@@ -140,7 +158,7 @@ describe InvitationsController, "valid update" do
|
|
140
158
|
end
|
141
159
|
|
142
160
|
it "accepts the invitation" do
|
143
|
-
Invitation.should have_received(:
|
161
|
+
Invitation.should have_received(:find_by_code!).with(invitation.to_param)
|
144
162
|
invitation.should have_received(:accept).with(attributes)
|
145
163
|
end
|
146
164
|
|
@@ -150,11 +168,11 @@ describe InvitationsController, "valid update" do
|
|
150
168
|
end
|
151
169
|
|
152
170
|
describe InvitationsController, "invalid update" do
|
153
|
-
let(:invitation) { Factory.stub(:invitation) }
|
171
|
+
let(:invitation) { Factory.stub(:invitation, :code => 'abc') }
|
154
172
|
let(:account) { invitation.account }
|
155
173
|
|
156
174
|
before do
|
157
|
-
Invitation.stubs(:
|
175
|
+
Invitation.stubs(:find_by_code! => invitation)
|
158
176
|
invitation.stubs(:accept => false)
|
159
177
|
put :update, :id => invitation.to_param,
|
160
178
|
:account_id => account.to_param,
|
@@ -174,3 +192,22 @@ describe InvitationsController, "invalid update" do
|
|
174
192
|
should assign_to(:invitation).with(invitation)
|
175
193
|
end
|
176
194
|
end
|
195
|
+
|
196
|
+
describe InvitationsController, "update for a used invitation" do
|
197
|
+
let(:invitation) { Factory.stub(:invitation, :code => 'abc', :used => true) }
|
198
|
+
let(:account) { invitation.account }
|
199
|
+
|
200
|
+
before do
|
201
|
+
Invitation.stubs(:find_by_code! => invitation)
|
202
|
+
put :update, :id => invitation.to_param, :account_id => account.to_param
|
203
|
+
end
|
204
|
+
|
205
|
+
it "redirects to the root url" do
|
206
|
+
should redirect_to("/")
|
207
|
+
end
|
208
|
+
|
209
|
+
it "sets a flash message" do
|
210
|
+
should set_the_flash.to(/used/i)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
@@ -7,6 +7,7 @@ describe Invitation do
|
|
7
7
|
it { should have_and_belong_to_many(:projects) }
|
8
8
|
|
9
9
|
it { should_not allow_mass_assignment_of(:account_id) }
|
10
|
+
it { should_not allow_mass_assignment_of(:used) }
|
10
11
|
|
11
12
|
%w(new_user_name new_user_email new_user_password
|
12
13
|
new_user_password_confirmation existing_user_password).each do |attribute|
|
@@ -19,9 +20,15 @@ end
|
|
19
20
|
|
20
21
|
describe Invitation, "saved" do
|
21
22
|
let(:mail) { stub('invitation', :deliver => true) }
|
22
|
-
before { InvitationMailer.stubs(:invitation => mail) }
|
23
23
|
subject { Factory(:invitation) }
|
24
24
|
let(:email) { subject.email }
|
25
|
+
let(:code) { 'abchex123' }
|
26
|
+
|
27
|
+
before do
|
28
|
+
SecureRandom.stubs(:hex => code)
|
29
|
+
InvitationMailer.stubs(:invitation => mail)
|
30
|
+
subject
|
31
|
+
end
|
25
32
|
|
26
33
|
it "sends an invitation email" do
|
27
34
|
InvitationMailer.should have_received(:invitation).with(subject)
|
@@ -39,6 +46,15 @@ describe Invitation, "saved" do
|
|
39
46
|
it "defauls existing user email to invited email" do
|
40
47
|
subject.existing_user_email.should == subject.email
|
41
48
|
end
|
49
|
+
|
50
|
+
it "generates a code" do
|
51
|
+
SecureRandom.should have_received(:hex).with(8)
|
52
|
+
subject.code.should == code
|
53
|
+
end
|
54
|
+
|
55
|
+
it "uses the code in the url" do
|
56
|
+
subject.to_param.should == code
|
57
|
+
end
|
42
58
|
end
|
43
59
|
|
44
60
|
describe Invitation, "valid accept for a new user" do
|
@@ -75,6 +91,10 @@ describe Invitation, "valid accept for a new user" do
|
|
75
91
|
user.should be_member_of(project)
|
76
92
|
end
|
77
93
|
end
|
94
|
+
|
95
|
+
it "marks the invitation as used" do
|
96
|
+
subject.reload.should be_used
|
97
|
+
end
|
78
98
|
end
|
79
99
|
|
80
100
|
describe Invitation, "invalid accept for a new user" do
|
@@ -94,6 +114,10 @@ describe Invitation, "invalid accept for a new user" do
|
|
94
114
|
it "adds error messages" do
|
95
115
|
subject.errors[:new_user_password].should be_present
|
96
116
|
end
|
117
|
+
|
118
|
+
it "doesn't mark the invitation as used" do
|
119
|
+
subject.reload.should_not be_used
|
120
|
+
end
|
97
121
|
end
|
98
122
|
|
99
123
|
describe Invitation, "valid accept for an existing user" do
|
@@ -115,6 +139,10 @@ describe Invitation, "valid accept for an existing user" do
|
|
115
139
|
it "adds the user to the account" do
|
116
140
|
account.users.should include(user)
|
117
141
|
end
|
142
|
+
|
143
|
+
it "marks the invitation as used" do
|
144
|
+
subject.reload.should be_used
|
145
|
+
end
|
118
146
|
end
|
119
147
|
|
120
148
|
describe Invitation, "accepting with an invalid password" do
|
@@ -136,6 +164,108 @@ describe Invitation, "accepting with an invalid password" do
|
|
136
164
|
end
|
137
165
|
end
|
138
166
|
|
167
|
+
describe Invitation, "saved" do
|
168
|
+
let(:mail) { stub('invitation', :deliver => true) }
|
169
|
+
subject { Factory(:invitation) }
|
170
|
+
let(:email) { subject.email }
|
171
|
+
let(:code) { 'abchex123' }
|
172
|
+
|
173
|
+
before do
|
174
|
+
SecureRandom.stubs(:hex => code)
|
175
|
+
InvitationMailer.stubs(:invitation => mail)
|
176
|
+
subject
|
177
|
+
end
|
178
|
+
|
179
|
+
it "sends an invitation email" do
|
180
|
+
InvitationMailer.should have_received(:invitation).with(subject)
|
181
|
+
mail.should have_received(:deliver)
|
182
|
+
end
|
183
|
+
|
184
|
+
it "delegates account name" do
|
185
|
+
subject.account_name.should == subject.account.name
|
186
|
+
end
|
187
|
+
|
188
|
+
it "defauls new user email to invited email" do
|
189
|
+
subject.new_user_email.should == subject.email
|
190
|
+
end
|
191
|
+
|
192
|
+
it "defauls existing user email to invited email" do
|
193
|
+
subject.existing_user_email.should == subject.email
|
194
|
+
end
|
195
|
+
|
196
|
+
it "generates a code" do
|
197
|
+
SecureRandom.should have_received(:hex).with(8)
|
198
|
+
subject.code.should == code
|
199
|
+
end
|
200
|
+
|
201
|
+
it "uses the code in the url" do
|
202
|
+
subject.to_param.should == code
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
describe Invitation, "valid accept for a new user" do
|
207
|
+
let(:account) { Factory(:account) }
|
208
|
+
let(:projects) { [Factory(:project, :account => account)] }
|
209
|
+
let(:password) { 'secret' }
|
210
|
+
let(:name) { 'Rocket' }
|
211
|
+
subject { Factory(:invitation, :account => account, :projects => projects) }
|
212
|
+
|
213
|
+
let!(:result) do
|
214
|
+
subject.accept(:new_user_password => password,
|
215
|
+
:new_user_password_confirmation => password,
|
216
|
+
:new_user_name => name)
|
217
|
+
end
|
218
|
+
|
219
|
+
let(:user) { subject.user }
|
220
|
+
|
221
|
+
it "returns true" do
|
222
|
+
result.should be_true
|
223
|
+
end
|
224
|
+
|
225
|
+
it "creates a saved, confirmed user" do
|
226
|
+
user.should_not be_nil
|
227
|
+
user.should be_persisted
|
228
|
+
user.name.should == name
|
229
|
+
end
|
230
|
+
|
231
|
+
it "adds the user to the account" do
|
232
|
+
account.users.should include(user)
|
233
|
+
end
|
234
|
+
|
235
|
+
it "adds the user to each of the invitation's projects" do
|
236
|
+
projects.each do |project|
|
237
|
+
user.should be_member_of(project)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
it "marks the invitation as used" do
|
242
|
+
subject.reload.should be_used
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
describe Invitation, "invalid accept for a new user" do
|
247
|
+
subject { Factory(:invitation) }
|
248
|
+
let!(:result) { subject.accept({}) }
|
249
|
+
let(:user) { subject.user }
|
250
|
+
let(:account) { subject.account }
|
251
|
+
|
252
|
+
it "returns false" do
|
253
|
+
result.should be_false
|
254
|
+
end
|
255
|
+
|
256
|
+
it "doesn't create a user" do
|
257
|
+
user.should be_new_record
|
258
|
+
end
|
259
|
+
|
260
|
+
it "adds error messages" do
|
261
|
+
subject.errors[:new_user_password].should be_present
|
262
|
+
end
|
263
|
+
|
264
|
+
it "doesn't mark the invitation as used" do
|
265
|
+
subject.reload.should_not be_used
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
139
269
|
describe Invitation, "accepting with an unknown email" do
|
140
270
|
subject { Factory(:invitation, :email => 'unknown') }
|
141
271
|
let(:account) { subject.account }
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: saucy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 63
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 2
|
9
|
-
-
|
10
|
-
version: 0.2.
|
9
|
+
- 20
|
10
|
+
version: 0.2.20
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- thoughtbot, inc.
|
@@ -17,13 +17,14 @@ autorequire:
|
|
17
17
|
bindir: bin
|
18
18
|
cert_chain: []
|
19
19
|
|
20
|
-
date: 2011-02-
|
20
|
+
date: 2011-02-11 00:00:00 -05:00
|
21
21
|
default_executable:
|
22
22
|
dependencies:
|
23
23
|
- !ruby/object:Gem::Dependency
|
24
|
-
|
24
|
+
type: :runtime
|
25
25
|
prerelease: false
|
26
|
-
|
26
|
+
name: formtastic
|
27
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
27
28
|
none: false
|
28
29
|
requirements:
|
29
30
|
- - ">="
|
@@ -33,12 +34,12 @@ dependencies:
|
|
33
34
|
- 1
|
34
35
|
- 2
|
35
36
|
version: "1.2"
|
36
|
-
|
37
|
-
version_requirements: *id001
|
37
|
+
requirement: *id001
|
38
38
|
- !ruby/object:Gem::Dependency
|
39
|
-
|
39
|
+
type: :runtime
|
40
40
|
prerelease: false
|
41
|
-
|
41
|
+
name: railties
|
42
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
42
43
|
none: false
|
43
44
|
requirements:
|
44
45
|
- - ">="
|
@@ -49,12 +50,12 @@ dependencies:
|
|
49
50
|
- 0
|
50
51
|
- 3
|
51
52
|
version: 3.0.3
|
52
|
-
|
53
|
-
version_requirements: *id002
|
53
|
+
requirement: *id002
|
54
54
|
- !ruby/object:Gem::Dependency
|
55
|
-
|
55
|
+
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
|
57
|
+
name: braintree
|
58
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
58
59
|
none: false
|
59
60
|
requirements:
|
60
61
|
- - ">="
|
@@ -65,12 +66,12 @@ dependencies:
|
|
65
66
|
- 6
|
66
67
|
- 2
|
67
68
|
version: 2.6.2
|
68
|
-
|
69
|
-
version_requirements: *id003
|
69
|
+
requirement: *id003
|
70
70
|
- !ruby/object:Gem::Dependency
|
71
|
-
|
71
|
+
type: :runtime
|
72
72
|
prerelease: false
|
73
|
-
|
73
|
+
name: sham_rack
|
74
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
74
75
|
none: false
|
75
76
|
requirements:
|
76
77
|
- - "="
|
@@ -81,12 +82,12 @@ dependencies:
|
|
81
82
|
- 3
|
82
83
|
- 3
|
83
84
|
version: 1.3.3
|
84
|
-
|
85
|
-
version_requirements: *id004
|
85
|
+
requirement: *id004
|
86
86
|
- !ruby/object:Gem::Dependency
|
87
|
-
|
87
|
+
type: :runtime
|
88
88
|
prerelease: false
|
89
|
-
|
89
|
+
name: sinatra
|
90
|
+
version_requirements: &id005 !ruby/object:Gem::Requirement
|
90
91
|
none: false
|
91
92
|
requirements:
|
92
93
|
- - "="
|
@@ -97,12 +98,12 @@ dependencies:
|
|
97
98
|
- 1
|
98
99
|
- 2
|
99
100
|
version: 1.1.2
|
100
|
-
|
101
|
-
version_requirements: *id005
|
101
|
+
requirement: *id005
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
|
-
|
103
|
+
type: :development
|
104
104
|
prerelease: false
|
105
|
-
|
105
|
+
name: aruba
|
106
|
+
version_requirements: &id006 !ruby/object:Gem::Requirement
|
106
107
|
none: false
|
107
108
|
requirements:
|
108
109
|
- - "="
|
@@ -113,8 +114,7 @@ dependencies:
|
|
113
114
|
- 2
|
114
115
|
- 6
|
115
116
|
version: 0.2.6
|
116
|
-
|
117
|
-
version_requirements: *id006
|
117
|
+
requirement: *id006
|
118
118
|
description: Clearance-based Rails engine for Software as a Service (Saas) that provides account and project management
|
119
119
|
email: support@thoughtbot.com
|
120
120
|
executables: []
|