## Summary - Closes [#34](#34) - Companion for [chat_web_app#75](ai_ml_operations/chat_web_app#75) (portal cancel/change local sync) - Soft-delete `DELETE /api/user/` for the authenticated user only: `deleted=True`, `is_active=False`, hide conversations, blacklist outstanding refresh tokens; staff self-delete rejected - Stripe `customer.subscription.updated` / `deleted` webhooks sync plan status, `cancel_at_period_end`, and `current_period_end`; checkout assigns plan from `metadata.plan_slug` - **UserAuthEvent audit**: `account_deleted`, `subscription_started` (first active plan), `subscription_updated` (plan/status/cancel changes) — visible on user admin - Document FE contract in README (endpoint, response, post-delete logout) ## Test plan - [ ] `uv run python manage.py test chat_backend.tests.test_views_users.CustomUserSelfDeleteTestCase finance.tests` - [ ] Authenticated `DELETE /api/user/` soft-deletes self, hides conversations, blocks re-login, writes `account_deleted` auth event - [ ] Checkout / Backer assign writes `subscription_started`; portal cancel/change writes `subscription_updated` - [ ] Anonymous / staff self-delete rejected; body cannot target another user - [ ] After portal cancel, webhook sets `cancel_at_period_end` / `canceled` on `GET /finance/subscription/`Reviewed-on: #39
This commit was merged in pull request #39.
This commit is contained in:
1 parent
cc45ae5808
commit
eedc842b08
14 files changed
+740
-10
No files matched your search
@@ -26,6 +26,17 @@ class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
|
||||
|
||||
return token
|
||||
|
||||
def validate(self, attrs):
|
||||
data = super().validate(attrs)
|
||||
if getattr(self.user, "deleted", False):
|
||||
from rest_framework_simplejwt.exceptions import AuthenticationFailed
|
||||
|
||||
raise AuthenticationFailed(
|
||||
"No active account found with the given credentials",
|
||||
code="no_active_account",
|
||||
)
|
||||
return data
|
||||
|
||||
|
||||
class CompanySerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
@@ -70,12 +81,18 @@ class CustomUserSerializer(serializers.ModelSerializer):
|
||||
"status": UserSubscription.Status.NONE,
|
||||
"source": UserSubscription.Source.NONE,
|
||||
"needs_checkout": True,
|
||||
"cancel_at_period_end": False,
|
||||
"current_period_end": None,
|
||||
}
|
||||
return {
|
||||
"plan": plan_to_dict(sub.plan) if sub.plan_id else None,
|
||||
"status": sub.status,
|
||||
"source": sub.source,
|
||||
"needs_checkout": needs_checkout(obj),
|
||||
"cancel_at_period_end": bool(sub.cancel_at_period_end),
|
||||
"current_period_end": (
|
||||
sub.current_period_end.isoformat() if sub.current_period_end else None
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user