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. 61
      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-crispy-forms==1.6.0
django-extensions==1.6.7 django-extensions==1.6.7
django-extra-views==0.8.0 django-extra-views==0.8.0
django-filter==0.13.0 django-filter==0.15.3
django-floppyforms==1.6.2 django-floppyforms==1.6.2
django-model-utils==2.5 django-model-utils==2.5
django-sass-processor==0.4.6 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.base.models import AppConfig
from sapl.parlamentares.models import Filiacao from sapl.parlamentares.models import Filiacao
register = template.Library() register = template.Library()

28
sapl/compilacao/forms.py

@ -42,10 +42,18 @@ class TipoTaForm(ModelForm):
label=TipoTextoArticulado._meta.get_field( label=TipoTextoArticulado._meta.get_field(
'descricao').verbose_name) 'descricao').verbose_name)
participacao_social = forms.NullBooleanField( participacao_social = forms.ChoiceField(
label=TipoTextoArticulado._meta.get_field( label=TipoTextoArticulado._meta.get_field(
'participacao_social').verbose_name, '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) required=True)
class Meta: class Meta:
@ -54,21 +62,27 @@ class TipoTaForm(ModelForm):
'descricao', 'descricao',
'content_type', 'content_type',
'participacao_social', 'participacao_social',
'publicacao_func'
] ]
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
row1 = to_row([ row1 = to_row([
('sigla', 2), ('sigla', 3),
('descricao', 4), ('descricao', 5),
('content_type', 3), ('content_type', 4),
('participacao_social', 3), ])
row2 = to_row([
(InlineRadios('participacao_social'), 3),
(InlineRadios('publicacao_func'), 3),
]) ])
self.helper = FormHelper() self.helper = FormHelper()
self.helper.layout = SaplFormLayout( self.helper.layout = SaplFormLayout(
Fieldset(_('Identificação Básica'), 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) 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, choices=YES_NO_CHOICES,
verbose_name=_('Participação Social')) 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: class Meta:
verbose_name = _('Tipo de Texto Articulado') verbose_name = _('Tipo de Texto Articulado')
verbose_name_plural = _('Tipos de Texto Articulados') verbose_name_plural = _('Tipos de Texto Articulados')
@ -635,7 +641,7 @@ class Dispositivo(BaseModel, TimestampedMixin):
ta = models.ForeignKey( ta = models.ForeignKey(
TextoArticulado, TextoArticulado,
on_delete=models.PROTECT, on_delete=models.CASCADE,
related_name='dispositivos_set', related_name='dispositivos_set',
verbose_name=_('Texto Articulado')) verbose_name=_('Texto Articulado'))
ta_publicado = models.ForeignKey( ta_publicado = models.ForeignKey(
@ -702,8 +708,10 @@ class Dispositivo(BaseModel, TimestampedMixin):
'via formulários de edição avançada.')), 'via formulários de edição avançada.')),
('change_dispositivo_registros_compilacao', _( ('change_dispositivo_registros_compilacao', _(
'Permissão de registro de compilação via editor dinâmico.')), '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.')), '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): def __str__(self):
@ -1260,7 +1268,7 @@ class Dispositivo(BaseModel, TimestampedMixin):
disps[0].get_numero_completo()) disps[0].get_numero_completo())
# dispositivo.transform_in_next() # dispositivo.transform_in_next()
else: else:
dispositivo.set_numero_completo([1, 0, 0, 0, 0, 0, ]) dispositivo.set_numero_completo([0, 0, 0, 0, 0, 0, ])
else: else:
if ';' in tipo_base.rotulo_prefixo_texto: 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) ta_id = str(d.ta_id)
d_pk = str(d.pk) d_pk = str(d.pk)
if ta_id not in ta_dpts_parents or d_pk not in ta_dpts_parents[ta_id]: 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 = {} dpts_parents = {}
ta_dpts_parents[ta_id] = dpts_parents ta_dpts_parents[ta_id] = dpts_parents
update_dispositivos_parents(dpts_parents, ta_id) 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 collections import OrderedDict
from datetime import datetime, timedelta from datetime import datetime, timedelta
import logging
import sys
from braces.views import FormMessagesMixin from braces.views import FormMessagesMixin
from django import forms from django import forms
from django.conf import settings from django.conf import settings
from django.contrib import messages 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.contrib.contenttypes.models import ContentType
from django.core.signing import Signer 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 import connection, transaction
from django.db.models import Q from django.db.models import Q
from django.db.utils import IntegrityError 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.dateparse import parse_date
from django.utils.decorators import method_decorator from django.utils.decorators import method_decorator
from django.utils.encoding import force_text 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 string_concat
from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from django.views.generic.detail import DetailView from django.views.generic.detail import DetailView
from django.views.generic.edit import (CreateView, DeleteView, FormView, from django.views.generic.edit import (CreateView, DeleteView, FormView,
@ -46,14 +47,15 @@ from sapl.compilacao.models import (Dispositivo, Nota,
VeiculoPublicacao, Vide) VeiculoPublicacao, Vide)
from sapl.compilacao.utils import (DISPOSITIVO_SELECT_RELATED, from sapl.compilacao.utils import (DISPOSITIVO_SELECT_RELATED,
DISPOSITIVO_SELECT_RELATED_EDIT) 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 from sapl.settings import BASE_DIR
TipoNotaCrud = Crud.build(TipoNota, 'tipo_nota')
TipoVideCrud = Crud.build(TipoVide, 'tipo_vide') TipoNotaCrud = CrudAux.build(TipoNota, 'tipo_nota')
TipoPublicacaoCrud = Crud.build(TipoPublicacao, 'tipo_publicacao') TipoVideCrud = CrudAux.build(TipoVide, 'tipo_vide')
VeiculoPublicacaoCrud = Crud.build(VeiculoPublicacao, 'veiculo_publicacao') TipoPublicacaoCrud = CrudAux.build(TipoPublicacao, 'tipo_publicacao')
TipoDispositivoCrud = Crud.build( VeiculoPublicacaoCrud = CrudAux.build(VeiculoPublicacao, 'veiculo_publicacao')
TipoDispositivoCrud = CrudAux.build(
TipoDispositivo, 'tipo_dispositivo') TipoDispositivo, 'tipo_dispositivo')
logger = logging.getLogger(BASE_DIR.name) logger = logging.getLogger(BASE_DIR.name)
@ -87,12 +89,31 @@ def choice_models_in_extenal_views():
return result 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): class IntegracaoTaView(TemplateView):
def get_redirect_deactivated(self): def get_redirect_deactivated(self):
messages.error( messages.error(
self.request, 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('/') return redirect('/')
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
@ -100,6 +121,16 @@ class IntegracaoTaView(TemplateView):
try: try:
if settings.DEBUG or not TipoDispositivo.objects.exists(): if settings.DEBUG or not TipoDispositivo.objects.exists():
self.import_pattern() 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: except Exception as e:
logger.error( logger.error(
string_concat( string_concat(
@ -108,6 +139,25 @@ class IntegracaoTaView(TemplateView):
str(e))) str(e)))
return self.get_redirect_deactivated() 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']) item = get_object_or_404(self.model, pk=kwargs['pk'])
related_object_type = ContentType.objects.get_for_model(item) related_object_type = ContentType.objects.get_for_model(item)
@ -128,71 +178,43 @@ class IntegracaoTaView(TemplateView):
else: else:
ta = ta[0] ta = ta[0]
if hasattr(item, 'ementa') and item.ementa: ta.data = getattr(item, map_fields['data']
ta.ementa = item.ementa if map_fields['data'] else 'xxx', datetime.now())
else:
ta.ementa = _('Integração com %s sem ementa.') % item
if hasattr(item, 'observacao') and item.observacao: ta.ementa = getattr(
ta.observacao = item.observacao item, map_fields['ementa']
else: if map_fields['ementa'] else 'xxx', _(
ta.observacao = _('Integração com %s sem observacao.') % item 'Integração com %s sem ementa.') % item)
if hasattr(item, 'numero') and item.numero: ta.observacao = getattr(
ta.numero = item.numero item, map_fields['observacao']
else: if map_fields['observacao'] else 'xxx', '')
ta.numero = int('%s%s%s' % (
ta.numero = getattr(
item, map_fields['numero']
if map_fields['numero'] else 'xxx', int('%s%s%s' % (
int(datetime.now().year), int(datetime.now().year),
int(datetime.now().month), int(datetime.now().month),
int(datetime.now().day))) int(datetime.now().day))))
if hasattr(item, 'ano') and item.ano: ta.ano = getattr(item, map_fields['ano']
ta.ano = item.ano if map_fields['ano'] else 'xxx', datetime.now().year)
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() ta.save()
return redirect(to=reverse_lazy('sapl.compilacao:ta_text', if Dispositivo.objects.filter(ta_id=ta.pk).exists():
kwargs={'ta_id': ta.pk})) 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={}))
else: else:
return redirect(to=reverse_lazy('sapl.compilacao:ta_text_edit',
return redirect(to=reverse_lazy( kwargs={'ta_id': ta.pk}))
'%s:%s_detail' % (
item._meta.app_config.name, item._meta.model_name),
kwargs={'pk': item.pk}))"""
def import_pattern(self): def import_pattern(self):
from unipath import Path from unipath import Path
compilacao_app = Path(__file__).ancestor(1) compilacao_app = Path(__file__).ancestor(1)
print(compilacao_app) # print(compilacao_app)
with open(compilacao_app + '/compilacao_data_tables.sql', 'r') as f: with open(compilacao_app + '/compilacao_data_tables.sql', 'r') as f:
lines = f.readlines() lines = f.readlines()
lines = [line.rstrip('\n') for line in lines] lines = [line.rstrip('\n') for line in lines]
@ -251,7 +273,19 @@ class IntegracaoTaView(TemplateView):
abstract = True 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): def get_context_data(self, **kwargs):
context = super(CompMixin, self).get_context_data(**kwargs) context = super(CompMixin, self).get_context_data(**kwargs)
@ -271,6 +305,7 @@ class TipoTaListView(CompMixin, ListView):
model = TipoTextoArticulado model = TipoTextoArticulado
paginate_by = 10 paginate_by = 10
verbose_name = model._meta.verbose_name verbose_name = model._meta.verbose_name
permission_required = 'compilacao.list_tipotextoarticulado'
@property @property
def title(self): def title(self):
@ -287,6 +322,7 @@ class TipoTaCreateView(CompMixin, FormMessagesMixin, CreateView):
template_name = "crud/form.html" template_name = "crud/form.html"
form_valid_message = _('Registro criado com sucesso!') form_valid_message = _('Registro criado com sucesso!')
form_invalid_message = _('O registro não foi criado.') form_invalid_message = _('O registro não foi criado.')
permission_required = 'compilacao.add_tipotextoarticulado'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.object = None self.object = None
@ -308,12 +344,14 @@ class TipoTaCreateView(CompMixin, FormMessagesMixin, CreateView):
class TipoTaDetailView(CompMixin, DetailView): class TipoTaDetailView(CompMixin, DetailView):
model = TipoTextoArticulado model = TipoTextoArticulado
permission_required = 'compilacao.detail_tipotextoarticulado'
class TipoTaUpdateView(CompMixin, UpdateView): class TipoTaUpdateView(CompMixin, UpdateView):
model = TipoTextoArticulado model = TipoTextoArticulado
form_class = TipoTaForm form_class = TipoTaForm
template_name = "crud/form.html" template_name = "crud/form.html"
permission_required = 'compilacao.change_tipotextoarticulado'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.object = self.get_object() self.object = self.get_object()
@ -336,6 +374,7 @@ class TipoTaUpdateView(CompMixin, UpdateView):
class TipoTaDeleteView(CompMixin, DeleteView): class TipoTaDeleteView(CompMixin, DeleteView):
model = TipoTextoArticulado model = TipoTextoArticulado
template_name = "crud/confirm_delete.html" template_name = "crud/confirm_delete.html"
permission_required = 'compilacao.delete_tipotextoarticulado'
@property @property
def detail_url(self): def detail_url(self):
@ -350,6 +389,7 @@ class TaListView(CompMixin, ListView):
model = TextoArticulado model = TextoArticulado
paginate_by = 10 paginate_by = 10
verbose_name = model._meta.verbose_name verbose_name = model._meta.verbose_name
permission_required = 'compilacao.list_textoarticulado'
@property @property
def title(self): def title(self):
@ -389,6 +429,7 @@ class TaCreateView(CompMixin, FormMessagesMixin, CreateView):
template_name = "crud/form.html" template_name = "crud/form.html"
form_valid_message = _('Registro criado com sucesso!') form_valid_message = _('Registro criado com sucesso!')
form_invalid_message = _('O registro não foi criado.') form_invalid_message = _('O registro não foi criado.')
permission_required = 'compilacao.add_tipotextoarticulado'
def get_success_url(self): def get_success_url(self):
return reverse_lazy('sapl.compilacao:ta_detail', return reverse_lazy('sapl.compilacao:ta_detail',
@ -403,6 +444,7 @@ class TaUpdateView(CompMixin, UpdateView):
model = TextoArticulado model = TextoArticulado
form_class = TaForm form_class = TaForm
template_name = "crud/form.html" template_name = "crud/form.html"
permission_required = 'compilacao.change_textoarticulado'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.object = self.get_object() self.object = self.get_object()
@ -425,6 +467,7 @@ class TaUpdateView(CompMixin, UpdateView):
class TaDeleteView(CompMixin, DeleteView): class TaDeleteView(CompMixin, DeleteView):
model = TextoArticulado model = TextoArticulado
template_name = "crud/confirm_delete.html" template_name = "crud/confirm_delete.html"
permission_required = 'compilacao.delete_textoarticulado'
@property @property
def detail_url(self): def detail_url(self):
@ -464,14 +507,11 @@ class NotaMixin(DispositivoSuccessUrlMixin):
return initial return initial
@method_decorator(login_required)
def dispatch(self, *args, **kwargs):
return super(NotaMixin, self).dispatch(*args, **kwargs)
class NotasCreateView(NotaMixin, CreateView): class NotasCreateView(NotaMixin, CreateView):
template_name = 'compilacao/ajax_form.html' template_name = 'compilacao/ajax_form.html'
form_class = NotaForm form_class = NotaForm
permission_required = 'compilacao.add_nota'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
flag_action, modelo_nota = self.get_modelo_nota(request) flag_action, modelo_nota = self.get_modelo_nota(request)
@ -506,6 +546,7 @@ class NotasEditView(NotaMixin, UpdateView):
model = Nota model = Nota
template_name = 'compilacao/ajax_form.html' template_name = 'compilacao/ajax_form.html'
form_class = NotaForm form_class = NotaForm
permission_required = 'compilacao.change_nota'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
flag_action, modelo_nota = self.get_modelo_nota(request) flag_action, modelo_nota = self.get_modelo_nota(request)
@ -517,6 +558,8 @@ class NotasEditView(NotaMixin, UpdateView):
class NotasDeleteView(NotaMixin, TemplateView): class NotasDeleteView(NotaMixin, TemplateView):
permission_required = 'compilacao.delete_nota'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
nt = Nota.objects.get(pk=self.kwargs['pk']) nt = Nota.objects.get(pk=self.kwargs['pk'])
nt.delete() nt.delete()
@ -535,59 +578,28 @@ class VideMixin(DispositivoSuccessUrlMixin):
return initial 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): class VideCreateView(VideMixin, CreateView):
model = Vide model = Vide
template_name = 'compilacao/ajax_form.html' template_name = 'compilacao/ajax_form.html'
form_class = VideForm form_class = VideForm
permission_required = 'compilacao.add_vide'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.object = None self.object = None
form = self.get_form() form = self.get_form()
return self.render_to_response(self.get_context_data(form=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): class VideEditView(VideMixin, UpdateView):
model = Vide model = Vide
template_name = 'compilacao/ajax_form.html' template_name = 'compilacao/ajax_form.html'
form_class = VideForm form_class = VideForm
permission_required = 'compilacao.change_vide'
class VideDeleteView(VideMixin, TemplateView): class VideDeleteView(VideMixin, TemplateView):
permission_required = 'compilacao.delete_vide'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
vd = Vide.objects.get(pk=self.kwargs['pk']) vd = Vide.objects.get(pk=self.kwargs['pk'])
@ -595,9 +607,26 @@ class VideDeleteView(VideMixin, TemplateView):
return HttpResponseRedirect(self.get_success_url()) 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 model = Publicacao
verbose_name = model._meta.verbose_name verbose_name = model._meta.verbose_name
permission_required = []
@property @property
def title(self): def title(self):
@ -605,11 +634,6 @@ class PublicacaoListView(CompMixin, ListView):
self.model._meta.verbose_name_plural, self.model._meta.verbose_name_plural,
self.ta)) self.ta))
@property
def ta(self):
ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id'])
return ta
@property @property
def create_url(self): def create_url(self):
return reverse_lazy( return reverse_lazy(
@ -626,12 +650,13 @@ class PublicacaoListView(CompMixin, ListView):
return context return context
class PublicacaoCreateView(CompMixin, FormMessagesMixin, CreateView): class PublicacaoCreateView(PublicacaoMixin, FormMessagesMixin, CreateView):
model = Publicacao model = Publicacao
form_class = PublicacaoForm form_class = PublicacaoForm
template_name = "crud/form.html" template_name = "crud/form.html"
form_valid_message = _('Registro criado com sucesso!') form_valid_message = _('Registro criado com sucesso!')
form_invalid_message = _('O registro não foi criado.') form_invalid_message = _('O registro não foi criado.')
permission_required = 'compilacao.add_publicacao'
def get_success_url(self): def get_success_url(self):
return reverse_lazy( return reverse_lazy(
@ -650,14 +675,16 @@ class PublicacaoCreateView(CompMixin, FormMessagesMixin, CreateView):
return {'ta': self.kwargs['ta_id']} return {'ta': self.kwargs['ta_id']}
class PublicacaoDetailView(CompMixin, DetailView): class PublicacaoDetailView(PublicacaoMixin, DetailView):
model = Publicacao model = Publicacao
permission_required = 'compilacao.detail_publicacao'
class PublicacaoUpdateView(CompMixin, UpdateView): class PublicacaoUpdateView(PublicacaoMixin, UpdateView):
model = Publicacao model = Publicacao
form_class = PublicacaoForm form_class = PublicacaoForm
template_name = "crud/form.html" template_name = "crud/form.html"
permission_required = 'compilacao.change_publicacao'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.object = self.get_object() self.object = self.get_object()
@ -678,9 +705,10 @@ class PublicacaoUpdateView(CompMixin, UpdateView):
return self.get_success_url() return self.get_success_url()
class PublicacaoDeleteView(CompMixin, DeleteView): class PublicacaoDeleteView(PublicacaoMixin, DeleteView):
model = Publicacao model = Publicacao
template_name = "crud/confirm_delete.html" template_name = "crud/confirm_delete.html"
permission_required = 'compilacao.delete_publicacao'
@property @property
def detail_url(self): def detail_url(self):
@ -709,42 +737,7 @@ class TextView(CompMixin, ListView):
ta_vigencia = None ta_vigencia = None
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id']) self.object = self.ta
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()
return super(TextView, self).get(request, *args, **kwargs) return super(TextView, self).get(request, *args, **kwargs)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
@ -936,8 +929,9 @@ class DispositivoView(TextView):
return itens return itens
class TextEditView(TemplateView): class TextEditView(CompMixin, TemplateView):
template_name = 'compilacao/text_edit.html' template_name = 'compilacao/text_edit.html'
permission_required = 'compilacao.change_dispositivo_edicao_dinamica'
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
dispositivo_id = int(self.kwargs['dispositivo_id']) \ dispositivo_id = int(self.kwargs['dispositivo_id']) \
@ -946,7 +940,7 @@ class TextEditView(TemplateView):
if dispositivo_id: if dispositivo_id:
self.object = Dispositivo.objects.get(pk=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: if not dispositivo_id:
ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id']) ta = TextoArticulado.objects.get(pk=self.kwargs['ta_id'])
@ -1721,6 +1715,12 @@ class ActionDispositivoCreateMixin(ActionsCommonsMixin):
for td in otds: 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( if paradentro and not td.permitido_inserir_in(
tipb, tipb,
include_relative_autos=True, include_relative_autos=True,
@ -2417,11 +2417,12 @@ class ActionsEditMixin(ActionDragAndMoveDispositivoAlteradoMixin,
class DispositivoDinamicEditView( class DispositivoDinamicEditView(
CompMixin, ActionsEditMixin, TextEditView, UpdateView): ActionsEditMixin, TextEditView, UpdateView):
template_name = 'compilacao/text_edit_bloco.html' template_name = 'compilacao/text_edit_bloco.html'
model = Dispositivo model = Dispositivo
form_class = DispositivoEdicaoBasicaForm form_class = DispositivoEdicaoBasicaForm
contador = -1 contador = -1
permission_required = 'compilacao.change_dispositivo_edicao_dinamica',
def get_initial(self): def get_initial(self):
initial = UpdateView.get_initial(self) initial = UpdateView.get_initial(self)
@ -2615,7 +2616,6 @@ class DispositivoSearchFragmentFormView(ListView):
def get_queryset(self): def get_queryset(self):
try: try:
n = 10 n = 10
if 'max_results' in self.request.GET: if 'max_results' in self.request.GET:
n = int(self.request.GET['max_results']) n = int(self.request.GET['max_results'])
@ -2799,6 +2799,8 @@ class DispositivoEdicaoBasicaView(CompMixin, FormMessagesMixin, UpdateView):
form_invalid_message = _('Houve erro em registrar ' form_invalid_message = _('Houve erro em registrar '
'as alterações no Dispositivo') 'as alterações no Dispositivo')
permission_required = 'compilacao.change_dispositivo_edicao_avancada'
@property @property
def cancel_url(self): def cancel_url(self):
return reverse_lazy( return reverse_lazy(
@ -2871,6 +2873,8 @@ class DispositivoEdicaoVigenciaView(CompMixin, FormMessagesMixin, UpdateView):
form_invalid_message = _('Houve erro em registrar ' form_invalid_message = _('Houve erro em registrar '
'as alterações no Dispositivo') 'as alterações no Dispositivo')
permission_required = 'compilacao.change_dispositivo_edicao_avancada'
@property @property
def cancel_url(self): def cancel_url(self):
return reverse_lazy( return reverse_lazy(
@ -2894,6 +2898,9 @@ class DispositivoDefinidorVigenciaView(CompMixin, FormMessagesMixin, FormView):
form_invalid_message = _('Houve erro em registrar ' form_invalid_message = _('Houve erro em registrar '
'as alterações no Dispositivo') 'as alterações no Dispositivo')
permission_required = ('compilacao.change_dispositivo_edicao_avancada',
'compilacao.change_dispositivo_de_vigencia_global')
def get_form_kwargs(self): def get_form_kwargs(self):
kwargs = FormView.get_form_kwargs(self) kwargs = FormView.get_form_kwargs(self)
kwargs.update({ kwargs.update({
@ -2951,6 +2958,8 @@ class DispositivoEdicaoAlteracaoView(CompMixin, FormMessagesMixin, UpdateView):
form_invalid_message = _('Houve erro em registrar ' form_invalid_message = _('Houve erro em registrar '
'as alterações no Dispositivo') 'as alterações no Dispositivo')
permission_required = 'compilacao.change_dispositivo_registros_compilacao'
@property @property
def cancel_url(self): def cancel_url(self):
return reverse_lazy( return reverse_lazy(
@ -2983,6 +2992,8 @@ class TextNotificacoesView(CompMixin, ListView, FormView):
template_name = 'compilacao/text_notificacoes.html' template_name = 'compilacao/text_notificacoes.html'
form_class = TextNotificacoesForm form_class = TextNotificacoesForm
permission_required = 'compilacao.view_dispositivo_notificacoes'
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
self.object = TextoArticulado.objects.get(pk=self.kwargs['ta_id']) self.object = TextoArticulado.objects.get(pk=self.kwargs['ta_id'])
return super(TextNotificacoesView, self).get(request, *args, **kwargs) 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 django.views.generic.list import MultipleObjectMixin
from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display 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.settings import BASE_DIR
from sapl.utils import normalize 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 = \ ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \
'list', 'create', 'detail', 'update', '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): def _form_invalid_message(msg):
return '%s %s' % (_('Formulário inválido.'), 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 import os
from datetime import date, datetime
import django_filters
from crispy_forms.bootstrap import (Alert, FormActions, InlineCheckboxes, from crispy_forms.bootstrap import (Alert, FormActions, InlineCheckboxes,
InlineRadios) InlineRadios)
from crispy_forms.helper import FormHelper 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 import ModelForm, widgets
from django.forms.forms import Form from django.forms.forms import Form
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import django_filters
import sapl
from sapl.base.models import Autor from sapl.base.models import Autor
from sapl.comissoes.models import Comissao from sapl.comissoes.models import Comissao
from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column, from sapl.crispy_layout_mixin import (SaplFormLayout, form_actions, to_column,
to_row) 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, from sapl.norma.models import (LegislacaoCitada, NormaJuridica,
TipoNormaJuridica) TipoNormaJuridica)
from sapl.parlamentares.models import Parlamentar from sapl.parlamentares.models import Parlamentar
from sapl.protocoloadm.models import Protocolo from sapl.protocoloadm.models import Protocolo
from sapl.settings import MAX_DOC_UPLOAD_SIZE from sapl.settings import MAX_DOC_UPLOAD_SIZE
from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES,
ChoiceWithoutValidationField, RangeWidgetOverride, ChoiceWithoutValidationField,
MateriaPesquisaOrderingFilter, RangeWidgetOverride,
autor_label, autor_modal, models_with_gr_for_model) autor_label, autor_modal, models_with_gr_for_model)
import sapl
from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial, from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial,
DocumentoAcessorio, MateriaLegislativa, Numeracao, DocumentoAcessorio, MateriaLegislativa, Numeracao,
@ -65,6 +67,33 @@ class ReceberProposicaoForm(Form):
super(ReceberProposicaoForm, self).__init__(*args, **kwargs) 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 UnidadeTramitacaoForm(ModelForm):
class Meta: class Meta:
@ -444,6 +473,8 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
label=u'Ano da Matéria', label=u'Ano da Matéria',
choices=em_tramitacao) choices=em_tramitacao)
o = MateriaPesquisaOrderingFilter()
class Meta: class Meta:
model = MateriaLegislativa model = MateriaLegislativa
fields = ['numero', fields = ['numero',
@ -453,7 +484,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
'data_apresentacao', 'data_apresentacao',
'data_publicacao', 'data_publicacao',
'autoria__autor__tipo', 'autoria__autor__tipo',
# 'autoria__autor__partido', # FIXME 'autoria__autor__partido',
'relatoria__parlamentar_id', 'relatoria__parlamentar_id',
'local_origem_externa', 'local_origem_externa',
'tramitacao__unidade_tramitacao_destino', 'tramitacao__unidade_tramitacao_destino',
@ -461,29 +492,6 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet):
'em_tramitacao', '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): def __init__(self, *args, **kwargs):
super(MateriaLegislativaFilterSet, self).__init__(*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.auth import get_user_model
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.core.files.uploadedfile import SimpleUploadedFile from django.core.files.uploadedfile import SimpleUploadedFile
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from model_mommy import mommy from model_mommy import mommy
import pytest
from sapl.base.models import Autor, TipoAutor from sapl.base.models import Autor, TipoAutor
from sapl.comissoes.models import Comissao, TipoComissao from sapl.comissoes.models import Comissao, TipoComissao

7
sapl/materia/urls.py

@ -4,7 +4,8 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
AcompanhamentoExcluirView, AcompanhamentoExcluirView,
AcompanhamentoMateriaView, AnexadaCrud, AcompanhamentoMateriaView, AnexadaCrud,
AutoriaCrud, ConfirmarProposicao, AutoriaCrud, ConfirmarProposicao,
DespachoInicialCrud, DocumentoAcessorioCrud, CriarProtocoloMateriaView, DespachoInicialCrud,
DocumentoAcessorioCrud,
DocumentoAcessorioEmLoteView, DocumentoAcessorioEmLoteView,
LegislacaoCitadaCrud, MateriaLegislativaCrud, LegislacaoCitadaCrud, MateriaLegislativaCrud,
MateriaLegislativaPesquisaView, MateriaTaView, MateriaLegislativaPesquisaView, MateriaTaView,
@ -34,6 +35,10 @@ urlpatterns_materia = [
TramitacaoCrud.get_urls() + TramitacaoCrud.get_urls() +
RelatoriaCrud.get_urls() + RelatoriaCrud.get_urls() +
DocumentoAcessorioCrud.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/recuperar-materia', recuperar_materia),
url(r'^materia/(?P<pk>[0-9]+)/ta$', url(r'^materia/(?P<pk>[0-9]+)/ta$',
MateriaTaView.as_view(), name='materia_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, ACTION_LIST, ACTION_UPDATE, RP_DETAIL, RP_LIST,
Crud, CrudAux, MasterDetailCrud, Crud, CrudAux, MasterDetailCrud,
PermissionRequiredForAppCrudMixin, make_pagination) PermissionRequiredForAppCrudMixin, make_pagination)
from sapl.materia import apps
from sapl.materia.forms import (AnexadaForm, ConfirmarProposicaoForm, from sapl.materia.forms import (AnexadaForm, ConfirmarProposicaoForm,
LegislacaoCitadaForm, ProposicaoForm, LegislacaoCitadaForm, ProposicaoForm,
TipoProposicaoForm) TipoProposicaoForm)
from sapl.norma.models import LegislacaoCitada from sapl.norma.models import LegislacaoCitada
from sapl.protocoloadm.models import Protocolo
from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label, from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
autor_modal, gerar_hash_arquivo, get_base_url, autor_modal, gerar_hash_arquivo, get_base_url,
montar_row_autor) montar_row_autor)
@ -40,8 +40,9 @@ import sapl
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
DocumentoAcessorioForm, MateriaLegislativaFilterSet, DocumentoAcessorioForm, MateriaLegislativaFilterSet,
PrimeiraTramitacaoEmLoteFilterSet, ReceberProposicaoForm, MateriaSimplificadaForm, PrimeiraTramitacaoEmLoteFilterSet,
TramitacaoEmLoteFilterSet, filtra_tramitacao_destino, ReceberProposicaoForm, TramitacaoEmLoteFilterSet,
filtra_tramitacao_destino,
filtra_tramitacao_destino_and_status, filtra_tramitacao_destino_and_status,
filtra_tramitacao_status) filtra_tramitacao_status)
from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial, from .models import (AcompanhamentoMateria, Anexada, Autoria, DespachoInicial,
@ -67,9 +68,49 @@ TipoFimRelatoriaCrud = CrudAux.build(
TipoFimRelatoria, 'fim_relatoria') 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): class MateriaTaView(IntegracaoTaView):
model = MateriaLegislativa model = MateriaLegislativa
model_type_foreignkey = TipoMateriaLegislativa 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): def get(self, request, *args, **kwargs):
""" """
@ -86,8 +127,15 @@ class MateriaTaView(IntegracaoTaView):
class ProposicaoTaView(IntegracaoTaView): class ProposicaoTaView(IntegracaoTaView):
model = Proposicao model = Proposicao
model_type_foreignkey = TipoProposicao model_type_foreignkey = TipoProposicao
# TODO implmentar o mapa de fields e utiliza-lo em IntegracaoTaView map_fields = {
fields = { 'data': 'data_recebimento',
'ementa': 'descricao',
'observacao': None,
'numero': 'numero_proposicao',
'ano': 'ano',
}
map_funcs = {
'publicacao_func': False
} }
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):

2
sapl/norma/forms.py

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

11
sapl/norma/views.py

@ -28,6 +28,17 @@ TipoNormaCrud = CrudAux.build(
class NormaTaView(IntegracaoTaView): class NormaTaView(IntegracaoTaView):
model = NormaJuridica model = NormaJuridica
model_type_foreignkey = TipoNormaJuridica 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): 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 from .models import Cronometro
CronometroPainelCrud = Crud.build(Cronometro, '') CronometroPainelCrud = Crud.build(Cronometro, '')
# FIXME mudar lógica # FIXME mudar lógica

3
sapl/parlamentares/views.py

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

49
sapl/protocoloadm/forms.py

@ -1,5 +1,6 @@
from datetime import datetime from datetime import datetime
import django_filters
from crispy_forms.bootstrap import InlineRadios from crispy_forms.bootstrap import InlineRadios
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Fieldset, Layout, Submit 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.db import models
from django.forms import ModelForm from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.base.models import Autor from sapl.base.models import Autor
from sapl.crispy_layout_mixin import form_actions, to_row from sapl.crispy_layout_mixin import form_actions, to_row
from sapl.materia.models import UnidadeTramitacao from sapl.materia.models import UnidadeTramitacao
from sapl.utils import (RANGE_ANOS, RangeWidgetOverride, autor_label, from sapl.utils import (RANGE_ANOS, AnoNumeroOrderingFilter,
autor_modal) RangeWidgetOverride, autor_label, autor_modal)
from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo, from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo,
Protocolo, TipoDocumentoAdministrativo, Protocolo, TipoDocumentoAdministrativo,
TramitacaoAdministrativo) TramitacaoAdministrativo)
TIPOS_PROTOCOLO = [('0', 'Enviado'), ('1', 'Recebido'), ('', 'Ambos')] TIPOS_PROTOCOLO = [('0', 'Enviado'), ('1', 'Recebido'), ('', 'Ambos')]
NATUREZA_PROCESSO = [('', 'Ambos'), NATUREZA_PROCESSO = [('', 'Ambos'),
@ -69,6 +68,8 @@ class ProtocoloFilterSet(django_filters.FilterSet):
widget=forms.Select( widget=forms.Select(
attrs={'class': 'selector'})) attrs={'class': 'selector'}))
o = AnoNumeroOrderingFilter()
class Meta: class Meta:
model = Protocolo model = Protocolo
fields = ['numero', fields = ['numero',
@ -77,25 +78,6 @@ class ProtocoloFilterSet(django_filters.FilterSet):
'tipo_materia', '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): def __init__(self, *args, **kwargs):
super(ProtocoloFilterSet, self).__init__(*args, **kwargs) super(ProtocoloFilterSet, self).__init__(*args, **kwargs)
@ -163,6 +145,8 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
interessado = django_filters.CharFilter(lookup_expr='icontains') interessado = django_filters.CharFilter(lookup_expr='icontains')
o = AnoNumeroOrderingFilter()
class Meta: class Meta:
model = DocumentoAdministrativo model = DocumentoAdministrativo
fields = ['tipo', fields = ['tipo',
@ -172,25 +156,6 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet):
'tramitacaoadministrativo__unidade_tramitacao_destino', 'tramitacaoadministrativo__unidade_tramitacao_destino',
'tramitacaoadministrativo__status'] '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): def __init__(self, *args, **kwargs):
super(DocumentoAdministrativoFilterSet, self).__init__(*args, **kwargs) super(DocumentoAdministrativoFilterSet, self).__init__(*args, **kwargs)

5
sapl/protocoloadm/urls.py

@ -9,7 +9,8 @@ from sapl.protocoloadm.views import (AnularProtocoloAdmView,
DocumentoAcessorioAdministrativoView, DocumentoAcessorioAdministrativoView,
DocumentoAdministrativoCrud, DocumentoAdministrativoCrud,
PesquisarDocumentoAdministrativoView, PesquisarDocumentoAdministrativoView,
ProtocoloDocumentoView, ProtocoloListView, ProtocoloDocumentoView,
ProtocoloMateriaTemplateView,
ProtocoloMateriaView, ProtocoloMateriaView,
ProtocoloMostrarView, ProtocoloMostrarView,
ProtocoloPesquisaView, 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', 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.views.generic.base import TemplateView
from django_filters.views import FilterView from django_filters.views import FilterView
import sapl
from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination
from sapl.materia.models import TipoMateriaLegislativa from sapl.materia.models import TipoMateriaLegislativa
from sapl.utils import (create_barcode, get_client_ip) from sapl.utils import create_barcode, get_client_ip
import sapl
from .forms import (AnularProcoloAdmForm, DocumentoAcessorioAdministrativoForm, from .forms import (AnularProcoloAdmForm, DocumentoAcessorioAdministrativoForm,
DocumentoAdministrativoFilterSet, DocumentoAdministrativoFilterSet,
@ -26,14 +26,13 @@ from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo,
Protocolo, StatusTramitacaoAdministrativo, Protocolo, StatusTramitacaoAdministrativo,
TipoDocumentoAdministrativo, TramitacaoAdministrativo) TipoDocumentoAdministrativo, TramitacaoAdministrativo)
TipoDocumentoAdministrativoCrud = CrudAux.build( TipoDocumentoAdministrativoCrud = CrudAux.build(
TipoDocumentoAdministrativo, '') TipoDocumentoAdministrativo, '')
#ProtocoloDocumentoCrud = Crud.build(Protocolo, '') # ProtocoloDocumentoCrud = Crud.build(Protocolo, '')
# FIXME precisa de uma chave diferente para o layout # FIXME precisa de uma chave diferente para o layout
#ProtocoloMateriaCrud = Crud.build(Protocolo, '') # ProtocoloMateriaCrud = Crud.build(Protocolo, '')
DocumentoAcessorioAdministrativoCrud = Crud.build( DocumentoAcessorioAdministrativoCrud = Crud.build(
@ -47,8 +46,7 @@ class DocumentoAdministrativoMixin:
if app_config and app_config.documentos_administrativos == 'O': if app_config and app_config.documentos_administrativos == 'O':
return True return True
return self.request.user.has_module_perms( return super().has_permission()
sapl.base.models.AppConfig.label)
class DocumentoAdministrativoCrud(Crud): class DocumentoAdministrativoCrud(Crud):
@ -60,10 +58,10 @@ class DocumentoAdministrativoCrud(Crud):
'numero_protocolo', 'assunto', 'numero_protocolo', 'assunto',
'interessado', 'tramitacao', 'texto_integral'] 'interessado', 'tramitacao', 'texto_integral']
class ListView(Crud.ListView, DocumentoAdministrativoMixin): class ListView(DocumentoAdministrativoMixin, Crud.ListView):
pass pass
class DetailView(Crud.DetailView, DocumentoAdministrativoMixin): class DetailView(DocumentoAdministrativoMixin, Crud.DetailView):
pass pass
@ -314,8 +312,9 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
form_valid_message = _('Matéria cadastrada com sucesso!') form_valid_message = _('Matéria cadastrada com sucesso!')
permission_required = ('protocoloadm.add_protocolo',) permission_required = ('protocoloadm.add_protocolo',)
def get_success_url(self): def get_success_url(self, protocolo):
return reverse('sapl.protocoloadm:protocolo') return reverse('sapl.protocoloadm:materia_continuar', kwargs={
'pk': protocolo.pk})
def form_valid(self, form): def form_valid(self, form):
try: try:
@ -353,12 +352,25 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
protocolo.numero_paginas = self.request.POST['numero_paginas'] protocolo.numero_paginas = self.request.POST['numero_paginas']
protocolo.observacao = self.request.POST['observacao'] protocolo.observacao = self.request.POST['observacao']
protocolo.save() 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, class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
DocumentoAdministrativoMixin): PermissionRequiredMixin,
FilterView):
model = DocumentoAdministrativo model = DocumentoAdministrativo
filterset_class = DocumentoAdministrativoFilterSet filterset_class = DocumentoAdministrativoFilterSet
paginate_by = 10 paginate_by = 10
@ -565,65 +577,13 @@ class TramitacaoAdmCrud(MasterDetailCrud):
class UpdateView(MasterDetailCrud.UpdateView): class UpdateView(MasterDetailCrud.UpdateView):
form_class = TramitacaoAdmEditForm form_class = TramitacaoAdmEditForm
class ListView(MasterDetailCrud.ListView, DocumentoAdministrativoMixin): class ListView(DocumentoAdministrativoMixin, MasterDetailCrud.ListView):
def get_queryset(self): def get_queryset(self):
qs = super(MasterDetailCrud.ListView, self).get_queryset() qs = super(MasterDetailCrud.ListView, self).get_queryset()
kwargs = {self.crud.parent_field: self.kwargs['pk']} kwargs = {self.crud.parent_field: self.kwargs['pk']}
return qs.filter(**kwargs).order_by('-data_tramitacao', '-id') return qs.filter(**kwargs).order_by('-data_tramitacao', '-id')
class DetailView(MasterDetailCrud.DetailView, class DetailView(DocumentoAdministrativoMixin,
DocumentoAdministrativoMixin): MasterDetailCrud.DetailView):
pass 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.base import models as base
from sapl.comissoes import models as comissoes from sapl.comissoes import models as comissoes
from sapl.compilacao import models as compilacao 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.lexml import models as lexml
from sapl.materia import models as materia from sapl.materia import models as materia
from sapl.norma import models as norma 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) SAPL_GROUP_PROTOCOLO, SAPL_GROUP_SESSAO)
from sapl.sessao import models as 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] __base__ = [RP_LIST, RP_DETAIL, RP_ADD, RP_CHANGE, RP_DELETE]
__listdetailchange__ = [RP_LIST, RP_DETAIL, RP_CHANGE] __listdetailchange__ = [RP_LIST, RP_DETAIL, RP_CHANGE]
@ -74,10 +113,12 @@ rules_group_materia = {
(compilacao.Dispositivo, __base__ + [ (compilacao.Dispositivo, __base__ + [
'change_dispositivo_edicao_dinamica', 'change_dispositivo_edicao_dinamica',
# sobre a regra abaixo deve ser pensada sobre isso # TODO: adicionar 'change_dispositivo_registros_compilacao'
# abre possibilidade pra haver compilacao de emenda com projeto # quando testes forem feitos para permtir que matérias possam
# mas testes devem ser feitos especificamente para materia # ser vinculadas a outras matérias via registro de compilação.
# 'change_dispositivo_registros_compilacao' # 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.Vide, __base__),
(compilacao.Nota, __base__), (compilacao.Nota, __base__),
(compilacao.Dispositivo, __base__ + [ (compilacao.Dispositivo, __base__ + [
'change_dispositivo_notificacoes', 'view_dispositivo_notificacoes',
'change_dispositivo_edicao_dinamica', 'change_dispositivo_edicao_dinamica',
'change_dispositivo_edicao_avancada', '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.TipoComissao, __base__),
(comissoes.Periodo, __base__), (comissoes.Periodo, __base__),
(materia.AssuntoMateria, []), # não há implementação (materia.AssuntoMateria, __base__), # não há implementação
(materia.MateriaAssunto, []), # não há implementação (materia.MateriaAssunto, __base__), # não há implementação
(materia.TipoProposicao, __base__), (materia.TipoProposicao, __base__),
(materia.TipoMateriaLegislativa, __base__), (materia.TipoMateriaLegislativa, __base__),
(materia.RegimeTramitacao, __base__), (materia.RegimeTramitacao, __base__),

89
sapl/rules/tests/test_rules.py

@ -1,19 +1,22 @@
import pytest
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.contrib.auth.models import Permission from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.utils import six from django.utils import six
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import pytest
from sapl.rules import SAPL_GROUPS from sapl.base.models import CasaLegislativa, ProblemaMigracao
from sapl.rules.map_rules import rules_patterns 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 sapl.test_urls import create_perms_post_migrate
from scripts.lista_permissions_in_decorators import \ from scripts.lista_permissions_in_decorators import \
lista_permissions_in_decorators lista_permissions_in_decorators
from scripts.lista_urls import lista_urls from scripts.lista_urls import lista_urls
sapl_appconfs = [apps.get_app_config(n[5:]) for n in settings.SAPL_APPS] sapl_appconfs = [apps.get_app_config(n[5:]) for n in settings.SAPL_APPS]
sapl_models = [] sapl_models = []
@ -26,7 +29,7 @@ sapl_models.reverse()
def test_groups_in_rules_patterns(group_item): def test_groups_in_rules_patterns(group_item):
test = False test = False
for rules_group in rules_patterns: for rules_group in map_rules.rules_patterns:
if rules_group['group'] == group_item: if rules_group['group'] == group_item:
test = True test = True
@ -37,7 +40,7 @@ def test_groups_in_rules_patterns(group_item):
def test_models_in_rules_patterns(model_item): def test_models_in_rules_patterns(model_item):
test = False test = False
for rules_group in rules_patterns: for rules_group in map_rules.rules_patterns:
rules_model = rules_group['rules'] rules_model = rules_group['rules']
for rm in rules_model: for rm in rules_model:
if rm[0] == model_item: if rm[0] == model_item:
@ -49,6 +52,75 @@ def test_models_in_rules_patterns(model_item):
str(model_item), str(model_item),
model_item._meta.verbose_name) 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.django_db(transaction=False)
@pytest.mark.parametrize('model_item', sapl_models) @pytest.mark.parametrize('model_item', sapl_models)
@ -57,7 +129,7 @@ def test_permission_of_rules_exists(model_item):
print(model_item) print(model_item)
create_perms_post_migrate(model_item._meta.app_config) 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'] rules_model = rules_group['rules']
for rm in rules_model: for rm in rules_model:
model = rm[0] model = rm[0]
@ -77,7 +149,8 @@ def test_permission_of_rules_exists(model_item):
content_type=content_type, content_type=content_type,
codename=codename).exists() 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, codename,
model_item) 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.forms import MateriaLegislativaFilterSet
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.parlamentares.models import Parlamentar 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, from .models import (Bancada, ExpedienteMateria, Orador, OradorExpediente,
OrdemDia, SessaoPlenaria, SessaoPlenariaPresenca) OrdemDia, SessaoPlenaria, SessaoPlenariaPresenca)
@ -21,7 +23,10 @@ from .models import (Bancada, ExpedienteMateria, Orador, OradorExpediente,
def recupera_anos(): def recupera_anos():
try: try:
anos_list = SessaoPlenaria.objects.all().dates('data_inicio', 'year') 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 return anos
except: except:
return [] return []
@ -203,6 +208,8 @@ class SessaoPlenariaFilterSet(django_filters.FilterSet):
class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet): class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet):
o = MateriaPesquisaOrderingFilter()
class Meta: class Meta:
model = MateriaLegislativa model = MateriaLegislativa
fields = ['numero', fields = ['numero',
@ -212,20 +219,12 @@ class AdicionarVariasMateriasFilterSet(MateriaLegislativaFilterSet):
'data_apresentacao', 'data_apresentacao',
'data_publicacao', 'data_publicacao',
'autoria__autor__tipo', 'autoria__autor__tipo',
# 'autoria__autor__partido', # FIXME 'autoria__autor__partido',
'relatoria__parlamentar_id', 'relatoria__parlamentar_id',
'local_origem_externa', 'local_origem_externa',
'em_tramitacao', '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): def __init__(self, *args, **kwargs):
super(MateriaLegislativaFilterSet, self).__init__(*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.norma.models import NormaJuridica
from sapl.parlamentares.models import (Legislatura, Parlamentar, from sapl.parlamentares.models import (Legislatura, Parlamentar,
SessaoLegislativa) SessaoLegislativa)
from sapl.sessao.apps import AppConfig from sapl.sessao.apps import AppConfig
from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm
@ -45,7 +44,6 @@ from .models import (Bancada, Bloco, CargoBancada, CargoMesa,
SessaoPlenariaPresenca, TipoExpediente, SessaoPlenariaPresenca, TipoExpediente,
TipoResultadoVotacao, TipoSessaoPlenaria, VotoParlamentar) TipoResultadoVotacao, TipoSessaoPlenaria, VotoParlamentar)
TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria') TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria')
TipoExpedienteCrud = CrudAux.build(TipoExpediente, 'tipo_expediente') TipoExpedienteCrud = CrudAux.build(TipoExpediente, 'tipo_expediente')
CargoBancadaCrud = CrudAux.build(CargoBancada, '') CargoBancadaCrud = CrudAux.build(CargoBancada, '')
@ -61,11 +59,9 @@ TipoResultadoVotacaoCrud = CrudAux.build(
def reordernar_materias_expediente(request, pk): def reordernar_materias_expediente(request, pk):
expedientes = ExpedienteMateria.objects.filter( expedientes = ExpedienteMateria.objects.filter(
sessao_plenaria_id=pk) sessao_plenaria_id=pk)
exp_num = 1 for exp_num, e in enumerate(expedientes, 1):
for e in expedientes:
e.numero_ordem = exp_num e.numero_ordem = exp_num
e.save() e.save()
exp_num += 1
return HttpResponseRedirect( return HttpResponseRedirect(
reverse('sapl.sessao:expedientemateria_list', kwargs={'pk': pk})) reverse('sapl.sessao:expedientemateria_list', kwargs={'pk': pk}))
@ -74,11 +70,9 @@ def reordernar_materias_expediente(request, pk):
def reordernar_materias_ordem(request, pk): def reordernar_materias_ordem(request, pk):
ordens = OrdemDia.objects.filter( ordens = OrdemDia.objects.filter(
sessao_plenaria_id=pk) sessao_plenaria_id=pk)
ordem_num = 1 for ordem_num, o in enumerate(ordens, 1):
for o in ordens:
o.numero_ordem = ordem_num o.numero_ordem = ordem_num
o.save() o.save()
ordem_num += 1
return HttpResponseRedirect( return HttpResponseRedirect(
reverse('sapl.sessao:ordemdia_list', kwargs={'pk': pk})) 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.debug',
'django.template.context_processors.request', 'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth', 'django.contrib.auth.context_processors.auth',
"django.core.context_processors.media", "django.template.context_processors.media",
"django.core.context_processors.static", "django.template.context_processors.static",
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'sapl.context_processors.parliament_info', 'sapl.context_processors.parliament_info',
], ],

48
sapl/templates/compilacao/ajax_actions_dinamic_edit.html

@ -1,21 +1,23 @@
{% load i18n %} {% load i18n %}
<div class="btn-toolbar pull-right" role="toolbar" > <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 %} </button>
<div class="btn-group " role="group"> <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">
<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 Alteração" %}
Registrar Revogação </button>
</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">
<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 Inclusão" %}
Registrar Alteração </button>
</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>
</div> </div>
{%endif%} {%endif%}
{% endif %}
<div class="btn-group " role="group"> <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"> <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> <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="construct">Construtor</a></li>
<li><a class="btn-editor-type" editortype="textarea">Editor Simples</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-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> </ul>
</div> </div>
</div> </div>
@ -61,11 +65,13 @@
{% endfor %} {% endfor %}
{%endif%} {%endif%}
</div> </div>
{% if not object.ta_publicado and not object.dispositivo_subsequente and not object.tipo_dispositivo.dispositivo_de_alteracao%} {% if perms.compilacao.change_dispositivo_de_vigencia_global %}
<div class="btn-group " role="group"> {% if not object.ta_publicado and not object.dispositivo_subsequente and not object.tipo_dispositivo.dispositivo_de_alteracao%}
<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%}"> <div class="btn-group " role="group">
DVt <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%}">
</button> DVt
</div> </button>
{%endif%} </div>
{% endif %}
{% endif %}
</div> </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_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_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 %} {% 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> {% 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 %}
<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> {% 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 %}
<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> {% 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 %}
<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_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> </ul>
{% endblock sections_nav %}{% trans '' %} {% endblock sections_nav %}{% trans '' %}

12
sapl/templates/compilacao/publicacao_list.html

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

14
sapl/templates/compilacao/text_edit.html

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

18
sapl/templates/compilacao/text_list.html

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

18
sapl/templates/compilacao/textoarticulado_detail.html

@ -8,14 +8,20 @@
{%if object %} {%if object %}
<li> <li>
{% if object.content_object%} {% 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%} {%else%}
<a href="{% url 'sapl.compilacao:ta_detail' object.pk %}">{% trans 'Início' %}</a> <a href="{% url 'sapl.compilacao:ta_detail' object.pk %}">{% trans 'Início' %}</a>
{%endif%} {%endif%}
</li> </li>
<li><a href="{% url 'sapl.compilacao:ta_pub_list' object.pk %}">{% model_verbose_name_plural 'sapl.compilacao.models.Publicacao' %}</a></li> {% if object.tipo_ta.publicacao_func %}
<li><a href="{% url 'sapl.compilacao:ta_text_notificacoes' object.pk %}">{% trans 'Notificações' %}</a></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' object.pk %}">{% trans 'Texto' %}</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 %} {% endif %}
</ul> </ul>
{% endblock %} {% endblock %}
@ -25,8 +31,10 @@
{% block actions %} {% block actions %}
<div class="clearfix"> <div class="clearfix">
<div class="actions btn-group pull-right" role="group"> <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> <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> <a href="{% url 'sapl.compilacao:ta_text_edit' object.pk %}" class="btn btn-default">{% trans 'Editar Texto' %}</a>
{% endif %} {% endif %}
</div> </div>

14
sapl/templates/compilacao/textoarticulado_list.html

@ -8,12 +8,14 @@
{% endblock detail_content %} {% endblock detail_content %}
{% block actions %} {% block actions %}
<div class="actions btn-group pull-right clearfix" role="group"> {% if perms.compilacao.add_textoarticulado %}
<a href="{{ view.create_url }}" class="btn btn-default"> <div class="actions btn-group pull-right clearfix" role="group">
{% trans 'Adicionar'%} {%model_verbose_name 'sapl.compilacao.models.TextoArticulado'%} <a href="{{ view.create_url }}" class="btn btn-default">
</a> {% trans 'Adicionar'%} {%model_verbose_name 'sapl.compilacao.models.TextoArticulado'%}
{% include 'compilacao/textoarticulado_menu_config.html' %} </a>
</div> {% include 'compilacao/textoarticulado_menu_config.html' %}
</div>
{% endif %}
{% endblock actions %} {% endblock actions %}
<table class="table table-striped table-hover"> <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> <i class="fa fa-cog fa-1x fa-fw"></i>
</button> </button>
<ul class="dropdown-menu" role="menu"> <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> {% 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 %}
<li><a href="{% url 'sapl.compilacao:veiculopublicacao_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.VeiculoPublicacao'%}</a></li> {% 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 %}
<li><a href="{% url 'sapl.compilacao:tiponota_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoNota'%}</a></li> {% if perms.compilacao.list_veiculopublicacao %}<li><a href="{% url 'sapl.compilacao:veiculopublicacao_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.VeiculoPublicacao'%}</a></li>{% endif %}
<li><a href="{% url 'sapl.compilacao:tipovide_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoVide'%}</a></li> {% if perms.compilacao.list_tiponota %}<li><a href="{% url 'sapl.compilacao:tiponota_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoNota'%}</a></li>{% endif %}
<li><a href="{% url 'sapl.compilacao:tipodispositivo_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoDispositivo'%}</a></li> {% if perms.compilacao.list_tipovide %}<li><a href="{% url 'sapl.compilacao:tipovide_list' %}">{%model_verbose_name_plural 'sapl.compilacao.models.TipoVide'%}</a></li>{% endif %}
<li><a href="#">TODO: Perfil Estrutural de Textos Articulados</a></li>
{% 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> </ul>

5
sapl/templates/compilacao/tipotextoarticulado_detail.html

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

12
sapl/templates/compilacao/tipotextoarticulado_list.html

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

5
sapl/templates/materia/tipoproposicao_form.html

@ -22,13 +22,10 @@ $(document).ready(function(){
initial_select=''; initial_select='';
radios.append(html_radio); radios.append(html_radio);
}); });
}); });
}); });
$('#id_content_type').trigger('change');
$("#div_id_tipo_conteudo_related_radio .controls").addClass('controls-radio-checkbox'); $("#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="stop-painel" value="Fechar Painel" class="button primary">
<input type="submit" name="save-painel" value="Salvar" class="button primary"> <input type="submit" name="save-painel" value="Salvar" class="button primary">
</form> </form>
</br>
</br>
<a class="btn btn-primary" href="{{request.META.HTTP_REFERER}}">Voltar</a>
{% endblock %} {% 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 /> <br />
<strong>Documento Vinculado:</strong></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; &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 target="popup" class="btn btn-primary" onclick="window.open('{% url 'sapl.protocoloadm:comprovante_protocolo' protocolo.pk%}','Comprovante','width=800, height=600')">Comprovante
</a> </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_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_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_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> </div>
<br /> <br />
<h1>Operação do Painel Eletrônico</h1> <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 import include, url
from django.conf.urls.static import static from django.conf.urls.static import static
from django.contrib import admin 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 from django.views.static import serve as view_static_server
import sapl.api.urls import sapl.api.urls
@ -33,6 +33,7 @@ import sapl.protocoloadm.urls
import sapl.relatorios.urls import sapl.relatorios.urls
import sapl.sessao.urls import sapl.sessao.urls
urlpatterns = [ urlpatterns = [
url(r'^$', TemplateView.as_view(template_name='index.html')), url(r'^$', TemplateView.as_view(template_name='index.html')),
url(r'^admin/', include(admin.site.urls)), url(r'^admin/', include(admin.site.urls)),
@ -53,6 +54,9 @@ urlpatterns = [
url(r'', include(sapl.base.urls)), url(r'', include(sapl.base.urls)),
url(r'', include(sapl.api.urls)), url(r'', include(sapl.api.urls)),
url(r'^favicon\.ico$', RedirectView.as_view(
url='/static/img/favicon.ico', permanent=True)),
] ]

61
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 hashlib
import logging import logging
import re 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.helper import FormHelper
from crispy_forms.layout import HTML, Button from crispy_forms.layout import HTML, Button
from django import forms from django import forms
from django.apps import apps from django.apps import apps
from django.conf import settings from django.conf import settings
from django.contrib import admin 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, from django.contrib.contenttypes.fields import (GenericForeignKey, GenericRel,
GenericRelation) GenericRelation)
from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ValidationError
from django.core.exceptions import PermissionDenied, ValidationError
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from floppyforms import ClearableFileInput from floppyforms import ClearableFileInput
import magic
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
from sapl.settings import BASE_DIR from sapl.settings import BASE_DIR
sapl_logger = logging.getLogger(BASE_DIR.name) sapl_logger = logging.getLogger(BASE_DIR.name)
@ -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): def gerar_hash_arquivo(arquivo, pk, block_size=2**20):
md5 = hashlib.md5() md5 = hashlib.md5()
arq = open(arquivo, 'rb') arq = open(arquivo, 'rb')

1
scripts/lista_permissions_in_decorators.py

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

Loading…
Cancel
Save