Skip to content

Commit 4a6a0b9

Browse files
committed
Allow to specify a map id in ulogger, to allow writing tracks to a shared map
1 parent e8b6113 commit 4a6a0b9

4 files changed

Lines changed: 94 additions & 43 deletions

File tree

app/models/layer.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ class Layer
1010
scope :geojson, -> { where(type: "geojson") }
1111
scope :overpass, -> { where(type: "overpass") }
1212

13-
field :type
13+
field :type, default: "geojson"
1414
field :name
1515
field :query
1616
field :heatmap, type: Boolean

engines/ulogger/README.md

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,32 @@
11
# µlogger API for Mapforge
22

3-
* App: https://f-droid.org/packages/net.fabiszewski.ulogger
4-
* Original server project: https://github.com/bfabiszewski/ulogger-server
5-
* Client project: https://github.com/bfabiszewski/ulogger-android
3+
* App: [https://f-droid.org/packages/net.fabiszewski.ulogger](https://f-droid.org/packages/net.fabiszewski.ulogger)
4+
* Original server project: [https://github.com/bfabiszewski/ulogger-server](https://github.com/bfabiszewski/ulogger-server)
5+
* Client project: [https://github.com/bfabiszewski/ulogger-android](https://github.com/bfabiszewski/ulogger-android)
66

77
![Mapforge µlogger track](https://github.com/digitaltom/mapforge/blob/main/engines/ulogger/docs/track.jpg?raw=true)
88

99
## Usage
1010

1111
To use the µlogger app with mapforge.org, you need to go to its settings,
12-
and use `https://mapforge.org/ulogger` as server url, and if you want your track to get assigned to your account, add your mapforge login account email as user name (no password).
12+
and use `https://mapforge.org/ulogger` as server url, and if you want your track to get assigned to your account, add your mapforge **email** as user name (any password).
1313

1414
![Screenshot_20250616-160431](https://github.com/user-attachments/assets/f7f31edf-fc88-41ac-bf35-7513f955a401)
1515

16-
Recorded tracks are private by default, so they are not shown to other users. You can decide to share a link to your track from the µlogger app.
16+
Recorded tracks are private by default, so they are not shown to other users. You can decide to share a link to your track from the µlogger app.
1717

1818

1919
## API endpoints
2020
Auth
2121
`curl -H 'Content-Type: application/x-www-form-urlencoded' -X POST http://localhost:3000/ulogger/client/index.php -d 'action=auth&pass=supers3cr3t&user=cwh@domain.org'`
2222

23-
Sets a cookie with a token for the following requests. If a user with the provided email is found, the map is assigned to that user.
23+
Sets a cookie with a session token for the following requests. If a user with the provided email is found, the map is assigned to that user.
2424

2525
New Track
2626
`curl -H 'Content-Type: application/x-www-form-urlencoded' -X POST http://localhost:3000/ulogger/client/index.php -d 'action=addtrack&track=Auto_2024.06.09_20.59.57'`
2727

28+
By using a track name of format `<private_map_id>#<track_name>`, you can add your track to an existing map.
29+
2830
Append New Trackpoint
2931
`curl -H 'Content-Type: application/x-www-form-urlencoded' -X POST http://localhost:3000/ulogger/client/index.php -d 'action=addpos&altitude=374.299987792969&provider=network&trackid=18&accuracy=16.113000869751&lon=11.1158342&time=1717959606&lat=49.4442029'`
3032

engines/ulogger/app/controllers/api/ulogger_controller.rb

Lines changed: 41 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -25,30 +25,53 @@ class Api::UloggerController < ApplicationController
2525
:stroke => "#62a0ea"
2626
}
2727

28+
# params: {"pass" => "pwd", "user" => "user@mail.com"}
2829
def auth
2930
session["email"] = params[:user]
3031
render json: { error: false }
3132
end
3233

34+
# Called by the app on first waypoint upload
35+
# params: { "track" => "tom_2026-03-24_11.08" }
36+
# When track name matches "<private_map_id>#<track name>", you can log into an existing map/track
3337
def addtrack
3438
@user = User.find_by(email: session["email"])
35-
map_id, padded_id = create_numeric_map_id
36-
@map = Map.create!(private_id: padded_id, name: params[:track],
37-
public_id: params[:track],
38-
view_permission: "link",
39-
edit_permission: "link",
40-
user: @user)
41-
@map.save!
42-
render json: { error: false, trackid: map_id }
39+
if params[:track] =~ /^(\d+)#(\S+)/
40+
session["track_name"] = $2
41+
@map = Map.find_by(private_id: $1)
42+
else
43+
session["track_name"] = params[:track]
44+
@map = Map.create!(private_id: random_map_id, name: params[:track],
45+
view_permission: "link",
46+
edit_permission: "link",
47+
user: @user)
48+
end
49+
if @map
50+
render json: { error: false, trackid: @map.private_id.to_i }
51+
else
52+
Rails.logger.error("Cannot create map for track '#{params[:track]}'")
53+
render json: { error: true, message: "Invalid trackid" }
54+
end
4355
end
4456

57+
# params: {"altitude" => "384.600006103516", "provider" => "network",
58+
# "trackid" => "123", "accuracy" => "12.3999996185303",
59+
# "lon" => "11.0871855", "time" => "1774346910", "lat" => "49.428361"}
60+
#
61+
# Uses/Creates track with track name from 'addtrack' call before
4562
def addpos
4663
coords = [ params[:lon].to_f, params[:lat].to_f, params[:altitude].to_f.round(2) ]
47-
features = @map.layers.geojson.first.features
4864

49-
# if the map has no track yet, create one, else append
50-
track = features.line_string.first
51-
track ||= Feature.new(layer: @map.layers.first, geometry: { "coordinates" => [] }, properties: TRACK_PROPERTIES)
65+
# Find track layer, fallback to map name which also has the initial track name by default
66+
track_name = session["track_name"] || @map.name
67+
layer = @map.layers.geojson.find { |l| l.name == track_name } || @map.layers.create(name: track_name)
68+
features = layer.features
69+
70+
# Find track with current name on map, or create new
71+
track = features.line_string.find { |l| l.properties['title'] == track_name }
72+
track ||= Feature.new(layer: layer, geometry: { "coordinates" => [] }, properties: TRACK_PROPERTIES)
73+
track.update(properties: track.properties.merge({ 'title' => track_name }))
74+
5275
track_coords = track.geometry["coordinates"] << coords
5376
track.update(geometry: { "type" => "LineString",
5477
"coordinates" => track_coords })
@@ -96,7 +119,7 @@ def addpos
96119
private
97120

98121
def set_map
99-
@map = Map.find_by(private_id: "%024d" % [ params[:trackid] ])
122+
@map = Map.find_by(private_id: params[:trackid])
100123
render json: { error: true, message: "Invalid trackid" } unless @map
101124
end
102125

@@ -123,8 +146,8 @@ def image_properties(img)
123146

124147
def location_properties
125148
{ "marker-size": "8",
126-
"marker-color": "#ff7800",
127-
stroke: "#000000" }
149+
"marker-color": "#ff7800",
150+
"stroke": "#000000" }
128151
end
129152

130153
def description
@@ -138,13 +161,9 @@ def description
138161
end.join("\n")
139162
end
140163

141-
# mongoid needs a BSON::ObjectId (24 char hex) as primary key,
142-
# which we use as map id currently
143-
def create_numeric_map_id
144-
id = SecureRandom.rand(1..JAVA_MAXINT)
145-
padded = "%024d" % [ id ]
146-
return create_numeric_map_id if Map.exists?(private_id: padded)
147-
[ id, padded ]
164+
# ulogger needs a numeric map id
165+
def random_map_id
166+
SecureRandom.rand(1..JAVA_MAXINT)
148167
end
149168
end
150169
end

engines/ulogger/spec/requests/api/ulogger_controller_spec.rb

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,25 +16,44 @@
1616
describe "#addtrack" do
1717
subject { response }
1818

19-
before { post "/ulogger/client/index.php", params: payload }
20-
21-
let(:payload) { { action: "addtrack", track: "ulogger track" } }
2219
let(:response_body) { JSON.parse(response.body) }
2320

24-
it { is_expected.to have_http_status(200) }
25-
it { expect(response_body["error"]).to be(false) }
21+
context "creating a new track" do
22+
before { post "/ulogger/client/index.php", params: payload }
2623

27-
it "returns a numeric id" do
28-
expect(response_body["trackid"]).to be > 0
29-
expect(response_body["trackid"]).to be < Api::UloggerController::JAVA_MAXINT
30-
end
24+
let(:payload) { { action: "addtrack", track: "ulogger track" } }
25+
26+
it { is_expected.to have_http_status(200) }
27+
it { expect(response_body["error"]).to be(false) }
3128

32-
it "creates map in db with 24 digits" do
33-
expect(Map.find_by(private_id: "%024d" % [ response_body["trackid"] ])).not_to be_nil
29+
it "returns a numeric id" do
30+
expect(response_body["trackid"]).to be > 0
31+
expect(response_body["trackid"]).to be < Api::UloggerController::JAVA_MAXINT
32+
end
33+
34+
it "creates map in db with trackid" do
35+
expect(Map.find_by(private_id: response_body["trackid"])).not_to be_nil
36+
end
37+
38+
it "sets map name" do
39+
expect(Map.find_by(private_id: response_body["trackid"]).name).to eq "ulogger track"
40+
end
3441
end
3542

36-
it "sets map name" do
37-
expect(Map.find_by(private_id: "%024d" % [ response_body["trackid"] ]).name).to eq "ulogger track"
43+
context "using existing map" do
44+
before do
45+
post "/ulogger/client/index.php", params: payload
46+
end
47+
48+
let(:map) { create(:map, private_id: 12345) }
49+
let(:payload) { { action: "addtrack", track: "#{map.private_id}#ulogger track2" } }
50+
51+
it { is_expected.to have_http_status(200) }
52+
it { expect(response_body["error"]).to be(false) }
53+
54+
it "uses existing map" do
55+
expect(response_body["trackid"]).to eq map.private_id.to_i
56+
end
3857
end
3958
end
4059

@@ -46,7 +65,7 @@
4665
post "/ulogger/client/index.php", params: payload
4766
end
4867

49-
let(:map) { create(:map, private_id: "%024d" % [ trackid ]) }
68+
let(:map) { create(:map, private_id: trackid, name: 'ulogger') }
5069
let(:trackid) { 924977797 }
5170
let(:payload) {
5271
{ action: "addpos", altitude: 374.29, speed: 4.3,
@@ -58,6 +77,17 @@
5877
it { is_expected.to have_http_status(200) }
5978
it { expect(response_body["error"]).to be(false) }
6079

80+
it "creates new layer for track" do
81+
expect(map.reload.layers.count).to eq 2
82+
# no session["track_name"] is set, track layer will inherit map name
83+
expect(map.layers.geojson.select { |l| l.name == "ulogger" }.count).to eq 1
84+
end
85+
86+
it "adds points into the new layer" do
87+
layer = map.reload.layers.geojson.find { |l| l.name == "ulogger" }
88+
expect(layer.features.point.count).to eq 1
89+
end
90+
6191
it "adds point feature at coordinates" do
6292
expect(map.reload.features.point.count).to eq 1
6393
expect(map.reload.features.point.first.geometry["coordinates"])

0 commit comments

Comments
 (0)