feat: create, publish, import and report on quizzes over MCP
- quizzes_create_quiz, update_quiz, delete_quiz (confirm repeats the slug), publish, unpublish, import_quiz (the existing import route) and quiz_stats on new manage routes - stats close expired open test attempts first, then report per student over completed whole-quiz attempts and per question over every completed attempt - input is checked before the database; TestManageAPIAgainstDatabase is written and skipped under -short
This commit is contained in:
@@ -114,3 +114,78 @@ func managedQuestion(q models.Question) managedQuestionJSON {
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
type statsJSON struct {
|
||||
Quiz statsQuizJSON `json:"quiz"`
|
||||
Students []studentStatJSON `json:"students"`
|
||||
Questions []questionStatJSON `json:"questions"`
|
||||
}
|
||||
|
||||
type statsQuizJSON struct {
|
||||
ID uint `json:"id"`
|
||||
Slug string `json:"slug"`
|
||||
Title string `json:"title"`
|
||||
Mode string `json:"mode"`
|
||||
PassingScore int `json:"passing_score"`
|
||||
QuestionCount int `json:"question_count"`
|
||||
}
|
||||
|
||||
type studentStatJSON struct {
|
||||
UserID uint `json:"user_id"`
|
||||
Email string `json:"email"`
|
||||
Name *string `json:"name"`
|
||||
Surname *string `json:"surname"`
|
||||
Attempts int `json:"attempts"`
|
||||
BestScorePercent *float64 `json:"best_score_percent"`
|
||||
LastScorePercent *float64 `json:"last_score_percent"`
|
||||
LastCompletedAt *wire.Time `json:"last_completed_at"`
|
||||
Passed bool `json:"passed"`
|
||||
}
|
||||
|
||||
type questionStatJSON struct {
|
||||
ID uint `json:"id"`
|
||||
Text string `json:"text"`
|
||||
Type string `json:"type"`
|
||||
Answered int `json:"answered"`
|
||||
Correct int `json:"correct"`
|
||||
CorrectPercent *float64 `json:"correct_percent"`
|
||||
MostChosenWrong *wrongAnswerJSON `json:"most_chosen_wrong"`
|
||||
}
|
||||
|
||||
type wrongAnswerJSON struct {
|
||||
AnswerID uint `json:"answer_id"`
|
||||
Text string `json:"text"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
func quizStats(s *classes.Stats) statsJSON {
|
||||
out := statsJSON{
|
||||
Quiz: statsQuizJSON{
|
||||
ID: s.Quiz.ID, Slug: s.Quiz.Slug, Title: s.Quiz.Title, Mode: quizMode(&s.Quiz),
|
||||
PassingScore: s.Quiz.PassingScore, QuestionCount: s.QuestionCount,
|
||||
},
|
||||
Students: make([]studentStatJSON, 0, len(s.Students)),
|
||||
Questions: make([]questionStatJSON, 0, len(s.Questions)),
|
||||
}
|
||||
for _, st := range s.Students {
|
||||
row := studentStatJSON{
|
||||
UserID: st.UserID, Email: st.Email, Name: st.Name, Surname: st.Surname, Attempts: st.Attempts,
|
||||
BestScorePercent: st.BestScorePercent, LastScorePercent: st.LastScorePercent, Passed: st.Passed,
|
||||
}
|
||||
if st.LastCompletedAt != nil {
|
||||
t := wireTime(*st.LastCompletedAt)
|
||||
row.LastCompletedAt = &t
|
||||
}
|
||||
out.Students = append(out.Students, row)
|
||||
}
|
||||
for _, q := range s.Questions {
|
||||
row := questionStatJSON{
|
||||
ID: q.ID, Text: q.Text, Type: q.Type, Answered: q.Answered, Correct: q.Correct, CorrectPercent: q.CorrectPercent,
|
||||
}
|
||||
if q.MostChosenWrong != nil {
|
||||
row.MostChosenWrong = &wrongAnswerJSON{AnswerID: q.MostChosenWrong.AnswerID, Text: q.MostChosenWrong.Text, Count: q.MostChosenWrong.Count}
|
||||
}
|
||||
out.Questions = append(out.Questions, row)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user