mno-enterprise-core 3.1.4 → 3.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/images/mno_enterprise/logo-intuit.png +0 -0
- data/app/assets/images/mno_enterprise/main-logo.png +0 -0
- data/app/assets/stylesheets/mno_enterprise/mail.css +1 -4
- data/app/controllers/mno_enterprise/application_controller.rb +1 -1
- data/app/helpers/mno_enterprise/application_helper.rb +7 -7
- data/app/models/mno_enterprise/app.rb +12 -3
- data/app/models/mno_enterprise/app_answer.rb +13 -0
- data/app/models/mno_enterprise/app_comment.rb +10 -0
- data/app/models/mno_enterprise/app_feedback.rb +7 -0
- data/app/models/mno_enterprise/app_question.rb +9 -0
- data/app/models/mno_enterprise/app_review.rb +7 -0
- data/app/models/mno_enterprise/base_resource.rb +6 -1
- data/app/models/mno_enterprise/identity.rb +24 -0
- data/app/models/mno_enterprise/impac/alert.rb +10 -0
- data/app/models/mno_enterprise/impac/dashboard.rb +10 -11
- data/app/models/mno_enterprise/impac/kpi.rb +4 -2
- data/app/models/mno_enterprise/impac/widget.rb +4 -1
- data/app/models/mno_enterprise/team.rb +1 -33
- data/app/models/mno_enterprise/user.rb +109 -28
- data/app/views/system_notifications/email-change.html.erb +27 -0
- data/app/views/system_notifications/email-change.text.erb +10 -0
- data/app/views/system_notifications/password-change.html.erb +25 -0
- data/app/views/system_notifications/password-change.text.erb +7 -0
- data/app/views/system_notifications/reconfirmation-instructions.html.erb +7 -5
- data/app/views/system_notifications/reconfirmation-instructions.text.erb +3 -2
- data/config/initializers/config.rb +5 -0
- data/config/locales/models/user/en.yml +5 -0
- data/config/locales/templates/components/en.yml +9 -0
- data/config/locales/templates/dashboard/en.yml +14 -0
- data/config/locales/templates/dashboard/marketplace/en.yml +111 -8
- data/config/locales/templates/dashboard/organization/en.yml +1 -0
- data/config/locales/templates/impac/dock/en.yml +28 -0
- data/config/locales/views/auth/shared/en.yml +1 -2
- data/config/locales/views/webhook/o_auth/providers/en.yml +11 -6
- data/lib/devise/hooks/lockable.rb +13 -0
- data/lib/devise/models/remote_authenticatable.rb +31 -5
- data/lib/generators/mno_enterprise/install/install_generator.rb +7 -0
- data/lib/generators/mno_enterprise/install/templates/Procfile +1 -1
- data/lib/generators/mno_enterprise/install/templates/Procfile.dev +1 -1
- data/lib/generators/mno_enterprise/install/templates/config/application.yml +17 -0
- data/lib/generators/mno_enterprise/install/templates/config/initializers/mno_enterprise.rb +8 -3
- data/lib/generators/mno_enterprise/install/templates/config/newrelic.yml +46 -0
- data/lib/generators/mno_enterprise/install/templates/config/puma.rb +56 -0
- data/lib/generators/mno_enterprise/install/templates/config/settings/production.yml +1 -1
- data/lib/generators/mno_enterprise/install/templates/config/settings/uat.yml +1 -1
- data/lib/generators/mno_enterprise/install/templates/config/settings.yml +21 -0
- data/lib/generators/mno_enterprise/install/templates/stylesheets/variables.less +3 -0
- data/lib/her_extension/model/associations/association_proxy.rb +10 -6
- data/lib/mno_enterprise/concerns/controllers/auth/confirmations_controller.rb +1 -1
- data/lib/mno_enterprise/concerns/controllers/auth/omniauth_callbacks_controller.rb +203 -0
- data/lib/mno_enterprise/concerns/models/ability.rb +28 -0
- data/lib/mno_enterprise/concerns/models/app_instance.rb +22 -4
- data/lib/mno_enterprise/concerns/models/intercom_user.rb +28 -0
- data/lib/mno_enterprise/concerns/models/organization.rb +14 -1
- data/lib/mno_enterprise/concerns/models/team.rb +67 -0
- data/lib/mno_enterprise/core.rb +22 -3
- data/lib/mno_enterprise/impac_client.rb +19 -0
- data/lib/mno_enterprise/mail_adapters/mandrill_adapter.rb +4 -1
- data/lib/mno_enterprise/testing_support/factories/app_review.rb +51 -0
- data/lib/mno_enterprise/testing_support/factories/apps.rb +12 -10
- data/lib/mno_enterprise/testing_support/factories/identity.rb +9 -0
- data/lib/mno_enterprise/testing_support/factories/impac/alerts.rb +18 -0
- data/lib/mno_enterprise/testing_support/factories/impac/kpis.rb +5 -9
- data/lib/mno_enterprise/testing_support/factories/users.rb +4 -0
- data/lib/mno_enterprise/testing_support/jpi_v1_test_helper.rb +39 -0
- data/lib/mno_enterprise/testing_support/organizations_shared_helpers.rb +2 -1
- data/lib/mno_enterprise/testing_support/shared_examples/jpi_v1_admin.rb +38 -0
- data/lib/mno_enterprise/version.rb +1 -1
- data/spec/lib/devise/model/remote_authenticable_spec.rb +76 -0
- data/spec/lib/mno_enterprise/impac_client_spec.rb +31 -0
- data/spec/mno_enterprise_spec.rb +7 -8
- data/spec/models/mno_enterprise/app_spec.rb +1 -1
- data/spec/models/mno_enterprise/identity_spec.rb +39 -0
- data/spec/models/mno_enterprise/organization_spec.rb +19 -2
- data/spec/models/mno_enterprise/user_spec.rb +238 -0
- metadata +86 -22
@@ -0,0 +1,18 @@
|
|
1
|
+
FactoryGirl.define do
|
2
|
+
|
3
|
+
factory :mno_enterprise_impac_alert, :class => 'Impac::Alert' do
|
4
|
+
factory :impac_alert, class: MnoEnterprise::Impac::Alert do
|
5
|
+
|
6
|
+
sequence(:id) { |n| n }
|
7
|
+
# Mno-hub is sending back a impac_kpi_id, and with Her, the factory objects aren't working so well...
|
8
|
+
# kpi { build(:impac_kpi).attributes }
|
9
|
+
impac_kpi_id 1
|
10
|
+
service "inapp"
|
11
|
+
title "Test Alert"
|
12
|
+
recipients [{id: 1, email: 'test@maestrano.com'}]
|
13
|
+
|
14
|
+
# Properly build the resource with Her
|
15
|
+
initialize_with { new(attributes).tap { |e| e.clear_attribute_changes! } }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -1,17 +1,13 @@
|
|
1
1
|
FactoryGirl.define do
|
2
|
-
|
2
|
+
|
3
3
|
factory :mno_enterprise_impac_kpi, :class => 'Impac::Kpi' do
|
4
4
|
factory :impac_kpi, class: MnoEnterprise::Impac::Kpi do
|
5
|
-
|
5
|
+
|
6
6
|
sequence(:id) { |n| n }
|
7
7
|
dashboard { build(:impac_dashboard).attributes }
|
8
|
-
endpoint "
|
9
|
-
element_watched "
|
10
|
-
|
11
|
-
targets {}
|
12
|
-
settings {}
|
13
|
-
extra_params {}
|
14
|
-
|
8
|
+
endpoint "finance/revenue"
|
9
|
+
element_watched "evolution"
|
10
|
+
|
15
11
|
# Properly build the resource with Her
|
16
12
|
initialize_with { new(attributes).tap { |e| e.clear_attribute_changes! } }
|
17
13
|
end
|
@@ -46,6 +46,10 @@ FactoryGirl.define do
|
|
46
46
|
organizations { [build(:organization).attributes] }
|
47
47
|
end
|
48
48
|
|
49
|
+
trait :kpi_enabled do
|
50
|
+
kpi_enabled true
|
51
|
+
end
|
52
|
+
|
49
53
|
# Properly build the resource with Her
|
50
54
|
initialize_with { new(attributes).tap { |e| e.clear_attribute_changes! } }
|
51
55
|
end
|
@@ -34,6 +34,7 @@ module MnoEnterprise::TestingSupport::JpiV1TestHelper
|
|
34
34
|
sign_in user
|
35
35
|
allow(ability).to receive(:can?).with(any_args).and_return(false)
|
36
36
|
expect(subject).to_not be_successful
|
37
|
+
expect(subject.code).to eq('403')
|
37
38
|
end
|
38
39
|
end
|
39
40
|
|
@@ -46,4 +47,42 @@ module MnoEnterprise::TestingSupport::JpiV1TestHelper
|
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
50
|
+
shared_examples_for "a not found response" do
|
51
|
+
it { expect(subject).to_not be_success }
|
52
|
+
it do
|
53
|
+
subject
|
54
|
+
expect(response.status).to eq(404)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
shared_examples_for "a bad request response" do
|
59
|
+
it { expect(subject).to_not be_success }
|
60
|
+
it do
|
61
|
+
subject
|
62
|
+
expect(response.status).to eq(400)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
shared_examples_for "a forbidden response" do
|
67
|
+
it { expect(subject).to_not be_success }
|
68
|
+
it do
|
69
|
+
subject
|
70
|
+
expect(response.status).to eq(403)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
shared_examples_for "an internal server error response" do
|
75
|
+
it { expect(subject).to_not be_success }
|
76
|
+
it do
|
77
|
+
subject
|
78
|
+
expect(response.status).to eq(500)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
shared_examples_for "a paginated action" do
|
83
|
+
it 'adds the pagination metadata' do
|
84
|
+
subject
|
85
|
+
expect(response.headers['X-Total-Count']).to be_a(Fixnum)
|
86
|
+
end
|
87
|
+
end
|
49
88
|
end
|
@@ -52,7 +52,8 @@ module MnoEnterprise::TestingSupport::OrganizationsSharedHelpers
|
|
52
52
|
ret = {
|
53
53
|
'id' => organization.id,
|
54
54
|
'name' => organization.name,
|
55
|
-
'soa_enabled' => organization.soa_enabled
|
55
|
+
'soa_enabled' => organization.soa_enabled,
|
56
|
+
'payment_restriction' => organization.payment_restriction
|
56
57
|
}
|
57
58
|
|
58
59
|
if admin
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module MnoEnterprise::TestingSupport::SharedExamples::JpiV1Admin
|
2
|
+
shared_examples "a jpi v1 admin action" do
|
3
|
+
context "without a signed in user" do
|
4
|
+
before { sign_out('user') }
|
5
|
+
|
6
|
+
it "prevents access" do
|
7
|
+
expect(subject).to_not be_successful
|
8
|
+
expect(subject.code).to eq('401')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
context "with a non admin signed in user" do
|
13
|
+
let(:user) { FactoryGirl.build(:user) }
|
14
|
+
before do
|
15
|
+
api_stub_for(get: "/users/#{user.id}", response: from_api(user))
|
16
|
+
sign_in user
|
17
|
+
end
|
18
|
+
|
19
|
+
it "prevents access" do
|
20
|
+
expect(subject).to_not be_successful
|
21
|
+
expect(subject.code).to eq('401')
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "with a signed in admin" do
|
26
|
+
let(:user) { FactoryGirl.build(:user, :admin, :with_organizations) }
|
27
|
+
before do
|
28
|
+
api_stub_for(get: "/users/#{user.id}", response: from_api(user))
|
29
|
+
sign_in user
|
30
|
+
end
|
31
|
+
|
32
|
+
it "authorizes access" do
|
33
|
+
sign_in user
|
34
|
+
expect(subject).to be_successful
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
RSpec.describe Devise::Models::RemoteAuthenticatable < ActiveSupport::TestCase do
|
4
|
+
let(:user) { build(:user, email: 'test@maestrano.com', password: 'oldpass') }
|
5
|
+
|
6
|
+
before do
|
7
|
+
api_stub_for(put: "/users/#{user.id}", response: from_api(user))
|
8
|
+
end
|
9
|
+
|
10
|
+
describe 'Sends an email on password update' do
|
11
|
+
subject { user.update(updates) }
|
12
|
+
|
13
|
+
context 'when password change notifications are enabled' do
|
14
|
+
before { user.class.send_password_change_notification = true }
|
15
|
+
|
16
|
+
context 'when the user is confirmed' do
|
17
|
+
let(:user) { build(:user, email: 'test@maestrano.com', password: 'oldpass', confirmed_at: nil) }
|
18
|
+
let(:updates) { {password: 'newpass', password_confirmation: 'newpass', confirmed_at: Time.current} }
|
19
|
+
|
20
|
+
it 'does not send an email' do
|
21
|
+
expect(user).not_to receive(:send_devise_notification)
|
22
|
+
subject
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
context 'when the password is changed' do
|
27
|
+
let(:updates) { {password: 'newpass', password_confirmation: 'newpass'} }
|
28
|
+
|
29
|
+
it 'sends an email' do
|
30
|
+
expect(user).to receive(:send_devise_notification).with(:password_change)
|
31
|
+
subject
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when password does not change notifications are disabled' do
|
37
|
+
before { user.class.send_password_change_notification = false }
|
38
|
+
|
39
|
+
context 'when the password is not updated' do
|
40
|
+
let(:updates) { {name: 'Bob'} }
|
41
|
+
|
42
|
+
it 'does not send an email' do
|
43
|
+
expect(user).not_to receive(:send_devise_notification)
|
44
|
+
subject
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when the password to change is invalid' do
|
49
|
+
let(:updates) { {password: '', password_confirmation: ''} }
|
50
|
+
|
51
|
+
it 'does not send an email' do
|
52
|
+
expect(user).not_to receive(:send_devise_notification)
|
53
|
+
subject
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context 'when the password and its confirmation are different' do
|
58
|
+
let(:updates) { {password: 'password1', password_confirmation: 'another_password'} }
|
59
|
+
|
60
|
+
it 'does not send an email' do
|
61
|
+
expect(user).not_to receive(:send_devise_notification)
|
62
|
+
subject
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
context 'when the password is given without confirmation' do
|
67
|
+
let(:updates) { {password: 'new_password'} }
|
68
|
+
|
69
|
+
it 'does not send an email' do
|
70
|
+
expect(user).not_to receive(:send_devise_notification)
|
71
|
+
subject
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require "rails_helper"
|
2
|
+
|
3
|
+
describe MnoEnterprise::ImpacClient do
|
4
|
+
subject { MnoEnterprise::ImpacClient }
|
5
|
+
|
6
|
+
let(:host_path) { "http://localhost:4000" }
|
7
|
+
let(:params) { { sso_session: '1234' } }
|
8
|
+
let(:endpoint) { "/some/endpoint" }
|
9
|
+
let(:url) { "http://localhost:4000/some/endpoint?sso_session=1234" }
|
10
|
+
|
11
|
+
describe ".host" do
|
12
|
+
it { expect(subject.host).to eq(host_path) }
|
13
|
+
end
|
14
|
+
|
15
|
+
describe ".endpoint_url" do
|
16
|
+
it { expect(subject.endpoint_url(endpoint, params)).to eq(url) }
|
17
|
+
context "when the endpoint misses the first '/'" do
|
18
|
+
let(:endpoint) { "some/endpoint" }
|
19
|
+
it { expect(subject.endpoint_url(endpoint, params)).to eq(url) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe ".send_get" do
|
24
|
+
let(:opts) { {some: 'opts'} }
|
25
|
+
|
26
|
+
before { allow(subject).to receive(:get).with(url, opts).and_return(true) }
|
27
|
+
|
28
|
+
it { expect(subject.send_get(endpoint, params, opts)).to eq(true) }
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
data/spec/mno_enterprise_spec.rb
CHANGED
@@ -51,28 +51,27 @@ describe MnoEnterprise do
|
|
51
51
|
end
|
52
52
|
|
53
53
|
context 'router' do
|
54
|
+
let(:id) { "cld-1d45e6" }
|
55
|
+
let(:root_path) { "#{MnoEnterprise.mno_api_host}#{MnoEnterprise.mno_api_root_path}" }
|
54
56
|
|
55
57
|
describe 'launch_url' do
|
56
|
-
|
57
|
-
let(:url) { "#{
|
58
|
+
|
59
|
+
let(:url) { "#{root_path}/launch/#{id}" }
|
58
60
|
it { expect(MnoEnterprise.router.launch_url(id)).to eq(url) }
|
59
61
|
end
|
60
62
|
|
61
63
|
describe 'authorize_oauth_url' do
|
62
|
-
let(:
|
63
|
-
let(:url) { "#{MnoEnterprise.mno_api_host}#{MnoEnterprise.mno_api_root_path}/oauth/#{id}/authorize" }
|
64
|
+
let(:url) { "#{root_path}/oauth/#{id}/authorize" }
|
64
65
|
it { expect(MnoEnterprise.router.authorize_oauth_url(id)).to eq(url) }
|
65
66
|
end
|
66
67
|
|
67
68
|
describe 'disconnect_oauth_url' do
|
68
|
-
let(:
|
69
|
-
let(:url) { "#{MnoEnterprise.mno_api_host}#{MnoEnterprise.mno_api_root_path}/oauth/#{id}/disconnect" }
|
69
|
+
let(:url) { "#{root_path}/oauth/#{id}/disconnect" }
|
70
70
|
it { expect(MnoEnterprise.router.disconnect_oauth_url(id)).to eq(url) }
|
71
71
|
end
|
72
72
|
|
73
73
|
describe 'sync_oauth_url' do
|
74
|
-
let(:
|
75
|
-
let(:url) { "#{MnoEnterprise.mno_api_host}#{MnoEnterprise.mno_api_root_path}/oauth/#{id}/sync" }
|
74
|
+
let(:url) { "#{root_path}/oauth/#{id}/sync" }
|
76
75
|
it { expect(MnoEnterprise.router.sync_oauth_url(id)).to eq(url) }
|
77
76
|
end
|
78
77
|
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rails_helper'
|
2
|
+
|
3
|
+
module MnoEnterprise
|
4
|
+
RSpec.describe Identity, type: :model do
|
5
|
+
let(:auth) { OmniAuth::AuthHash.new(provider: 'test', uid: 'usr-123') }
|
6
|
+
let(:identity) { build(:identity, provider: auth.provider, uid: auth.uid) }
|
7
|
+
|
8
|
+
describe '.find_for_oauth' do
|
9
|
+
subject { described_class.find_for_oauth(auth) }
|
10
|
+
|
11
|
+
context 'when the identity exist' do
|
12
|
+
before do
|
13
|
+
filter = {uid: auth.uid, provider: auth.provider}
|
14
|
+
api_stub_for(get: "/identities", params: {filter: filter}, response: from_api([identity]))
|
15
|
+
# We don't stub POST identities therefore testing there's no creation
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'returns the existing entity' do
|
19
|
+
expect(subject).to eq(identity)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
context 'when the identity does not exist' do
|
24
|
+
before do
|
25
|
+
filter = {uid: auth.uid, provider: auth.provider}
|
26
|
+
api_stub_for(get: "/identities", params: {filter: filter}, response: from_api([]))
|
27
|
+
|
28
|
+
# Test that it creates the entity? How can we add expect on post?
|
29
|
+
api_stub_for(post: "/identities", response: from_api(identity))
|
30
|
+
end
|
31
|
+
|
32
|
+
# find or create
|
33
|
+
it 'creates the identity and returns it' do
|
34
|
+
expect(subject).to eq(identity)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -1,7 +1,24 @@
|
|
1
1
|
require 'rails_helper'
|
2
2
|
|
3
3
|
module MnoEnterprise
|
4
|
-
RSpec.describe Organization, :
|
5
|
-
|
4
|
+
RSpec.describe Organization, type: :model do
|
5
|
+
describe '#payment_restriction' do
|
6
|
+
let(:organization) { FactoryGirl.build(:organization) }
|
7
|
+
subject { organization.payment_restriction }
|
8
|
+
|
9
|
+
context 'without metadata' do
|
10
|
+
it { is_expected.to be nil }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'without payment restriction' do
|
14
|
+
before { organization.meta_data = {} }
|
15
|
+
it { is_expected.to be nil }
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'with payment restriction' do
|
19
|
+
before { organization.meta_data = {payment_restriction: ['visa']} }
|
20
|
+
it { is_expected.to eq(['visa']) }
|
21
|
+
end
|
22
|
+
end
|
6
23
|
end
|
7
24
|
end
|
@@ -37,8 +37,246 @@ module MnoEnterprise
|
|
37
37
|
load 'app/models/mno_enterprise/user.rb'
|
38
38
|
end
|
39
39
|
end
|
40
|
+
end
|
41
|
+
|
42
|
+
describe :intercom_user_hash do
|
43
|
+
let(:user) { MnoEnterprise::User.new(email: 'admin@example.com') }
|
44
|
+
|
45
|
+
context 'without Intercom' do
|
46
|
+
# default
|
47
|
+
it { expect(user).not_to respond_to(:intercom_user_hash) }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'with Intercom' do
|
51
|
+
before do
|
52
|
+
allow(MnoEnterprise).to receive(:intercom_enabled?).and_return(true)
|
53
|
+
allow(MnoEnterprise).to receive(:intercom_api_secret).and_return('mysecret')
|
54
|
+
|
55
|
+
# Reload User class to include IntercomUser concern
|
56
|
+
MnoEnterprise.send(:remove_const, :User)
|
57
|
+
load 'app/models/mno_enterprise/user.rb'
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'returns the user intercom hash' do
|
61
|
+
expect(user.intercom_user_hash).not_to be_nil
|
62
|
+
end
|
40
63
|
|
64
|
+
after do
|
65
|
+
# Reset to default
|
66
|
+
MnoEnterprise.send(:remove_const, :User)
|
67
|
+
load 'app/models/mno_enterprise/user.rb'
|
68
|
+
end
|
69
|
+
end
|
41
70
|
end
|
42
71
|
|
72
|
+
describe 'Omniauth' do
|
73
|
+
let(:firstname) { "Jack" }
|
74
|
+
let(:lastname) { "Beauregard" }
|
75
|
+
let(:provider) { 'someprovider' }
|
76
|
+
let(:auth) { OmniAuth::AuthHash.new(
|
77
|
+
{
|
78
|
+
provider: provider,
|
79
|
+
uid: '123545',
|
80
|
+
info: {
|
81
|
+
first_name: firstname,
|
82
|
+
last_name: lastname,
|
83
|
+
email: 'jack.beauregard@maestrano.com'
|
84
|
+
}
|
85
|
+
}
|
86
|
+
) }
|
87
|
+
|
88
|
+
|
89
|
+
describe '.find_for_oauth' do
|
90
|
+
it { expect(described_class).to respond_to(:find_for_oauth) }
|
91
|
+
|
92
|
+
subject { described_class.find_for_oauth(auth) }
|
93
|
+
|
94
|
+
context 'without a signed in user' do
|
95
|
+
|
96
|
+
context 'with a matching identity' do
|
97
|
+
let(:user) { build(:user, email: auth.info.email) }
|
98
|
+
let(:identity) { build(:identity, provider: auth.provider, uid: auth.uid, user: user.attributes) }
|
99
|
+
|
100
|
+
before { expect(Identity).to receive(:find_for_oauth) { identity } }
|
101
|
+
|
102
|
+
it 'returns the matching user' do
|
103
|
+
expect(subject).to eq(user)
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'does not create a new user' do
|
107
|
+
expect(described_class).not_to receive(:create_from_omniauth)
|
108
|
+
subject
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
context 'with no matching identity' do
|
113
|
+
let(:identity) { build(:identity, provider: auth.provider, uid: auth.uid) }
|
114
|
+
before { expect(Identity).to receive(:find_for_oauth) { identity } }
|
115
|
+
|
116
|
+
context 'when a user with a matching email exists' do
|
117
|
+
let(:user) { build(:user, email: auth.info.email) }
|
118
|
+
before do
|
119
|
+
api_stub_for(get: "/users", params: {filter: {email: auth.info.email}}, response: from_api([user]))
|
120
|
+
api_stub_for(post: "/identities", response: from_api(identity))
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'associates the new identity with the user' do
|
124
|
+
subject
|
125
|
+
expect(identity.user_id).to eq(user.id)
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'returns the matching user' do
|
129
|
+
expect(subject).to eq(user)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'does not create a new user' do
|
133
|
+
expect(described_class).not_to receive(:create_from_omniauth)
|
134
|
+
subject
|
135
|
+
end
|
136
|
+
|
137
|
+
context 'with Intuit provider' do
|
138
|
+
let(:provider) { 'intuit' }
|
139
|
+
|
140
|
+
context 'when email is authorised' do
|
141
|
+
subject { described_class.find_for_oauth(auth, authorized_link_to_email: auth[:info][:email]) }
|
142
|
+
it 'does not raise an error' do
|
143
|
+
expect { subject }.not_to raise_error
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
context 'when email is not authorised' do
|
148
|
+
it 'raises an error' do
|
149
|
+
expect { subject }.to raise_error(SecurityError, 'reconfirm credentials')
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context 'when no user with a matching email exists' do
|
156
|
+
let(:user) { described_class.new }
|
157
|
+
let(:identity) { build(:identity, provider: auth.provider, uid: auth.uid) }
|
158
|
+
|
159
|
+
before do
|
160
|
+
api_stub_for(get: "/users", params: {filter: {email: auth.info.email}}, response: from_api(nil))
|
161
|
+
api_stub_for(post: "/identities", response: from_api(identity))
|
162
|
+
end
|
163
|
+
|
164
|
+
it 'creates and returns a new user' do
|
165
|
+
expect(described_class).to receive(:create_from_omniauth).with(auth, {}).and_return(user)
|
166
|
+
expect(subject).to eq(user)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context 'with a signed in user' do
|
173
|
+
let(:user) { FactoryGirl.build(:user) }
|
174
|
+
subject { described_class.find_for_oauth(auth, {}, user) }
|
175
|
+
|
176
|
+
context 'when the identity match the current user' do
|
177
|
+
let(:identity) { build(:identity, provider: auth.provider, uid: auth.uid, user: user.attributes) }
|
178
|
+
before { expect(Identity).to receive(:find_for_oauth) { identity } }
|
179
|
+
|
180
|
+
it 'does not touch the identity' do
|
181
|
+
# no stub
|
182
|
+
subject
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'returns the current user' do
|
186
|
+
expect(subject).to eq(user)
|
187
|
+
end
|
188
|
+
|
189
|
+
it 'does not create a new user' do
|
190
|
+
expect(described_class).not_to receive(:create_from_omniauth)
|
191
|
+
subject
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
context 'when the identity does not match the current user' do
|
196
|
+
let(:identity) { build(:identity, provider: auth.provider, uid: auth.uid) }
|
197
|
+
before { expect(Identity).to receive(:find_for_oauth) { identity } }
|
198
|
+
|
199
|
+
before do
|
200
|
+
api_stub_for(post: "/identities", response: from_api(identity))
|
201
|
+
end
|
202
|
+
|
203
|
+
it 're-assign the identity to the current user' do
|
204
|
+
subject
|
205
|
+
expect(identity.user_id).to eq(user.id)
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'returns the current user' do
|
209
|
+
expect(subject).to eq(user)
|
210
|
+
end
|
211
|
+
|
212
|
+
it 'does not create a new user' do
|
213
|
+
expect(described_class).not_to receive(:create_from_omniauth)
|
214
|
+
subject
|
215
|
+
end
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
describe '.create_from_omniauth' do
|
221
|
+
let(:user) { build(:user) }
|
222
|
+
|
223
|
+
before do
|
224
|
+
allow(MnoEnterprise::User).to receive(:new) { user }
|
225
|
+
allow(user).to receive(:save) { user }
|
226
|
+
end
|
227
|
+
|
228
|
+
subject { described_class.create_from_omniauth(auth) }
|
229
|
+
|
230
|
+
it { expect(described_class).to respond_to(:create_from_omniauth) }
|
231
|
+
|
232
|
+
it 'creates a new user with the proper fields' do
|
233
|
+
expect(MnoEnterprise::User).to receive(:new).with(
|
234
|
+
hash_including(
|
235
|
+
name: auth.info.first_name,
|
236
|
+
surname: auth.info.last_name,
|
237
|
+
email: auth.info.email
|
238
|
+
)).and_return(user)
|
239
|
+
subject
|
240
|
+
end
|
241
|
+
|
242
|
+
it 'skips email confirmation' do
|
243
|
+
expect(user).to receive(:skip_confirmation!)
|
244
|
+
expect(subject).to be_confirmed
|
245
|
+
end
|
246
|
+
|
247
|
+
context 'with Intuit provider' do
|
248
|
+
let(:provider) { 'intuit' }
|
249
|
+
|
250
|
+
it 'does not skip email confirmation' do
|
251
|
+
expect(user).not_to receive(:skip_confirmation!)
|
252
|
+
subject
|
253
|
+
end
|
254
|
+
end
|
255
|
+
|
256
|
+
context 'with some params' do
|
257
|
+
let(:comp_name) { 'some company to be set' }
|
258
|
+
subject { described_class.create_from_omniauth(auth, company: comp_name) }
|
259
|
+
|
260
|
+
it 'creates a user with correct attributes' do
|
261
|
+
expect(subject.company).to eq(comp_name)
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
context 'when omniauth provides a user with no name' do
|
266
|
+
let(:firstname) { nil }
|
267
|
+
let(:lastname) { nil }
|
268
|
+
|
269
|
+
it "creates a user with name='first_part_of_email' and surname=''" do
|
270
|
+
expect(MnoEnterprise::User).to receive(:new).with(
|
271
|
+
hash_including(
|
272
|
+
name: 'jack.beauregard',
|
273
|
+
surname: '',
|
274
|
+
email: auth.info.email
|
275
|
+
)).and_return(user)
|
276
|
+
subject
|
277
|
+
end
|
278
|
+
end
|
279
|
+
end
|
280
|
+
end
|
43
281
|
end
|
44
282
|
end
|