From f1d63c5b1bdccb5b730890e5e23ae8fbd062b373 Mon Sep 17 00:00:00 2001 From: Edward Date: Fri, 9 Mar 2018 14:34:39 -0300 Subject: [PATCH] =?UTF-8?q?[N=C3=83O=20FA=C3=87A=20MERGE=20AINDA]=20Fix=20?= =?UTF-8?q?#1725=20(#1740)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fix #1725 - Adiciona tela de admin ao SAPL --- sapl/base/forms.py | 96 ++++++++++++++++++++++- sapl/base/urls.py | 12 ++- sapl/base/views.py | 119 ++++++++++++++++++++++++++++- sapl/templates/auth/user_form.html | 14 ++++ sapl/templates/auth/user_list.html | 33 ++++++++ sapl/templates/navbar.yaml | 2 +- 6 files changed, 269 insertions(+), 7 deletions(-) create mode 100644 sapl/templates/auth/user_form.html create mode 100644 sapl/templates/auth/user_list.html diff --git a/sapl/base/forms.py b/sapl/base/forms.py index cdc6d25c8..7cdf950c6 100644 --- a/sapl/base/forms.py +++ b/sapl/base/forms.py @@ -22,7 +22,7 @@ from sapl.settings import MAX_IMAGE_UPLOAD_SIZE from sapl.utils import (RANGE_ANOS, ChoiceWithoutValidationField, ImageThumbnailFileInput, RangeWidgetOverride, autor_label, autor_modal, models_with_gr_for_model, - qs_override_django_filter) + qs_override_django_filter, YES_NO_CHOICES) from .models import AppConfig, CasaLegislativa @@ -40,6 +40,100 @@ STATUS_USER_CHOICE = [ ('X', _('Excluir Usuário')), ] +class UsuarioCreateForm(ModelForm): + + username = forms.CharField(required=True, label="Nome de usuário") + firstname = forms.CharField(required=True, label="Nome") + lastname = forms.CharField(required=True, label="Sobrenome") + password1 = forms.CharField(required=True, widget=forms.PasswordInput, label='Senha') + password2 = forms.CharField(required=True, widget=forms.PasswordInput, label='Confirmar senha') + user_active = forms.ChoiceField(required=False, choices=YES_NO_CHOICES, label="Usuário ativo?", initial='True') + + ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')] + + roles = forms.MultipleChoiceField(required=True, widget=forms.CheckboxSelectMultiple(), choices=ROLES) + + class Meta: + model = get_user_model() + fields = ['username', 'firstname', 'lastname', 'email', 'password1', 'password2', 'user_active', 'roles'] + + def clean(self): + super(UsuarioCreateForm, self).clean() + + if not self.is_valid(): + return self.cleaned_data + + data = self.cleaned_data + if data['password1'] != data['password2']: + raise ValidationError('Senhas informadas são diferentes') + + def __init__(self, *args, **kwargs): + + super(UsuarioCreateForm, self).__init__(*args, **kwargs) + + row0 = to_row([('username', 12)]) + + row1 = to_row([('firstname', 6), + ('lastname', 6)]) + + row2 = to_row([('email', 6), + ('user_active', 6)]) + row3 = to_row( + [('password1', 6), + ('password2', 6)]) + + row4 = to_row([(form_actions(label='Confirmar'), 6)]) + + self.helper = FormHelper() + self.helper.layout = Layout( + row0, + row1, + row3, + row2, + 'roles', + row4) + +class UsuarioEditForm(ModelForm): + ROLES = [(g.id, g.name) for g in Group.objects.all().order_by('name')] + + password1 = forms.CharField(required=False, widget=forms.PasswordInput, label='Senha') + password2 = forms.CharField(required=False, widget=forms.PasswordInput, label='Confirmar senha') + user_active = forms.ChoiceField(choices=YES_NO_CHOICES, required=True, label="Usuário ativo?", initial='True') + roles = forms.MultipleChoiceField(required=True, widget=forms.CheckboxSelectMultiple(), choices=ROLES) + + class Meta: + model = get_user_model() + fields = ['email', 'password1', 'password2', 'user_active', 'roles'] + + def __init__(self, *args, **kwargs): + + super(UsuarioEditForm, self).__init__(*args, **kwargs) + + row1 = to_row([('email', 6), + ('user_active', 6)]) + row2 = to_row( + [('password1', 6), + ('password2', 6)]) + + row3 = to_row([(form_actions(label='Salvar Alterações'), 6)]) + + self.helper = FormHelper() + self.helper.layout = Layout( + row1, + row2, + 'roles', + row3) + + def clean(self): + super(UsuarioEditForm, self).clean() + + if not self.is_valid(): + return self.cleaned_data + + data = self.cleaned_data + if data['password1'] and data['password1'] != data['password2']: + raise ValidationError('Senhas informadas são diferentes') + class TipoAutorForm(ModelForm): diff --git a/sapl/base/urls.py b/sapl/base/urls.py index 3b7d76e40..e1e2e1c00 100644 --- a/sapl/base/urls.py +++ b/sapl/base/urls.py @@ -17,10 +17,18 @@ from .views import (AlterarSenha, AppConfigCrud, CasaLegislativaCrud, RelatorioMateriasPorAutorView, RelatorioMateriasTramitacaoView, RelatorioPresencaSessaoView, SaplSearchView, - RelatorioDataFimPrazoTramitacaoView) + RelatorioDataFimPrazoTramitacaoView, ListarUsuarioView, EditUsuarioView, CreateUsuarioView, + DeleteUsuarioView) app_name = AppConfig.name +admin_user = [ + url(r'^sistema/usuario/$', ListarUsuarioView.as_view(), name='user_list'), + url(r'^sistema/usuario/create$', CreateUsuarioView.as_view(), name='user_create'), + url(r'^sistema/usuario/(?P\d+)/edit$', EditUsuarioView.as_view(), name='user_edit'), + url(r'^sistema/usuario/(?P\d+)/delete$', DeleteUsuarioView.as_view(), name='user_delete') +] + alterar_senha = [ url(r'^sistema/alterar-senha/$', AlterarSenha.as_view(), @@ -111,4 +119,4 @@ urlpatterns = [ url(r'^sistema/search/', SaplSearchView(), name='haystack_search'), -] + recuperar_senha + alterar_senha +] + recuperar_senha + alterar_senha + admin_user diff --git a/sapl/base/views.py b/sapl/base/views.py index 386364420..e2bdcef3f 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -1,5 +1,6 @@ from django.conf import settings from django.contrib.auth import get_user_model, update_session_auth_hash +from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.models import Group from django.contrib.auth.tokens import default_token_generator from django.core.exceptions import ObjectDoesNotExist, PermissionDenied @@ -13,13 +14,13 @@ from django.utils.encoding import force_bytes from django.utils.http import urlsafe_base64_decode, urlsafe_base64_encode from django.utils.translation import ugettext_lazy as _ from django.utils.translation import string_concat -from django.views.generic import FormView +from django.views.generic import FormView, ListView, DetailView, UpdateView, CreateView, DeleteView from django.views.generic.base import TemplateView from django_filters.views import FilterView from haystack.views import SearchView from sapl.base.forms import AutorForm, AutorFormForAdmin, TipoAutorForm from sapl.base.models import Autor, TipoAutor -from sapl.crud.base import CrudAux +from sapl.crud.base import (CrudAux, make_pagination) from sapl.materia.models import (Autoria, MateriaLegislativa, TipoMateriaLegislativa) from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria, @@ -34,7 +35,7 @@ from .forms import (AlterarSenhaForm, CasaLegislativaForm, RelatorioMateriasPorAutorFilterSet, RelatorioMateriasTramitacaoilterSet, RelatorioPresencaSessaoFilterSet, - RelatorioDataFimPrazoTramitacaoFilterSet) + RelatorioDataFimPrazoTramitacaoFilterSet, UsuarioEditForm, UsuarioCreateForm) from .models import AppConfig, CasaLegislativa @@ -520,6 +521,118 @@ class RelatorioMateriasPorAutorView(FilterView): return context +class ListarUsuarioView(PermissionRequiredMixin, ListView): + model = get_user_model() + template_name = 'auth/user_list.html' + context_object_name = 'user_list' + permission_required = ('base.list_appconfig',) + paginate_by = 10 + + def get_queryset(self): + qs = super(ListarUsuarioView, self).get_queryset() + return qs.order_by('username') + + def get_context_data(self, **kwargs): + context = super(ListarUsuarioView, self).get_context_data(**kwargs) + paginator = context['paginator'] + page_obj = context['page_obj'] + context['page_range'] = make_pagination( + page_obj.number, paginator.num_pages) + context['NO_ENTRIES_MSG'] = 'Nenhum usuário cadastrado.' + return context + + +class CreateUsuarioView(PermissionRequiredMixin, CreateView): + model = get_user_model() + form_class = UsuarioCreateForm + success_message = 'Usuário criado com sucesso' + permission_required = ('base.add_appconfig',) + + def get_success_url(self): + return reverse('sapl.base:user_list') + + def form_valid(self, form): + + data = form.cleaned_data + + new_user = get_user_model().objects.create(username=data['username'], email=data['email']) + new_user.first_name = data['firstname'] + new_user.last_name = data['lastname'] + new_user.set_password(data['password1']) + new_user.is_superuser = False + new_user.is_staff = False + new_user.save() + + groups = Group.objects.filter(id__in=data['roles']) + for g in groups: + g.user_set.add(new_user) + + return HttpResponseRedirect(self.get_success_url()) + +class DeleteUsuarioView(PermissionRequiredMixin, DeleteView): + + model = get_user_model() + permission_required = ('base.delete_appconfig',) + + def get_success_url(self): + return reverse('sapl.base:user_list') + + def get(self, request, *args, **kwargs): + return self.post(request, *args, **kwargs) + + def get_queryset(self): + qs = super(DeleteUsuarioView, self).get_queryset() + return qs.filter(id=self.kwargs['pk']) + + + +class EditUsuarioView(PermissionRequiredMixin, UpdateView): + model = get_user_model() + form_class = UsuarioEditForm + success_message = 'Usuário editado com sucesso' + permission_required = ('base.change_appconfig',) + + def get_success_url(self): + return reverse('sapl.base:user_list') + + def get_initial(self): + initial = super(EditUsuarioView, self).get_initial() + + user = get_user_model().objects.get(id=self.kwargs['pk']) + roles = [str(g.id) for g in user.groups.all()] + initial['roles'] = roles + initial['user_active'] = user.is_active + + return initial + + def form_valid(self, form): + + user = form.save(commit=False) + data = form.cleaned_data + + # new_user.first_name = data['firstname'] + # new_user.last_name = data['lastname'] + + if data['password1']: + user.set_password(data['password1']) + + if data['user_active'] == 'True' and not user.is_active: + user.is_active = True + elif data['user_active'] == 'False' and user.is_active: + user.is_active = False + + user.save() + + for g in user.groups.all(): + g.user_set.remove(user) + + groups = Group.objects.filter(id__in=data['roles']) + for g in groups: + g.user_set.add(user) + + return super(EditUsuarioView, self).form_valid(form) + + class CasaLegislativaCrud(CrudAux): model = CasaLegislativa diff --git a/sapl/templates/auth/user_form.html b/sapl/templates/auth/user_form.html new file mode 100644 index 000000000..3b19ee162 --- /dev/null +++ b/sapl/templates/auth/user_form.html @@ -0,0 +1,14 @@ +{% extends "base.html" %} +{% load i18n crispy_forms_tags %} + +{% block base_content %} + +
+ {% csrf_token %} + {% crispy form %} + {% if object.pk %} + Remover usuário + {% endif %} +
+ +{% endblock base_content %} \ No newline at end of file diff --git a/sapl/templates/auth/user_list.html b/sapl/templates/auth/user_list.html new file mode 100644 index 000000000..d1f45fca6 --- /dev/null +++ b/sapl/templates/auth/user_list.html @@ -0,0 +1,33 @@ +{% extends "base.html" %} +{% load i18n %} +{% load tz %} +{% load common_tags %} +{% block base_content %} +
+

Lista de usuários

+ {% if not user_list %} +

{{ NO_ENTRIES_MSG }}

+ {% else %} + + + + + + + + + {% for user in user_list %} + + + + + {% endfor %} + +
Nome de UsuárioE-mail do Usuário
+ {{ user.username }} + {{ user.email }}
+ {% endif %} + Criar Usuário +
+ {% include 'paginacao.html'%} +{% endblock base_content %} \ No newline at end of file diff --git a/sapl/templates/navbar.yaml b/sapl/templates/navbar.yaml index c9411cb5c..934557aea 100644 --- a/sapl/templates/navbar.yaml +++ b/sapl/templates/navbar.yaml @@ -68,7 +68,7 @@ url: '/sistema' check_permission: base.view_tabelas_auxiliares - title: {% trans 'Administração de Usuários' %} - url: '/admin' + url: {% url 'sapl.base:user_list' %} check_permission: user.is_superuser {% comment %}