Skip to content

Commit 2f65891

Browse files
authored
Merge pull request #47 from alphagov/refactor-requests-controller-params
Refactor requests controller params
2 parents e141da4 + 7d6de7f commit 2f65891

3 files changed

Lines changed: 81 additions & 28 deletions

File tree

app/controllers/api/requests_controller.rb

Lines changed: 33 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
module Api
22
class RequestsController < Api::BaseController
33
wrap_parameters include: Request.attribute_names + [:recipients]
4+
before_action :set_request_record, only: %i[update resend_emails]
45

56
def create
6-
if request_params[:recipients].blank?
7-
return render json: { errors: ["At least one recipient email is required"] }, status: :bad_request
8-
end
7+
errors = validate_create_params
8+
return render json: { errors: errors }, status: :bad_request if errors.any?
99

1010
fact_check_request = Request.new(request_params.except(:recipients))
1111

@@ -26,30 +26,22 @@ def create
2626
end
2727

2828
def update
29-
request_record = Request.find_by(source_app: params[:source_app], source_id: params[:source_id])
30-
31-
if request_record.nil?
32-
return render json: { errors: "Request with ID #{params[:source_id]} not found for app #{params[:source_app]}" }, status: :bad_request
29+
if params.dig(:request, :current_content).present? && update_params[:current_content].blank?
30+
return render json: { errors: ["current_content must be a hash"] }, status: :bad_request
3331
end
3432

35-
if request_record.update(update_params)
36-
render json: { id: request_record.id, source_id: request_record.source_id, source_app: request_record.source_app }, status: :ok
33+
if @request_record.update(update_params)
34+
render json: { id: @request_record.id, source_id: @request_record.source_id, source_app: @request_record.source_app }, status: :ok
3735
else
38-
render json: { errors: request_record.errors.full_messages }, status: :unprocessable_entity
36+
render json: { errors: @request_record.errors.full_messages }, status: :unprocessable_entity
3937
end
4038
end
4139

4240
def resend_emails
43-
request_record = Request.find_by(source_app: params[:source_app], source_id: params[:source_id])
44-
45-
unless request_record
46-
return render json: { errors: "Request with ID #{params[:source_id]} not found for app #{params[:source_app]}" }, status: :bad_request
47-
end
48-
49-
if NotifyService.resend_emails(request_record)
50-
render json: { id: request_record.id, source_id: request_record.source_id, source_app: request_record.source_app }, status: :ok
41+
if NotifyService.resend_emails(@request_record)
42+
render json: { id: @request_record.id, source_id: @request_record.source_id, source_app: @request_record.source_app }, status: :ok
5143
else
52-
render json: { errors: request_record.errors.full_messages }, status: :unprocessable_entity
44+
render json: { errors: @request_record.errors.full_messages }, status: :unprocessable_entity
5345
end
5446
end
5547

@@ -77,5 +69,27 @@ def update_params
7769
current_content: {},
7870
)
7971
end
72+
73+
def validate_create_params
74+
errors = []
75+
76+
errors << "At least one recipient email is required" if request_params[:recipients].blank?
77+
78+
%i[current_content previous_content].each do |content_hash|
79+
if params.dig(:request, content_hash).present? && request_params[content_hash].blank?
80+
errors << "#{content_hash} must be a hash"
81+
end
82+
end
83+
84+
errors
85+
end
86+
87+
def set_request_record
88+
@request_record = Request.find_by(source_app: params[:source_app], source_id: params[:source_id])
89+
90+
unless @request_record
91+
render json: { errors: ["Request with ID #{params[:source_id]} not found for app #{params[:source_app]}"] }, status: :not_found
92+
end
93+
end
8094
end
8195
end

app/models/request.rb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,12 @@ class Request < ApplicationRecord
1010
scope :most_recent_first, -> { order(created_at: :desc) }
1111
scope :most_recent_for_source, ->(source_id) { for_source(source_id).most_recent_first.first }
1212

13+
private
14+
1315
def content_data_must_be_string_pairs
1416
%i[current_content previous_content].each do |content_field|
1517
content_hash = public_send(content_field)
16-
next if content_hash.blank?
18+
next if content_hash.nil?
1719

1820
unless content_hash.is_a?(Hash)
1921
errors.add(content_field, "#{content_field} is not a hash")

spec/requests/api/requests_spec.rb

Lines changed: 45 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,28 @@
118118
end
119119
end
120120

121+
context "if current_content is not a hash" do
122+
let(:dynamic_current_content) { "not a hash" }
123+
124+
it "returns an error" do
125+
post "/api/requests", params: base_payload, as: :json
126+
127+
expect(response).to have_http_status(:bad_request)
128+
json = JSON.parse(response.body)
129+
expect(json["errors"]).to include("current_content must be a hash")
130+
end
131+
end
132+
133+
context "if previous_content is not a hash" do
134+
it "returns an error" do
135+
post "/api/requests", params: valid_payload.merge(previous_content: "not a hash"), as: :json
136+
137+
expect(response).to have_http_status(:bad_request)
138+
json = JSON.parse(response.body)
139+
expect(json["errors"]).to include("previous_content must be a hash")
140+
end
141+
end
142+
121143
context "without recipients" do
122144
it "returns a 400 error" do
123145
payload = valid_payload
@@ -158,7 +180,7 @@
158180
it "returns a 400 error" do
159181
post "/api/requests/#{invalid_source_app}/#{invalid_source_id}/resend-emails", as: :json
160182

161-
expect(response).to have_http_status(:bad_request)
183+
expect(response).to have_http_status(:not_found)
162184
json = JSON.parse(response.body)
163185
expect(json["errors"]).to include(
164186
"Request with ID #{invalid_source_id} not found for app #{invalid_source_app}",
@@ -170,7 +192,7 @@
170192
it "returns a 400 error" do
171193
post "/api/requests/#{existing_request.source_app}/#{invalid_source_id}/resend-emails", as: :json
172194

173-
expect(response).to have_http_status(:bad_request)
195+
expect(response).to have_http_status(:not_found)
174196
json = JSON.parse(response.body)
175197
expect(json["errors"]).to include(
176198
"Request with ID #{invalid_source_id} not found for app #{existing_request.source_app}",
@@ -182,7 +204,7 @@
182204
it "returns a 400 error" do
183205
post "/api/requests/#{invalid_source_app}/#{existing_request.source_id}/resend-emails", as: :json
184206

185-
expect(response).to have_http_status(:bad_request)
207+
expect(response).to have_http_status(:not_found)
186208
json = JSON.parse(response.body)
187209
expect(json["errors"]).to include(
188210
"Request with ID #{existing_request.source_id} not found for app #{invalid_source_app}",
@@ -196,7 +218,7 @@
196218
it "returns a 400 error" do
197219
post "/api/requests/#{existing_request_whitehall.source_app}/#{existing_request.source_id}/resend-emails", as: :json
198220

199-
expect(response).to have_http_status(:bad_request)
221+
expect(response).to have_http_status(:not_found)
200222
json = JSON.parse(response.body)
201223
expect(json["errors"]).to include(
202224
"Request with ID #{existing_request.source_id} not found for app #{existing_request_whitehall.source_app}",
@@ -253,7 +275,7 @@
253275
it "returns a 400 error" do
254276
patch "/api/requests/#{invalid_source_app}/#{invalid_source_id}", params: update_payload, as: :json
255277

256-
expect(response).to have_http_status(:bad_request)
278+
expect(response).to have_http_status(:not_found)
257279
json = JSON.parse(response.body)
258280
expect(json["errors"]).to include(
259281
"Request with ID #{invalid_source_id} not found for app #{invalid_source_app}",
@@ -265,7 +287,7 @@
265287
it "returns a 400 error" do
266288
patch "/api/requests/#{update_payload[:source_app]}/#{invalid_source_id}", params: update_payload, as: :json
267289

268-
expect(response).to have_http_status(:bad_request)
290+
expect(response).to have_http_status(:not_found)
269291
json = JSON.parse(response.body)
270292
expect(json["errors"]).to include(
271293
"Request with ID #{invalid_source_id} not found for app #{update_payload[:source_app]}",
@@ -277,7 +299,7 @@
277299
it "returns a 400 error" do
278300
patch "/api/requests/#{invalid_source_app}/#{update_payload[:source_id]}", params: update_payload, as: :json
279301

280-
expect(response).to have_http_status(:bad_request)
302+
expect(response).to have_http_status(:not_found)
281303
json = JSON.parse(response.body)
282304
expect(json["errors"]).to include(
283305
"Request with ID #{update_payload[:source_id]} not found for app #{invalid_source_app}",
@@ -290,7 +312,7 @@
290312

291313
it "returns a 400 error" do
292314
patch "/api/requests/#{second_request[:source_app]}/#{update_payload[:source_id]}", params: update_payload, as: :json
293-
expect(response).to have_http_status(:bad_request)
315+
expect(response).to have_http_status(:not_found)
294316
json = JSON.parse(response.body)
295317
expect(json["errors"]).to include(
296318
"Request with ID #{update_payload[:source_id]} not found for app #{second_request[:source_app]}",
@@ -313,5 +335,20 @@
313335
)
314336
end
315337
end
338+
339+
context "if current_content is not a hash" do
340+
let(:invalid_content_payload) { { source_app: existing_request.source_app, source_id: existing_request.source_id, current_content: "not a hash" } }
341+
342+
it "returns errors for current_content format" do
343+
patch "/api/requests/#{existing_request.source_app}/#{existing_request.source_id}", params: invalid_content_payload, as: :json
344+
345+
expect(response).to have_http_status(:bad_request)
346+
347+
json = JSON.parse(response.body)
348+
expect(json["errors"]).to include(
349+
"current_content must be a hash",
350+
)
351+
end
352+
end
316353
end
317354
end

0 commit comments

Comments
 (0)