Files
geo/server/internal/tenant/transport/subscription_guard.go
T
root 63667ed2d1 feat(membership): enforce tenant subscription plans with blocked UI
Add configurable membership plans (free/plus/pro) synced to DB on boot, a
subscription guard middleware that blocks tenant endpoints on expired or
missing plans, and a MembershipBlockedView that surfaces the reason so
the admin can contact the tenant owner. Quota and brand-library reads now
honor the active plan's policy JSON and expired subscriptions.
2026-04-18 20:56:05 +08:00

64 lines
1.6 KiB
Go

package transport
import (
"time"
"github.com/gin-gonic/gin"
"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) 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
}
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()
}
}