Enable moving own features on MapLibre and switch to raster tiles.
CI / test (push) Successful in 4s

Add feature geometry PATCH API support and update MapLibre demo to use OSM raster tiles, load all public/owned features, and let logged-in users drag their own feature markers to persist new positions.

Made-with: Cursor
This commit is contained in:
2026-03-02 22:28:44 +00:00
parent 59c9a719e0
commit 5716d4adf6
5 changed files with 136 additions and 2 deletions
+22
View File
@@ -308,6 +308,28 @@ func TestCollectionOwnershipIsolation(t *testing.T) {
if resp.StatusCode != http.StatusForbidden {
t.Fatalf("expected 403, got %d", resp.StatusCode)
}
featureID := createFeatureData["id"].(string)
patchOwnResp, patchOwnData := patchJSON(t, client, server.URL+"/v1/features/"+featureID, map[string]interface{}{
"geometry": map[string]interface{}{
"type": "Point",
"coordinates": []float64{-16.6299, 28.4639, 11},
},
}, user1Token)
if patchOwnResp.StatusCode != http.StatusOK {
t.Fatalf("owner patch feature status=%d body=%v", patchOwnResp.StatusCode, patchOwnData)
}
patchOtherResp, patchOtherData := patchJSON(t, client, server.URL+"/v1/features/"+featureID, map[string]interface{}{
"geometry": map[string]interface{}{
"type": "Point",
"coordinates": []float64{-16.6301, 28.4641, 12},
},
}, user2Token)
if patchOtherResp.StatusCode != http.StatusForbidden {
t.Fatalf("non-owner patch feature status=%d body=%v", patchOtherResp.StatusCode, patchOtherData)
}
}
func TestAssetLifecycleAndVisibility(t *testing.T) {
+23
View File
@@ -42,6 +42,7 @@ func (a *API) Routes() http.Handler {
mux.HandleFunc("POST /v1/collections/{id}/features", a.createFeature)
mux.HandleFunc("GET /v1/collections/{id}/features", a.listFeatures)
mux.HandleFunc("GET /v1/features/public", a.listPublicFeatures)
mux.HandleFunc("PATCH /v1/features/{id}", a.patchFeature)
mux.HandleFunc("DELETE /v1/features/{id}", a.deleteFeature)
mux.HandleFunc("POST /v1/assets", a.createAsset)
mux.HandleFunc("PATCH /v1/assets/{id}", a.patchAsset)
@@ -393,6 +394,28 @@ func (a *API) deleteFeature(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusNoContent)
}
func (a *API) patchFeature(w http.ResponseWriter, r *http.Request) {
user, err := a.authUser(r)
if err != nil {
writeErr(w, err)
return
}
featureID := r.PathValue("id")
var req struct {
Geometry store.Point `json:"geometry"`
}
if err := readJSON(r, &req); err != nil {
writeErr(w, app.ErrBadRequest)
return
}
feature, err := a.service.UpdateFeatureGeometry(user, featureID, req.Geometry)
if err != nil {
writeErr(w, err)
return
}
writeJSON(w, http.StatusOK, feature)
}
func (a *API) createAsset(w http.ResponseWriter, r *http.Request) {
user, err := a.authUser(r)
if err != nil {