Support uploading .geojson files directly
CI / check (push) Successful in 45s
CI / deploy (push) Successful in 15s

A .geojson file needs no GPX/FIT conversion — it's already the shape
gpx.js expects — so GpxStore#geojson now just reads and returns it
as-is, no cache sidecar. save/tree/the upload dropzone and its zip
handling all pick it up through the existing TRACK_EXTENSIONS list.

Also fixes a bug the new "cached" tree icon would have shipped with:
a GPX/FIT's own .geojson cache sidecar (e.g. "ride.gpx.geojson") also
matches the new .geojson branch in list_children, which would have
listed it as a second, phantom tree entry — excluded explicitly, with
a regression test.
This commit is contained in:
randy committed 2026-09-07 22:48:58 +02:00
1 parent 44d235bbcf
commit b4f205667b
8 files changed
+110 -19

No files matched your search

+12
View File
@@ -60,6 +60,18 @@ class AppTest < Minitest::Test
assert_operator track["properties"]["distance_meters"], :>, 0
end
def test_geojson_upload_is_served_back_unchanged
content = '{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"kind":"waypoint","name":"Spot"},"geometry":{"type":"Point","coordinates":[17.1,48.1]}}]}'
response = post_file("/api/gpx", filename: "spots.geojson", content: content, env: logged_in_env)
assert_equal 200, response.status
assert_equal ["spots.geojson"], json_body(response)["paths"]
file_response = request.get("/api/gpx/file/spots.geojson")
assert_equal 200, file_response.status
assert_equal "Spot", json_body(file_response)["features"][0]["properties"]["name"]
end
def test_unparseable_gpx_returns_422
post_file("/api/gpx", filename: "bad.gpx", content: "<gpx><trk unclosed>", env: logged_in_env)
+33
View File
@@ -145,6 +145,35 @@ class GpxStoreTest < Minitest::Test
refute file["cached"]
end
def test_geojson_extension_is_preserved_not_forced_to_gpx
path = @store.save(folder: "", filename: "spots.geojson", io: StringIO.new(sample_geojson))
assert_equal "spots.geojson", path
end
def test_uploaded_geojson_is_served_as_is_with_no_cache_file
path = @store.save(folder: "", filename: "spots.geojson", io: StringIO.new(sample_geojson))
assert_equal sample_geojson, @store.geojson(path)
refute File.file?(@store.resolve_file(path) + ".geojson"), "a .geojson source needs no separate cache sidecar"
end
def test_uploaded_geojson_is_always_reported_cached
@store.save(folder: "", filename: "spots.geojson", io: StringIO.new(sample_geojson))
file = @store.tree["children"].find { |c| c["name"] == "spots.geojson" }
assert file["cached"]
assert_equal ["waypoint"], file["kinds"]
end
# A GPX/FIT's own GeoJSON cache sidecar (e.g. "ride.gpx.geojson") also
# ends in ".geojson" — regression test for it not showing up as its own
# second, phantom tree entry alongside "ride.gpx".
def test_geojson_cache_sidecar_is_not_listed_as_its_own_tree_entry
@store.save(folder: "", filename: "ride.gpx", io: StringIO.new(sample_gpx))
assert_equal ["ride.gpx"], @store.tree["children"].map { |c| c["name"] }
end
private
def sample_gpx
@@ -152,4 +181,8 @@ class GpxStoreTest < Minitest::Test
<gpx><wpt lat="48.1" lon="17.1"><name>Waypoint</name></wpt></gpx>
GPX
end
def sample_geojson
'{"type":"FeatureCollection","features":[{"type":"Feature","properties":{"kind":"waypoint","name":"Spot"},"geometry":{"type":"Point","coordinates":[17.1,48.1]}}]}'
end
end