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,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe User::Identities::EmailVerification do
4
+ subject :password_reset do
5
+ described_class.password_reset.create(recipient: Faker::Internet.safe_email)
6
+ end
7
+
8
+ it 'can be spent' do
9
+ password_reset.spend
10
+ expect(password_reset).to be_valid
11
+ end
12
+
13
+
14
+ context 'after two weeks' do
15
+ subject :old_password_reset do
16
+ verification_life_span = 2.weeks + 1.day
17
+ Timecop.travel verification_life_span.ago do
18
+ described_class.password_reset.create(recipient: Faker::Internet.safe_email)
19
+ end
20
+ end
21
+
22
+ it {is_expected.to be_stale}
23
+
24
+ it 'cannot be spent' do
25
+ old_password_reset.spend
26
+ expect(old_password_reset).not_to be_valid
27
+ end
28
+ end
29
+
30
+ context 'once spent' do
31
+ subject :spent_password_reset do
32
+ described_class.password_reset.create(recipient: Faker::Internet.safe_email, spent_at: Time.now)
33
+ end
34
+
35
+ it 'cannot be spent again' do
36
+ spent_password_reset.spend
37
+ expect(spent_password_reset).not_to be_valid
38
+ end
39
+
40
+ end
41
+
42
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe User::Identities::Facebook 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::Github 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::IdToken do
4
+ pending "add some examples to (or delete) #{__FILE__}"
5
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ require 'shared_contexts/user'
3
+
4
+ describe User::Identities::OAuth do
5
+ include_context 'user'
6
+
7
+ it 'creates the identity from oauth data' do
8
+ oauth_identity = described_class.find_or_build_from_omniauth(facebook_oauth_data)
9
+
10
+ expect(oauth_identity).to be_a(User::Identities::Facebook)
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe User::Identities::Twitter do
4
+ pending "add some examples to (or delete) #{__FILE__}"
5
+ end
@@ -0,0 +1,141 @@
1
+ require 'spec_helper'
2
+ require 'shared_contexts/user'
3
+
4
+ describe User::ResetPassword do
5
+ include_context 'user'
6
+
7
+ def validated_reset_password token, password, confirmation=nil
8
+ confirmation = password if confirmation.nil?
9
+ reset_password = described_class.new(code: token,
10
+ password: password,
11
+ password_confirmation: confirmation)
12
+ reset_password.valid?
13
+ reset_password
14
+ end
15
+
16
+
17
+ context 'with a valid reset token' do
18
+ let (:reset_token) do
19
+ password_reset_verification = a_user.email.reset_password!
20
+ password_reset_verification.token
21
+ end
22
+
23
+ let! (:old_password) {a_user.email.password}
24
+
25
+ context 'does not miss validation callbacks' do
26
+ subject :reset_password do
27
+ described_class.new(code: reset_token,
28
+ password: new_password,
29
+ password_confirmation: new_password)
30
+ end
31
+
32
+ it 'resets the password without skipping the before_validation' do
33
+ reset_password.perform
34
+ a_user.reload
35
+ expect(a_user.email.authenticate(new_password)).not_to be false
36
+ end
37
+ end
38
+
39
+ context 'and a valid password' do
40
+ subject :reset_password do
41
+ described_class.new(code: reset_token,
42
+ password: new_password,
43
+ password_confirmation: new_password)
44
+ end
45
+
46
+ it {is_expected.to be_valid}
47
+
48
+ it 'resets the password' do
49
+ reset_password.perform!
50
+ a_user.reload
51
+ expect(a_user.email.authenticate(new_password)).not_to be false
52
+ end
53
+
54
+ context 'once performed' do
55
+ before do
56
+ reset_password.perform!
57
+ a_user.reload
58
+ end
59
+
60
+ it 'spends the verification token' do
61
+ reset_password.verification.reload
62
+ expect(reset_password.verification).to be_spent
63
+ end
64
+
65
+ it 'the new password can be used to authenticate' do
66
+ expect(a_user.email.authenticate(new_password)).not_to be false
67
+ end
68
+
69
+ it 'a wrong password cannot be used to authenticate' do
70
+ expect(a_user.email.authenticate('not the new password')).to be false
71
+ end
72
+
73
+ it 'the old password cannot be used to authenticate' do
74
+ expect(a_user.email.authenticate(old_password)).to be false
75
+ end
76
+
77
+ it 'cannot be redeemed anymore' do
78
+ another_reset = described_class.new(code: reset_token,
79
+ password: new_password,
80
+ password_confirmation: new_password)
81
+ expect(another_reset).not_to be_valid
82
+ expect(another_reset.errors[:code].size).to eq(1)
83
+
84
+ end
85
+ end
86
+ end
87
+
88
+ context 'and a bad password' do
89
+
90
+
91
+ let :empty_reset_password do
92
+ validated_reset_password(reset_token, '')
93
+ end
94
+
95
+ let :short_reset_password do
96
+ validated_reset_password(reset_token, 'pw')
97
+ end
98
+
99
+ let :mismatching_reset_password do
100
+ validated_reset_password(reset_token, new_password, 'mismatching confirmation')
101
+ end
102
+
103
+ it 'does not allow empty passwords' do
104
+ expect(empty_reset_password.errors.messages[:password].size).to eq(1)
105
+ end
106
+
107
+ it 'validates password length' do
108
+ expect(short_reset_password.errors.messages[:password].size).to eq(1)
109
+ end
110
+
111
+ it 'requires confirmation' do
112
+ expect(mismatching_reset_password.errors.messages[:password_confirmation].size).to eq(1)
113
+ end
114
+ end
115
+ end
116
+
117
+ context 'without a valid reset token' do
118
+ subject :reset_password do
119
+ validated_reset_password('invalid token', new_password)
120
+ end
121
+
122
+ it {expect {subject}.to raise_error ActiveRecord::RecordNotFound}
123
+ end
124
+
125
+ context 'with an expired verification token' do
126
+ let (:stale_verification_token) do
127
+ Timecop.travel (2.weeks + 1.day).ago do
128
+ address_verification = a_user.email.reset_password!
129
+ address_verification.token
130
+ end
131
+ end
132
+
133
+ subject :reset_password_with_stale_token do
134
+ validated_reset_password(stale_verification_token, new_password)
135
+ end
136
+
137
+ it {is_expected.not_to be_valid}
138
+ it {expect(reset_password_with_stale_token.errors.messages[:code].size).to eq(1)}
139
+ end
140
+
141
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ require 'shared_contexts/user'
3
+
4
+ describe User::SendPasswordReset, type: :model do
5
+ include_context 'user'
6
+
7
+ let :dummy_verification do
8
+ double(User::Identities::EmailVerification, save: true, token: '123456')
9
+ end
10
+
11
+ context 'resetting the password for an existing account' do
12
+ subject(:send_reset) {described_class.new(email: a_user.email.address)}
13
+
14
+ it 'has a verification code' do
15
+ send_reset.perform!
16
+ expect(send_reset.code).not_to be_nil
17
+ end
18
+
19
+ it 'does create an email verification' do
20
+ expect(User::Identities::EmailVerification).to receive(:new).and_return(dummy_verification)
21
+ send_reset.perform!
22
+ end
23
+ end
24
+
25
+ context 'with an unknown email address' do
26
+ before do
27
+ allow(User::Identities::Email).to receive(:find_by_address).and_return(nil)
28
+ end
29
+
30
+ subject(:send_reset) {described_class.new(email: 'dont.find.me@example.com')}
31
+
32
+ it {is_expected.to be_valid}
33
+
34
+ it 'has no verification code' do
35
+ send_reset.perform!
36
+ expect(send_reset.code).to be_nil
37
+ end
38
+
39
+ it 'does not create an email verification' do
40
+ expect(User::Identities::EmailVerification).not_to receive(:new)
41
+ send_reset.perform!
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+ require 'shared_contexts/user'
3
+
4
+ describe User::SendSignUpInvite do
5
+ include_context 'user'
6
+
7
+ subject(:send_invite) {described_class.new(sender: a_user, recipient: invite_recipient)}
8
+
9
+ context 'When the sender has one invite remaining' do
10
+ before do
11
+ a_user.invites_stack.update({remaining_invites: 1})
12
+ end
13
+
14
+ it 'is used to send invites' do
15
+ send_invite.perform!
16
+ expect(send_invite.invite).not_to be_nil
17
+ expect(send_invite.stack.remaining_invites).to eq(0)
18
+ end
19
+ end
20
+
21
+ context 'if the user has no invites left' do
22
+ before do
23
+ a_user.invites_stack.update({remaining_invites: 0})
24
+ end
25
+
26
+ it 'is used to send invites' do
27
+ expect(send_invite).not_to be_valid
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+ require 'shared_contexts/user'
3
+
4
+ describe User::SignIn do
5
+ include_context 'user'
6
+
7
+ context 'with a valid email/password combination' do
8
+ subject :sign_in do
9
+ described_class.new(email: a_user.email.address,
10
+ password: a_user.email.password)
11
+ .sign_in_with(User::Identities::Email)
12
+ end
13
+
14
+ it {is_expected.to be_valid}
15
+ end
16
+
17
+ context 'with a bad email/password combination' do
18
+ subject :sign_in do
19
+ described_class.new(email: a_user.email.address,
20
+ password: '')
21
+ .sign_in_with(User::Identities::Email)
22
+ end
23
+
24
+ before {subject.valid?}
25
+
26
+ it {is_expected.not_to be_valid}
27
+ it {expect(subject.errors).to include(:base)}
28
+ it {expect(subject.errors).not_to include(:identity)}
29
+ end
30
+
31
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe User::SignUpInvites::Invite, type: :model do
4
+ context 'validates the recipient format' do
5
+ subject(:invite) { described_class.new(recipient: 'not a vaild email') }
6
+
7
+ it 'is not allowed more invites' do
8
+ expect(invite).not_to be_valid
9
+ end
10
+ end
11
+ end
12
+
13
+
@@ -0,0 +1,21 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe User::SignUpInvites::Stack, :type => :model do
4
+
5
+ subject(:invites_stack) {described_class.create(remaining_invites: 2)}
6
+
7
+ it 'decrements the available invites' do
8
+ invites_stack.invites.create(recipient: Faker::Internet.safe_email)
9
+ expect(invites_stack.remaining_invites).to eql(1)
10
+ end
11
+
12
+ context 'when the stack is out of invites' do
13
+ subject(:dry_invites_stack) {described_class.create(remaining_invites: 0)}
14
+
15
+ it 'is not allowed more invites' do
16
+ new_invite = dry_invites_stack.invites.create(recipient: Faker::Internet.safe_email)
17
+ expect(dry_invites_stack).not_to be_valid
18
+ end
19
+ end
20
+
21
+ end
@@ -0,0 +1,58 @@
1
+ require 'spec_helper'
2
+ require 'shared_contexts/user'
3
+
4
+ describe User::SignUp do
5
+ include_context 'user'
6
+
7
+ context 'with valid details' do
8
+ subject :sign_up do
9
+ p = 'some secret'
10
+ sign_up = described_class.new(user_name: 'foo',
11
+ email: 'foo@example.com',
12
+ password: p,
13
+ password_confirmation: p)
14
+ sign_up.sign_up_with(User::Identities::Email)
15
+ end
16
+
17
+ it {is_expected.to be_valid}
18
+
19
+ context 'succeeds' do
20
+ before {sign_up.perform!}
21
+
22
+ it {expect { User::Account.find(sign_up.account.id) }.to_not raise_error}
23
+ end
24
+ end
25
+
26
+ context 'with bad details' do
27
+ subject :new_sign_up do
28
+ sign_up = described_class.new(user_name: a_user.name,
29
+ email: a_user.email.address,
30
+ password: p,
31
+ password_confirmation: p)
32
+ sign_up.sign_up_with(User::Identities::Email)
33
+ end
34
+
35
+ before {new_sign_up.valid?}
36
+
37
+ it {is_expected.not_to be_valid}
38
+ it {expect(new_sign_up.errors).to include(:email)}
39
+ it {expect(new_sign_up.errors).not_to include(:email_identity)}
40
+ end
41
+
42
+ context 'with social media' do
43
+ it 'can be invited and register with twitter'
44
+
45
+ context 'can be created logging in with facebook' do
46
+ # User fills up the signup form with his user name and clicks to register with facebook
47
+ subject :sign_up do
48
+ sign_up = described_class.new(user_name: Faker::Internet.user_name,
49
+ oauth_data: facebook_oauth_data)
50
+ sign_up.sign_up_with(User::Identities::OAuth)
51
+ end
52
+
53
+ it {is_expected.to be_valid}
54
+ it {expect(sign_up.identity).to be_a(User::Identities::Facebook)}
55
+ end
56
+ end
57
+
58
+ end
@@ -0,0 +1,83 @@
1
+ require 'spec_helper'
2
+ require 'shared_contexts/user'
3
+
4
+ describe User::SignUpWithInvite do
5
+ include_context 'user'
6
+
7
+ context 'without an invite' do
8
+ subject :sign_up_without_invite do
9
+ sign_up = described_class.new(user_name: invite_recipient_user_name,
10
+ email: Faker::Internet.safe_email,
11
+ password: new_password,
12
+ password_confirmation: new_password)
13
+ end
14
+
15
+ before {sign_up_without_invite.valid?}
16
+
17
+ it {is_expected.not_to be_valid}
18
+ it {expect(sign_up_without_invite.errors).to include(:invite)}
19
+ end
20
+
21
+ context 'with a spent invite' do
22
+
23
+ let :spent_invite do
24
+ a_user.create_invite! recipient: invite_recipient
25
+ end
26
+
27
+ subject :sign_up_with_spent_invite do
28
+ user_name = Faker::Internet.user_name
29
+ sign_up = described_class.new(user_name: user_name,
30
+ code: spent_invite.code,
31
+ email: "#{user_name}@example.com",
32
+ password: new_password,
33
+ password_confirmation: new_password)
34
+ sign_up.sign_up_with(User::Identities::Email)
35
+ end
36
+
37
+ before {sign_up_with_spent_invite.valid?}
38
+
39
+ it {is_expected.not_to be_valid}
40
+ it {expect(sign_up_with_spent_invite.errors).to include(:invite)}
41
+ end
42
+
43
+ context 'with an invite' do
44
+ subject :sign_up_with_invite do
45
+ sign_up = described_class.new(user_name: invite_recipient,
46
+ code: a_sign_up_invite.code,
47
+ email: a_sign_up_invite.recipient,
48
+ password: new_password,
49
+ password_confirmation: new_password)
50
+ sign_up.sign_up_with(User::Identities::Email)
51
+ end
52
+
53
+ it {expect { sign_up_with_invite.perform! }.to_not raise_error}
54
+
55
+ end
56
+
57
+ context 'when redeemed' do
58
+ subject :sign_up_with_invite do
59
+ sign_up = described_class.new(user_name: invite_recipient,
60
+ code: a_sign_up_invite.code,
61
+ email: a_sign_up_invite.recipient,
62
+ password: new_password,
63
+ password_confirmation: new_password)
64
+ sign_up.sign_up_with(User::Identities::Email)
65
+ end
66
+
67
+ before {sign_up_with_invite.perform!}
68
+
69
+ it { expect(User::Account.where(id: sign_up_with_invite.account.id)).to exist }
70
+ end
71
+
72
+ it 'can be created logging in with facebook' do
73
+ # User fills up the signup form with his user name and clicks to register with facebook
74
+ sign_up = described_class.new(code: a_sign_up_invite.code,
75
+ oauth_data: facebook_oauth_data)
76
+ sign_up.sign_up_with(User::Identities::OAuth)
77
+
78
+ expect(sign_up).to be_valid
79
+ expect(sign_up.identity).to be_a(User::Identities::Facebook)
80
+ sign_up.perform
81
+ end
82
+
83
+ end