user_plane 0.0.15

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 (205) hide show
  1. checksums.yaml +7 -0
  2. data/MIT-LICENSE +20 -0
  3. data/Rakefile +30 -0
  4. data/app/assets/javascripts/user_plane/application.js +13 -0
  5. data/app/assets/stylesheets/user_plane/application.css +15 -0
  6. data/app/concerns/null_object_persistable.rb +62 -0
  7. data/app/controllers/user/confirm_email_addresses_controller.rb +17 -0
  8. data/app/controllers/user/details_controller.rb +48 -0
  9. data/app/controllers/user/invites_controller.rb +69 -0
  10. data/app/controllers/user/reset_passwords_controller.rb +50 -0
  11. data/app/controllers/user/sign_ins_controller.rb +53 -0
  12. data/app/controllers/user/sign_ups_controller.rb +47 -0
  13. data/app/controllers/user_plane/application_controller.rb +5 -0
  14. data/app/helpers/user_plane/application_helper.rb +4 -0
  15. data/app/mailers/user_plane/application_mailer.rb +8 -0
  16. data/app/mailers/user_plane/invite_mailer.rb +14 -0
  17. data/app/mailers/user_plane/verification_mailer.rb +25 -0
  18. data/app/models/session_manager.rb +100 -0
  19. data/app/models/user.rb +5 -0
  20. data/app/models/user/account.rb +26 -0
  21. data/app/models/user/confirm_email_address.rb +55 -0
  22. data/app/models/user/guest.rb +18 -0
  23. data/app/models/user/identities.rb +5 -0
  24. data/app/models/user/identities/email.rb +98 -0
  25. data/app/models/user/identities/email_verification.rb +70 -0
  26. data/app/models/user/identities/facebook.rb +5 -0
  27. data/app/models/user/identities/github.rb +5 -0
  28. data/app/models/user/identities/id_token.rb +7 -0
  29. data/app/models/user/identities/o_auth.rb +67 -0
  30. data/app/models/user/identities/o_auth_endpoint.rb +28 -0
  31. data/app/models/user/identities/twitter.rb +5 -0
  32. data/app/models/user/identity.rb +26 -0
  33. data/app/models/user/reset_password.rb +59 -0
  34. data/app/models/user/send_password_reset.rb +25 -0
  35. data/app/models/user/send_sign_up_invite.rb +27 -0
  36. data/app/models/user/sign_in.rb +42 -0
  37. data/app/models/user/sign_up.rb +47 -0
  38. data/app/models/user/sign_up_invites.rb +5 -0
  39. data/app/models/user/sign_up_invites/invite.rb +46 -0
  40. data/app/models/user/sign_up_invites/stack.rb +22 -0
  41. data/app/models/user/sign_up_with_invite.rb +45 -0
  42. data/app/models/user/suspension.rb +7 -0
  43. data/app/models/user/update_details.rb +103 -0
  44. data/app/views/layouts/user_plane/application.html.erb +14 -0
  45. data/app/views/user/details/edit.html.erb +37 -0
  46. data/app/views/user/invites/edit.html.erb +34 -0
  47. data/app/views/user/invites/new.html.erb +21 -0
  48. data/app/views/user/reset_passwords/edit.html.erb +26 -0
  49. data/app/views/user/reset_passwords/new.html.erb +21 -0
  50. data/app/views/user/sign_ins/new.html.erb +25 -0
  51. data/app/views/user/sign_ups/new.html.erb +33 -0
  52. data/app/views/user_plane/invite_mailer/invite.html.erb +2 -0
  53. data/app/views/user_plane/invite_mailer/invite.text.erb +3 -0
  54. data/app/views/user_plane/verification_mailer/address_verification.html.erb +2 -0
  55. data/app/views/user_plane/verification_mailer/address_verification.text.erb +4 -0
  56. data/app/views/user_plane/verification_mailer/password_reset.html.erb +2 -0
  57. data/app/views/user_plane/verification_mailer/password_reset.text.erb +4 -0
  58. data/config/initializers/inflections.rb +3 -0
  59. data/config/locales/en.yml +63 -0
  60. data/config/locales/it.yml +62 -0
  61. data/config/routes.rb +5 -0
  62. data/db/migrate/20121128143404_create_user_accounts.rb +11 -0
  63. data/db/migrate/20121226202553_create_user_identities_o_auths.rb +12 -0
  64. data/db/migrate/20121226203032_create_user_identities_emails.rb +13 -0
  65. data/db/migrate/20121227144617_create_user_identities_email_verifications.rb +15 -0
  66. data/db/migrate/20130113120152_create_user_identities_id_tokens.rb +12 -0
  67. data/db/migrate/20141025230304_create_user_sign_up_invites_stacks.rb +10 -0
  68. data/db/migrate/20141025230500_create_user_sign_up_invites_invites.rb +13 -0
  69. data/db/migrate/20141026230208_create_user_suspensions.rb +13 -0
  70. data/lib/generators/user_plane/view/details_generator.rb +22 -0
  71. data/lib/generators/user_plane/view/helpers.rb +68 -0
  72. data/lib/generators/user_plane/view/invites_generator.rb +23 -0
  73. data/lib/generators/user_plane/view/reset_passwords_generator.rb +22 -0
  74. data/lib/generators/user_plane/view/sign_ins_generator.rb +18 -0
  75. data/lib/generators/user_plane/view/sign_ups_generator.rb +22 -0
  76. data/lib/generators/user_plane/views_generator.rb +32 -0
  77. data/lib/tasks/user_plane_tasks.rake +4 -0
  78. data/lib/user_plane.rb +43 -0
  79. data/lib/user_plane/command.rb +24 -0
  80. data/lib/user_plane/engine.rb +27 -0
  81. data/lib/user_plane/fresh_validator.rb +9 -0
  82. data/lib/user_plane/omniauth.rb +50 -0
  83. data/lib/user_plane/redirect_to_sign_in.rb +22 -0
  84. data/lib/user_plane/route_concerns.rb +167 -0
  85. data/lib/user_plane/session_manager_concern.rb +9 -0
  86. data/lib/user_plane/signed_in_constraint.rb +11 -0
  87. data/lib/user_plane/token_segment.rb +52 -0
  88. data/lib/user_plane/version.rb +3 -0
  89. data/spec/controllers/user/confirm_email_addresses_controller_spec.rb +5 -0
  90. data/spec/controllers/user/details_controller_spec.rb +5 -0
  91. data/spec/controllers/user/invites_controller_spec.rb +19 -0
  92. data/spec/controllers/user/reset_passwords_controller_spec.rb +5 -0
  93. data/spec/controllers/user/sign_ins_controller_spec.rb +34 -0
  94. data/spec/controllers/user/sign_ups_controller_spec.rb +5 -0
  95. data/spec/dummy/README.rdoc +28 -0
  96. data/spec/dummy/Rakefile +6 -0
  97. data/spec/dummy/app/assets/javascripts/application.js +13 -0
  98. data/spec/dummy/app/assets/stylesheets/application.css +15 -0
  99. data/spec/dummy/app/controllers/application_controller.rb +7 -0
  100. data/spec/dummy/app/controllers/welcome_controller.rb +3 -0
  101. data/spec/dummy/app/helpers/application_helper.rb +2 -0
  102. data/spec/dummy/app/views/layouts/application.html.erb +30 -0
  103. data/spec/dummy/app/views/welcome/index.html.erb +1 -0
  104. data/spec/dummy/bin/bundle +3 -0
  105. data/spec/dummy/bin/rails +4 -0
  106. data/spec/dummy/bin/rake +4 -0
  107. data/spec/dummy/config.ru +4 -0
  108. data/spec/dummy/config/application.rb +30 -0
  109. data/spec/dummy/config/boot.rb +5 -0
  110. data/spec/dummy/config/database.yml +49 -0
  111. data/spec/dummy/config/environment.rb +5 -0
  112. data/spec/dummy/config/environments/development.rb +37 -0
  113. data/spec/dummy/config/environments/production.rb +78 -0
  114. data/spec/dummy/config/environments/test.rb +39 -0
  115. data/spec/dummy/config/initializers/assets.rb +8 -0
  116. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  117. data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
  118. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  119. data/spec/dummy/config/initializers/inflections.rb +16 -0
  120. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  121. data/spec/dummy/config/initializers/session_store.rb +3 -0
  122. data/spec/dummy/config/initializers/user_plane.rb +5 -0
  123. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  124. data/spec/dummy/config/locales/en.yml +23 -0
  125. data/spec/dummy/config/routes.rb +43 -0
  126. data/spec/dummy/config/secrets.yml +22 -0
  127. data/spec/dummy/db/schema.rb +101 -0
  128. data/spec/dummy/log/development.log +0 -0
  129. data/spec/dummy/log/test.log +20185 -0
  130. data/spec/dummy/public/404.html +67 -0
  131. data/spec/dummy/public/422.html +67 -0
  132. data/spec/dummy/public/500.html +66 -0
  133. data/spec/dummy/public/favicon.ico +0 -0
  134. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/-pOuxJZhYk_qXqMNKgm23KfvzyUW71NynNLlcNBOubE.cache +0 -0
  135. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/3AV9ywHBH56Leqey5LeznxK9vu4HD8fF3zSTk4MiDJA.cache +1 -0
  136. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/5fzR1G0D8ukHkPkLXsUu6rP6qV82aIdx3hugKkDy6nM.cache +0 -0
  137. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/9bKtJ2lkHPqtboGfbyknZ1OyH4xYO-aml7U3qhv-3kk.cache +0 -0
  138. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/HjDmE9SFP2wimdNHU8Nff9cm3vFZ5soO1iw7Jdlb6z8.cache +0 -0
  139. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/J9j6OdatarYW7VzVCVttmGphOhJKL0QXasdheyrgsTE.cache +2 -0
  140. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/KqrOQSlg0Th0N3XXx-h4p5BVJCfN0D8rRLoA9VxvXrc.cache +1 -0
  141. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/UCB1W65KwVU8ttOY8jnPRDp8HyyYYEjeTwwPD6R4qy8.cache +1 -0
  142. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/YmMSaaBmIcNZWPVF9jXcGBi-kwEzMuxzwPT_Zrcj1Bo.cache +2 -0
  143. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/g3wU8ajFWb5ZLPvujEt5l9DesbFCiAwqjx1WQgwTtHA.cache +1 -0
  144. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/i5pp88VHKoqlxQJdgmQd_lkgX1-4em_uHqNDjQ4nyHA.cache +0 -0
  145. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/jL74yXjxf8cb6Olkjbw1C28MH_HbZe221l8AI6WVeH0.cache +3 -0
  146. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/puh7X4rfS3eDN9oHTXoQdAgqxivonrwAAdYZ4UB3GIg.cache +1 -0
  147. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/qxPWFIWnE6gOCY-SsdBJe7Cgm5D3YUwaEne78Y7XdRg.cache +1 -0
  148. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/rM9s67WgzKMZ1bRhUdA0yhPZDlyRE5a1kmdt7cS6m4c.cache +3 -0
  149. data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/rVoG8EHlrCOgY4ZkzOj64f0jiTcbteQ_SYNzq9RqY0I.cache +0 -0
  150. data/spec/fabricators/user_account_fabricator.rb +11 -0
  151. data/spec/fabricators/user_guest_fabricator.rb +2 -0
  152. data/spec/fabricators/user_identities_email_fabricator.rb +8 -0
  153. data/spec/fabricators/user_identities_email_verification_fabricator.rb +5 -0
  154. data/spec/fabricators/user_identities_id_token_fabricator.rb +2 -0
  155. data/spec/fabricators/user_sign_up_fabricator.rb +51 -0
  156. data/spec/fabricators/user_sign_up_invites_invite_fabricator.rb +3 -0
  157. data/spec/fabricators/user_sign_up_invites_stack_fabricator.rb +4 -0
  158. data/spec/fabricators/user_suspension_fabricator.rb +4 -0
  159. data/spec/fabricators/user_update_detail_fabricator.rb +2 -0
  160. data/spec/features/user_plane/user_plane_invites_spec.rb +31 -0
  161. data/spec/features/user_plane/user_plane_reset_passwords_spec.rb +31 -0
  162. data/spec/features/user_plane/user_plane_sign_ins_spec.rb +44 -0
  163. data/spec/features/user_plane/user_plane_signed_in_only_spec.rb +31 -0
  164. data/spec/features/user_plane/user_plane_update_details_spec.rb +43 -0
  165. data/spec/fixtures/user_plane/invite_mailer/invite +3 -0
  166. data/spec/fixtures/user_plane/verification_mailer/address_verification +3 -0
  167. data/spec/fixtures/user_plane/verification_mailer/password_reset +3 -0
  168. data/spec/lib/generators/views_generator_spec.rb +16 -0
  169. data/spec/lib/route_concerns_spec.rb +54 -0
  170. data/spec/mailers/previews/user_plane/invite_mailer_preview.rb +11 -0
  171. data/spec/mailers/previews/user_plane/verification_mailer_preview.rb +16 -0
  172. data/spec/mailers/user_plane/invite_mailer_spec.rb +25 -0
  173. data/spec/mailers/user_plane/verification_mailer_spec.rb +52 -0
  174. data/spec/models/session_manager_spec.rb +28 -0
  175. data/spec/models/user/account_spec.rb +26 -0
  176. data/spec/models/user/confirm_email_address_spec.rb +101 -0
  177. data/spec/models/user/guest_spec.rb +5 -0
  178. data/spec/models/user/identities/email_spec.rb +5 -0
  179. data/spec/models/user/identities/email_verification_spec.rb +42 -0
  180. data/spec/models/user/identities/facebook_spec.rb +5 -0
  181. data/spec/models/user/identities/github_spec.rb +5 -0
  182. data/spec/models/user/identities/id_token_spec.rb +5 -0
  183. data/spec/models/user/identities/o_auth_spec.rb +12 -0
  184. data/spec/models/user/identities/twitter_spec.rb +5 -0
  185. data/spec/models/user/reset_password_spec.rb +141 -0
  186. data/spec/models/user/send_password_reset_spec.rb +44 -0
  187. data/spec/models/user/send_sign_up_invite_spec.rb +30 -0
  188. data/spec/models/user/sign_in_spec.rb +31 -0
  189. data/spec/models/user/sign_up_invites/invite_spec.rb +13 -0
  190. data/spec/models/user/sign_up_invites/stack_spec.rb +21 -0
  191. data/spec/models/user/sign_up_spec.rb +58 -0
  192. data/spec/models/user/sign_up_with_invite_spec.rb +83 -0
  193. data/spec/models/user/suspension_spec.rb +5 -0
  194. data/spec/models/user/update_details_spec.rb +98 -0
  195. data/spec/routing/invites_spec.rb +49 -0
  196. data/spec/routing/reset_passwords_spec.rb +31 -0
  197. data/spec/routing/sign_ins_spec.rb +36 -0
  198. data/spec/routing/update_details_spec.rb +30 -0
  199. data/spec/shared_contexts/feature_helpers.rb +12 -0
  200. data/spec/shared_contexts/routing.rb +8 -0
  201. data/spec/shared_contexts/user.rb +67 -0
  202. data/spec/spec_helper.rb +38 -0
  203. data/spec/support/fabrication.rb +7 -0
  204. data/spec/support/omniauth.rb +4 -0
  205. metadata +770 -0
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require 'shared_contexts/user'
3
+
4
+ RSpec.feature "SignedInOnly", type: :feature do
5
+ include_context 'user'
6
+
7
+ scenario 'trying to access a signed-in-only' do
8
+ visit '/signed_in_only'
9
+ expect(current_path).to eql(polymorphic_path([User::SignIn.new], action: :new))
10
+
11
+ fill_in 'Email', with: a_user.email.address
12
+ fill_in 'Password', with: a_user.email.password
13
+ click_button 'Sign In'
14
+
15
+ expect(current_path).to eql('/signed_in_only')
16
+ expect(page).to have_text 'You are successfully signed in.'
17
+ end
18
+
19
+ scenario 'trying to access a non-existing route when sigend in' do
20
+ visit '/non_existing'
21
+ expect(current_path).to eql(polymorphic_path([User::SignIn.new], action: :new))
22
+
23
+ fill_in 'Email', with: a_user.email.address
24
+ fill_in 'Password', with: a_user.email.password
25
+ click_button 'Sign In'
26
+
27
+ expect(current_path).to eql('/non_existing')
28
+ expect(page.status_code).to eq(404)
29
+ end
30
+
31
+ end
@@ -0,0 +1,43 @@
1
+ require 'spec_helper'
2
+ require 'shared_contexts/user'
3
+ require 'shared_contexts/feature_helpers'
4
+
5
+ RSpec.feature "UpdateDetails", type: :feature do
6
+ include_context 'user'
7
+ include_context 'feature_helpers'
8
+
9
+ scenario 'changing the email address' do
10
+ sign_in(a_user)
11
+
12
+ new_email = Faker::Internet.safe_email
13
+
14
+ visit polymorphic_path([User::UpdateDetails.new], action: :edit)
15
+ fill_in 'Email', with: new_email
16
+ click_button 'Update'
17
+
18
+ click_link 'Sign Out'
19
+
20
+ open_email(new_email)
21
+ current_email.click_link 'link'
22
+
23
+
24
+ visit polymorphic_path([User::SignIn.new], action: :new)
25
+ fill_in 'Email', with: new_email
26
+ fill_in 'Password', with: a_user.email.password
27
+ click_button 'Sign In'
28
+
29
+ expect(page).to have_text 'You are successfully signed in.'
30
+ # expect(current_path).to eql('/signed_in_only')
31
+ end
32
+
33
+ scenario 'changing the user name' do
34
+ sign_in(a_user)
35
+
36
+ visit polymorphic_path([User::UpdateDetails.new], action: :edit)
37
+ fill_in 'Name', with: 'marvin'
38
+ click_button 'Update'
39
+
40
+ expect(page).to have_selector('input[value="marvin"]')
41
+ end
42
+
43
+ end
@@ -0,0 +1,3 @@
1
+ InviteMailer#invite
2
+
3
+ Hi, find me in app/views/user_plane/invite_mailer/invite
@@ -0,0 +1,3 @@
1
+ VerificationMailer#address_verification
2
+
3
+ Hi, find me in app/views/user_plane/verification_mailer/address_verification
@@ -0,0 +1,3 @@
1
+ VerificationMailer#password_reset
2
+
3
+ Hi, find me in app/views/user_plane/verification_mailer/password_reset
@@ -0,0 +1,16 @@
1
+ require "spec_helper"
2
+ require 'generators/user_plane/views_generator'
3
+
4
+ describe UserPlane::Generators::ViewsGenerator, type: :generator do
5
+ destination Dir.mktmpdir
6
+
7
+ before(:each) do
8
+ prepare_destination
9
+ run_generator
10
+ end
11
+
12
+ it "creates a test initializer" do
13
+ assert_file 'app/views/user/invites/new.html.erb', /form_for\(@send_sign_up_invite\)/
14
+ assert_file 'app/views/user/invites/edit.html.erb', /form_for\(@sign_up_with_invite\)/
15
+ end
16
+ end
@@ -0,0 +1,54 @@
1
+ require 'spec_helper'
2
+
3
+ describe UserPlane::RouteConcerns::AbstractConcern do
4
+
5
+ let (:mapper) {double()}
6
+ before {allow(mapper).to receive(:namespace).and_yield}
7
+
8
+ let :init_options do
9
+ {module: 'baz'}
10
+ end
11
+
12
+ subject :a_resource_concern do
13
+ class ConcreteConcern < described_class
14
+ def build
15
+ mapper.resource options(as: :foo)
16
+ end
17
+ end
18
+
19
+ ConcreteConcern.new(init_options)
20
+ end
21
+
22
+ it 'combines options' do
23
+ allow(mapper).to receive(:resource_scope?).and_return(true)
24
+ expect(mapper).to receive(:resource).with(hash_including(as: :foo))
25
+ a_resource_concern.call(mapper)
26
+ end
27
+
28
+
29
+ context 'concern-specific options' do
30
+ subject :a_two_level_concern do
31
+ class ConcreteConcern < described_class
32
+ def build
33
+ foo_controller = concern_options.delete(:controller)
34
+ mapper.resource options
35
+ mapper.resource options(as: :foo, to: "#{foo_controller}#action")
36
+ end
37
+ end
38
+
39
+ ConcreteConcern.new(init_options)
40
+ end
41
+
42
+ it 'combines options' do
43
+ allow(mapper).to receive(:resource_scope?).and_return(true)
44
+
45
+ allow(mapper).to receive(:resource)
46
+ expect(mapper).to receive(:resource).with(hash_including(as: :foo, to: 'foo#action'))
47
+
48
+ a_two_level_concern.call(mapper, controller: :foo)
49
+ end
50
+ end
51
+
52
+ it 'removes :on if the route is not a resoucrce scope'
53
+
54
+ end
@@ -0,0 +1,11 @@
1
+ module UserPlane
2
+ # Preview all emails at http://localhost:3000/rails/mailers/user_plane/invite_mailer
3
+ class InviteMailerPreview < ActionMailer::Preview
4
+
5
+ # Preview this email at http://localhost:3000/rails/mailers/user_plane/invite_mailer/invite
6
+ def invite
7
+ InviteMailer.invite
8
+ end
9
+
10
+ end
11
+ end
@@ -0,0 +1,16 @@
1
+ module UserPlane
2
+ # Preview all emails at http://localhost:3000/rails/mailers/user_plane/verification_mailer
3
+ class VerificationMailerPreview < ActionMailer::Preview
4
+
5
+ # Preview this email at http://localhost:3000/rails/mailers/user_plane/verification_mailer/address_verification
6
+ def address_verification
7
+ VerificationMailer.address_verification
8
+ end
9
+
10
+ # Preview this email at http://localhost:3000/rails/mailers/user_plane/verification_mailer/password_reset
11
+ def password_reset
12
+ VerificationMailer.password_reset
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,25 @@
1
+ require "spec_helper"
2
+ require 'shared_contexts/user'
3
+
4
+
5
+ module UserPlane
6
+ describe InviteMailer, type: :mailer do
7
+ include_context 'user'
8
+
9
+ describe "invite" do
10
+
11
+ subject(:mail) { InviteMailer.invite a_sign_up_invite }
12
+
13
+ it "renders the headers" do
14
+ expect(mail.subject).to eq("Invite")
15
+ expect(mail.to).to eq([a_sign_up_invite.recipient])
16
+ expect(mail.from).to eq(["accounts@example.com"])
17
+ end
18
+
19
+ it "links to the sign up page" do
20
+ expect(mail.body.encoded).to match("http://example.com/invites/#{a_sign_up_invite.code}/redeem")
21
+ end
22
+ end
23
+
24
+ end
25
+ end
@@ -0,0 +1,52 @@
1
+ require "spec_helper"
2
+ require 'shared_contexts/user'
3
+
4
+
5
+ module UserPlane
6
+ describe VerificationMailer, type: :mailer do
7
+ include_context 'user'
8
+
9
+ describe "address_verification" do
10
+
11
+ let :address_verification do
12
+ a_user.email.unverified_address = Faker::Internet.safe_email
13
+ a_user.email.save!
14
+ User::ConfirmEmailAddress.new(verification: a_user.email.address_change_verification)
15
+ end
16
+
17
+ subject(:mail) { VerificationMailer.address_verification address_verification}
18
+
19
+ it "renders the headers" do
20
+ expect(mail.subject).to eq("Address verification")
21
+ expect(mail.to).to eq([address_verification.verification.recipient])
22
+ expect(mail.from).to eq(["accounts@example.com"])
23
+ end
24
+
25
+ it "renders the body" do
26
+ confirm_link = "http://example.com/account/confirm_email/#{address_verification.code}"
27
+ expect(mail.body.encoded).to match(confirm_link)
28
+ end
29
+ end
30
+
31
+ describe "password_reset" do
32
+
33
+ let :reset_password do
34
+ User::ResetPassword.new(verification: a_user.email.reset_password!)
35
+ end
36
+
37
+ subject(:mail) { VerificationMailer.password_reset reset_password}
38
+
39
+ it "renders the headers" do
40
+ expect(mail.subject).to eq("Password reset")
41
+ expect(mail.to).to eq([reset_password.verification.recipient])
42
+ expect(mail.from).to eq(["accounts@example.com"])
43
+ end
44
+
45
+ it "renders the body" do
46
+ reset_link = "http://example.com/account/reset_passwords/#{reset_password.code}/edit"
47
+ expect(mail.body.encoded).to match(reset_link)
48
+ end
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ describe SessionManager do
4
+ describe 'logging in' do
5
+ let(:account) { Fabricate(:user_with_email_identity) }
6
+ let(:session_manager) { SessionManager.new({}) }
7
+
8
+ it 'stores and retrieves a user account through an identity' do
9
+ session_manager.identity = account.identities.first
10
+ session_hash = session_manager.instance_variable_get '@session'
11
+ new_session = SessionManager.new(session_hash)
12
+ expect(new_session.identity).to eql(account.identities.first)
13
+ expect(new_session.account).to eql(account)
14
+ end
15
+
16
+
17
+ it 'goes stale after a few minutes' do
18
+ session_hash = session_manager.instance_variable_get '@session'
19
+ new_session_manager = SessionManager.new(session_hash)
20
+
21
+ Timecop.travel(90.minutes.from_now) do
22
+ expect(new_session_manager.identity).to be_nil
23
+ expect(new_session_manager.account).to be_a(User::Guest)
24
+ end
25
+ end
26
+
27
+ end
28
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'shared_contexts/user'
3
+
4
+ describe User::Account do
5
+ include_context 'user'
6
+
7
+ it 'must have an identity' do
8
+ new_user = described_class.new(name: Faker::Internet.user_name)
9
+ expect(new_user).not_to be_valid
10
+ end
11
+
12
+ it 'has a uuid'
13
+
14
+ describe 'an existing user' do
15
+
16
+ it 'can forget an identity'
17
+
18
+ it 'can be disabled' do
19
+ login_token = a_user.email.serialize
20
+
21
+ a_user.suspensions.create(message: "Dodgy account")
22
+
23
+ expect { User::Identity.deserialize!(login_token) }.to raise_error
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,101 @@
1
+ require 'spec_helper'
2
+ require 'shared_contexts/user'
3
+
4
+ describe User::ConfirmEmailAddress do
5
+ include_context 'user'
6
+ let (:new_address) { Faker::Internet.safe_email }
7
+ let! (:old_address) { a_user.email.address }
8
+
9
+ context 'with a valid confirmation token' do
10
+ let (:address_change_verification_token) do
11
+ address_verification = a_user.email.verifications.address_change_verification.create(recipient: new_address)
12
+ address_verification.token
13
+ end
14
+
15
+
16
+ subject :confirm_email_address do
17
+ described_class.new(code: address_change_verification_token)
18
+ end
19
+
20
+ it {is_expected.to be_valid}
21
+
22
+ it 'confirms the first email address' do
23
+ expect(a_user.email).to be_verified
24
+ end
25
+
26
+ it 'changes the email address' do
27
+ confirm_email_address.perform!
28
+ a_user.reload
29
+ expect(a_user.email.address).to eql(new_address)
30
+ end
31
+
32
+ context 'once performed' do
33
+ before do
34
+ confirm_email_address.perform!
35
+ a_user.reload
36
+ end
37
+
38
+ it 'spends the verification token' do
39
+ confirm_email_address.verification.reload
40
+ expect(confirm_email_address.verification).to be_spent
41
+ end
42
+
43
+ context 'cannot be redeemed anymore' do
44
+ subject :verifying_again do
45
+ verifying_again = described_class.new(code: address_change_verification_token)
46
+ verifying_again.valid?
47
+ verifying_again
48
+ end
49
+
50
+ it {is_expected.not_to be_valid}
51
+ it {expect(verifying_again.errors.messages[:code].size).to eq(1)}
52
+ end
53
+ end
54
+ end
55
+
56
+ context 'without a valid verification token' do
57
+ subject :confirmation_with_bad_token do
58
+ email_address_confirmation = described_class.new(code: 'not a valid token')
59
+ email_address_confirmation.valid?
60
+ email_address_confirmation
61
+ end
62
+
63
+ it {is_expected.not_to be_valid}
64
+ it {expect(confirmation_with_bad_token.errors.messages[:code].size).to eq(1)}
65
+ end
66
+
67
+ context 'with an expired verification' do
68
+ let (:stale_verification_token) do
69
+ Timecop.travel (2.weeks + 1.day).ago do
70
+ address_verification = a_user.email.verifications.address_change_verification.create(recipient: new_address)
71
+ address_verification.token
72
+ end
73
+ end
74
+
75
+ subject :confirmation_with_stale_token do
76
+ email_address_confirmation = described_class.new(code: stale_verification_token)
77
+ email_address_confirmation.valid?
78
+ email_address_confirmation
79
+ end
80
+
81
+ it {is_expected.not_to be_valid}
82
+ it {expect(confirmation_with_stale_token.errors.messages[:code].size).to eq(1)}
83
+ end
84
+
85
+ context 'when the address being verified is taken' do
86
+ let (:address_change_verification_token) do
87
+ address_verification = a_user.email.verifications.address_change_verification.create(recipient: new_address)
88
+ address_verification.token
89
+ end
90
+
91
+ subject :confirm_email_address do
92
+ conflicting_signup = Fabricate(:user_sign_up, email: new_address)
93
+ conflicting_signup.perform!
94
+
95
+ described_class.new(code: address_change_verification_token)
96
+ end
97
+
98
+ it {is_expected.not_to be_valid}
99
+ end
100
+
101
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe User::Guest, :type => :model do
4
+ pending "add some examples to (or delete) #{__FILE__}"
5
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe User::Identities::Email do
4
+ pending "add some examples to (or delete) #{__FILE__}"
5
+ end