216 lines
6.4 KiB
Go
216 lines
6.4 KiB
Go
package handlers
|
|
|
|
import (
|
|
"Yimaru-Backend/internal/domain"
|
|
"strconv"
|
|
|
|
"github.com/gofiber/fiber/v2"
|
|
)
|
|
|
|
// CreateAssessmentQuestion godoc
|
|
// @Summary Create assessment question
|
|
// @Description Creates a new assessment question using the unified questions system
|
|
// @Tags assessment-question
|
|
// @Accept json
|
|
// @Produce json
|
|
// @Param body body createQuestionReq true "Create question payload"
|
|
// @Success 201 {object} domain.Response
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/assessment/questions [post]
|
|
func (h *Handler) CreateAssessmentQuestion(c *fiber.Ctx) error {
|
|
var req createQuestionReq
|
|
if err := c.BodyParser(&req); err != nil {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid request body",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
if req.QuestionText == "" {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Validation error",
|
|
Error: "question_text is required",
|
|
})
|
|
}
|
|
|
|
// Build options input
|
|
var options []domain.CreateQuestionOptionInput
|
|
for _, opt := range req.Options {
|
|
options = append(options, domain.CreateQuestionOptionInput{
|
|
OptionText: opt.OptionText,
|
|
OptionOrder: opt.OptionOrder,
|
|
IsCorrect: opt.IsCorrect,
|
|
})
|
|
}
|
|
|
|
// Build short answers input
|
|
var shortAnswers []domain.CreateShortAnswerInput
|
|
for _, sa := range req.ShortAnswers {
|
|
shortAnswers = append(shortAnswers, domain.CreateShortAnswerInput{
|
|
AcceptableAnswer: sa.AcceptableAnswer,
|
|
MatchType: sa.MatchType,
|
|
})
|
|
}
|
|
|
|
input := domain.CreateQuestionInput{
|
|
QuestionText: req.QuestionText,
|
|
QuestionType: req.QuestionType,
|
|
DifficultyLevel: req.DifficultyLevel,
|
|
Points: req.Points,
|
|
Explanation: req.Explanation,
|
|
Tips: req.Tips,
|
|
VoicePrompt: req.VoicePrompt,
|
|
SampleAnswerVoicePrompt: req.SampleAnswerVoicePrompt,
|
|
Status: req.Status,
|
|
Options: options,
|
|
ShortAnswers: shortAnswers,
|
|
}
|
|
|
|
question, err := h.assessmentSvc.CreateQuestion(c.Context(), input)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to create assessment question",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusCreated).JSON(domain.Response{
|
|
Message: "Assessment question created successfully",
|
|
StatusCode: fiber.StatusCreated,
|
|
Success: true,
|
|
Data: questionRes{
|
|
ID: question.ID,
|
|
QuestionText: question.QuestionText,
|
|
QuestionType: question.QuestionType,
|
|
Status: question.Status,
|
|
CreatedAt: question.CreatedAt.String(),
|
|
},
|
|
})
|
|
}
|
|
|
|
// ListAssessmentQuestions godoc
|
|
// @Summary List assessment questions
|
|
// @Description Returns all active assessment questions from the initial assessment set
|
|
// @Tags assessment-question
|
|
// @Produce json
|
|
// @Success 200 {array} domain.QuestionWithDetails
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/assessment/questions [get]
|
|
func (h *Handler) ListAssessmentQuestions(c *fiber.Ctx) error {
|
|
questions, err := h.assessmentSvc.ListQuestions(c.Context())
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to fetch assessment questions",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
var questionResponses []questionRes
|
|
for _, q := range questions {
|
|
var options []optionRes
|
|
for _, opt := range q.Options {
|
|
options = append(options, optionRes{
|
|
ID: opt.ID,
|
|
OptionText: opt.OptionText,
|
|
OptionOrder: opt.OptionOrder,
|
|
IsCorrect: opt.IsCorrect,
|
|
})
|
|
}
|
|
|
|
var shortAnswers []shortAnswerRes
|
|
for _, sa := range q.ShortAnswers {
|
|
shortAnswers = append(shortAnswers, shortAnswerRes{
|
|
ID: sa.ID,
|
|
AcceptableAnswer: sa.AcceptableAnswer,
|
|
MatchType: sa.MatchType,
|
|
})
|
|
}
|
|
|
|
questionResponses = append(questionResponses, questionRes{
|
|
ID: q.ID,
|
|
QuestionText: q.QuestionText,
|
|
QuestionType: q.QuestionType,
|
|
DifficultyLevel: q.DifficultyLevel,
|
|
Points: q.Points,
|
|
Status: q.Status,
|
|
CreatedAt: q.CreatedAt.String(),
|
|
Options: options,
|
|
ShortAnswers: shortAnswers,
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
|
Message: "Questions fetched successfully",
|
|
Data: questionResponses,
|
|
Success: true,
|
|
StatusCode: 200,
|
|
})
|
|
}
|
|
|
|
// GetAssessmentQuestionByID godoc
|
|
// @Summary Get assessment question by ID
|
|
// @Description Returns a single assessment question with its options or answer
|
|
// @Tags assessment-question
|
|
// @Produce json
|
|
// @Param id path int true "Question ID"
|
|
// @Success 200 {object} domain.QuestionWithDetails
|
|
// @Failure 400 {object} domain.ErrorResponse
|
|
// @Failure 404 {object} domain.ErrorResponse
|
|
// @Failure 500 {object} domain.ErrorResponse
|
|
// @Router /api/v1/assessment/questions/{id} [get]
|
|
func (h *Handler) GetAssessmentQuestionByID(c *fiber.Ctx) error {
|
|
idStr := c.Params("id")
|
|
id, err := strconv.ParseInt(idStr, 10, 64)
|
|
if err != nil || id <= 0 {
|
|
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{
|
|
Message: "Invalid question ID",
|
|
Error: "question ID must be a positive integer",
|
|
})
|
|
}
|
|
|
|
question, err := h.assessmentSvc.GetQuestionByID(c.Context(), id)
|
|
if err != nil {
|
|
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{
|
|
Message: "Failed to fetch assessment question",
|
|
Error: err.Error(),
|
|
})
|
|
}
|
|
|
|
var options []optionRes
|
|
for _, opt := range question.Options {
|
|
options = append(options, optionRes{
|
|
ID: opt.ID,
|
|
OptionText: opt.OptionText,
|
|
OptionOrder: opt.OptionOrder,
|
|
IsCorrect: opt.IsCorrect,
|
|
})
|
|
}
|
|
|
|
var shortAnswers []shortAnswerRes
|
|
for _, sa := range question.ShortAnswers {
|
|
shortAnswers = append(shortAnswers, shortAnswerRes{
|
|
ID: sa.ID,
|
|
AcceptableAnswer: sa.AcceptableAnswer,
|
|
MatchType: sa.MatchType,
|
|
})
|
|
}
|
|
|
|
return c.Status(fiber.StatusOK).JSON(domain.Response{
|
|
Message: "Question fetched successfully",
|
|
Data: questionRes{
|
|
ID: question.ID,
|
|
QuestionText: question.QuestionText,
|
|
QuestionType: question.QuestionType,
|
|
DifficultyLevel: question.DifficultyLevel,
|
|
Points: question.Points,
|
|
Status: question.Status,
|
|
CreatedAt: question.CreatedAt.String(),
|
|
Options: options,
|
|
ShortAnswers: shortAnswers,
|
|
},
|
|
Success: true,
|
|
StatusCode: 200,
|
|
})
|
|
}
|