Browse Source

Merge branch 'master' into Assunto-Norma-3

pull/781/head
LeandroRoberto 8 years ago
parent
commit
4dc756531c
  1. 2
      requirements/requirements.txt
  2. 1
      sapl/base/templatetags/common_tags.py
  3. 28
      sapl/compilacao/forms.py
  4. 19
      sapl/compilacao/migrations/0060_auto_20161101_0913.py
  5. 21
      sapl/compilacao/migrations/0061_auto_20161101_1025.py
  6. 19
      sapl/compilacao/migrations/0062_auto_20161101_1221.py
  7. 20
      sapl/compilacao/migrations/0063_tipotextoarticulado_publicacao_func.py
  8. 14
      sapl/compilacao/models.py
  9. 2
      sapl/compilacao/templatetags/compilacao_filters.py
  10. 313
      sapl/compilacao/views.py
  11. 6
      sapl/crud/base.py
  12. 66
      sapl/materia/forms.py
  13. 2
      sapl/materia/tests/test_materia.py
  14. 7
      sapl/materia/urls.py
  15. 58
      sapl/materia/views.py
  16. 2
      sapl/norma/forms.py
  17. 11
      sapl/norma/views.py
  18. 1
      sapl/painel/views.py
  19. 3
      sapl/parlamentares/views.py
  20. 49
      sapl/protocoloadm/forms.py
  21. 5
      sapl/protocoloadm/urls.py
  22. 100
      sapl/protocoloadm/views.py
  23. 62
      sapl/rules/map_rules.py
  24. 89
      sapl/rules/tests/test_rules.py
  25. 21
      sapl/sessao/forms.py
  26. 10
      sapl/sessao/views.py
  27. 4
      sapl/settings.py
  28. 48
      sapl/templates/compilacao/ajax_actions_dinamic_edit.html
  29. 8
      sapl/templates/compilacao/dispositivo_form.html
  30. 12
      sapl/templates/compilacao/publicacao_list.html
  31. 14
      sapl/templates/compilacao/text_edit.html
  32. 18
      sapl/templates/compilacao/text_list.html
  33. 18
      sapl/templates/compilacao/textoarticulado_detail.html
  34. 14
      sapl/templates/compilacao/textoarticulado_list.html
  35. 18
      sapl/templates/compilacao/textoarticulado_menu_config.html
  36. 5
      sapl/templates/compilacao/tipotextoarticulado_detail.html
  37. 12
      sapl/templates/compilacao/tipotextoarticulado_list.html
  38. 5
      sapl/templates/materia/tipoproposicao_form.html
  39. 4
      sapl/templates/painel/controlador.html
  40. 25
      sapl/templates/protocoloadm/MateriaTemplate.html
  41. 8
      sapl/templates/protocoloadm/protocolo_mostrar.html
  42. 2
      sapl/templates/sessao/painel.html
  43. 6
      sapl/urls.py
  44. 65
      sapl/utils.py
  45. 1
      scripts/lista_permissions_in_decorators.py

2
requirements/requirements.txt

@ -8,7 +8,7 @@ django-compressor==2.0
django-crispy-forms==1.6.0
django-extensions==1.6.7
django-extra-views==0.8.0
django-filter==0.13.0
django-filter==0.15.3
django-floppyforms==1.6.2
django-model-utils==2.5
django-sass-processor==0.4.6

1
sapl/base/templatetags/common_tags.py

@ -3,6 +3,7 @@ from django import template
from sapl.base.models import AppConfig
from sapl.parlamentares.models import Filiacao
register = template.Library()

28
sapl/compilacao/forms.py

@ -42,10 +42,18 @@ class TipoTaForm(ModelForm):
label=TipoTextoArticulado._meta.get_field(
'descricao').verbose_name)
participacao_social = forms.NullBooleanField(
participacao_social = forms.ChoiceField(
label=TipoTextoArticulado._meta.get_field(
'participacao_social').verbose_name,
widget=forms.Select(choices=YES_NO_CHOICES),
choices=YES_NO_CHOICES,
widget=forms.RadioSelect(),
required=True)
publicacao_func = forms.ChoiceField(
label=TipoTextoArticulado._meta.get_field(
'publicacao_func').verbose_name,
choices=YES_NO_CHOICES,
widget=forms.RadioSelect(),
required=True)
class Meta:
@ -54,21 +62,27 @@ class TipoTaForm(ModelForm):
'descricao',
'content_type',
'participacao_social',
'publicacao_func'
]
def __init__(self, *args, **kwargs):
row1 = to_row([
('sigla', 2),
('descricao', 4),
('content_type', 3),
('participacao_social', 3),
('sigla', 3),
('descricao', 5),
('content_type', 4),
])
row2 = to_row([
(InlineRadios('participacao_social'), 3),
(InlineRadios('publicacao_func'), 3),
])
self.helper = FormHelper()
self.helper.layout = SaplFormLayout(
Fieldset(_('Identificação Básica'),
row1, css_class="col-md-12"))
row1, css_class="col-md-12"),
Fieldset(_('Funcionalidades'),
row2, css_class="col-md-12"))
super(TipoTaForm, self).__init__(*args, **kwargs)

19
sapl/compilacao/migrations/0060_auto_20161101_0913.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-11-01 09:13
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0059_auto_20161027_1323'),
]
operations = [
migrations.AlterModelOptions(
name='dispositivo',
options={'ordering': ['ta', 'ordem'], 'permissions': (('change_dispositivo_edicao_dinamica', 'Permissão de edição de dispositivos originais via editor dinâmico.'), ('change_dispositivo_edicao_avancada', 'Permissão de edição de dispositivos originais via formulários de edição avançada.'), ('change_dispositivo_registros_compilacao', 'Permissão de registro de compilação via editor dinâmico.'), ('view_dispositivo_notificacoes', 'Permissão de acesso às notificações de pendências.')), 'verbose_name': 'Dispositivo', 'verbose_name_plural': 'Dispositivos'},
),
]

21
sapl/compilacao/migrations/0061_auto_20161101_1025.py

@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-11-01 10:25
from __future__ import unicode_literals
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0060_auto_20161101_0913'),
]
operations = [
migrations.AlterField(
model_name='dispositivo',
name='ta',
field=models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, related_name='dispositivos_set', to='compilacao.TextoArticulado', verbose_name='Texto Articulado'),
),
]

19
sapl/compilacao/migrations/0062_auto_20161101_1221.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-11-01 12:21
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0061_auto_20161101_1025'),
]
operations = [
migrations.AlterModelOptions(
name='dispositivo',
options={'ordering': ['ta', 'ordem'], 'permissions': (('change_dispositivo_edicao_dinamica', 'Permissão de edição de dispositivos originais via editor dinâmico.'), ('change_dispositivo_edicao_avancada', 'Permissão de edição de dispositivos originais via formulários de edição avançada.'), ('change_dispositivo_registros_compilacao', 'Permissão de registro de compilação via editor dinâmico.'), ('view_dispositivo_notificacoes', 'Permissão de acesso às notificações de pendências.'), ('change_dispositivo_de_vigencia_global', 'Permissão alteração global do dispositivo de vigência')), 'verbose_name': 'Dispositivo', 'verbose_name_plural': 'Dispositivos'},
),
]

20
sapl/compilacao/migrations/0063_tipotextoarticulado_publicacao_func.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-11-03 11:06
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('compilacao', '0062_auto_20161101_1221'),
]
operations = [
migrations.AddField(
model_name='tipotextoarticulado',
name='publicacao_func',
field=models.NullBooleanField(choices=[(True, 'Sim'), (False, 'Não')], default=True, verbose_name='Histórico de Publicação'),
),
]

14
sapl/compilacao/models.py

@ -81,6 +81,12 @@ class TipoTextoArticulado(models.Model):
choices=YES_NO_CHOICES,
verbose_name=_('Participação Social'))
publicacao_func = models.NullBooleanField(
default=True,
blank=True, null=True,
choices=YES_NO_CHOICES,
verbose_name=_('Histórico de Publicação'))
class Meta:
verbose_name = _('Tipo de Texto Articulado')
verbose_name_plural = _('Tipos de Texto Articulados')
@ -635,7 +641,7 @@ class Dispositivo(BaseModel, TimestampedMixin):
ta = models.ForeignKey(
TextoArticulado,
on_delete=models.PROTECT,
on_delete=models.CASCADE,
related_name='dispositivos_set',
verbose_name=_('Texto Articulado'))
ta_publicado = models.ForeignKey(
@ -702,8 +708,10 @@ class Dispositivo(BaseModel, TimestampedMixin):
'via formulários de edição avançada.')),
('change_dispositivo_registros_compilacao', _(
'Permissão de registro de compilação via editor dinâmico.')),
('change_dispositivo_notificacoes', _(
('view_dispositivo_notificacoes', _(
'Permissão de acesso às notificações de pendências.')),
('change_dispositivo_de_vigencia_global', _(
'Permissão alteração global do dispositivo de vigência')),
)
def __str__(self):
@ -1260,7 +1268,7 @@ class Dispositivo(BaseModel, TimestampedMixin):
disps[0].get_numero_completo())
# dispositivo.transform_in_next()
else:
dispositivo.set_numero_completo([1, 0, 0, 0, 0, 0, ])
dispositivo.set_numero_completo([0, 0, 0, 0, 0, 0, ])
else:
if ';' in tipo_base.rotulo_prefixo_texto:

2
sapl/compilacao/templatetags/compilacao_filters.py

@ -211,7 +211,7 @@ def heranca(request, d, ignore_ultimo=0, ignore_primeiro=0):
ta_id = str(d.ta_id)
d_pk = str(d.pk)
if ta_id not in ta_dpts_parents or d_pk not in ta_dpts_parents[ta_id]:
print('recarregando estrutura temporaria de heranças')
#print('recarregando estrutura temporaria de heranças')
dpts_parents = {}
ta_dpts_parents[ta_id] = dpts_parents
update_dispositivos_parents(dpts_parents, ta_id)

313
sapl/compilacao/views.py

@ -1,16 +1,17 @@
import logging
import sys
from collections import OrderedDict
from datetime import datetime, timedelta
import logging
import sys
from braces.views import FormMessagesMixin
from django import forms
from django.conf import settings
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from django.contrib.auth.decorators import login_required, permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.contrib.contenttypes.models import ContentType
from django.core.signing import Signer
from django.core.urlresolvers import reverse_lazy
from django.core.urlresolvers import reverse_lazy, reverse
from django.db import connection, transaction
from django.db.models import Q
from django.db.utils import IntegrityError
@ -20,8 +21,8 @@ from django.shortcuts import get_object_or_404, redirect
from django.utils.dateparse import parse_date
from django.utils.decorators import method_decorator
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import TemplateView
from django.views.generic.detail import DetailView
from django.views.generic.edit import (CreateView, DeleteView, FormView,
@ -46,14 +47,15 @@ from sapl.compilacao.models import (Dispositivo, Nota,
VeiculoPublicacao, Vide)
from sapl.compilacao.utils import (DISPOSITIVO_SELECT_RELATED,
DISPOSITIVO_SELECT_RELATED_EDIT)
from sapl.crud.base import Crud, CrudListView, make_pagination
from sapl.crud.base import CrudAux, CrudListView, make_pagination
from sapl.settings import BASE_DIR
TipoNotaCrud = Crud.build(TipoNota, 'tipo_nota')
TipoVideCrud = Crud.build(TipoVide, 'tipo_vide')
TipoPublicacaoCrud = Crud.build(TipoPublicacao, 'tipo_publicacao')
VeiculoPublicacaoCrud = Crud.build(VeiculoPublicacao, 'veiculo_publicacao')
TipoDispositivoCrud = Crud.build(
TipoNotaCrud = CrudAux.build(TipoNota, 'tipo_nota')
TipoVideCrud = CrudAux.build(TipoVide, 'tipo_vide')
TipoPublicacaoCrud = CrudAux.build(TipoPublicacao, 'tipo_publicacao')
VeiculoPublicacaoCrud = CrudAux.build(VeiculoPublicacao, 'veiculo_publicacao')
TipoDispositivoCrud = CrudAux.build(
TipoDispositivo, 'tipo_dispositivo')
logger = logging.getLogger(BASE_DIR.name)
@ -87,12 +89,31 @@ def choice_models_in_extenal_views():
return result
def choice_model_type_foreignkey_in_extenal_views(id_tipo_ta=None):
yield None, '-------------'
if not id_tipo_ta:
return
tipo_ta = TipoTextoArticulado.objects.get(pk=id_tipo_ta)
integrations_view_names = get_integrations_view_names()
for item in integrations_view_names:
if hasattr(item, 'model_type_foreignkey'):
if (tipo_ta.content_type.model == item.model.__name__.lower() and
tipo_ta.content_type.app_label ==
item.model._meta.app_label):
for i in item.model_type_foreignkey.objects.all():
yield i.pk, i
class IntegracaoTaView(TemplateView):
def get_redirect_deactivated(self):
messages.error(
self.request,
_('O modulo de Textos Articulados está desativado.'))
_('O modulo de Textos Articulados para %s está desativado.'
) % self.model._meta.verbose_name_plural)
return redirect('/')
def get(self, request, *args, **kwargs):
@ -100,6 +121,16 @@ class IntegracaoTaView(TemplateView):
try:
if settings.DEBUG or not TipoDispositivo.objects.exists():
self.import_pattern()
if hasattr(self, 'map_funcs'):
tipo_ta = TipoTextoArticulado.objects.get(
content_type=ContentType.objects.get_for_model(
self.model))
for key, value in self.map_funcs.items():
setattr(tipo_ta, key, value)
tipo_ta.save()
except Exception as e:
logger.error(
string_concat(
@ -108,6 +139,25 @@ class IntegracaoTaView(TemplateView):
str(e)))
return self.get_redirect_deactivated()
assert hasattr(self, 'map_fields'), _(
"""
O mapa dos campos não foi definido. Ele deve seguir a estrutura
de chaves abaixo:
map_fields = {
'data': 'data',
'ementa': 'ementa',
'observacao': 'observacao',
'numero': 'numero',
'ano': 'ano',
}
Caso o model de integração não possua um dos campos,
implemente, ou passe `None` para as chaves que são fixas.
""")
map_fields = self.map_fields
item = get_object_or_404(self.model, pk=kwargs['pk'])
related_object_type = ContentType.objects.get_for_model(item)
@ -128,71 +178,43 @@ class IntegracaoTaView(TemplateView):
else:
ta = ta[0]
if hasattr(item, 'ementa') and item.ementa:
ta.ementa = item.ementa
else:
ta.ementa = _('Integração com %s sem ementa.') % item
ta.data = getattr(item, map_fields['data']
if map_fields['data'] else 'xxx', datetime.now())
if hasattr(item, 'observacao') and item.observacao:
ta.observacao = item.observacao
else:
ta.observacao = _('Integração com %s sem observacao.') % item
ta.ementa = getattr(
item, map_fields['ementa']
if map_fields['ementa'] else 'xxx', _(
'Integração com %s sem ementa.') % item)
if hasattr(item, 'numero') and item.numero:
ta.numero = item.numero
else:
ta.numero = int('%s%s%s' % (
ta.observacao = getattr(
item, map_fields['observacao']
if map_fields['observacao'] else 'xxx', '')
ta.numero = getattr(
item, map_fields['numero']
if map_fields['numero'] else 'xxx', int('%s%s%s' % (
int(datetime.now().year),
int(datetime.now().month),
int(datetime.now().day)))
int(datetime.now().day))))
if hasattr(item, 'ano') and item.ano:
ta.ano = item.ano
else:
ta.ano = datetime.now().year
if hasattr(item, 'data_apresentacao'):
ta.data = item.data_apresentacao
elif hasattr(item, 'data'):
ta.data = item.data
else:
ta.data = datetime.now()
ta.ano = getattr(item, map_fields['ano']
if map_fields['ano'] else 'xxx', datetime.now().year)
ta.save()
return redirect(to=reverse_lazy('sapl.compilacao:ta_text',
kwargs={'ta_id': ta.pk}))
"""msg = messages.error if not request.user.is_anonymous(
) else messages.info
msg(request,
_('A funcionalidade de Textos Articulados está desativada.'))
if not request.user.is_anonymous():
msg(
request,
_('Para ativá-la, os Tipos de Textos devem ser criados.'))
msg(request,
_('Sua tela foi redirecionada para a tela de '
'cadastro de Textos Articulados.'))
return redirect(to=reverse_lazy('sapl.compilacao:tipo_ta_list',
kwargs={}))
if Dispositivo.objects.filter(ta_id=ta.pk).exists():
return redirect(to=reverse_lazy('sapl.compilacao:ta_text',
kwargs={'ta_id': ta.pk}))
else:
return redirect(to=reverse_lazy(
'%s:%s_detail' % (
item._meta.app_config.name, item._meta.model_name),
kwargs={'pk': item.pk}))"""
return redirect(to=reverse_lazy('sapl.compilacao:ta_text_edit',
kwargs={'ta_id': ta.pk}))
def import_pattern(self):
from unipath import Path
compilacao_app = Path(__file__).ancestor(1)
print(compilacao_app)
# print(compilacao_app)
with open(compilacao_app + '/compilacao_data_tables.sql', 'r') as f:
lines = f.readlines()
lines = [line.rstrip('\n') for line in lines]
@ -251,7 +273,19 @@ class IntegracaoTaView(TemplateView):
abstract = True
class CompMixin:
class CompMixin(PermissionRequiredMixin):
permission_required = []
def has_permission(self):
perms = self.get_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
@property
def ta(self):
ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id'])
return ta
def get_context_data(self, **kwargs):
context = super(CompMixin, self).get_context_data(**kwargs)
@ -271,6 +305,7 @@ class TipoTaListView(CompMixin, ListView):
model = TipoTextoArticulado
paginate_by = 10
verbose_name = model._meta.verbose_name
permission_required = 'compilacao.list_tipotextoarticulado'
@property
def title(self):
@ -287,6 +322,7 @@ class TipoTaCreateView(CompMixin, FormMessagesMixin, CreateView):
template_name = "crud/form.html"
form_valid_message = _('Registro criado com sucesso!')
form_invalid_message = _('O registro não foi criado.')
permission_required = 'compilacao.add_tipotextoarticulado'
def get(self, request, *args, **kwargs):
self.object = None
@ -308,12 +344,14 @@ class TipoTaCreateView(CompMixin, FormMessagesMixin, CreateView):
class TipoTaDetailView(CompMixin, DetailView):
model = TipoTextoArticulado
permission_required = 'compilacao.detail_tipotextoarticulado'
class TipoTaUpdateView(CompMixin, UpdateView):
model = TipoTextoArticulado
form_class = TipoTaForm
template_name = "crud/form.html"
permission_required = 'compilacao.change_tipotextoarticulado'
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@ -336,6 +374,7 @@ class TipoTaUpdateView(CompMixin, UpdateView):
class TipoTaDeleteView(CompMixin, DeleteView):
model = TipoTextoArticulado
template_name = "crud/confirm_delete.html"
permission_required = 'compilacao.delete_tipotextoarticulado'
@property
def detail_url(self):
@ -350,6 +389,7 @@ class TaListView(CompMixin, ListView):
model = TextoArticulado
paginate_by = 10
verbose_name = model._meta.verbose_name
permission_required = 'compilacao.list_textoarticulado'
@property
def title(self):
@ -389,6 +429,7 @@ class TaCreateView(CompMixin, FormMessagesMixin, CreateView):
template_name = "crud/form.html"
form_valid_message = _('Registro criado com sucesso!')
form_invalid_message = _('O registro não foi criado.')
permission_required = 'compilacao.add_tipotextoarticulado'
def get_success_url(self):
return reverse_lazy('sapl.compilacao:ta_detail',
@ -403,6 +444,7 @@ class TaUpdateView(CompMixin, UpdateView):
model = TextoArticulado
form_class = TaForm
template_name = "crud/form.html"
permission_required = 'compilacao.change_textoarticulado'
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@ -425,6 +467,7 @@ class TaUpdateView(CompMixin, UpdateView):
class TaDeleteView(CompMixin, DeleteView):
model = TextoArticulado
template_name = "crud/confirm_delete.html"
permission_required = 'compilacao.delete_textoarticulado'
@property
def detail_url(self):
@ -464,14 +507,11 @@ class NotaMixin(DispositivoSuccessUrlMixin):
return initial
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(NotaMixin, self).dispatch(*args, **kwargs)
class NotasCreateView(NotaMixin, CreateView):
template_name = 'compilacao/ajax_form.html'
form_class = NotaForm
permission_required = 'compilacao.add_nota'
def get(self, request, *args, **kwargs):
flag_action, modelo_nota = self.get_modelo_nota(request)
@ -506,6 +546,7 @@ class NotasEditView(NotaMixin, UpdateView):
model = Nota
template_name = 'compilacao/ajax_form.html'
form_class = NotaForm
permission_required = 'compilacao.change_nota'
def get(self, request, *args, **kwargs):
flag_action, modelo_nota = self.get_modelo_nota(request)
@ -517,6 +558,8 @@ class NotasEditView(NotaMixin, UpdateView):
class NotasDeleteView(NotaMixin, TemplateView):
permission_required = 'compilacao.delete_nota'
def get(self, request, *args, **kwargs):
nt = Nota.objects.get(pk=self.kwargs['pk'])
nt.delete()
@ -535,59 +578,28 @@ class VideMixin(DispositivoSuccessUrlMixin):
return initial
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(VideMixin, self).dispatch(*args, **kwargs)
def choice_model_type_foreignkey_in_extenal_views(id_tipo_ta=None):
yield None, '-------------'
if not id_tipo_ta:
return
tipo_ta = TipoTextoArticulado.objects.get(pk=id_tipo_ta)
integrations_view_names = get_integrations_view_names()
for item in integrations_view_names:
if hasattr(item, 'model_type_foreignkey'):
if (tipo_ta.content_type.model == item.model.__name__.lower() and
tipo_ta.content_type.app_label ==
item.model._meta.app_label):
for i in item.model_type_foreignkey.objects.all():
yield i.pk, i
class VideCreateView(VideMixin, CreateView):
model = Vide
template_name = 'compilacao/ajax_form.html'
form_class = VideForm
permission_required = 'compilacao.add_vide'
def get(self, request, *args, **kwargs):
self.object = None
form = self.get_form()
return self.render_to_response(self.get_context_data(form=form))
"""
def get_form_kwargs(self):
kwargs = super(VideCreateView, self).get_form_kwargs()
if 'choice_model_type_foreignkey_in_extenal_views' not in kwargs:
kwargs.update({
'choice_model_type_foreignkey_in_extenal_views':
choice_model_type_foreignkey_in_extenal_views
})
return kwargs"""
class VideEditView(VideMixin, UpdateView):
model = Vide
template_name = 'compilacao/ajax_form.html'
form_class = VideForm
permission_required = 'compilacao.change_vide'
class VideDeleteView(VideMixin, TemplateView):
permission_required = 'compilacao.delete_vide'
def get(self, request, *args, **kwargs):
vd = Vide.objects.get(pk=self.kwargs['pk'])
@ -595,9 +607,26 @@ class VideDeleteView(VideMixin, TemplateView):
return HttpResponseRedirect(self.get_success_url())
class PublicacaoListView(CompMixin, ListView):
class PublicacaoMixin(CompMixin):
def dispatch(self, request, *args, **kwargs):
ta = self.ta
if not ta.tipo_ta.publicacao_func:
messages.error(request, _(
'A funcionalidade de %s está desativada para %s.') % (
TipoTextoArticulado._meta.get_field(
'publicacao_func').verbose_name,
ta.tipo_ta.descricao))
return redirect(reverse('sapl.compilacao:ta_text',
kwargs={'ta_id': self.kwargs['ta_id']}))
return PermissionRequiredMixin.dispatch(self, request, *args, **kwargs)
class PublicacaoListView(PublicacaoMixin, ListView):
model = Publicacao
verbose_name = model._meta.verbose_name
permission_required = []
@property
def title(self):
@ -605,11 +634,6 @@ class PublicacaoListView(CompMixin, ListView):
self.model._meta.verbose_name_plural,
self.ta))
@property
def ta(self):
ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id'])
return ta
@property
def create_url(self):
return reverse_lazy(
@ -626,12 +650,13 @@ class PublicacaoListView(CompMixin, ListView):
return context
class PublicacaoCreateView(CompMixin, FormMessagesMixin, CreateView):
class PublicacaoCreateView(PublicacaoMixin, FormMessagesMixin, CreateView):
model = Publicacao
form_class = PublicacaoForm
template_name = "crud/form.html"
form_valid_message = _('Registro criado com sucesso!')
form_invalid_message = _('O registro não foi criado.')
permission_required = 'compilacao.add_publicacao'
def get_success_url(self):
return reverse_lazy(
@ -650,14 +675,16 @@ class PublicacaoCreateView(CompMixin, FormMessagesMixin, CreateView):
return {'ta': self.kwargs['ta_id']}
class PublicacaoDetailView(CompMixin, DetailView):
class PublicacaoDetailView(PublicacaoMixin, DetailView):
model = Publicacao
permission_required = 'compilacao.detail_publicacao'
class PublicacaoUpdateView(CompMixin, UpdateView):
class PublicacaoUpdateView(PublicacaoMixin, UpdateView):
model = Publicacao
form_class = PublicacaoForm
template_name = "crud/form.html"
permission_required = 'compilacao.change_publicacao'
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@ -678,9 +705,10 @@ class PublicacaoUpdateView(CompMixin, UpdateView):
return self.get_success_url()
class PublicacaoDeleteView(CompMixin, DeleteView):
class PublicacaoDeleteView(PublicacaoMixin, DeleteView):
model = Publicacao
template_name = "crud/confirm_delete.html"
permission_required = 'compilacao.delete_publicacao'
@property
def detail_url(self):
@ -709,42 +737,7 @@ class TextView(CompMixin, ListView):
ta_vigencia = None
def get(self, request, *args, **kwargs):
ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id'])
self.object = ta
if ta.content_object:
item = ta.content_object
self.object = item
if hasattr(item, 'ementa') and item.ementa:
ta.ementa = item.ementa
else:
ta.ementa = _('Integração com %s sem ementa.') % item
if hasattr(item, 'observacao') and item.observacao:
ta.observacao = item.observacao
else:
ta.observacao = _('Integração com %s sem observacao.') % item
if hasattr(item, 'numero') and item.numero:
ta.numero = item.numero
else:
ta.numero = int('%s%s%s' % (
int(datetime.now().year),
int(datetime.now().month),
int(datetime.now().day)))
if hasattr(item, 'ano') and item.ano:
ta.ano = item.ano
else:
ta.ano = datetime.now().year
if hasattr(item, 'data_apresentacao'):
ta.data = item.data_apresentacao
elif hasattr(item, 'data'):
ta.data = item.data
else:
ta.data = datetime.now()
ta.save()
self.object = self.ta
return super(TextView, self).get(request, *args, **kwargs)
def get_context_data(self, **kwargs):
@ -936,8 +929,9 @@ class DispositivoView(TextView):
return itens
class TextEditView(TemplateView):
class TextEditView(CompMixin, TemplateView):
template_name = 'compilacao/text_edit.html'
permission_required = 'compilacao.change_dispositivo_edicao_dinamica'
def get_context_data(self, **kwargs):
dispositivo_id = int(self.kwargs['dispositivo_id']) \
@ -946,7 +940,7 @@ class TextEditView(TemplateView):
if dispositivo_id:
self.object = Dispositivo.objects.get(pk=dispositivo_id)
context = super(TextEditView, self).get_context_data(**kwargs)
context = super(TemplateView, self).get_context_data(**kwargs)
if not dispositivo_id:
ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id'])
@ -1721,6 +1715,12 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin):
for td in otds:
if td.dispositivo_de_alteracao:
if not self.request.user.has_perm(
'compilacao.'
'change_dispositivo_registros_compilacao'):
continue
if paradentro and not td.permitido_inserir_in(
tipb,
include_relative_autos=True,
@ -2417,11 +2417,12 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
class DispositivoDinamicEditView(
CompMixin, ActionsEditMixin, TextEditView, UpdateView):
ActionsEditMixin, TextEditView, UpdateView):
template_name = 'compilacao/text_edit_bloco.html'
model = Dispositivo
form_class = DispositivoEdicaoBasicaForm
contador = -1
permission_required = 'compilacao.change_dispositivo_edicao_dinamica',
def get_initial(self):
initial = UpdateView.get_initial(self)
@ -2615,7 +2616,6 @@ class DispositivoSearchFragmentFormView(ListView):
def get_queryset(self):
try:
n = 10
if 'max_results' in self.request.GET:
n = int(self.request.GET['max_results'])
@ -2799,6 +2799,8 @@ class DispositivoEdicaoBasicaView(CompMixin, FormMessagesMixin, UpdateView):
form_invalid_message = _('Houve erro em registrar '
'as alterações no Dispositivo')
permission_required = 'compilacao.change_dispositivo_edicao_avancada'
@property
def cancel_url(self):
return reverse_lazy(
@ -2871,6 +2873,8 @@ class DispositivoEdicaoVigenciaView(CompMixin, FormMessagesMixin, UpdateView):
form_invalid_message = _('Houve erro em registrar '
'as alterações no Dispositivo')
permission_required = 'compilacao.change_dispositivo_edicao_avancada'
@property
def cancel_url(self):
return reverse_lazy(
@ -2894,6 +2898,9 @@ class DispositivoDefinidorVigenciaView(CompMixin, FormMessagesMixin, FormView):
form_invalid_message = _('Houve erro em registrar '
'as alterações no Dispositivo')
permission_required = ('compilacao.change_dispositivo_edicao_avancada',
'compilacao.change_dispositivo_de_vigencia_global')
def get_form_kwargs(self):
kwargs = FormView.get_form_kwargs(self)
kwargs.update({
@ -2951,6 +2958,8 @@ class DispositivoEdicaoAlteracaoView(CompMixin, FormMessagesMixin, UpdateView):
form_invalid_message = _('Houve erro em registrar '
'as alterações no Dispositivo')
permission_required = 'compilacao.change_dispositivo_registros_compilacao'
@property
def cancel_url(self):
return reverse_lazy(
@ -2983,6 +2992,8 @@ class TextNotificacoesView(CompMixin, ListView, FormView):
template_name = 'compilacao/text_notificacoes.html'
form_class = TextNotificacoesForm
permission_required = 'compilacao.view_dispositivo_notificacoes'
def get(self, request, *args, **kwargs):
self.object = TextoArticulado.objects.get(pk=self.kwargs['ta_id'])
return super(TextNotificacoesView, self).get(request, *args, **kwargs)

6
sapl/crud/base.py

@ -24,6 +24,8 @@ from django.views.generic.base import ContextMixin
from django.views.generic.list import MultipleObjectMixin
from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display
from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL,
RP_LIST)
from sapl.settings import BASE_DIR
from sapl.utils import normalize
@ -32,10 +34,6 @@ logger = logging.getLogger(BASE_DIR.name)
ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \
'list', 'create', 'detail', 'update', 'delete'
# RP - Radical das permissões para "..."
RP_LIST, RP_DETAIL, RP_ADD, RP_CHANGE, RP_DELETE =\
'.list_', '.detail_', '.add_', '.change_', '.delete_',
def _form_invalid_message(msg):
return '%s %s' % (_('Formulário inválido.'), msg)

66
sapl/materia/forms.py

@ -1,7 +1,8 @@
from datetime import date, datetime
import os
from datetime import date, datetime
import django_filters
from crispy_forms.bootstrap import (Alert, FormActions, InlineCheckboxes,
InlineRadios)
from crispy_forms.helper import FormHelper
@ -17,22 +18,23 @@ 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,
to_row)
from sapl.materia.models import RegimeTramitacao, TipoDocumento, TipoProposicao
from sapl.materia.models import (MateriaLegislativa, RegimeTramitacao,
TipoDocumento, TipoProposicao)
from sapl.norma.models import (LegislacaoCitada, NormaJuridica,
TipoNormaJuridica)
from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import Protocolo
from sapl.settings import MAX_DOC_UPLOAD_SIZE
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
ChoiceWithoutValidationField, RangeWidgetOverride,
ChoiceWithoutValidationField,
MateriaPesquisaOrderingFilter, RangeWidgetOverride,
autor_label, autor_modal, models_with_gr_for_model)
import sapl
from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial,
DocumentoAcessorio, MateriaLegislativa, Numeracao,
@ -65,6 +67,33 @@ class ReceberProposicaoForm(Form):
super(ReceberProposicaoForm, self).__init__(*args, **kwargs)
class MateriaSimplificadaForm(ModelForm):
class Meta:
model = MateriaLegislativa
fields = ['tipo', 'numero', 'ano', 'data_apresentacao',
'numero_origem_externa', 'regime_tramitacao',
'em_tramitacao', 'ementa', 'texto_original']
def __init__(self, *args, **kwargs):
row1 = to_row([('tipo', 6), ('numero', 3), ('ano', 3)])
row2 = to_row([('data_apresentacao', 6), ('numero_origem_externa', 6)])
row3 = to_row([('regime_tramitacao', 6), ('em_tramitacao', 6)])
row4 = to_row([('ementa', 12)])
row5 = to_row([('texto_original', 12)])
self.helper = FormHelper()
self.helper.layout = Layout(
Fieldset(
_('Formulário Simplificado'),
row1, row2, row3, row4, row5,
form_actions(save_label='Salvar')
)
)
super(MateriaSimplificadaForm, self).__init__(*args, **kwargs)
class UnidadeTramitacaoForm(ModelForm):
class Meta:
@ -444,6 +473,8 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
label=u'Ano da Matéria',
choices=em_tramitacao)
o = MateriaPesquisaOrderingFilter()
class Meta:
model = MateriaLegislativa
fields = ['numero',
@ -453,7 +484,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
'data_apresentacao',
'data_publicacao',
'autoria__autor__tipo',
# 'autoria__autor__partido',
# FIXME 'autoria__autor__partido',
'relatoria__parlamentar_id',
'local_origem_externa',
'tramitacao__unidade_tramitacao_destino',
@ -461,29 +492,6 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
'em_tramitacao',
]
order_by = (
('', 'Selecione'),
('dataC', 'Data, Tipo, Ano, Numero - Ordem Crescente'),
('dataD', 'Data, Tipo, Ano, Numero - Ordem Decrescente'),
('tipoC', 'Tipo, Ano, Numero, Data - Ordem Crescente'),
('tipoD', 'Tipo, Ano, Numero, Data - Ordem Decrescente')
)
order_by_mapping = {
'': [],
'dataC': ['data_apresentacao', 'tipo__sigla', 'ano', 'numero'],
'dataD': ['-data_apresentacao', '-tipo__sigla', '-ano', '-numero'],
'tipoC': ['tipo__sigla', 'ano', 'numero', 'data_apresentacao'],
'tipoD': ['-tipo__sigla', '-ano', '-numero', '-data_apresentacao'],
}
def get_order_by(self, order_value):
if order_value in self.order_by_mapping:
return self.order_by_mapping[order_value]
else:
return super(MateriaLegislativaFilterSet,
self).get_order_by(order_value)
def __init__(self, *args, **kwargs):
super(MateriaLegislativaFilterSet, self).__init__(*args, **kwargs)

2
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

7
sapl/materia/urls.py

@ -4,7 +4,8 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
AcompanhamentoExcluirView,
AcompanhamentoMateriaView, AnexadaCrud,
AutoriaCrud, ConfirmarProposicao,
DespachoInicialCrud, DocumentoAcessorioCrud,
CriarProtocoloMateriaView, DespachoInicialCrud,
DocumentoAcessorioCrud,
DocumentoAcessorioEmLoteView,
LegislacaoCitadaCrud, MateriaLegislativaCrud,
MateriaLegislativaPesquisaView, MateriaTaView,
@ -34,6 +35,10 @@ urlpatterns_materia = [
TramitacaoCrud.get_urls() +
RelatoriaCrud.get_urls() +
DocumentoAcessorioCrud.get_urls())),
url(r'^materia/(?P<pk>[0-9]+)/create_simplificado$',
CriarProtocoloMateriaView.as_view(),
name='materia_create_simplificado'),
url(r'^materia/recuperar-materia', recuperar_materia),
url(r'^materia/(?P<pk>[0-9]+)/ta$',
MateriaTaView.as_view(), name='materia_ta'),

58
sapl/materia/views.py

@ -28,11 +28,11 @@ from sapl.crud.base import (ACTION_CREATE, ACTION_DELETE, ACTION_DETAIL,
ACTION_LIST, ACTION_UPDATE, RP_DETAIL, RP_LIST,
Crud, CrudAux, MasterDetailCrud,
PermissionRequiredForAppCrudMixin, make_pagination)
from sapl.materia import apps
from sapl.materia.forms import (AnexadaForm, ConfirmarProposicaoForm,
LegislacaoCitadaForm, ProposicaoForm,
TipoProposicaoForm)
from sapl.norma.models import LegislacaoCitada
from sapl.protocoloadm.models import Protocolo
from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
autor_modal, gerar_hash_arquivo, get_base_url,
montar_row_autor)
@ -40,8 +40,9 @@ import sapl
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
DocumentoAcessorioForm, MateriaLegislativaFilterSet,
PrimeiraTramitacaoEmLoteFilterSet, ReceberProposicaoForm,
TramitacaoEmLoteFilterSet, filtra_tramitacao_destino,
MateriaSimplificadaForm, PrimeiraTramitacaoEmLoteFilterSet,
ReceberProposicaoForm, TramitacaoEmLoteFilterSet,
filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status,
filtra_tramitacao_status)
from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial,
@ -67,9 +68,49 @@ TipoFimRelatoriaCrud = CrudAux.build(
TipoFimRelatoria, 'fim_relatoria')
class CriarProtocoloMateriaView(CreateView):
template_name = "crud/form.html"
form_class = MateriaSimplificadaForm
form_valid_message = _('Matéria cadastrada com sucesso!')
def get_success_url(self, materia):
return reverse('sapl.materia:materialegislativa_detail', kwargs={
'pk': materia.pk})
def get_context_data(self, **kwargs):
context = super(
CriarProtocoloMateriaView, self).get_context_data(**kwargs)
protocolo = Protocolo.objects.get(pk=self.kwargs['pk'])
context['form'].fields['tipo'].initial = protocolo.tipo_materia
context['form'].fields['numero'].initial = protocolo.numero
context['form'].fields['ano'].initial = protocolo.ano
context['form'].fields['data_apresentacao'].initial = protocolo.data
context['form'].fields[
'numero_origem_externa'].initial = protocolo.numero
context['form'].fields['ementa'].initial = protocolo.observacao
return context
def form_valid(self, form):
materia = form.save()
return redirect(self.get_success_url(materia))
class MateriaTaView(IntegracaoTaView):
model = MateriaLegislativa
model_type_foreignkey = TipoMateriaLegislativa
map_fields = {
'data': 'data_apresentacao',
'ementa': 'ementa',
'observacao': None,
'numero': 'numero',
'ano': 'ano',
}
map_funcs = {
'publicacao_func': False
}
def get(self, request, *args, **kwargs):
"""
@ -86,8 +127,15 @@ class MateriaTaView(IntegracaoTaView):
class ProposicaoTaView(IntegracaoTaView):
model = Proposicao
model_type_foreignkey = TipoProposicao
# TODO implmentar o mapa de fields e utiliza-lo em IntegracaoTaView
fields = {
map_fields = {
'data': 'data_recebimento',
'ementa': 'descricao',
'observacao': None,
'numero': 'numero_proposicao',
'ano': 'ano',
}
map_funcs = {
'publicacao_func': False
}
def get(self, request, *args, **kwargs):

2
sapl/norma/forms.py

@ -64,7 +64,7 @@ class NormaJuridicaPesquisaForm(ModelForm):
ano = forms.ModelChoiceField(
label='Ano',
required=False,
queryset=NormaJuridica.objects.order_by('ano').values_list(
queryset=NormaJuridica.objects.order_by('-ano').values_list(
'ano', flat=True).distinct(),
empty_label='Selecione'
)

11
sapl/norma/views.py

@ -28,6 +28,17 @@ TipoNormaCrud = CrudAux.build(
class NormaTaView(IntegracaoTaView):
model = NormaJuridica
model_type_foreignkey = TipoNormaJuridica
map_fields = {
'data': 'data',
'ementa': 'ementa',
'observacao': 'observacao',
'numero': 'numero',
'ano': 'ano',
}
map_funcs = {
'publicacao_func': True
}
def get(self, request, *args, **kwargs):
"""

1
sapl/painel/views.py

@ -16,7 +16,6 @@ from sapl.sessao.models import (ExpedienteMateria, OrdemDia, PresencaOrdemDia,
from .models import Cronometro
CronometroPainelCrud = Crud.build(Cronometro, '')
# FIXME mudar lógica

3
sapl/parlamentares/views.py

@ -64,8 +64,7 @@ class ProposicaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView):
class ListView(CrudBaseForListAndDetailExternalAppView.ListView):
def get_queryset(self):
return super().get_queryset().filter(
data_envio__isnull=False)
return super().get_queryset().filter(data_envio__isnull=False)
class ParticipacaoParlamentarCrud(CrudBaseForListAndDetailExternalAppView):

49
sapl/protocoloadm/forms.py

@ -1,5 +1,6 @@
from datetime import datetime
import django_filters
from crispy_forms.bootstrap import InlineRadios
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Fieldset, Layout, Submit
@ -8,19 +9,17 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import models
from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.base.models import Autor
from sapl.crispy_layout_mixin import form_actions, to_row
from sapl.materia.models import UnidadeTramitacao
from sapl.utils import (RANGE_ANOS, RangeWidgetOverride, autor_label,
autor_modal)
from sapl.utils import (RANGE_ANOS, AnoNumeroOrderingFilter,
RangeWidgetOverride, autor_label, autor_modal)
from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo,
Protocolo, TipoDocumentoAdministrativo,
TramitacaoAdministrativo)
TIPOS_PROTOCOLO = [('0', 'Enviado'), ('1', 'Recebido'), ('', 'Ambos')]
NATUREZA_PROCESSO = [('', 'Ambos'),
@ -69,6 +68,8 @@ class ProtocoloFilterSet(django_filters.FilterSet):
widget=forms.Select(
attrs={'class': 'selector'}))
o = AnoNumeroOrderingFilter()
class Meta:
model = Protocolo
fields = ['numero',
@ -77,25 +78,6 @@ class ProtocoloFilterSet(django_filters.FilterSet):
'tipo_materia',
]
order_by = (
('', 'Selecione'),
('CRE', 'Ordem Crescente'),
('DEC', 'Ordem Decrescente'),
)
order_by_mapping = {
'': [],
'CRE': ['ano', 'numero'],
'DEC': ['-ano', '-numero'],
}
def get_order_by(self, order_value):
if order_value in self.order_by_mapping:
return self.order_by_mapping[order_value]
else:
return super(ProtocoloFilterSet,
self).get_order_by(order_value)
def __init__(self, *args, **kwargs):
super(ProtocoloFilterSet, self).__init__(*args, **kwargs)
@ -163,6 +145,8 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
interessado = django_filters.CharFilter(lookup_expr='icontains')
o = AnoNumeroOrderingFilter()
class Meta:
model = DocumentoAdministrativo
fields = ['tipo',
@ -172,25 +156,6 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
'tramitacaoadministrativo__unidade_tramitacao_destino',
'tramitacaoadministrativo__status']
order_by = (
('', 'Selecione'),
('CRE', 'Ordem Crescente'),
('DEC', 'Ordem Decrescente'),
)
order_by_mapping = {
'': [],
'CRE': ['ano', 'numero'],
'DEC': ['-ano', '-numero'],
}
def get_order_by(self, order_value):
if order_value in self.order_by_mapping:
return self.order_by_mapping[order_value]
else:
return super(DocumentoAdministrativoFilterSet,
self).get_order_by(order_value)
def __init__(self, *args, **kwargs):
super(DocumentoAdministrativoFilterSet, self).__init__(*args, **kwargs)

5
sapl/protocoloadm/urls.py

@ -9,7 +9,8 @@ from sapl.protocoloadm.views import (AnularProtocoloAdmView,
DocumentoAcessorioAdministrativoView,
DocumentoAdministrativoCrud,
PesquisarDocumentoAdministrativoView,
ProtocoloDocumentoView, ProtocoloListView,
ProtocoloDocumentoView,
ProtocoloMateriaTemplateView,
ProtocoloMateriaView,
ProtocoloMostrarView,
ProtocoloPesquisaView,
@ -60,6 +61,8 @@ urlpatterns_protocolo = [
url(r'^protocoloadm/(?P<pk>\d+)/continuar$',
ProtocoloMateriaTemplateView.as_view(), name='materia_continuar'),
url(r'^protocoloadm/anular-protocolo',

100
sapl/protocoloadm/views.py

@ -12,10 +12,10 @@ from django.views.generic import CreateView, DetailView, FormView, ListView
from django.views.generic.base import TemplateView
from django_filters.views import FilterView
import sapl
from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination
from sapl.materia.models import TipoMateriaLegislativa
from sapl.utils import (create_barcode, get_client_ip)
import sapl
from sapl.utils import create_barcode, get_client_ip
from .forms import (AnularProcoloAdmForm, DocumentoAcessorioAdministrativoForm,
DocumentoAdministrativoFilterSet,
@ -26,14 +26,13 @@ from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo,
Protocolo, StatusTramitacaoAdministrativo,
TipoDocumentoAdministrativo, TramitacaoAdministrativo)
TipoDocumentoAdministrativoCrud = CrudAux.build(
TipoDocumentoAdministrativo, '')
#ProtocoloDocumentoCrud = Crud.build(Protocolo, '')
# ProtocoloDocumentoCrud = Crud.build(Protocolo, '')
# FIXME precisa de uma chave diferente para o layout
#ProtocoloMateriaCrud = Crud.build(Protocolo, '')
# ProtocoloMateriaCrud = Crud.build(Protocolo, '')
DocumentoAcessorioAdministrativoCrud = Crud.build(
@ -47,8 +46,7 @@ class DocumentoAdministrativoMixin:
if app_config and app_config.documentos_administrativos == 'O':
return True
return self.request.user.has_module_perms(
sapl.base.models.AppConfig.label)
return super().has_permission()
class DocumentoAdministrativoCrud(Crud):
@ -60,10 +58,10 @@ class DocumentoAdministrativoCrud(Crud):
'numero_protocolo', 'assunto',
'interessado', 'tramitacao', 'texto_integral']
class ListView(Crud.ListView, DocumentoAdministrativoMixin):
class ListView(DocumentoAdministrativoMixin, Crud.ListView):
pass
class DetailView(Crud.DetailView, DocumentoAdministrativoMixin):
class DetailView(DocumentoAdministrativoMixin, Crud.DetailView):
pass
@ -314,8 +312,9 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
form_valid_message = _('Matéria cadastrada com sucesso!')
permission_required = ('protocoloadm.add_protocolo',)
def get_success_url(self):
return reverse('sapl.protocoloadm:protocolo')
def get_success_url(self, protocolo):
return reverse('sapl.protocoloadm:materia_continuar', kwargs={
'pk': protocolo.pk})
def form_valid(self, form):
try:
@ -353,12 +352,25 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
protocolo.numero_paginas = self.request.POST['numero_paginas']
protocolo.observacao = self.request.POST['observacao']
protocolo.save()
return redirect(self.get_success_url())
return redirect(self.get_success_url(protocolo))
class ProtocoloMateriaTemplateView(PermissionRequiredMixin, TemplateView):
template_name = "protocoloadm/MateriaTemplate.html"
permission_required = ('protocoloadm.detail_protocolo', )
def get_context_data(self, **kwargs):
context = super(ProtocoloMateriaTemplateView, self).get_context_data(
**kwargs)
protocolo = Protocolo.objects.get(pk=self.kwargs['pk'])
context.update({'protocolo': protocolo})
return context
class PesquisarDocumentoAdministrativoView(PermissionRequiredMixin,
FilterView,
DocumentoAdministrativoMixin):
class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
PermissionRequiredMixin,
FilterView):
model = DocumentoAdministrativo
filterset_class = DocumentoAdministrativoFilterSet
paginate_by = 10
@ -565,65 +577,13 @@ class TramitacaoAdmCrud(MasterDetailCrud):
class UpdateView(MasterDetailCrud.UpdateView):
form_class = TramitacaoAdmEditForm
class ListView(MasterDetailCrud.ListView, DocumentoAdministrativoMixin):
class ListView(DocumentoAdministrativoMixin, MasterDetailCrud.ListView):
def get_queryset(self):
qs = super(MasterDetailCrud.ListView, self).get_queryset()
kwargs = {self.crud.parent_field: self.kwargs['pk']}
return qs.filter(**kwargs).order_by('-data_tramitacao', '-id')
class DetailView(MasterDetailCrud.DetailView,
DocumentoAdministrativoMixin):
class DetailView(DocumentoAdministrativoMixin,
MasterDetailCrud.DetailView):
pass
"""
def get_nome_autor(request):
nome_autor = ''
if request.method == 'GET':
id = request.GET.get('id', '')
try:
autor = Autor.objects.get(pk=id)
if autor.parlamentar:
nome_autor = autor.parlamentar.nome_parlamentar
elif autor.comissao:
nome_autor = autor.comissao.nome
except ObjectDoesNotExist:
pass
return HttpResponse("{\"nome\":\"" + nome_autor + "\"}",
content_type="application/json; charset=utf-8")"""
"""
def pesquisa_autores(request):
q = ''
if request.method == 'GET':
q = request.GET.get('q', '')
autor = Autor.objects.filter(
Q(nome__icontains=q) |
Q(parlamentar__nome_parlamentar__icontains=q) |
Q(comissao__nome__icontains=q)
)
autor = Autor.objects.filter(nome__icontains=q)
autores = []
for a in autor:
nome = ''
if a.nome:
nome = a.nome
elif a.parlamentar:
nome = a.parlamentar.nome_parlamentar
elif a.comissao:
nome = a.comissao.nome
autores.append((a.id, nome))
autores = sorted(autores, key=lambda x: x[1])
return HttpResponse(json.dumps(autores,
sort_keys=True,
ensure_ascii=False),
content_type="application/json; charset=utf-8")
"""

62
sapl/rules/map_rules.py

@ -1,7 +1,6 @@
from sapl.base import models as base
from sapl.comissoes import models as comissoes
from sapl.compilacao import models as compilacao
from sapl.crud.base import RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL, RP_LIST
from sapl.lexml import models as lexml
from sapl.materia import models as materia
from sapl.norma import models as norma
@ -16,7 +15,47 @@ from sapl.rules import (SAPL_GROUP_ADMINISTRATIVO, SAPL_GROUP_ANONYMOUS,
SAPL_GROUP_PROTOCOLO, SAPL_GROUP_SESSAO)
from sapl.sessao import models as sessao
# RP = Radicao de Permissão
"""
Todas as permissões do django framework seguem o padrão
[app_label].[radical_de_permissao]_[model]
ou seja, em sapl.norma.NormaJuridica, por exemplo, o django framework cria
três permissões registadas na classe Permission:
definição uso
- add_normajuridica norma.add_normajuridica
- change_normajuridica norma.change_normajuridica
- delete_normajuridica norma.delete_normajuridica
No SAPL foram acrescidas em todos os models as duas regras abaixo, adicionadas
com o Signal post_migrate `create_proxy_permissions`
localizado em sapl.rules.apps.py.
- list_normajuridica norma.list_normajuridica
- detail_normajuridica norma.detail_normajuridica
Tanto o Crud implementado em sapl.crud.base.py quanto o Signal post_migrate
`update_groups` que é responsável por ler o mapa deste
arquivo (sapl.rules.map_rules.py) e criar os grupos definidos na regra de
negócio trabalham com os cinco radiais de permissão
e com qualquer outro tipo de permissão customizada, nesta ordem de precedência.
Os cinco radicais de permissão completa são:
RP_LIST, RP_DETAIL, RP_ADD, RP_CHANGE, RP_DELETE =\
'.list_', '.detail_', '.add_', '.change_', '.delete_',
Tanto a app crud quanto a app rules estão sempre ligadas a um model. Ao lidar
com permissões, sempre é analisado se é apenas um radical ou permissão
completa, sendo apenas um radical, a permissão completa é montada com base
no model associado.
"""
RP_LIST, RP_DETAIL, RP_ADD, RP_CHANGE, RP_DELETE =\
'.list_', '.detail_', '.add_', '.change_', '.delete_',
__base__ = [RP_LIST, RP_DETAIL, RP_ADD, RP_CHANGE, RP_DELETE]
__listdetailchange__ = [RP_LIST, RP_DETAIL, RP_CHANGE]
@ -74,10 +113,12 @@ rules_group_materia = {
(compilacao.Dispositivo, __base__ + [
'change_dispositivo_edicao_dinamica',
# sobre a regra abaixo deve ser pensada sobre isso
# abre possibilidade pra haver compilacao de emenda com projeto
# mas testes devem ser feitos especificamente para materia
# 'change_dispositivo_registros_compilacao'
# TODO: adicionar 'change_dispositivo_registros_compilacao'
# quando testes forem feitos para permtir que matérias possam
# ser vinculadas a outras matérias via registro de compilação.
# Normalmente emendas e/ou projetos substitutivos podem alterar
# uma matéria original. Fazer esse registro de compilação
# oferecia um autografo eletrônico pronto ser convertido em Norma.
])
]
}
@ -95,10 +136,11 @@ rules_group_norma = {
(compilacao.Vide, __base__),
(compilacao.Nota, __base__),
(compilacao.Dispositivo, __base__ + [
'change_dispositivo_notificacoes',
'view_dispositivo_notificacoes',
'change_dispositivo_edicao_dinamica',
'change_dispositivo_edicao_avancada',
'change_dispositivo_registros_compilacao'
'change_dispositivo_registros_compilacao',
'change_dispositivo_de_vigencia_global'
])
]
}
@ -163,8 +205,8 @@ rules_group_geral = {
(comissoes.TipoComissao, __base__),
(comissoes.Periodo, __base__),
(materia.AssuntoMateria, []), # não há implementação
(materia.MateriaAssunto, []), # não há implementação
(materia.AssuntoMateria, __base__), # não há implementação
(materia.MateriaAssunto, __base__), # não há implementação
(materia.TipoProposicao, __base__),
(materia.TipoMateriaLegislativa, __base__),
(materia.RegimeTramitacao, __base__),

89
sapl/rules/tests/test_rules.py

@ -1,19 +1,22 @@
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.base.models import CasaLegislativa, ProblemaMigracao
from sapl.compilacao.models import (PerfilEstruturalTextoArticulado,
TipoDispositivo,
TipoDispositivoRelationship)
from sapl.materia.models import AcompanhamentoMateria
from sapl.rules import SAPL_GROUPS, map_rules
from sapl.test_urls import create_perms_post_migrate
from scripts.lista_permissions_in_decorators import \
lista_permissions_in_decorators
from scripts.lista_urls import lista_urls
sapl_appconfs = [apps.get_app_config(n[5:]) for n in settings.SAPL_APPS]
sapl_models = []
@ -26,7 +29,7 @@ sapl_models.reverse()
def test_groups_in_rules_patterns(group_item):
test = False
for rules_group in rules_patterns:
for rules_group in map_rules.rules_patterns:
if rules_group['group'] == group_item:
test = True
@ -37,7 +40,7 @@ def test_groups_in_rules_patterns(group_item):
def test_models_in_rules_patterns(model_item):
test = False
for rules_group in rules_patterns:
for rules_group in map_rules.rules_patterns:
rules_model = rules_group['rules']
for rm in rules_model:
if rm[0] == model_item:
@ -49,6 +52,75 @@ def test_models_in_rules_patterns(model_item):
str(model_item),
model_item._meta.verbose_name)
# __falsos_positivos__
__fp__in__test_permission_of_models_in_rules_patterns = {
map_rules.RP_ADD: [CasaLegislativa,
ProblemaMigracao,
TipoDispositivo,
TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado],
map_rules.RP_CHANGE: [ProblemaMigracao,
AcompanhamentoMateria,
TipoDispositivo,
TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado],
map_rules.RP_DELETE: [CasaLegislativa,
ProblemaMigracao,
TipoDispositivo,
TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado],
map_rules.RP_LIST: [ProblemaMigracao,
AcompanhamentoMateria,
TipoDispositivo,
TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado],
map_rules.RP_DETAIL: [ProblemaMigracao,
AcompanhamentoMateria,
TipoDispositivo,
TipoDispositivoRelationship,
PerfilEstruturalTextoArticulado]
}
@pytest.mark.django_db(transaction=False)
@pytest.mark.parametrize('model_item', sapl_models)
def test_permission_of_models_in_rules_patterns(model_item):
create_perms_post_migrate(model_item._meta.app_config)
permissions = map_rules.__base__ + list(
filter(
lambda perm: not perm.startswith(
'detail_') and not perm.startswith('list_'),
map(lambda x: x[0],
model_item._meta.permissions))
)
__fp__ = __fp__in__test_permission_of_models_in_rules_patterns
for perm in permissions:
if perm in __fp__ and model_item in __fp__[perm]:
continue
test = False
for rules_group in map_rules.rules_patterns:
rules_model = rules_group['rules']
for rm in rules_model:
model = rm[0]
rules = rm[1]
if model == model_item:
if perm in rules:
test = True
break
assert test, _('A permissão (%s) do model (%s) não foi adicionado em '
'nenhum grupo padrão para regras de acesso.') % (
perm,
str(model_item))
@pytest.mark.django_db(transaction=False)
@pytest.mark.parametrize('model_item', sapl_models)
@ -57,7 +129,7 @@ def test_permission_of_rules_exists(model_item):
print(model_item)
create_perms_post_migrate(model_item._meta.app_config)
for rules_group in rules_patterns:
for rules_group in map_rules.rules_patterns:
rules_model = rules_group['rules']
for rm in rules_model:
model = rm[0]
@ -77,7 +149,8 @@ def test_permission_of_rules_exists(model_item):
content_type=content_type,
codename=codename).exists()
assert p, _('Permissão (%s) no model (%s) não existe.') % (
assert p, _('Permissão (%s) associada ao model (%s) '
'não está em _meta.permissions.') % (
codename,
model_item)

21
sapl/sessao/forms.py

@ -12,7 +12,9 @@ from sapl.crispy_layout_mixin import form_actions, to_row
from sapl.materia.forms import MateriaLegislativaFilterSet
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.parlamentares.models import Parlamentar
from sapl.utils import RANGE_DIAS_MES, RANGE_MESES, autor_label, autor_modal
from sapl.utils import (RANGE_DIAS_MES, RANGE_MESES,
MateriaPesquisaOrderingFilter, autor_label,
autor_modal)
from .models import (Bancada, ExpedienteMateria, Orador, OradorExpediente,
OrdemDia, SessaoPlenaria, SessaoPlenariaPresenca)
@ -21,7 +23,10 @@ from .models import (Bancada, ExpedienteMateria, Orador, OradorExpediente,
def recupera_anos():
try:
anos_list = SessaoPlenaria.objects.all().dates('data_inicio', 'year')
anos = [(k.year, k.year) for k in anos_list]
# a listagem deve ser em ordem descrescente, mas por algum motivo
# a adicao de .order_by acima depois do all() nao surte efeito
# apos a adicao do .dates(), por isso o reversed() abaixo
anos = [(k.year, k.year) for k in reversed(anos_list)]
return anos
except:
return []
@ -203,6 +208,8 @@ class SessaoPlenariaFilterSet(django_filters.FilterSet):
class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet):
o = MateriaPesquisaOrderingFilter()
class Meta:
model = MateriaLegislativa
fields = ['numero',
@ -212,20 +219,12 @@ class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet):
'data_apresentacao',
'data_publicacao',
'autoria__autor__tipo',
# 'autoria__autor__partido',
# FIXME 'autoria__autor__partido',
'relatoria__parlamentar_id',
'local_origem_externa',
'em_tramitacao',
]
order_by = (
('', 'Selecione'),
('dataC', 'Data, Tipo, Ano, Numero - Ordem Crescente'),
('dataD', 'Data, Tipo, Ano, Numero - Ordem Decrescente'),
('tipoC', 'Tipo, Ano, Numero, Data - Ordem Crescente'),
('tipoD', 'Tipo, Ano, Numero, Data - Ordem Decrescente')
)
def __init__(self, *args, **kwargs):
super(MateriaLegislativaFilterSet, self).__init__(*args, **kwargs)

10
sapl/sessao/views.py

@ -29,7 +29,6 @@ from sapl.materia.views import MateriaLegislativaPesquisaView
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
@ -45,7 +44,6 @@ 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, '')
@ -61,11 +59,9 @@ TipoResultadoVotacaoCrud = CrudAux.build(
def reordernar_materias_expediente(request, pk):
expedientes = ExpedienteMateria.objects.filter(
sessao_plenaria_id=pk)
exp_num = 1
for e in expedientes:
for exp_num, e in enumerate(expedientes, 1):
e.numero_ordem = exp_num
e.save()
exp_num += 1
return HttpResponseRedirect(
reverse('sapl.sessao:expedientemateria_list', kwargs={'pk': pk}))
@ -74,11 +70,9 @@ def reordernar_materias_expediente(request, pk):
def reordernar_materias_ordem(request, pk):
ordens = OrdemDia.objects.filter(
sessao_plenaria_id=pk)
ordem_num = 1
for o in ordens:
for ordem_num, o in enumerate(ordens, 1):
o.numero_ordem = ordem_num
o.save()
ordem_num += 1
return HttpResponseRedirect(
reverse('sapl.sessao:ordemdia_list', kwargs={'pk': pk}))

4
sapl/settings.py

@ -132,8 +132,8 @@ TEMPLATES = [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
"django.core.context_processors.media",
"django.core.context_processors.static",
"django.template.context_processors.media",
"django.template.context_processors.static",
'django.contrib.messages.context_processors.messages',
'sapl.context_processors.parliament_info',
],

48
sapl/templates/compilacao/ajax_actions_dinamic_edit.html

@ -1,21 +1,23 @@
{% load i18n %}
<div class="btn-toolbar pull-right" role="toolbar" >
{% if perms.compilacao.change_dispositivo_registros_compilacao %}
{% if object.tipo_dispositivo.dispositivo_de_articulacao and object.tipo_dispositivo.dispositivo_de_alteracao %}
<div class="btn-group " role="group">
<button type="button" class="btn btn-default btn-sm btn-compila" pk="{{object.pk}}" action="get_form_revogacao" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
{% trans "Registrar Revogação" %}
{% if object.tipo_dispositivo.dispositivo_de_articulacao and object.tipo_dispositivo.dispositivo_de_alteracao %}
<div class="btn-group " role="group">
<button type="button" class="btn btn-default btn-sm btn-compila" pk="{{object.pk}}" action="get_form_revogacao" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
Registrar Revogação
</button>
<button type="button" class="btn btn-default btn-sm btn-compila" pk="{{object.pk}}" action="get_form_alteracao" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
Registrar Alteração
</button>
<button type="button" class="btn btn-default btn-sm btn-compila" pk="{{object.pk}}" action="get_form_inclusao" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
Registrar Inclusão
</button>
</button>
<button type="button" class="btn btn-default btn-sm btn-compila" pk="{{object.pk}}" action="get_form_alteracao" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
{% trans "Registrar Alteração" %}
</button>
<button type="button" class="btn btn-default btn-sm btn-compila" pk="{{object.pk}}" action="get_form_inclusao" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
{% trans "Registrar Inclusão" %}
</button>
</div>
{%endif%}
</div>
{%endif%}
{% endif %}
<div class="btn-group " role="group">
<button type="button" class="btn btn-default btn-sm radius-right" data-toggle="dropdown" aria-haspopup="true" aria-expanded="true">
<i class="fa fa-edit fa-lg"></i>
@ -25,7 +27,9 @@
<li><a class="btn-editor-type" editortype="construct">Construtor</a></li>
<li><a class="btn-editor-type" editortype="textarea">Editor Simples</a></li>
<li><a class="btn-editor-type" editortype="tinymce">Editor Tinymce</a></li>
<li><a class="btn-editor-avancado" href="{% url 'sapl.compilacao:dispositivo_edit' object.ta_id object.pk %}" >Editor Avançado</a></li>
{% if perms.compilacao.change_dispositivo_edicao_avancada %}
<li><a class="btn-editor-avancado" href="{% url 'sapl.compilacao:dispositivo_edit' object.ta_id object.pk %}" >Editor Avançado</a></li>
{% endif %}
</ul>
</div>
</div>
@ -61,11 +65,13 @@
{% endfor %}
{%endif%}
</div>
{% if not object.ta_publicado and not object.dispositivo_subsequente and not object.tipo_dispositivo.dispositivo_de_alteracao%}
<div class="btn-group " role="group">
<button type="button" class="btn-action btn btn-xs radius-right {% if object.pk == object.dispositivo_vigencia_id %}btn-primary{%else%}btn-default{%endif%}" pk="{{object.pk}}" action="json_set_dvt" title="{% if object.pk == object.dispositivo_vigencia_id %}{% trans 'Dispositivo de Vigência Atual'%}{%else%}{% trans 'Tornar este o Dispositivo de Vigência de todo o Texto Articulado.'%}{%endif%}">
DVt
</button>
</div>
{%endif%}
{% if perms.compilacao.change_dispositivo_de_vigencia_global %}
{% if not object.ta_publicado and not object.dispositivo_subsequente and not object.tipo_dispositivo.dispositivo_de_alteracao%}
<div class="btn-group " role="group">
<button type="button" class="btn-action btn btn-xs radius-right {% if object.pk == object.dispositivo_vigencia_id %}btn-primary{%else%}btn-default{%endif%}" pk="{{object.pk}}" action="json_set_dvt" title="{% if object.pk == object.dispositivo_vigencia_id %}{% trans 'Dispositivo de Vigência Atual'%}{%else%}{% trans 'Tornar este o Dispositivo de Vigência de todo o Texto Articulado.'%}{%endif%}">
DVt
</button>
</div>
{% endif %}
{% endif %}
</div>

8
sapl/templates/compilacao/dispositivo_form.html

@ -10,10 +10,10 @@
{% url 'sapl.compilacao:dispositivo_edit_vigencia' object.ta_id object.pk as edit_vigencia_url %}
{% url 'sapl.compilacao:dispositivo_edit_alteracao' object.ta_id object.pk as edit_alteracao_url %}
{% url 'sapl.compilacao:dispositivo_edit_definidor_vigencia' object.ta_id object.pk as edit_definidor_vigencia_url %}
<li {% if request.get_full_path == edit_url %}class="active"{%endif%}><a class="btn-warning" href="{{ edit_url }}">{% trans 'Dados Básicos' %}</a></li>
<li {% if request.get_full_path == edit_vigencia_url %}class="active"{%endif%}><a class="btn-warning" href="{{ edit_vigencia_url }}" >{% trans 'Vigência' %}</a></li>
<li {% if request.get_full_path == edit_definidor_vigencia_url %}class="active"{%endif%}><a class="btn-danger" href="{{ edit_definidor_vigencia_url }}" >{% trans 'Definidor de Vigência' %}</a></li>
<li {% if request.get_full_path == edit_alteracao_url %}class="active"{%endif%}><a class="btn-danger" href="{{ edit_alteracao_url }}" >{% trans 'Alteração' %}</a></li>
{% if perms.compilacao.change_dispositivo_edicao_avancada %}<li {% if request.get_full_path == edit_url %}class="active"{%endif%}><a class="btn-warning" href="{{ edit_url }}">{% trans 'Dados Básicos' %}</a></li>{% endif %}
{% if perms.compilacao.change_dispositivo_edicao_avancada %}<li {% if request.get_full_path == edit_vigencia_url %}class="active"{%endif%}><a class="btn-warning" href="{{ edit_vigencia_url }}" >{% trans 'Vigência' %}</a></li>{% endif %}
{% if perms.compilacao.change_dispositivo_de_vigencia_global %}<li {% if request.get_full_path == edit_definidor_vigencia_url %}class="active"{%endif%}><a class="btn-danger" href="{{ edit_definidor_vigencia_url }}" >{% trans 'Definidor de Vigência' %}</a></li>{% endif %}
{% if perms.compilacao.change_dispositivo_registros_compilacao %}<li {% if request.get_full_path == edit_alteracao_url %}class="active"{%endif%}><a class="btn-danger" href="{{ edit_alteracao_url }}" >{% trans 'Alteração' %}</a></li>{% endif %}
</ul>
{% endblock sections_nav %}{% trans '' %}

12
sapl/templates/compilacao/publicacao_list.html

@ -5,11 +5,13 @@
{% block base_content %}
<div class="actions btn-group pull-right" role="group">
<a href="{{ view.create_url }}" class="btn btn-default">
{% trans 'Adicionar'%} {%model_verbose_name 'sapl.compilacao.models.Publicacao'%}
</a>
</div>
{% if perms.compilacao.add_publicacao %}
<div class="actions btn-group pull-right" role="group">
<a href="{{ view.create_url }}" class="btn btn-default">
{% trans 'Adicionar'%} {%model_verbose_name 'sapl.compilacao.models.Publicacao'%}
</a>
</div>
{% endif %}
{% if not object_list %}
<p>{{ NO_ENTRIES_MSG }}</p>

14
sapl/templates/compilacao/text_edit.html

@ -15,14 +15,16 @@
{% endblock %}
{% block actions %}
<div class="clearfix">
<div class="actions btn-toolbar pull-right" role="toolbar">
<div class="actions btn-group" role="group">
<a href="{% url 'sapl.compilacao:ta_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Metadados do Texto Articulado' %}</a>
{% include 'compilacao/textoarticulado_menu_config.html' %}
{% if perms.compilacao.change_textoarticulado %}
<div class="clearfix">
<div class="actions btn-toolbar pull-right" role="toolbar">
<div class="actions btn-group" role="group">
<a href="{% url 'sapl.compilacao:ta_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Metadados do Texto Articulado' %}</a>
{% include 'compilacao/textoarticulado_menu_config.html' %}
</div>
</div>
</div>
</div>
{% endif %}
{% endblock actions %}
{% block base_content %}{{block.super}}

18
sapl/templates/compilacao/text_list.html

@ -9,17 +9,17 @@
{{block.super}}
<link rel="stylesheet" href="{% sass_src 'styles/compilacao.scss' %}" type="text/css">
{% endblock %}
{% block extra_sections_nav %}{% endblock %}
{% block base_content %}
{% block actions %}
<div class="clearfix">
<div class="actions btn-group pull-right" role="group">
{% if user.is_authenticated %}
<a href="{% url 'sapl.compilacao:ta_text_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Texto' %}</a>
{% endif %}
{% if perms.compilacao.change_dispositivo_edicao_dinamica %}
{% block actions %}
<div class="clearfix">
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'sapl.compilacao:ta_text_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Texto' %}</a>
</div>
</div>
</div>
{% endblock actions %}
{% endblock actions %}
{% endif %}
{% block detail_content %}
{{block.super}}

18
sapl/templates/compilacao/textoarticulado_detail.html

@ -8,14 +8,20 @@
{%if object %}
<li>
{% if object.content_object%}
<a href="{% url object|urldetail_content_type object.content_object.pk %}" title="{% trans 'Ir para '%}{{object.content_object}}">Início</a>
<a href="{% url object|urldetail_content_type object.content_object.pk %}" title="{% trans 'Voltar para '%}{{object.content_object}}">{% trans 'Voltar para '%}{{object.content_object}}</a>
{%else%}
<a href="{% url 'sapl.compilacao:ta_detail' object.pk %}">{% trans 'Início' %}</a>
{%endif%}
</li>
<li><a href="{% url 'sapl.compilacao:ta_pub_list' object.pk %}">{% model_verbose_name_plural 'sapl.compilacao.models.Publicacao' %}</a></li>
<li><a href="{% url 'sapl.compilacao:ta_text_notificacoes' object.pk %}">{% trans 'Notificações' %}</a></li>
<li><a href="{% url 'sapl.compilacao:ta_text' object.pk %}">{% trans 'Texto' %}</a></li>
{% if object.tipo_ta.publicacao_func %}
<li><a href="{% url 'sapl.compilacao:ta_pub_list' object.pk %}">{% model_verbose_name_plural 'sapl.compilacao.models.Publicacao' %}</a></li>
{% endif %}
{% if perms.compilacao.view_dispositivo_notificacoes %}
<li><a href="{% url 'sapl.compilacao:ta_text_notificacoes' object.pk %}">{% trans 'Notificações' %}</a></li>
{% endif %}
{% block extra_sections_nav %}
<li><a href="{% url 'sapl.compilacao:ta_text' object.pk %}">{% trans 'Texto' %}</a></li>
{% endblock %}
{% endif %}
</ul>
{% endblock %}
@ -25,8 +31,10 @@
{% block actions %}
<div class="clearfix">
<div class="actions btn-group pull-right" role="group">
{% if user.is_authenticated %}
{% if perms.compilacao.change_textoarticulado %}
<a href="{% url 'sapl.compilacao:ta_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Metadados do Texto Articulado' %}</a>
{% endif %}
{% if perms.compilacao.change_dispositivo_edicao_dinamica %}
<a href="{% url 'sapl.compilacao:ta_text_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Texto' %}</a>
{% endif %}
</div>

14
sapl/templates/compilacao/textoarticulado_list.html

@ -8,12 +8,14 @@
{% endblock detail_content %}
{% block actions %}
<div class="actions btn-group pull-right clearfix" role="group">
<a href="{{ view.create_url }}" class="btn btn-default">
{% trans 'Adicionar'%} {%model_verbose_name 'sapl.compilacao.models.TextoArticulado'%}
</a>
{% include 'compilacao/textoarticulado_menu_config.html' %}
</div>
{% if perms.compilacao.add_textoarticulado %}
<div class="actions btn-group pull-right clearfix" role="group">
<a href="{{ view.create_url }}" class="btn btn-default">
{% trans 'Adicionar'%} {%model_verbose_name 'sapl.compilacao.models.TextoArticulado'%}
</a>
{% include 'compilacao/textoarticulado_menu_config.html' %}
</div>
{% endif %}
{% endblock actions %}
<table class="table table-striped table-hover">

18
sapl/templates/compilacao/textoarticulado_menu_config.html

@ -4,11 +4,15 @@
<i class="fa fa-cog fa-1x fa-fw"></i>
</button>
<ul class="dropdown-menu" role="menu">
<li><a href="{% url 'sapl.compilacao:tipo_ta_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoTextoArticulado'%}</a></li>
<li><a href="{% url 'sapl.compilacao:tipopublicacao_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoPublicacao'%}</a></li>
<li><a href="{% url 'sapl.compilacao:veiculopublicacao_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.VeiculoPublicacao'%}</a></li>
<li><a href="{% url 'sapl.compilacao:tiponota_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoNota'%}</a></li>
<li><a href="{% url 'sapl.compilacao:tipovide_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoVide'%}</a></li>
<li><a href="{% url 'sapl.compilacao:tipodispositivo_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoDispositivo'%}</a></li>
<li><a href="#">TODO: Perfil Estrutural de Textos Articulados</a></li>
{% if perms.compilacao.list_tipotextoarticulado %}<li><a href="{% url 'sapl.compilacao:tipo_ta_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoTextoArticulado'%}</a></li>{% endif %}
{% if perms.compilacao.list_tipo_publicacao %}<li><a href="{% url 'sapl.compilacao:tipopublicacao_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoPublicacao'%}</a></li>{% endif %}
{% if perms.compilacao.list_veiculopublicacao %}<li><a href="{% url 'sapl.compilacao:veiculopublicacao_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.VeiculoPublicacao'%}</a></li>{% endif %}
{% if perms.compilacao.list_tiponota %}<li><a href="{% url 'sapl.compilacao:tiponota_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoNota'%}</a></li>{% endif %}
{% if perms.compilacao.list_tipovide %}<li><a href="{% url 'sapl.compilacao:tipovide_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoVide'%}</a></li>{% endif %}
{% if user.is_superuser %}
<li><a href="{% url 'sapl.compilacao:tipodispositivo_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoDispositivo'%}</a></li>
<li><a href="#">TODO: Perfil Estrutural de Textos Articulados</a></li>
{% endif %}
</ul>

5
sapl/templates/compilacao/tipotextoarticulado_detail.html

@ -9,8 +9,9 @@
<div class="clearfix">
{% block actions %}
<div class="actions btn-group pull-right" role="group">
<a class="btn btn-default" href="{% url 'sapl.compilacao:tipo_ta_edit' object.pk %}">{% trans 'Editar' %}</a>
<a class="btn btn-default" href="{% url 'sapl.compilacao:tipo_ta_delete' object.pk %}">{% trans 'Excluir' %}</a>
{% if perms.compilacao.change_tipotextoarticulado %}<a class="btn btn-default" href="{% url 'sapl.compilacao:tipo_ta_edit' object.pk %}">{% trans 'Editar' %}</a>{% endif %}
{% if perms.compilacao.delete_tipotextoarticulado %}<a class="btn btn-default" href="{% url 'sapl.compilacao:tipo_ta_delete' object.pk %}">{% trans 'Excluir' %}</a>{% endif %}
</div>
{% endblock actions %}
</div>

12
sapl/templates/compilacao/tipotextoarticulado_list.html

@ -5,11 +5,13 @@
{% block base_content %}
{% block actions %}
<div class="actions btn-group pull-right" role="group">
<a href="{{ view.create_url }}" class="btn btn-default">
{% trans 'Adicionar'%} {%model_verbose_name 'sapl.compilacao.models.TipoTextoArticulado'%}
</a>
</div>
{% if perms.compilacao.add_tipotextoarticulado %}
<div class="actions btn-group pull-right" role="group">
<a href="{{ view.create_url }}" class="btn btn-default">
{% trans 'Adicionar'%} {%model_verbose_name 'sapl.compilacao.models.TipoTextoArticulado'%}
</a>
</div>
{% endif %}
{% endblock actions %}
{% if not object_list %}

5
sapl/templates/materia/tipoproposicao_form.html

@ -22,13 +22,10 @@ $(document).ready(function(){
initial_select='';
radios.append(html_radio);
});
});
});
$('#id_content_type').trigger('change');
$("#div_id_tipo_conteudo_related_radio .controls").addClass('controls-radio-checkbox');
$('#id_content_type').trigger('change');
});

4
sapl/templates/painel/controlador.html

@ -21,4 +21,8 @@ FECHADO
<input type="submit" name="stop-painel" value="Fechar Painel" class="button primary">
<input type="submit" name="save-painel" value="Salvar" class="button primary">
</form>
</br>
</br>
<a class="btn btn-primary" href="{{request.META.HTTP_REFERER}}">Voltar</a>
{% endblock %}

25
sapl/templates/protocoloadm/MateriaTemplate.html

@ -0,0 +1,25 @@
{% extends "base.html" %}
{% load i18n common_tags%}
{% block base_content %}
<div class="alert alert-success alert-dismissible fade in" role="alert">
<p align="center"><b><font color="green">Matéria procololada com sucesso!</font></b></p>
</div>
<div align="center">
<a href="{% url 'sapl.materia:materia_create_simplificado' protocolo.pk %}" class="btn btn-warning">Criar Matéria</a>
<br /><br />
<div class="row">
<div class="col-md-6">
<a onclick="window.open('{% url 'sapl.relatorios:relatorio_etiqueta_protocolo' protocolo.numero protocolo.ano %}','Comprovante','width=400, height=200')"class="btn btn-secondary">Imprimir Etiqueta</a>
</div>
<div class="col-md-6">
<a target="popup" class="btn btn-secondary" onclick="window.open('{% url 'sapl.protocoloadm:comprovante_protocolo' protocolo.pk %}','Comprovante','width=800, height=700')">Imprimir Comprovante</a>
</div>
</div>
<br />
<a href="{% url 'sapl.protocoloadm:protocolo' %}" class="btn btn-primary">Continuar</a>
</div>
{% endblock base_content %}

8
sapl/templates/protocoloadm/protocolo_mostrar.html

@ -16,7 +16,13 @@
<br />
<strong>Documento Vinculado:</strong></br>
<a href="{% url 'sapl.protocoloadm:criar_documento' protocolo.pk %}" class="btn btn-primary">Criar Documento</a>
{% if protocolo.tipo_documento %}
<a href="{% url 'sapl.protocoloadm:criar_documento' protocolo.pk %}" class="btn btn-primary">Criar Documento</a>
{% elif protocolo.tipo_materia %}
<a href="{% url 'sapl.materia:materia_create_simplificado' protocolo.pk %}" class="btn btn-primary">Criar Matéria</a>
{% endif %}
&nbsp;&nbsp;&nbsp;&nbsp;
<a target="popup" class="btn btn-primary" onclick="window.open('{% url 'sapl.protocoloadm:comprovante_protocolo' protocolo.pk%}','Comprovante','width=800, height=600')">Comprovante
</a>

2
sapl/templates/sessao/painel.html

@ -19,7 +19,7 @@
<!--<div class="col-md-6"><a href="{% url 'sapl.painel:painel_mensagem' %}" class="btn btn-primary btn-sm active">Iniciar painel mensagem</a></div>
<div class="col-md-6"><a href="{% url 'sapl.painel:painel_parlamentar' %}" class="btn btn-primary btn-sm active">Iniciar painel parlamentares</a></div>
<div class="col-md-6"><a href="{% url 'sapl.painel:painel_votacao' %}" class="btn btn-primary btn-sm active">Iniciar painel votação</a></div> -->
<div class="col-md-6"><a href="{% url 'sapl.painel:painel_controlador' %}" target="_blank" class="btn btn-primary btn-sm active">Controlador Painel</a></div>
<div class="col-md-6"><a href="{% url 'sapl.painel:painel_controlador' %}" class="btn btn-primary btn-sm active">Controlador Painel</a></div>
</div>
<br />
<h1>Operação do Painel Eletrônico</h1>

6
sapl/urls.py

@ -17,7 +17,7 @@ from django.conf import settings
from django.conf.urls import include, url
from django.conf.urls.static import static
from django.contrib import admin
from django.views.generic.base import TemplateView
from django.views.generic.base import TemplateView, RedirectView
from django.views.static import serve as view_static_server
import sapl.api.urls
@ -33,6 +33,7 @@ import sapl.protocoloadm.urls
import sapl.relatorios.urls
import sapl.sessao.urls
urlpatterns = [
url(r'^$', TemplateView.as_view(template_name='index.html')),
url(r'^admin/', include(admin.site.urls)),
@ -53,6 +54,9 @@ urlpatterns = [
url(r'', include(sapl.base.urls)),
url(r'', include(sapl.api.urls)),
url(r'^favicon\.ico$', RedirectView.as_view(
url='/static/img/favicon.ico', permanent=True)),
]

65
sapl/utils.py

@ -1,30 +1,27 @@
from datetime import date
from functools import wraps
from unicodedata import normalize as unicodedata_normalize
import hashlib
import logging
import re
from datetime import date
from functools import wraps
from unicodedata import normalize as unicodedata_normalize
import django_filters
import magic
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button
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.fields import (GenericForeignKey, GenericRel,
GenericRelation)
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import PermissionDenied, ValidationError
from django.core.exceptions import ValidationError
from django.utils.translation import ugettext_lazy as _
from floppyforms import ClearableFileInput
import magic
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
from sapl.settings import BASE_DIR
sapl_logger = logging.getLogger(BASE_DIR.name)
@ -399,12 +396,12 @@ def permissoes(nome_grupo, app_label):
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
@ -470,6 +467,52 @@ def permissao_tb_aux(self):
"""
class MateriaPesquisaOrderingFilter(django_filters.OrderingFilter):
choices = (
('', 'Selecione'),
('dataC', 'Data, Tipo, Ano, Numero - Ordem Crescente'),
('dataD', 'Data, Tipo, Ano, Numero - Ordem Decrescente'),
('tipoC', 'Tipo, Ano, Numero, Data - Ordem Crescente'),
('tipoD', 'Tipo, Ano, Numero, Data - Ordem Decrescente')
)
order_by_mapping = {
'': [],
'dataC': ['data_apresentacao', 'tipo__sigla', 'ano', 'numero'],
'dataD': ['-data_apresentacao', '-tipo__sigla', '-ano', '-numero'],
'tipoC': ['tipo__sigla', 'ano', 'numero', 'data_apresentacao'],
'tipoD': ['-tipo__sigla', '-ano', '-numero', '-data_apresentacao'],
}
def __init__(self, *args, **kwargs):
kwargs['choices'] = self.choices
super(MateriaPesquisaOrderingFilter, self).__init__(*args, **kwargs)
def filter(self, qs, value):
_value = self.order_by_mapping[value[0]] if value else value
return super().filter(qs, _value)
class AnoNumeroOrderingFilter(django_filters.OrderingFilter):
choices = (('', 'Selecione...'),
('CRE', 'Ordem Crescente'),
('DEC', 'Ordem Decrescente'),)
order_by_mapping = {
'': [],
'CRE': ['ano', 'numero'],
'DEC': ['-ano', '-numero'],
}
def __init__(self, *args, **kwargs):
kwargs['choices'] = self.choices
super(AnoNumeroOrderingFilter, self).__init__(*args, **kwargs)
def filter(self, qs, value):
_value = self.order_by_mapping[value[0]] if value else value
return super().filter(qs, _value)
def gerar_hash_arquivo(arquivo, pk, block_size=2**20):
md5 = hashlib.md5()
arq = open(arquivo, 'rb')

1
scripts/lista_permissions_in_decorators.py

@ -2,7 +2,6 @@ import ast
import inspect
import os
if __name__ == '__main__':
import django

Loading…
Cancel
Save