Skip to content

Commit

Permalink
require user query string for modifying neuronjson
Browse files Browse the repository at this point in the history
  • Loading branch information
DocSavage committed Jul 23, 2024
1 parent 779bb50 commit 6610219
Show file tree
Hide file tree
Showing 3 changed files with 25 additions and 21 deletions.
11 changes: 11 additions & 0 deletions datatype/neuronjson/neuronjson.go
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,9 @@ POST <api URL>/node/<UUID>/<data name>/key/<key>
the entire annotation. The replace behavior can be explicitly set if desired
to match old keyvalue semantics.
NOTE: A user query string in the form of ?u=someuserid *must* be present or an
error will be returned.
For each field, a *_user and *_time field will be added to the annotation unless
one is already present. The *_user field will be set to the user making the
request and the *_time field will be set to the current time. If the current
Expand Down Expand Up @@ -466,6 +469,9 @@ POST <api URL>/node/<UUID>/<data name>/keyvalues[?query-options]
Allows batch ingest of data. Each POSTed neuron annotation is handled in same
was as described in POST /key.
NOTE: A user query string in the form of ?u=someuserid *must* be present or an
error will be returned.
The POST body must include a KeyValues serialization as defined by the following
protobuf3 definitions:
Expand Down Expand Up @@ -1409,6 +1415,11 @@ func (d *Data) storeAndUpdate(ctx *datastore.VersionedCtx, keyStr string, newDat
// If replace is true, will use given value instead of updating fields that were given.
// If field values are given but do not change, the _user and _time fields will not be updated.
func (d *Data) PutData(ctx *datastore.VersionedCtx, keyStr string, value []byte, conditionals []string, replace bool) error {
// Don't permit putting data without a valid user set.
if ctx.User == "" {
return fmt.Errorf("cannot alter neuronjson data without a valid user")
}

// Allow "schema" and "schema_batch" on /key endpoint for backwards compatibility with DVID keyvalue instances.
switch keyStr {
case "0":
Expand Down
31 changes: 13 additions & 18 deletions datatype/neuronjson/neuronjson_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -348,6 +348,7 @@ func TestNeuronjsonRoundTrip(t *testing.T) {
}

ctx := datastore.NewVersionedCtx(dataservice, versionID)
ctx.User = "tester"

keyStr := "1234"
value := []byte(`{"bodyid": 1234, "a string": "foo", "a number": 1234, "a list": [1, 2, 3]}`)
Expand Down Expand Up @@ -684,7 +685,7 @@ func TestKeyvalueRequests(t *testing.T) {
server.TestHTTP(t, "POST", key1req, strings.NewReader(value1))

// Expect error if key 0 is used
badrequest := fmt.Sprintf("%snode/%s/%s/key/0", server.WebAPIPath, uuid, name)
badrequest := fmt.Sprintf("%snode/%s/%s/key/0?u=tester", server.WebAPIPath, uuid, name)
server.TestBadHTTP(t, "POST", badrequest, strings.NewReader(`{"bodyid": 0, "data": "foo"}`))

// Check HEAD response
Expand Down Expand Up @@ -776,7 +777,7 @@ func TestKeyvalueRequests(t *testing.T) {

// Check query
query := `{"a string": ["moo", "goo"]}`
queryreq := fmt.Sprintf("%snode/%s/%s/query", server.WebAPIPath, uuid, name)
queryreq := fmt.Sprintf("%snode/%s/%s/query?u=tester", server.WebAPIPath, uuid, name)
returnValue = server.TestHTTP(t, "GET", queryreq, strings.NewReader(query))

expectedValue = []byte("[" + value2 + "," + value3 + "]")
Expand All @@ -790,12 +791,12 @@ func TestKeyvalueRequests(t *testing.T) {
}

query = `{"a string": ["moo", "goo"], "a number": 2345}`
queryreq = fmt.Sprintf("%snode/%s/%s/query?show=all", server.WebAPIPath, uuid, name)
queryreq = fmt.Sprintf("%snode/%s/%s/query?show=all&u=tester", server.WebAPIPath, uuid, name)
returnValue = server.TestHTTP(t, "POST", queryreq, strings.NewReader(query))
checkBasicAndAll(t, value2, returnValue, "martha")

query = `{"a string": ["moo", "goo"], "a number": [2345, 3456]}`
queryreq = fmt.Sprintf("%snode/%s/%s/query", server.WebAPIPath, uuid, name)
queryreq = fmt.Sprintf("%snode/%s/%s/query?u=tester", server.WebAPIPath, uuid, name)
returnValue = server.TestHTTP(t, "POST", queryreq, strings.NewReader(query))

expectedValue = []byte("[" + value2 + "," + value3 + "]")
Expand All @@ -804,7 +805,6 @@ func TestKeyvalueRequests(t *testing.T) {
}

query = `{"unused field": "foo"}`
queryreq = fmt.Sprintf("%snode/%s/%s/query", server.WebAPIPath, uuid, name)
returnValue = server.TestHTTP(t, "POST", queryreq, strings.NewReader(query))

expectedValue = []byte("[]")
Expand All @@ -813,7 +813,6 @@ func TestKeyvalueRequests(t *testing.T) {
}

query = `{"a string": "moo", "unused field": "foo"}`
queryreq = fmt.Sprintf("%snode/%s/%s/query", server.WebAPIPath, uuid, name)
returnValue = server.TestHTTP(t, "POST", queryreq, strings.NewReader(query))

expectedValue = []byte("[]")
Expand All @@ -823,7 +822,6 @@ func TestKeyvalueRequests(t *testing.T) {

// Check regex query
query = `{"a string": "re/^(f|m)oo"}`
queryreq = fmt.Sprintf("%snode/%s/%s/query", server.WebAPIPath, uuid, name)
returnValue = server.TestHTTP(t, "POST", queryreq, strings.NewReader(query))

expectedValue = []byte("[" + value1 + "," + value2 + "]")
Expand All @@ -832,7 +830,6 @@ func TestKeyvalueRequests(t *testing.T) {
}

query = `{"a string": "re/^(f|m)oo", "a list": "mom"}`
queryreq = fmt.Sprintf("%snode/%s/%s/query", server.WebAPIPath, uuid, name)
returnValue = server.TestHTTP(t, "POST", queryreq, strings.NewReader(query))

expectedValue = []byte("[" + value2 + "]")
Expand All @@ -841,7 +838,6 @@ func TestKeyvalueRequests(t *testing.T) {
}

query = `{"a string": "re/^(f|m)oo", "a list": ["re/.*x", "re/om"]}`
queryreq = fmt.Sprintf("%snode/%s/%s/query", server.WebAPIPath, uuid, name)
returnValue = server.TestHTTP(t, "POST", queryreq, strings.NewReader(query))

expectedValue = []byte("[" + value2 + "]")
Expand Down Expand Up @@ -1023,7 +1019,7 @@ func TestStressConcurrentRW(t *testing.T) {
i := 0
for {
i++
keyreq := fmt.Sprintf("%snode/%s/neurons/key/%d", server.WebAPIPath, uuid, i)
keyreq := fmt.Sprintf("%snode/%s/neurons/key/%d?u=tester", server.WebAPIPath, uuid, i)
keyval := fmt.Sprintf(`{"bodyid": %d, "somedata": "value-%d"}`, i, i)
server.TestHTTP(t, "POST", keyreq, strings.NewReader(keyval))
select {
Expand Down Expand Up @@ -1202,7 +1198,7 @@ func TestAll(t *testing.T) {
allNeurons := make(ListNeuronJSON, len(testData))
var keyreq = make([]string, len(testData))
for i := 0; i < len(testData); i++ {
keyreq[i] = fmt.Sprintf("%snode/%s/neurons/key/%s", server.WebAPIPath, uuid, testData[i].key)
keyreq[i] = fmt.Sprintf("%snode/%s/neurons/key/%s?u=tester", server.WebAPIPath, uuid, testData[i].key)
server.TestHTTP(t, "POST", keyreq[i], strings.NewReader(testData[i].val))
if err := json.Unmarshal([]byte(testData[i].val), &(allNeurons[i])); err != nil {
t.Fatalf("Unable to parse test annotation %d: %v\n", i, err)
Expand Down Expand Up @@ -1268,7 +1264,7 @@ func TestDeleteWithNull(t *testing.T) {
allNeurons := make(ListNeuronJSON, len(testData))
var keyreq = make([]string, len(testData))
for i := 0; i < len(testData); i++ {
keyreq[i] = fmt.Sprintf("%snode/%s/neurons/key/%s", server.WebAPIPath, uuid, testData[i].key)
keyreq[i] = fmt.Sprintf("%snode/%s/neurons/key/%s?u=tester", server.WebAPIPath, uuid, testData[i].key)
server.TestHTTP(t, "POST", keyreq[i], strings.NewReader(testData[i].val))
if err := json.Unmarshal([]byte(testData[i].val), &(allNeurons[i])); err != nil {
t.Fatalf("Unable to parse test annotation %d: %v\n", i, err)
Expand Down Expand Up @@ -1325,7 +1321,7 @@ func TestKeyvalueRange(t *testing.T) {
}

// PUT a value
key1req := fmt.Sprintf("%snode/%s/unversiontest/key/%s", server.WebAPIPath, uuid, testData[0].key)
key1req := fmt.Sprintf("%snode/%s/unversiontest/key/%s?u=tester", server.WebAPIPath, uuid, testData[0].key)
server.TestHTTP(t, "POST", key1req, strings.NewReader(testData[0].val))

returnValue := server.TestHTTP(t, "GET", key1req, nil)
Expand All @@ -1334,7 +1330,7 @@ func TestKeyvalueRange(t *testing.T) {
}

// Add 2nd k/v
key2req := fmt.Sprintf("%snode/%s/unversiontest/key/%s", server.WebAPIPath, uuid, testData[1].key)
key2req := fmt.Sprintf("%snode/%s/unversiontest/key/%s?u=tester", server.WebAPIPath, uuid, testData[1].key)
server.TestHTTP(t, "POST", key2req, strings.NewReader(testData[1].val))

// Test
Expand Down Expand Up @@ -1368,13 +1364,13 @@ func TestFieldExistenceAndVersioning(t *testing.T) {
// Add the first 4 annotations
var keyreq = make([]string, len(testData))
for i := 0; i < len(testData); i++ {
keyreq[i] = fmt.Sprintf("%snode/%s/%s/key/%s", server.WebAPIPath, uuid, data.DataName(), testData[i].key)
keyreq[i] = fmt.Sprintf("%snode/%s/%s/key/%s?u=tester", server.WebAPIPath, uuid, data.DataName(), testData[i].key)
server.TestHTTP(t, "POST", keyreq[i], strings.NewReader(testData[i].val))
}

// Check field existence query
query := `{"a number": "exists/0"}`
queryreq := fmt.Sprintf("%snode/%s/%s/query", server.WebAPIPath, uuid, data.DataName())
queryreq := fmt.Sprintf("%snode/%s/%s/query?u=tester", server.WebAPIPath, uuid, data.DataName())
returnValue := server.TestHTTP(t, "POST", queryreq, strings.NewReader(query))

expectedValue := []byte("[" + testData[1].val + "," + testData[3].val + "]")
Expand All @@ -1400,7 +1396,6 @@ func TestFieldExistenceAndVersioning(t *testing.T) {

// Check if field is missing or empty string.
query = `[{"baz": "exists/0"}, {"baz": ""}]`
queryreq = fmt.Sprintf("%snode/%s/%s/query", server.WebAPIPath, uuid, data.DataName())
returnValue = server.TestHTTP(t, "POST", queryreq, strings.NewReader(query))

expectedValue = []byte("[" + testData[0].val + "," + testData[2].val + "]")
Expand All @@ -1421,7 +1416,7 @@ func TestFieldExistenceAndVersioning(t *testing.T) {
if err != nil {
t.Fatalf("couldn't serialize keyvalues: %v\n", err)
}
kvsPostReq := fmt.Sprintf("%snode/%s/%s/keyvalues", server.WebAPIPath, uuid, data.DataName())
kvsPostReq := fmt.Sprintf("%snode/%s/%s/keyvalues?u=tester", server.WebAPIPath, uuid, data.DataName())
server.TestHTTP(t, "POST", kvsPostReq, bytes.NewReader(serialization))

// Commit current version
Expand Down
4 changes: 1 addition & 3 deletions datatype/neuronjson/query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func TestQueryBodyIDs(t *testing.T) {
server.TestHTTP(t, "POST", apiStr, payload)

for bodyid, jsonStr := range sampleData {
keyreq := fmt.Sprintf("%snode/%s/neurons/key/%d", server.WebAPIPath, uuid, bodyid)
keyreq := fmt.Sprintf("%snode/%s/neurons/key/%d?u=tester", server.WebAPIPath, uuid, bodyid)
server.TestHTTP(t, "POST", keyreq, strings.NewReader(jsonStr))
}

Expand All @@ -51,7 +51,6 @@ func TestQueryBodyIDs(t *testing.T) {
}

query = `[{"bodyid": [1000, 2000]}, {"bodyid": [3000]}]`
queryreq = fmt.Sprintf("%snode/%s/%s/query", server.WebAPIPath, uuid, "neurons")
returnValue = server.TestHTTP(t, "POST", queryreq, strings.NewReader(query))

expectedValue = []byte(fmt.Sprintf("[%s,%s,%s]", sampleData[1000], sampleData[2000], sampleData[3000]))
Expand All @@ -60,7 +59,6 @@ func TestQueryBodyIDs(t *testing.T) {
}

query = `{"bodyid": [3003], "position": [303, 301, 303]}`
queryreq = fmt.Sprintf("%snode/%s/%s/query", server.WebAPIPath, uuid, "neurons")
returnValue = server.TestHTTP(t, "POST", queryreq, strings.NewReader(query))

expectedValue = []byte(fmt.Sprintf("[%s]", sampleData[3003]))
Expand Down

0 comments on commit 6610219

Please sign in to comment.