more course CRUD fix
This commit is contained in:
parent
5858aeb744
commit
2ff1e89263
113
gen/db/compat_course_management.go
Normal file
113
gen/db/compat_course_management.go
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
package dbgen
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
func (q *Queries) GetSubModuleByIDCompat(ctx context.Context, id int64) (SubModule, error) {
|
||||
row := q.db.QueryRow(ctx, `
|
||||
SELECT id, module_id, title, description, display_order, is_active, created_at, legacy_sub_course_id
|
||||
FROM sub_modules
|
||||
WHERE id = $1
|
||||
`, id)
|
||||
var i SubModule
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.ModuleID,
|
||||
&i.Title,
|
||||
&i.Description,
|
||||
&i.DisplayOrder,
|
||||
&i.IsActive,
|
||||
&i.CreatedAt,
|
||||
&i.LegacySubCourseID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateSubModuleCompat(ctx context.Context, id int64, title string, description string, isActive bool) error {
|
||||
_, err := q.db.Exec(ctx, `
|
||||
UPDATE sub_modules
|
||||
SET
|
||||
title = $1,
|
||||
description = NULLIF($2, ''),
|
||||
is_active = $3
|
||||
WHERE id = $4
|
||||
`, title, description, isActive, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (q *Queries) DeleteSubModuleCompat(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, `DELETE FROM sub_modules WHERE id = $1`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateSubModuleVideoCompat(ctx context.Context, id int64, title string, description string, videoURL string) error {
|
||||
_, err := q.db.Exec(ctx, `
|
||||
UPDATE sub_module_videos
|
||||
SET
|
||||
title = $1,
|
||||
description = NULLIF($2, ''),
|
||||
video_url = $3
|
||||
WHERE id = $4
|
||||
`, title, description, videoURL, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (q *Queries) DeleteSubModuleVideoCompat(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, `DELETE FROM sub_module_videos WHERE id = $1`, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (q *Queries) UpdatePracticeCompat(ctx context.Context, id int64, title string, description string, persona string) error {
|
||||
_, err := q.db.Exec(ctx, `
|
||||
UPDATE question_sets
|
||||
SET
|
||||
title = $1,
|
||||
description = NULLIF($2, ''),
|
||||
persona = NULLIF($3, ''),
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $4
|
||||
`, title, description, persona, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = q.db.Exec(ctx, `
|
||||
UPDATE sub_module_practices
|
||||
SET
|
||||
title = $1,
|
||||
description = NULLIF($2, '')
|
||||
WHERE question_set_id = $3
|
||||
`, title, description, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (q *Queries) UpdatePracticeStatusCompat(ctx context.Context, id int64, isActive bool) error {
|
||||
status := "ARCHIVED"
|
||||
if isActive {
|
||||
status = "PUBLISHED"
|
||||
}
|
||||
|
||||
_, err := q.db.Exec(ctx, `
|
||||
UPDATE question_sets
|
||||
SET
|
||||
status = $1,
|
||||
updated_at = CURRENT_TIMESTAMP
|
||||
WHERE id = $2
|
||||
`, status, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = q.db.Exec(ctx, `
|
||||
UPDATE sub_module_practices
|
||||
SET is_active = $1
|
||||
WHERE question_set_id = $2
|
||||
`, isActive, id)
|
||||
return err
|
||||
}
|
||||
|
||||
func (q *Queries) DeletePracticeCompat(ctx context.Context, id int64) error {
|
||||
_, err := q.db.Exec(ctx, `DELETE FROM question_sets WHERE id = $1`, id)
|
||||
return err
|
||||
}
|
||||
|
|
@ -81,6 +81,25 @@ type createSubModuleVideoReq struct {
|
|||
Status *string `json:"status"`
|
||||
}
|
||||
|
||||
type updateSubModuleReq struct {
|
||||
Title *string `json:"title"`
|
||||
Description *string `json:"description"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
}
|
||||
|
||||
type updateSubModuleVideoReq struct {
|
||||
Title *string `json:"title"`
|
||||
Description *string `json:"description"`
|
||||
VideoURL *string `json:"video_url"`
|
||||
}
|
||||
|
||||
type updatePracticeReq struct {
|
||||
Title *string `json:"title"`
|
||||
Description *string `json:"description"`
|
||||
Persona *string `json:"persona"`
|
||||
IsActive *bool `json:"is_active"`
|
||||
}
|
||||
|
||||
type attachSubModuleLessonReq struct {
|
||||
SubModuleID int64 `json:"sub_module_id"`
|
||||
QuestionSetID int64 `json:"question_set_id"`
|
||||
|
|
@ -738,3 +757,167 @@ func (h *Handler) CreateSubModulePractice(c *fiber.Ctx) error {
|
|||
return c.Status(fiber.StatusCreated).JSON(domain.Response{Message: "Practice created", Data: created})
|
||||
}
|
||||
|
||||
func (h *Handler) GetSubModuleVideos(c *fiber.Ctx) error {
|
||||
subModuleID, err := strconv.ParseInt(c.Params("subModuleId"), 10, 64)
|
||||
if err != nil || subModuleID <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid sub-module ID", Error: "subModuleId must be a positive integer"})
|
||||
}
|
||||
|
||||
videos, err := h.analyticsDB.GetSubModuleVideos(c.Context(), subModuleID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to load sub-module videos", Error: err.Error()})
|
||||
}
|
||||
|
||||
return c.JSON(domain.Response{
|
||||
Message: "Sub-module videos retrieved successfully",
|
||||
Data: map[string]interface{}{
|
||||
"videos": videos,
|
||||
"total_count": len(videos),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func (h *Handler) UpdateSubModule(c *fiber.Ctx) error {
|
||||
subModuleID, err := strconv.ParseInt(c.Params("subModuleId"), 10, 64)
|
||||
if err != nil || subModuleID <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid sub-module ID", Error: "subModuleId must be a positive integer"})
|
||||
}
|
||||
|
||||
existing, err := h.analyticsDB.GetSubModuleByIDCompat(c.Context(), subModuleID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to load sub-module", Error: err.Error()})
|
||||
}
|
||||
|
||||
var req updateSubModuleReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid request body", Error: err.Error()})
|
||||
}
|
||||
|
||||
title := existing.Title
|
||||
if req.Title != nil {
|
||||
title = *req.Title
|
||||
}
|
||||
description := ""
|
||||
if existing.Description.Valid {
|
||||
description = existing.Description.String
|
||||
}
|
||||
if req.Description != nil {
|
||||
description = *req.Description
|
||||
}
|
||||
isActive := existing.IsActive
|
||||
if req.IsActive != nil {
|
||||
isActive = *req.IsActive
|
||||
}
|
||||
|
||||
if err := h.analyticsDB.UpdateSubModuleCompat(c.Context(), subModuleID, title, description, isActive); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to update sub-module", Error: err.Error()})
|
||||
}
|
||||
|
||||
updated, err := h.analyticsDB.GetSubModuleByIDCompat(c.Context(), subModuleID)
|
||||
if err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Sub-module updated but failed to fetch latest record", Error: err.Error()})
|
||||
}
|
||||
return c.JSON(domain.Response{Message: "Sub-module updated", Data: updated})
|
||||
}
|
||||
|
||||
func (h *Handler) DeleteSubModule(c *fiber.Ctx) error {
|
||||
subModuleID, err := strconv.ParseInt(c.Params("subModuleId"), 10, 64)
|
||||
if err != nil || subModuleID <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid sub-module ID", Error: "subModuleId must be a positive integer"})
|
||||
}
|
||||
|
||||
if err := h.analyticsDB.DeleteSubModuleCompat(c.Context(), subModuleID); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to delete sub-module", Error: err.Error()})
|
||||
}
|
||||
return c.JSON(domain.Response{Message: "Sub-module deleted"})
|
||||
}
|
||||
|
||||
func (h *Handler) UpdateSubModuleVideo(c *fiber.Ctx) error {
|
||||
videoID, err := strconv.ParseInt(c.Params("videoId"), 10, 64)
|
||||
if err != nil || videoID <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid video ID", Error: "videoId must be a positive integer"})
|
||||
}
|
||||
|
||||
var req updateSubModuleVideoReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid request body", Error: err.Error()})
|
||||
}
|
||||
if req.Title == nil || strings.TrimSpace(*req.Title) == "" || req.VideoURL == nil || strings.TrimSpace(*req.VideoURL) == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "title and video_url are required"})
|
||||
}
|
||||
|
||||
description := ""
|
||||
if req.Description != nil {
|
||||
description = *req.Description
|
||||
}
|
||||
|
||||
if err := h.analyticsDB.UpdateSubModuleVideoCompat(c.Context(), videoID, *req.Title, description, *req.VideoURL); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to update sub-module video", Error: err.Error()})
|
||||
}
|
||||
return c.JSON(domain.Response{Message: "Sub-module video updated"})
|
||||
}
|
||||
|
||||
func (h *Handler) DeleteSubModuleVideo(c *fiber.Ctx) error {
|
||||
videoID, err := strconv.ParseInt(c.Params("videoId"), 10, 64)
|
||||
if err != nil || videoID <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid video ID", Error: "videoId must be a positive integer"})
|
||||
}
|
||||
|
||||
if err := h.analyticsDB.DeleteSubModuleVideoCompat(c.Context(), videoID); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to delete sub-module video", Error: err.Error()})
|
||||
}
|
||||
return c.JSON(domain.Response{Message: "Sub-module video deleted"})
|
||||
}
|
||||
|
||||
func (h *Handler) UpdatePractice(c *fiber.Ctx) error {
|
||||
practiceID, err := strconv.ParseInt(c.Params("practiceId"), 10, 64)
|
||||
if err != nil || practiceID <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid practice ID", Error: "practiceId must be a positive integer"})
|
||||
}
|
||||
|
||||
var req updatePracticeReq
|
||||
if err := c.BodyParser(&req); err != nil {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid request body", Error: err.Error()})
|
||||
}
|
||||
|
||||
if req.IsActive != nil {
|
||||
if err := h.analyticsDB.UpdatePracticeStatusCompat(c.Context(), practiceID, *req.IsActive); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to update practice status", Error: err.Error()})
|
||||
}
|
||||
return c.JSON(domain.Response{Message: "Practice status updated"})
|
||||
}
|
||||
|
||||
title := ""
|
||||
if req.Title != nil {
|
||||
title = *req.Title
|
||||
}
|
||||
description := ""
|
||||
if req.Description != nil {
|
||||
description = *req.Description
|
||||
}
|
||||
persona := ""
|
||||
if req.Persona != nil {
|
||||
persona = *req.Persona
|
||||
}
|
||||
if strings.TrimSpace(title) == "" {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "title is required"})
|
||||
}
|
||||
|
||||
if err := h.analyticsDB.UpdatePracticeCompat(c.Context(), practiceID, title, description, persona); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to update practice", Error: err.Error()})
|
||||
}
|
||||
return c.JSON(domain.Response{Message: "Practice updated"})
|
||||
}
|
||||
|
||||
func (h *Handler) DeletePractice(c *fiber.Ctx) error {
|
||||
practiceID, err := strconv.ParseInt(c.Params("practiceId"), 10, 64)
|
||||
if err != nil || practiceID <= 0 {
|
||||
return c.Status(fiber.StatusBadRequest).JSON(domain.ErrorResponse{Message: "Invalid practice ID", Error: "practiceId must be a positive integer"})
|
||||
}
|
||||
|
||||
if err := h.analyticsDB.DeletePracticeCompat(c.Context(), practiceID); err != nil {
|
||||
return c.Status(fiber.StatusInternalServerError).JSON(domain.ErrorResponse{Message: "Failed to delete practice", Error: err.Error()})
|
||||
}
|
||||
return c.JSON(domain.Response{Message: "Practice deleted"})
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -91,9 +91,16 @@ func (a *App) initAppRoutes() {
|
|||
groupV1.Post("/course-management/levels", a.authMiddleware, a.RequirePermission("subcourses.create"), h.CreateLevel)
|
||||
groupV1.Post("/course-management/modules", a.authMiddleware, a.RequirePermission("subcourses.create"), h.CreateModule)
|
||||
groupV1.Post("/course-management/sub-modules", a.authMiddleware, a.RequirePermission("subcourses.create"), h.CreateSubModule)
|
||||
groupV1.Put("/course-management/sub-modules/:subModuleId", a.authMiddleware, a.RequirePermission("subcourses.update"), h.UpdateSubModule)
|
||||
groupV1.Delete("/course-management/sub-modules/:subModuleId", a.authMiddleware, a.RequirePermission("subcourses.delete"), h.DeleteSubModule)
|
||||
groupV1.Get("/course-management/sub-modules/:subModuleId/videos", a.authMiddleware, a.RequirePermission("videos.list"), h.GetSubModuleVideos)
|
||||
groupV1.Post("/course-management/sub-module-videos", a.authMiddleware, a.RequirePermission("videos.create"), h.CreateSubModuleVideo)
|
||||
groupV1.Put("/course-management/sub-module-videos/:videoId", a.authMiddleware, a.RequirePermission("videos.update"), h.UpdateSubModuleVideo)
|
||||
groupV1.Delete("/course-management/sub-module-videos/:videoId", a.authMiddleware, a.RequirePermission("videos.delete"), h.DeleteSubModuleVideo)
|
||||
groupV1.Post("/course-management/sub-module-lessons", a.authMiddleware, a.RequirePermission("question_sets.update"), h.AttachSubModuleLesson)
|
||||
groupV1.Post("/course-management/sub-module-practices", a.authMiddleware, a.RequirePermission("question_sets.update"), h.CreateSubModulePractice)
|
||||
groupV1.Put("/course-management/practices/:practiceId", a.authMiddleware, a.RequirePermission("question_sets.update"), h.UpdatePractice)
|
||||
groupV1.Delete("/course-management/practices/:practiceId", a.authMiddleware, a.RequirePermission("question_sets.delete"), h.DeletePractice)
|
||||
|
||||
// Questions
|
||||
groupV1.Post("/questions", a.authMiddleware, a.RequirePermission("questions.create"), h.CreateQuestion)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user