Files
sm-quizzes-plugin/classes/open.go
Jakub Zych 297780cb8e feat: add open questions with a pending grading state
- 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
2026-11-09 17:48:11 +01:00

34 lines
1.0 KiB
Go

package classes
import (
"strings"
"unicode/utf8"
"git.golem15.com/golem15/sm-quizzes-plugin/models"
)
// MaxLength is the longest answer an open question accepts, in characters:
// its MaxLength when set and positive, else models.DefaultMaxLength.
func MaxLength(q models.Question) int {
if q.MaxLength != nil && *q.MaxLength > 0 {
return *q.MaxLength
}
return models.DefaultMaxLength
}
// CheckOpenText cleans a student's answer to an open question (D-04): it
// removes every NUL character (Postgres text refuses them) and the
// surrounding whitespace. A blank text is a FieldError text_required and a
// text longer than MaxLength(q) characters (runes, not bytes) is a
// FieldError text_too_long.
func CheckOpenText(text string, q models.Question) (string, error) {
text = strings.TrimSpace(strings.ReplaceAll(text, "\x00", ""))
if text == "" {
return "", &FieldError{Field: "text", Key: "text_required"}
}
if utf8.RuneCountInString(text) > MaxLength(q) {
return "", &FieldError{Field: "text", Key: "text_too_long"}
}
return text, nil
}