Commit f98df110 authored by delanoe's avatar delanoe

[FEAT] Login page with feedback in case of errors + CSS fix + secured.

parent c12ad2a7
from gargantext.util.http import *
from django.contrib.auth import authenticate, login, logout
from django.core.urlresolvers import reverse_lazy
from django.views.generic import FormView
from django.shortcuts import redirect
from gargantext.models.users import User
from django import forms
from django.contrib import auth
from gargantext.views.pages.projects import overview
from gargantext.views.pages.forms import AuthenticationForm
def login(request):
"""Performs user login
"""
auth.logout(request)
# if the user send her authentication data to the page
if request.method == "POST":
# /!\ pass is sent clear in POST data: use SSL
user = auth.authenticate(
username = request.POST['username'],
password = request.POST['password']
)
if user is not None and user.is_active:
auth.login(request, user)
# if "next" forwarded from the GET via the template form
if 'the_next_page' in request.POST:
return redirect(request.POST['the_next_page'])
else:
return redirect('/projects/')
class LoginView(FormView):
form_class = AuthenticationForm
success_url = reverse_lazy(overview) #A la place de profile_view, choisir n'importe quelle vue
template_name = 'pages/main/login.html'
# if the user wants to access the login form
additional_context = {}
# if for exemple: auth/?next=/project/5/corpus/554/document/556/
# => we'll forward ?next="..." into template with form
if 'next' in request.GET:
additional_context = {'next_page':request.GET['next']}
def form_valid(self, form):
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(username=username, password=password)
return render(
template_name = 'pages/auth/login.html',
request = request,
context = additional_context,
)
if user is not None and user.is_active:
login(self.request, user)
return super(LoginView, self).form_valid(form)
else:
return self.form_invalid(form)
def logout(request):
def out(request):
"""Logout the user, and redirect to main page
"""
auth.logout(request)
logout(request)
return redirect('/')
from django import forms
from django.contrib.auth import (
authenticate, get_user_model, password_validation,
)
from django.contrib.auth.hashers import (
UNUSABLE_PASSWORD_PREFIX, identify_hasher,
)
from django.utils.html import format_html, format_html_join
from django.utils.text import capfirst
from django.utils.translation import ugettext, ugettext_lazy as _
from gargantext.models.users import User
class AuthenticationForm(forms.Form):
"""
Base class for authenticating users. Extend this to get a form that accepts
username/password logins.
"""
username = forms.CharField(max_length=254, widget=forms.TextInput(attrs={'class':"form-control", 'placeholder': "username"}))
password = forms.CharField(label=_("Password"), strip=False, widget=forms.PasswordInput(attrs={'class':'form-control', 'placeholder': 'Password'}))
error_messages = {
'invalid_login': _("Please enter a correct %(username)s and password. "
"Note that both fields may be case-sensitive."),
'inactive': _("This account is inactive."),
}
def __init__(self, request=None, *args, **kwargs):
"""
The 'request' parameter is set for custom auth use by subclasses.
The form data comes in via the standard 'data' kwarg.
"""
self.request = request
self.user_cache = None
super(AuthenticationForm, self).__init__(*args, **kwargs)
# Set the label for the "username" field.
UserModel = get_user_model()
self.username_field = UserModel._meta.get_field(UserModel.USERNAME_FIELD)
if self.fields['username'].label is None:
self.fields['username'].label = capfirst(self.username_field.verbose_name)
def clean(self):
username = self.cleaned_data.get('username')
password = self.cleaned_data.get('password')
if username and password:
self.user_cache = authenticate(username=username,
password=password)
if self.user_cache is None:
raise forms.ValidationError(
'Invalid data'
)
else:
self.confirm_login_allowed(self.user_cache)
return self.cleaned_data
def confirm_login_allowed(self, user):
"""
Controls whether the given User may log in. This is a policy setting,
independent of end-user authentication. This default behavior is to
allow login by active users, and reject login by inactive users.
If the given user cannot log in, this method should raise a
``forms.ValidationError``.
If the given user may log in, this method should return None.
"""
if not user.is_active:
raise forms.ValidationError(
'Compte Inactif'
)
def get_user_id(self):
if self.user_cache:
return self.user_cache.id
return None
def get_user(self):
return self.user_cache
......@@ -10,6 +10,7 @@ from gargantext.util.toolchain import parse_extract_indexhyperdata
from datetime import datetime
from collections import defaultdict
from django.utils.translation import ugettext_lazy
import re
......@@ -57,7 +58,6 @@ def overview(request):
)
from django.utils.translation import ugettext_lazy
class NewCorpusForm(forms.Form):
type = forms.ChoiceField(
choices = enumerate(resource_type['name'] for resource_type in RESOURCETYPES),
......
from django.conf.urls import url
from . import main, auth
from . import main
from . import projects, corpora, terms
from .auth import LoginView, out
urlpatterns = [
......@@ -12,8 +13,8 @@ urlpatterns = [
# maintenance mode
url(r'^maintenance/?$', main.maintenance),
# authentication
url(r'^auth/login/?$', auth.login),
url(r'^auth/logout/?$', auth.logout),
url(r'^auth/login/?$' , LoginView.as_view()),
url(r'^auth/logout/?$', out),
# projects
url(r'^projects/?$' , projects.overview),
......
This source diff could not be displayed because it is too large. You can view the blob instead.
<!DOCTYPE html>
<html>
{% load staticfiles %}
<meta http-equiv="content-type" content="text/html;charset=UTF-8" />
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<title>Login | Gargantext</title>
<!-- Prevent the demo from appearing in search engines (REMOVE THIS) -->
<meta name="robots" content="noindex">
<!-- Material Design Icons -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<!-- Roboto Web Font -->
<link href="https://fonts.googleapis.com/css?family=Roboto:regular,bold,italic,thin,light,bolditalic,black,medium&amp;lang=en" rel="stylesheet">
<!-- App CSS -->
<link type="text/css" href="{% static "css/login.min.css" %}" rel="stylesheet">
</head>
<body class="login">
<div class="row">
<div class="col-sm-10 col-sm-push-1 col-md-6 col-md-push-3 col-lg-6 col-lg-push-3">
<h2 class="text-primary center m-a-2">
<i class="material-icons md-36">control_point</i> <span class="icon-text">Gargantext</span>
</h2>
<div class="card-group">
<div class="card">
<div class="card-block">
<div class="center">
<h4 class="m-b-0"><span class="icon-text">Connexion</span></h4>
<p class="text-muted">Login to your account</p>
</div>
{% if form.errors %}
<div class="alert alert-danger fade in">
<a href="#" class="close" data-dismiss="alert" aria-label="close" title="close">×</a>
<strong>{{form.non_field_errors}}</strong>
</div>
{% endif %}
<form action="" method="post">
{% csrf_token %}
<div class="form-group">
{{form.username}}
</div>
<div class="form-group">
{{form.password}}
<div class="clearfix"></div>
</div>
<div class="center">
<button type="submit" class="btn btn-primary btn-rounded">Login</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
<!-- jQuery -->
<script src="{% static "js/jquery/jquery.min.js" %}"></script>
<!-- Bootstrap -->
<script src="{% static "js/bootstrap/bootstrap.min.js" %}"></script>
</body>
</html>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment