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')