forked from GithubBackups/healthchecks
"Close Account" section in Settings page. Fixes #95
This commit is contained in:
parent
d739d8ff62
commit
e685154cc2
57
hc/accounts/tests/test_close_account.py
Normal file
57
hc/accounts/tests/test_close_account.py
Normal file
@ -0,0 +1,57 @@
|
||||
from django.contrib.auth.models import User
|
||||
from mock import patch
|
||||
|
||||
from hc.test import BaseTestCase
|
||||
from hc.api.models import Check
|
||||
from hc.payments.models import Subscription
|
||||
|
||||
|
||||
class CloseAccountTestCase(BaseTestCase):
|
||||
|
||||
@patch("hc.payments.models.Subscription.cancel")
|
||||
def test_it_works(self, mock_cancel):
|
||||
Check.objects.create(user=self.alice, tags="foo a-B_1 baz@")
|
||||
Subscription.objects.create(user=self.alice, subscription_id="123")
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
r = self.client.post("/accounts/close/")
|
||||
self.assertEqual(r.status_code, 302)
|
||||
|
||||
# Alice should be gone
|
||||
alices = User.objects.filter(username="alice")
|
||||
self.assertFalse(alices.exists())
|
||||
|
||||
# Alice should be gone
|
||||
alices = User.objects.filter(username="alice")
|
||||
self.assertFalse(alices.exists())
|
||||
|
||||
# Bob's current team should be updated to self
|
||||
self.bobs_profile.refresh_from_db()
|
||||
self.assertEqual(self.bobs_profile.current_team, self.bobs_profile)
|
||||
|
||||
# Check should be gone
|
||||
self.assertFalse(Check.objects.exists())
|
||||
|
||||
# Subscription should have been canceled
|
||||
self.assertTrue(mock_cancel.called)
|
||||
|
||||
# Subscription should be gone
|
||||
self.assertFalse(Subscription.objects.exists())
|
||||
|
||||
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)
|
||||
|
||||
# Alice should be still present
|
||||
self.alice.refresh_from_db()
|
||||
self.profile.refresh_from_db()
|
||||
|
||||
# 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)
|
@ -16,6 +16,7 @@ urlpatterns = [
|
||||
url(r'^profile/$', views.profile, name="hc-profile"),
|
||||
url(r'^profile/notifications/$', views.notifications, name="hc-notifications"),
|
||||
url(r'^profile/badges/$', views.badges, name="hc-badges"),
|
||||
url(r'^close/$', views.close, name="hc-close"),
|
||||
|
||||
url(r'^unsubscribe_reports/([\w-]+)/$',
|
||||
views.unsubscribe_reports, name="hc-unsubscribe-reports"),
|
||||
|
@ -12,12 +12,14 @@ from django.contrib.auth.models import User
|
||||
from django.core import signing
|
||||
from django.http import HttpResponseForbidden, HttpResponseBadRequest
|
||||
from django.shortcuts import redirect, render
|
||||
from django.views.decorators.http import require_POST
|
||||
from hc.accounts.forms import (EmailPasswordForm, InviteTeamMemberForm,
|
||||
RemoveTeamMemberForm, ReportSettingsForm,
|
||||
SetPasswordForm, TeamNameForm)
|
||||
from hc.accounts.models import Profile, Member
|
||||
from hc.api.models import Channel, Check
|
||||
from hc.lib.badges import get_badge_url
|
||||
from hc.payments.models import Subscription
|
||||
|
||||
|
||||
def _make_user(email):
|
||||
@ -338,3 +340,24 @@ def switch_team(request, target_username):
|
||||
request.user.profile.save()
|
||||
|
||||
return redirect("hc-checks")
|
||||
|
||||
|
||||
@require_POST
|
||||
@login_required
|
||||
def close(request):
|
||||
user = request.user
|
||||
|
||||
# Subscription needs to be canceled before it is deleted:
|
||||
sub = Subscription.objects.filter(user=user).first()
|
||||
if sub:
|
||||
sub.cancel()
|
||||
|
||||
# Any users currently using this team need to switch to their own team:
|
||||
for partner in Profile.objects.filter(current_team=user.profile):
|
||||
partner.current_team = partner
|
||||
partner.save()
|
||||
|
||||
user.delete()
|
||||
|
||||
request.session.flush()
|
||||
return redirect("hc-index")
|
||||
|
@ -39,6 +39,14 @@ class Subscription(models.Model):
|
||||
self._pm = braintree.PaymentMethod.find(self.payment_method_token)
|
||||
return self._pm
|
||||
|
||||
def cancel(self):
|
||||
if self.subscription_id:
|
||||
braintree.Subscription.cancel(self.subscription_id)
|
||||
|
||||
self.subscription_id = ""
|
||||
self.plan_id = ""
|
||||
self.save()
|
||||
|
||||
def pm_is_credit_card(self):
|
||||
return isinstance(self._get_braintree_payment_method(),
|
||||
braintree.credit_card.CreditCard)
|
||||
|
@ -13,7 +13,7 @@ class CancelPlanTestCase(BaseTestCase):
|
||||
self.sub.plan_id = "P5"
|
||||
self.sub.save()
|
||||
|
||||
@patch("hc.payments.views.braintree")
|
||||
@patch("hc.payments.models.braintree")
|
||||
def test_it_works(self, mock_braintree):
|
||||
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
|
@ -156,12 +156,7 @@ def update_payment_method(request):
|
||||
@require_POST
|
||||
def cancel_plan(request):
|
||||
sub = Subscription.objects.get(user=request.user)
|
||||
|
||||
braintree.Subscription.cancel(sub.subscription_id)
|
||||
sub.subscription_id = ""
|
||||
sub.plan_id = ""
|
||||
sub.save()
|
||||
|
||||
sub.cancel()
|
||||
return redirect("hc-pricing")
|
||||
|
||||
|
||||
|
@ -17,4 +17,10 @@
|
||||
|
||||
.page-profile .icon-ok {
|
||||
color: #5cb85c;
|
||||
}
|
||||
|
||||
#close-account {
|
||||
margin-left: 24px;
|
||||
border-color: #d43f3a;
|
||||
color: #d43f3a;
|
||||
}
|
@ -136,6 +136,22 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-body settings-block">
|
||||
{% csrf_token %}
|
||||
<h2>Close Account</h2>
|
||||
<a
|
||||
id="close-account"
|
||||
href="#"
|
||||
class="btn btn-default pull-right"
|
||||
data-toggle="modal"
|
||||
data-target="#close-account-modal">Close Account</a>
|
||||
This will permanently remove your healthchecks.io account
|
||||
<form action="{% url 'hc-close' %}" method="post">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -268,6 +284,33 @@
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="close-account-modal" class="modal">
|
||||
<div class="modal-dialog">
|
||||
<form id="close-account-form" method="post" action="{% url 'hc-close' %}">
|
||||
{% csrf_token %}
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<button type="button" class="close" data-dismiss="modal">×</button>
|
||||
<h4 class="remove-check-title">Close Account</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p></p>
|
||||
<p>You are about to permanently remove
|
||||
the account <strong>{{ profile }}</strong> and all
|
||||
of its associated checks and integrations.</p>
|
||||
<p>Are you sure?</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
|
||||
<button
|
||||
type="submit"
|
||||
class="btn btn-danger">Close Account</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block scripts %}
|
||||
|
Loading…
x
Reference in New Issue
Block a user