saasy 0.0.1

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.
Files changed (146) hide show
  1. data/CHANGELOG.md +114 -0
  2. data/Gemfile +26 -0
  3. data/README.md +118 -0
  4. data/Rakefile +38 -0
  5. data/app/controllers/accounts_controller.rb +68 -0
  6. data/app/controllers/billings_controller.rb +25 -0
  7. data/app/controllers/invitations_controller.rb +65 -0
  8. data/app/controllers/memberships_controller.rb +45 -0
  9. data/app/controllers/plans_controller.rb +24 -0
  10. data/app/controllers/profiles_controller.rb +19 -0
  11. data/app/helpers/limits_helper.rb +13 -0
  12. data/app/mailers/billing_mailer.rb +53 -0
  13. data/app/mailers/invitation_mailer.rb +18 -0
  14. data/app/models/invitation.rb +113 -0
  15. data/app/models/limit.rb +49 -0
  16. data/app/models/membership.rb +26 -0
  17. data/app/models/permission.rb +19 -0
  18. data/app/models/signup.rb +163 -0
  19. data/app/views/accounts/_account.html.erb +9 -0
  20. data/app/views/accounts/_blank_slate.html.erb +6 -0
  21. data/app/views/accounts/_projects.html.erb +12 -0
  22. data/app/views/accounts/_subnav.html.erb +10 -0
  23. data/app/views/accounts/edit.html.erb +34 -0
  24. data/app/views/accounts/index.html.erb +9 -0
  25. data/app/views/accounts/new.html.erb +36 -0
  26. data/app/views/billing_mailer/completed_trial.text.erb +13 -0
  27. data/app/views/billing_mailer/expiring_trial.text.erb +15 -0
  28. data/app/views/billing_mailer/new_unactivated.text.erb +1 -0
  29. data/app/views/billing_mailer/problem.html.erb +13 -0
  30. data/app/views/billing_mailer/problem.text.erb +14 -0
  31. data/app/views/billing_mailer/receipt.html.erb +41 -0
  32. data/app/views/billing_mailer/receipt.text.erb +25 -0
  33. data/app/views/billings/_form.html.erb +8 -0
  34. data/app/views/billings/edit.html.erb +13 -0
  35. data/app/views/billings/show.html.erb +29 -0
  36. data/app/views/invitation_mailer/invitation.text.erb +6 -0
  37. data/app/views/invitations/new.html.erb +17 -0
  38. data/app/views/invitations/show.html.erb +22 -0
  39. data/app/views/layouts/saucy.html.erb +36 -0
  40. data/app/views/limits/_meter.html.erb +13 -0
  41. data/app/views/memberships/edit.html.erb +21 -0
  42. data/app/views/memberships/index.html.erb +17 -0
  43. data/app/views/plans/_plan.html.erb +32 -0
  44. data/app/views/plans/_terms.html.erb +15 -0
  45. data/app/views/plans/edit.html.erb +33 -0
  46. data/app/views/plans/index.html.erb +12 -0
  47. data/app/views/profiles/_inputs.html.erb +5 -0
  48. data/app/views/profiles/edit.html.erb +36 -0
  49. data/app/views/projects/_form.html.erb +36 -0
  50. data/app/views/projects/edit.html.erb +22 -0
  51. data/app/views/projects/index.html.erb +28 -0
  52. data/app/views/projects/new.html.erb +13 -0
  53. data/app/views/projects/show.html.erb +0 -0
  54. data/app/views/shared/_project_dropdown.html.erb +55 -0
  55. data/app/views/shared/_saucy_javascript.html.erb +33 -0
  56. data/config/locales/en.yml +37 -0
  57. data/config/routes.rb +19 -0
  58. data/features/run_features.feature +83 -0
  59. data/features/step_definitions/clearance_steps.rb +45 -0
  60. data/features/step_definitions/rails_steps.rb +73 -0
  61. data/features/step_definitions/saucy_steps.rb +8 -0
  62. data/features/support/env.rb +4 -0
  63. data/features/support/file.rb +11 -0
  64. data/lib/generators/saucy/base.rb +18 -0
  65. data/lib/generators/saucy/features/features_generator.rb +91 -0
  66. data/lib/generators/saucy/features/templates/README +3 -0
  67. data/lib/generators/saucy/features/templates/factories.rb +71 -0
  68. data/lib/generators/saucy/features/templates/features/edit_profile.feature +9 -0
  69. data/lib/generators/saucy/features/templates/features/edit_project_permissions.feature +37 -0
  70. data/lib/generators/saucy/features/templates/features/edit_user_permissions.feature +47 -0
  71. data/lib/generators/saucy/features/templates/features/manage_account.feature +35 -0
  72. data/lib/generators/saucy/features/templates/features/manage_billing.feature +93 -0
  73. data/lib/generators/saucy/features/templates/features/manage_plan.feature +143 -0
  74. data/lib/generators/saucy/features/templates/features/manage_projects.feature +139 -0
  75. data/lib/generators/saucy/features/templates/features/manage_users.feature +142 -0
  76. data/lib/generators/saucy/features/templates/features/new_account.feature +33 -0
  77. data/lib/generators/saucy/features/templates/features/project_dropdown.feature +77 -0
  78. data/lib/generators/saucy/features/templates/features/sign_up.feature +32 -0
  79. data/lib/generators/saucy/features/templates/features/sign_up_paid.feature +65 -0
  80. data/lib/generators/saucy/features/templates/features/trial_plans.feature +82 -0
  81. data/lib/generators/saucy/features/templates/step_definitions/account_steps.rb +30 -0
  82. data/lib/generators/saucy/features/templates/step_definitions/braintree_steps.rb +25 -0
  83. data/lib/generators/saucy/features/templates/step_definitions/cron_steps.rb +23 -0
  84. data/lib/generators/saucy/features/templates/step_definitions/email_steps.rb +40 -0
  85. data/lib/generators/saucy/features/templates/step_definitions/factory_girl_steps.rb +1 -0
  86. data/lib/generators/saucy/features/templates/step_definitions/html_steps.rb +51 -0
  87. data/lib/generators/saucy/features/templates/step_definitions/plan_steps.rb +16 -0
  88. data/lib/generators/saucy/features/templates/step_definitions/project_steps.rb +4 -0
  89. data/lib/generators/saucy/features/templates/step_definitions/session_steps.rb +37 -0
  90. data/lib/generators/saucy/features/templates/step_definitions/user_steps.rb +100 -0
  91. data/lib/generators/saucy/features/templates/support/braintree.rb +5 -0
  92. data/lib/generators/saucy/install/install_generator.rb +40 -0
  93. data/lib/generators/saucy/install/templates/controllers/projects_controller.rb +3 -0
  94. data/lib/generators/saucy/install/templates/create_saucy_tables.rb +115 -0
  95. data/lib/generators/saucy/install/templates/models/account.rb +3 -0
  96. data/lib/generators/saucy/install/templates/models/plan.rb +3 -0
  97. data/lib/generators/saucy/install/templates/models/project.rb +3 -0
  98. data/lib/generators/saucy/specs/specs_generator.rb +20 -0
  99. data/lib/generators/saucy/specs/templates/support/braintree.rb +5 -0
  100. data/lib/generators/saucy/views/views_generator.rb +23 -0
  101. data/lib/saucy.rb +10 -0
  102. data/lib/saucy/account.rb +132 -0
  103. data/lib/saucy/account_authorization.rb +67 -0
  104. data/lib/saucy/configuration.rb +29 -0
  105. data/lib/saucy/engine.rb +35 -0
  106. data/lib/saucy/fake_braintree.rb +134 -0
  107. data/lib/saucy/layouts.rb +36 -0
  108. data/lib/saucy/plan.rb +54 -0
  109. data/lib/saucy/project.rb +125 -0
  110. data/lib/saucy/projects_controller.rb +94 -0
  111. data/lib/saucy/railties/tasks.rake +28 -0
  112. data/lib/saucy/routing_extensions.rb +121 -0
  113. data/lib/saucy/subscription.rb +237 -0
  114. data/lib/saucy/user.rb +30 -0
  115. data/spec/controllers/accounts_controller_spec.rb +228 -0
  116. data/spec/controllers/application_controller_spec.rb +32 -0
  117. data/spec/controllers/invitations_controller_spec.rb +215 -0
  118. data/spec/controllers/memberships_controller_spec.rb +117 -0
  119. data/spec/controllers/plans_controller_spec.rb +13 -0
  120. data/spec/controllers/profiles_controller_spec.rb +48 -0
  121. data/spec/controllers/projects_controller_spec.rb +216 -0
  122. data/spec/environment.rb +95 -0
  123. data/spec/layouts_spec.rb +21 -0
  124. data/spec/mailers/billing_mailer_spec.rb +68 -0
  125. data/spec/mailers/invitiation_mailer_spec.rb +19 -0
  126. data/spec/models/account_spec.rb +218 -0
  127. data/spec/models/invitation_spec.rb +320 -0
  128. data/spec/models/limit_spec.rb +70 -0
  129. data/spec/models/membership_spec.rb +37 -0
  130. data/spec/models/permission_spec.rb +30 -0
  131. data/spec/models/plan_spec.rb +81 -0
  132. data/spec/models/project_spec.rb +223 -0
  133. data/spec/models/signup_spec.rb +177 -0
  134. data/spec/models/subscription_spec.rb +481 -0
  135. data/spec/models/user_spec.rb +72 -0
  136. data/spec/route_extensions_spec.rb +51 -0
  137. data/spec/saucy_spec.rb +62 -0
  138. data/spec/scaffold/config/routes.rb +5 -0
  139. data/spec/spec_helper.rb +39 -0
  140. data/spec/support/authentication_helpers.rb +81 -0
  141. data/spec/support/authorization_helpers.rb +56 -0
  142. data/spec/support/braintree.rb +7 -0
  143. data/spec/support/clearance_matchers.rb +55 -0
  144. data/spec/support/notifications.rb +57 -0
  145. data/spec/views/accounts/_account.html.erb_spec.rb +37 -0
  146. metadata +325 -0
@@ -0,0 +1,30 @@
1
+ module Saucy
2
+ module User
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ attr_accessible :name, :project_ids, :email, :password
7
+ has_many :memberships
8
+ has_many :accounts, :through => :memberships
9
+ has_many :permissions
10
+ has_many :projects, :through => :permissions
11
+ validates_presence_of :name
12
+ end
13
+
14
+ module InstanceMethods
15
+ def admin_of?(account)
16
+ memberships.exists?(:account_id => account.id, :admin => true)
17
+ end
18
+
19
+ def member_of?(account_or_project)
20
+ account_or_project.has_member?(self)
21
+ end
22
+ end
23
+
24
+ module ClassMethods
25
+ def by_name
26
+ order('users.name')
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,228 @@
1
+ require 'spec_helper'
2
+
3
+ describe AccountsController, "routes" do
4
+ it { should route(:get, "/plans/abc/accounts/new").
5
+ to(:action => :new, :plan_id => :abc) }
6
+ it { should route(:get, "/accounts").to(:action => :index) }
7
+ it { should route(:post, "/plans/abc/accounts").
8
+ to(:action => :create, :plan_id => :abc) }
9
+ it { should route(:put, "/accounts/1").to(:action => :update, :id => 1) }
10
+ it { should route(:get, "/accounts/1/edit").to(:action => :edit, :id => 1) }
11
+ it { should route(:delete, "/accounts/1").to(:action => :destroy, :id => 1) }
12
+ end
13
+
14
+ describe AccountsController, "new" do
15
+ let(:signup) { stub('signup') }
16
+ let(:plan) { Factory(:plan) }
17
+
18
+ before do
19
+ Signup.stubs(:new => signup)
20
+ get :new, :plan_id => plan.to_param
21
+ end
22
+
23
+ it "renders the new account form" do
24
+ should respond_with(:success)
25
+ should render_template(:new)
26
+ end
27
+
28
+ it "assigns a new signup" do
29
+ Signup.should have_received(:new)
30
+ should assign_to(:signup).with(signup)
31
+ end
32
+
33
+ it "notifies observers" do
34
+ should notify_observers("plan_viewed", :plan => plan, :request => request)
35
+ end
36
+ end
37
+
38
+ describe AccountsController, "successful create for a confirmed user" do
39
+ let(:user) { Factory.stub(:user) }
40
+ let(:account) { Factory.stub(:account) }
41
+ let(:signup) { stub('signup', :user => user,
42
+ :user= => nil,
43
+ :plan= => plan,
44
+ :account => account) }
45
+ let(:signup_attributes) { "attributes" }
46
+ let(:plan) { Factory(:plan) }
47
+
48
+ before do
49
+ Signup.stubs(:new => signup)
50
+ signup.stubs(:save => true)
51
+ sign_in_as user
52
+ post :create, :signup => signup_attributes, :plan_id => plan.to_param
53
+ end
54
+
55
+ it "creates an signup" do
56
+ Signup.should have_received(:new).with(signup_attributes)
57
+ signup.should have_received(:save)
58
+ end
59
+
60
+ it "redirects to the root" do
61
+ should redirect_to(new_account_project_url(signup.account))
62
+ end
63
+
64
+ it "sets the current user" do
65
+ signup.should have_received(:user=).with(user)
66
+ end
67
+
68
+ it { should set_the_flash.to(/created/i) }
69
+ it { should_not set_the_flash.to(/confirm/i) }
70
+ it { should be_signed_in.as(user) }
71
+
72
+ it "notifies observers" do
73
+ should notify_observers("account_created", :account => signup.account,
74
+ :request => request)
75
+ end
76
+ end
77
+
78
+ describe AccountsController, "failed create" do
79
+ let(:signup) { stub('signup', :user= => nil, :plan= => plan) }
80
+ let(:signup_attributes) { "attributes" }
81
+ let(:plan) { Factory(:plan) }
82
+
83
+ before do
84
+ Signup.stubs(:new => signup)
85
+ signup.stubs(:save => false)
86
+ post :create, :signup => signup_attributes, :plan_id => plan.to_param
87
+ end
88
+
89
+ it "creates an signup" do
90
+ Signup.should have_received(:new).with(signup_attributes)
91
+ signup.should have_received(:save)
92
+ end
93
+
94
+ it "renders the new signup form" do
95
+ should respond_with(:success)
96
+ should render_template(:new)
97
+ end
98
+
99
+ it "assigns a new signup" do
100
+ Signup.should have_received(:new)
101
+ should assign_to(:signup).with(signup)
102
+ end
103
+ end
104
+
105
+ describe AccountsController, "index with multiple projects" do
106
+ let(:user) { Factory.stub(:user) }
107
+ let(:accounts) { %w(one two) }
108
+ let(:projects) { %w(one two) }
109
+
110
+ before do
111
+ user.stubs(:accounts => accounts)
112
+ user.stubs(:projects => projects)
113
+ sign_in_as user
114
+ get :index
115
+ end
116
+
117
+ it "renders the dashboard page" do
118
+ should respond_with(:success)
119
+ should render_template(:index)
120
+ end
121
+
122
+ it "assigns the user's accounts" do
123
+ user.should have_received(:accounts)
124
+ should assign_to(:accounts).with(accounts)
125
+ end
126
+ end
127
+
128
+ describe AccountsController, "signed out" do
129
+ it "redirects to sign_in on index" do
130
+ get :index
131
+ should redirect_to(sign_in_path)
132
+ end
133
+ it "redirects to sign_in on edit" do
134
+ get :edit, :id => 1
135
+ should redirect_to(sign_in_path)
136
+ end
137
+ it "redirects to sign_in on update" do
138
+ put :update, :id => 1, :account => {}
139
+ should redirect_to(sign_in_path)
140
+ end
141
+ end
142
+
143
+ describe AccountsController, "index with one project" do
144
+ let(:user) { Factory.stub(:user) }
145
+ let(:accounts) { %w(one two) }
146
+ let(:projects) { [Factory.stub(:project)] }
147
+
148
+ before do
149
+ user.stubs(:accounts => accounts)
150
+ user.stubs(:projects => projects)
151
+ sign_in_as user
152
+ get :index
153
+ end
154
+
155
+ it "redirects to the project" do
156
+ should redirect_to(controller.project_url(projects.first))
157
+ end
158
+ end
159
+
160
+ describe AccountsController, "valid update", :as => :account_admin do
161
+ before do
162
+ put :update,
163
+ :account => Factory.attributes_for(:account),
164
+ :id => account.to_param
165
+ end
166
+
167
+ it "redirects to settings" do
168
+ should redirect_to(edit_profile_url)
169
+ end
170
+
171
+ it { should set_the_flash.to(/updated/) }
172
+ end
173
+
174
+ describe AccountsController, "invalid update", :as => :account_admin do
175
+ before do
176
+ put :update,
177
+ :account => {:name => ""},
178
+ :id => account.to_param
179
+ end
180
+
181
+ it { should respond_with(:success) }
182
+ it { should render_template(:edit) }
183
+ end
184
+
185
+ describe AccountsController, "edit", :as => :account_admin do
186
+ before do
187
+ get :edit, :id => account.to_param
188
+ end
189
+
190
+ it "renders the edit template" do
191
+ should respond_with(:success)
192
+ should render_template(:edit)
193
+ end
194
+
195
+ it "assigns the account" do
196
+ should assign_to(:account).with(account)
197
+ end
198
+ end
199
+
200
+ describe AccountsController, "destroy", :as => :account_admin do
201
+ before do
202
+ Account.stubs(:find_by_keyword! => account)
203
+ account.stubs(:destroy)
204
+ delete :destroy, :id => account.to_param
205
+ end
206
+
207
+ it "redirects to the root url" do
208
+ should redirect_to("/")
209
+ end
210
+
211
+ it "sets the flash" do
212
+ should set_the_flash.to(/deleted/i)
213
+ end
214
+
215
+ it "deletes the account" do
216
+ account.should have_received(:destroy)
217
+ end
218
+ end
219
+
220
+ describe AccountsController, "permissions", :as => :account_member do
221
+ it { should deny_access.
222
+ on(:get, :edit, :id => account.to_param).
223
+ flash(/admin/) }
224
+ it { should deny_access.
225
+ on(:put, :update, :id => account.to_param).
226
+ flash(/admin/) }
227
+ end
228
+
@@ -0,0 +1,32 @@
1
+ require 'spec_helper'
2
+
3
+ describe ApplicationController do
4
+
5
+ describe "with a valid account id in the params" do
6
+ before do
7
+ @account = Factory(:account)
8
+ @controller.stubs(:params).returns(:account_id => @account.to_param)
9
+ end
10
+
11
+ it "should return the corresponding account from current_account" do
12
+ @controller.__send__(:current_account).should == @account
13
+ end
14
+ end
15
+
16
+ describe "with an invalid account id in the params" do
17
+ before do
18
+ @controller.stubs(:params).returns(:account_id => "invalid")
19
+ end
20
+
21
+ it "should return the corresponding account from current_account" do
22
+ expect { @controller.__send__(:current_account) }.
23
+ to raise_error(ActiveRecord::RecordNotFound)
24
+ end
25
+ end
26
+
27
+ it { should filter_param(:card_number) }
28
+ it { should filter_param(:cardholder_name) }
29
+ it { should filter_param(:verification_code) }
30
+ it { should filter_param(:expiration_month) }
31
+ it { should filter_param(:expiration_year) }
32
+ end
@@ -0,0 +1,215 @@
1
+ require 'spec_helper'
2
+
3
+ describe InvitationsController, "routes" do
4
+ it { should route(:get, "/accounts/abc/invitations/new").
5
+ to(:action => :new, :account_id => 'abc') }
6
+ it { should route(:post, "/accounts/abc/invitations").
7
+ to(:action => :create, :account_id => 'abc') }
8
+ it { should route(:get, "/accounts/abc/invitations/xyz").
9
+ to(:action => :show, :account_id => 'abc', :id => 'xyz') }
10
+ it { should route(:put, "/accounts/abc/invitations/xyz").
11
+ to(:action => :update, :account_id => 'abc', :id => 'xyz') }
12
+ end
13
+
14
+ describe InvitationsController, "permissions" do
15
+ let(:account) { Factory(:account) }
16
+ before { sign_in }
17
+ it { should deny_access.
18
+ on(:get, :new, :account_id => account.to_param).
19
+ flash(/admin/) }
20
+ it { should deny_access.
21
+ on(:post, :create, :account_id => account.to_param).
22
+ flash(/admin/) }
23
+ end
24
+
25
+ describe InvitationsController, "new", :as => :account_admin do
26
+ let(:invitation) { Invitation.new }
27
+ let(:projects) { ['one', 'two'] }
28
+
29
+ before do
30
+ Account.stubs(:find_by_keyword! => account)
31
+ account.stubs(:projects_by_name => projects)
32
+ Invitation.stubs(:new => invitation)
33
+ get :new, :account_id => account.to_param
34
+ end
35
+
36
+ it "renders the new template" do
37
+ should respond_with(:success)
38
+ should render_template(:new)
39
+ end
40
+
41
+ it "assigns an invitation" do
42
+ Invitation.should have_received(:new)
43
+ should assign_to(:invitation).with(invitation)
44
+ end
45
+
46
+ it "assigns projects" do
47
+ should assign_to(:projects).with(projects)
48
+ end
49
+ end
50
+
51
+ describe InvitationsController, "valid create", :as => :account_admin do
52
+ let(:invitation) { Factory.stub(:invitation) }
53
+ let(:attributes) { 'attributes' }
54
+
55
+ before do
56
+ Invitation.stubs(:new => invitation)
57
+ invitation.stubs(:account=)
58
+ invitation.stubs(:sender=)
59
+ invitation.stubs(:save => true)
60
+ post :create, :account_id => account.to_param, :invitation => attributes
61
+ end
62
+
63
+ it "redirects to the membership index" do
64
+ should redirect_to(account_memberships_url(account))
65
+ end
66
+
67
+ it "saves an invitation" do
68
+ Invitation.should have_received(:new).with(attributes)
69
+ invitation.should have_received(:account=).with(account)
70
+ invitation.should have_received(:sender=).with(current_user)
71
+ invitation.should have_received(:save)
72
+ end
73
+
74
+ it "sets a flash message" do
75
+ should set_the_flash.to(/invited/i)
76
+ end
77
+ end
78
+
79
+ describe InvitationsController, "invalid create", :as => :account_admin do
80
+ let(:invitation) { Factory.stub(:invitation) }
81
+ let(:projects) { ['one', 'two'] }
82
+
83
+ before do
84
+ Invitation.stubs(:new => invitation)
85
+ invitation.stubs(:save => false)
86
+ Account.stubs(:find_by_keyword! => account)
87
+ account.stubs(:projects_by_name => projects)
88
+ post :create, :account_id => account.to_param, :invitation => {}
89
+ end
90
+
91
+ it "renders the new template" do
92
+ should respond_with(:success)
93
+ should render_template(:new)
94
+ end
95
+
96
+ it "doesn't set a flash message" do
97
+ should_not set_the_flash
98
+ end
99
+
100
+ it "assigns projects" do
101
+ should assign_to(:projects).with(projects)
102
+ end
103
+ end
104
+
105
+ describe InvitationsController, "show" do
106
+ let(:invitation) { Factory.stub(:invitation, :code => 'abc') }
107
+ let(:account) { invitation.account }
108
+
109
+ before do
110
+ Invitation.stubs(:find_by_code! => invitation)
111
+ get :show, :id => invitation.to_param, :account_id => account.to_param
112
+ end
113
+
114
+ it "renders the show template" do
115
+ should respond_with(:success)
116
+ should render_template(:show)
117
+ end
118
+
119
+ it "assigns the invitation" do
120
+ Invitation.should have_received(:find_by_code!).with(invitation.to_param)
121
+ should assign_to(:invitation).with(invitation)
122
+ end
123
+ end
124
+
125
+ describe InvitationsController, "show for a used invitation" do
126
+ let(:invitation) { Factory.stub(:invitation, :code => 'abc', :used => true) }
127
+ let(:account) { invitation.account }
128
+
129
+ before do
130
+ Invitation.stubs(:find_by_code! => invitation)
131
+ get :show, :id => invitation.to_param, :account_id => account.to_param
132
+ end
133
+
134
+ it "redirects to the root url" do
135
+ should redirect_to("/")
136
+ end
137
+
138
+ it "sets a flash message" do
139
+ should set_the_flash.to(/used/i)
140
+ end
141
+ end
142
+
143
+ describe InvitationsController, "valid update" do
144
+ let(:invitation) { Factory.stub(:invitation, :code => 'abc') }
145
+ let(:account) { invitation.account }
146
+ let(:attributes) { 'attributes' }
147
+ let(:user) { Factory.stub(:user) }
148
+
149
+ before do
150
+ Invitation.stubs(:find_by_code! => invitation)
151
+ invitation.stubs(:accept => true)
152
+ invitation.stubs(:user => user)
153
+ put :update, :id => invitation.to_param,
154
+ :account_id => account.to_param,
155
+ :invitation => attributes
156
+ end
157
+
158
+ it "signs the user in" do
159
+ should be_signed_in.as(user)
160
+ end
161
+
162
+ it "accepts the invitation" do
163
+ Invitation.should have_received(:find_by_code!).with(invitation.to_param)
164
+ invitation.should have_received(:accept).with(attributes)
165
+ end
166
+
167
+ it "redirects to the root page" do
168
+ should redirect_to(root_url)
169
+ end
170
+ end
171
+
172
+ describe InvitationsController, "invalid update" do
173
+ let(:invitation) { Factory.stub(:invitation, :code => 'abc') }
174
+ let(:account) { invitation.account }
175
+
176
+ before do
177
+ Invitation.stubs(:find_by_code! => invitation)
178
+ invitation.stubs(:accept => false)
179
+ put :update, :id => invitation.to_param,
180
+ :account_id => account.to_param,
181
+ :invitation => {}
182
+ end
183
+
184
+ it "doesn't sign in" do
185
+ should_not be_signed_in
186
+ end
187
+
188
+ it "renders the show template" do
189
+ should respond_with(:success)
190
+ should render_template(:show)
191
+ end
192
+
193
+ it "assigns the invitation" do
194
+ should assign_to(:invitation).with(invitation)
195
+ end
196
+ end
197
+
198
+ describe InvitationsController, "update for a used invitation" do
199
+ let(:invitation) { Factory.stub(:invitation, :code => 'abc', :used => true) }
200
+ let(:account) { invitation.account }
201
+
202
+ before do
203
+ Invitation.stubs(:find_by_code! => invitation)
204
+ put :update, :id => invitation.to_param, :account_id => account.to_param
205
+ end
206
+
207
+ it "redirects to the root url" do
208
+ should redirect_to("/")
209
+ end
210
+
211
+ it "sets a flash message" do
212
+ should set_the_flash.to(/used/i)
213
+ end
214
+ end
215
+