mno-enterprise-api 3.2.1 → 3.3.0

Sign up to get free protection for your applications and to get access to all the features.
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