forked from GithubBackups/healthchecks
Improved layout & style, fixed hamburger menu in login page.
This commit is contained in:
parent
160aa191c8
commit
a58ce791c0
@ -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
|
||||
|
@ -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):
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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')),
|
||||
|
74
static/css/login.css
Normal file
74
static/css/login.css
Normal file
@ -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;
|
||||
}
|
||||
|
@ -3,77 +3,82 @@
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col-sm-6 col-sm-offset-3">
|
||||
<div class="hc-dialog">
|
||||
{% if bad_link %}
|
||||
<h1>Incorrect Login Link</h1>
|
||||
<div class="dialog-body">
|
||||
<p>The login link you just used is either incorrect or expired.</p>
|
||||
<p>Please use the form below to request a fresh login link:</p>
|
||||
</div>
|
||||
{% else %}
|
||||
<h1>{% site_name %}</h1>
|
||||
<div class="dialog-body">
|
||||
<p>
|
||||
{% 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 %}
|
||||
</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
<div class="col-xs-10 col-xs-offset-1 col-sm-12 col-sm-offset-0 col-lg-8 col-lg-offset-2">
|
||||
|
||||
{% if bad_credentials %}
|
||||
<p class="alert alert-danger">Incorrect email or password.</p>
|
||||
{% endif %}
|
||||
<h1>Sign In to {% site_name %}</h1>
|
||||
{% if bad_link %}
|
||||
<div class="alert alert-warning">
|
||||
<p>The login link you just used is either incorrect or expired.</p>
|
||||
<p>Please use the form below to request a fresh login link.</p>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<form id="magic-link-form" method="post">
|
||||
{% csrf_token %}
|
||||
|
||||
<div class="form-group">
|
||||
<div class="input-group input-group-lg">
|
||||
<div class="input-group-addon">
|
||||
<span class="icon-mail"></span>
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
name="identity"
|
||||
value="{{ form.identity.value|default:"" }}"
|
||||
placeholder="you@example.org">
|
||||
</div>
|
||||
</div>
|
||||
{% if magic_form.email.errors %}
|
||||
<p class="text-danger">Incorrect email address.</p>
|
||||
{% else %}
|
||||
<p>Enter your <strong>email address</strong>.</p>
|
||||
{% endif %}
|
||||
|
||||
{% if not show_password %}
|
||||
<div class="checkbox" id="password-toggle">
|
||||
<label>
|
||||
<input type="checkbox"> I want to use a password
|
||||
</label>
|
||||
</div>
|
||||
{% endif %}
|
||||
<input
|
||||
type="text"
|
||||
class="form-control input-lg"
|
||||
name="email"
|
||||
value="{{ magic_form.email.value|default:"" }}"
|
||||
placeholder="you@example.org">
|
||||
|
||||
<p id="link-instruction">
|
||||
We will email you a magic sign in link.
|
||||
</p>
|
||||
|
||||
<div id="password-block" class="form-group {% if not show_password %} hide {% endif %}">
|
||||
<div class="input-group input-group-lg">
|
||||
<div class="input-group-addon">
|
||||
<span class="icon-dots"></span>
|
||||
</div>
|
||||
<input
|
||||
type="password"
|
||||
class="form-control"
|
||||
name="password"
|
||||
placeholder="password">
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="clearfix">
|
||||
<button type="submit" class="btn btn-lg btn-primary pull-right">
|
||||
Log In
|
||||
<button type="submit" class="btn btn-lg btn-primary btn-block">
|
||||
Email Me a Link
|
||||
</button>
|
||||
</form>
|
||||
<div id="login-sep" class="hidden-xs"><div>or</div></div>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 visible-xs-block">
|
||||
<div id="xs-login-sep">
|
||||
<div>or</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-6">
|
||||
<form id="login-form" method="post">
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="action" value="login" />
|
||||
|
||||
{% if form.non_field_errors %}
|
||||
<p class="text-danger">Incorrect email or password.</p>
|
||||
{% else %}
|
||||
<p>
|
||||
Enter your <strong>email address</strong> and <strong>password</strong>.
|
||||
</p>
|
||||
{% endif %}
|
||||
|
||||
<input
|
||||
type="text"
|
||||
class="form-control input-lg"
|
||||
name="email"
|
||||
value="{{ form.email.value|default:"" }}"
|
||||
placeholder="you@example.org">
|
||||
|
||||
<input
|
||||
type="password"
|
||||
class="form-control input-lg"
|
||||
name="password"
|
||||
placeholder="your password">
|
||||
|
||||
<button type="submit" class="btn btn-lg btn-primary btn-block">
|
||||
Sign In
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -82,6 +87,7 @@
|
||||
{% block scripts %}
|
||||
{% compress js %}
|
||||
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
|
||||
<script src="{% static 'js/bootstrap.min.js' %}"></script>
|
||||
<script src="{% static 'js/login.js' %}"></script>
|
||||
{% endcompress %}
|
||||
{% endblock %}
|
||||
|
@ -42,6 +42,7 @@
|
||||
<link rel="stylesheet" href="{% static 'css/checkbox.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/radio.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/billing.css' %}" type="text/css">
|
||||
<link rel="stylesheet" href="{% static 'css/login.css' %}" type="text/css">
|
||||
{% endcompress %}
|
||||
</head>
|
||||
<body class="page-{{ page }}">
|
||||
@ -109,14 +110,6 @@
|
||||
|
||||
</ul>
|
||||
|
||||
|
||||
{% if request.user.is_authenticated %}
|
||||
{% else %}
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="{% url 'hc-login' %}">Log In</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
|
||||
{% if request.user.is_authenticated %}
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
@ -148,6 +141,10 @@
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
{% elif page != "login" %}
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li><a href="{% url 'hc-login' %}">Log In</a></li>
|
||||
</ul>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user