From 5d5e6206e438ff7903533644e9dc778b11193d87 Mon Sep 17 00:00:00 2001 From: polaris <2673986789@qq.com> Date: Mon, 29 Jul 2024 22:42:07 +0800 Subject: [PATCH] feat: question campus --- apis/cache.go | 37 +++++++++---- apis/question.go | 131 ++++++++++++++++++++++++++++++----------------- apis/schemas.go | 15 ++++-- 3 files changed, 122 insertions(+), 61 deletions(-) diff --git a/apis/cache.go b/apis/cache.go index df87249..d21ea4c 100644 --- a/apis/cache.go +++ b/apis/cache.go @@ -115,28 +115,45 @@ LOAD_FILES: currentQuestion := &questionConfig.Questions[i] if currentQuestion.Group == "required" { questionConfig.RequiredQuestions = append(questionConfig.RequiredQuestions, currentQuestion) - } else { + } else if currentQuestion.Group == "optional" { questionConfig.OptionalQuestions = append(questionConfig.OptionalQuestions, currentQuestion) + } else if currentQuestion.Group == "campus" { + questionConfig.CampusQuestions = append(questionConfig.CampusQuestions, currentQuestion) } } - if questionConfig.Spec.NumberOfQuestions > 0 { - if questionConfig.Spec.NumberOfQuestions < len(questionConfig.RequiredQuestions) { + if questionConfig.Spec.NumberOfOptionalQuestions > 0 { + if questionConfig.Spec.NumberOfOptionalQuestions > len(questionConfig.OptionalQuestions) { log.Warn(). Str("filename", file.Name()). - Int("number_of_questions", questionConfig.Spec.NumberOfQuestions). - Int("number_of_required_questions", len(questionConfig.RequiredQuestions)). - Msg("expected number of questions is less than number of required questions") + Int("number_of_optional_questions", questionConfig.Spec.NumberOfOptionalQuestions). + Int("number_of_optional_questions", len(questionConfig.OptionalQuestions)). + Msg("expected number of optional questions is greater than number of optional questions") continue LOAD_FILES } - if questionConfig.Spec.NumberOfQuestions > len(questionConfig.Questions) { + } else if questionConfig.Spec.NumberOfOptionalQuestions < -1 { + log.Warn(). + Str("filename", file.Name()). + Int("number_of_optional_questions", questionConfig.Spec.NumberOfOptionalQuestions). + Msg("expected number of optional questions is less than -1") + continue LOAD_FILES + } + + if questionConfig.Spec.NumberOfCampusQuestions > 0 { + if questionConfig.Spec.NumberOfCampusQuestions > len(questionConfig.CampusQuestions) { log.Warn(). Str("filename", file.Name()). - Int("number_of_questions", questionConfig.Spec.NumberOfQuestions). - Int("number_of_questions", len(questionConfig.Questions)). - Msg("expected number of questions is greater than number of questions") + Int("number_of_campus_questions", questionConfig.Spec.NumberOfCampusQuestions). + Int("number_of_campus_questions", len(questionConfig.CampusQuestions)). + Msg("expected number of campus questions is greater than number of campus questions") continue LOAD_FILES } + } else if questionConfig.Spec.NumberOfCampusQuestions < -1 { + log.Warn(). + Str("filename", file.Name()). + Int("number_of_campus_questions", questionConfig.Spec.NumberOfCampusQuestions). + Msg("expected number of campus questions is less than 0") + continue LOAD_FILES } valid := true diff --git a/apis/question.go b/apis/question.go index 8001cc2..f6b6b5a 100644 --- a/apis/question.go +++ b/apis/question.go @@ -49,74 +49,101 @@ func RetrieveQuestions(c *fiber.Ctx) (err error) { } var ( - questions = questionConfig.Questions - requiredQuestions = questionConfig.RequiredQuestions - optionalQuestions = questionConfig.OptionalQuestions - number = questionConfig.Spec.NumberOfQuestions - inOrder = questionConfig.Spec.InOrder + // questions = questionConfig.Questions + // number = questionConfig.Spec.NumberOfQuestions + requiredQuestions = questionConfig.RequiredQuestions + optionalQuestions = questionConfig.OptionalQuestions + campusQuestions = questionConfig.CampusQuestions + numberOfOptionalQuestions = questionConfig.Spec.NumberOfOptionalQuestions + numberOfCampusQuestions = questionConfig.Spec.NumberOfCampusQuestions + inOrder = questionConfig.Spec.InOrder ) + number := len(requiredQuestions) + if numberOfOptionalQuestions == -1 { + number += len(optionalQuestions) + } else if numberOfOptionalQuestions >= 0 { + number += numberOfOptionalQuestions + } else { + return common.InternalServerError("[retrieve questions]: number of optional questions invalid") + } + if numberOfCampusQuestions == -1 { + number += len(campusQuestions) + } else if numberOfCampusQuestions >= 0 { + number += numberOfCampusQuestions + } else { + return common.InternalServerError("[retrieve questions]: number of campus questions invalid") + } + var questionsResponse = QuestionConfig{ Version: version, Spec: QuestionSpec{ - NumberOfQuestions: number, - InOrder: inOrder, + NumberOfOptionalQuestions: numberOfOptionalQuestions, + NumberOfCampusQuestions: numberOfCampusQuestions, + NumberOfQuestions: number, + InOrder: inOrder, }, } - if number == 0 { - // send all questions - questionsResponse.Questions = make([]Question, len(questions)) - copy(questionsResponse.Questions, questions) + questionsResponse.Questions = make([]Question, number) + tmpQuestions := make([]*Question, 0, number) - } else if number == -1 { - // send all required questions - questionsResponse.Questions = make([]Question, len(requiredQuestions)) + if number == 0 { + return common.InternalServerError("[retrieve questions]: number of questions too small") + } - for i, question := range requiredQuestions { - questionsResponse.Questions[i] = *question - } - } else { - // send all required questions and part of random optional questions according to number - // be sure that number == len(requiredQuestions) + len(chosenOptionalQuestions) - // if number < len(requiredQuestions), return error - questionsResponse.Questions = make([]Question, number) - optionalQuestionsNumber := number - len(requiredQuestions) - if optionalQuestionsNumber < 0 { - return common.InternalServerError("[retrieve questions]: number of questions too small") - } + copy(tmpQuestions, requiredQuestions) - for i, question := range requiredQuestions { - questionsResponse.Questions[i] = *question - } + // for i, question := range requiredQuestions { + // tmpQuestions[i] = question + // // questionsResponse.Questions[i] = *question + // } + // questionConfig.Questions = append(questionConfig.Questions, optionalQuestions...) + if numberOfOptionalQuestions == -1 { + // send all opntional questions + tmpQuestions = append(tmpQuestions, optionalQuestions...) + } else if numberOfOptionalQuestions > 0 { // shuffle optional questions - if optionalQuestionsNumber > 0 { - chosenOptionalQuestions := make([]*Question, len(optionalQuestions)) - copy(chosenOptionalQuestions, optionalQuestions) - rand.Shuffle(len(chosenOptionalQuestions), func(i, j int) { - chosenOptionalQuestions[i], chosenOptionalQuestions[j] = chosenOptionalQuestions[j], chosenOptionalQuestions[i] - }) - - for i, question := range chosenOptionalQuestions { - questionsResponse.Questions[i+len(requiredQuestions)] = *question - if i == optionalQuestionsNumber-1 { - break - } - } - } + chosenOptionalQuestions := make([]*Question, len(optionalQuestions)) + copy(chosenOptionalQuestions, optionalQuestions) + rand.Shuffle(len(chosenOptionalQuestions), func(i, j int) { + chosenOptionalQuestions[i], chosenOptionalQuestions[j] = chosenOptionalQuestions[j], chosenOptionalQuestions[i] + }) + + tmpQuestions = append(tmpQuestions, chosenOptionalQuestions[:numberOfOptionalQuestions]...) + } + + if numberOfCampusQuestions == -1 { + // send all campus questions + tmpQuestions = append(tmpQuestions, campusQuestions...) + } else if numberOfCampusQuestions > 0 { + // shuffle campus questions + chosenCampusQuestions := make([]*Question, len(campusQuestions)) + copy(chosenCampusQuestions, campusQuestions) + rand.Shuffle(len(chosenCampusQuestions), func(i, j int) { + chosenCampusQuestions[i], chosenCampusQuestions[j] = chosenCampusQuestions[j], chosenCampusQuestions[i] + }) + + tmpQuestions = append(tmpQuestions, chosenCampusQuestions[:numberOfCampusQuestions]...) } + + if !inOrder { - rand.Shuffle(len(questionsResponse.Questions), func(i, j int) { - questionsResponse.Questions[i], questionsResponse.Questions[j] = questionsResponse.Questions[j], questionsResponse.Questions[i] + rand.Shuffle(len(tmpQuestions), func(i, j int) { + tmpQuestions[i], tmpQuestions[j] = tmpQuestions[j], tmpQuestions[i] }) } else { - sort.Slice(questionsResponse.Questions, func(i, j int) bool { - return questionsResponse.Questions[i].ID < questionsResponse.Questions[j].ID + sort.Slice(tmpQuestions, func(i, j int) bool { + return tmpQuestions[i].ID < tmpQuestions[j].ID }) } + for i, question := range tmpQuestions { + questionsResponse.Questions[i] = *question + } + // shuffle options for i := range questionsResponse.Questions { options := questionsResponse.Questions[i].Options // copy slice pointer only @@ -127,8 +154,12 @@ func RetrieveQuestions(c *fiber.Ctx) (err error) { // clear analysis and answer for i := range questionsResponse.Questions { + if questionsResponse.Questions[i].Group == "campus" { + questionsResponse.Questions[i].Group = "optional" + } questionsResponse.Questions[i].Analysis = "" questionsResponse.Questions[i].Answer = nil + questionsResponse.Questions[i].Option = questionsResponse.Questions[i].Options } return c.JSON(questionsResponse) @@ -183,9 +214,10 @@ func AnswerQuestions(c *fiber.Ctx) (err error) { var ( questions = questionConfig.Questions requiredQuestions = questionConfig.RequiredQuestions - number = questionConfig.Spec.NumberOfQuestions ) + number := len(requiredQuestions) + questionConfig.Spec.NumberOfOptionalQuestions + questionConfig.Spec.NumberOfCampusQuestions + // get all submitted question number and required question number submittedQuestionNumber := len(body.Answers) submittedRequiredQuestionNumber := 0 @@ -253,6 +285,9 @@ func AnswerQuestions(c *fiber.Ctx) (err error) { } accessToken, refreshToken, err := user.CreateJWTToken() + if err != nil { + return + } return c.JSON(SubmitResponse{ Correct: true, diff --git a/apis/schemas.go b/apis/schemas.go index 74dc480..f9234e0 100644 --- a/apis/schemas.go +++ b/apis/schemas.go @@ -104,7 +104,7 @@ type Question struct { Type QuestionType `json:"type" yaml:"type" validate:"oneof=single-selection true-or-false multi-selection"` // 题目分组,可选或必选 - Group string `json:"group" yaml:"group" validate:"oneof=optional required"` + Group string `json:"group" yaml:"group" validate:"oneof=optional required campus"` // 问题描述 Question string `json:"question" yaml:"question" validate:"required"` @@ -122,6 +122,9 @@ type Question struct { // 有一个或多个选项,如果是判断题,则选项只能是 true 或者 false // 如果 Answer 中的答案不在 Options 中,则会在解析时加到 Options 中 Options []string `json:"options" yaml:"options"` + + // 椰树 swift + Option []string `json:"option" yaml:"option"` // 题目解析,预留,可选 Analysis string `json:"analysis,omitempty" yaml:"analysis,omitempty"` @@ -129,12 +132,17 @@ type Question struct { // QuestionSpec 题库的发题、判题的规格 schema type QuestionSpec struct { - // 表示总的题目数量。 + NumberOfQuestions int `json:"number_of_questions" yaml:"number_of_questions"` + + // 表示可选题的题目数量。 // 发送题目时,题库中的必做题都会发送,可选题会根据题目数量随机发送。 // 如果总的题目数量小于题库中的必做题数量,将会在解析时返回错误。 // 如果设置为 0 或者不设置,则题库中的所有题目都会发送 // 如果设置为 -1,则题库中的必做题都会发送,可选题不会发送 - NumberOfQuestions int `json:"number_of_questions" yaml:"number_of_questions"` + NumberOfOptionalQuestions int `json:"number_of_optional_questions" yaml:"number_of_optional_questions"` + + // 校园题的数量 + NumberOfCampusQuestions int `json:"number_of_campus_questions" yaml:"number_of_campus_questions"` // 表示是否由题目声明顺序由上到下顺序出题,默认为 false,即乱序出题 InOrder bool `json:"in_order" yaml:"in_order"` @@ -154,6 +162,7 @@ type QuestionConfig struct { // 辅助信息,不需要填写 RequiredQuestions []*Question `json:"-" yaml:"-"` OptionalQuestions []*Question `json:"-" yaml:"-"` + CampusQuestions []*Question `json:"-" yaml:"-"` } // SubmitAnswer 提交的答案 schema.