feat: add account subscription authorization
This commit is contained in:
@@ -86,6 +86,18 @@ class AuthorizationDecision:
|
||||
return not self.allowed
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class SubscriptionAuthorizationDecision:
|
||||
product_code: str
|
||||
allowed: bool
|
||||
code: str
|
||||
entitlement: SoftwareEntitlement | None = None
|
||||
|
||||
@property
|
||||
def would_reject(self) -> bool:
|
||||
return not self.allowed
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class DeviceRegistrationResult:
|
||||
device: ClientDevice
|
||||
@@ -911,3 +923,74 @@ def evaluate_device_authorization(*, user, product_code: str, device=None, raw_c
|
||||
if not credential.is_active_at(now) or not credential.entitlement.is_usable_at(now):
|
||||
return AuthorizationDecision(product_code, False, "license_expired", credential.id)
|
||||
return AuthorizationDecision(product_code, True, "", credential.id)
|
||||
|
||||
|
||||
def evaluate_account_authorization(*, user, product_code: str, now=None):
|
||||
"""Authorize a product by account entitlement, without device or credential checks."""
|
||||
now = now or timezone.now()
|
||||
usable_entitlement = (
|
||||
SoftwareEntitlement.objects.filter(
|
||||
user=user,
|
||||
product_code=product_code,
|
||||
status=SoftwareEntitlement.Status.ACTIVE,
|
||||
starts_at__lte=now,
|
||||
grace_expires_at__gt=now,
|
||||
)
|
||||
.order_by("-expires_at", "-id")
|
||||
.first()
|
||||
)
|
||||
if usable_entitlement is not None:
|
||||
return SubscriptionAuthorizationDecision(
|
||||
product_code=product_code,
|
||||
allowed=True,
|
||||
code="",
|
||||
entitlement=usable_entitlement,
|
||||
)
|
||||
|
||||
historical_entitlement = (
|
||||
SoftwareEntitlement.objects.filter(
|
||||
user=user,
|
||||
product_code=product_code,
|
||||
)
|
||||
.exclude(status=SoftwareEntitlement.Status.REVOKED)
|
||||
.order_by("-grace_expires_at", "-id")
|
||||
.first()
|
||||
)
|
||||
if historical_entitlement is not None:
|
||||
return SubscriptionAuthorizationDecision(
|
||||
product_code=product_code,
|
||||
allowed=False,
|
||||
code="subscription_expired",
|
||||
entitlement=historical_entitlement,
|
||||
)
|
||||
return SubscriptionAuthorizationDecision(
|
||||
product_code=product_code,
|
||||
allowed=False,
|
||||
code="subscription_required",
|
||||
)
|
||||
|
||||
|
||||
def software_subscription_status(*, user, product_code: str, now=None) -> dict:
|
||||
decision = evaluate_account_authorization(
|
||||
user=user,
|
||||
product_code=product_code,
|
||||
now=now,
|
||||
)
|
||||
entitlement = decision.entitlement
|
||||
return {
|
||||
"product_code": product_code,
|
||||
"status": (
|
||||
"active"
|
||||
if decision.allowed
|
||||
else ("expired" if decision.code == "subscription_expired" else "required")
|
||||
),
|
||||
"allowed": decision.allowed,
|
||||
"code": decision.code or None,
|
||||
"plan": {
|
||||
"name": entitlement.plan_name,
|
||||
"expires_at": entitlement.expires_at.isoformat(),
|
||||
"grace_expires_at": entitlement.grace_expires_at.isoformat(),
|
||||
}
|
||||
if entitlement is not None
|
||||
else None,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user