summaryrefslogtreecommitdiff
path: root/Biz/PodcastItLater/Web.py
diff options
context:
space:
mode:
Diffstat (limited to 'Biz/PodcastItLater/Web.py')
-rw-r--r--Biz/PodcastItLater/Web.py85
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,
],
)