Add DFC Address API endpoint

This commit is contained in:
Maikel Linke
2023-08-24 15:52:21 +10:00
parent a8d15154a2
commit 20b09b5352
7 changed files with 134 additions and 6 deletions

View File

@@ -0,0 +1,61 @@
# frozen_string_literal: true
# Controller used to provide the CatalogItem API for the DFC application
module DfcProvider
class AddressesController < DfcProvider::ApplicationController
def show
address = Spree::Address.find(params.require(:id))
return not_found unless authorized(address)
dfc_address = AddressBuilder.address(address)
render json: DfcIo.export(dfc_address)
end
private
# Does the current user have access to this address?
#
# It's possible to guess address ids and therefore we need to prevent the
# collection of sensitive customer data.
#
# We may want to extend the list of authorised addresses once the DFC API
# references them. To start with, we would only need enterprise addresses
# but I included a few more options to show how this will probably evolve.
#
# Currently not checked models:
#
# - Spree::Card
# - Spree::Order
# - Spree::Shipment
# - Subscription
def authorized(address)
current_user.ship_address_id == address.id ||
current_user.bill_address_id == address.id ||
[
customer_address(address),
public_enterprise_group_address(address),
public_enterprise_address(address),
managed_enterprise_address(address),
].any?(&:exists?)
end
def customer_address(address)
current_user.customers.where(bill_address: address).or(
current_user.customers.where(ship_address: address)
)
end
def public_enterprise_group_address(address)
EnterpriseGroup.where(address:)
end
def public_enterprise_address(address)
Enterprise.activated.visible.is_distributor.where(address:)
end
def managed_enterprise_address(address)
current_user.enterprises.where(address:)
end
end
end

View File

@@ -2,9 +2,8 @@
class AddressBuilder < DfcBuilder
def self.address(address)
# TODO add url helper/address contoller so we can do urls.address_url(address.id)
DataFoodConsortium::Connector::Address.new(
"http://test.host/api/dfc-v1.7/address/#{address.id}",
urls.address_url(address),
street: address.address1,
postalCode: address.zipcode,
city: address.city,

View File

@@ -1,6 +1,7 @@
# frozen_string_literal: true
DfcProvider::Engine.routes.draw do
resources :addresses, only: [:show]
resources :enterprises, only: [:show] do
resources :catalog_items, only: [:index, :show, :update]
resources :supplied_products, only: [:create, :show, :update]

View File

@@ -0,0 +1,41 @@
# frozen_string_literal: true
require DfcProvider::Engine.root.join("spec/swagger_helper")
describe "Addresses", type: :request, swagger_doc: "dfc-v1.7/swagger.yaml", rswag_autodoc: true do
let(:user) { create(:oidc_user) }
let(:address) { create(:address, id: 40_000) }
let(:result) { json_response }
before { login_as user }
path "/api/dfc-v1.7/addresses/{id}" do
get "Show address" do
parameter name: :id, in: :path, type: :string
produces "application/json"
response "200", "successful" do
let(:id) { address.id }
before { create(:enterprise, owner: user, address:) }
run_test! do
expect(result["@id"]).to eq "http://test.host/api/dfc-v1.7/addresses/40000"
expect(result["@type"]).to eq "dfc-b:Address"
end
end
response "404", "not found" do
context "when the address doesn't exist" do
let(:id) { 0 }
run_test!
end
context "when the address doesn't belong to you" do
let(:id) { address.id }
run_test!
end
end
end
end
end

View File

@@ -14,7 +14,7 @@ describe AddressBuilder do
describe ".address" do
it "assigns a semantic id" do
expect(result.semanticId).to eq(
"http://test.host/api/dfc-v1.7/address/1"
"http://test.host/api/dfc-v1.7/addresses/1"
)
end

View File

@@ -9,7 +9,7 @@ describe EnterpriseBuilder do
:enterprise,
id: 10_000, name: "Fabi's Farm",
description: "The place where stuff grows", abn: "123 456 789 0",
address: build(:address, city: "Melbourne"),
address: build(:address, id: 40_000, city: "Melbourne"),
)
}
let(:variant) {

View File

@@ -38,6 +38,32 @@ security:
- ofn_api_token: []
- ofn_session: []
paths:
"/api/dfc-v1.7/addresses/{id}":
get:
summary: Show address
parameters:
- name: id
in: path
required: true
schema:
type: string
responses:
'200':
description: successful
content:
application/json:
examples:
test_example:
value:
"@context": https://www.datafoodconsortium.org
"@id": http://test.host/api/dfc-v1.7/addresses/40000
"@type": dfc-b:Address
dfc-b:hasStreet: 10 Lovely Street
dfc-b:hasPostalCode: '20170'
dfc-b:hasCity: Herndon
dfc-b:hasCountry: Australia
'404':
description: not found
"/api/dfc-v1.7/enterprises/{enterprise_id}/catalog_items":
parameters:
- name: enterprise_id
@@ -64,7 +90,7 @@ paths:
dfc-b:affiliates: http://test.host/api/dfc-v1.7/enterprises/10000
- "@id": http://test.host/api/dfc-v1.7/enterprises/10000
"@type": dfc-b:Enterprise
dfc-b:hasAddress: http://test.host/api/dfc-v1.7/address/40000
dfc-b:hasAddress: http://test.host/api/dfc-v1.7/addresses/40000
dfc-b:hasName: Fred's Farm
dfc-b:hasDescription: Beautiful
dfc-b:supplies: http://test.host/api/dfc-v1.7/enterprises/10000/supplied_products/10001
@@ -221,7 +247,7 @@ paths:
"@graph":
- "@id": http://test.host/api/dfc-v1.7/enterprises/10000
"@type": dfc-b:Enterprise
dfc-b:hasAddress: http://test.host/api/dfc-v1.7/address/40000
dfc-b:hasAddress: http://test.host/api/dfc-v1.7/addresses/40000
dfc-b:hasName: Fred's Farm
dfc-b:hasDescription: This is an awesome enterprise
dfc-b:VATnumber: 123 456