mno-enterprise-core 3.1.4 → 3.2.0
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 +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
|