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.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/Rakefile +30 -0
- data/app/assets/javascripts/user_plane/application.js +13 -0
- data/app/assets/stylesheets/user_plane/application.css +15 -0
- data/app/concerns/null_object_persistable.rb +62 -0
- data/app/controllers/user/confirm_email_addresses_controller.rb +17 -0
- data/app/controllers/user/details_controller.rb +48 -0
- data/app/controllers/user/invites_controller.rb +69 -0
- data/app/controllers/user/reset_passwords_controller.rb +50 -0
- data/app/controllers/user/sign_ins_controller.rb +53 -0
- data/app/controllers/user/sign_ups_controller.rb +47 -0
- data/app/controllers/user_plane/application_controller.rb +5 -0
- data/app/helpers/user_plane/application_helper.rb +4 -0
- data/app/mailers/user_plane/application_mailer.rb +8 -0
- data/app/mailers/user_plane/invite_mailer.rb +14 -0
- data/app/mailers/user_plane/verification_mailer.rb +25 -0
- data/app/models/session_manager.rb +100 -0
- data/app/models/user.rb +5 -0
- data/app/models/user/account.rb +26 -0
- data/app/models/user/confirm_email_address.rb +55 -0
- data/app/models/user/guest.rb +18 -0
- data/app/models/user/identities.rb +5 -0
- data/app/models/user/identities/email.rb +98 -0
- data/app/models/user/identities/email_verification.rb +70 -0
- data/app/models/user/identities/facebook.rb +5 -0
- data/app/models/user/identities/github.rb +5 -0
- data/app/models/user/identities/id_token.rb +7 -0
- data/app/models/user/identities/o_auth.rb +67 -0
- data/app/models/user/identities/o_auth_endpoint.rb +28 -0
- data/app/models/user/identities/twitter.rb +5 -0
- data/app/models/user/identity.rb +26 -0
- data/app/models/user/reset_password.rb +59 -0
- data/app/models/user/send_password_reset.rb +25 -0
- data/app/models/user/send_sign_up_invite.rb +27 -0
- data/app/models/user/sign_in.rb +42 -0
- data/app/models/user/sign_up.rb +47 -0
- data/app/models/user/sign_up_invites.rb +5 -0
- data/app/models/user/sign_up_invites/invite.rb +46 -0
- data/app/models/user/sign_up_invites/stack.rb +22 -0
- data/app/models/user/sign_up_with_invite.rb +45 -0
- data/app/models/user/suspension.rb +7 -0
- data/app/models/user/update_details.rb +103 -0
- data/app/views/layouts/user_plane/application.html.erb +14 -0
- data/app/views/user/details/edit.html.erb +37 -0
- data/app/views/user/invites/edit.html.erb +34 -0
- data/app/views/user/invites/new.html.erb +21 -0
- data/app/views/user/reset_passwords/edit.html.erb +26 -0
- data/app/views/user/reset_passwords/new.html.erb +21 -0
- data/app/views/user/sign_ins/new.html.erb +25 -0
- data/app/views/user/sign_ups/new.html.erb +33 -0
- data/app/views/user_plane/invite_mailer/invite.html.erb +2 -0
- data/app/views/user_plane/invite_mailer/invite.text.erb +3 -0
- data/app/views/user_plane/verification_mailer/address_verification.html.erb +2 -0
- data/app/views/user_plane/verification_mailer/address_verification.text.erb +4 -0
- data/app/views/user_plane/verification_mailer/password_reset.html.erb +2 -0
- data/app/views/user_plane/verification_mailer/password_reset.text.erb +4 -0
- data/config/initializers/inflections.rb +3 -0
- data/config/locales/en.yml +63 -0
- data/config/locales/it.yml +62 -0
- data/config/routes.rb +5 -0
- data/db/migrate/20121128143404_create_user_accounts.rb +11 -0
- data/db/migrate/20121226202553_create_user_identities_o_auths.rb +12 -0
- data/db/migrate/20121226203032_create_user_identities_emails.rb +13 -0
- data/db/migrate/20121227144617_create_user_identities_email_verifications.rb +15 -0
- data/db/migrate/20130113120152_create_user_identities_id_tokens.rb +12 -0
- data/db/migrate/20141025230304_create_user_sign_up_invites_stacks.rb +10 -0
- data/db/migrate/20141025230500_create_user_sign_up_invites_invites.rb +13 -0
- data/db/migrate/20141026230208_create_user_suspensions.rb +13 -0
- data/lib/generators/user_plane/view/details_generator.rb +22 -0
- data/lib/generators/user_plane/view/helpers.rb +68 -0
- data/lib/generators/user_plane/view/invites_generator.rb +23 -0
- data/lib/generators/user_plane/view/reset_passwords_generator.rb +22 -0
- data/lib/generators/user_plane/view/sign_ins_generator.rb +18 -0
- data/lib/generators/user_plane/view/sign_ups_generator.rb +22 -0
- data/lib/generators/user_plane/views_generator.rb +32 -0
- data/lib/tasks/user_plane_tasks.rake +4 -0
- data/lib/user_plane.rb +43 -0
- data/lib/user_plane/command.rb +24 -0
- data/lib/user_plane/engine.rb +27 -0
- data/lib/user_plane/fresh_validator.rb +9 -0
- data/lib/user_plane/omniauth.rb +50 -0
- data/lib/user_plane/redirect_to_sign_in.rb +22 -0
- data/lib/user_plane/route_concerns.rb +167 -0
- data/lib/user_plane/session_manager_concern.rb +9 -0
- data/lib/user_plane/signed_in_constraint.rb +11 -0
- data/lib/user_plane/token_segment.rb +52 -0
- data/lib/user_plane/version.rb +3 -0
- data/spec/controllers/user/confirm_email_addresses_controller_spec.rb +5 -0
- data/spec/controllers/user/details_controller_spec.rb +5 -0
- data/spec/controllers/user/invites_controller_spec.rb +19 -0
- data/spec/controllers/user/reset_passwords_controller_spec.rb +5 -0
- data/spec/controllers/user/sign_ins_controller_spec.rb +34 -0
- data/spec/controllers/user/sign_ups_controller_spec.rb +5 -0
- data/spec/dummy/README.rdoc +28 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/app/assets/javascripts/application.js +13 -0
- data/spec/dummy/app/assets/stylesheets/application.css +15 -0
- data/spec/dummy/app/controllers/application_controller.rb +7 -0
- data/spec/dummy/app/controllers/welcome_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +30 -0
- data/spec/dummy/app/views/welcome/index.html.erb +1 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +30 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +49 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +78 -0
- data/spec/dummy/config/environments/test.rb +39 -0
- data/spec/dummy/config/initializers/assets.rb +8 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/spec/dummy/config/initializers/inflections.rb +16 -0
- data/spec/dummy/config/initializers/mime_types.rb +4 -0
- data/spec/dummy/config/initializers/session_store.rb +3 -0
- data/spec/dummy/config/initializers/user_plane.rb +5 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +23 -0
- data/spec/dummy/config/routes.rb +43 -0
- data/spec/dummy/config/secrets.yml +22 -0
- data/spec/dummy/db/schema.rb +101 -0
- data/spec/dummy/log/development.log +0 -0
- data/spec/dummy/log/test.log +20185 -0
- data/spec/dummy/public/404.html +67 -0
- data/spec/dummy/public/422.html +67 -0
- data/spec/dummy/public/500.html +66 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/-pOuxJZhYk_qXqMNKgm23KfvzyUW71NynNLlcNBOubE.cache +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/3AV9ywHBH56Leqey5LeznxK9vu4HD8fF3zSTk4MiDJA.cache +1 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/5fzR1G0D8ukHkPkLXsUu6rP6qV82aIdx3hugKkDy6nM.cache +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/9bKtJ2lkHPqtboGfbyknZ1OyH4xYO-aml7U3qhv-3kk.cache +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/HjDmE9SFP2wimdNHU8Nff9cm3vFZ5soO1iw7Jdlb6z8.cache +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/J9j6OdatarYW7VzVCVttmGphOhJKL0QXasdheyrgsTE.cache +2 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/KqrOQSlg0Th0N3XXx-h4p5BVJCfN0D8rRLoA9VxvXrc.cache +1 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/UCB1W65KwVU8ttOY8jnPRDp8HyyYYEjeTwwPD6R4qy8.cache +1 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/YmMSaaBmIcNZWPVF9jXcGBi-kwEzMuxzwPT_Zrcj1Bo.cache +2 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/g3wU8ajFWb5ZLPvujEt5l9DesbFCiAwqjx1WQgwTtHA.cache +1 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/i5pp88VHKoqlxQJdgmQd_lkgX1-4em_uHqNDjQ4nyHA.cache +0 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/jL74yXjxf8cb6Olkjbw1C28MH_HbZe221l8AI6WVeH0.cache +3 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/puh7X4rfS3eDN9oHTXoQdAgqxivonrwAAdYZ4UB3GIg.cache +1 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/qxPWFIWnE6gOCY-SsdBJe7Cgm5D3YUwaEne78Y7XdRg.cache +1 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/rM9s67WgzKMZ1bRhUdA0yhPZDlyRE5a1kmdt7cS6m4c.cache +3 -0
- data/spec/dummy/tmp/cache/assets/test/sprockets/v3.0/rVoG8EHlrCOgY4ZkzOj64f0jiTcbteQ_SYNzq9RqY0I.cache +0 -0
- data/spec/fabricators/user_account_fabricator.rb +11 -0
- data/spec/fabricators/user_guest_fabricator.rb +2 -0
- data/spec/fabricators/user_identities_email_fabricator.rb +8 -0
- data/spec/fabricators/user_identities_email_verification_fabricator.rb +5 -0
- data/spec/fabricators/user_identities_id_token_fabricator.rb +2 -0
- data/spec/fabricators/user_sign_up_fabricator.rb +51 -0
- data/spec/fabricators/user_sign_up_invites_invite_fabricator.rb +3 -0
- data/spec/fabricators/user_sign_up_invites_stack_fabricator.rb +4 -0
- data/spec/fabricators/user_suspension_fabricator.rb +4 -0
- data/spec/fabricators/user_update_detail_fabricator.rb +2 -0
- data/spec/features/user_plane/user_plane_invites_spec.rb +31 -0
- data/spec/features/user_plane/user_plane_reset_passwords_spec.rb +31 -0
- data/spec/features/user_plane/user_plane_sign_ins_spec.rb +44 -0
- data/spec/features/user_plane/user_plane_signed_in_only_spec.rb +31 -0
- data/spec/features/user_plane/user_plane_update_details_spec.rb +43 -0
- data/spec/fixtures/user_plane/invite_mailer/invite +3 -0
- data/spec/fixtures/user_plane/verification_mailer/address_verification +3 -0
- data/spec/fixtures/user_plane/verification_mailer/password_reset +3 -0
- data/spec/lib/generators/views_generator_spec.rb +16 -0
- data/spec/lib/route_concerns_spec.rb +54 -0
- data/spec/mailers/previews/user_plane/invite_mailer_preview.rb +11 -0
- data/spec/mailers/previews/user_plane/verification_mailer_preview.rb +16 -0
- data/spec/mailers/user_plane/invite_mailer_spec.rb +25 -0
- data/spec/mailers/user_plane/verification_mailer_spec.rb +52 -0
- data/spec/models/session_manager_spec.rb +28 -0
- data/spec/models/user/account_spec.rb +26 -0
- data/spec/models/user/confirm_email_address_spec.rb +101 -0
- data/spec/models/user/guest_spec.rb +5 -0
- data/spec/models/user/identities/email_spec.rb +5 -0
- data/spec/models/user/identities/email_verification_spec.rb +42 -0
- data/spec/models/user/identities/facebook_spec.rb +5 -0
- data/spec/models/user/identities/github_spec.rb +5 -0
- data/spec/models/user/identities/id_token_spec.rb +5 -0
- data/spec/models/user/identities/o_auth_spec.rb +12 -0
- data/spec/models/user/identities/twitter_spec.rb +5 -0
- data/spec/models/user/reset_password_spec.rb +141 -0
- data/spec/models/user/send_password_reset_spec.rb +44 -0
- data/spec/models/user/send_sign_up_invite_spec.rb +30 -0
- data/spec/models/user/sign_in_spec.rb +31 -0
- data/spec/models/user/sign_up_invites/invite_spec.rb +13 -0
- data/spec/models/user/sign_up_invites/stack_spec.rb +21 -0
- data/spec/models/user/sign_up_spec.rb +58 -0
- data/spec/models/user/sign_up_with_invite_spec.rb +83 -0
- data/spec/models/user/suspension_spec.rb +5 -0
- data/spec/models/user/update_details_spec.rb +98 -0
- data/spec/routing/invites_spec.rb +49 -0
- data/spec/routing/reset_passwords_spec.rb +31 -0
- data/spec/routing/sign_ins_spec.rb +36 -0
- data/spec/routing/update_details_spec.rb +30 -0
- data/spec/shared_contexts/feature_helpers.rb +12 -0
- data/spec/shared_contexts/routing.rb +8 -0
- data/spec/shared_contexts/user.rb +67 -0
- data/spec/spec_helper.rb +38 -0
- data/spec/support/fabrication.rb +7 -0
- data/spec/support/omniauth.rb +4 -0
- 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,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,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
|