From e318a2c02b119655a14f7018ba180501c6c01e9a Mon Sep 17 00:00:00 2001 From: Marcio Mazza Date: Thu, 14 Apr 2016 13:06:02 -0300 Subject: [PATCH 1/3] =?UTF-8?q?Inicia=20implementa=C3=A7=C3=A3o=20do=20log?= =?UTF-8?q?in=20simples?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- base/tests/test_login.py | 74 +++++++++++++++++++++++++++++++++++++ base/tests/teststub_urls.py | 8 ++++ base/urls.py | 5 ++- base/views.py | 42 ++++++++++++++++++++- templates/base.html | 13 +++++++ 5 files changed, 140 insertions(+), 2 deletions(-) create mode 100644 base/tests/test_login.py create mode 100644 base/tests/teststub_urls.py diff --git a/base/tests/test_login.py b/base/tests/test_login.py new file mode 100644 index 000000000..78cacf4a4 --- /dev/null +++ b/base/tests/test_login.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +import pytest +from django.contrib.auth.models import User +from django.test.html import parse_html as html + + +pytestmark = pytest.mark.django_db + +@pytest.fixture +def user(): + return User.objects.create_user('jfirmino', password='123') + +def test_login_aparece_na_barra_para_usuario_nao_logado(client): + response = client.get('/') + assert 'Login' in response.content + +def test_username_do_usuario_logado_aparece_na_barra(client, user): + assert client.login(username='jfirmino', password='123') + response = client.get('/') + assert html('Login') not in html(response.content) + assert 'jfirmino' in response.content + assert html('Sair') in html(response.content) + +def test_nome_completo_do_usuario_logado_aparece_na_barra(client, user): + # nome completo para o usuario + user.first_name = 'Joao' + user.last_name = 'Firmino' + user.save() + assert client.login(username='jfirmino', password='123') + response = client.get('/') + assert html('Login') not in html(response.content) + assert 'Joao Firmino' in response.content + assert html('Sair') in html(response.content) + +@pytest.mark.parametrize("link_login,destino", [ + # login a partir de uma pagina retorna para ela mesma + ('/login/?next=/zzzz', 'http://testserver/zzzz'), + ('/login/?next=/', 'http://testserver/'), + # login a partir da propria pagina de login redireciona para home + ('/login/?next=/login/', 'http://testserver/'), + # link sem destino de retorno (next) redireciona para home + ('/login/', 'http://testserver/'), +]) +def test_login(app, user, link_login, destino): + pagina_login = app.get(link_login) + form = pagina_login.forms['login-form'] + form['username'] = 'jfirmino' + form['password'] = '123' + res = form.submit() + + assert user.pk == app.session['_auth_user_id'] + assert res.url == destino + +@pytest.mark.urls('home.teststub_urls') +@pytest.mark.parametrize("link_logout,destino", [ + # logout a partir de uma pagina retorna para ela mesma + ('/logout/?next=/zzzz', 'http://testserver/zzzz'), + ('/logout/?next=/', 'http://testserver/'), + # logout a partir da propria pagina de logout redireciona para home + ('/logout/?next=/logout/', 'http://testserver/'), + # link sem destino de retorno (next) redireciona para home + ('/logout/', 'http://testserver/'), +]) +def test_logout(client, user, link_logout, destino): + # com um usuário logado ... + assert client.login(username='jfirmino', password='123') + assert user.pk == client.session['_auth_user_id'] + + # ... acionamos o link de logout + res = client.get(link_logout, follow=True) + destino_real = res.redirect_chain[-1][0] + + assert '_auth_user_id' not in client.session + assert destino_real == destino diff --git a/base/tests/teststub_urls.py b/base/tests/teststub_urls.py new file mode 100644 index 000000000..b244287fc --- /dev/null +++ b/base/tests/teststub_urls.py @@ -0,0 +1,8 @@ +from django.conf.urls import patterns, url + +from sapl.urls import urlpatterns as original_patterns + + +urlpatterns = original_patterns + patterns('', + url(r'^zzzz$', 'home.views.index', name='zzzz'), +) diff --git a/base/urls.py b/base/urls.py index 4ddb4532a..cb3154934 100644 --- a/base/urls.py +++ b/base/urls.py @@ -3,7 +3,7 @@ from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.views.generic.base import TemplateView from .apps import AppConfig -from .views import CasaLegislativaTableAuxView, HelpView +from .views import CasaLegislativaTableAuxView, HelpView, login, logout app_name = AppConfig.name @@ -14,6 +14,9 @@ urlpatterns = [ name='help_base'), url(r'^casa-legislativa$', CasaLegislativaTableAuxView.as_view(), name='casa_legislativa'), + + url(r'^login/$', login, name='login'), + url(r'^logout/$', logout, name='logout'), ] # Fix a static asset finding error on Django 1.9 + gunicorn: diff --git a/base/views.py b/base/views.py index 1950ce99a..f69fc5b5d 100644 --- a/base/views.py +++ b/base/views.py @@ -1,11 +1,17 @@ import os from functools import lru_cache +import django.contrib.auth.views +from crispy_forms.helper import FormHelper +from crispy_forms.layout import Hidden, Submit from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse +from django.http import HttpResponseRedirect +from django.shortcuts import render from django.views.generic import FormView from django.views.generic.base import TemplateView +from .areas import areas_em_pares from .forms import CasaLegislativaTabelaAuxForm from .models import CasaLegislativa @@ -42,7 +48,7 @@ class CasaLegislativaTableAuxView(FormView): casa = CasaLegislativa.objects.first() if casa: if ("remover" in request.POST or - (form.cleaned_data['logotipo'] and casa.logotipo)): + (form.cleaned_data['logotipo'] and casa.logotipo)): try: os.unlink(casa.logotipo.path) except OSError: @@ -65,3 +71,37 @@ class CasaLegislativaTableAuxView(FormView): def get_success_url(self): return reverse('base:casa_legislativa') + + +def index(request): + """Página Inicial""" + + return render(request, 'home.html', {'areas': areas_em_pares}) + + +def login(request): + """Página de Login""" + + helper = FormHelper() + helper.form_id = 'login-form' + helper.form_class = 'form-horizontal' + helper.label_class = 'col-lg-1' + helper.field_class = 'col-lg-3' + helper.form_method = 'post' + + login_path = reverse('base:login') + helper.form_action = login_path + + next_path = request.REQUEST.get('next', '/') + if next_path == login_path: + next_path = '/' + helper.add_input(Hidden('next', next_path)) + helper.add_input(Submit('submit', 'Submit')) + + return django.contrib.auth.views.login(request, + extra_context={'helper': helper}) + + +def logout(request): + django.contrib.auth.views.logout(request) + return HttpResponseRedirect(request.GET.get('next', '/')) diff --git a/templates/base.html b/templates/base.html index e14cb7d89..6d5017f18 100644 --- a/templates/base.html +++ b/templates/base.html @@ -102,6 +102,19 @@ + + From 9954890316c877503f40ce57f0a901012965a783 Mon Sep 17 00:00:00 2001 From: Eduardo Calil Date: Mon, 18 Apr 2016 13:51:24 -0300 Subject: [PATCH 2/3] Cria o Login --- base/forms.py | 12 +++++++ base/urls.py | 11 +++++-- base/views.py | 39 ----------------------- sapl/settings.py | 1 + templates/base.html | 13 ++++++-- templates/base/login.html | 67 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 98 insertions(+), 45 deletions(-) create mode 100644 templates/base/login.html diff --git a/base/forms.py b/base/forms.py index d0e660312..838008f66 100644 --- a/base/forms.py +++ b/base/forms.py @@ -1,6 +1,7 @@ from crispy_forms.helper import FormHelper from crispy_forms.layout import HTML, Fieldset, Layout from django import forms +from django.contrib.auth.forms import AuthenticationForm from django.core.exceptions import ValidationError from django.forms import ModelForm from django.utils.translation import ugettext_lazy as _ @@ -108,3 +109,14 @@ class CasaLegislativaTabelaAuxForm(ModelForm): ) ) super(CasaLegislativaTabelaAuxForm, self).__init__(*args, **kwargs) + + +class LoginForm(AuthenticationForm): + username = forms.CharField(label="Username", max_length=30, + widget=forms.TextInput( + attrs={ + 'class': 'form-control', 'name': 'username'})) + password = forms.CharField(label="Password", max_length=30, + widget=forms.TextInput( + attrs={ + 'class': 'form-control', 'name': 'password'})) diff --git a/base/urls.py b/base/urls.py index cb3154934..0a4caad73 100644 --- a/base/urls.py +++ b/base/urls.py @@ -1,12 +1,15 @@ from django.conf.urls import url +from django.contrib.auth import views from django.contrib.staticfiles.urls import staticfiles_urlpatterns from django.views.generic.base import TemplateView from .apps import AppConfig -from .views import CasaLegislativaTableAuxView, HelpView, login, logout +from .forms import LoginForm +from .views import CasaLegislativaTableAuxView, HelpView app_name = AppConfig.name + urlpatterns = [ url(r'^sistema/', TemplateView.as_view(template_name='sistema.html')), url(r'^ajuda/(?P\w+)$', HelpView.as_view(), name='help_topic'), @@ -15,8 +18,10 @@ urlpatterns = [ url(r'^casa-legislativa$', CasaLegislativaTableAuxView.as_view(), name='casa_legislativa'), - url(r'^login/$', login, name='login'), - url(r'^logout/$', logout, name='logout'), + url(r'^login/$', views.login, { + 'template_name': 'base/login.html', 'authentication_form': LoginForm}, + name='login'), + url(r'^logout/$', views.logout, {'next_page': '/login'}, name='logout') ] # Fix a static asset finding error on Django 1.9 + gunicorn: diff --git a/base/views.py b/base/views.py index f69fc5b5d..9ee21b2c4 100644 --- a/base/views.py +++ b/base/views.py @@ -1,17 +1,11 @@ import os from functools import lru_cache -import django.contrib.auth.views -from crispy_forms.helper import FormHelper -from crispy_forms.layout import Hidden, Submit from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse -from django.http import HttpResponseRedirect -from django.shortcuts import render from django.views.generic import FormView from django.views.generic.base import TemplateView -from .areas import areas_em_pares from .forms import CasaLegislativaTabelaAuxForm from .models import CasaLegislativa @@ -72,36 +66,3 @@ class CasaLegislativaTableAuxView(FormView): def get_success_url(self): return reverse('base:casa_legislativa') - -def index(request): - """Página Inicial""" - - return render(request, 'home.html', {'areas': areas_em_pares}) - - -def login(request): - """Página de Login""" - - helper = FormHelper() - helper.form_id = 'login-form' - helper.form_class = 'form-horizontal' - helper.label_class = 'col-lg-1' - helper.field_class = 'col-lg-3' - helper.form_method = 'post' - - login_path = reverse('base:login') - helper.form_action = login_path - - next_path = request.REQUEST.get('next', '/') - if next_path == login_path: - next_path = '/' - helper.add_input(Hidden('next', next_path)) - helper.add_input(Submit('submit', 'Submit')) - - return django.contrib.auth.views.login(request, - extra_context={'helper': helper}) - - -def logout(request): - django.contrib.auth.views.logout(request) - return HttpResponseRedirect(request.GET.get('next', '/')) diff --git a/sapl/settings.py b/sapl/settings.py index a9900084b..b3361ae9c 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -30,6 +30,7 @@ DEBUG = config('DEBUG', default=False, cast=bool) ALLOWED_HOSTS = ['*'] +LOGIN_REDIRECT_URL = '/' # SAPL business apps in dependency order SAPL_APPS = ( diff --git a/templates/base.html b/templates/base.html index 6d5017f18..87ff23dfb 100644 --- a/templates/base.html +++ b/templates/base.html @@ -103,14 +103,21 @@ diff --git a/templates/base/login.html b/templates/base/login.html new file mode 100644 index 000000000..f167217aa --- /dev/null +++ b/templates/base/login.html @@ -0,0 +1,67 @@ +{% extends "crud/detail.html" %} +{% load i18n %} +{% block base_content %} + + {% if form.errors %} + +

Usuário e/ou Senha inexistente. Tente novamente.

+ {% endif %} + + {% if next %} + {% if user.is_authenticated %} +

Você não tem acesso a esta página. Se quiser continuar, faça o Login.

+ + {% else %} +

Por favor, faça o Login para acessar esta página.

+ {% endif %} + + {% endif %} + +
+
+
+ +
+
+
+ +{% endblock base_content %} + + {% block javascript %} + + + + + {% endblock %} From 45379a8eb078c62449df299a7c0d88f590c92ce8 Mon Sep 17 00:00:00 2001 From: Eduardo Calil Date: Tue, 19 Apr 2016 11:43:15 -0300 Subject: [PATCH 3/3] Melhora a mensagem de erro no Login --- base/views.py | 1 - sapl/settings.py | 1 + templates/base/login.html | 10 +++++----- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/base/views.py b/base/views.py index 9ee21b2c4..2e801a3c5 100644 --- a/base/views.py +++ b/base/views.py @@ -65,4 +65,3 @@ class CasaLegislativaTableAuxView(FormView): def get_success_url(self): return reverse('base:casa_legislativa') - diff --git a/sapl/settings.py b/sapl/settings.py index b3361ae9c..1673ebf84 100644 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -31,6 +31,7 @@ DEBUG = config('DEBUG', default=False, cast=bool) ALLOWED_HOSTS = ['*'] LOGIN_REDIRECT_URL = '/' +LOGIN_URL = '/login/?next=' # SAPL business apps in dependency order SAPL_APPS = ( diff --git a/templates/base/login.html b/templates/base/login.html index f167217aa..e091ef5a3 100644 --- a/templates/base/login.html +++ b/templates/base/login.html @@ -2,11 +2,6 @@ {% load i18n %} {% block base_content %} - {% if form.errors %} - -

Usuário e/ou Senha inexistente. Tente novamente.

- {% endif %} - {% if next %} {% if user.is_authenticated %}

Você não tem acesso a esta página. Se quiser continuar, faça o Login.

@@ -30,6 +25,11 @@

+ {% if form.errors %} +
Usuário e/ou Senha inexistente. +
+ + {% endif %}
Usuário {{ form.username }}