refactor: drop the quiz import and the golem15.quizzes dependency
golem15.quizzes now serves its own import at /api/v1/quizzes/import behind the same shared API token.
This commit is contained in:
@@ -12,7 +12,6 @@ import (
|
||||
"time"
|
||||
"unicode"
|
||||
|
||||
quizzes "git.golem15.com/golem15/sm-quizzes-plugin/classes"
|
||||
usermodels "git.golem15.com/golem15/sm-user-plugin/models"
|
||||
"git.golem15.com/golem15/summercms/modules/bouncer"
|
||||
"git.golem15.com/golem15/summercms/modules/lagoon"
|
||||
@@ -134,41 +133,6 @@ func (h *Handlers) ApplySeed(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
// ImportQuiz answers POST /quizzes?replace=: quizzes:import over HTTP. The
|
||||
// body is the quiz document of golem15.quizzes. An existing slug is a 409
|
||||
// unless replace is on.
|
||||
func (h *Handlers) ImportQuiz(w http.ResponseWriter, r *http.Request) {
|
||||
raw, ok := body(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
doc, err := quizzes.ParseImport(raw)
|
||||
if err != nil {
|
||||
writeInvalid(w, err.Error())
|
||||
return
|
||||
}
|
||||
db, ok := h.db(w, r)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
res, err := quizzes.Import(r.Context(), db, doc, flag(r, "replace"))
|
||||
if errors.Is(err, quizzes.ErrQuizExists) {
|
||||
wire.WriteJSON(w, http.StatusConflict, map[string]any{"error": true, "message": "A quiz with the slug " + doc.Slug + " already exists; pass replace=1 to replace its questions."})
|
||||
return
|
||||
}
|
||||
if err != nil {
|
||||
writeOpaque500(w)
|
||||
return
|
||||
}
|
||||
writeData(w, map[string]any{
|
||||
"id": res.Quiz.ID,
|
||||
"slug": res.Quiz.Slug,
|
||||
"created": res.Created,
|
||||
"questions": res.Questions,
|
||||
"answers": res.Answers,
|
||||
})
|
||||
}
|
||||
|
||||
// managedMaterialJSON is a material as the management API shows it: drafts
|
||||
// too, so published_at may be null.
|
||||
type managedMaterialJSON struct {
|
||||
|
||||
3
go.mod
3
go.mod
@@ -3,7 +3,6 @@ module git.golem15.com/jakub/sm-bm-plugin
|
||||
go 1.27.0
|
||||
|
||||
require (
|
||||
git.golem15.com/golem15/sm-quizzes-plugin v0.0.0
|
||||
git.golem15.com/golem15/sm-user-plugin v0.0.0
|
||||
git.golem15.com/golem15/summercms v0.0.0
|
||||
github.com/go-gormigrate/gormigrate/v2 v2.1.7
|
||||
@@ -122,5 +121,3 @@ require (
|
||||
replace git.golem15.com/golem15/summercms => ../../../../summercms.go
|
||||
|
||||
replace git.golem15.com/golem15/sm-user-plugin => ../../golem15/user
|
||||
|
||||
replace git.golem15.com/golem15/sm-quizzes-plugin => ../../golem15/quizzes
|
||||
|
||||
@@ -54,9 +54,8 @@ type Plugin struct {
|
||||
func (p *Plugin) ID() string { return "jz.bm" }
|
||||
|
||||
// Requires golem15.user: its users table holds the students, and its
|
||||
// jwt.auth middleware guards the API. golem15.quizzes holds the quizzes the
|
||||
// management API imports.
|
||||
func (p *Plugin) Requires() []string { return []string{"golem15.user", "golem15.quizzes"} }
|
||||
// jwt.auth and user.api_token middleware guard the APIs.
|
||||
func (p *Plugin) Requires() []string { return []string{"golem15.user"} }
|
||||
|
||||
func (p *Plugin) Register(app *backpack.App) error {
|
||||
p.app = app
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
_ "git.golem15.com/golem15/sm-quizzes-plugin"
|
||||
_ "git.golem15.com/golem15/sm-user-plugin"
|
||||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||||
"git.golem15.com/golem15/summercms/modules/bonfire"
|
||||
@@ -48,11 +47,10 @@ func testConfig(t *testing.T) *compass.Config {
|
||||
return cfg
|
||||
}
|
||||
|
||||
// activate boots the plugin and both declared dependencies the way the
|
||||
// generated main does.
|
||||
// activate boots golem15.user and jz.bm the way the generated main does.
|
||||
func activate(t *testing.T, app *backpack.App) []party.Plugin {
|
||||
t.Helper()
|
||||
plugins, err := party.Activate(app, []string{"golem15.user", "golem15.quizzes", "jz.bm"})
|
||||
plugins, err := party.Activate(app, []string{"golem15.user", "jz.bm"})
|
||||
if err != nil {
|
||||
t.Fatalf("Activate: %v", err)
|
||||
}
|
||||
@@ -73,7 +71,7 @@ func bmPlugin(t *testing.T, plugins []party.Plugin) *bm.Plugin {
|
||||
func TestPluginActivates(t *testing.T) {
|
||||
app := backpack.New(testConfig(t))
|
||||
p := bmPlugin(t, activate(t, app))
|
||||
if p.ID() != "jz.bm" || !slices.Equal(p.Requires(), []string{"golem15.user", "golem15.quizzes"}) {
|
||||
if p.ID() != "jz.bm" || !slices.Equal(p.Requires(), []string{"golem15.user"}) {
|
||||
t.Errorf("ID %q Requires %v", p.ID(), p.Requires())
|
||||
}
|
||||
if n := len(p.Models()); n != 10 {
|
||||
@@ -125,7 +123,6 @@ func TestRoutes(t *testing.T) {
|
||||
"POST /api/v1/bm/materials",
|
||||
"DELETE /api/v1/bm/materials/{id}",
|
||||
"POST /api/v1/bm/seed",
|
||||
"POST /api/v1/bm/quizzes",
|
||||
}
|
||||
var got []string
|
||||
sawFeed := false
|
||||
|
||||
@@ -91,7 +91,7 @@ func (p *Plugin) Routes(r pact.Router) error {
|
||||
g.Post("/calendar-feed/rotate", h.RotateCalendarFeed, "throttle:10,1")
|
||||
g.Delete("/calendar-feed", h.DeleteCalendarFeed)
|
||||
})
|
||||
// The management API: what bm:seed and quizzes:import do, plus materials,
|
||||
// The management API: what bm:seed does, plus materials,
|
||||
// behind the application-wide user API token. Scope limits delegation;
|
||||
// user.permission checks the owner's current group permissions.
|
||||
r.Group(ManagePrefix, surf.Use(bucketManage, "user.api_token"), func(g pact.Router) {
|
||||
@@ -105,7 +105,6 @@ func (p *Plugin) Routes(r pact.Router) error {
|
||||
"user.permission:"+controllers.PermCourses,
|
||||
"user.permission:"+controllers.PermSchedule,
|
||||
"user.permission:"+controllers.PermMaterials)
|
||||
g.Post("/quizzes", h.ImportQuiz, "user.scope:write", "user.permission:golem15.quizzes.access_quizzes")
|
||||
})
|
||||
// The calendar feed: public, because calendar clients fetch it without
|
||||
// credentials; the token in the path is the credential. ServeMux cannot
|
||||
|
||||
@@ -10,7 +10,6 @@ import (
|
||||
"testing"
|
||||
"testing/fstest"
|
||||
|
||||
_ "git.golem15.com/golem15/sm-quizzes-plugin"
|
||||
_ "git.golem15.com/golem15/sm-user-plugin"
|
||||
"git.golem15.com/golem15/summercms/modules/backpack"
|
||||
"git.golem15.com/golem15/summercms/modules/compass"
|
||||
@@ -220,7 +219,7 @@ func TestStaticThroughRouter(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
app := backpack.New(cfg)
|
||||
plugins, err := party.Activate(app, []string{"golem15.user", "golem15.quizzes", "jz.bm"})
|
||||
plugins, err := party.Activate(app, []string{"golem15.user", "jz.bm"})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user