package transport import ( "errors" "strings" "time" "github.com/gin-gonic/gin" "github.com/jackc/pgx/v5" "github.com/geo-platform/tenant-api/internal/shared/auth" "github.com/geo-platform/tenant-api/internal/shared/response" "github.com/geo-platform/tenant-api/internal/tenant/repository" ) func RequireActiveTenantSubscription( plans repository.TenantPlanRepository, authRepos ...repository.AuthRepository, ) gin.HandlerFunc { return func(c *gin.Context) { actor, ok := auth.ActorFromCtx(c.Request.Context()) if !ok { response.Error(c, response.ErrUnauthorized(40100, "not_authenticated", "not authenticated")) c.Abort() return } if len(authRepos) > 0 && authRepos[0] != nil { user, err := authRepos[0].GetUserByID(c.Request.Context(), actor.UserID) if err != nil { if errors.Is(err, pgx.ErrNoRows) { response.Error(c, response.ErrNotFound(40401, "user_not_found", "user not found")) } else { response.Error(c, response.ErrInternal(50092, "user_lookup_failed", "failed to load user")) } c.Abort() return } if !strings.EqualFold(strings.TrimSpace(user.Status), "active") { response.Error(c, response.ErrForbidden( 40311, "user_disabled", "user account is disabled, please contact support", )) c.Abort() return } } now := time.Now().UTC() access, err := plans.GetTenantPlanAccess(c.Request.Context(), actor.TenantID, now) if err != nil { response.Error(c, response.ErrInternal(50091, "subscription_lookup_failed", "failed to load tenant subscription")) c.Abort() return } if access != nil && access.HasActiveAccess(now) { c.Next() return } reason := "" if access != nil { reason = access.BlockedReason(now) } else { reason = "subscription_required" } switch reason { case "trial_plan_expired": response.Error(c, response.ErrForbidden( 40382, "trial_plan_expired", "free trial has expired, please contact administrator to reactivate access", )) case "subscription_required": response.Error(c, response.ErrForbidden( 40381, "subscription_required", "subscription is required, please contact administrator", )) default: response.Error(c, response.ErrForbidden( 40383, "subscription_inactive", "subscription is inactive, please contact administrator", )) } c.Abort() } }