package handlers import ( "context" "Yimaru-Backend/internal/domain" "Yimaru-Backend/internal/services/courses" "Yimaru-Backend/internal/services/examprep" "Yimaru-Backend/internal/services/modules" "Yimaru-Backend/internal/services/programs" "github.com/gofiber/fiber/v2" ) func (h *Handler) learnerHasSubscriptionCategory(c *fiber.Ctx, category domain.SubscriptionCategory) (bool, error) { userID, ok := c.Locals("user_id").(int64) if !ok || userID == 0 { return false, fiber.NewError(fiber.StatusUnauthorized, "Unauthorized") } return h.subscriptionsSvc.HasActiveSubscriptionByCategory(c.Context(), userID, category) } func (h *Handler) blockLearnerIfNotLMSProgram(c *fiber.Ctx, program domain.Program) error { role, _ := c.Locals("role").(domain.Role) if !role.IsCustomerLearnerRole() { return nil } if !domain.IsLMSContentCategory(program.Category) { return c.Status(fiber.StatusNotFound).JSON(domain.ErrorResponse{ Message: "Program not found", }) } return nil } func applyProgramEffectiveAccessTier(p *domain.Program) { p.EffectiveAccessTier = p.AccessTier } func applyCourseEffectiveAccessTier(course *domain.Course, program domain.Program) { course.EffectiveAccessTier = domain.EffectiveContentAccessTier(program.AccessTier, course.AccessTier) } func applyModuleEffectiveAccessTier(module *domain.Module, program domain.Program, course domain.Course) { module.EffectiveAccessTier = domain.EffectiveContentAccessTier(program.AccessTier, course.AccessTier, module.AccessTier) } func applyLessonEffectiveAccessTier(lesson *domain.Lesson, program domain.Program, course domain.Course, module domain.Module) { lesson.EffectiveAccessTier = domain.EffectiveContentAccessTier(program.AccessTier, course.AccessTier, module.AccessTier, lesson.AccessTier) } func applyExamPrepCatalogCourseEffectiveAccessTier(cc *domain.ExamPrepCatalogCourse) { cc.EffectiveAccessTier = cc.AccessTier } func applyExamPrepUnitEffectiveAccessTier(unit *domain.ExamPrepUnit, catalogCourse domain.ExamPrepCatalogCourse) { unit.EffectiveAccessTier = domain.EffectiveContentAccessTier(catalogCourse.AccessTier, unit.AccessTier) } func applyExamPrepModuleEffectiveAccessTier(module *domain.ExamPrepModule, catalogCourse domain.ExamPrepCatalogCourse, unit domain.ExamPrepUnit) { module.EffectiveAccessTier = domain.EffectiveContentAccessTier(catalogCourse.AccessTier, unit.AccessTier, module.AccessTier) } func applyExamPrepLessonEffectiveAccessTier(lesson *domain.ExamPrepLesson, catalogCourse domain.ExamPrepCatalogCourse, unit domain.ExamPrepUnit, module domain.ExamPrepModule) { lesson.EffectiveAccessTier = domain.EffectiveContentAccessTier(catalogCourse.AccessTier, unit.AccessTier, module.AccessTier, lesson.AccessTier) } func annotateProgramsEffectiveAccessTier(items []domain.Program) { for i := range items { applyProgramEffectiveAccessTier(&items[i]) } } func annotateCoursesEffectiveAccessTier(items []domain.Course, program domain.Program) { for i := range items { applyCourseEffectiveAccessTier(&items[i], program) } } func annotateExamPrepCatalogCoursesEffectiveAccessTier(items []domain.ExamPrepCatalogCourse) { for i := range items { applyExamPrepCatalogCourseEffectiveAccessTier(&items[i]) } } func (h *Handler) annotateLMSModulesEffectiveAccessTier(ctx context.Context, courseID int64, items []domain.Module) error { course, err := h.courseSvc.GetByID(ctx, courseID) if err != nil { return err } program, err := h.programSvc.GetByID(ctx, course.ProgramID) if err != nil { return err } for i := range items { applyModuleEffectiveAccessTier(&items[i], program, course) } return nil } func (h *Handler) annotateLMSModuleEffectiveAccessTier(ctx context.Context, module *domain.Module) error { course, err := h.courseSvc.GetByID(ctx, module.CourseID) if err != nil { return err } program, err := h.programSvc.GetByID(ctx, course.ProgramID) if err != nil { return err } applyModuleEffectiveAccessTier(module, program, course) return nil } func (h *Handler) annotateLMSLessonsEffectiveAccessTier(ctx context.Context, moduleID int64, items []domain.Lesson) error { module, err := h.moduleSvc.GetByID(ctx, moduleID) if err != nil { return err } course, err := h.courseSvc.GetByID(ctx, module.CourseID) if err != nil { return err } program, err := h.programSvc.GetByID(ctx, course.ProgramID) if err != nil { return err } for i := range items { applyLessonEffectiveAccessTier(&items[i], program, course, module) } return nil } func (h *Handler) annotateLMSLessonEffectiveAccessTier(ctx context.Context, lesson *domain.Lesson) error { module, err := h.moduleSvc.GetByID(ctx, lesson.ModuleID) if err != nil { return err } course, err := h.courseSvc.GetByID(ctx, module.CourseID) if err != nil { return err } program, err := h.programSvc.GetByID(ctx, course.ProgramID) if err != nil { return err } applyLessonEffectiveAccessTier(lesson, program, course, module) return nil } func (h *Handler) annotateExamPrepUnitsEffectiveAccessTier(ctx context.Context, catalogCourseID int64, items []domain.ExamPrepUnit) error { cc, err := h.examPrepSvc.GetCatalogCourseByID(ctx, catalogCourseID) if err != nil { return err } for i := range items { applyExamPrepUnitEffectiveAccessTier(&items[i], cc) } return nil } func (h *Handler) annotateExamPrepUnitEffectiveAccessTier(ctx context.Context, unit *domain.ExamPrepUnit) error { cc, err := h.examPrepSvc.GetCatalogCourseByID(ctx, unit.CatalogCourseID) if err != nil { return err } applyExamPrepUnitEffectiveAccessTier(unit, cc) return nil } func (h *Handler) annotateExamPrepModulesEffectiveAccessTier(ctx context.Context, unitID int64, items []domain.ExamPrepModule) error { unit, err := h.examPrepSvc.GetUnitByID(ctx, unitID) if err != nil { return err } cc, err := h.examPrepSvc.GetCatalogCourseByID(ctx, unit.CatalogCourseID) if err != nil { return err } for i := range items { applyExamPrepModuleEffectiveAccessTier(&items[i], cc, unit) } return nil } func (h *Handler) annotateExamPrepModuleEffectiveAccessTier(ctx context.Context, module *domain.ExamPrepModule) error { unit, err := h.examPrepSvc.GetUnitByID(ctx, module.UnitID) if err != nil { return err } cc, err := h.examPrepSvc.GetCatalogCourseByID(ctx, unit.CatalogCourseID) if err != nil { return err } applyExamPrepModuleEffectiveAccessTier(module, cc, unit) return nil } func (h *Handler) annotateExamPrepLessonsEffectiveAccessTier(ctx context.Context, moduleID int64, items []domain.ExamPrepLesson) error { module, err := h.examPrepSvc.GetModuleByID(ctx, moduleID) if err != nil { return err } unit, err := h.examPrepSvc.GetUnitByID(ctx, module.UnitID) if err != nil { return err } cc, err := h.examPrepSvc.GetCatalogCourseByID(ctx, unit.CatalogCourseID) if err != nil { return err } for i := range items { applyExamPrepLessonEffectiveAccessTier(&items[i], cc, unit, module) } return nil } func (h *Handler) annotateExamPrepLessonEffectiveAccessTier(ctx context.Context, lesson *domain.ExamPrepLesson) error { module, err := h.examPrepSvc.GetModuleByID(ctx, lesson.UnitModuleID) if err != nil { return err } unit, err := h.examPrepSvc.GetUnitByID(ctx, module.UnitID) if err != nil { return err } cc, err := h.examPrepSvc.GetCatalogCourseByID(ctx, unit.CatalogCourseID) if err != nil { return err } applyExamPrepLessonEffectiveAccessTier(lesson, cc, unit, module) return nil } func mapLMSEffectiveAccessTierError(err error) (int, string) { switch { case err == nil: return 0, "" case err == programs.ErrProgramNotFound, err == courses.ErrCourseNotFound, err == modules.ErrModuleNotFound: return 404, "Not found" default: return 500, "Failed to build content access metadata" } } func mapExamPrepEffectiveAccessTierError(err error) (int, string) { switch { case err == nil: return 0, "" case err == examprep.ErrCatalogCourseNotFound, err == examprep.ErrUnitNotFound, err == examprep.ErrModuleNotFound, err == examprep.ErrLessonNotFound: return 404, "Not found" default: return 500, "Failed to build content access metadata" } }