mno-enterprise-api 3.2.1 → 3.3.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/mno_enterprise/config.js.coffee.erb +8 -0
  3. data/app/controllers/mno_enterprise/admin/invoices_controller.rb +18 -0
  4. data/app/controllers/mno_enterprise/impersonate_controller.rb +5 -1
  5. data/app/controllers/mno_enterprise/jpi/v1/admin/audit_events_controller.rb +9 -0
  6. data/app/controllers/mno_enterprise/jpi/v1/admin/users_controller.rb +10 -4
  7. data/app/controllers/mno_enterprise/jpi/v1/audit_events_controller.rb +28 -0
  8. data/app/controllers/mno_enterprise/jpi/v1/base_resource_controller.rb +1 -1
  9. data/app/controllers/mno_enterprise/webhook/events_controller.rb +7 -0
  10. data/app/views/mno_enterprise/auth/confirmations/lounge.html.haml +26 -25
  11. data/app/views/mno_enterprise/jpi/v1/admin/audit_events/_audit_event.json.jbuilder +1 -1
  12. data/app/views/mno_enterprise/jpi/v1/admin/audit_events/index.csv.erb +14 -0
  13. data/app/views/mno_enterprise/jpi/v1/admin/organizations/_invoices.json.jbuilder +1 -0
  14. data/app/views/mno_enterprise/jpi/v1/admin/organizations/_organization.json.jbuilder +1 -1
  15. data/app/views/mno_enterprise/jpi/v1/admin/users/show.json.jbuilder +1 -0
  16. data/app/views/mno_enterprise/jpi/v1/audit_events/_audit_event.json.jbuilder +5 -0
  17. data/app/views/mno_enterprise/jpi/v1/audit_events/index.csv.erb +12 -0
  18. data/app/views/mno_enterprise/jpi/v1/audit_events/index.json.jbuilder +4 -0
  19. data/app/views/mno_enterprise/jpi/v1/current_users/show.json.jbuilder +1 -1
  20. data/app/views/mno_enterprise/jpi/v1/impac/kpis/_kpi.json.jbuilder +1 -1
  21. data/app/views/mno_enterprise/jpi/v1/impac/widgets/_widget.json.jbuilder +3 -1
  22. data/app/views/mno_enterprise/jpi/v1/marketplace/_app.json.jbuilder +10 -1
  23. data/app/views/mno_enterprise/jpi/v1/organizations/_organization.json.jbuilder +1 -1
  24. data/app/views/mno_enterprise/webhook/o_auth/authorize.html.haml +1 -1
  25. data/config/routes.rb +16 -5
  26. data/lib/mno_enterprise/audit_events_listener.rb +11 -6
  27. data/lib/mno_enterprise/concerns/controllers/jpi/v1/current_users_controller.rb +6 -1
  28. data/lib/mno_enterprise/concerns/controllers/jpi/v1/impac/kpis_controller.rb +9 -10
  29. data/lib/mno_enterprise/concerns/controllers/jpi/v1/impac/widgets_controller.rb +6 -3
  30. data/lib/mno_enterprise/concerns/controllers/jpi/v1/marketplace_controller.rb +20 -8
  31. data/lib/mno_enterprise/concerns/controllers/jpi/v1/organizations_controller.rb +12 -0
  32. data/lib/mno_enterprise/concerns/controllers/jpi/v1/teams_controller.rb +13 -0
  33. data/lib/mno_enterprise/concerns/controllers/pages_controller.rb +2 -0
  34. data/lib/mno_enterprise/concerns/controllers/webhook/events_controller.rb +22 -0
  35. data/lib/mno_enterprise/concerns/controllers/webhook/o_auth_controller.rb +12 -3
  36. data/lib/mno_enterprise/event_logger.rb +2 -2
  37. data/lib/mno_enterprise/intercom_events_listener.rb +25 -30
  38. data/spec/controllers/mno_enterprise/admin/invoices_controller_spec.rb +38 -0
  39. data/spec/controllers/mno_enterprise/impersonate_controller_spec.rb +6 -0
  40. data/spec/controllers/mno_enterprise/jpi/v1/admin/audit_events_controller_spec.rb +9 -0
  41. data/spec/controllers/mno_enterprise/jpi/v1/admin/organizations_controller_spec.rb +3 -2
  42. data/spec/controllers/mno_enterprise/jpi/v1/admin/users_controller_spec.rb +2 -1
  43. data/spec/controllers/mno_enterprise/jpi/v1/audit_events_controller_spec.rb +49 -0
  44. data/spec/controllers/mno_enterprise/jpi/v1/current_users_controller_spec.rb +16 -0
  45. data/spec/controllers/mno_enterprise/jpi/v1/impac/kpis_controller_spec.rb +124 -89
  46. data/spec/controllers/mno_enterprise/jpi/v1/marketplace_controller_spec.rb +83 -36
  47. data/spec/controllers/mno_enterprise/jpi/v1/organizations_controller_spec.rb +18 -3
  48. data/spec/controllers/mno_enterprise/org_invites_controller_spec.rb +3 -3
  49. data/spec/controllers/mno_enterprise/provision_controller_spec.rb +2 -2
  50. data/spec/controllers/mno_enterprise/webhook/o_auth_controller_spec.rb +1 -1
  51. data/spec/lib/mno_enterprise/audit_events_listener_spec.rb +11 -0
  52. data/spec/lib/mno_enterprise/intercom_events_listener_spec.rb +74 -31
  53. data/spec/routing/devise/registrations_routing_spec.rb +43 -6
  54. data/spec/routing/mno_enterprise/admin/invoices_controller_routing_spec.rb +11 -0
  55. data/spec/routing/mno_enterprise/impersonate_controller_routing_spec.rb +30 -4
  56. data/spec/routing/mno_enterprise/jpi/v1/audit_events_controller_routing_spec.rb +11 -0
  57. metadata +20 -4
@@ -26,6 +26,12 @@ module MnoEnterprise
26
26
  get :create, user_id: user2.id
27
27
  expect(controller.current_user.id).to eq(user2.id)
28
28
  end
29
+
30
+ context 'with an organisation id in parameters' do
31
+ before { get :create, user_id: user.id, dhbRefId: 10 }
32
+
33
+ it { is_expected.to redirect_to('/dashboard/#!?dhbRefId=10') }
34
+ end
29
35
  end
30
36
 
31
37
  describe "#destroy" do
@@ -35,6 +35,15 @@ module MnoEnterprise
35
35
  expect(response).to render_template :index
36
36
  end
37
37
  end
38
+
39
+ context 'csv' do
40
+ before { request.env["HTTP_ACCEPT"] = 'text/csv' }
41
+
42
+ it 'renders the :index view' do
43
+ subject
44
+ expect(response).to render_template :index
45
+ end
46
+ end
38
47
  end
39
48
  end
40
49
  end
@@ -67,7 +67,8 @@ module MnoEnterprise
67
67
  'name' => organization.name,
68
68
  'soa_enabled' => organization.soa_enabled,
69
69
  'created_at' => organization.created_at,
70
- 'credit_card' => {'presence' => organization.credit_card?}
70
+ 'credit_card' => {'presence' => organization.credit_card?},
71
+ 'account_frozen' => organization.account_frozen
71
72
  }],
72
73
  'metadata' => {'pagination' => {'count' => 1}}
73
74
  }
@@ -138,7 +139,7 @@ module MnoEnterprise
138
139
  end
139
140
 
140
141
  it 'provision the app instances' do
141
- params.merge!(app_nids: ['xero', app_instance.app.nid])
142
+ params[:app_nids] = ['xero', app_instance.app.nid]
142
143
 
143
144
  # Track the API call
144
145
  create = false
@@ -13,7 +13,8 @@ module MnoEnterprise
13
13
  'id' => org.id,
14
14
  'uid' => org.uid,
15
15
  'name' => org.name,
16
- 'created_at' => org.created_at
16
+ 'created_at' => org.created_at,
17
+ 'account_frozen' => org.account_frozen
17
18
  }
18
19
  end
19
20
  end
@@ -0,0 +1,49 @@
1
+ require 'rails_helper'
2
+
3
+ module MnoEnterprise
4
+ describe Jpi::V1::AuditEventsController, type: :controller do
5
+ include MnoEnterprise::TestingSupport::JpiV1TestHelper
6
+
7
+ render_views
8
+ routes { MnoEnterprise::Engine.routes }
9
+ before { request.env["HTTP_ACCEPT"] = 'application/json' }
10
+
11
+ #===============================================
12
+ # Assignments
13
+ #===============================================
14
+ # Stub controller ability
15
+ let!(:ability) { stub_ability }
16
+ before { allow(ability).to receive(:can?).with(any_args).and_return(true) }
17
+
18
+ # Stub user and mnoe API calls
19
+ let(:user) { FactoryGirl.build(:user, :with_organizations) }
20
+ let(:organization) { user.organizations.first }
21
+ let(:audit_event) { FactoryGirl.build(:audit_event) }
22
+
23
+ before do
24
+ api_stub_for(get: "/users/#{user.id}", response: from_api(user))
25
+ api_stub_for(get: "/users/#{user.id}/organizations", response: from_api([organization]))
26
+ api_stub_for(get: "/organizations/#{organization.id}", response: from_api(organization))
27
+ api_stub_for(get: '/audit_events', response: from_api([audit_event]))
28
+ sign_in user
29
+ end
30
+
31
+ describe 'GET #index' do
32
+ subject { get :index, organization_id: organization.id }
33
+
34
+ it_behaves_like "jpi v1 protected action"
35
+
36
+ context 'sucess' do
37
+ it 'assigns @audit_events' do
38
+ subject
39
+ expect(assigns(:audit_events).to_a).to eq([audit_event])
40
+ end
41
+
42
+ it 'renders the :index view' do
43
+ subject
44
+ expect(response).to render_template :index
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
@@ -63,9 +63,21 @@ module MnoEnterprise
63
63
  hash
64
64
  end
65
65
 
66
+ shared_examples "a user management action" do
67
+ context 'when Organization management is disabled' do
68
+ before { Settings.merge!(user_management: {enabled: false}) }
69
+ before { sign_in user }
70
+ after { Settings.reload! }
71
+
72
+ it { is_expected.to have_http_status(:forbidden) }
73
+ end
74
+ end
75
+
66
76
  # Stub user retrieval
67
77
  let!(:user) { build(:user, :with_deletion_request, :with_organizations, :kpi_enabled) }
68
78
  before { api_stub_for(get: "/users/#{user.id}", response: from_api(user)) }
79
+ before { api_stub_for(get: "/users/#{user.id}/organizations?filter%5Baccount_frozen%5D=false", response: from_api(user.organizations)) }
80
+
69
81
 
70
82
  describe "GET #show" do
71
83
  subject { get :show }
@@ -103,6 +115,8 @@ module MnoEnterprise
103
115
 
104
116
  subject { put :update, user: attrs }
105
117
 
118
+ it_behaves_like 'a user management action'
119
+
106
120
  describe 'guest' do
107
121
  before { subject }
108
122
  it { expect(response).to_not be_success }
@@ -132,6 +146,8 @@ module MnoEnterprise
132
146
 
133
147
  subject { put :update_password, user: attrs }
134
148
 
149
+ it_behaves_like 'a user management action'
150
+
135
151
  describe 'guest' do
136
152
  before { subject }
137
153
  it { expect(response).to_not be_success }
@@ -24,7 +24,9 @@ module MnoEnterprise
24
24
  before { allow_any_instance_of(MnoEnterprise::Impac::Dashboard).to receive(:owner).and_return(user) }
25
25
 
26
26
  let(:kpi_targets) { { evolution: [{max: "20"}] } }
27
- let(:kpi) { build(:impac_kpi, dashboard: dashboard, targets: kpi_targets) }
27
+ let(:settings) { {} }
28
+ let(:extra_params) { [] }
29
+ let(:kpi) { build(:impac_kpi, dashboard: dashboard, targets: kpi_targets, settings: settings, extra_params: extra_params) }
28
30
  let(:kpi_hash) { from_api(kpi)[:data].except(:dashboard) }
29
31
 
30
32
  let(:alert) { build(:impac_alert, kpi: kpi) }
@@ -56,7 +58,7 @@ module MnoEnterprise
56
58
  before { allow(MnoEnterprise).to receive(:tenant_id).and_return(auth[:username]) }
57
59
  before { allow(MnoEnterprise).to receive(:tenant_key).and_return(auth[:password]) }
58
60
 
59
- it { subject; expect(response.code).to eq('200') }
61
+ it { subject; expect(response).to have_http_status(:ok) }
60
62
 
61
63
  it "successfully discovers and customises available kpis" do
62
64
  expect(MnoEnterprise::ImpacClient).to receive(:send_get)
@@ -75,131 +77,164 @@ module MnoEnterprise
75
77
  end
76
78
 
77
79
  describe 'POST #create' do
78
- subject { post :create, dashboard_id: dashboard.id, kpi: kpi_hash }
79
- let (:kpi_targets) { {} }
80
+ shared_examples "create kpi action" do
80
81
 
81
- before do
82
- api_stub_for(get: "/dashboards/#{dashboard.id}", response: from_api(dashboard))
83
- api_stub_for(post: "/dashboards/#{dashboard.id}/kpis", response: from_api(kpi))
84
- api_stub_for(get: "/dashboards/#{dashboard.id}/kpis", response: from_api([]))
85
- api_stub_for(get: "/kpis/#{kpi.id}", response: from_api(kpi)) # kpi.reload
86
- # TODO: this call should not happen as alerts should be wrapped into the kpi object
87
- api_stub_for(get: "/kpis/#{kpi.id}/alerts", response: from_api(alerts_hashes))
88
- end
82
+ it "creates the kpi" do
83
+ subject
84
+ expect(assigns(:kpi)).to eq(kpi)
85
+ end
89
86
 
90
- it_behaves_like "jpi v1 authorizable action"
87
+ context "when there are kpi targets" do
88
+ let(:kpi_targets) { { evolution: [{max: "20"}] } }
91
89
 
92
- it ".dashboard retrieves the correct dashboard" do
93
- subject
94
- expect(assigns(:dashboard)).to eq(dashboard)
95
- end
90
+ before do
91
+ api_stub_for(post: "/users/#{user.id}/alerts", response: from_api(alert))
92
+ api_stub_for(get: "/users/#{user.id}/alerts", response: from_api({}))
93
+ end
96
94
 
97
- it "creates the kpi" do
98
- subject
99
- expect(assigns(:kpi)).to eq(kpi)
95
+ it "creates kpi alerts" do
96
+ subject
97
+ expect(assigns(:kpi).alerts).to eq([alert])
98
+ expect(response).to have_http_status(:ok)
99
+ end
100
+ end
101
+
102
+ it { subject; expect(response).to have_http_status(:ok) }
100
103
  end
101
104
 
102
- context "when there are kpi targets" do
103
- let(:kpi_targets) { { evolution: [{max: "20"}] } }
105
+ let (:kpi_targets) { {} }
106
+
107
+ context "a dashboard KPI" do
108
+ subject { post :create, dashboard_id: dashboard.id, kpi: kpi_hash }
104
109
 
105
110
  before do
106
- api_stub_for(post: "/users/#{user.id}/alerts", response: from_api(alert))
107
- api_stub_for(get: "/users/#{user.id}/alerts", response: from_api({}))
111
+ api_stub_for(get: "/dashboards/#{dashboard.id}", response: from_api(dashboard))
112
+ api_stub_for(post: "/dashboards/#{dashboard.id}/kpis", response: from_api(kpi))
113
+ api_stub_for(get: "/dashboards/#{dashboard.id}/kpis", response: from_api([]))
114
+ api_stub_for(get: "/kpis/#{kpi.id}", response: from_api(kpi)) # kpi.reload
115
+ # TODO: this call should not happen as alerts should be wrapped into the kpi object
116
+ api_stub_for(get: "/kpis/#{kpi.id}/alerts", response: from_api(alerts_hashes))
108
117
  end
109
118
 
110
- it "creates kpi alerts" do
119
+ it_behaves_like "jpi v1 authorizable action"
120
+
121
+ it_behaves_like "create kpi action"
122
+
123
+ it ".dashboard retrieves the correct dashboard" do
111
124
  subject
112
- expect(assigns(:kpi).alerts).to eq([alert])
113
- expect(response.code).to eq('200')
125
+ expect(assigns(:dashboard)).to eq(dashboard)
114
126
  end
115
127
  end
116
128
 
117
- it { subject; expect(response.code).to eq('200') }
118
- end
129
+ context "a widget KPI" do
130
+ let(:widget) { build(:impac_widget) }
131
+ subject { post :create, dashboard_id: dashboard.id, kpi: kpi_hash.merge(widget_id: widget.id) }
119
132
 
120
- describe 'PUT #update' do
121
- let(:kpi_hash) { from_api(kpi)[:data].except(:dashboard).merge(element_watched: 'New Watchable') }
122
- let(:params) { {} }
133
+ before do
134
+ api_stub_for(get: "/widgets/#{widget.id}", response: from_api(widget))
135
+ api_stub_for(post: "/widgets/#{widget.id}/kpis", response: from_api(kpi))
136
+ api_stub_for(get: "/widgets/#{widget.id}/kpis", response: from_api([]))
137
+ api_stub_for(get: "/kpis/#{kpi.id}", response: from_api(kpi)) # kpi.reload
138
+ # TODO: this call should not happen as alerts should be wrapped into the kpi object
139
+ api_stub_for(get: "/kpis/#{kpi.id}/alerts", response: from_api(alerts_hashes))
140
+ end
123
141
 
124
- subject { put :update, id: kpi.id, kpi: kpi_hash.merge(params) }
142
+ it_behaves_like "jpi v1 authorizable action"
125
143
 
126
- before do
127
- api_stub_for(get: "/kpis/#{kpi.id}", response: from_api(kpi))
128
- api_stub_for(put: "/kpis/#{kpi.id}", response: kpi_hash)
129
- api_stub_for(get: "/kpis/#{kpi.id}/alerts", response: from_api(alerts_hashes))
130
- end
144
+ it_behaves_like "create kpi action"
131
145
 
132
- before { kpi.save }
146
+ it ".widget retrieves the correct widget" do
147
+ subject
148
+ expect(assigns(:widget)).to eq(widget)
149
+ end
150
+ end
151
+ end
133
152
 
134
- it_behaves_like "jpi v1 authorizable action"
153
+ describe 'PUT #update' do
154
+ RSpec.shared_examples 'a kpi update action' do
155
+ it "updates the kpi" do
156
+ subject
157
+ expect(assigns(:kpi).element_watched).to eq('New Watchable')
158
+ expect(response).to have_http_status(:ok)
159
+ end
135
160
 
136
- it "updates the kpi" do
137
- subject
138
- expect(assigns(:kpi).element_watched).to eq('New Watchable')
139
- expect(response.code).to eq('200')
140
- end
161
+ context "target set for the first time" do
162
+ let(:kpi_targets) { nil }
163
+ let(:params) { { targets: {evolution: [{max:'20'}]} } }
141
164
 
142
- context "target set for the first time" do
143
- let(:kpi_targets) { nil }
144
- let(:params) { { targets: {evolution: [{max:'20'}]} } }
165
+ before do
166
+ api_stub_for(post: "/users/#{user.id}/alerts", response: from_api(alert))
167
+ api_stub_for(get: "/users/#{user.id}/alerts", response: from_api({}))
168
+ end
145
169
 
146
- before do
147
- api_stub_for(post: "/users/#{user.id}/alerts", response: from_api(alert))
148
- api_stub_for(get: "/users/#{user.id}/alerts", response: from_api({}))
170
+ it "creates an alert" do
171
+ subject
172
+ expect(assigns(:kpi).alerts).to eq([alert])
173
+ expect(response).to have_http_status(:ok)
174
+ end
149
175
  end
150
176
 
151
- it "creates an alert" do
152
- subject
153
- expect(assigns(:kpi).alerts).to eq([alert])
154
- expect(response.code).to eq('200')
177
+ context "when targets have changed" do
178
+ let(:alert) { build(:impac_alert, kpi: kpi, sent: true) }
179
+ let(:params) { { targets: {evolution: [{max:'30'}]} } }
180
+
181
+ before { api_stub_for(put: "/alerts/#{alert.id}", response: from_api({})) }
182
+
183
+ it "updates the sent status of all the kpi's alerts" do
184
+ subject
185
+ expect(assigns(:kpi).alerts).to eq([alert])
186
+ expect(response).to have_http_status(:ok)
187
+ end
155
188
  end
156
- end
157
189
 
158
- context "when targets have changed" do
159
- let(:alert) { build(:impac_alert, kpi: kpi, sent: true) }
160
- let(:params) { { targets: {evolution: [{max:'30'}]} } }
190
+ context "when no targets are given / targets are nil" do
191
+ let(:settings) { { currency: 'GBP' } }
192
+ let(:params) { { targets: nil } }
161
193
 
162
- before { api_stub_for(put: "/alerts/#{alert.id}", response: from_api({})) }
194
+ it "does not remove the kpi targets" do
195
+ subject
196
+ expect(assigns(:kpi).targets).to eq(kpi_targets.deep_stringify_keys)
197
+ expect(response).to have_http_status(:ok)
198
+ end
199
+ end
163
200
 
164
- it "updates the sent status of all the kpi's alerts" do
165
- subject
166
- expect(assigns(:kpi).alerts).to eq([alert])
167
- expect(response.code).to eq('200')
201
+ context "when no extra_params are given / extra_params are nil" do
202
+ let(:settings) { { currency: 'GBP' } }
203
+ let(:extra_params) { ['some-param'] }
204
+ let(:params) { { extra_params: nil } }
205
+
206
+ it "does not remove the kpi extra_params" do
207
+ subject
208
+ expect(assigns(:kpi).extra_params).to eq(['some-param'])
209
+ expect(response).to have_http_status(:ok)
210
+ end
168
211
  end
169
212
  end
170
213
 
171
- context "when a kpi has no targets, nor is being updated with any" do
172
- let(:kpi_targets) { nil }
173
- let(:params) { { targets: {} } }
214
+ let(:kpi_hash) { from_api(kpi)[:data].except(:dashboard).merge(element_watched: 'New Watchable') }
215
+ let(:params) { {} }
174
216
 
175
- before { api_stub_for(delete: "/alerts/#{alert.id}", response: from_api({})) }
217
+ subject { put :update, id: kpi.id, kpi: kpi_hash.merge(params) }
176
218
 
177
- it "destroys the kpi's alerts" do
178
- subject
179
- expect(response.code).to eq('200')
180
- end
219
+ before do
220
+ api_stub_for(get: "/kpis/#{kpi.id}", response: from_api(kpi))
221
+ api_stub_for(put: "/kpis/#{kpi.id}", response: kpi_hash)
222
+ api_stub_for(get: "/kpis/#{kpi.id}/alerts", response: from_api(alerts_hashes))
181
223
  end
182
224
 
183
- context "when no targets are given / targets are nil" do
184
- let(:kpi) { build(:impac_kpi, dashboard: dashboard, targets: kpi_targets, settings: { currency: 'GBP' }) }
185
- let(:params) { { targets: nil } }
225
+ before { kpi.save }
186
226
 
187
- it "does not remove the kpi targets" do
188
- subject
189
- expect(assigns(:kpi).targets).to eq(kpi_targets.deep_stringify_keys)
190
- expect(response.code).to eq('200')
191
- end
227
+ context "a dashboard KPI" do
228
+ it_behaves_like "jpi v1 authorizable action"
229
+ it_behaves_like "a kpi update action"
192
230
  end
193
231
 
194
- context "when no extra_params are given / extra_params are nil" do
195
- let(:kpi) { build(:impac_kpi, dashboard: dashboard, targets: kpi_targets, extra_params: ['some-param'], settings: { currency: 'GBP' }) }
196
- let(:params) { { extra_params: nil } }
232
+ context "a widget KPI" do
233
+ let(:widget) { build(:impac_widget) }
234
+ let(:kpi) { build(:impac_kpi, widget: widget, targets: kpi_targets, settings: settings, extra_params: extra_params) }
197
235
 
198
- it "does not remove the kpi extra_params" do
199
- subject
200
- expect(assigns(:kpi).extra_params).to eq(['some-param'])
201
- expect(response.code).to eq('200')
202
- end
236
+ it_behaves_like "jpi v1 authorizable action"
237
+ it_behaves_like "a kpi update action"
203
238
  end
204
239
  end
205
240
 
@@ -211,7 +246,7 @@ module MnoEnterprise
211
246
 
212
247
  it_behaves_like "jpi v1 authorizable action"
213
248
 
214
- it { expect(response.code).to eq('200') }
249
+ it { expect(response).to have_http_status(:ok) }
215
250
  end
216
251
  end
217
252
  end
@@ -31,13 +31,19 @@ module MnoEnterprise
31
31
  'single_billing' => app.single_billing?,
32
32
  'tiny_description' => app.tiny_description,
33
33
  'description' => markdown(app.sanitized_description),
34
+ 'known_limitations' => markdown(app.known_limitations),
35
+ 'getting_started' => markdown(app.getting_started),
34
36
  'testimonials' => app.testimonials,
35
37
  'pictures' => app.pictures,
36
38
  'pricing_plans' => app.pricing_plans,
37
39
  'rank' => app.rank,
40
+ 'support_url' => app.support_url,
41
+ 'key_workflows' => app.key_workflows,
42
+ 'key_features' => app.key_features,
38
43
  'multi_instantiable' => app.multi_instantiable,
39
44
  'subcategories' => app.subcategories,
40
45
  'average_rating' => app.average_rating,
46
+ 'add_on' => app.add_on?,
41
47
  'running_instances_count' => app.running_instances_count
42
48
  }
43
49
  end
@@ -72,6 +78,8 @@ module MnoEnterprise
72
78
  params: { filter: { 'nid.in' => MnoEnterprise.marketplace_listing } },
73
79
  response: from_api([app])
74
80
  )
81
+ # TODO: Shouldn't need to stub this
82
+ api_stub_for(get: "/apps/#{app.id}/shared_entities", response: from_api([]))
75
83
  end
76
84
 
77
85
  it { is_expected.to be_success }
@@ -86,6 +94,8 @@ module MnoEnterprise
86
94
  before do
87
95
  MnoEnterprise.marketplace_listing = nil
88
96
  api_stub_for(get: '/apps', response: from_api([app]))
97
+ # TODO: Shouldn't need to stub this
98
+ api_stub_for(get: "/apps/#{app.id}/shared_entities", response: from_api([]))
89
99
  end
90
100
 
91
101
  it { is_expected.to be_success }
@@ -94,55 +104,92 @@ module MnoEnterprise
94
104
  subject
95
105
  expect(JSON.parse(response.body)).to eq(JSON.parse(hash_for_apps([app]).to_json))
96
106
  end
97
- end
98
- end
99
107
 
100
- describe 'GET #show' do
101
- before { api_stub_for(get: "/apps/#{app.id}", response: from_api(app)) }
102
- subject { get :show, id: app.id }
108
+ context 'with multiple apps' do
109
+ let(:app1) { build(:app, rank: 5 ) }
110
+ let(:app2) { build(:app, rank: 0 ) }
111
+
112
+ before do
113
+ api_stub_for(get: '/apps', response: from_api([app1, app2]))
114
+ # TODO: Shouldn't need to stub this
115
+ api_stub_for(get: "/apps/#{app1.id}/shared_entities", response: from_api([]))
116
+ api_stub_for(get: "/apps/#{app2.id}/shared_entities", response: from_api([]))
117
+ end
118
+
119
+ it 'returns the apps in the correct order' do
120
+ subject
121
+ expect(assigns(:apps)).to eq([app2, app1])
122
+ end
123
+ end
103
124
 
104
- it { is_expected.to be_success }
125
+ context 'when multiples apps and a nil rank' do
126
+ let(:app1) { build(:app, rank: 5 ) }
127
+ let(:app2) { build(:app, rank: 0 ) }
128
+ let(:app3) { build(:app, rank: nil ) }
129
+
130
+ before do
131
+ api_stub_for(get: '/apps', response: from_api([app1, app3, app2]))
132
+ # TODO: Shouldn't need to stub this
133
+ api_stub_for(get: "/apps/#{app1.id}/shared_entities", response: from_api([]))
134
+ api_stub_for(get: "/apps/#{app2.id}/shared_entities", response: from_api([]))
135
+ api_stub_for(get: "/apps/#{app3.id}/shared_entities", response: from_api([]))
136
+ end
137
+
138
+ it 'returns the apps in the correct order' do
139
+ subject
140
+ expect(assigns(:apps)).to eq([app2, app1, app3])
141
+ end
142
+ end
105
143
 
106
- it 'returns the right response' do
107
- subject
108
- expect(JSON.parse(response.body)).to eq(JSON.parse(hash_for_app(app).to_json))
109
- end
110
- end
144
+ describe 'caching' do
145
+ context 'on the first request' do
146
+ it { is_expected.to have_http_status(:ok) }
111
147
 
112
- describe 'GET #index' do
113
- subject { get :index }
148
+ it 'sets the correct cache headers' do
149
+ subject
150
+ header = response.headers['Last-Modified']
114
151
 
115
- context 'when multiples apps' do
116
- let(:app1) { build(:app, rank: 5 ) }
117
- let(:app2) { build(:app, rank: 0 ) }
152
+ expect(header).to be_present
118
153
 
119
- before do
120
- MnoEnterprise.marketplace_listing = nil
121
- api_stub_for(get: '/apps', response: from_api([app1,app2]))
122
- end
154
+ # Parse and serialise to get correct format and avoid ms difference
155
+ expect(Time.rfc822(header).in_time_zone.to_s).to eq(app.updated_at.to_s)
156
+ end
157
+ end
123
158
 
124
- it { is_expected.to be_success }
159
+ context 'on a subsequent request' do
125
160
 
126
- it 'returns the right response' do
127
- subject
128
- expect(JSON.parse(response.body)).to eq(JSON.parse(hash_for_apps([app2, app1]).to_json))
161
+ before do
162
+ request.env['HTTP_IF_MODIFIED_SINCE'] = last_modified.rfc2822
163
+ end
164
+
165
+ context 'if it is not stale' do
166
+ # Can't be based on the previous request due to parsing and rounding issues with ms
167
+ let(:last_modified) { app.updated_at + 10.minutes }
168
+ it { is_expected.to have_http_status(:not_modified) }
169
+ end
170
+
171
+ context 'if it is stale' do
172
+ let(:last_modified) { app.updated_at - 10.minutes }
173
+ it { is_expected.to have_http_status(:ok) }
174
+ end
175
+ end
129
176
  end
130
177
  end
178
+ end
131
179
 
132
- context 'when multiples apps and attributes nil' do
133
- let(:app1) { build(:app, rank: 5 ) }
134
- let(:app2) { build(:app, rank: 0 ) }
135
- let(:app3) { build(:app, rank: nil ) }
180
+ describe 'GET #show' do
181
+ before do
182
+ api_stub_for(get: "/apps/#{app.id}", response: from_api(app))
183
+ # TODO: Shouldn't need to stub this
184
+ api_stub_for(get: "/apps/#{app.id}/shared_entities", response: from_api([]))
185
+ end
186
+ subject { get :show, id: app.id }
136
187
 
137
- before do
138
- MnoEnterprise.marketplace_listing = nil
139
- api_stub_for(get: '/apps', response: from_api([app1,app3,app2]))
140
- end
188
+ it { is_expected.to be_success }
141
189
 
142
- it 'returns the right response' do
143
- subject
144
- expect(JSON.parse(response.body)).to eq(JSON.parse(hash_for_apps([app2, app1, app3]).to_json))
145
- end
190
+ it 'returns the right response' do
191
+ subject
192
+ expect(JSON.parse(response.body)).to eq(JSON.parse(hash_for_app(app).to_json))
146
193
  end
147
194
  end
148
195
  end