diff options
Diffstat (limited to 'Biz/PodcastItLater/Web.py')
| -rw-r--r-- | Biz/PodcastItLater/Web.py | 85 |
1 files changed, 85 insertions, 0 deletions
diff --git a/Biz/PodcastItLater/Web.py b/Biz/PodcastItLater/Web.py index 7e8e969..903af17 100644 --- a/Biz/PodcastItLater/Web.py +++ b/Biz/PodcastItLater/Web.py @@ -1314,12 +1314,54 @@ def account_page(request: Request) -> UI.PageLayout | RedirectResponse: ), classes=["card", "mb-4"], ), + html.div( + html.h4( + html.i(classes=["bi", "bi-exclamation-triangle-fill", "me-2"]), + "Danger Zone", + classes=["card-header", "bg-transparent", "text-danger"], + ), + html.div( + html.p( + "Once you delete your account, there is no going back. " + "Please be certain.", + classes=["card-text"], + ), + html.button( + html.i(classes=["bi", "bi-trash", "me-2"]), + "Delete Account", + hx_delete="/account", + hx_confirm=( + "Are you absolutely sure you want to delete " + "your account? This action cannot be undone." + ), + classes=["btn", "btn-outline-danger"], + ), + classes=["card-body"], + ), + classes=["card", "border-danger", "mb-4"], + ), user=user, current_page="account", error=None, ) +@app.delete("/account") +def delete_account(request: Request) -> Response: + """Delete user account.""" + user_id = request.session.get("user_id") + if not user_id: + return RedirectResponse(url="/?error=login_required") + + Core.Database.delete_user(user_id) + request.session.clear() + + return Response( + "Account deleted", + headers={"HX-Redirect": "/?message=account_deleted"}, + ) + + @app.get("/logout") def logout(request: Request) -> Response: """Handle logout.""" @@ -3164,6 +3206,48 @@ class TestUsageLimits(BaseWebTest): self.assertEqual(usage["articles"], 20) +class TestAccountDeletion(BaseWebTest): + """Test account deletion functionality.""" + + def setUp(self) -> None: + """Set up test user.""" + super().setUp() + self.user_id, _ = Core.Database.create_user("delete@example.com") + Core.Database.update_user_status(self.user_id, "active") + self.client.post("/login", data={"email": "delete@example.com"}) + + def test_delete_account(self) -> None: + """User can delete their own account.""" + # Create some data + Core.Database.add_to_queue( + "https://example.com", + "delete@example.com", + self.user_id, + ) + + # Delete account + response = self.client.delete("/account") + + self.assertEqual(response.status_code, 200) + self.assertIn("Account deleted", response.text) + self.assertIn("HX-Redirect", response.headers) + + # Verify user is gone + user = Core.Database.get_user_by_id(self.user_id) + self.assertIsNone(user) + + # Verify session is cleared + response = self.client.get("/") + self.assertNotIn("Logged in as", response.text) + + def test_delete_requires_auth(self) -> None: + """Cannot delete account without login.""" + self.client.get("/logout") + response = self.client.delete("/account") + + self.assertIn("/?error=login_required", response.headers["location"]) + + def test() -> None: """Run all tests for the web module.""" Test.run( @@ -3180,6 +3264,7 @@ def test() -> None: TestEpisodeDeduplication, TestMetricsTracking, TestUsageLimits, + TestAccountDeletion, ], ) |
