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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/images/mno_enterprise/logo-intuit.png +0 -0
  3. data/app/assets/images/mno_enterprise/main-logo.png +0 -0
  4. data/app/assets/stylesheets/mno_enterprise/mail.css +1 -4
  5. data/app/controllers/mno_enterprise/application_controller.rb +1 -1
  6. data/app/helpers/mno_enterprise/application_helper.rb +7 -7
  7. data/app/models/mno_enterprise/app.rb +12 -3
  8. data/app/models/mno_enterprise/app_answer.rb +13 -0
  9. data/app/models/mno_enterprise/app_comment.rb +10 -0
  10. data/app/models/mno_enterprise/app_feedback.rb +7 -0
  11. data/app/models/mno_enterprise/app_question.rb +9 -0
  12. data/app/models/mno_enterprise/app_review.rb +7 -0
  13. data/app/models/mno_enterprise/base_resource.rb +6 -1
  14. data/app/models/mno_enterprise/identity.rb +24 -0
  15. data/app/models/mno_enterprise/impac/alert.rb +10 -0
  16. data/app/models/mno_enterprise/impac/dashboard.rb +10 -11
  17. data/app/models/mno_enterprise/impac/kpi.rb +4 -2
  18. data/app/models/mno_enterprise/impac/widget.rb +4 -1
  19. data/app/models/mno_enterprise/team.rb +1 -33
  20. data/app/models/mno_enterprise/user.rb +109 -28
  21. data/app/views/system_notifications/email-change.html.erb +27 -0
  22. data/app/views/system_notifications/email-change.text.erb +10 -0
  23. data/app/views/system_notifications/password-change.html.erb +25 -0
  24. data/app/views/system_notifications/password-change.text.erb +7 -0
  25. data/app/views/system_notifications/reconfirmation-instructions.html.erb +7 -5
  26. data/app/views/system_notifications/reconfirmation-instructions.text.erb +3 -2
  27. data/config/initializers/config.rb +5 -0
  28. data/config/locales/models/user/en.yml +5 -0
  29. data/config/locales/templates/components/en.yml +9 -0
  30. data/config/locales/templates/dashboard/en.yml +14 -0
  31. data/config/locales/templates/dashboard/marketplace/en.yml +111 -8
  32. data/config/locales/templates/dashboard/organization/en.yml +1 -0
  33. data/config/locales/templates/impac/dock/en.yml +28 -0
  34. data/config/locales/views/auth/shared/en.yml +1 -2
  35. data/config/locales/views/webhook/o_auth/providers/en.yml +11 -6
  36. data/lib/devise/hooks/lockable.rb +13 -0
  37. data/lib/devise/models/remote_authenticatable.rb +31 -5
  38. data/lib/generators/mno_enterprise/install/install_generator.rb +7 -0
  39. data/lib/generators/mno_enterprise/install/templates/Procfile +1 -1
  40. data/lib/generators/mno_enterprise/install/templates/Procfile.dev +1 -1
  41. data/lib/generators/mno_enterprise/install/templates/config/application.yml +17 -0
  42. data/lib/generators/mno_enterprise/install/templates/config/initializers/mno_enterprise.rb +8 -3
  43. data/lib/generators/mno_enterprise/install/templates/config/newrelic.yml +46 -0
  44. data/lib/generators/mno_enterprise/install/templates/config/puma.rb +56 -0
  45. data/lib/generators/mno_enterprise/install/templates/config/settings/production.yml +1 -1
  46. data/lib/generators/mno_enterprise/install/templates/config/settings/uat.yml +1 -1
  47. data/lib/generators/mno_enterprise/install/templates/config/settings.yml +21 -0
  48. data/lib/generators/mno_enterprise/install/templates/stylesheets/variables.less +3 -0
  49. data/lib/her_extension/model/associations/association_proxy.rb +10 -6
  50. data/lib/mno_enterprise/concerns/controllers/auth/confirmations_controller.rb +1 -1
  51. data/lib/mno_enterprise/concerns/controllers/auth/omniauth_callbacks_controller.rb +203 -0
  52. data/lib/mno_enterprise/concerns/models/ability.rb +28 -0
  53. data/lib/mno_enterprise/concerns/models/app_instance.rb +22 -4
  54. data/lib/mno_enterprise/concerns/models/intercom_user.rb +28 -0
  55. data/lib/mno_enterprise/concerns/models/organization.rb +14 -1
  56. data/lib/mno_enterprise/concerns/models/team.rb +67 -0
  57. data/lib/mno_enterprise/core.rb +22 -3
  58. data/lib/mno_enterprise/impac_client.rb +19 -0
  59. data/lib/mno_enterprise/mail_adapters/mandrill_adapter.rb +4 -1
  60. data/lib/mno_enterprise/testing_support/factories/app_review.rb +51 -0
  61. data/lib/mno_enterprise/testing_support/factories/apps.rb +12 -10
  62. data/lib/mno_enterprise/testing_support/factories/identity.rb +9 -0
  63. data/lib/mno_enterprise/testing_support/factories/impac/alerts.rb +18 -0
  64. data/lib/mno_enterprise/testing_support/factories/impac/kpis.rb +5 -9
  65. data/lib/mno_enterprise/testing_support/factories/users.rb +4 -0
  66. data/lib/mno_enterprise/testing_support/jpi_v1_test_helper.rb +39 -0
  67. data/lib/mno_enterprise/testing_support/organizations_shared_helpers.rb +2 -1
  68. data/lib/mno_enterprise/testing_support/shared_examples/jpi_v1_admin.rb +38 -0
  69. data/lib/mno_enterprise/version.rb +1 -1
  70. data/spec/lib/devise/model/remote_authenticable_spec.rb +76 -0
  71. data/spec/lib/mno_enterprise/impac_client_spec.rb +31 -0
  72. data/spec/mno_enterprise_spec.rb +7 -8
  73. data/spec/models/mno_enterprise/app_spec.rb +1 -1
  74. data/spec/models/mno_enterprise/identity_spec.rb +39 -0
  75. data/spec/models/mno_enterprise/organization_spec.rb +19 -2
  76. data/spec/models/mno_enterprise/user_spec.rb +238 -0
  77. 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 "an/endpoint"
9
- element_watched "a_watchable"
10
- source "impac"
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
@@ -1,3 +1,3 @@
1
1
  module MnoEnterprise
2
- VERSION = '3.1.4'
2
+ VERSION = '3.2.0'
3
3
  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
@@ -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
- let(:id) { "cld-1d45e6" }
57
- let(:url) { "#{MnoEnterprise.mno_api_host}#{MnoEnterprise.mno_api_root_path}/launch/#{id}" }
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(:id) { "cld-1d45e6" }
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(:id) { "cld-1d45e6" }
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(:id) { "cld-1d45e6" }
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
@@ -26,7 +26,7 @@ module MnoEnterprise
26
26
  end
27
27
 
28
28
  describe 'appinfo methods' do
29
- %i(single_billing? coming_soon?).each do |method|
29
+ %i(single_billing? coming_soon? add_on?).each do |method|
30
30
  it { expect(described_class.new).to respond_to(method) }
31
31
  end
32
32
  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, :type => :model do
5
- pending "add some examples to (or delete) #{__FILE__}"
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