From 2a2f17a8eb1e3b3fb838a14d040f80b19d4a69d9 Mon Sep 17 00:00:00 2001 From: LeandroRoberto Date: Mon, 3 Oct 2016 13:36:40 -0300 Subject: [PATCH] =?UTF-8?q?Ref.=20perms=20da=20app=20sessao=20e=20inclui?= =?UTF-8?q?=20valida=C3=A7=C3=A3o=20painel?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sapl/base/models.py | 11 +- sapl/base/templatetags/common_tags.py | 10 +- sapl/base/views.py | 2 +- sapl/crud/base.py | 21 ++- sapl/sessao/views.py | 189 ++++++++++++-------------- sapl/templates/sessao/subnav.yaml | 5 +- sapl/utils.py | 26 +++- 7 files changed, 152 insertions(+), 112 deletions(-) diff --git a/sapl/base/models.py b/sapl/base/models.py index cc2004455..a0a902702 100644 --- a/sapl/base/models.py +++ b/sapl/base/models.py @@ -107,6 +107,15 @@ class AppConfig(models.Model): ('view_tabelas_auxiliares', _('Visualizar Tabelas Auxiliares')), ) + @classmethod + def attr(cls, attr): + config = AppConfig.objects.first() + + if not config: + return '' + + return getattr(config, attr) + def __str__(self): return _('Configurações da Aplicação - %(id)s') % { 'id': self.id} @@ -204,4 +213,4 @@ def create_proxy_permissions( models.signals.post_migrate.connect( receiver=create_proxy_permissions, - dispatch_uid="django.contrib.auth.management.create_permissions") \ No newline at end of file + dispatch_uid="django.contrib.auth.management.create_permissions") diff --git a/sapl/base/templatetags/common_tags.py b/sapl/base/templatetags/common_tags.py index c926a485d..86205cef2 100644 --- a/sapl/base/templatetags/common_tags.py +++ b/sapl/base/templatetags/common_tags.py @@ -122,10 +122,12 @@ def ultima_filiacao(value): @register.filter def get_config_not_exists(user): - if not AppConfig.objects.all().exists(): - return True - else: - return False + return not AppConfig.objects.exists() + + +@register.filter +def get_config_attr(attribute): + return AppConfig.attr(attribute) @register.filter diff --git a/sapl/base/views.py b/sapl/base/views.py index fa3475a8d..b7d6378b8 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -1,5 +1,5 @@ -from braces.views import PermissionRequiredMixin +from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.urlresolvers import reverse from django.db.models import Count, Q from django.http import HttpResponseRedirect diff --git a/sapl/crud/base.py b/sapl/crud/base.py index 5e55acaff..e72a9b5c9 100644 --- a/sapl/crud/base.py +++ b/sapl/crud/base.py @@ -158,11 +158,25 @@ class ListWithSearchForm(forms.Form): ) +class PermissionRequiredForAppCrudMixin(PermissionRequiredMixin): + + def has_permission(self): + apps = self.app_label + if isinstance(apps, str): + apps = apps, + # papp_label vazio dará acesso geral + for app in apps: + if not self.request.user.has_module_perms(app): + return False + return True + + class PermissionRequiredContainerCrudMixin(PermissionRequiredMixin): def has_permission(self): perms = self.get_permission_required() - # Torna a view pública se não possuir o atributo permission_required + # Torna a view pública se não possuir conteudo + # no atributo permission_required return self.request.user.has_perms(perms) if len(perms) else True def dispatch(self, request, *args, **kwargs): @@ -673,7 +687,10 @@ class CrudDetailView(PermissionRequiredContainerCrudMixin, return DetailView.get_object(self, queryset=queryset) def get(self, request, *args, **kwargs): - self.object = self.model.objects.get(pk=kwargs.get('pk')) + try: + self.object = self.model.objects.get(pk=kwargs.get('pk')) + except: + raise Http404 obj = self.crud if hasattr(self, 'crud') else self if hasattr(obj, 'model_set') and obj.model_set: self.object_list = self.get_queryset() diff --git a/sapl/sessao/views.py b/sapl/sessao/views.py index acb31a2f9..f7e2201e9 100644 --- a/sapl/sessao/views.py +++ b/sapl/sessao/views.py @@ -1,9 +1,9 @@ from datetime import datetime from re import sub -from braces.views import PermissionRequiredMixin from django.contrib import messages from django.contrib.auth.decorators import permission_required +from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.urlresolvers import reverse from django.forms.utils import ErrorList @@ -19,8 +19,10 @@ from django.views.generic.edit import FormMixin from django_filters.views import FilterView from rest_framework import generics +from sapl.base.models import AppConfig as AppsAppConfig from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, - MasterDetailCrud, make_pagination) + MasterDetailCrud, make_pagination, + PermissionRequiredForAppCrudMixin) from sapl.materia.forms import pega_ultima_tramitacao from sapl.materia.models import (Autoria, DocumentoAcessorio, TipoMateriaLegislativa, Tramitacao) @@ -29,8 +31,9 @@ from sapl.norma.models import NormaJuridica from sapl.parlamentares.models import (Legislatura, Parlamentar, SessaoLegislativa) from sapl.sessao.apps import AppConfig +from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm from sapl.sessao.serializers import SessaoPlenariaSerializer -from sapl.utils import permissoes_painel, permissoes_sessao +from sapl.utils import permissoes_painel, permission_required_for_app from .forms import (AdicionarVariasMateriasFilterSet, ExpedienteForm, ListMateriaForm, MesaForm, PautaSessaoFilterSet, @@ -43,9 +46,9 @@ from .models import (Bancada, Bloco, CargoBancada, CargoMesa, SessaoPlenariaPresenca, TipoExpediente, TipoResultadoVotacao, TipoSessaoPlenaria, VotoParlamentar) + #OrdemDiaCrud = Crud.build(OrdemDia, '') #RegistroVotacaoCrud = Crud.build(RegistroVotacao, '') - TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria') TipoExpedienteCrud = CrudAux.build(TipoExpediente, 'tipo_expediente') CargoBancadaCrud = CrudAux.build(CargoBancada, '') @@ -129,12 +132,14 @@ class MateriaOrdemDiaCrud(MasterDetailCrud): 'resultado'] class CreateView(MasterDetailCrud.CreateView): + form_class = OrdemDiaForm def get_success_url(self): return reverse('sapl.sessao:ordemdia_list', kwargs={'pk': self.kwargs['pk']}) class UpdateView(MasterDetailCrud.UpdateView): + form_class = OrdemDiaForm def get_initial(self): self.initial['tipo_materia'] = self.object.materia.tipo.id @@ -299,35 +304,40 @@ class ExpedienteMateriaCrud(MasterDetailCrud): obj.resultado = btn_abrir else: url = '' - if obj.tipo_votacao == 1: - url = reverse('sapl.sessao:votacaosimbolicaexpedit', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.materia_id, - 'mid': obj.pk}) - elif obj.tipo_votacao == 2: - url = reverse('sapl.sessao:votacaonominalexpedit', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.materia_id, - 'mid': obj.pk}) - elif obj.tipo_votacao == 3: - url = reverse('sapl.sessao:votacaosecretaexpedit', - kwargs={ - 'pk': obj.sessao_plenaria_id, - 'oid': obj.materia_id, - 'mid': obj.pk}) - obj.resultado = '%s' % (url, - obj.resultado) + + if self.request.user.has_module_perms(AppConfig.label): + if obj.tipo_votacao == 1: + url = reverse( + 'sapl.sessao:votacaosimbolicaexpedit', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.materia_id, + 'mid': obj.pk}) + elif obj.tipo_votacao == 2: + url = reverse('sapl.sessao:votacaonominalexpedit', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.materia_id, + 'mid': obj.pk}) + elif obj.tipo_votacao == 3: + url = reverse('sapl.sessao:votacaosecretaexpedit', + kwargs={ + 'pk': obj.sessao_plenaria_id, + 'oid': obj.materia_id, + 'mid': obj.pk}) + obj.resultado = '%s' % (url, + obj.resultado) return [self._as_row(obj) for obj in object_list] class CreateView(MasterDetailCrud.CreateView): + form_class = ExpedienteMateriaForm def get_success_url(self): return reverse('sapl.sessao:expedientemateria_list', kwargs={'pk': self.kwargs['pk']}) class UpdateView(MasterDetailCrud.UpdateView): + form_class = ExpedienteMateriaForm def get_initial(self): self.initial['tipo_materia'] = self.object.materia.tipo.id @@ -393,9 +403,6 @@ class SessaoCrud(Crud): list_field_names = ['data_inicio', 'legislatura', 'sessao_legislativa', 'tipo'] - class CrudDetailView(DetailView): - model = SessaoPlenaria - class ListView(Crud.ListView): ordering = ['-data_inicio'] @@ -409,6 +416,13 @@ class SessaoCrud(Crud): 'sessao_legislativa': sessao_legislativa} +class SessaoPermissionMixin(PermissionRequiredForAppCrudMixin, + FormMixin, + DetailView): + model = SessaoPlenaria + app_label = AppConfig.label, + + class PresencaMixin: def get_presencas(self): @@ -445,14 +459,7 @@ class PresencaView(FormMixin, PresencaMixin, DetailView): form_class = PresencaForm model = SessaoPlenaria - @method_decorator(permission_required(( - '%s.add_%s' % ( - AppConfig.label, SessaoPlenariaPresenca._meta.model_name), - '%s.change_%s' % ( - AppConfig.label, SessaoPlenariaPresenca._meta.model_name), - '%s.delete_%s' % ( - AppConfig.label, SessaoPlenariaPresenca._meta.model_name), - ))) + @method_decorator(permission_required_for_app(AppConfig.label)) def post(self, request, *args, **kwargs): self.object = self.get_object() form = self.get_form() @@ -492,9 +499,31 @@ class PresencaView(FormMixin, PresencaMixin, DetailView): return reverse('sapl.sessao:presenca', kwargs={'pk': pk}) -class PainelView(PermissionRequiredMixin, TemplateView): +class PainelView(PermissionRequiredForAppCrudMixin, TemplateView): template_name = 'sessao/painel.html' - permission_required = permissoes_painel() + app_label = 'painel' + + def has_permission(self): + painel_aberto = AppsAppConfig.attr('painel_aberto') + + if painel_aberto and self.request.user.is_anonymous(): + return True + + return PermissionRequiredForAppCrudMixin.has_permission(self) + + def get(self, request, *args, **kwargs): + if request.user.is_anonymous(): + self.template_name = 'painel/index.html' + return TemplateView.get(self, request, *args, **kwargs) + + def get_context_data(self, **kwargs): + + context = TemplateView.get_context_data(self, **kwargs) + context.update({ + 'head_title': str(_('Painel Plenário')), + 'sessao_id': kwargs['pk']}) + + return context class PresencaOrdemDiaView(FormMixin, PresencaMixin, DetailView): @@ -502,11 +531,7 @@ class PresencaOrdemDiaView(FormMixin, PresencaMixin, DetailView): form_class = PresencaForm model = SessaoPlenaria - @method_decorator(permission_required(( - '%s.add_%s' % (AppConfig.label, PresencaOrdemDia._meta.model_name), - '%s.change_%s' % (AppConfig.label, PresencaOrdemDia._meta.model_name), - '%s.delete_%s' % (AppConfig.label, PresencaOrdemDia._meta.model_name), - ))) + @method_decorator(permission_required_for_app(AppConfig.label)) def post(self, request, *args, **kwargs): self.object = self.get_object() @@ -514,9 +539,6 @@ class PresencaOrdemDiaView(FormMixin, PresencaMixin, DetailView): pk = kwargs['pk'] - if not self.request.user.has_perms(permissoes_sessao()): - return self.form_invalid(form) - if form.is_valid(): # Pegar os presentes salvos no banco presentes_banco = PresencaOrdemDia.objects.filter( @@ -589,11 +611,7 @@ class ListMateriaOrdemDiaView(FormMixin, DetailView): return self.render_to_response(context) - @method_decorator(permission_required(( - '%s.add_%s' % (AppConfig.label, OrdemDia._meta.model_name), - '%s.change_%s' % (AppConfig.label, OrdemDia._meta.model_name), - '%s.delete_%s' % (AppConfig.label, OrdemDia._meta.model_name), - ))) + @method_decorator(permission_required_for_app(AppConfig.label)) def post(self, request, *args, **kwargs): self.object = self.get_object() context = self.get_context_data(object=self.object) @@ -684,11 +702,7 @@ class MesaView(FormMixin, DetailView): return self.render_to_response(context) - @method_decorator(permission_required(( - '%s.add_integrantemesa' % AppConfig.label, - '%s.change_integrantemesa' % AppConfig.label, - '%s.delete_integrantemesa' % AppConfig.label, - ))) + @method_decorator(permission_required_for_app(AppConfig.label)) def post(self, request, *args, **kwargs): self.object = self.get_object() form = MesaForm(request.POST) @@ -759,8 +773,9 @@ class MesaView(FormMixin, DetailView): return reverse('sapl.sessao:mesa', kwargs={'pk': pk}) -class ResumoView(SessaoCrud.CrudDetailView): +class ResumoView(DetailView): template_name = 'sessao/resumo.html' + model = SessaoPlenaria def get(self, request, *args, **kwargs): self.object = self.get_object() @@ -931,18 +946,16 @@ class ResumoView(SessaoCrud.CrudDetailView): return self.render_to_response(context) -class ExpedienteView(FormMixin, - SessaoCrud.CrudDetailView): +class ExpedienteView(FormMixin, DetailView): template_name = 'sessao/expediente.html' form_class = ExpedienteForm + model = SessaoPlenaria + @method_decorator(permission_required_for_app(AppConfig.label)) def post(self, request, *args, **kwargs): self.object = self.get_object() form = ExpedienteForm(request.POST) - if not self.request.user.has_perms(permissoes_sessao()): - return self.form_invalid(form) - if form.is_valid(): list_tipo = request.POST.getlist('tipo') list_conteudo = request.POST.getlist('conteudo') @@ -999,16 +1012,13 @@ class ExpedienteView(FormMixin, return reverse('sapl.sessao:expediente', kwargs={'pk': pk}) -class VotacaoEditView(PermissionRequiredMixin, - FormMixin, - SessaoCrud.CrudDetailView): +class VotacaoEditView(SessaoPermissionMixin): ''' Votação Simbólica e Secreta ''' template_name = 'sessao/votacao/votacao_edit.html' - permission_required = permissoes_sessao() def post(self, request, *args, **kwargs): @@ -1075,9 +1085,7 @@ class VotacaoEditView(PermissionRequiredMixin, kwargs={'pk': pk}) -class VotacaoView(PermissionRequiredMixin, - FormMixin, - SessaoCrud.CrudDetailView): +class VotacaoView(SessaoPermissionMixin): ''' Votação Simbólica e Secreta @@ -1085,7 +1093,6 @@ class VotacaoView(PermissionRequiredMixin, template_name = 'sessao/votacao/votacao.html' form_class = VotacaoForm - permission_required = permissoes_sessao() def get(self, request, *args, **kwargs): self.object = self.get_object() @@ -1197,11 +1204,8 @@ class VotacaoView(PermissionRequiredMixin, kwargs={'pk': pk}) -class VotacaoNominalView(PermissionRequiredMixin, - FormMixin, - SessaoCrud.CrudDetailView): +class VotacaoNominalView(SessaoPermissionMixin): template_name = 'sessao/votacao/nominal.html' - permission_required = permissoes_sessao() def get(self, request, *args, **kwargs): ordem_id = kwargs['mid'] @@ -1325,11 +1329,8 @@ class VotacaoNominalView(PermissionRequiredMixin, kwargs={'pk': pk}) -class VotacaoNominalEditView(PermissionRequiredMixin, - FormMixin, - SessaoCrud.CrudDetailView): +class VotacaoNominalEditView(SessaoPermissionMixin): template_name = 'sessao/votacao/nominal_edit.html' - permission_required = permissoes_sessao() def get(self, request, *args, **kwargs): context = {} @@ -1405,11 +1406,8 @@ class VotacaoNominalEditView(PermissionRequiredMixin, kwargs={'pk': pk}) -class VotacaoNominalExpedienteView(PermissionRequiredMixin, - FormMixin, - SessaoCrud.CrudDetailView): +class VotacaoNominalExpedienteView(SessaoPermissionMixin): template_name = 'sessao/votacao/nominal.html' - permission_required = permissoes_sessao() def get(self, request, *args, **kwargs): expediente_id = kwargs['mid'] @@ -1531,11 +1529,8 @@ class VotacaoNominalExpedienteView(PermissionRequiredMixin, kwargs={'pk': pk}) -class VotacaoNominalExpedienteEditView(PermissionRequiredMixin, - FormMixin, - SessaoCrud.CrudDetailView): +class VotacaoNominalExpedienteEditView(SessaoPermissionMixin): template_name = 'sessao/votacao/nominal_edit.html' - permission_required = permissoes_sessao() def get(self, request, *args, **kwargs): context = {} @@ -1610,9 +1605,7 @@ class VotacaoNominalExpedienteEditView(PermissionRequiredMixin, kwargs={'pk': pk}) -class VotacaoExpedienteView(PermissionRequiredMixin, - FormMixin, - SessaoCrud.CrudDetailView): +class VotacaoExpedienteView(SessaoPermissionMixin): ''' Votação Simbólica e Secreta @@ -1620,7 +1613,6 @@ class VotacaoExpedienteView(PermissionRequiredMixin, template_name = 'sessao/votacao/votacao.html' form_class = VotacaoForm - permission_required = permissoes_sessao() def get(self, request, *args, **kwargs): self.object = self.get_object() @@ -1734,9 +1726,7 @@ class VotacaoExpedienteView(PermissionRequiredMixin, kwargs={'pk': pk}) -class VotacaoExpedienteEditView(PermissionRequiredMixin, - FormMixin, - SessaoCrud.CrudDetailView): +class VotacaoExpedienteEditView(SessaoPermissionMixin): ''' Votação Simbólica e Secreta @@ -1744,7 +1734,6 @@ class VotacaoExpedienteEditView(PermissionRequiredMixin, template_name = 'sessao/votacao/votacao_edit.html' form_class = VotacaoEditForm - permission_required = permissoes_sessao() def get_success_url(self): pk = self.kwargs['pk'] @@ -1835,8 +1824,9 @@ class PautaSessaoListView(SessaoListView): template_name = "sessao/pauta_sessao_list.html" -class PautaSessaoDetailView(SessaoCrud.CrudDetailView): +class PautaSessaoDetailView(DetailView): template_name = "sessao/pauta_sessao_detail.html" + model = SessaoPlenaria def get(self, request, *args, **kwargs): self.object = self.get_object() @@ -1946,8 +1936,9 @@ class SessaoPlenariaView(generics.ListAPIView): serializer_class = SessaoPlenariaSerializer -class PautaExpedienteDetail(SessaoCrud.CrudDetailView): +class PautaExpedienteDetail(DetailView): template_name = "sessao/pauta/expediente.html" + model = SessaoPlenaria def get(self, request, *args, **kwargs): pk = self.kwargs['pk'] @@ -1964,8 +1955,9 @@ class PautaExpedienteDetail(SessaoCrud.CrudDetailView): 'tramitacao': tramitacao}) -class PautaOrdemDetail(SessaoCrud.CrudDetailView): +class PautaOrdemDetail(DetailView): template_name = "sessao/pauta/ordem.html" + model = SessaoPlenaria def get(self, request, *args, **kwargs): pk = self.kwargs['pk'] @@ -2063,11 +2055,11 @@ def retira_materias_ja_adicionadas(id_sessao, model): return lista_id_materias -class AdicionarVariasMateriasExpediente(PermissionRequiredMixin, +class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin, MateriaLegislativaPesquisaView): filterset_class = AdicionarVariasMateriasFilterSet template_name = 'sessao/adicionar_varias_materias_expediente.html' - permission_required = permissoes_sessao() + app_label = AppConfig.label def get_filterset_kwargs(self, filterset_class): super(AdicionarVariasMateriasExpediente, @@ -2143,7 +2135,6 @@ class AdicionarVariasMateriasExpediente(PermissionRequiredMixin, class AdicionarVariasMateriasOrdemDia(AdicionarVariasMateriasExpediente): filterset_class = AdicionarVariasMateriasFilterSet template_name = 'sessao/adicionar_varias_materias_ordem.html' - permission_required = permissoes_sessao() def get_filterset_kwargs(self, filterset_class): super(AdicionarVariasMateriasExpediente, diff --git a/sapl/templates/sessao/subnav.yaml b/sapl/templates/sessao/subnav.yaml index cca959a10..ac08302f4 100644 --- a/sapl/templates/sessao/subnav.yaml +++ b/sapl/templates/sessao/subnav.yaml @@ -1,4 +1,5 @@ -{% load i18n %} +{% load i18n common_tags %} + - title: {% trans 'Abertura' %} children: - title: {% trans 'Dados Básicos' %} @@ -28,6 +29,6 @@ - title: {% trans 'Painel Eletrônico' %} url: painel - + {% if not 'painel_aberto'|get_config_attr %}check_permission: painel.list_painel{%endif%} - title: {% trans 'Resumo' %} url: resumo diff --git a/sapl/utils.py b/sapl/utils.py index 3b6d8b1f0..467d0d2b2 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -1,18 +1,19 @@ -import hashlib from datetime import date from functools import wraps from unicodedata import normalize as unicodedata_normalize +import hashlib -import magic from django import forms from django.apps import apps from django.conf import settings from django.contrib import admin +from django.contrib.auth.decorators import user_passes_test from django.contrib.auth.models import Permission from django.contrib.contenttypes.models import ContentType -from django.core.exceptions import ValidationError +from django.core.exceptions import ValidationError, PermissionDenied from django.utils.translation import ugettext_lazy as _ from floppyforms import ClearableFileInput +import magic def normalize(txt): @@ -279,6 +280,25 @@ def permissoes(nome_grupo, app_label): return set(lista_permissoes) +def permission_required_for_app(app_label, login_url=None, + raise_exception=False): + """ + Decorator for views that checks whether a user has a particular permission + enabled, redirecting to the log-in page if necessary. + If the raise_exception parameter is given the PermissionDenied exception + is raised. + """ + def check_perms(user): + if user.has_module_perms(app_label): + return True + # In case the 403 handler should be called raise the exception + if raise_exception: + raise PermissionDenied + # As the last resort, show the login form + return False + return user_passes_test(check_perms, login_url=login_url) + + def permissoes_materia(): return permissoes('Operador de Matéria', 'materia')