Files
sm-quizzes-plugin/controllers/api/import.go
Jakub Zych 032f2da17f feat: serve quizzes:import over HTTP behind the shared user API token
POST /api/v1/quizzes/import runs behind golem15.user's user.api_token with
the write scope and the golem15.quizzes.access_quizzes permission.
2026-10-04 23:15:01 +02:00

59 lines
1.8 KiB
Go

package api
import (
"errors"
"io"
"net/http"
"git.golem15.com/golem15/sm-quizzes-plugin/classes"
"git.golem15.com/golem15/summercms/modules/wire"
"gorm.io/gorm"
)
// ImportQuiz answers POST /import?replace=: quizzes:import over HTTP, for
// the management API behind golem15.user's API token. The body is the
// import document. A document that does not parse is a 422 and writes
// nothing; an existing slug is a 409 unless replace is 1 or true.
func (h *Handlers) ImportQuiz(w http.ResponseWriter, r *http.Request) {
raw, err := io.ReadAll(r.Body)
var tooLarge *http.MaxBytesError
switch {
case errors.As(err, &tooLarge):
wire.WriteJSON(w, http.StatusRequestEntityTooLarge, map[string]any{"error": true, "message": "Request body too large."})
return
case err != nil:
wire.WriteJSON(w, http.StatusBadRequest, map[string]any{"error": true, "message": "Unreadable request body."})
return
}
doc, err := classes.ParseImport(raw)
if err != nil {
wire.WriteJSON(w, http.StatusUnprocessableEntity, map[string]any{"message": err.Error()})
return
}
var db *gorm.DB
if h.App != nil {
db, _ = h.App.Lookup[*gorm.DB]()
}
if db == nil {
wire.WriteOpaque500(w)
return
}
replace := r.URL.Query().Get("replace")
res, err := classes.Import(r.Context(), db, doc, replace == "1" || replace == "true")
if errors.Is(err, classes.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 {
wire.WriteOpaque500(w)
return
}
wire.WriteJSON(w, http.StatusOK, map[string]any{"data": map[string]any{
"id": res.Quiz.ID,
"slug": res.Quiz.Slug,
"created": res.Created,
"questions": res.Questions,
"answers": res.Answers,
}})
}