feat: add account subscription authorization

This commit is contained in:
QiuSW
2026-07-21 16:38:52 +08:00
parent 64a3dfec1d
commit d9230b9688
11 changed files with 245 additions and 15 deletions
+31 -8
View File
@@ -77,9 +77,10 @@ from apps.licensing.services import (
SoftwareOrderPayMethodMismatchError,
apply_software_payment,
create_migration_request,
evaluate_device_authorization,
expire_software_order,
query_and_apply_software_payment,
evaluate_account_authorization,
software_subscription_status,
record_device_heartbeat,
register_device,
resolve_optional_device_session,
@@ -394,22 +395,26 @@ class CmshopeeShadowAuthorizationMixin:
product_code = "cmshopee"
def optional_client_device(self, request):
device = super().optional_client_device(request)
decision = evaluate_device_authorization(
try:
device = super().optional_client_device(request)
except ApiRequestError:
# A stale device session must not block an account-based subscription.
request.device_session_present = bool(
request.headers.get("X-Device-Session", "").strip()
)
device = None
decision = evaluate_account_authorization(
user=request.user,
product_code=self.product_code,
device=device,
raw_credential_token=request.headers.get("X-Device-Credential", ""),
)
event = {
"event": "cmshopee_authorization_shadow",
"event": "cmshopee_subscription_authorization",
"product_code": self.product_code,
"user_id": request.user.id,
"client_device_id": getattr(device, "id", None),
"credential_id": decision.credential_id,
"would_reject": decision.would_reject,
"would_reject_code": decision.code,
"shadow_mode": settings.CMSHOPEE_AUTHORIZATION_SHADOW_MODE,
"enforcement": settings.CMSHOPEE_SUBSCRIPTION_ENFORCEMENT,
}
authorization_logger.info(
"%s %s",
@@ -417,6 +422,13 @@ class CmshopeeShadowAuthorizationMixin:
event,
extra={"cmshopee_authorization": event},
)
if settings.CMSHOPEE_SUBSCRIPTION_ENFORCEMENT and decision.would_reject:
message = (
"当前账号没有有效的软件订阅"
if decision.code == "subscription_required"
else "软件订阅已到期,请先续订"
)
raise ApiRequestError(decision.code, message, status.HTTP_403_FORBIDDEN)
request.cmshopee_authorization = decision
return device
@@ -440,6 +452,17 @@ class CmshopeeGenerateImageTaskDetailView(GenerateImageTaskDetailView):
pass
class CmshopeeSubscriptionStatusView(ExternalApiView):
def get(self, request):
return Response(
software_subscription_status(
user=request.user,
product_code="cmshopee",
),
status=status.HTTP_200_OK,
)
class BalanceView(ExternalApiView):
def get(self, request):
balance = get_balance_snapshot(request.user)