Skip to content

Commit

Permalink
Beneficiary's Addresses API (#1676)
Browse files Browse the repository at this point in the history
  • Loading branch information
samnang authored Jan 3, 2025
1 parent d066c76 commit fd54aef
Show file tree
Hide file tree
Showing 8 changed files with 217 additions and 4 deletions.
34 changes: 34 additions & 0 deletions app/controllers/api/v1/addresses_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module API
module V1
class AddressesController < BaseController
def index
respond_with_resource(beneficiary.addresses)
end

def create
validate_request_schema(
with: ::V1::BeneficiaryAddressRequestSchema,
location: ->(resource) { api_v1_beneficiary_address_path(beneficiary, resource) }
) do |permitted_params|
beneficiary.addresses.create!(permitted_params)
end
end

def show
address = beneficiary.addresses.find(params[:id])
respond_with_resource(address)
end

def destroy
address = beneficiary.addresses.find(params[:id])
address.destroy!

head :no_content
end

def beneficiary
@beneficiary ||= current_account.beneficiaries.find(params[:beneficiary_id])
end
end
end
end
6 changes: 4 additions & 2 deletions app/models/account.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class Account < ApplicationRecord
DEFAULT_PERMISSIONS_BITMASK = 0
TWILIO_ACCOUNT_SID_PREFIX = "AC".freeze
DEFAULT_PLATFORM_PROVIDER = "twilio".freeze
PLATFORM_PROVIDERS = [DEFAULT_PLATFORM_PROVIDER, "somleng"].freeze
PLATFORM_PROVIDERS = [ DEFAULT_PLATFORM_PROVIDER, "somleng" ].freeze
DEFAULT_CALL_FLOW_LOGIC = "CallFlowLogic::HelloWorld".freeze

include MetadataHelpers
Expand All @@ -27,6 +27,8 @@ class Account < ApplicationRecord

has_many :contacts,
dependent: :restrict_with_error
has_many :beneficiaries, class_name: "Contact",
dependent: :restrict_with_error

has_many :callouts,
dependent: :restrict_with_error
Expand Down Expand Up @@ -93,7 +95,7 @@ def write_batch_operation_access_token
end

def phone_call_queue_limit
[settings.fetch("phone_call_queue_limit").to_i, 1000].max
[ settings.fetch("phone_call_queue_limit").to_i, 1000 ].max
end

def from_phone_number
Expand Down
22 changes: 22 additions & 0 deletions app/request_schemas/v1/beneficiary_address_request_schema.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
module V1
class BeneficiaryAddressRequestSchema < BaseRequestSchema
params do
required(:data).value(:hash).schema do
required(:type).filled(:str?, eql?: "address")
required(:attributes).value(:hash).schema do
required(:iso_region_code).maybe(:string)
optional(:administrative_division_level_2_code).maybe(:string)
optional(:administrative_division_level_2_name).maybe(:string)
optional(:administrative_division_level_3_code).maybe(:string)
optional(:administrative_division_level_3_name).maybe(:string)
optional(:administrative_division_level_4_code).maybe(:string)
optional(:administrative_division_level_4_name).maybe(:string)
end
end
end

def output
super.except(:account)
end
end
end
2 changes: 1 addition & 1 deletion app/request_schemas/v1/beneficiary_request_schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class BeneficiaryRequestSchema < BaseRequestSchema
optional(:metadata).value(:hash)

optional(:address).filled(:hash).schema do
optional(:iso_region_code).maybe(:string)
required(:iso_region_code).maybe(:string)
optional(:administrative_division_level_2_code).maybe(:string)
optional(:administrative_division_level_2_name).maybe(:string)
optional(:administrative_division_level_3_code).maybe(:string)
Expand Down
4 changes: 3 additions & 1 deletion config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@
end

namespace :v1, module: "api/v1", as: "api_v1", defaults: { format: "json" } do
resources :beneficiaries, only: [ :index, :create, :show, :update ]
resources :beneficiaries, only: [ :index, :create, :show, :update ] do
resources :addresses, only: [ :index, :create, :show, :destroy ]
end
end

namespace "api", defaults: { format: "json" } do
Expand Down
5 changes: 5 additions & 0 deletions spec/factories.rb
Original file line number Diff line number Diff line change
Expand Up @@ -216,4 +216,9 @@

association :audio_file, factory: :active_storage_attachment, filename: "test.mp3"
end

factory :address, class: "BeneficiaryAddress" do
beneficiary
iso_region_code { "KH-1" }
end
end
84 changes: 84 additions & 0 deletions spec/requests/open_ews_api/v1/beneficiaries/addresses_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
require "rails_helper"

RSpec.resource "Beneficiary's Addresses" do
get "/v1/beneficiaries/:beneficiary_id/addresses" do
example "List all a beneficiary's addresses" do
account = create(:account)
beneficiary = create(:beneficiary, account:)
address1 = create(:address, beneficiary:)
address2 = create(:address, beneficiary:)
other_beneficiary = create(:beneficiary)
_other_address = create(:address, beneficiary: other_beneficiary)

set_authorization_header_for(account)
do_request(beneficiary_id: beneficiary.id)

expect(response_status).to eq(200)
expect(response_body).to match_jsonapi_resource_collection_schema("address")
expect(json_response.fetch("data").pluck("id")).to contain_exactly(
address1.id.to_s,
address2.id.to_s
)
end
end

post "/v1/beneficiaries/:beneficiary_id/addresses" do
example "Create an address for a beneficiary" do
account = create(:account)
beneficiary = create(:beneficiary, account:)

set_authorization_header_for(account)
do_request(
beneficiary_id: beneficiary.id,
data: {
type: :address,
attributes: {
iso_region_code: "KH-1",
administrative_division_level_2_code: "01"
}
}
)

expect(response_status).to eq(201)
expect(response_body).to match_jsonapi_resource_schema("address")
expect(jsonapi_response_attributes).to include(
"iso_region_code" => "KH-1",
"administrative_division_level_2_code" => "01"
)
end
end

get "/v1/beneficiaries/:beneficiary_id/addresses/:id" do
example "Get an address for a beneficiary" do
account = create(:account)
beneficiary = create(:beneficiary, account:)
address = create(:address, beneficiary:)

set_authorization_header_for(account)
do_request(
beneficiary_id: beneficiary.id,
id: address.id
)

expect(response_status).to eq(200)
expect(response_body).to match_jsonapi_resource_schema("address")
expect(json_response.dig("data", "id")).to eq(address.id.to_s)
end
end

delete "/v1/beneficiaries/:beneficiary_id/addresses/:id" do
example "Delete an address for a beneficiary" do
account = create(:account)
beneficiary = create(:beneficiary, account:)
address = create(:address, beneficiary:)

set_authorization_header_for(account)
do_request(
beneficiary_id: beneficiary.id,
id: address.id
)

expect(response_status).to eq(204)
end
end
end
64 changes: 64 additions & 0 deletions spec/requests/open_ews_api/v1/beneficiaries_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,13 @@

RSpec.resource "Beneficiaries" do
get "/v1/beneficiaries" do
with_options scope: :filter do
parameter(
:status, "Must be one of #{Contact.status.values.map { |t| "`#{t}`" }.join(", ")}.",
required: false
)
end

example "List all active beneficiaries" do
account = create(:account)
account_beneficiary = create(:beneficiary, account:)
Expand Down Expand Up @@ -35,6 +42,63 @@
end

post "/v1/beneficiaries" do
with_options scope: %i[data attributes] do
parameter(
:msisdn, "Phone number in E.164 format or shortcode.",
required: true
)
parameter(
:language_code, "Language code in ISO 639-1 format.",
required: false
)
parameter(
:gender, "Must be one of `M` or `F`.",
required: false
)
parameter(
:date_of_birth, "Date of birth in `YYYY-MM-DD` format.",
required: false
)
parameter(
:iso_country_code, "The ISO 3166-1 alpha-2 country code of the phone number. It must be matched with the country of `msisdn` parameter.",
required: false
)
parameter(
:metadata, "Set of key-value pairs that you can attach to an object. This can be useful for storing additional information about the object in a structured format.",
required: false
)
with_options scope: :address do
parameter(
:iso_region_code, "ISO 3166-2 of the country's subdivisions(e.g., provinces or states)",
required: false
)
parameter(
:administrative_division_level_2_code, "Code of administrative division level 2(e.g. district)",
required: false
)
parameter(
:administrative_division_level_2_name, "Name of administrative division level 2",
required: false
)
parameter(
:administrative_division_level_3_code, "Code of administrative division level 2(e.g. commune)",
required: false
)
parameter(
:administrative_division_level_3_name, "Name of administrative division level 3",
required: false
)
parameter(
:administrative_division_level_4_code, "Code of administrative division level 4(e.g. village)",
required: false
)
parameter(
:administrative_division_level_4_name, "Name of administrative division level 4",
required: false
)
end
end

example "Create a beneficiary" do
account = create(:account)

Expand Down

0 comments on commit fd54aef

Please sign in to comment.