forked from GithubBackups/healthchecks
Update the signup form to collect browser's timezone
This commit is contained in:
parent
6094bca241
commit
548b2ac33c
@ -28,12 +28,13 @@ class Base64Field(forms.CharField):
|
||||
raise ValidationError(message="Cannot decode base64")
|
||||
|
||||
|
||||
class AvailableEmailForm(forms.Form):
|
||||
class SignupForm(forms.Form):
|
||||
# Call it "identity" instead of "email"
|
||||
# to avoid some of the dumber bots
|
||||
identity = LowercaseEmailField(
|
||||
error_messages={"required": "Please enter your email address."}
|
||||
)
|
||||
tz = forms.CharField(required=False)
|
||||
|
||||
def clean_identity(self):
|
||||
v = self.cleaned_data["identity"]
|
||||
@ -47,6 +48,15 @@ class AvailableEmailForm(forms.Form):
|
||||
|
||||
return v
|
||||
|
||||
def clean_tz(self):
|
||||
# Declare tz as "clean" only if we can find it in pytz.all_timezones
|
||||
if self.cleaned_data["tz"] in pytz.all_timezones:
|
||||
return self.cleaned_data["tz"]
|
||||
|
||||
# Otherwise, return None, and *don't* throw a validation exception:
|
||||
# If user's browser reports a timezone we don't recognize, we
|
||||
# should ignore the timezone but still save the rest of the form.
|
||||
|
||||
|
||||
class EmailLoginForm(forms.Form):
|
||||
# Call it "identity" instead of "email"
|
||||
|
@ -1,7 +1,7 @@
|
||||
import getpass
|
||||
|
||||
from django.core.management.base import BaseCommand
|
||||
from hc.accounts.forms import AvailableEmailForm
|
||||
from hc.accounts.forms import SignupForm
|
||||
from hc.accounts.views import _make_user
|
||||
|
||||
|
||||
@ -14,7 +14,7 @@ class Command(BaseCommand):
|
||||
|
||||
while not email:
|
||||
raw = input("Email address:")
|
||||
form = AvailableEmailForm({"identity": raw})
|
||||
form = SignupForm({"identity": raw})
|
||||
if not form.is_valid():
|
||||
self.stderr.write("Error: " + " ".join(form.errors["identity"]))
|
||||
continue
|
||||
|
@ -9,8 +9,8 @@ from django.conf import settings
|
||||
|
||||
class SignupTestCase(TestCase):
|
||||
@override_settings(USE_PAYMENTS=False)
|
||||
def test_it_sends_link(self):
|
||||
form = {"identity": "alice@example.org"}
|
||||
def test_it_works(self):
|
||||
form = {"identity": "alice@example.org", "tz": "Europe/Riga"}
|
||||
|
||||
r = self.client.post("/accounts/signup/", form)
|
||||
self.assertContains(r, "Account created")
|
||||
@ -21,8 +21,10 @@ class SignupTestCase(TestCase):
|
||||
|
||||
# A profile should have been created
|
||||
profile = Profile.objects.get()
|
||||
self.assertEqual(profile.check_limit, 500)
|
||||
self.assertEqual(profile.sms_limit, 500)
|
||||
self.assertEqual(profile.call_limit, 500)
|
||||
self.assertEqual(profile.tz, "Europe/Riga")
|
||||
|
||||
# And email sent
|
||||
self.assertEqual(len(mail.outbox), 1)
|
||||
@ -44,25 +46,25 @@ class SignupTestCase(TestCase):
|
||||
self.assertEqual(channel.project, project)
|
||||
|
||||
@override_settings(USE_PAYMENTS=True)
|
||||
def test_it_sets_high_limits(self):
|
||||
form = {"identity": "alice@example.org"}
|
||||
def test_it_sets_limits(self):
|
||||
form = {"identity": "alice@example.org", "tz": ""}
|
||||
|
||||
self.client.post("/accounts/signup/", form)
|
||||
|
||||
# A profile should have been created
|
||||
profile = Profile.objects.get()
|
||||
self.assertEqual(profile.check_limit, 20)
|
||||
self.assertEqual(profile.sms_limit, 5)
|
||||
self.assertEqual(profile.call_limit, 0)
|
||||
|
||||
@override_settings(REGISTRATION_OPEN=False)
|
||||
def test_it_obeys_registration_open(self):
|
||||
form = {"identity": "dan@example.org"}
|
||||
form = {"identity": "dan@example.org", "tz": ""}
|
||||
|
||||
r = self.client.post("/accounts/signup/", form)
|
||||
self.assertEqual(r.status_code, 403)
|
||||
|
||||
def test_it_ignores_case(self):
|
||||
form = {"identity": "ALICE@EXAMPLE.ORG"}
|
||||
form = {"identity": "ALICE@EXAMPLE.ORG", "tz": ""}
|
||||
self.client.post("/accounts/signup/", form)
|
||||
|
||||
# There should be exactly one user:
|
||||
@ -73,19 +75,30 @@ class SignupTestCase(TestCase):
|
||||
alice = User(username="alice", email="alice@example.org")
|
||||
alice.save()
|
||||
|
||||
form = {"identity": "alice@example.org"}
|
||||
form = {"identity": "alice@example.org", "tz": ""}
|
||||
r = self.client.post("/accounts/signup/", form)
|
||||
self.assertContains(r, "already exists")
|
||||
|
||||
def test_it_checks_syntax(self):
|
||||
form = {"identity": "alice at example org"}
|
||||
form = {"identity": "alice at example org", "tz": ""}
|
||||
r = self.client.post("/accounts/signup/", form)
|
||||
self.assertContains(r, "Enter a valid email address")
|
||||
|
||||
def test_it_checks_length(self):
|
||||
aaa = "a" * 300
|
||||
form = {"identity": f"alice+{aaa}@example.org"}
|
||||
form = {"identity": f"alice+{aaa}@example.org", "tz": ""}
|
||||
r = self.client.post("/accounts/signup/", form)
|
||||
self.assertContains(r, "Address is too long.")
|
||||
|
||||
self.assertFalse(User.objects.exists())
|
||||
|
||||
@override_settings(USE_PAYMENTS=False)
|
||||
def test_it_ignores_bad_tz(self):
|
||||
form = {"identity": "alice@example.org", "tz": "Foo/Bar"}
|
||||
|
||||
r = self.client.post("/accounts/signup/", form)
|
||||
self.assertContains(r, "Account created")
|
||||
self.assertIn("auto-login", r.cookies)
|
||||
|
||||
profile = Profile.objects.get()
|
||||
self.assertEqual(profile.tz, "UTC")
|
||||
|
@ -59,7 +59,7 @@ def _allow_redirect(redirect_url):
|
||||
return match.url_name in POST_LOGIN_ROUTES
|
||||
|
||||
|
||||
def _make_user(email, with_project=True):
|
||||
def _make_user(email, tz=None, with_project=True):
|
||||
username = str(uuid.uuid4())[:30]
|
||||
user = User(username=username, email=email)
|
||||
user.set_unusable_password()
|
||||
@ -84,7 +84,10 @@ def _make_user(email, with_project=True):
|
||||
channel.checks.add(check)
|
||||
|
||||
# Ensure a profile gets created
|
||||
Profile.objects.for_user(user)
|
||||
profile = Profile.objects.for_user(user)
|
||||
if tz:
|
||||
profile.tz = tz
|
||||
profile.save()
|
||||
|
||||
return user
|
||||
|
||||
@ -173,10 +176,11 @@ def signup(request):
|
||||
return HttpResponseForbidden()
|
||||
|
||||
ctx = {}
|
||||
form = forms.AvailableEmailForm(request.POST)
|
||||
form = forms.SignupForm(request.POST)
|
||||
if form.is_valid():
|
||||
email = form.cleaned_data["identity"]
|
||||
user = _make_user(email)
|
||||
tz = form.cleaned_data["tz"]
|
||||
user = _make_user(email, tz)
|
||||
profile = Profile.objects.for_user(user)
|
||||
profile.send_instant_login_link()
|
||||
ctx["created"] = True
|
||||
|
@ -4,11 +4,17 @@ $(function () {
|
||||
var base = document.getElementById("base-url").getAttribute("href").slice(0, -1);
|
||||
var email = $("#signup-email").val();
|
||||
|
||||
try {
|
||||
var tz = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
||||
} catch(err) {
|
||||
var tz = "UTC";
|
||||
}
|
||||
|
||||
$("#signup-go").prop("disabled", true);
|
||||
$.ajax({
|
||||
url: base + "/accounts/signup/",
|
||||
type: "post",
|
||||
data: {"identity": email},
|
||||
data: {"identity": email, "tz": tz},
|
||||
success: function(data) {
|
||||
$("#signup-result").html(data).show();
|
||||
$("#signup-go").prop("disabled", false);
|
||||
|
Loading…
x
Reference in New Issue
Block a user