Skip to content

Commit

Permalink
Merge pull request #21 from ppolariss/main
Browse files Browse the repository at this point in the history
feat: question campus
  • Loading branch information
JingYiJun authored Jul 29, 2024
2 parents 14d7961 + 5d5e620 commit 1965872
Show file tree
Hide file tree
Showing 3 changed files with 122 additions and 61 deletions.
37 changes: 27 additions & 10 deletions apis/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
131 changes: 83 additions & 48 deletions apis/question.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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,
Expand Down
15 changes: 12 additions & 3 deletions apis/schemas.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand All @@ -122,19 +122,27 @@ 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"`
}

// 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"`
Expand All @@ -154,6 +162,7 @@ type QuestionConfig struct {
// 辅助信息,不需要填写
RequiredQuestions []*Question `json:"-" yaml:"-"`
OptionalQuestions []*Question `json:"-" yaml:"-"`
CampusQuestions []*Question `json:"-" yaml:"-"`
}

// SubmitAnswer 提交的答案 schema.
Expand Down

0 comments on commit 1965872

Please sign in to comment.