- migration: open question type, rubric, max_length, quiz grader and the grading and review columns of attempt answers - open answers are checked, stored as pending and never scored on answer; a changed text resets the grading state - student JSON gains text, grading_status, grader_feedback, review_comment, max_length, needs_review and open_answers; the rubric is never serialized
63 lines
2.1 KiB
Go
63 lines
2.1 KiB
Go
// Package graders is the grader registry of golem15.quizzes. A plugin that
|
|
// grades open answers implements HasGraders, and golem15.quizzes collects
|
|
// its graders at boot. Manual is built in and is never called: an answer of
|
|
// a manual quiz waits for the owner. The package imports only the standard
|
|
// library, so a grading plugin can depend on it without pulling in the rest
|
|
// of golem15.quizzes.
|
|
package graders
|
|
|
|
import "context"
|
|
|
|
// Manual is the built-in grader code: the owner grades every open answer.
|
|
const Manual = "manual"
|
|
|
|
// ManualLabel is the lang key of Manual in the admin grader dropdown.
|
|
const ManualLabel = "golem15.quizzes::lang.graders.manual"
|
|
|
|
// Input is one open answer to grade.
|
|
type Input struct {
|
|
QuizID uint
|
|
QuestionID uint
|
|
AttemptID uint
|
|
AnswerID uint
|
|
UserID uint
|
|
// Question is the owner-authored question text.
|
|
Question string
|
|
// ModelAnswer is the owner-authored model answer; it may be empty.
|
|
ModelAnswer string
|
|
// Rubric is the owner-authored grading rubric; it may be empty and is
|
|
// owner-only: it must never reach the student.
|
|
Rubric string
|
|
// Answer is the student's text. It is untrusted input.
|
|
Answer string
|
|
// Points is the full value of the question.
|
|
Points int
|
|
}
|
|
|
|
// Result is a grader's verdict. golem15.quizzes clamps Points to
|
|
// 0..Input.Points in steps of 0.5 and refuses a value that is not a finite
|
|
// number.
|
|
type Result struct {
|
|
Points float64
|
|
Feedback string
|
|
}
|
|
|
|
// Grader grades open answers. Grade runs in a background job with no
|
|
// transaction open, so it may take seconds; an error is retried a few times
|
|
// and then leaves the answer failed for the owner to grade.
|
|
type Grader interface {
|
|
// Code identifies the grader in a quiz's grader field, such as "ai".
|
|
// It must match ^[a-z][a-z0-9_]{0,63}$ and must not be Manual.
|
|
Code() string
|
|
// Label is the lang key or text the admin grader dropdown shows.
|
|
Label() string
|
|
// Grade scores one answer.
|
|
Grade(ctx context.Context, in Input) (Result, error)
|
|
}
|
|
|
|
// HasGraders is implemented by a plugin that provides graders.
|
|
// golem15.quizzes calls it once at boot.
|
|
type HasGraders interface {
|
|
QuizGraders() []Grader
|
|
}
|