diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb index 602ee085b..dfa2eaf7f 100644 --- a/app/controllers/api_controller.rb +++ b/app/controllers/api_controller.rb @@ -2,21 +2,17 @@ class ApiController < ApplicationController skip_before_action :require_login - before_action :authorize_api_access + before_action :authorize_api_access, :contributor def show - contributor = Contributor.find_by(external_id: external_id) - - unless contributor + if contributor + render json: { status: 'ok', data: { first_name: contributor.first_name, external_id: contributor.external_id } }, status: :ok + else render json: { status: 'error', message: 'Not found' }, status: :not_found - return end - - render json: { status: 'ok', data: { first_name: contributor.first_name, external_id: contributor.external_id } }, status: :ok end def create - contributor = Contributor.find_by(external_id: external_id) if contributor render json: { status: 'ok', @@ -41,8 +37,51 @@ def create end end + def current_request + if contributor + current_personalized_request = contributor.received_messages.first + render json: { + status: 'ok', + data: { + id: current_personalized_request.id, + personalized_text: current_personalized_request.text, + contributor_replies_count: contributor.replies.where(request_id: current_personalized_request.request.id).count + } + }, status: :ok + else + render json: { status: 'error', message: 'Not found' }, status: :not_found + end + end + + def messages + if contributor + message = Message.new( + request: contributor.active_request, + text: messages_params[:text], + sender: contributor + ) + message.raw_data.attach( + io: StringIO.new(JSON.generate(messages_params)), + filename: 'api.json', + content_type: 'application/json' + ) + + if message.save! + render json: { status: 'ok', data: { id: message.id, text: message.text } }, status: :created + else + render json: { status: 'error', message: 'Record could not be created' }, status: :unprocessable_entity + end + else + render json: { status: 'error', message: 'Not found' }, status: :not_found + end + end + private + def contributor + @contributor ||= Contributor.find_by(external_id: external_id) + end + def authorize_api_access authenticate_or_request_with_http_token do |token, _options| ActiveSupport::SecurityUtils.secure_compare(token, Setting.api_token) @@ -56,4 +95,8 @@ def external_id def onboard_params params.permit(:first_name) end + + def messages_params + params.permit(:text) + end end diff --git a/config/routes.rb b/config/routes.rb index f72e8c7a7..3016fabfa 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -122,4 +122,6 @@ get '/v1/contributors/me', to: 'api#show' post '/v1/contributors', to: 'api#create' + get '/v1/contributors/me/requests/current', to: 'api#current_request' + post '/v1/contributors/me/messages', to: 'api#messages' end diff --git a/spec/requests/api_spec.rb b/spec/requests/api_spec.rb index da0dd8317..0e235a021 100644 --- a/spec/requests/api_spec.rb +++ b/spec/requests/api_spec.rb @@ -147,4 +147,139 @@ end end end + + describe 'GET /contributors/me/requests/current' do + subject { -> { get '/v1/contributors/me/requests/current', headers: headers } } + + describe 'not authorized' do + context 'missing auth headers' do + it 'returns not authorized' do + subject.call + + expect(response).to have_http_status(:unauthorized) + expect(response.code.to_i).to eq(401) + end + end + + context 'invalid token' do + let(:headers) { { 'Authorization' => "Bearer #{SecureRandom.urlsafe_base64(128)}" } } + + it 'returns not authorized' do + subject.call + + expect(response).to have_http_status(:unauthorized) + expect(response.code.to_i).to eq(401) + end + end + end + + describe 'authorized' do + before { allow(Setting).to receive(:api_token).and_return(token) } + let(:headers) { valid_headers } + + context 'unknown contributor' do + it 'returns not found' do + subject.call + + expect(response).to have_http_status(:not_found) + expect(response.code.to_i).to eq(404) + end + + it 'returns error status with message Not found' do + subject.call + + expect(response.body).to eq({ status: 'error', message: 'Not found' }.to_json) + end + end + + context 'known contributor' do + let(:contributor) { create(:contributor, external_id: external_id) } + let!(:message) { create(:message, :outbound, recipient_id: contributor.id) } + let(:expected_response) do + { + status: 'ok', + data: + { + id: message.id, + personalized_text: message.text, + contributor_replies_count: contributor.replies.where(request_id: message.request.id).count + } + }.to_json + end + + it 'returns resource data' do + subject.call + + expect(response.body).to eq(expected_response) + expect(response.code.to_i).to eq(200) + end + end + end + + describe 'POST /v1/contributors/me/messages' do + subject { -> { post v1_contributors_me_messages_path, params: { text: 'Create this message' }, headers: headers } } + + describe 'not authorized' do + context 'missing auth headers' do + it 'returns not authorized' do + subject.call + + expect(response).to have_http_status(:unauthorized) + expect(response.code.to_i).to eq(401) + end + end + + context 'invalid token' do + let(:headers) { { 'Authorization' => "Bearer #{SecureRandom.urlsafe_base64(128)}" } } + + it 'returns not authorized' do + subject.call + + expect(response).to have_http_status(:unauthorized) + expect(response.code.to_i).to eq(401) + end + end + end + + describe 'authorized' do + before { allow(Setting).to receive(:api_token).and_return(token) } + + let(:headers) { valid_headers } + let(:expected_response) do + { + status: 'ok', + data: { + id: Message.first.id, + text: Message.first.text + } + } + end + + context 'unknown contributor' do + it 'returns not found' do + subject.call + + expect(response).to have_http_status(:not_found) + expect(response.code.to_i).to eq(404) + end + end + + context 'known contributor' do + let!(:contributor) { create(:contributor, external_id: external_id) } + let!(:request) { create(:request) } + + it 'creates a message' do + expect { subject.call }.to change(Message, :count).by(1) + end + + it 'returns resource data' do + subject.call + + expect(response.body).to eq(expected_response.to_json) + expect(response.code.to_i).to eq(201) + end + end + end + end + end end