Browse Source

Especifica permissoes e cria teste de verificação

pull/781/head
LeandroRoberto 8 years ago
parent
commit
d05cf6909f
  1. 27
      sapl/base/templatetags/common_tags.py
  2. 84
      sapl/materia/forms.py
  3. 6
      sapl/materia/tests/test_materia.py
  4. 5
      sapl/materia/views.py
  5. 19
      sapl/norma/migrations/0019_auto_20161028_0232.py
  6. 6
      sapl/painel/views.py
  7. 81
      sapl/rules/tests/test_rules.py
  8. 23
      sapl/sessao/views.py
  9. 49
      sapl/templates/base/appconfig_list.html
  10. 6
      sapl/utils.py

27
sapl/base/templatetags/common_tags.py

@ -3,8 +3,6 @@ from django import template
from sapl.base.models import AppConfig
from sapl.parlamentares.models import Filiacao
from sapl.utils import permissoes_adm
register = template.Library()
@ -87,26 +85,6 @@ def get_delete_perm(value, arg):
return perm.__contains__(nome_app + can_delete)
@register.filter
def get_doc_adm_template_perms(user):
app_config = AppConfig.objects.last()
if app_config:
if app_config.documentos_administrativos == 'O':
return True
return user.has_perms(permissoes_adm())
@register.filter
def ver_menu_sistema_perm(value):
u = value
if u.groups.filter(name='Operador Geral').exists() or u.is_superuser:
return True
else:
return False
@register.filter
def ultima_filiacao(value):
parlamentar = value
@ -120,11 +98,6 @@ def ultima_filiacao(value):
return None
@register.filter
def get_config_not_exists(user):
return not AppConfig.objects.exists()
@register.filter
def get_config_attr(attribute):
return AppConfig.attr(attribute)

84
sapl/materia/forms.py

@ -1,8 +1,7 @@
import os
from datetime import date, datetime
import os
import django_filters
from crispy_forms.bootstrap import (Alert, FormActions, InlineCheckboxes,
InlineRadios)
from crispy_forms.helper import FormHelper
@ -18,8 +17,8 @@ from django.db.models import Max
from django.forms import ModelForm, widgets
from django.forms.forms import Form
from django.utils.translation import ugettext_lazy as _
import django_filters
import sapl
from sapl.base.models import Autor
from sapl.comissoes.models import Comissao
from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
@ -33,6 +32,7 @@ from sapl.settings import MAX_DOC_UPLOAD_SIZE
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
ChoiceWithoutValidationField, RangeWidgetOverride,
autor_label, autor_modal, models_with_gr_for_model)
import sapl
from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial,
DocumentoAcessorio, MateriaLegislativa, Numeracao,
@ -84,66 +84,6 @@ class UnidadeTramitacaoForm(ModelForm):
return cleaned_data
class ProposicaoOldForm(ModelForm):
tipo_materia = forms.ModelChoiceField(
label=_('Matéria Vinculada'),
required=False,
queryset=TipoMateriaLegislativa.objects.all(),
empty_label='Selecione',
)
numero_materia = forms.CharField(
label='Número', required=False)
ano_materia = forms.CharField(
label='Ano', required=False)
def clean_texto_original(self):
texto_original = self.cleaned_data.get('texto_original', False)
if texto_original:
if texto_original.size > MAX_DOC_UPLOAD_SIZE:
raise ValidationError("Arquivo muito grande. ( > 5mb )")
return texto_original
def clean_data_envio(self):
data_envio = self.cleaned_data.get('data_envio') or None
if (not data_envio) and len(self.initial) > 1:
data_envio = datetime.now()
return data_envio
def clean(self):
cleaned_data = self.cleaned_data
if 'tipo' in cleaned_data:
if cleaned_data['tipo'].descricao == 'Parecer':
if self.instance.materia:
cleaned_data['materia'] = self.instance.materia
else:
try:
materia = MateriaLegislativa.objects.get(
tipo_id=cleaned_data['tipo_materia'],
ano=cleaned_data['ano_materia'],
numero=cleaned_data['numero_materia'])
except ObjectDoesNotExist:
msg = _('Matéria adicionada não existe!')
raise ValidationError(msg)
else:
cleaned_data['materia'] = materia
return cleaned_data
def save(self, commit=False):
proposicao = super(ProposicaoOldForm, self).save(commit)
if 'materia' in self.cleaned_data:
proposicao.materia = self.cleaned_data['materia']
proposicao.save()
return proposicao
class Meta:
model = Proposicao
fields = ['tipo', 'data_envio', 'descricao', 'texto_original', 'autor']
widgets = {'autor': forms.HiddenInput()}
class AcompanhamentoMateriaForm(ModelForm):
class Meta:
@ -953,13 +893,13 @@ class ProposicaoForm(forms.ModelForm):
if self.instance.materia_de_vinculo:
self.fields[
'tipo_materia'
].initial = self.instance.materia_de_vinculo.tipo
].initial = self.instance.materia_de_vinculo.tipo
self.fields[
'numero_materia'
].initial = self.instance.materia_de_vinculo.numero
].initial = self.instance.materia_de_vinculo.numero
self.fields[
'ano_materia'
].initial = self.instance.materia_de_vinculo.ano
].initial = self.instance.materia_de_vinculo.ano
def clean_texto_original(self):
texto_original = self.cleaned_data.get('texto_original', False)
@ -1133,13 +1073,13 @@ class ConfirmarProposicaoForm(ProposicaoForm):
if self.instance.materia_de_vinculo:
self.fields[
'tipo_materia'
].initial = self.instance.materia_de_vinculo.tipo
].initial = self.instance.materia_de_vinculo.tipo
self.fields[
'numero_materia'
].initial = self.instance.materia_de_vinculo.numero
].initial = self.instance.materia_de_vinculo.numero
self.fields[
'ano_materia'
].initial = self.instance.materia_de_vinculo.ano
].initial = self.instance.materia_de_vinculo.ano
if self.proposicao_incorporacao_obrigatoria == 'C':
self.fields['gerar_protocolo'].initial = True
@ -1156,7 +1096,7 @@ class ConfirmarProposicaoForm(ProposicaoForm):
_('Regimente de Tramitação deve ser informado.'))
elif self.instance.tipo.content_type.model_class(
) == TipoDocumento and not cd['materia_de_vinculo']:
) == TipoDocumento and not cd['materia_de_vinculo']:
raise ValidationError(
_('Documentos não podem ser incorporados sem definir '
@ -1224,7 +1164,7 @@ class ConfirmarProposicaoForm(ProposicaoForm):
conteudo_gerado = None
if self.instance.tipo.content_type.model_class(
) == TipoMateriaLegislativa:
) == TipoMateriaLegislativa:
numero__max = MateriaLegislativa.objects.filter(
tipo=proposicao.tipo.tipo_conteudo_related,
ano=datetime.now().year).aggregate(Max('numero'))
@ -1358,7 +1298,7 @@ class ConfirmarProposicaoForm(ProposicaoForm):
protocolo.anulado = False
if self.instance.tipo.content_type.model_class(
) == TipoMateriaLegislativa:
) == TipoMateriaLegislativa:
protocolo.tipo_materia = proposicao.tipo.tipo_conteudo_related
elif self.instance.tipo.content_type.model_class() == TipoDocumento:
protocolo.tipo_documento = proposicao.tipo.tipo_conteudo_related

6
sapl/materia/tests/test_materia.py

@ -1,9 +1,9 @@
import pytest
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.urlresolvers import reverse
from model_mommy import mommy
import pytest
from sapl.base.models import Autor, TipoAutor
from sapl.comissoes.models import Comissao, TipoComissao
@ -452,7 +452,7 @@ def test_proposicao_submit(admin_client):
*models_with_gr_for_model(TipoProposicao))
for pk, mct in enumerate(mcts):
tipo_conteudo_related = mommy.make(mct, pk=pk)
tipo_conteudo_related = mommy.make(mct, pk=pk + 1)
response = admin_client.post(
reverse('sapl.materia:proposicao_create'),
@ -475,7 +475,7 @@ def test_proposicao_submit(admin_client):
assert proposicao is not None
assert proposicao.descricao == 'Teste proposição'
assert proposicao.tipo.pk == 3
assert proposicao.tipo.tipo_conteudo_related.pk == pk
assert proposicao.tipo.tipo_conteudo_related.pk == pk + 1
@pytest.mark.django_db(transaction=False)

5
sapl/materia/views.py

@ -5,6 +5,7 @@ from string import ascii_letters, digits
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML
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
from django.core.mail import send_mail
@ -34,7 +35,7 @@ from sapl.materia.forms import (AnexadaForm, ConfirmarProposicaoForm,
from sapl.norma.models import LegislacaoCitada
from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
autor_modal, gerar_hash_arquivo, get_base_url,
montar_row_autor, permission_required_for_app)
montar_row_autor)
import sapl
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
@ -101,7 +102,7 @@ class ProposicaoTaView(IntegracaoTaView):
return self.get_redirect_deactivated()
@permission_required_for_app(app_label=apps.AppConfig.label)
@permission_required('materia.detail_materialegislativa')
def recuperar_materia(request):
tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo'])
ano = request.GET.get('ano', '')

19
sapl/norma/migrations/0019_auto_20161028_0232.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-28 02:32
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('norma', '0018_auto_20161027_1434'),
]
operations = [
migrations.AlterUniqueTogether(
name='assuntonormarelationship',
unique_together=set([('assunto', 'norma')]),
),
]

6
sapl/painel/views.py

@ -7,6 +7,7 @@ from django.shortcuts import render
from django.utils.translation import ugettext_lazy as _
from sapl.crud.base import Crud
from sapl.painel.apps import AppConfig
from sapl.painel.models import Painel
from sapl.parlamentares.models import Filiacao
from sapl.sessao.models import (ExpedienteMateria, OrdemDia, PresencaOrdemDia,
@ -15,11 +16,14 @@ from sapl.sessao.models import (ExpedienteMateria, OrdemDia, PresencaOrdemDia,
from .models import Cronometro
CronometroPainelCrud = Crud.build(Cronometro, '')
# FIXME mudar lógica
def check_permission(user):
return user.has_perms(permissoes_painel())
return user.has_module_perms(AppConfig.label)
@user_passes_test(check_permission)

81
sapl/rules/tests/test_rules.py

@ -1,13 +1,16 @@
import pytest
from django.apps import apps
from django.conf import settings
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.utils import six
from django.utils.translation import ugettext_lazy as _
import pytest
from sapl.rules import SAPL_GROUPS
from sapl.rules.map_rules import rules_patterns
from sapl.test_urls import create_perms_post_migrate
from scripts.lista_urls import lista_urls
sapl_appconfs = [apps.get_app_config(n[5:]) for n in settings.SAPL_APPS]
@ -47,7 +50,7 @@ def test_models_in_rules_patterns(model_item):
@pytest.mark.django_db(transaction=False)
@pytest.mark.parametrize('model_item', sapl_models)
def test_permission_exists(model_item):
def test_permission_of_rules_exists(model_item):
print(model_item)
create_perms_post_migrate(model_item._meta.app_config)
@ -75,3 +78,77 @@ def test_permission_exists(model_item):
assert p, _('Permissão (%s) no model (%s) não existe.') % (
codename,
model_item)
_lista_urls = lista_urls()
@pytest.mark.django_db(transaction=False)
@pytest.mark.parametrize('url_item', _lista_urls)
def test_permission_required_of_views_exists(url_item):
"""
testa se, nas views que possuem atributo permission_required,
as permissões fixas escritas manualmente realmente exitem em Permission
Obs: isso não testa permissões escritas em anotações de método ou classe
"""
for app in sapl_appconfs:
# readequa permissões dos models adicionando
# list e detail permissions
create_perms_post_migrate(app)
key, url, var, app_name = url_item
url = '/' + (url % {v: 1 for v in var})
assert '\n' not in url, """
A url (%s) da app (%s) está mal formada.
""" % (app_name, url)
view = None
if hasattr(key, 'view_class'):
view = key.view_class
if hasattr(view, 'permission_required'):
if isinstance(view.permission_required, six.string_types):
perms = (view.permission_required, )
else:
perms = view.permission_required
if not perms:
return
for perm in perms:
if perm[0] == '.' and perm[-1] == '_':
model = None
if hasattr(view, 'model') and view.model:
model = view.model
elif hasattr(view, 'filterset_class'):
model = view.fielterset_class._meta.model
elif hasattr(view, 'form_class'):
model = view.form_class._meta.model
assert model, _('model %s não localizado em %s'
) % (model, view)
codename = perm[1:] + view.model._meta.model_name
else:
codename = perm
codename = codename.split('.')
if len(codename) == 1:
content_type = ContentType.objects.get_by_natural_key(
app_label=model._meta.app_label,
model=model._meta.model_name)
p = Permission.objects.filter(
content_type=content_type,
codename=codename[0]).exists()
elif len(codename) == 2:
p = Permission.objects.filter(
content_type__app_label=codename[0],
codename=codename[1]).exists()
assert p, _('Permissão (%s) na view (%s) não existe.') % (
codename,
view)

23
sapl/sessao/views.py

@ -2,6 +2,7 @@ from datetime import datetime
from re import sub
from django.contrib import messages
from django.contrib.auth.decorators import permission_required
from django.core.exceptions import ObjectDoesNotExist
from django.core.urlresolvers import reverse
from django.forms.utils import ErrorList
@ -28,10 +29,9 @@ from sapl.materia.views import MateriaLegislativaPesquisaView
from sapl.norma.models import NormaJuridica
from sapl.parlamentares.models import (Legislatura, Parlamentar,
SessaoLegislativa)
from sapl.sessao import apps
from sapl.sessao.apps import AppConfig
from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm
from sapl.utils import permission_required_for_app
from .forms import (AdicionarVariasMateriasFilterSet, ExpedienteForm,
ListMateriaForm, MesaForm, OradorExpedienteForm,
@ -45,6 +45,7 @@ from .models import (Bancada, Bloco, CargoBancada, CargoMesa,
SessaoPlenariaPresenca, TipoExpediente,
TipoResultadoVotacao, TipoSessaoPlenaria, VotoParlamentar)
TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria')
TipoExpedienteCrud = CrudAux.build(TipoExpediente, 'tipo_expediente')
CargoBancadaCrud = CrudAux.build(CargoBancada, '')
@ -83,7 +84,7 @@ def reordernar_materias_ordem(request, pk):
reverse('sapl.sessao:ordemdia_list', kwargs={'pk': pk}))
@permission_required_for_app(app_label=apps.AppConfig.label)
@permission_required('sessao.change_expedientemateria')
def abrir_votacao_expediente_view(request, pk, spk):
existe_votacao_aberta = ExpedienteMateria.objects.filter(
sessao_plenaria_id=spk, votacao_aberta=True
@ -100,7 +101,7 @@ def abrir_votacao_expediente_view(request, pk, spk):
reverse('sapl.sessao:expedientemateria_list', kwargs={'pk': spk}))
@permission_required_for_app(app_label=apps.AppConfig.label)
@permission_required('sessao.change_ordemdia')
def abrir_votacao_ordem_view(request, pk, spk):
existe_votacao_aberta = OrdemDia.objects.filter(
sessao_plenaria_id=spk, votacao_aberta=True
@ -523,14 +524,12 @@ class PresencaView(FormMixin, PresencaMixin, DetailView):
_('Presença'), self.object)
return context
@method_decorator(permission_required_for_app(AppConfig.label))
@method_decorator(permission_required(
'sessao.add_sessaoplenariapresenca'))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
if not self.request.user.has_module_perms(AppConfig.label):
return self.form_invalid(form)
if form.is_valid():
# Pegar os presentes salvos no banco
presentes_banco = SessaoPlenariaPresenca.objects.filter(
@ -603,7 +602,7 @@ class PresencaOrdemDiaView(FormMixin, PresencaMixin, DetailView):
_('Presença Ordem do Dia'), self.object)
return context
@method_decorator(permission_required_for_app(AppConfig.label))
@method_decorator(permission_required('sessao.add_presencaordemdia'))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
@ -683,7 +682,7 @@ class ListMateriaOrdemDiaView(FormMixin, DetailView):
return self.render_to_response(context)
@method_decorator(permission_required_for_app(AppConfig.label))
@method_decorator(permission_required('sessao.change_ordemdia'))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
@ -785,7 +784,7 @@ class MesaView(FormMixin, DetailView):
_('Mesa Diretora'), self.object)
return context
@method_decorator(permission_required_for_app(AppConfig.label))
@method_decorator(permission_required('sessao.change_integrantemesa'))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = MesaForm(request.POST)
@ -1040,7 +1039,7 @@ class ExpedienteView(FormMixin, DetailView):
_('Expediente Diversos'), self.object)
return context
@method_decorator(permission_required_for_app(AppConfig.label))
@method_decorator(permission_required('sessao.add_expedientesessao'))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = ExpedienteForm(request.POST)

49
sapl/templates/base/appconfig_list.html

@ -1,49 +0,0 @@
{% extends "crud/list.html" %}
{% load i18n %}
{% load common_tags %}
{% block base_content %}
<div class="actions btn-group pull-right" role="group">
{% if user|get_config_not_exists %}
<a href="{{ view.create_url }}" class="btn btn-default">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar {{ verbose_name }} {% endblocktrans %}
</a>
{% endif %}
{% block more_buttons %}{% endblock more_buttons %}
</div>
<br/><br/>
{% block extra_content %} {% endblock %}
{% if not rows %}
<p>{{ NO_ENTRIES_MSG }}</p>
{% else %}
<table class="table table-striped table-hover">
<thead>
<tr>
{% for name in headers %}
<th>{{ name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for value_list in rows %}
<tr>
{% for value, href in value_list %}
<td>
{% if href %}
<a href="{{ href }}">{{ value }}</a>
{% else %}
{{ value|safe }}
{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
{% include "paginacao.html" %}
{% endblock %}

6
sapl/utils.py

@ -395,17 +395,16 @@ def permissoes(nome_grupo, app_label):
except:
pass
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
@ -416,7 +415,6 @@ def permission_required_for_app(app_label, login_url=None,
return False
return user_passes_test(check_perms, login_url=login_url)
"""
def permissoes_materia():
return permissoes('Operador de Matéria', 'materia')

Loading…
Cancel
Save