From c46482aac783b2337872ea7517e09ab1ae0ec5f3 Mon Sep 17 00:00:00 2001 From: Ryan Arakawa Date: Mon, 9 Mar 2026 15:28:14 -0500 Subject: [PATCH] add request_changes endpoint - submitter is found by slug and authorized --- .../submitters_request_changes_controller.rb | 20 ++++++ config/routes.rb | 5 ++ .../api_submitters_request_changes_spec.rb | 61 +++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 app/controllers/api/submitters_request_changes_controller.rb create mode 100644 spec/requests/api_submitters_request_changes_spec.rb diff --git a/app/controllers/api/submitters_request_changes_controller.rb b/app/controllers/api/submitters_request_changes_controller.rb new file mode 100644 index 00000000..5ec070db --- /dev/null +++ b/app/controllers/api/submitters_request_changes_controller.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module Api + class SubmittersRequestChangesController < ApiBaseController + before_action :load_submitter + + def request_changes + @submitter.update!(changes_requested_at: Time.current, completed_at: nil) unless @submitter.changes_requested_at? + + render json: Submitters::SerializeForApi.call(@submitter), status: :ok + end + + private + + def load_submitter + @submitter = Submitter.find_by!(slug: params[:slug]) + authorize! :read, @submitter + end + end +end diff --git a/config/routes.rb b/config/routes.rb index f886341d..1e673b04 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -34,6 +34,11 @@ Rails.application.routes.draw do resources :submitter_email_clicks, only: %i[create] resources :submitter_form_views, only: %i[create] resources :submitters, only: %i[index show update] + resources :submitters, only: %i[], param: 'slug' do + member do + post :request_changes, controller: 'submitters_request_changes' + end + end resources :submissions, only: %i[index show create destroy] do resources :documents, only: %i[index], controller: 'submission_documents' resource :signed_document_url, only: %i[show] diff --git a/spec/requests/api_submitters_request_changes_spec.rb b/spec/requests/api_submitters_request_changes_spec.rb new file mode 100644 index 00000000..71260c50 --- /dev/null +++ b/spec/requests/api_submitters_request_changes_spec.rb @@ -0,0 +1,61 @@ +# frozen_string_literal: true + +describe 'API Submitters Request Changes' do + let(:account) { create(:account) } + let(:user) { create(:user, account:) } + let(:template) { create(:template, account:, author: user) } + let(:submission) { create(:submission, template:, account:, created_by_user: user) } + let(:submitter) do + create( + :submitter, + submission:, + account:, + completed_at: 1.hour.ago, + uuid: template.submitters.first['uuid'] + ) + end + + describe 'POST /api/submitters/:slug/request_changes' do + context 'when authenticated with a valid token' do + it 'clears completed_at and sets changes_requested_at' do + expect do + post "/api/submitters/#{submitter.slug}/request_changes", + headers: { 'x-auth-token': user.access_token.token } + end.to change { submitter.reload.changes_requested_at }.from(nil) + .and change { submitter.reload.completed_at }.to(nil) + + expect(response).to have_http_status(:ok) + end + + it 'is idempotent when changes already requested' do + submitter.update!(changes_requested_at: 1.hour.ago) + + expect do + post "/api/submitters/#{submitter.slug}/request_changes", + headers: { 'x-auth-token': user.access_token.token } + end.not_to(change { submitter.reload.changes_requested_at }) + + expect(response).to have_http_status(:ok) + end + end + + context 'when authenticated with a different account token' do + let(:other_user) { create(:user, account: create(:account)) } + + it 'returns forbidden' do + post "/api/submitters/#{submitter.slug}/request_changes", + headers: { 'x-auth-token': other_user.access_token.token } + + expect(response).to have_http_status(:forbidden) + end + end + + context 'when unauthenticated' do + it 'returns unauthorized' do + post "/api/submitters/#{submitter.slug}/request_changes" + + expect(response).to have_http_status(:unauthorized) + end + end + end +end