From 56bc8ef61c9252b963f5b5e1b237d09cc8d3c743 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Leli=C3=A8vre?= Date: Thu, 19 Dec 2024 11:49:40 +0100 Subject: [PATCH 1/5] update --- app/controllers/api/v1/requests_controller.rb | 15 +++ app/policies/request_policy.rb | 9 ++ config/routes.rb | 2 +- spec/acceptance/api/v1/me_controller_spec.rb | 2 - .../api/v1/requests_controller_spec.rb | 59 +++++++++- spec/config/shared_contexts.rb | 5 +- spec/requests/api/v1/requests_spec.rb | 104 ++++++++++++++++-- test/fixtures/requests.yml | 27 +++++ 8 files changed, 206 insertions(+), 17 deletions(-) diff --git a/app/controllers/api/v1/requests_controller.rb b/app/controllers/api/v1/requests_controller.rb index 949ef25..8c16096 100644 --- a/app/controllers/api/v1/requests_controller.rb +++ b/app/controllers/api/v1/requests_controller.rb @@ -49,6 +49,14 @@ def create end end + def update + if @request.update(update_request_params) + render json: @request.to_blueprint, status: :ok + else + render_validation_error(@request) + end + end + def accept if @request.fire_state_event(:accept) render json: @request.to_blueprint @@ -104,6 +112,13 @@ def request_params ) end + def update_request_params + params.permit( + :plant_stage_id, :name, :plant_name, :plant_stage_name, + :quantity, :due_date, :temperature, :photoperiod + ) + end + def plant_attributes_from_params(request) return if request_params[:plant_stage_id].blank? diff --git a/app/policies/request_policy.rb b/app/policies/request_policy.rb index b033a47..f218ff1 100644 --- a/app/policies/request_policy.rb +++ b/app/policies/request_policy.rb @@ -29,6 +29,15 @@ def complete? true end + def update? + if record.request_distributions.exists? + record.errors.add(:base, 'cannot update a request with associated request distributions') + false + else + true + end + end + def destroy? if record.pending? true diff --git a/config/routes.rb b/config/routes.rb index b6c608e..61414ad 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -19,7 +19,7 @@ resources :plants, only: %i[index show create update destroy] - resources :requests, only: %i[index show create destroy], shallow: true do + resources :requests, only: %i[index show create update destroy], shallow: true do get :requests_to_handle_count, on: :collection post :accept, on: :member post :refuse, on: :member diff --git a/spec/acceptance/api/v1/me_controller_spec.rb b/spec/acceptance/api/v1/me_controller_spec.rb index c9c8ce4..a262b31 100644 --- a/spec/acceptance/api/v1/me_controller_spec.rb +++ b/spec/acceptance/api/v1/me_controller_spec.rb @@ -27,11 +27,9 @@ put '/api/v1/me' do parameter :first_name, 'The new first name', with_example: true parameter :last_name, 'The new last name', with_example: true - parameter :laboratory, 'The new laboratory (only for a requester)', with_example: true let(:first_name) { 'Updated first name' } let(:last_name) { 'Updated last name' } - let(:laboratory) { 'Updated laboratory' } let(:raw_post) { params.to_json } diff --git a/spec/acceptance/api/v1/requests_controller_spec.rb b/spec/acceptance/api/v1/requests_controller_spec.rb index 177295a..8ec9f80 100644 --- a/spec/acceptance/api/v1/requests_controller_spec.rb +++ b/spec/acceptance/api/v1/requests_controller_spec.rb @@ -192,9 +192,7 @@ request.update(status: :pending) end - example 'Cancel a request' \ - 'If the request is already accepted and the current user is a requester, ' \ - 'the request will be set as `in_cancelation`' do + example 'Cancel a request' do authentication :basic, "Bearer #{user_token.token}" do_request @@ -238,4 +236,59 @@ expect { request.reload }.to raise_exception(ActiveRecord::RecordNotFound) end end + + put '/api/v1/requests/:id' do + + let!(:request3) { requests(:request3) } + let(:id) { request3.id } + + parameter :plant_stage_id, 'ID of the requested plant_stage', with_example: true + parameter :name, 'Name of the request', with_example: true + parameter :plant_name, + 'Name of the requested plant (ignored if plant_stage_id given)', + with_example: true + parameter :plant_stage_name, + 'Name of the requested plant stage (ignored if plant_stage_id given)', + with_example: true + parameter :due_date, 'Due date of the request', with_example: true, type: :date + parameter :quantity, 'Quantity of plants desired', with_example: true, type: :integer + parameter :temperature, + '(Optional) Temperature of cultivation desired', + with_example: true, + type: :integer + parameter :photoperiod, + '(Optional) Photoperiod of cultivation desired (in hour/day)', + with_example: true, + type: :integer + + let(:plant_stage_id) { Plant.last.plant_stages.last.id } + let(:name) { 'My request'} + let(:plant_name) { Plant.last.name } + let(:plant_stage_name) { Plant.last.plant_stages.last.name } + let(:due_date) { Date.current + 6.months } + let(:quantity) { 150 } + let(:temperature) { 'Froid' } + let(:photoperiod) { 12 } + + let(:raw_post) { params.to_json } + + example 'Update a request' do + authentication :basic, "Bearer #{user_token.token}" + do_request + + expect(status).to eq(200) + + request.reload + + response = JSON.parse(response_body) + expect(response['plant_stage_id']).to eq(plant_stage_id) + expect(response['plant_stage_name']).to eq(plant_stage_name) + expect(response['plant_name']).to eq(plant_name) + expect(response['name']).to eq(name) + expect(response['due_date']).to eq(due_date.strftime('%F')) + expect(response['quantity']).to eq(quantity) + expect(response['temperature']).to eq(temperature) + expect(response['photoperiod']).to eq(photoperiod) + end + end end diff --git a/spec/config/shared_contexts.rb b/spec/config/shared_contexts.rb index c5f9a9f..0950535 100644 --- a/spec/config/shared_contexts.rb +++ b/spec/config/shared_contexts.rb @@ -1,12 +1,9 @@ # frozen_string_literal: true -RSpec.shared_context 'with authenticated requester' do +RSpec.shared_context 'without authentication' do let(:user) { users(:user1) } let(:application) { oauth_applications(:application) } let(:token) { Doorkeeper::AccessToken.create!(resource_owner_id: user.id, application:) } - let(:headers) do - { Authorization: "Bearer #{token.token}" } - end end RSpec.shared_context 'with authenticated grower' do diff --git a/spec/requests/api/v1/requests_spec.rb b/spec/requests/api/v1/requests_spec.rb index 8c2098d..d4aeabc 100644 --- a/spec/requests/api/v1/requests_spec.rb +++ b/spec/requests/api/v1/requests_spec.rb @@ -26,8 +26,8 @@ expect(response.parsed_body.count).to eq(2) expect(response.headers['Pagination-Current-Page']).to eq(1) expect(response.headers['Pagination-Per']).to eq(2) - expect(response.headers['Pagination-Total-Pages']).to eq(1) - expect(response.headers['Pagination-Total-Count']).to eq(2) + expect(response.headers['Pagination-Total-Pages']).to eq(2) + expect(response.headers['Pagination-Total-Count']).to eq(3) end it 'gets requests filtered by status' do @@ -191,7 +191,7 @@ end end - it_behaves_like 'with authenticated requester' do + it_behaves_like 'without authentication' do it 'can create a request from an existing plant_stage' do plant = Plant.last plant_stage = plant.plant_stages.last @@ -403,13 +403,12 @@ end end - context 'when 404' do - it_behaves_like 'with authenticated requester' do + context 'when 401' do + it_behaves_like 'without authentication' do it 'can\'t delete a request' do delete("/api/v1/requests/#{id}", headers:) - expect(status).to eq(403) - expect(response.parsed_body.dig('error', 'message')).not_to be_blank + expect(status).to eq(401) end end end @@ -429,4 +428,95 @@ end end end + + describe 'PUT api/v1/requests/:id' do + context 'when 403' do + it_behaves_like 'with authenticated grower' do + it 'can\'t update a request containing request_distributions' do + put( + "/api/v1/requests/#{id}", + headers:, + params: { + name: 'My request', + quantity: 150, + due_date: Date.current + 6.months, + comment: 'My comment', + temperature: 'Chaud', + photoperiod: 4 + } + ) + + expect(status).to eq(403) + expect(response.parsed_body.dig('error', 'message')).not_to be_blank + end + end + end + context 'when 422' do + let!(:request3) { requests(:request3) } + let!(:id) { request3.id } + + it_behaves_like 'with authenticated grower' do + it 'fails to update a request' do + + allow_any_instance_of(Request).to receive(:update).and_return(false) + + put( + "/api/v1/requests/#{id}", + headers:, + params: { + name: 'My request', + quantity: 150, + due_date: Date.current + 6.months, + comment: 'My comment', + temperature: 'Chaud', + photoperiod: 4 + } + ) + + expect(status).to eq(422) + expect(response.parsed_body.dig('error', 'message')).not_to be_blank + end + end + end + context 'when 404' do + it_behaves_like 'with authenticated grower' do + it 'can\'t update a request that doesn\'t exist' do + put( + '/api/v1/requests/999', + headers:, + params: { + name: 'My request', + quantity: 150, + due_date: Date.current + 6.months, + comment: 'My comment', + temperature: 'Chaud', + photoperiod: 4 + } + ) + + expect(status).to eq(404) + expect(response.parsed_body.dig('error', 'message')).not_to be_blank + end + end + end + context 'when 401' do + it_behaves_like 'without authentication' do + it 'can\'t update a request' do + put( + "/api/v1/requests/#{id}", + headers:, + params: { + name: 'My request', + quantity: 150, + due_date: Date.current + 6.months, + comment: 'My comment', + temperature: 'Chaud', + photoperiod: 4 + } + ) + expect(status).to eq(401) + end + end + end + end end diff --git a/test/fixtures/requests.yml b/test/fixtures/requests.yml index e1bfa92..f018397 100644 --- a/test/fixtures/requests.yml +++ b/test/fixtures/requests.yml @@ -53,6 +53,33 @@ request2: zone: *2 time: *3 +request3: + id: 3 + requester_first_name: Alice + requester_last_name: Johnson + requester_email: alice.johnson@example.com + laboratory: Research Lab + handler_id: 3 + plant_stage_id: 5 + name: Research request + plant_name: Lettuce + plant_stage_name: germination + status: pending + comment: This is a request for research purposes. + due_date: 2021-06-15 + quantity: 50 + temperature: "Cool" + photoperiod: 12 + created_at: !ruby/object:ActiveSupport::TimeWithZone + utc: &1 2021-01-20 14:35:08.434029000 Z + zone: &2 !ruby/object:ActiveSupport::TimeZone + name: Etc/UTC + time: *1 + updated_at: !ruby/object:ActiveSupport::TimeWithZone + utc: &3 2021-01-20 14:35:08.434029000 Z + zone: *2 + time: *3 + # == Schema Information # # Table name: requests From ff51f7b6ad27f1e52e49157e47e15ca4235f4967 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Leli=C3=A8vre?= Date: Thu, 19 Dec 2024 11:53:05 +0100 Subject: [PATCH 2/5] rubocop --- spec/acceptance/api/v1/requests_controller_spec.rb | 3 +-- spec/requests/api/v1/requests_spec.rb | 4 +++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/spec/acceptance/api/v1/requests_controller_spec.rb b/spec/acceptance/api/v1/requests_controller_spec.rb index 8ec9f80..5ff7e92 100644 --- a/spec/acceptance/api/v1/requests_controller_spec.rb +++ b/spec/acceptance/api/v1/requests_controller_spec.rb @@ -238,7 +238,6 @@ end put '/api/v1/requests/:id' do - let!(:request3) { requests(:request3) } let(:id) { request3.id } @@ -262,7 +261,7 @@ type: :integer let(:plant_stage_id) { Plant.last.plant_stages.last.id } - let(:name) { 'My request'} + let(:name) { 'My request' } let(:plant_name) { Plant.last.name } let(:plant_stage_name) { Plant.last.plant_stages.last.name } let(:due_date) { Date.current + 6.months } diff --git a/spec/requests/api/v1/requests_spec.rb b/spec/requests/api/v1/requests_spec.rb index d4aeabc..b79dfaa 100644 --- a/spec/requests/api/v1/requests_spec.rb +++ b/spec/requests/api/v1/requests_spec.rb @@ -451,13 +451,13 @@ end end end + context 'when 422' do let!(:request3) { requests(:request3) } let!(:id) { request3.id } it_behaves_like 'with authenticated grower' do it 'fails to update a request' do - allow_any_instance_of(Request).to receive(:update).and_return(false) put( @@ -478,6 +478,7 @@ end end end + context 'when 404' do it_behaves_like 'with authenticated grower' do it 'can\'t update a request that doesn\'t exist' do @@ -499,6 +500,7 @@ end end end + context 'when 401' do it_behaves_like 'without authentication' do it 'can\'t update a request' do From 5f8011a6bc3bcc4879e55179dbdacde4b1c44993 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Leli=C3=A8vre?= Date: Thu, 19 Dec 2024 15:35:07 +0100 Subject: [PATCH 3/5] fix bug --- app/controllers/api/v1/requests_controller.rb | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/app/controllers/api/v1/requests_controller.rb b/app/controllers/api/v1/requests_controller.rb index 8c16096..e946dcf 100644 --- a/app/controllers/api/v1/requests_controller.rb +++ b/app/controllers/api/v1/requests_controller.rb @@ -50,7 +50,8 @@ def create end def update - if @request.update(update_request_params) + plant_attributes_from_params(@request) + if @request.update(request_params) render json: @request.to_blueprint, status: :ok else render_validation_error(@request) @@ -106,19 +107,12 @@ def set_request def request_params params.permit( - :plant_stage_id, :name, :plant_name, :plant_stage_name, :quantity, :due_date, + :plant_stage_id, :name, :quantity, :due_date, :comment, :temperature, :photoperiod, :requester_first_name, :requester_last_name, :requester_email, :laboratory ) end - def update_request_params - params.permit( - :plant_stage_id, :name, :plant_name, :plant_stage_name, - :quantity, :due_date, :temperature, :photoperiod - ) - end - def plant_attributes_from_params(request) return if request_params[:plant_stage_id].blank? From d5ddf44d91a038cbbedcb9464ef07839ae139f51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Leli=C3=A8vre?= Date: Fri, 20 Dec 2024 09:36:04 +0100 Subject: [PATCH 4/5] Update requests_controller.rb --- app/controllers/api/v1/requests_controller.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/controllers/api/v1/requests_controller.rb b/app/controllers/api/v1/requests_controller.rb index e946dcf..1d93328 100644 --- a/app/controllers/api/v1/requests_controller.rb +++ b/app/controllers/api/v1/requests_controller.rb @@ -107,7 +107,7 @@ def set_request def request_params params.permit( - :plant_stage_id, :name, :quantity, :due_date, + :plant_stage_id, :plant_name, :plant_stage_name, :name, :quantity, :due_date, :comment, :temperature, :photoperiod, :requester_first_name, :requester_last_name, :requester_email, :laboratory ) From 60e0dab3f5d14e822b6666c9f137b2b2f1b7df57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Leli=C3=A8vre?= Date: Fri, 20 Dec 2024 10:24:27 +0100 Subject: [PATCH 5/5] Update seeds.rb --- db/seeds.rb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/db/seeds.rb b/db/seeds.rb index debdaf0..c8c52e1 100644 --- a/db/seeds.rb +++ b/db/seeds.rb @@ -147,7 +147,9 @@ plant_stage: Plant.last.plant_stages.last, comment: Faker::Movies::LordOfTheRings.quote, due_date: Date.current + 2.months, - quantity: 200 + quantity: 200, + temperature: 'Froid', + photoperiod: 16 ) # RequestDistributions