Compare commits

...

2 Commits

Author SHA1 Message Date
b1a1b97a0a Merge remote-tracking branch 'origin/production' 2026-04-14 04:03:21 -07:00
e3afadf2bb 404 errors fix 2026-04-14 03:56:49 -07:00
2 changed files with 69 additions and 0 deletions

View File

@ -18,6 +18,11 @@ type createCourseSubCategoryReq struct {
IsActive *bool `json:"is_active"`
}
type createCourseCategoryReq struct {
Name string `json:"name"`
IsActive *bool `json:"is_active"`
}
type createLevelReq struct {
CourseID int64 `json:"course_id"`
CEFRLevel string `json:"cefr_level"`
@ -111,6 +116,68 @@ func intOrNil(v *int32) interface{} {
return *v
}
// ListCourseCategories godoc
// @Summary List course categories
// @Description Legacy-compatible endpoint for listing course categories
// @Tags course-management
// @Produce json
// @Success 200 {object} domain.Response
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/course-management/categories [get]
func (h *Handler) ListCourseCategories(c *fiber.Ctx) error {
rows, err := h.analyticsDB.GetAllCourseCategories(c.Context(), dbgen.GetAllCourseCategoriesParams{
Offset: pgtype.Int4{Int32: 0, Valid: true},
Limit: pgtype.Int4{Int32: 10000, Valid: true},
})
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to load categories", Error: err.Error()})
}
total := 0
if len(rows) > 0 {
total = int(rows[0].TotalCount)
}
return c.JSON(domain.Response{
Message: "Categories retrieved successfully",
Data: map[string]interface{}{
"categories": rows,
"total_count": total,
},
})
}
// CreateCourseCategory godoc
// @Summary Create course category
// @Description Legacy-compatible endpoint for creating a course category
// @Tags course-management
// @Accept json
// @Produce json
// @Param body body createCourseCategoryReq true "Create category payload"
// @Success 201 {object} domain.Response
// @Failure 400 {object} domain.ErrorResponse
// @Failure 500 {object} domain.ErrorResponse
// @Router /api/v1/course-management/categories [post]
func (h *Handler) CreateCourseCategory(c *fiber.Ctx) error {
var req createCourseCategoryReq
if err := c.BodyParser(&req); err != nil {
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid request body", Error: err.Error()})
}
if strings.TrimSpace(req.Name) == "" {
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "name is required"})
}
created, err := h.analyticsDB.CreateCourseCategory(c.Context(), dbgen.CreateCourseCategoryParams{
Name: req.Name,
Column2: boolOrNil(req.IsActive),
})
if err != nil {
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to create category", Error: err.Error()})
}
return c.Status(fiber.StatusCreated).JSON(domain.Response{Message: "Course category created", Data: created})
}
// UnifiedHierarchy godoc
// @Summary Get unified course hierarchy
// @Description Returns full hierarchy: category -> sub-category -> course

View File

@ -79,6 +79,8 @@ func (a *App) initAppRoutes() {
groupV1.Get("/assessment/questions/:id", h.GetAssessmentQuestionByID)
// Unified Course Management (single hierarchy model)
groupV1.Get("/course-management/categories", a.authMiddleware, a.RequirePermission("learning_tree.get"), h.ListCourseCategories)
groupV1.Post("/course-management/categories", a.authMiddleware, a.RequirePermission("course_categories.create"), h.CreateCourseCategory)
groupV1.Get("/course-management/hierarchy", a.authMiddleware, a.RequirePermission("learning_tree.get"), h.UnifiedHierarchy)
groupV1.Get("/course-management/courses/:courseId/hierarchy", a.authMiddleware, a.RequirePermission("learning_tree.get"), h.UnifiedHierarchyByCourse)
groupV1.Post("/course-management/sub-categories", a.authMiddleware, a.RequirePermission("course_categories.create"), h.CreateCourseSubCategory)