feat: enhance limits

This commit is contained in:
Krispire Admin
2026-06-23 14:21:45 +05:30
parent eadef33eac
commit 96ebbfd719
12 changed files with 183 additions and 53 deletions
+23 -47
View File
@@ -3,19 +3,16 @@ package service
import (
"errors"
"fmt"
"github.com/prabhupadasays/spsays-bff/internal/model"
)
// Plan caps for the social features. Updates here propagate everywhere via
// EnforceBookmarkLimit / EnforceCollectionLimit.
// Plan identifiers. The numeric caps live in model.ResolveLimits (so the self
// user payload and these enforcers agree), and per-user admin overrides take
// precedence over the plan default.
const (
PlanFree = "free"
PlanPremium = "premium"
freeBookmarkLimit = 1
premiumBookmarkLimit = 5
freeCollectionPerVisibilityLimit = 5 // 5 public AND 5 private separately
// Premium has no collection cap.
)
// ErrPlanLimit signals that a free-plan limit blocks the requested action.
@@ -38,50 +35,29 @@ func (e *PlanLimitError) Error() string {
func (e *PlanLimitError) Is(target error) bool { return target == ErrPlanLimit }
// EnforceBookmarkLimit returns nil if the user is allowed to create one more
// bookmark, or a PlanLimitError otherwise.
func EnforceBookmarkLimit(plan string, currentCount int) error {
limit := bookmarkLimitFor(plan)
if currentCount >= limit {
return &PlanLimitError{Resource: "bookmarks", Limit: limit, Plan: plan}
// bookmark, or a PlanLimitError otherwise. The cap is the user's effective
// bookmark limit (plan default, or an admin override). A negative cap means
// unlimited.
func EnforceBookmarkLimit(u *model.User, currentCount int) error {
limit := u.EffectiveLimits().Bookmarks
if limit >= 0 && currentCount >= limit {
return &PlanLimitError{Resource: "bookmarks", Limit: limit, Plan: u.Plan}
}
return nil
}
// EnforceCollectionLimit returns nil if the user is allowed to create one
// more collection of the given visibility.
//
// `isPublic=true` → checks against public-collection cap
// `isPublic=false` → checks against private-collection cap
// Premium users have no cap → always nil.
func EnforceCollectionLimit(plan string, isPublic bool, currentCount int) error {
if plan == PlanPremium {
return nil
// EnforceCollectionLimit returns nil if the user is allowed to create one more
// collection of the given visibility. The cap is the user's effective
// public/private collection limit (plan default, or an admin override); a
// negative cap means unlimited.
func EnforceCollectionLimit(u *model.User, isPublic bool, currentCount int) error {
l := u.EffectiveLimits()
limit, resource := l.PrivateCollections, "private collections"
if isPublic {
limit, resource = l.PublicCollections, "public collections"
}
limit := freeCollectionPerVisibilityLimit
if currentCount >= limit {
resource := "private collections"
if isPublic {
resource = "public collections"
}
return &PlanLimitError{Resource: resource, Limit: limit, Plan: plan}
if limit >= 0 && currentCount >= limit {
return &PlanLimitError{Resource: resource, Limit: limit, Plan: u.Plan}
}
return nil
}
func bookmarkLimitFor(plan string) int {
if plan == PlanPremium {
return premiumBookmarkLimit
}
return freeBookmarkLimit
}
// BookmarkLimitFor returns the cap (for showing "X / Y used" in the UI).
func BookmarkLimitFor(plan string) int { return bookmarkLimitFor(plan) }
// CollectionLimitFor returns the per-visibility cap. -1 means unlimited.
func CollectionLimitFor(plan string) int {
if plan == PlanPremium {
return -1
}
return freeCollectionPerVisibilityLimit
}