Add public GeoJSON features API and load public 3D objects on maps.
CI / test (push) Successful in 3s
CI / test (push) Successful in 3s
Expose GET /v1/features/public (optional kind filter) and update Leaflet/MapLibre demos to render all public 3D assets globally, while still merging owner collections after login. Made-with: Cursor
This commit is contained in:
@@ -451,3 +451,101 @@ func TestAssetLifecycleAndVisibility(t *testing.T) {
|
||||
t.Fatalf("expected 403 for private asset, got %d", downloadPrivateResp.StatusCode)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListPublicFeatures(t *testing.T) {
|
||||
adminPub, adminPriv, err := ed25519.GenerateKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("generate admin key: %v", err)
|
||||
}
|
||||
adminPubB64 := base64.RawURLEncoding.EncodeToString(adminPub)
|
||||
server := newTestServer(adminPubB64)
|
||||
defer server.Close()
|
||||
client := server.Client()
|
||||
|
||||
adminToken := loginUser(t, client, server.URL, adminPubB64, adminPriv)
|
||||
|
||||
user1Pub, user1Priv, _ := ed25519.GenerateKey(rand.Reader)
|
||||
user1PubB64 := base64.RawURLEncoding.EncodeToString(user1Pub)
|
||||
registerUserViaAdmin(t, client, server.URL, adminPubB64, adminPriv, adminToken, user1PubB64, user1Priv, "invite-public-u1")
|
||||
user1Token := loginUser(t, client, server.URL, user1PubB64, user1Priv)
|
||||
|
||||
user2Pub, user2Priv, _ := ed25519.GenerateKey(rand.Reader)
|
||||
user2PubB64 := base64.RawURLEncoding.EncodeToString(user2Pub)
|
||||
registerUserViaAdmin(t, client, server.URL, adminPubB64, adminPriv, adminToken, user2PubB64, user2Priv, "invite-public-u2")
|
||||
user2Token := loginUser(t, client, server.URL, user2PubB64, user2Priv)
|
||||
|
||||
c1Resp, c1Data := postJSON(t, client, server.URL+"/v1/collections", map[string]string{"name": "u1-public"}, user1Token)
|
||||
if c1Resp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("u1 create collection status=%d body=%v", c1Resp.StatusCode, c1Data)
|
||||
}
|
||||
c1ID := c1Data["id"].(string)
|
||||
f1Resp, f1Data := postJSON(t, client, server.URL+"/v1/collections/"+c1ID+"/features", map[string]interface{}{
|
||||
"geometry": map[string]interface{}{"type": "Point", "coordinates": []float64{-16.25, 28.46, 5}},
|
||||
"properties": map[string]interface{}{
|
||||
"name": "u1-public-feature",
|
||||
},
|
||||
}, user1Token)
|
||||
if f1Resp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("u1 create feature status=%d body=%v", f1Resp.StatusCode, f1Data)
|
||||
}
|
||||
f1ID := f1Data["id"].(string)
|
||||
a1Resp, a1Data := postJSON(t, client, server.URL+"/v1/assets", map[string]interface{}{
|
||||
"featureId": f1ID,
|
||||
"checksum": "pub3d111",
|
||||
"ext": "glb",
|
||||
"kind": "3d",
|
||||
"isPublic": true,
|
||||
}, user1Token)
|
||||
if a1Resp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("u1 create public asset status=%d body=%v", a1Resp.StatusCode, a1Data)
|
||||
}
|
||||
a1ID := a1Data["asset"].(map[string]interface{})["id"].(string)
|
||||
|
||||
c2Resp, c2Data := postJSON(t, client, server.URL+"/v1/collections", map[string]string{"name": "u2-private"}, user2Token)
|
||||
if c2Resp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("u2 create collection status=%d body=%v", c2Resp.StatusCode, c2Data)
|
||||
}
|
||||
c2ID := c2Data["id"].(string)
|
||||
f2Resp, f2Data := postJSON(t, client, server.URL+"/v1/collections/"+c2ID+"/features", map[string]interface{}{
|
||||
"geometry": map[string]interface{}{"type": "Point", "coordinates": []float64{-16.3, 28.47, 7}},
|
||||
"properties": map[string]interface{}{
|
||||
"name": "u2-private-feature",
|
||||
},
|
||||
}, user2Token)
|
||||
if f2Resp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("u2 create feature status=%d body=%v", f2Resp.StatusCode, f2Data)
|
||||
}
|
||||
f2ID := f2Data["id"].(string)
|
||||
a2Resp, a2Data := postJSON(t, client, server.URL+"/v1/assets", map[string]interface{}{
|
||||
"featureId": f2ID,
|
||||
"checksum": "priv3d222",
|
||||
"ext": "glb",
|
||||
"kind": "3d",
|
||||
"isPublic": false,
|
||||
}, user2Token)
|
||||
if a2Resp.StatusCode != http.StatusCreated {
|
||||
t.Fatalf("u2 create private asset status=%d body=%v", a2Resp.StatusCode, a2Data)
|
||||
}
|
||||
|
||||
publicResp, publicData := getJSON(t, client, server.URL+"/v1/features/public?kind=3d", "")
|
||||
if publicResp.StatusCode != http.StatusOK {
|
||||
t.Fatalf("list public features status=%d body=%v", publicResp.StatusCode, publicData)
|
||||
}
|
||||
publicFeatures := publicData["features"].([]interface{})
|
||||
if len(publicFeatures) != 1 {
|
||||
t.Fatalf("expected 1 public feature, got %d", len(publicFeatures))
|
||||
}
|
||||
publicFeature := publicFeatures[0].(map[string]interface{})
|
||||
if publicFeature["id"].(string) != f1ID {
|
||||
t.Fatalf("expected public feature id=%s got=%v", f1ID, publicFeature["id"])
|
||||
}
|
||||
properties := publicFeature["properties"].(map[string]interface{})
|
||||
assets := properties["assets"].([]interface{})
|
||||
if len(assets) != 1 {
|
||||
t.Fatalf("expected 1 public asset, got %d", len(assets))
|
||||
}
|
||||
publicAsset := assets[0].(map[string]interface{})
|
||||
if publicAsset["id"].(string) != a1ID {
|
||||
t.Fatalf("expected public asset id=%s got=%v", a1ID, publicAsset["id"])
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user