diff --git a/CHANGELOG.md b/CHANGELOG.md index 09c25136..db87c886 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,9 +6,11 @@ All notable changes to this project will be documented in this file. ### Improvements - Content updates in the "Welcome" page. - Added "Docs > Third-Party Resources" page. +- Improved layout and styling in "Login" page. ### Bug Fixes -- Timezones were missing in the "Change Schedule" dialog, fixed +- Timezones were missing in the "Change Schedule" dialog, fixed. +- Fix hamburger menu button in "Login" page. ## 1.1.0 - 2018-08-20 diff --git a/hc/accounts/forms.py b/hc/accounts/forms.py index c1aca20e..a1765fa2 100644 --- a/hc/accounts/forms.py +++ b/hc/accounts/forms.py @@ -1,5 +1,7 @@ from datetime import timedelta as td from django import forms +from django.conf import settings +from django.contrib.auth import authenticate from django.contrib.auth.models import User @@ -10,9 +12,37 @@ class LowercaseEmailField(forms.EmailField): return value.lower() +class EmailForm(forms.Form): + email = LowercaseEmailField() + + def clean_email(self): + v = self.cleaned_data["email"] + + # If registration is not open then validate if an user + # account with this address exists- + if not settings.REGISTRATION_OPEN: + if not User.objects.filter(email=v).exists(): + raise forms.ValidationError("Incorrect email address.") + + return v + + class EmailPasswordForm(forms.Form): - identity = LowercaseEmailField() - password = forms.CharField(required=False) + email = LowercaseEmailField() + password = forms.CharField() + + def clean(self): + username = self.cleaned_data.get('email') + password = self.cleaned_data.get('password') + + if username and password: + self.user = authenticate(username=username, password=password) + if self.user is None: + raise forms.ValidationError("Incorrect email or password") + if not self.user.is_active: + raise forms.ValidationError("Account is inactive") + + return self.cleaned_data class ReportSettingsForm(forms.Form): diff --git a/hc/accounts/tests/test_login.py b/hc/accounts/tests/test_login.py index e7a7e66c..a2a7b088 100644 --- a/hc/accounts/tests/test_login.py +++ b/hc/accounts/tests/test_login.py @@ -10,7 +10,7 @@ from django.conf import settings class LoginTestCase(TestCase): def test_it_sends_link(self): - form = {"identity": "alice@example.org"} + form = {"email": "alice@example.org"} r = self.client.post("/accounts/login/", form) assert r.status_code == 302 @@ -32,10 +32,9 @@ class LoginTestCase(TestCase): self.client.get("/accounts/login/") assert "bad_link" not in self.client.session - @override_settings(REGISTRATION_OPEN=False) def test_it_obeys_registration_open(self): - form = {"identity": "dan@example.org"} + form = {"email": "dan@example.org"} r = self.client.post("/accounts/login/", form) assert r.status_code == 200 @@ -45,7 +44,7 @@ class LoginTestCase(TestCase): alice = User(username="alice", email="alice@example.org") alice.save() - form = {"identity": "ALICE@EXAMPLE.ORG"} + form = {"email": "ALICE@EXAMPLE.ORG"} r = self.client.post("/accounts/login/", form) assert r.status_code == 302 diff --git a/hc/accounts/views.py b/hc/accounts/views.py index d894fe26..a88d5722 100644 --- a/hc/accounts/views.py +++ b/hc/accounts/views.py @@ -17,7 +17,7 @@ from django.views.decorators.http import require_POST from hc.accounts.forms import (ChangeEmailForm, EmailPasswordForm, InviteTeamMemberForm, RemoveTeamMemberForm, ReportSettingsForm, SetPasswordForm, - TeamNameForm) + TeamNameForm, EmailForm) from hc.accounts.models import Profile, Member from hc.api.models import Channel, Check from hc.lib.badges import get_badge_url @@ -57,44 +57,38 @@ def _ensure_own_team(request): request.profile.save() -def login(request, show_password=False): - bad_credentials = False +def login(request): + form = EmailPasswordForm() + magic_form = EmailForm() + if request.method == 'POST': - form = EmailPasswordForm(request.POST) - if form.is_valid(): - email = form.cleaned_data["identity"] - password = form.cleaned_data["password"] - if len(password): - user = authenticate(username=email, password=password) - if user is not None and user.is_active: - auth_login(request, user) - return redirect("hc-checks") - bad_credentials = True - show_password = True - else: + if request.POST.get("action") == "login": + form = EmailPasswordForm(request.POST) + if form.is_valid(): + auth_login(request, form.user) + return redirect("hc-checks") + + else: + magic_form = EmailForm(request.POST) + if magic_form.is_valid(): + email = magic_form.cleaned_data["email"] user = None try: user = User.objects.get(email=email) except User.DoesNotExist: if settings.REGISTRATION_OPEN: user = _make_user(email) - else: - bad_credentials = True - if user: profile = Profile.objects.for_user(user) profile.send_instant_login_link() return redirect("hc-login-link-sent") - else: - form = EmailPasswordForm() - bad_link = request.session.pop("bad_link", None) ctx = { + "page": "login", "form": form, - "bad_credentials": bad_credentials, - "bad_link": bad_link, - "show_password": show_password + "magic_form": magic_form, + "bad_link": bad_link } return render(request, "accounts/login.html", ctx) diff --git a/hc/urls.py b/hc/urls.py index 669df950..1075ebc6 100644 --- a/hc/urls.py +++ b/hc/urls.py @@ -4,7 +4,7 @@ from django.urls import include, path from hc.accounts.views import login as hc_login urlpatterns = [ - path('admin/login/', hc_login, {"show_password": True}), + path('admin/login/', hc_login), path('admin/', admin.site.urls), path('accounts/', include('hc.accounts.urls')), path('', include('hc.api.urls')), diff --git a/static/css/login.css b/static/css/login.css new file mode 100644 index 00000000..cd8a0583 --- /dev/null +++ b/static/css/login.css @@ -0,0 +1,74 @@ +.page-login h1 { + text-align: center; + margin: 40px 0; +} + +.page-login .alert { + margin-bottom: 40px; +} + +.page-login form p { + margin-bottom: 20px; + text-align: center; +} + +.page-login form input { + margin-bottom: 20px; +} + +@media (min-width: 768px) { + #magic-link-form { + margin-right: 50px; + } + + #login-form { + margin-left: 50px; + } +} + +#link-instruction { + color: #999; + font-style: italic; + padding: 12px 16px; +} + +#login-sep { + background:#ddd; + position: absolute; + top: 10%; + right: -1px; + height: 80%; + width: 1px; +} + +#login-sep div { + position: absolute; + top: 40%; + width: 40px; + left: -20px; + text-align: center; + background: #fff; + font-style: italic; + color: #666; + font-size: 12px; + padding: 8px 0; +} + +#xs-login-sep { + text-align: center; + margin: 40px; + font-style: italic; + color: #666; + font-size: 12px; + height: 1px; + background: #ddd; +} + +#xs-login-sep div { + position: relative; + margin: 0 auto; + width: 30px; + top: -9px; + background: #fff; +} + diff --git a/templates/accounts/login.html b/templates/accounts/login.html index 6f1e75a8..474919f6 100644 --- a/templates/accounts/login.html +++ b/templates/accounts/login.html @@ -3,77 +3,82 @@ {% block content %}
-
-
- {% if bad_link %} -

Incorrect Login Link

-
-

The login link you just used is either incorrect or expired.

-

Please use the form below to request a fresh login link:

-
- {% else %} -

{% site_name %}

-
-

- {% if show_password %} - Please enter your email address and password. - {% else %} - Please enter your email address. - Next, we'll send you an email with log-in instructions! - {% endif %} -

-
- {% endif %} +
- {% if bad_credentials %} -

Incorrect email or password.

- {% endif %} +

Sign In to {% site_name %}

+ {% if bad_link %} +
+

The login link you just used is either incorrect or expired.

+

Please use the form below to request a fresh login link.

+
+ {% endif %} -
- {% csrf_token %} +
+
+ + {% csrf_token %} -
-
-
- -
- -
-
+ {% if magic_form.email.errors %} +

Incorrect email address.

+ {% else %} +

Enter your email address.

+ {% endif %} - {% if not show_password %} -
- -
- {% endif %} + + + + + + +
-
-
-
- -
- -
+
+
+
or
+
+ +
+
+ {% csrf_token %} + + + {% if form.non_field_errors %} +

Incorrect email or password.

+ {% else %} +

+ Enter your email address and password. +

+ {% endif %} + + -
- -
-
+ +
@@ -82,6 +87,7 @@ {% block scripts %} {% compress js %} + {% endcompress %} {% endblock %} diff --git a/templates/base.html b/templates/base.html index 9bae5500..d2818b30 100644 --- a/templates/base.html +++ b/templates/base.html @@ -42,6 +42,7 @@ + {% endcompress %} @@ -109,14 +110,6 @@ - - {% if request.user.is_authenticated %} - {% else %} - - {% endif %} - {% if request.user.is_authenticated %} + {% elif page != "login" %} + {% endif %}