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.
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