forked from GithubBackups/healthchecks
Update the "Change Email" function to use confirmation codes
This commit is contained in:
parent
ed6b15bfa9
commit
fb79948759
@ -118,12 +118,6 @@ class Profile(models.Model):
|
||||
}
|
||||
emails.transfer_request(self.user.email, ctx)
|
||||
|
||||
def send_change_email_link(self):
|
||||
token = self.prepare_token("change-email")
|
||||
path = reverse("hc-change-email", args=[token])
|
||||
ctx = {"button_text": "Change Email", "button_url": settings.SITE_ROOT + path}
|
||||
emails.change_email(self.user.email, ctx)
|
||||
|
||||
def send_sms_limit_notice(self, transport):
|
||||
ctx = {"transport": transport, "limit": self.sms_limit}
|
||||
if self.sms_limit != 500 and settings.USE_PAYMENTS:
|
||||
|
@ -1,39 +1,42 @@
|
||||
from django.contrib.auth.hashers import make_password
|
||||
|
||||
from hc.test import BaseTestCase
|
||||
|
||||
|
||||
class ChangeEmailTestCase(BaseTestCase):
|
||||
def test_it_shows_form(self):
|
||||
self.profile.token = make_password("foo", "change-email")
|
||||
self.profile.save()
|
||||
|
||||
def test_it_requires_sudo_mode(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
|
||||
r = self.client.get("/accounts/change_email/foo/")
|
||||
r = self.client.get("/accounts/change_email/")
|
||||
self.assertContains(r, "We have sent a confirmation code")
|
||||
|
||||
def test_it_shows_form(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
self.set_sudo_flag()
|
||||
|
||||
r = self.client.get("/accounts/change_email/")
|
||||
self.assertContains(r, "Change Account's Email Address")
|
||||
|
||||
def test_it_changes_password(self):
|
||||
self.profile.token = make_password("foo", "change-email")
|
||||
self.profile.save()
|
||||
|
||||
def test_it_updates_email(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
self.set_sudo_flag()
|
||||
|
||||
payload = {"email": "alice2@example.org"}
|
||||
self.client.post("/accounts/change_email/foo/", payload)
|
||||
r = self.client.post("/accounts/change_email/", payload, follow=True)
|
||||
self.assertRedirects(r, "/accounts/change_email/done/")
|
||||
self.assertContains(r, "Email Address Updated")
|
||||
|
||||
self.alice.refresh_from_db()
|
||||
self.assertEqual(self.alice.email, "alice2@example.org")
|
||||
self.assertFalse(self.alice.has_usable_password())
|
||||
|
||||
def test_it_requires_unique_email(self):
|
||||
self.profile.token = make_password("foo", "change-email")
|
||||
self.profile.save()
|
||||
# The user should have been logged out:
|
||||
self.assertNotIn("_auth_user_id", self.client.session)
|
||||
|
||||
def test_it_requires_unique_email(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
self.set_sudo_flag()
|
||||
|
||||
payload = {"email": "bob@example.org"}
|
||||
r = self.client.post("/accounts/change_email/foo/", payload)
|
||||
r = self.client.post("/accounts/change_email/", payload)
|
||||
self.assertContains(r, "bob@example.org is already registered")
|
||||
|
||||
self.alice.refresh_from_db()
|
||||
|
@ -75,23 +75,6 @@ class ProfileTestCase(BaseTestCase):
|
||||
|
||||
self.assertEqual(len(mail.outbox), 0)
|
||||
|
||||
def test_it_sends_change_email_link(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
|
||||
form = {"change_email": "1"}
|
||||
r = self.client.post("/accounts/profile/", form)
|
||||
assert r.status_code == 302
|
||||
|
||||
# profile.token should be set now
|
||||
self.profile.refresh_from_db()
|
||||
token = self.profile.token
|
||||
self.assertTrue(len(token) > 10)
|
||||
|
||||
# And an email should have been sent
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
expected_subject = "Change email address on %s" % settings.SITE_NAME
|
||||
self.assertEqual(mail.outbox[0].subject, expected_subject)
|
||||
|
||||
def test_leaving_works(self):
|
||||
self.client.login(username="bob@example.org", password="password")
|
||||
|
||||
|
@ -2,7 +2,7 @@ from hc.test import BaseTestCase
|
||||
|
||||
|
||||
class SetPasswordTestCase(BaseTestCase):
|
||||
def test_it_requires_sudo_mod(self):
|
||||
def test_it_requires_sudo_mode(self):
|
||||
self.client.login(username="alice@example.org", password="password")
|
||||
|
||||
r = self.client.get("/accounts/set_password/")
|
||||
|
@ -7,7 +7,6 @@ urlpatterns = [
|
||||
path("logout/", views.logout, name="hc-logout"),
|
||||
path("signup/", views.signup, name="hc-signup"),
|
||||
path("login_link_sent/", views.login_link_sent, name="hc-login-link-sent"),
|
||||
path("link_sent/", views.link_sent, name="hc-link-sent"),
|
||||
path(
|
||||
"check_token/<slug:username>/<slug:token>/",
|
||||
views.check_token,
|
||||
@ -23,7 +22,7 @@ urlpatterns = [
|
||||
),
|
||||
path("set_password/", views.set_password, name="hc-set-password"),
|
||||
path("change_email/done/", views.change_email_done, name="hc-change-email-done"),
|
||||
path("change_email/<slug:token>/", views.change_email, name="hc-change-email"),
|
||||
path("change_email/", views.change_email, name="hc-change-email"),
|
||||
path("two_factor/add/", views.add_credential, name="hc-add-credential"),
|
||||
path(
|
||||
"two_factor/<uuid:code>/remove/",
|
||||
|
@ -186,10 +186,6 @@ def login_link_sent(request):
|
||||
return render(request, "accounts/login_link_sent.html")
|
||||
|
||||
|
||||
def link_sent(request):
|
||||
return render(request, "accounts/link_sent.html")
|
||||
|
||||
|
||||
def check_token(request, username, token):
|
||||
if request.user.is_authenticated and request.user.username == username:
|
||||
# User is already logged in
|
||||
@ -235,21 +231,17 @@ def profile(request):
|
||||
if ctx["removed_credential_name"]:
|
||||
ctx["2fa_status"] = "info"
|
||||
|
||||
if request.method == "POST":
|
||||
if "change_email" in request.POST:
|
||||
profile.send_change_email_link()
|
||||
return redirect("hc-link-sent")
|
||||
elif "leave_project" in request.POST:
|
||||
code = request.POST["code"]
|
||||
try:
|
||||
project = Project.objects.get(code=code, member__user=request.user)
|
||||
except Project.DoesNotExist:
|
||||
return HttpResponseBadRequest()
|
||||
if request.method == "POST" and "leave_project" in request.POST:
|
||||
code = request.POST["code"]
|
||||
try:
|
||||
project = Project.objects.get(code=code, member__user=request.user)
|
||||
except Project.DoesNotExist:
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
Member.objects.filter(project=project, user=request.user).delete()
|
||||
Member.objects.filter(project=project, user=request.user).delete()
|
||||
|
||||
ctx["left_project"] = project
|
||||
ctx["my_projects_status"] = "info"
|
||||
ctx["left_project"] = project
|
||||
ctx["my_projects_status"] = "info"
|
||||
|
||||
return render(request, "accounts/profile.html", ctx)
|
||||
|
||||
@ -486,10 +478,8 @@ def set_password(request):
|
||||
|
||||
|
||||
@login_required
|
||||
def change_email(request, token):
|
||||
if not request.profile.check_token(token, "change-email"):
|
||||
return HttpResponseBadRequest()
|
||||
|
||||
@require_sudo_mode
|
||||
def change_email(request):
|
||||
if request.method == "POST":
|
||||
form = forms.ChangeEmailForm(request.POST)
|
||||
if form.is_valid():
|
||||
|
@ -62,10 +62,6 @@ def transfer_request(to, ctx):
|
||||
send("transfer-request", to, ctx)
|
||||
|
||||
|
||||
def change_email(to, ctx):
|
||||
send("change-email", to, ctx)
|
||||
|
||||
|
||||
def alert(to, ctx, headers={}):
|
||||
send("alert", to, ctx, headers)
|
||||
|
||||
|
@ -20,44 +20,49 @@
|
||||
</p>
|
||||
|
||||
{% if request.user.has_usable_password %}
|
||||
<p>
|
||||
Note: Changing the email address will also
|
||||
<strong>reset your current password</strong>
|
||||
<p class="alert alert-warning">
|
||||
<strong>Your password will be reset.</strong>
|
||||
For security purposes, after updating your email address,
|
||||
{% site_name %} will also reset your current password
|
||||
and log you out.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
{% if request.user.credentials.exists %}
|
||||
<p class="alert alert-warning">
|
||||
<strong>Two-factor authentication is active.</strong>
|
||||
If you are handing this account over to somebody else,
|
||||
consider disabling two-factor authentication first.
|
||||
</p>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<form class="form-horizontal" method="post">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">Current Email</label>
|
||||
<div class="col-sm-9">
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
disabled
|
||||
value="{{ request.user.email }}">
|
||||
</div>
|
||||
<label class="control-label">Current Email</label>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control input-lg"
|
||||
disabled
|
||||
value="{{ request.user.email }}">
|
||||
</div>
|
||||
|
||||
<div class="form-group {{ form.email.css_classes }}">
|
||||
<label for="ce-email" class="col-sm-3 control-label">New Email</label>
|
||||
<div class="col-sm-9">
|
||||
<input
|
||||
type="email"
|
||||
class="form-control"
|
||||
id="ce-email"
|
||||
name="email"
|
||||
placeholder="you@example.org">
|
||||
{% if form.email.errors %}
|
||||
<div class="help-block">
|
||||
{{ form.email.errors|join:"" }}
|
||||
</div>
|
||||
{% endif %}
|
||||
<label for="ce-email" class="control-label">New Email</label>
|
||||
<input
|
||||
type="email"
|
||||
class="form-control input-lg"
|
||||
id="ce-email"
|
||||
name="email"
|
||||
placeholder="you@example.org">
|
||||
{% if form.email.errors %}
|
||||
<div class="help-block">
|
||||
{{ form.email.errors|join:"" }}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix">
|
||||
|
@ -1,18 +0,0 @@
|
||||
{% extends "base.html" %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-sm-offset-3">
|
||||
<div class="hc-dialog">
|
||||
<h1>Email with Instructions Sent!</h1>
|
||||
<br />
|
||||
<p>
|
||||
We've sent you an email with further instructions.
|
||||
Please check your inbox!
|
||||
</p>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
@ -42,10 +42,9 @@
|
||||
Your account's email address is
|
||||
<code>{{ request.user.email }}</code>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
name="change_email"
|
||||
class="btn btn-default pull-right">Change Email</button>
|
||||
<a
|
||||
href="{% url 'hc-change-email' %}"
|
||||
class="btn btn-default pull-right">Change Email</a>
|
||||
</p>
|
||||
<p class="clearfix"></p>
|
||||
<p>
|
||||
|
@ -1,13 +0,0 @@
|
||||
{% extends "emails/base.html" %}
|
||||
{% load hc_extras %}
|
||||
|
||||
{% block content %}
|
||||
Hello,<br />
|
||||
To change the email address for your account on {% site_name %}, please press
|
||||
the button below:</p>
|
||||
{% endblock %}
|
||||
|
||||
{% block content_more %}
|
||||
Regards,<br />
|
||||
The {% site_name %} Team
|
||||
{% endblock %}
|
@ -1,11 +0,0 @@
|
||||
{% load hc_extras %}
|
||||
Hello,
|
||||
|
||||
Here's a link to change the email address for your account on {% site_name %}:
|
||||
|
||||
{{ button_url }}
|
||||
|
||||
|
||||
--
|
||||
Regards,
|
||||
{% site_name %}
|
@ -1,2 +0,0 @@
|
||||
{% load hc_extras %}
|
||||
Change email address on {% site_name %}
|
Loading…
x
Reference in New Issue
Block a user