Permanently deletes the authenticated user's account. This will: 1. Cancel any active Stripe subscription 2. Delete all marketplace agents created by the user 3. Delete the Auth0 user account This action is irreversible.
(current_user: AuthUser)
| 147 | |
| 148 | @app.delete("/delete-account", summary="Permanently delete user account") |
| 149 | async def delete_account(current_user: AuthUser): |
| 150 | """ |
| 151 | Permanently deletes the authenticated user's account. |
| 152 | This will: |
| 153 | 1. Cancel any active Stripe subscription |
| 154 | 2. Delete all marketplace agents created by the user |
| 155 | 3. Delete the Auth0 user account |
| 156 | |
| 157 | This action is irreversible. |
| 158 | """ |
| 159 | user_id = current_user.id |
| 160 | logger.info(f"Account deletion requested for user: {user_id}") |
| 161 | |
| 162 | # 1. Cancel Stripe subscription if exists |
| 163 | stripe_customer_id = None |
| 164 | if hasattr(current_user, 'app_metadata') and isinstance(current_user.app_metadata, dict): |
| 165 | stripe_customer_id = current_user.app_metadata.get("stripe_customer_id") |
| 166 | |
| 167 | email = (getattr(current_user, 'email', None) or '').lower() |
| 168 | if email: |
| 169 | email_hash = hashlib.sha256(email.encode()).hexdigest() |
| 170 | ghost_email = f"{email_hash}@deleted.invalid" |
| 171 | try: |
| 172 | all_customers = stripe.Customer.list(email=email, limit=100) |
| 173 | for cust in all_customers.data: |
| 174 | # Cancel active subscriptions |
| 175 | subscriptions = stripe.Subscription.list(customer=cust.id, status='all', limit=100) |
| 176 | for sub in subscriptions.data: |
| 177 | if sub.status in ('active', 'trialing'): |
| 178 | stripe.Subscription.cancel(sub.id) |
| 179 | logger.info(f"Cancelled Stripe subscription {sub.id} for user {user_id}") |
| 180 | |
| 181 | # Detach all payment methods |
| 182 | payment_methods = stripe.PaymentMethod.list(customer=cust.id, type="card") |
| 183 | for pm in payment_methods.data: |
| 184 | stripe.PaymentMethod.detach(pm.id) |
| 185 | |
| 186 | # Replace email with hash, wipe all other PII |
| 187 | stripe.Customer.modify( |
| 188 | cust.id, |
| 189 | email=ghost_email, |
| 190 | name="", |
| 191 | phone="", |
| 192 | address={}, |
| 193 | metadata={"deleted": "true"} |
| 194 | ) |
| 195 | logger.info(f"Redacted Stripe customer {cust.id} for user {user_id}") |
| 196 | except Exception as e: |
| 197 | logger.error(f"Failed to process Stripe data for user {user_id}: {e}") |
| 198 | # Continue with deletion even if Stripe fails |
| 199 | elif stripe_customer_id: |
| 200 | # Fallback: no email available, cancel by customer ID only |
| 201 | try: |
| 202 | subscriptions = stripe.Subscription.list(customer=stripe_customer_id, status='all', limit=100) |
| 203 | for sub in subscriptions.data: |
| 204 | if sub.status in ('active', 'trialing'): |
| 205 | stripe.Subscription.cancel(sub.id) |
| 206 | logger.info(f"Cancelled Stripe subscription {sub.id} for user {user_id}") |
nothing calls this directly
no test coverage detected