Skip to content

Commit aeae5cd

Browse files
committed
Accept a GeoJSON object (not only a string) for issue geometry
Conversions.to_geom / to_wkb called JSON.parse(geometry) unconditionally, so a JSON API request sending issue.geojson as an object hit JSON.parse(Hash), raised TypeError (not the rescued JSON::ParserError), and returned HTTP 500. Only a stringified GeoJSON blob worked. Add a coerce_geojson helper that accepts a String or an already-parsed object (Hash / ActionController::Parameters), mirroring the guard in .to_feature. The existing string path (and the web UI) are unchanged. Closes #393
1 parent 482b998 commit aeae5cd

2 files changed

Lines changed: 32 additions & 8 deletions

File tree

lib/redmine_gtt/conversions.rb

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -95,29 +95,40 @@ def self.geom_to_json(object, id: nil, properties: nil)
9595
GeomToJson.new.to_json(object, id: id, properties: properties)
9696
end
9797

98-
# Turn geometry attribute string (GeoJSON) into Rgeo object for database
99-
# use
98+
# Turn a geometry attribute into an Rgeo object for database use. The input
99+
# may be a GeoJSON String or an already-parsed GeoJSON object (a Hash, or
100+
# the ActionController::Parameters a JSON API request delivers).
100101
def self.to_geom(geometry)
101-
geojson = JSON.parse(geometry)
102102
RGeo::GeoJSON.decode(
103-
geojson,
103+
coerce_geojson(geometry),
104104
json_parser: :json,
105105
geo_factory: RGeo::Cartesian.preferred_factory(has_z_coordinate: true, srid: 4326)
106106
).geometry
107107
end
108108

109-
# Turn geometry attribute string into WKB for database use
109+
# Turn a geometry attribute into WKB for database use. Accepts the same
110+
# String or already-parsed object as .to_geom.
110111
def self.to_wkb(geometry)
111-
geojson = JSON.parse(geometry)
112-
feature = RGeo::GeoJSON.decode(geojson, json_parser: :json)
112+
feature = RGeo::GeoJSON.decode(coerce_geojson(geometry), json_parser: :json)
113113
ewkb = RGeo::WKRep::WKBGenerator.new(
114114
type_format: :ewkb,
115115
emit_ewkb_srid: true,
116116
hex_format: true
117117
)
118118
ewkb.generate feature.geometry
119119
rescue JSON::ParserError
120-
# The Gemetry is likely to be already in WKB format
120+
# The geometry is likely already in WKB format
121+
geometry
122+
end
123+
124+
# Accept a GeoJSON String or an already-parsed object. A nested object
125+
# previously reached JSON.parse(Hash) and raised a TypeError (surfacing as
126+
# HTTP 500 on the REST API); both forms now decode. Mirrors the String
127+
# guard already used in .to_feature.
128+
def self.coerce_geojson(geometry)
129+
return JSON.parse(geometry) if geometry.is_a?(String)
130+
return geometry.to_unsafe_h if geometry.respond_to?(:to_unsafe_h)
131+
121132
geometry
122133
end
123134

test/unit/issue_test.rb

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ class IssueTest < GttTest
1414
assert @issue.geom.present?
1515
end
1616

17+
test 'should accept geojson as a parsed object, not only a string' do
18+
# A JSON API request delivers geojson as an already-parsed object; this used
19+
# to reach JSON.parse(Hash) in Conversions.to_geom and raise (HTTP 500).
20+
feature = JSON.parse(example_geojson)
21+
assert feature.is_a?(Hash)
22+
23+
issue = @project.issues.last
24+
issue.geojson = feature
25+
assert issue.geom.present?, 'geom should be set from a GeoJSON object'
26+
assert issue.save
27+
assert_geojson Issue.find(issue.id).geojson
28+
end
29+
1730
test 'should load geojson' do
1831
@issue = Issue.find @issue.id
1932
assert j = @issue.geojson

0 commit comments

Comments
 (0)