Add structured materials, canvas layouts, tags and content permissions
This commit is contained in:
@@ -67,7 +67,7 @@ func TestOnboardingAndSharing(t *testing.T) {
|
||||
Register(mux, db, callbacks, "https://api.example.com", map[string]OnboardingConfig{
|
||||
project: {RequireWorkspace: true, Questions: []Question{{Key: "purpose", Required: true}}},
|
||||
})
|
||||
call := func(method, path, token string, body any, status int) response {
|
||||
call := func(method, path, token string, body any, status int, versions ...string) response {
|
||||
t.Helper()
|
||||
encoded, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
@@ -77,6 +77,9 @@ func TestOnboardingAndSharing(t *testing.T) {
|
||||
if token != "" {
|
||||
r.Header.Set("Authorization", "Bearer "+token)
|
||||
}
|
||||
if len(versions) > 0 {
|
||||
r.Header.Set("If-Match", versions[0])
|
||||
}
|
||||
w := httptest.NewRecorder()
|
||||
mux.ServeHTTP(w, r)
|
||||
if w.Code != status {
|
||||
@@ -119,6 +122,47 @@ func TestOnboardingAndSharing(t *testing.T) {
|
||||
contentShare := call("POST", workspacePath+"/shares", tokens[0], response{"role": "editor", "material_id": material}, 201)
|
||||
call("POST", base+"/shares/redeem", tokens[2], response{"token": contentShare["token"]}, 200)
|
||||
call("GET", workspacePath, tokens[2], nil, 404)
|
||||
articleContent := response{"schema_version": 1, "article": response{"sections": []any{response{
|
||||
"id": "chapter-1", "title": "Chapter", "description": "Chapter summary", "paragraphs": []any{response{"id": "p1", "text": "Paragraph", "description": "Paragraph summary"}},
|
||||
}}}}
|
||||
created := call("POST", workspacePath+"/materials", tokens[0], response{"kind": "article", "title": "Article", "content": articleContent}, 201)
|
||||
articleID := created["id"].(string)
|
||||
text := call("POST", workspacePath+"/materials", tokens[0], response{"kind": "text", "title": "Alpha", "content": response{"text": "Original"}}, 201)
|
||||
textPath := workspacePath + "/materials/" + text["id"].(string)
|
||||
call("GET", textPath, tokens[2], nil, 404)
|
||||
call("POST", textPath+"/grants", tokens[0], response{"account_id": accounts[2], "role": "viewer"}, 204)
|
||||
call("GET", textPath, tokens[2], nil, 200)
|
||||
changed := response{"title": "Beta", "content": response{"text": "Changed"}}
|
||||
call("PATCH", textPath, tokens[2], changed, 403, `"1"`)
|
||||
call("POST", textPath+"/grants", tokens[0], response{"account_id": accounts[2], "role": "editor"}, 204)
|
||||
call("PATCH", textPath, tokens[2], changed, 428)
|
||||
call("PATCH", textPath, tokens[2], changed, 204, `"1"`)
|
||||
call("PATCH", textPath, tokens[0], changed, 412, `"1"`)
|
||||
call("POST", workspacePath+"/materials", tokens[0], response{"kind": "article", "title": "Invalid", "content": response{"markdown": "raw markdown"}}, 400)
|
||||
tag := call("POST", workspacePath+"/tags", tokens[0], response{"name": "Research", "color": "#123456"}, 201)
|
||||
call("GET", workspacePath+"/tags", tokens[2], nil, 404)
|
||||
call("POST", textPath+"/tags", tokens[2], response{"tags": []string{tag["id"].(string)}}, 204, `"2"`)
|
||||
call("POST", textPath+"/open", tokens[2], nil, 204)
|
||||
filtered := call("GET", workspacePath+"/materials?sort=opened&tag="+tag["id"].(string), tokens[2], nil, 200)
|
||||
if len(filtered["items"].([]any)) != 1 {
|
||||
t.Fatal("tag-filtered material list leaked inaccessible materials")
|
||||
}
|
||||
board := call("POST", workspacePath+"/materials", tokens[0], response{"kind": "board", "title": "Board", "content": response{}}, 201)
|
||||
boardPath := workspacePath + "/materials/" + board["id"].(string)
|
||||
layout := call("POST", boardPath+"/layouts", tokens[0], response{"material_id": articleID, "x": 1, "y": 2, "width": 320, "height": 200, "z_index": 1}, 201, `"1"`)
|
||||
call("GET", boardPath+"/layouts", tokens[1], nil, 200)
|
||||
call("POST", boardPath+"/grants", tokens[0], response{"account_id": accounts[2], "role": "viewer"}, 204)
|
||||
hidden := call("GET", boardPath+"/layouts", tokens[2], nil, 200)
|
||||
if len(hidden["items"].([]any)) != 0 {
|
||||
t.Fatal("board share disclosed private child material")
|
||||
}
|
||||
call("DELETE", boardPath+"/layouts/"+layout["id"].(string), tokens[0], nil, 412, `"1"`)
|
||||
call("DELETE", boardPath+"/layouts/"+layout["id"].(string), tokens[0], nil, 204, `"2"`)
|
||||
call("DELETE", textPath+"/grants/"+accounts[2], tokens[0], nil, 204)
|
||||
call("GET", textPath, tokens[2], nil, 404)
|
||||
call("DELETE", workspacePath+"/tags/"+tag["id"].(string), tokens[0], nil, 204)
|
||||
call("PATCH", textPath, tokens[0], changed, 412, `"3"`)
|
||||
|
||||
email := "fixture@example.invalid"
|
||||
password := "a-long-fixture-password"
|
||||
call("POST", base+"/auth/register", "", response{"email": email, "password": password}, 202)
|
||||
|
||||
Reference in New Issue
Block a user