Files
sm-bm-plugin/controllers/api/json_test.go
Jakub Zych 418f8240a4 feat: private materials with per-user shares
A material may be private: only its author and the users it is shared
with see it. Every student read (list, detail, course detail and
counters, the checklist linked material, the token twins) goes through
one visibility fragment. Existing materials stay public with no author.

GET/PUT /_bm/api/v1/materials/{id}/access let the author, a material
manager, toggle the flag and pick the users; the first change of an
author-less material makes the caller its author.
2026-11-08 11:52:47 +01:00

93 lines
2.7 KiB
Go

package api
import (
"encoding/json"
"strings"
"testing"
"git.golem15.com/jakub/sm-bm-plugin/models"
)
// TestReadingJSONCarriesMeetingID checks that meeting_id is always present
// in a reading, as a number or as null.
func TestReadingJSONCarriesMeetingID(t *testing.T) {
id := uint(4)
for _, tc := range []struct {
meeting *uint
want string
}{
{&id, `"meeting_id":4`},
{nil, `"meeting_id":null`},
} {
b, err := json.Marshal(readingJSON{ID: 1, Title: "Lektura", MeetingID: tc.meeting})
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(b), tc.want) {
t.Errorf("reading JSON %s does not contain %s", b, tc.want)
}
}
}
// TestMaterialJSONCarriesMeetingID checks that meeting_id is always present
// in a material, as a number or as null.
func TestMaterialJSONCarriesMeetingID(t *testing.T) {
id := uint(4)
for _, tc := range []struct {
meeting *uint
want string
}{
{&id, `"meeting_id":4`},
{nil, `"meeting_id":null`},
} {
b, err := json.Marshal(newMaterialListJSON(models.Material{ID: 1, Title: "Materiał", Type: "pdf", MeetingID: tc.meeting}, 0))
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(b), tc.want) {
t.Errorf("material JSON %s does not contain %s", b, tc.want)
}
}
}
// TestMaterialJSONCarriesPrivacy checks that is_private is always present in
// a material and that the detail carries can_manage, false by default.
func TestMaterialJSONCarriesPrivacy(t *testing.T) {
for _, tc := range []struct {
private bool
want string
}{
{true, `"is_private":true`},
{false, `"is_private":false`},
} {
b, err := json.Marshal(newMaterialListJSON(models.Material{ID: 1, Title: "Materiał", Type: "pdf", IsPrivate: tc.private}, 0))
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(b), tc.want) {
t.Errorf("material JSON %s does not contain %s", b, tc.want)
}
}
b, err := json.Marshal(materialDetailJSON{materialListJSON: newMaterialListJSON(models.Material{ID: 1, Title: "Materiał", Type: "pdf"}, 0)})
if err != nil {
t.Fatal(err)
}
if !strings.Contains(string(b), `"can_manage":false`) {
t.Errorf("material detail JSON %s does not contain can_manage false", b)
}
}
// TestVisibleMaterialSQL checks the visibility fragment: public, the author,
// or a share of the caller, with the caller id bound twice.
func TestVisibleMaterialSQL(t *testing.T) {
got := visibleMaterialSQL("m")
for _, want := range []string{"m.is_private = FALSE", "m.author_user_id = ?", "jz_bm_material_shares", ".material_id = m.id"} {
if !strings.Contains(got, want) {
t.Errorf("visibleMaterialSQL(m) = %q, missing %q", got, want)
}
}
if n := strings.Count(got, "?"); n != 2 {
t.Errorf("visibleMaterialSQL(m) has %d placeholders, want 2", n)
}
}