diff --git a/cmd/main.go b/cmd/main.go index 9c0ce32..0f31aae 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -133,33 +133,6 @@ func main() { ) authSvc.InitGoogleOAuth(cfg.GoogleOAuthClientID, cfg.GoogleOAuthClientSecret, cfg.GoogleOAuthRedirectURL) - // leagueSvc := league.New(repository.NewLeagueStore(store)) - // eventSvc := event.New( - // cfg.Bet365Token, - // repository.NewEventStore(store), - // repository.NewEventHistoryStore(store), - // *leagueSvc, - // settingSvc, - // domain.MongoDBLogger, - // cfg, - // ) - - // marketSettingRepo := repository.NewMarketSettingStore(store) - - // if err := marketSettingRepo.EnsureAllMarketSettingsExist(context.Background()); err != nil { - // log.Fatalf("failed to ensure market settings: %v", err) - // } - - // oddsSvc := odds.New( - // repository.NewOddStore(store), - // marketSettingRepo, - // cfg, - // eventSvc, - // logger, - // domain.MongoDBLogger, - // ) - - // virtuaGamesRepo := repository.NewVirtualGameRepository(store) // Initialize producer // topic := "wallet-balance-topic" @@ -174,85 +147,8 @@ func main() { userSvc, ) - // / := wallet.NewService( - // repository.NewWalletStore(store), - // repository.NewTransferStore(store), - // // repository.NewDirectDepositStore(store), - // notificationSvc, - // userSvc, - // domain.MongoDBLogger, - // logger, - // ) - - // branchSvc := branch.NewService(repository.NewBranchStore(store)) - // companySvc := company.NewService(repository.NewCompanyStore(store)) - - // ticketSvc := ticke.NewService( - // repository.NewTicketStore(store), - // // eventSvc, - // // *oddsSvc, - // domain.MongoDBLogger, - // settingSvc, - // ) - // betSvc := bet.NewService( - // repository.NewBetStore(store), - // eventSvc, - // *oddsSvc, - // , - // *branchSvc, - // *companySvc, - // *settingSvc, - // *userSvc, - // notificationSvc, - // logger, - // domain.MongoDBLogger, - // ) - - // resultSvc := result.NewService( - // repository.NewResultLogStore(store), - // cfg, - // logger, - // domain.MongoDBLogger, - // // *betSvc, - // // *oddsSvc, - // // eventSvc, - // // leagueSvc, - // notificationSvc, - // messengerSvc, - // *userSvc, - // ) - - // bonusSvc := bonus.NewService( - // repository.NewBonusStore(store), - // settingSvc, - // notificationSvc, - // domain.MongoDBLogger, - // ) - // virtualGamesRepo := repository.NewVirtualGameRepository(store) recommendationRepo := repository.NewRecommendationRepository(store) - // referalSvc := referralservice.New( - // repository.NewReferralStore(store), - // *settingSvc, - // cfg, - // logger, - // domain.MongoDBLogger, - // ) - // raffleSvc := raffle.NewService( - // repository.NewRaffleStore(store), - // ) - // virtualGameSvc := virtualgameservice.New(virtualGamesRepo,, store, cfg, logger) - // aleaService := alea.NewAleaPlayService(virtualGamesRepo,, cfg, logger) - // veliCLient := veli.NewClient(cfg) - // veliVirtualGameService := veli.New(virtualGameSvc, virtualGamesRepo, *store, veliCLient, repository.NewTransferStore(store), domain.MongoDBLogger, cfg) - // orchestrationSvc := orchestration.New( - // virtualGameSvc, - // virtualGamesRepo, - // cfg, - // veliCLient, - // ) - // atlasClient := atlas.NewClient(cfg) - // atlasVirtualGameService := atlas.New(virtualGameSvc, virtualGamesRepo, atlasClient, repository.NewTransferStore(store), cfg) recommendationSvc := recommendation.NewService(recommendationRepo) // chapaClient := chapa.NewClient(cfg.CHAPA_BASE_URL, cfg.CHAPA_SECRET_KEY) @@ -291,15 +187,6 @@ func main() { // cfg, // ) - // enePulseSvc := enetpulse.New( - // *cfg, - // store, - // ) - - // go httpserver.StartEnetPulseCron(enePulseSvc, domain.MongoDBLogger) - // go httpserver.SetupReportandVirtualGameCronJobs(context.Background(), reportSvc, orchestrationSvc, "C:/Users/User/Desktop") - // go httpserver.ProcessBetCashback(context.TODO(), betSvc) - // bankRepository := repository.NewBankRepository(store) // instSvc := institutions.New(bankRepository) // Initialize report worker with CSV exporter @@ -320,11 +207,6 @@ func main() { // userSvc, // ) - // enetPulseSvc := enetpulse.New( - // *cfg, - // store, - // ) - // Initialize wallet monitoring service // walletMonitorSvc := monitor.NewService( // , @@ -454,11 +336,6 @@ func main() { cfg.TeamInviteExpiry, ) - // santimpayClient := santimpay.NewSantimPayClient(cfg) - - // santimpaySvc := santimpay.NewSantimPayService(santimpayClient, cfg, transferStore) - // telebirrSvc := telebirr.NewTelebirrService(cfg, transferStore) - // Activity Log service activityLogSvc := activitylogservice.NewService(store, domain.MongoDBLogger) diff --git a/internal/domain/role.go b/internal/domain/role.go index cc3dd6a..019d7d7 100644 --- a/internal/domain/role.go +++ b/internal/domain/role.go @@ -26,6 +26,11 @@ func (r Role) UsesLMSSequentialGating() bool { return r == RoleStudent } +// RequiresSubscription is true when paid subscription is required to access learning content. +func (r Role) RequiresSubscription() bool { + return r == RoleStudent +} + // IsCustomerLearnerRole is true for platform roles that sign in as customers and consume learner-facing LMS APIs. func (r Role) IsCustomerLearnerRole() bool { return r == RoleStudent || r == RoleOpenLearner diff --git a/internal/web_server/handlers/exam_prep_catalog_course_handler.go b/internal/web_server/handlers/exam_prep_catalog_course_handler.go index 38a8147..ca4bd8d 100644 --- a/internal/web_server/handlers/exam_prep_catalog_course_handler.go +++ b/internal/web_server/handlers/exam_prep_catalog_course_handler.go @@ -61,7 +61,7 @@ func (h *Handler) ListExamPrepCatalogCourses(c *fiber.Ctx) error { offset, _ := strconv.Atoi(c.Query("offset", "0")) role, _ := c.Locals("role").(domain.Role) - if role == domain.RoleStudent || role == domain.RoleOpenLearner { + if role.RequiresSubscription() { userID, ok := c.Locals("user_id").(int64) if !ok || userID == 0 { return c.Status(fiber.StatusUnauthorized).JSON(domain.ErrorResponse{ diff --git a/internal/web_server/middleware.go b/internal/web_server/middleware.go index 0e2d303..a8f4e39 100644 --- a/internal/web_server/middleware.go +++ b/internal/web_server/middleware.go @@ -15,8 +15,6 @@ import ( "go.uber.org/zap" ) -var categorySubscriptionGateDisabled = true - func (a *App) authMiddleware(c *fiber.Ctx) error { ip := c.IP() userAgent := c.Get("User-Agent") @@ -176,8 +174,8 @@ func (a *App) OnlyAdminAndAbove(c *fiber.Ctx) error { return c.Next() } -// RequireActiveSubscription enforces an active subscription for learner accounts. -// Staff roles (SUPER_ADMIN, ADMIN, INSTRUCTOR, SUPPORT) bypass this check. +// RequireActiveSubscription enforces an active subscription for STUDENT accounts. +// Staff roles and OPEN_LEARNER bypass this check. // Use after authMiddleware on routes that deliver paid learning content. func (a *App) RequireActiveSubscription() fiber.Handler { return func(c *fiber.Ctx) error { @@ -185,33 +183,27 @@ func (a *App) RequireActiveSubscription() fiber.Handler { if !ok { return fiber.NewError(fiber.StatusForbidden, "Role not found in context") } - switch role { - case domain.RoleSuperAdmin, domain.RoleAdmin, domain.RoleInstructor, domain.RoleSupport: - return c.Next() - case domain.RoleStudent, domain.RoleOpenLearner: - userID, ok := c.Locals("user_id").(int64) - if !ok || userID == 0 { - return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized") - } - active, err := a.subscriptionsSvc.HasActiveSubscription(c.Context(), userID) - if err != nil { - a.mongoLoggerSvc.Error("subscription check failed", - zap.Int64("userID", userID), - zap.String("path", c.Path()), - zap.Error(err), - zap.Time("timestamp", time.Now()), - ) - return fiber.NewError(fiber.StatusInternalServerError, "Failed to verify subscription") - } - if !active { - // Temporary bypass: allow unsubscribed learners to access content. - // Re-enable the previous 403 response when subscription gating is turned back on. - return c.Next() - } - return c.Next() - default: + if bypassSubscriptionForRole(role) || !role.RequiresSubscription() { return c.Next() } + userID, ok := c.Locals("user_id").(int64) + if !ok || userID == 0 { + return fiber.NewError(fiber.StatusUnauthorized, "Unauthorized") + } + active, err := a.subscriptionsSvc.HasActiveSubscription(c.Context(), userID) + if err != nil { + a.mongoLoggerSvc.Error("subscription check failed", + zap.Int64("userID", userID), + zap.String("path", c.Path()), + zap.Error(err), + zap.Time("timestamp", time.Now()), + ) + return fiber.NewError(fiber.StatusInternalServerError, "Failed to verify subscription") + } + if !active { + return fiber.NewError(fiber.StatusForbidden, "An active subscription is required") + } + return c.Next() } } @@ -221,14 +213,7 @@ func (a *App) RequireSubscriptionCategory(category domain.SubscriptionCategory) if err != nil { return err } - if bypassSubscriptionForRole(role) { - return c.Next() - } - if role != domain.RoleStudent && role != domain.RoleOpenLearner { - return c.Next() - } - if categorySubscriptionGateDisabled { - // Temporary bypass to disable category-aware learner access checks without changing route wiring. + if bypassSubscriptionForRole(role) || !role.RequiresSubscription() { return c.Next() } active, err := a.subscriptionsSvc.HasActiveSubscriptionByCategory(c.Context(), userID, category) @@ -255,14 +240,7 @@ func (a *App) RequireExamPrepSubscription() fiber.Handler { if err != nil { return err } - if bypassSubscriptionForRole(role) { - return c.Next() - } - if role != domain.RoleStudent && role != domain.RoleOpenLearner { - return c.Next() - } - if categorySubscriptionGateDisabled { - // Temporary bypass to disable category-aware learner access checks without changing route wiring. + if bypassSubscriptionForRole(role) || !role.RequiresSubscription() { return c.Next() }