Browse Source

Handle empty cities: places that return no items

tags/0.3.6^2
Bèr Kessels 1 month ago
parent
commit
26e0c969bf

+ 26
- 0
app/models/city.rb View File

@@ -27,6 +27,8 @@ module Hours
geometry: geometry,
ignore_undefined_attributes: ignore_undefined_attributes
)

@bbox ||= []
end

def slug
@@ -36,6 +38,30 @@ module Hours
def name
@name || 'onbekend'
end

def shape
return if bbox.empty?
RGeo::GeoJSON::EntityFactory.new.feature(factory.polygon(bbox_as_ring))
end

private

def bbox_as_ring
# Example BBOX:
# [0] 5.7576206,
# [1] 51.7905891,
# [2] 5.9083469,
# [3] 51.8946209
top_left = factory.point(bbox[0], bbox[1])
top_right = factory.point(bbox[2], bbox[1])
bottom_right = factory.point(bbox[2], bbox[3])
bottom_left = factory.point(bbox[0], bbox[3])
factory.linear_ring([top_left, top_right, bottom_right, bottom_left])
end

def factory
@factory ||= RGeo::Cartesian.simple_factory(srid: 4326)
end
end
end
end

+ 10
- 3
app/projections/city_query.rb View File

@@ -41,16 +41,23 @@ module Hours
private

def city
return @city if @city

response = @http_client.get('/autocomplete', city_params)

Hours::Models::City.from_geojson_feature(
@city = Hours::Models::City.from_geojson_feature(
RGeo::GeoJSON.decode(response.body).first
)
end

def places
## TODO: consider making the query of collection lazy.
response = @http_client.get('/features', city_center_params)
# TODO: consider making the query of collection lazy.
response = @http_client.post('/features') do |request|
request.body = { shape: RGeo::GeoJSON.encode(city.shape) }.to_json
request.headers[:content_type] = 'application/json'
request.params = city_center_params
end

places = RGeo::GeoJSON.decode(response.body)

places.map do |feature|

+ 2
- 0
lib/app.rb View File

@@ -129,6 +129,8 @@ module Hours
page_param
)
erb :region
rescue Faraday::BadRequestError
400
end

get %r{/places/(?<id>[\w:]+)}, provides: 'html' do

+ 1
- 1
test/fixtures/vcr_cassettes/city_arnhem.yml View File

@@ -31,7 +31,7 @@ http_interactions:
http_version: null
recorded_at: Sat, 13 Jun 2020 12:36:50 GMT
- request:
method: get
method: post
uri: http://localhost:4000/features?lat=51.984257&limit=20&lon=5.9108573&type%5B%5D=poi
body:
encoding: US-ASCII

+ 1
- 1
test/fixtures/vcr_cassettes/city_den_bosch.yml View File

@@ -30,7 +30,7 @@ http_interactions:
http_version: null
recorded_at: Sat, 13 Jun 2020 13:19:55 GMT
- request:
method: get
method: post
uri: http://localhost:4000/features?lat=0&limit=20&lon=0&type%5B%5D=poi
body:
encoding: US-ASCII

+ 20
- 19
test/fixtures/vcr_cassettes/city_eindhoven.yml
File diff suppressed because it is too large
View File


+ 59
- 0
test/fixtures/vcr_cassettes/city_error_400.yml View File

@@ -0,0 +1,59 @@
---
http_interactions:
- request:
method: get
uri: http://localhost:4000/autocomplete?limit=1&q=foo&type%5B%5D=city
body:
encoding: US-ASCII
string: ''
headers:
User-Agent:
- Faraday v1.0.0
response:
status:
code: 200
message: OK
headers:
content-length:
- '85'
connection:
- close
content-type:
- application/json
cache-control:
- max-age=3600
date:
- Mon, 15 Jun 2020 14:40:53 GMT
body:
encoding: UTF-8
string: '{"type":"FeatureCollection","geocoding":{"version":"0.1.0","query":""},"features":[]}'
http_version: null
recorded_at: Mon, 15 Jun 2020 14:40:53 GMT
- request:
method: post
uri: http://localhost:4000/features?lat=0&limit=20&lon=0&type%5B%5D=poi
body:
encoding: UTF-8
string: ''
headers:
User-Agent:
- Faraday v1.0.0
response:
status:
code: 400
message: Bad Request
headers:
content-length:
- '70'
connection:
- close
content-type:
- application/json
date:
- Mon, 15 Jun 2020 14:40:53 GMT
body:
encoding: UTF-8
string: '{"short":"validation error","long":"invalid json: Content type error"}'
http_version: null
recorded_at: Mon, 15 Jun 2020 14:40:53 GMT
recorded_with: VCR 5.1.0

+ 2
- 2
test/fixtures/vcr_cassettes/city_nijmegen.yml View File

@@ -31,11 +31,11 @@ http_interactions:
http_version: null
recorded_at: Sun, 14 Jun 2020 16:42:06 GMT
- request:
method: get
method: post
uri: http://localhost:4000/features?lat=51.8427385&limit=20&lon=5.8634696&type%5B%5D=poi
body:
encoding: US-ASCII
string: ''
string: '{ "shape": { "type": "Feature", "properties": {}, "geometry": { "type": "Polygon", "coordinates": [ [ [ 5.840950012207031, 51.855767762634734 ], [ 5.815973281860352, 51.83683823374741 ], [ 5.82996368408203, 51.81593757915817 ], [ 5.87493896484375, 51.816362054390844 ], [ 5.901889801025391, 51.837315546578246 ], [ 5.8728790283203125, 51.84887557848711 ], [ 5.840950012207031, 51.855767762634734 ] ] ] } } }'
headers:
User-Agent:
- Faraday v1.0.0

+ 1
- 1
test/fixtures/vcr_cassettes/city_zuidwolde.yml View File

@@ -32,7 +32,7 @@ http_interactions:
http_version: null
recorded_at: Sun, 14 Jun 2020 16:09:06 GMT
- request:
method: get
method: post
uri: http://localhost:4000/features?lat=53.262224708469496&limit=20&lon=6.60072720659541&type%5B%5D=poi
body:
encoding: US-ASCII

+ 1
- 1
test/fixtures/vcr_cassettes/city_zuidwolde_drenthe.yml View File

@@ -32,7 +32,7 @@ http_interactions:
http_version: null
recorded_at: Sun, 14 Jun 2020 16:09:08 GMT
- request:
method: get
method: post
uri: http://localhost:4000/features?lat=52.66255725914056&limit=20&lon=6.41926898445426&type%5B%5D=poi
body:
encoding: US-ASCII

+ 1
- 1
test/fixtures/vcr_cassettes/city_zuidwolde_groningen.yml View File

@@ -32,7 +32,7 @@ http_interactions:
http_version: null
recorded_at: Sun, 14 Jun 2020 16:09:08 GMT
- request:
method: get
method: post
uri: http://localhost:4000/features?lat=53.262224708469496&limit=20&lon=6.60072720659541&type%5B%5D=poi
body:
encoding: US-ASCII

+ 10
- 2
test/integration/web/view_regions_test.rb View File

@@ -126,12 +126,20 @@ describe 'web views regions' do

describe 'GET /in/eindhoven empty place' do
it 'shows empty text' do
skip 'implement searching with bounding box. Now it returns items'\
' ordered from NULL_ISLAND'
#@INK: implementing bbox as shape. but the Eindhoven vcr-cassette has no bbox
VCR.use_cassette :city_eindhoven do
visit '/in/eindhoven'
end
assert_text page, 'No places found in Eindhoven'
end
end

describe 'GET /in/foo returns a 400 error' do
it 'shows an error message' do
VCR.use_cassette :city_error_400 do
visit '/in/foo'
end
assert_equal 400, page.status_code
end
end
end

+ 28
- 9
test/projections/city_query_test.rb View File

@@ -17,29 +17,48 @@ describe Hours::Projections::CityQuery do

let(:search_response) { OpenStruct.new(body: body.to_json, code: 200) }
let(:features_response) { OpenStruct.new(body: body.to_json, code: 200) }
let(:emtpy_response) { OpenStruct.new(body: '{}', code: 200) }
let(:error_response) { OpenStruct.new(body: '', code: 500) }
let(:error_response) { OpenStruct.new(body: '[]', code: 400) }

let(:http_client) do
Minitest::Mock.new
end
class ClientRaises
def initialize(search_response, error_response)
@search_response = search_response
@error_response = error_response
end

subject do
Hours::Projections::CityQuery.new(http_client)
def get(*args)
@search_response
end
def post(*args)
raise(
Faraday::BadRequestError,
{ status: 400, headers: [], body: @error_response }
)
end
end

it '#handle fetches a single city and then its places from bragi' do
http_client = Minitest::Mock.new
http_client.expect(
:get,
search_response,
['/autocomplete', { q: 'nijmegen', limit: 1, type: ['city'] }]
)
subject = Hours::Projections::CityQuery.new(http_client)
# We cannot test that the correct req-args and req-body is set in the block
# because, somehow, minitest cannot move into the block easily.
# TODO: find out how to handle this: https://github.com/seattlerb/minitest/issues/545
http_client.expect(
:get,
:post,
features_response,
['/features', { type: ['poi'], lat: 0.5, lon: 102.0, limit: 20 }]
['/features'] # { type: ['poi'], lat: 0.5, lon: 102.0, limit: 20 }]
)
assert_kind_of Hours::Models::City, subject.handle('nijmegen')
assert_mock http_client
end

it '#handle catches error 400 from upstream' do
http_client = ClientRaises.new(search_response, error_response)
subject = Hours::Projections::CityQuery.new(http_client)
assert_raises(Faraday::BadRequestError) { subject.handle('nijmegen') }
end
end

Loading…
Cancel
Save