diff --git a/hc/accounts/tests/test_close_account.py b/hc/accounts/tests/test_close_account.py index e83fb827..3306f068 100644 --- a/hc/accounts/tests/test_close_account.py +++ b/hc/accounts/tests/test_close_account.py @@ -7,6 +7,21 @@ from hc.test import BaseTestCase class CloseAccountTestCase(BaseTestCase): + def test_it_requires_sudo_mode(self): + self.client.login(username="alice@example.org", password="password") + + r = self.client.get("/accounts/close/") + self.assertContains(r, "We have sent a confirmation code") + + def test_it_shows_confirmation_form(self): + self.client.login(username="alice@example.org", password="password") + self.set_sudo_flag() + + r = self.client.get("/accounts/close/") + self.assertContains(r, "Close Account?") + self.assertContains(r, "1 project") + self.assertContains(r, "0 checks") + @patch("hc.payments.models.braintree") def test_it_works(self, mock_braintree): Check.objects.create(project=self.project, tags="foo a-B_1 baz@") @@ -15,8 +30,11 @@ class CloseAccountTestCase(BaseTestCase): ) self.client.login(username="alice@example.org", password="password") - r = self.client.post("/accounts/close/") - self.assertEqual(r.status_code, 302) + self.set_sudo_flag() + + payload = {"confirmation": "alice@example.org"} + r = self.client.post("/accounts/close/", payload) + self.assertRedirects(r, "/") # Alice should be gone alices = User.objects.filter(username="alice") @@ -31,10 +49,26 @@ class CloseAccountTestCase(BaseTestCase): # Subscription should be gone self.assertFalse(Subscription.objects.exists()) + def test_it_requires_confirmation(self): + self.client.login(username="alice@example.org", password="password") + self.set_sudo_flag() + + payload = {"confirmation": "incorrect"} + r = self.client.post("/accounts/close/", payload) + self.assertContains(r, "Close Account?") + self.assertContains(r, "has-error") + + # Alice should be still present + self.alice.refresh_from_db() + self.profile.refresh_from_db() + def test_partner_removal_works(self): self.client.login(username="bob@example.org", password="password") - r = self.client.post("/accounts/close/") - self.assertEqual(r.status_code, 302) + self.set_sudo_flag() + + payload = {"confirmation": "bob@example.org"} + r = self.client.post("/accounts/close/", payload) + self.assertRedirects(r, "/") # Alice should be still present self.alice.refresh_from_db() @@ -43,8 +77,3 @@ class CloseAccountTestCase(BaseTestCase): # Bob should be gone bobs = User.objects.filter(username="bob") self.assertFalse(bobs.exists()) - - def test_it_rejects_get(self): - self.client.login(username="bob@example.org", password="password") - r = self.client.get("/accounts/close/") - self.assertEqual(r.status_code, 405) diff --git a/hc/accounts/views.py b/hc/accounts/views.py index 8c8e5eec..1c07766f 100644 --- a/hc/accounts/views.py +++ b/hc/accounts/views.py @@ -540,22 +540,29 @@ def unsubscribe_reports(request, signed_username): return render(request, "accounts/unsubscribed.html") -@require_POST @login_required +@require_sudo_mode def close(request): user = request.user - # Cancel their subscription: - sub = Subscription.objects.filter(user=user).first() - if sub: - sub.cancel() + if request.method == "POST": + if request.POST.get("confirmation") == request.user.email: + # Cancel their subscription: + sub = Subscription.objects.filter(user=user).first() + if sub: + sub.cancel() + + # Deleting user also deletes its profile, checks, channels etc. + user.delete() - user.delete() + request.session.flush() + return redirect("hc-index") - # Deleting user also deletes its profile, checks, channels etc. + ctx = {} + if "confirmation" in request.POST: + ctx["wrong_confirmation"] = True - request.session.flush() - return redirect("hc-index") + return render(request, "accounts/close_account.html", ctx) @require_POST diff --git a/templates/accounts/close_account.html b/templates/accounts/close_account.html new file mode 100644 index 00000000..a2906a67 --- /dev/null +++ b/templates/accounts/close_account.html @@ -0,0 +1,50 @@ +{% extends "base.html" %} +{% load compress static hc_extras %} + +{% block content %} + +
This will permanently remove your {{ site_name }} account.
+