Yimaru-BackEnd/internal/web_server/handlers/content_access_gate.go
2026-06-11 01:14:04 -07:00

256 lines
8.0 KiB
Go

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"
}
}