A per-user jz_bm_material_pins table and PUT/DELETE /materials/{id}/pin
on the student API and its token twins: 204 for a material the caller
may see, idempotent, 404 otherwise. List rows, course rows and the
detail carry pinned. The plain list lists the caller's pins first
(newest pin first); with q the relevance order stays. A pin writes only
the pins table and never changes the material's revision.
122 lines
3.6 KiB
Go
122 lines
3.6 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)
|
|
}
|
|
}
|
|
|
|
// TestMaterialJSONCarriesPinned checks that pinned is always present in a
|
|
// material row, false unless the caller set it, and that the detail carries
|
|
// the row's value.
|
|
func TestMaterialJSONCarriesPinned(t *testing.T) {
|
|
row := newMaterialListJSON(models.Material{ID: 1, Title: "Materiał", Type: "notatka"}, 0)
|
|
b, err := json.Marshal(row)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(string(b), `"pinned":false`) {
|
|
t.Errorf("material JSON %s does not contain pinned false", b)
|
|
}
|
|
row.Pinned = true
|
|
b, err = json.Marshal(row)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(string(b), `"pinned":true`) {
|
|
t.Errorf("pinned material JSON %s does not contain pinned true", b)
|
|
}
|
|
b, err = json.Marshal(materialDetailJSON{materialListJSON: row})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(string(b), `"pinned":true`) {
|
|
t.Errorf("pinned material detail JSON %s does not contain pinned true", 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)
|
|
}
|
|
}
|