Browse Source

Merge com o master

Please enter a commit message to explain why this merge is necessary,
pull/713/head
Eduardo Calil 8 years ago
parent
commit
f1c528162c
  1. 14
      sapl/base/models.py
  2. 10
      sapl/base/templatetags/common_tags.py
  3. 73
      sapl/base/templatetags/menus.py
  4. 2
      sapl/base/urls.py
  5. 2
      sapl/base/views.py
  6. 11
      sapl/comissoes/views.py
  7. 2
      sapl/crispy_layout_mixin.py
  8. 62
      sapl/crud/base.py
  9. 33
      sapl/materia/forms.py
  10. 19
      sapl/materia/migrations/0051_auto_20161004_0927.py
  11. 20
      sapl/materia/migrations/0052_auto_20161004_1041.py
  12. 4
      sapl/materia/models.py
  13. 55
      sapl/materia/views.py
  14. 3
      sapl/norma/models.py
  15. 8
      sapl/norma/views.py
  16. 4
      sapl/parlamentares/views.py
  17. 18
      sapl/relatorios/urls.py
  18. 25
      sapl/sessao/migrations/0028_auto_20161004_0927.py
  19. 35
      sapl/sessao/migrations/0029_auto_20161004_1101.py
  20. 2
      sapl/sessao/models.py
  21. 257
      sapl/sessao/views.py
  22. 10
      sapl/templates/comissoes/materias_em_tramitacao.html
  23. 58
      sapl/templates/crud/detail.html
  24. 104
      sapl/templates/materia/materialegislativa_filter.html
  25. 6
      sapl/templates/materia/subnav.yaml
  26. 82
      sapl/templates/menus/mesa_diretora/mesa_diretora.html
  27. 8
      sapl/templates/menus/subnav.html
  28. 1
      sapl/templates/parlamentares/subnav.yaml
  29. 73
      sapl/templates/protocoloadm/documentoadministrativo_filter.html
  30. 95
      sapl/templates/protocoloadm/protocolo_filter.html
  31. 1
      sapl/templates/sessao/expedientemateria_form.html
  32. 6
      sapl/templates/sessao/layouts.yaml
  33. 8
      sapl/templates/sessao/painel.html
  34. 63
      sapl/templates/sessao/pauta_sessao_filter.html
  35. 6
      sapl/templates/sessao/resumo.html
  36. 13
      sapl/templates/sessao/sessaoplenaria_filter.html
  37. 5
      sapl/templates/sessao/subnav.yaml
  38. 22
      sapl/utils.py
  39. 2
      scripts/inicializa_grupos_autorizacoes.py
  40. 74
      scripts/test_inicializa_grupos_autorizacoes.py

14
sapl/base/models.py

@ -7,12 +7,11 @@ from django.contrib.contenttypes.models import ContentType
from django.core import exceptions
from django.db import models, router
from django.db.utils import DEFAULT_DB_ALIAS
from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat
from sapl.utils import UF, YES_NO_CHOICES
TIPO_DOCUMENTO_ADMINISTRATIVO = (('O', _('Ostensivo')),
('R', _('Restritivo')))
@ -107,6 +106,15 @@ class AppConfig(models.Model):
('view_tabelas_auxiliares', _('Visualizar Tabelas Auxiliares')),
)
@classmethod
def attr(cls, attr):
config = AppConfig.objects.first()
if not config:
return ''
return getattr(config, attr)
def __str__(self):
return _('Configurações da Aplicação - %(id)s') % {
'id': self.id}
@ -204,4 +212,4 @@ def create_proxy_permissions(
models.signals.post_migrate.connect(
receiver=create_proxy_permissions,
dispatch_uid="django.contrib.auth.management.create_permissions")
dispatch_uid="django.contrib.auth.management.create_permissions")

10
sapl/base/templatetags/common_tags.py

@ -122,10 +122,12 @@ def ultima_filiacao(value):
@register.filter
def get_config_not_exists(user):
if not AppConfig.objects.all().exists():
return True
else:
return False
return not AppConfig.objects.exists()
@register.filter
def get_config_attr(attribute):
return AppConfig.attr(attribute)
@register.filter

73
sapl/base/templatetags/menus.py

@ -1,6 +1,7 @@
import yaml
from django import template
from django.core.urlresolvers import reverse
import yaml
register = template.Library()
@ -14,6 +15,12 @@ def subnav(context, path=None):
1) Se a variável path não é nula;
2) Se existe no contexto a chave subnav_template_name;
3) o path default: <app_name>/subnav.yaml
Os campos esperados nos arquivos yaml são:
title
url
check_permission - opcional. quando usado
será realizado o teste de permissão para renderizá-lo.
"""
menu = None
root_pk = context.get('root_pk', None)
@ -76,40 +83,36 @@ def resolve_urls_inplace(menu, pk, rm, context):
else:
if 'url' in menu:
url_name = menu['url']
menu['url'] = reverse('%s:%s' % (rm.app_name, menu['url']),
kwargs={'pk': pk})
menu['active'] = 'active'\
if context['request'].path == menu['url'] else ''
if not menu['active']:
"""
Se não encontrada diretamente,
procura a url acionada dentro do crud, caso seja um.
Serve para manter o active no suvnav correto ao acionar
as funcionalidades diretas do MasterDetailCrud, como:
- visualização de detalhes, adição, edição, remoção.
Casos para urls_extras:
Em relações de segundo nível, como ocorre em
(0) Comissões -> (1) Composição -> (2) Participação
(2) não tem ligação direta com (1) através da view. Para (2)
ser localizado, e o nav-tabs ou nav-pills do front-end serem
ativados foi inserido o teste de existência de urls_extras
para serem testadas e, sendo válidado, o active do front-end
seja devidamente colocado.
"""
view = context['view']
if hasattr(view, '__class__') and\
hasattr(view.__class__, 'crud'):
urls = view.__class__.crud.get_urls()
for u in urls:
if (u.name == url_name or
'urls_extras' in menu and
u.name in menu['urls_extras']):
menu['active'] = 'active'
break
if 'check_permission' in menu and not context[
'request'].user.has_perm(menu['check_permission']):
menu['url'] = ''
menu['active'] = ''
else:
menu['url'] = reverse(
'%s:%s' % (rm.app_name, menu['url']), kwargs={'pk': pk})
menu['active'] = 'active'\
if context['request'].path == menu['url'] else ''
if not menu['active']:
"""
Se não encontrada diretamente,
procura a url acionada dentro do crud, caso seja um.
Serve para manter o active no suvnav correto ao acionar
as funcionalidades diretas do MasterDetailCrud, como:
- visualização de detalhes, adição, edição, remoção.
"""
view = context['view']
if hasattr(view, '__class__') and\
hasattr(view.__class__, 'crud'):
urls = view.__class__.crud.get_urls()
for u in urls:
if (u.name == url_name or
'urls_extras' in menu and
u.name in menu['urls_extras']):
menu['active'] = 'active'
break
if 'children' in menu:
menu['active'] = resolve_urls_inplace(

2
sapl/base/urls.py

@ -20,7 +20,7 @@ urlpatterns = [
(TemplateView.as_view(template_name='sistema.html'))),
url(r'^ajuda/', TemplateView.as_view(template_name='ajuda.html')),
url(r'^relatorios/', TemplateView.as_view(
url(r'^relatorios/$', TemplateView.as_view(
template_name='base/relatorios_list.html')),
url(r'^ajuda/(?P<topic>\w+)$', HelpView.as_view(), name='help_topic'),
url(r'^ajuda/', TemplateView.as_view(template_name='ajuda/index.html'),

2
sapl/base/views.py

@ -1,5 +1,5 @@
from braces.views import PermissionRequiredMixin
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.urlresolvers import reverse
from django.db.models import Count, Q
from django.http import HttpResponseRedirect

11
sapl/comissoes/views.py

@ -68,13 +68,14 @@ class MateriasTramitacaoListView(ListView):
def get_queryset(self):
# FIXME: Otimizar consulta
lista = []
materias = MateriaLegislativa.objects.filter(tramitacao__isnull=False)
materias = MateriaLegislativa.objects.filter(
tramitacao__isnull=False).order_by('tipo', 'ano', 'numero')
for materia in materias:
comissao = materia.tramitacao_set.last(
).unidade_tramitacao_local.comissao
if comissao:
if comissao.pk == int(self.kwargs['pk']):
lista.append(materia)
).unidade_tramitacao_destino.comissao
if (comissao and materia not in lista and
comissao.pk == int(self.kwargs['pk'])):
lista.append(materia)
return lista
def get_context_data(self, **kwargs):

2
sapl/crispy_layout_mixin.py

@ -54,7 +54,7 @@ def get_field_display(obj, fieldname):
field = obj._meta.get_field(fieldname)
except:
value = getattr(obj, fieldname)
return '', value
return '', str(value)
verbose_name = str(field.verbose_name)\
if hasattr(field, 'verbose_name') else ''
if hasattr(field, 'choices') and field.choices:

62
sapl/crud/base.py

@ -13,8 +13,8 @@ from django.db import models
from django.http.response import Http404
from django.utils.decorators import classonlymethod
from django.utils.encoding import force_text
from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat
from django.views.generic import (CreateView, DeleteView, DetailView, ListView,
UpdateView)
from django.views.generic.base import ContextMixin
@ -23,7 +23,6 @@ from django.views.generic.list import MultipleObjectMixin
from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display
from sapl.utils import normalize
logger = logging.getLogger(__name__)
ACTION_LIST, ACTION_CREATE, ACTION_DETAIL, ACTION_UPDATE, ACTION_DELETE = \
@ -158,11 +157,25 @@ class ListWithSearchForm(forms.Form):
)
class PermissionRequiredForAppCrudMixin(PermissionRequiredMixin):
def has_permission(self):
apps = self.app_label
if isinstance(apps, str):
apps = apps,
# papp_label vazio dará acesso geral
for app in apps:
if not self.request.user.has_module_perms(app):
return False
return True
class PermissionRequiredContainerCrudMixin(PermissionRequiredMixin):
def has_permission(self):
perms = self.get_permission_required()
# Torna a view pública se não possuir o atributo permission_required
# Torna a view pública se não possuir conteudo
# no atributo permission_required
return self.request.user.has_perms(perms) if len(perms) else True
def dispatch(self, request, *args, **kwargs):
@ -302,7 +315,7 @@ class CrudBaseMixin(CrispyLayoutFormMixin):
def delete_url(self):
obj = self.crud if hasattr(self, 'crud') else self
if not obj.DeleteView.permission_required:
return self.resolve_url(ACTION_DELETE)
return self.resolve_url(ACTION_DELETE, args=(self.object.id,))
else:
return self.resolve_url(ACTION_DELETE, args=(self.object.id,))\
if self.request.user.has_perm(
@ -354,7 +367,6 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
for fieldname in self.list_field_names:
if not isinstance(fieldname, tuple):
fieldname = fieldname,
s = []
for fn in fieldname:
m = self.model
@ -363,20 +375,12 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
f = m._meta.get_field(f)
if hasattr(f, 'related_model') and f.related_model:
m = f.related_model
if m == self.model:
s.append(force_text(f.verbose_name))
else:
s.append(force_text(m._meta.verbose_name))
s.append(force_text(f.verbose_name))
s = ' / '.join(s)
r.append(s)
return r
def _as_row(self, obj):
"""
FIXME: Refatorar função para capturar url correta em caso de uso de
campos foreignkey. getHeaders faz isso para construir o título.
falta fazer com esta função
"""
r = []
for i, name in enumerate(self.list_field_names):
url = self.resolve_url(
@ -388,20 +392,28 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
url = url + ('?pkk=' + self.kwargs['pk']
if 'pk' in self.kwargs else '')
if not isinstance(name, tuple):
name = name,
""" se elemento de list_field_name for uma tupla, constrói a
informação com ' - ' se os campos forem simples,
ou com <br> se for m2m """
if isinstance(name, tuple):
s = ''
for j, n in enumerate(name):
ss = get_field_display(obj, n)[1]
ss = (
('<br>' if '<ul>' in ss else ' - ') + ss)\
if ss and j != 0 and s else ss
s += ss
m = obj
n = n.split('__')
for f in n[:-1]:
m = getattr(m, f)
if not m:
break
if m:
ss = get_field_display(m, n[-1])[1]
ss = (
('<br>' if '<ul>' in ss else ' - ') + ss)\
if ss and j != 0 and s else ss
s += ss
r.append((s, url))
else:
r.append((get_field_display(obj, name)[1], url))
return r
def get_context_data(self, **kwargs):
@ -674,7 +686,10 @@ class CrudDetailView(PermissionRequiredContainerCrudMixin,
return DetailView.get_object(self, queryset=queryset)
def get(self, request, *args, **kwargs):
self.object = self.model.objects.get(pk=kwargs.get('pk'))
try:
self.object = self.model.objects.get(pk=kwargs.get('pk'))
except:
raise Http404
obj = self.crud if hasattr(self, 'crud') else self
if hasattr(obj, 'model_set') and obj.model_set:
self.object_list = self.get_queryset()
@ -1070,9 +1085,6 @@ class MasterDetailCrud(Crud):
def get_url_regex(cls):
return r'^%s/(?P<pk>\d+)/edit$' % cls.model._meta.model_name
def get(self, request, *args, **kwargs):
return Crud.UpdateView.get(self, request, *args, **kwargs)
class DeleteView(Crud.DeleteView):
permission_required = RP_DELETE,

33
sapl/materia/forms.py

@ -1,5 +1,6 @@
from datetime import datetime
import django_filters
from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout
from django import forms
@ -11,7 +12,6 @@ from django.db import models, transaction
from django.db.models import Max
from django.forms import ModelForm
from django.utils.translation import ugettext_lazy as _
import django_filters
from sapl.comissoes.models import Comissao
from sapl.crispy_layout_mixin import form_actions, to_row
@ -27,7 +27,6 @@ from .models import (AcompanhamentoMateria, Anexada, Autor, Autoria,
Numeracao, Proposicao, Relatoria, TipoMateriaLegislativa,
Tramitacao, UnidadeTramitacao)
ANO_CHOICES = [('', '---------')] + RANGE_ANOS
@ -364,17 +363,35 @@ class LegislacaoCitadaForm(ModelForm):
else:
cleaned_data['norma'] = norma
if LegislacaoCitada.objects.filter(
filtro_base = LegislacaoCitada.objects.filter(
materia=self.instance.materia,
norma=cleaned_data['norma']
).exists():
msg = _('Essa Legislação já foi cadastrada.')
raise ValidationError(msg)
norma=self.cleaned_data['norma'],
disposicoes=self.cleaned_data['disposicoes'],
parte=self.cleaned_data['parte'],
livro=self.cleaned_data['livro'],
titulo=self.cleaned_data['titulo'],
capitulo=self.cleaned_data['capitulo'],
secao=self.cleaned_data['secao'],
subsecao=self.cleaned_data['subsecao'],
artigo=self.cleaned_data['artigo'],
paragrafo=self.cleaned_data['paragrafo'],
inciso=self.cleaned_data['inciso'],
alinea=self.cleaned_data['alinea'],
item=self.cleaned_data['item'])
if not self.instance.id:
if filtro_base.exists():
msg = _('Essa Legislação já foi cadastrada.')
raise ValidationError(msg)
else:
if filtro_base.exclude(id=self.instance.id).exists():
msg = _('Essa Legislação já foi cadastrada.')
raise ValidationError(msg)
return cleaned_data
def save(self, commit=False):
legislacao = super(LegislacaoCitadaForm, self).save(commit)
legislacao.norma = self.cleaned_data['norma']
legislacao.save()
return legislacao

19
sapl/materia/migrations/0051_auto_20161004_0927.py

@ -0,0 +1,19 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-04 12:27
from __future__ import unicode_literals
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
('materia', '0050_auto_20161003_0417'),
]
operations = [
migrations.AlterModelOptions(
name='tramitacao',
options={'ordering': ('-data_tramitacao',), 'verbose_name': 'Tramitação', 'verbose_name_plural': 'Tramitações'},
),
]

20
sapl/materia/migrations/0052_auto_20161004_1041.py

@ -0,0 +1,20 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-04 13:41
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('materia', '0051_auto_20161004_0927'),
]
operations = [
migrations.AlterField(
model_name='regimetramitacao',
name='descricao',
field=models.CharField(max_length=50, verbose_name='Descrição'),
),
]

4
sapl/materia/models.py

@ -35,7 +35,7 @@ class TipoMateriaLegislativa(models.Model):
class RegimeTramitacao(models.Model):
descricao = models.CharField(max_length=50)
descricao = models.CharField(max_length=50, verbose_name=_('Descrição'))
class Meta:
verbose_name = _('Regime Tramitação')
@ -589,7 +589,7 @@ class Tramitacao(models.Model):
class Meta:
verbose_name = _('Tramitação')
verbose_name_plural = _('Tramitações')
ordering = 'data_tramitacao',
ordering = '-data_tramitacao',
def __str__(self):
return _('%(materia)s | %(status)s | %(data)s') % {

55
sapl/materia/views.py

@ -26,9 +26,11 @@ from django_filters.views import FilterView
from sapl.base.models import CasaLegislativa
from sapl.compilacao.views import IntegracaoTaView
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux, CrudDetailView,
MasterDetailCrud, make_pagination)
from sapl.materia.forms import AnexadaForm
from sapl.crud.base import (ACTION_CREATE, ACTION_DELETE, ACTION_DETAIL,
ACTION_LIST, ACTION_UPDATE, RP_DETAIL, RP_LIST,
Crud, CrudAux, CrudDetailView, MasterDetailCrud,
make_pagination)
from sapl.materia.forms import AnexadaForm, LegislacaoCitadaForm
from sapl.norma.models import LegislacaoCitada
from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
autor_modal, gerar_hash_arquivo, get_base_url,
@ -50,9 +52,6 @@ from .models import (AcompanhamentoMateria, Anexada, Autor, Autoria,
TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao,
Tramitacao, UnidadeTramitacao)
AnexadaCrud = Crud.build(Anexada, '')
OrigemCrud = Crud.build(Origem, '')
TipoMateriaCrud = CrudAux.build(
@ -720,7 +719,39 @@ class LegislacaoCitadaCrud(MasterDetailCrud):
return reverse('%s:%s' % (namespace, self.url_name(suffix)),
args=args)
def has_permission(self):
return self.request.user.has_module_perms('materia')
@property
def list_url(self):
return self.resolve_url(ACTION_LIST, args=(self.kwargs['pk'],))\
if self.request.user.has_module_perms('materia') else ''
@property
def create_url(self):
return self.resolve_url(ACTION_CREATE, args=(self.kwargs['pk'],))\
if self.request.user.has_module_perms('materia') else ''
@property
def detail_url(self):
return self.resolve_url(ACTION_DETAIL, args=(self.object.id,))\
if self.request.user.has_module_perms('materia') else ''
@property
def update_url(self):
return self.resolve_url(ACTION_UPDATE, args=(self.kwargs['pk'],))\
if self.request.user.has_module_perms('materia') else ''
@property
def delete_url(self):
return self.resolve_url(ACTION_DELETE, args=(self.object.id,))\
if self.request.user.has_module_perms('materia') else ''
class CreateView(MasterDetailCrud.CreateView):
form_class = LegislacaoCitadaForm
class UpdateView(MasterDetailCrud.UpdateView):
form_class = LegislacaoCitadaForm
def get_initial(self):
self.initial['tipo'] = self.object.norma.tipo.id
@ -751,6 +782,18 @@ class AnexadaCrud(MasterDetailCrud):
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['materia_anexada', 'data_anexacao']
class CreateView(MasterDetailCrud.CreateView):
form_class = AnexadaForm
class UpdateView(MasterDetailCrud.UpdateView):
form_class = AnexadaForm
def get_initial(self):
self.initial['tipo'] = self.object.materia_anexada.tipo.id
self.initial['numero'] = self.object.materia_anexada.numero
self.initial['ano'] = self.object.materia_anexada.ano
return self.initial
class DetailView(MasterDetailCrud.DetailView):
@property

3
sapl/norma/models.py

@ -167,6 +167,9 @@ class LegislacaoCitada(models.Model):
verbose_name = _('Legislação')
verbose_name_plural = _('Legislações')
def __str__(self):
return str(self.norma)
class VinculoNormaJuridica(models.Model):
TIPO_VINCULO_CHOICES = (

8
sapl/norma/views.py

@ -5,12 +5,12 @@ from django.views.generic import FormView, ListView
from sapl.compilacao.views import IntegracaoTaView
from sapl.crud.base import RP_DETAIL, RP_LIST, Crud, CrudAux, make_pagination
from sapl.norma.forms import NormaJuridicaForm
from .forms import NormaJuridicaPesquisaForm
from .models import (AssuntoNorma, LegislacaoCitada, NormaJuridica,
TipoNormaJuridica)
from .models import AssuntoNorma, NormaJuridica, TipoNormaJuridica
LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '')
# LegislacaoCitadaCrud = Crud.build(LegislacaoCitada, '')
AssuntoNormaCrud = CrudAux.build(AssuntoNorma, 'assunto_norma_juridica',
@ -28,6 +28,7 @@ class NormaCrud(Crud):
public = [RP_LIST, RP_DETAIL]
class UpdateView(Crud.UpdateView):
form_class = NormaJuridicaForm
@property
def layout_key(self):
@ -42,6 +43,7 @@ class NormaCrud(Crud):
return self.initial.copy()
class CreateView(Crud.CreateView):
form_class = NormaJuridicaForm
@property
def layout_key(self):

4
sapl/parlamentares/views.py

@ -118,6 +118,10 @@ class MandatoCrud(MasterDetailCrud):
model = Mandato
parent_field = 'parlamentar'
public = [RP_DETAIL, RP_LIST]
list_field_names = ['legislatura',
'votos_recebidos',
'coligacao',
'coligacao__numero_votos']
class ListView(MasterDetailCrud.ListView):
ordering = ('-legislatura__numero')

18
sapl/relatorios/urls.py

@ -10,22 +10,22 @@ from .views import (relatorio_capa_processo,
app_name = AppConfig.name
urlpatterns = [
url(r'^relatorio/materia$', relatorio_materia, name='relatorio_materia'),
url(r'^relatorio/capa-processo$',
url(r'^relatorios/materia$', relatorio_materia, name='relatorio_materia'),
url(r'^relatorios/capa-processo$',
relatorio_capa_processo, name='relatorio_capa_processo'),
url(r'^relatorio/ordem-dia$', relatorio_ordem_dia,
url(r'^relatorios/ordem-dia$', relatorio_ordem_dia,
name='relatorio_ordem_dia'),
url(r'^relatorio/relatorio-documento-administrativo$',
url(r'^relatorios/relatorio-documento-administrativo$',
relatorio_documento_administrativo,
name='relatorio_documento_administrativo'),
url(r'^relatorio/espelho$', relatorio_espelho,
url(r'^relatorios/espelho$', relatorio_espelho,
name='relatorio_espelho'),
url(r'^relatorio/(?P<pk>\d+)/sessao-plenaria$',
url(r'^relatorios/(?P<pk>\d+)/sessao-plenaria$',
relatorio_sessao_plenaria, name='relatorio_sessao_plenaria'),
url(r'^relatorio/protocolo$',
url(r'^relatorios/protocolo$',
relatorio_protocolo, name='relatorio_protocolo'),
url(r'^relatorio/(?P<nro>\d+)/(?P<ano>\d+)/etiqueta-protocolo$',
url(r'^relatorios/(?P<nro>\d+)/(?P<ano>\d+)/etiqueta-protocolo$',
relatorio_etiqueta_protocolo, name='relatorio_etiqueta_protocolo'),
url(r'^relatorio/pauta-sessao$',
url(r'^relatorios/pauta-sessao$',
relatorio_pauta_sessao, name='relatorio_pauta_sessao'),
]

25
sapl/sessao/migrations/0028_auto_20161004_0927.py

@ -0,0 +1,25 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-04 12:27
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sessao', '0027_auto_20161003_0417'),
]
operations = [
migrations.AlterField(
model_name='orador',
name='url_discurso',
field=models.CharField(blank=True, max_length=150, verbose_name='URL Vídeo ou Observação'),
),
migrations.AlterField(
model_name='oradorexpediente',
name='url_discurso',
field=models.CharField(blank=True, max_length=150, verbose_name='URL Vídeo ou Observação'),
),
]

35
sapl/sessao/migrations/0029_auto_20161004_1101.py

@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.7 on 2016-10-04 14:01
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('sessao', '0028_auto_20161004_0927'),
]
operations = [
migrations.AddField(
model_name='orador',
name='observacao',
field=models.CharField(blank=True, max_length=150, verbose_name='Observação'),
),
migrations.AddField(
model_name='oradorexpediente',
name='observacao',
field=models.CharField(blank=True, max_length=150, verbose_name='Observação'),
),
migrations.AlterField(
model_name='orador',
name='url_discurso',
field=models.URLField(blank=True, max_length=150, verbose_name='URL Vídeo'),
),
migrations.AlterField(
model_name='oradorexpediente',
name='url_discurso',
field=models.URLField(blank=True, max_length=150, verbose_name='URL Vídeo'),
),
]

2
sapl/sessao/models.py

@ -215,6 +215,8 @@ class AbstractOrador(models.Model): # Oradores
verbose_name=_('Ordem de pronunciamento'))
url_discurso = models.URLField(
max_length=150, blank=True, verbose_name=_('URL Vídeo'))
observacao = models.CharField(
max_length=150, blank=True, verbose_name=_('Observação'))
class Meta:
abstract = True

257
sapl/sessao/views.py

@ -1,9 +1,7 @@
from datetime import datetime
from re import sub
from braces.views import PermissionRequiredMixin
from django.contrib import messages
from django.contrib.auth.decorators import permission_required
from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.core.urlresolvers import reverse
from django.forms.utils import ErrorList
@ -19,8 +17,10 @@ from django.views.generic.edit import FormMixin
from django_filters.views import FilterView
from rest_framework import generics
from sapl.base.models import AppConfig as AppsAppConfig
from sapl.crud.base import (RP_DETAIL, RP_LIST, Crud, CrudAux,
MasterDetailCrud, make_pagination)
MasterDetailCrud,
PermissionRequiredForAppCrudMixin, make_pagination)
from sapl.materia.forms import pega_ultima_tramitacao
from sapl.materia.models import (Autoria, DocumentoAcessorio,
TipoMateriaLegislativa, Tramitacao)
@ -29,8 +29,9 @@ from sapl.norma.models import NormaJuridica
from sapl.parlamentares.models import (Legislatura, Parlamentar,
SessaoLegislativa)
from sapl.sessao.apps import AppConfig
from sapl.sessao.forms import ExpedienteMateriaForm, OrdemDiaForm
from sapl.sessao.serializers import SessaoPlenariaSerializer
from sapl.utils import permissoes_painel, permissoes_sessao
from sapl.utils import permission_required_for_app
from .forms import (AdicionarVariasMateriasFilterSet, ExpedienteForm,
ListMateriaForm, MesaForm, PautaSessaoFilterSet,
@ -43,9 +44,8 @@ from .models import (Bancada, Bloco, CargoBancada, CargoMesa,
SessaoPlenariaPresenca, TipoExpediente,
TipoResultadoVotacao, TipoSessaoPlenaria, VotoParlamentar)
OrdemDiaCrud = Crud.build(OrdemDia, '')
RegistroVotacaoCrud = Crud.build(RegistroVotacao, '')
# OrdemDiaCrud = Crud.build(OrdemDia, '')
# RegistroVotacaoCrud = Crud.build(RegistroVotacao, '')
TipoSessaoCrud = CrudAux.build(TipoSessaoPlenaria, 'tipo_sessao_plenaria')
TipoExpedienteCrud = CrudAux.build(TipoExpediente, 'tipo_expediente')
CargoBancadaCrud = CrudAux.build(CargoBancada, '')
@ -122,18 +122,21 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
model = OrdemDia
parent_field = 'sessao_plenaria'
help_path = ''
public = [RP_LIST, RP_DETAIL]
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['numero_ordem', 'materia', 'observacao',
'resultado']
class CreateView(MasterDetailCrud.CreateView):
form_class = OrdemDiaForm
def get_success_url(self):
return reverse('sapl.sessao:ordemdia_list',
kwargs={'pk': self.kwargs['pk']})
class UpdateView(MasterDetailCrud.UpdateView):
form_class = OrdemDiaForm
def get_initial(self):
self.initial['tipo_materia'] = self.object.materia.tipo.id
@ -173,11 +176,11 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
'pk': obj.sessao_plenaria_id,
'oid': obj.materia_id,
'mid': obj.pk})
if self.request.user.has_perms(permissoes_sessao()):
if self.request.user.has_module_perms(AppConfig.label):
btn_registrar = '''
<a href="%s"
class="btn btn-primary"
role="button">Registrar Votação</a>''' % (
<a href="%s"
class="btn btn-primary"
role="button">Registrar Votação</a>''' % (
url)
obj.resultado = btn_registrar
else:
@ -245,12 +248,13 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
model = ExpedienteMateria
parent_field = 'sessao_plenaria'
help_path = ''
public = [RP_LIST, RP_DETAIL]
class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['numero_ordem', 'materia',
'observacao', 'resultado']
class ListView(Crud.PublicMixin, MasterDetailCrud.ListView):
class ListView(MasterDetailCrud.ListView):
ordering = ['numero_ordem', 'materia', 'resultado']
def get_rows(self, object_list):
@ -277,16 +281,19 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
'oid': obj.materia_id,
'mid': obj.pk})
btn_registrar = '''
<a href="%s"
class="btn btn-primary"
role="button">Registrar Votação</a>''' % (url)
obj.resultado = btn_registrar
if self.request.user.has_module_perms(AppConfig.label):
btn_registrar = '''
<a href="%s" class="btn btn-primary"
role="button">
Registrar Votação</a>''' % (url)
obj.resultado = btn_registrar
else:
url = reverse('sapl.sessao:abrir_votacao_exp', kwargs={
'pk': obj.pk, 'spk': obj.sessao_plenaria_id})
btn_abrir = '''
Matéria não votada<br />
btn_abrir = '''Matéria não votada<br />'''
if self.request.user.has_module_perms(AppConfig.label):
btn_abrir += '''
<a href="%s"
class="btn btn-primary"
role="button">Abrir Votação</a>''' % (url)
@ -294,35 +301,40 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
obj.resultado = btn_abrir
else:
url = ''
if obj.tipo_votacao == 1:
url = reverse('sapl.sessao:votacaosimbolicaexpedit',
kwargs={
'pk': obj.sessao_plenaria_id,
'oid': obj.materia_id,
'mid': obj.pk})
elif obj.tipo_votacao == 2:
url = reverse('sapl.sessao:votacaonominalexpedit',
kwargs={
'pk': obj.sessao_plenaria_id,
'oid': obj.materia_id,
'mid': obj.pk})
elif obj.tipo_votacao == 3:
url = reverse('sapl.sessao:votacaosecretaexpedit',
kwargs={
'pk': obj.sessao_plenaria_id,
'oid': obj.materia_id,
'mid': obj.pk})
obj.resultado = '<a href="%s">%s</a>' % (url,
obj.resultado)
if self.request.user.has_module_perms(AppConfig.label):
if obj.tipo_votacao == 1:
url = reverse(
'sapl.sessao:votacaosimbolicaexpedit',
kwargs={
'pk': obj.sessao_plenaria_id,
'oid': obj.materia_id,
'mid': obj.pk})
elif obj.tipo_votacao == 2:
url = reverse('sapl.sessao:votacaonominalexpedit',
kwargs={
'pk': obj.sessao_plenaria_id,
'oid': obj.materia_id,
'mid': obj.pk})
elif obj.tipo_votacao == 3:
url = reverse('sapl.sessao:votacaosecretaexpedit',
kwargs={
'pk': obj.sessao_plenaria_id,
'oid': obj.materia_id,
'mid': obj.pk})
obj.resultado = '<a href="%s">%s</a>' % (url,
obj.resultado)
return [self._as_row(obj) for obj in object_list]
class CreateView(MasterDetailCrud.CreateView):
form_class = ExpedienteMateriaForm
def get_success_url(self):
return reverse('sapl.sessao:expedientemateria_list',
kwargs={'pk': self.kwargs['pk']})
class UpdateView(MasterDetailCrud.UpdateView):
form_class = ExpedienteMateriaForm
def get_initial(self):
self.initial['tipo_materia'] = self.object.materia.tipo.id
@ -403,9 +415,6 @@ class SessaoCrud(Crud):
list_field_names = ['data_inicio', 'legislatura', 'sessao_legislativa',
'tipo']
class CrudDetailView(DetailView):
model = SessaoPlenaria
class ListView(Crud.ListView):
ordering = ['-data_inicio']
@ -419,6 +428,13 @@ class SessaoCrud(Crud):
'sessao_legislativa': sessao_legislativa}
class SessaoPermissionMixin(PermissionRequiredForAppCrudMixin,
FormMixin,
DetailView):
model = SessaoPlenaria
app_label = AppConfig.label,
class PresencaMixin:
def get_presencas(self):
@ -455,14 +471,13 @@ class PresencaView(FormMixin, PresencaMixin, DetailView):
form_class = PresencaForm
model = SessaoPlenaria
@method_decorator(permission_required((
'%s.add_%s' % (
AppConfig.label, SessaoPlenariaPresenca._meta.model_name),
'%s.change_%s' % (
AppConfig.label, SessaoPlenariaPresenca._meta.model_name),
'%s.delete_%s' % (
AppConfig.label, SessaoPlenariaPresenca._meta.model_name),
)))
def get_context_data(self, **kwargs):
context = FormMixin.get_context_data(self, **kwargs)
context['title'] = '%s <small>(%s)</small>' % (
_('Presença'), self.object)
return context
@method_decorator(permission_required_for_app(AppConfig.label))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = self.get_form()
@ -502,9 +517,33 @@ class PresencaView(FormMixin, PresencaMixin, DetailView):
return reverse('sapl.sessao:presenca', kwargs={'pk': pk})
class PainelView(PermissionRequiredMixin, TemplateView):
class PainelView(PermissionRequiredForAppCrudMixin, TemplateView):
template_name = 'sessao/painel.html'
permission_required = permissoes_painel()
app_label = 'painel'
def has_permission(self):
painel_aberto = AppsAppConfig.attr('painel_aberto')
if painel_aberto and self.request.user.is_anonymous():
return True
return PermissionRequiredForAppCrudMixin.has_permission(self)
def get(self, request, *args, **kwargs):
if request.user.is_anonymous():
self.template_name = 'painel/index.html'
return TemplateView.get(self, request, *args, **kwargs)
def get_context_data(self, **kwargs):
context = TemplateView.get_context_data(self, **kwargs)
context.update({
'head_title': str(_('Painel Plenário')),
'sessao_id': kwargs['pk'],
'root_pk': kwargs['pk'],
'sessaoplenaria': SessaoPlenaria.objects.get(pk=kwargs['pk'])})
return context
class PresencaOrdemDiaView(FormMixin, PresencaMixin, DetailView):
@ -512,11 +551,13 @@ class PresencaOrdemDiaView(FormMixin, PresencaMixin, DetailView):
form_class = PresencaForm
model = SessaoPlenaria
@method_decorator(permission_required((
'%s.add_%s' % (AppConfig.label, PresencaOrdemDia._meta.model_name),
'%s.change_%s' % (AppConfig.label, PresencaOrdemDia._meta.model_name),
'%s.delete_%s' % (AppConfig.label, PresencaOrdemDia._meta.model_name),
)))
def get_context_data(self, **kwargs):
context = FormMixin.get_context_data(self, **kwargs)
context['title'] = '%s <small>(%s)</small>' % (
_('Presença Ordem do Dia'), self.object)
return context
@method_decorator(permission_required_for_app(AppConfig.label))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
@ -524,9 +565,6 @@ class PresencaOrdemDiaView(FormMixin, PresencaMixin, DetailView):
pk = kwargs['pk']
if not self.request.user.has_perms(permissoes_sessao()):
return self.form_invalid(form)
if form.is_valid():
# Pegar os presentes salvos no banco
presentes_banco = PresencaOrdemDia.objects.filter(
@ -599,11 +637,7 @@ class ListMateriaOrdemDiaView(FormMixin, DetailView):
return self.render_to_response(context)
@method_decorator(permission_required((
'%s.add_%s' % (AppConfig.label, OrdemDia._meta.model_name),
'%s.change_%s' % (AppConfig.label, OrdemDia._meta.model_name),
'%s.delete_%s' % (AppConfig.label, OrdemDia._meta.model_name),
)))
@method_decorator(permission_required_for_app(AppConfig.label))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
context = self.get_context_data(object=self.object)
@ -694,11 +728,13 @@ class MesaView(FormMixin, DetailView):
return self.render_to_response(context)
@method_decorator(permission_required((
'%s.add_integrantemesa' % AppConfig.label,
'%s.change_integrantemesa' % AppConfig.label,
'%s.delete_integrantemesa' % AppConfig.label,
)))
def get_context_data(self, **kwargs):
context = FormMixin.get_context_data(self, **kwargs)
context['title'] = '%s <small>(%s)</small>' % (
_('Mesa Diretora'), self.object)
return context
@method_decorator(permission_required_for_app(AppConfig.label))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = MesaForm(request.POST)
@ -761,7 +797,6 @@ class MesaView(FormMixin, DetailView):
lista_cargos_ocupados.append(cargo)
lista = list(set(lista_cargos) - set(lista_cargos_ocupados))
lista.sort(key=lambda x: x.descricao)
return lista
def get_success_url(self):
@ -769,8 +804,9 @@ class MesaView(FormMixin, DetailView):
return reverse('sapl.sessao:mesa', kwargs={'pk': pk})
class ResumoView(SessaoCrud.CrudDetailView):
class ResumoView(DetailView):
template_name = 'sessao/resumo.html'
model = SessaoPlenaria
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@ -941,18 +977,22 @@ class ResumoView(SessaoCrud.CrudDetailView):
return self.render_to_response(context)
class ExpedienteView(FormMixin,
SessaoCrud.CrudDetailView):
class ExpedienteView(FormMixin, DetailView):
template_name = 'sessao/expediente.html'
form_class = ExpedienteForm
model = SessaoPlenaria
def get_context_data(self, **kwargs):
context = FormMixin.get_context_data(self, **kwargs)
context['title'] = '%s <small>(%s)</small>' % (
_('Expediente Diversos'), self.object)
return context
@method_decorator(permission_required_for_app(AppConfig.label))
def post(self, request, *args, **kwargs):
self.object = self.get_object()
form = ExpedienteForm(request.POST)
if not self.request.user.has_perms(permissoes_sessao()):
return self.form_invalid(form)
if form.is_valid():
list_tipo = request.POST.getlist('tipo')
list_conteudo = request.POST.getlist('conteudo')
@ -1009,16 +1049,13 @@ class ExpedienteView(FormMixin,
return reverse('sapl.sessao:expediente', kwargs={'pk': pk})
class VotacaoEditView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
class VotacaoEditView(SessaoPermissionMixin):
'''
Votação Simbólica e Secreta
'''
template_name = 'sessao/votacao/votacao_edit.html'
permission_required = permissoes_sessao()
def post(self, request, *args, **kwargs):
@ -1085,9 +1122,7 @@ class VotacaoEditView(PermissionRequiredMixin,
kwargs={'pk': pk})
class VotacaoView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
class VotacaoView(SessaoPermissionMixin):
'''
Votação Simbólica e Secreta
@ -1095,7 +1130,6 @@ class VotacaoView(PermissionRequiredMixin,
template_name = 'sessao/votacao/votacao.html'
form_class = VotacaoForm
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@ -1207,11 +1241,8 @@ class VotacaoView(PermissionRequiredMixin,
kwargs={'pk': pk})
class VotacaoNominalView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
class VotacaoNominalView(SessaoPermissionMixin):
template_name = 'sessao/votacao/nominal.html'
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
ordem_id = kwargs['mid']
@ -1335,11 +1366,8 @@ class VotacaoNominalView(PermissionRequiredMixin,
kwargs={'pk': pk})
class VotacaoNominalEditView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
class VotacaoNominalEditView(SessaoPermissionMixin):
template_name = 'sessao/votacao/nominal_edit.html'
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
context = {}
@ -1415,11 +1443,8 @@ class VotacaoNominalEditView(PermissionRequiredMixin,
kwargs={'pk': pk})
class VotacaoNominalExpedienteView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
class VotacaoNominalExpedienteView(SessaoPermissionMixin):
template_name = 'sessao/votacao/nominal.html'
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
expediente_id = kwargs['mid']
@ -1541,11 +1566,8 @@ class VotacaoNominalExpedienteView(PermissionRequiredMixin,
kwargs={'pk': pk})
class VotacaoNominalExpedienteEditView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
class VotacaoNominalExpedienteEditView(SessaoPermissionMixin):
template_name = 'sessao/votacao/nominal_edit.html'
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
context = {}
@ -1620,9 +1642,7 @@ class VotacaoNominalExpedienteEditView(PermissionRequiredMixin,
kwargs={'pk': pk})
class VotacaoExpedienteView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
class VotacaoExpedienteView(SessaoPermissionMixin):
'''
Votação Simbólica e Secreta
@ -1630,7 +1650,6 @@ class VotacaoExpedienteView(PermissionRequiredMixin,
template_name = 'sessao/votacao/votacao.html'
form_class = VotacaoForm
permission_required = permissoes_sessao()
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@ -1744,9 +1763,7 @@ class VotacaoExpedienteView(PermissionRequiredMixin,
kwargs={'pk': pk})
class VotacaoExpedienteEditView(PermissionRequiredMixin,
FormMixin,
SessaoCrud.CrudDetailView):
class VotacaoExpedienteEditView(SessaoPermissionMixin):
'''
Votação Simbólica e Secreta
@ -1754,7 +1771,6 @@ class VotacaoExpedienteEditView(PermissionRequiredMixin,
template_name = 'sessao/votacao/votacao_edit.html'
form_class = VotacaoEditForm
permission_required = permissoes_sessao()
def get_success_url(self):
pk = self.kwargs['pk']
@ -1845,8 +1861,9 @@ class PautaSessaoListView(SessaoListView):
template_name = "sessao/pauta_sessao_list.html"
class PautaSessaoDetailView(SessaoCrud.CrudDetailView):
class PautaSessaoDetailView(DetailView):
template_name = "sessao/pauta_sessao_detail.html"
model = SessaoPlenaria
def get(self, request, *args, **kwargs):
self.object = self.get_object()
@ -1956,8 +1973,9 @@ class SessaoPlenariaView(generics.ListAPIView):
serializer_class = SessaoPlenariaSerializer
class PautaExpedienteDetail(SessaoCrud.CrudDetailView):
class PautaExpedienteDetail(DetailView):
template_name = "sessao/pauta/expediente.html"
model = SessaoPlenaria
def get(self, request, *args, **kwargs):
pk = self.kwargs['pk']
@ -1974,8 +1992,9 @@ class PautaExpedienteDetail(SessaoCrud.CrudDetailView):
'tramitacao': tramitacao})
class PautaOrdemDetail(SessaoCrud.CrudDetailView):
class PautaOrdemDetail(DetailView):
template_name = "sessao/pauta/ordem.html"
model = SessaoPlenaria
def get(self, request, *args, **kwargs):
pk = self.kwargs['pk']
@ -2073,11 +2092,11 @@ def retira_materias_ja_adicionadas(id_sessao, model):
return lista_id_materias
class AdicionarVariasMateriasExpediente(PermissionRequiredMixin,
class AdicionarVariasMateriasExpediente(PermissionRequiredForAppCrudMixin,
MateriaLegislativaPesquisaView):
filterset_class = AdicionarVariasMateriasFilterSet
template_name = 'sessao/adicionar_varias_materias_expediente.html'
permission_required = permissoes_sessao()
app_label = AppConfig.label
def get_filterset_kwargs(self, filterset_class):
super(AdicionarVariasMateriasExpediente,
@ -2138,6 +2157,8 @@ class AdicionarVariasMateriasExpediente(PermissionRequiredMixin,
expediente = ExpedienteMateria()
expediente.sessao_plenaria_id = self.kwargs['pk']
expediente.materia_id = materia.id
expediente.observacao = MateriaLegislativa.objects.get(
pk=materia.id).ementa
if lista_materias_expediente:
posicao = lista_materias_expediente.last().numero_ordem + 1
expediente.numero_ordem = posicao
@ -2147,13 +2168,15 @@ class AdicionarVariasMateriasExpediente(PermissionRequiredMixin,
expediente.tipo_votacao = request.POST['tipo_votacao_%s' % m]
expediente.save()
return self.get(request, self.kwargs)
pk = self.kwargs['pk']
return HttpResponseRedirect(
reverse('sapl.sessao:expedientemateria_list', kwargs={'pk': pk}))
class AdicionarVariasMateriasOrdemDia(AdicionarVariasMateriasExpediente):
filterset_class = AdicionarVariasMateriasFilterSet
template_name = 'sessao/adicionar_varias_materias_ordem.html'
permission_required = permissoes_sessao()
def get_filterset_kwargs(self, filterset_class):
super(AdicionarVariasMateriasExpediente,
@ -2199,6 +2222,8 @@ class AdicionarVariasMateriasOrdemDia(AdicionarVariasMateriasExpediente):
ordem_dia = OrdemDia()
ordem_dia.sessao_plenaria_id = self.kwargs['pk']
ordem_dia.materia_id = materia.id
ordem_dia.observacao = MateriaLegislativa.objects.get(
pk=materia.id).ementa
if lista_materias_ordem_dia:
posicao = lista_materias_ordem_dia.last().numero_ordem + 1
ordem_dia.numero_ordem = posicao

10
sapl/templates/comissoes/materias_em_tramitacao.html

@ -3,12 +3,16 @@
{% load crispy_forms_tags %}
{% block actions %} {% endblock %}
{% block title %}
<h1 class="page-header">
Matérias em Tramitação <small>({{object}})</small>
</h1>
{% endblock %}
{% block detail_content %}
<fieldset>
<legend>{{comissao}}</legend>
<b>Há {{page_obj|length}} matéria(s) em tramitação nesta unidade.</b> <br><br>
{% for materia in page_obj %}
<b><a href="{% url 'sapl.materia:materialegislativa_detail' materia.id %}">
{{materia.tipo.sigla}} {{materia.numero}} {{materia.ano}} - {{materia.tipo}}
@ -18,7 +22,5 @@
<b>Situação: </b>{{materia.tramitacao_set.last.status.descricao}}<br>
<br>
{% endfor %}
</fieldset>
{% endblock detail_content %}

58
sapl/templates/crud/detail.html

@ -48,36 +48,38 @@
{% endfor %}
{% endblock detail_content %}
<div class="container-table">
{% if not rows %}
<p>{{ NO_ENTRIES_MSG }}</p>
{% else %}
<div class="result-count">{% blocktrans with verbose_name_plural=view.model_set_verbose_name_plural %}Total de {{ verbose_name_plural }}: <strong>{{count}}</strong>{% endblocktrans %}</div>
<table class="table table-striped table-hover">
<thead>
{% block table_content %}
<div class="container-table">
{% if not rows %}
<p>{{ NO_ENTRIES_MSG }}</p>
{% else %}
<div class="result-count">{% blocktrans with verbose_name_plural=view.model_set_verbose_name_plural %}Total de {{ verbose_name_plural }}: <strong>{{count}}</strong>{% endblocktrans %}</div>
<table class="table table-striped table-hover">
<thead>
<tr>
{% for name in headers %}
<th>{{ name }}</th>
{% endfor %}
</tr>
</thead>
<tbody>
{% for value_list in rows %}
<tr>
{% for name in headers %}
<th>{{ name }}</th>
{% for value, href in value_list %}
<td>
{% if href %}
<a href="{{ href }}">{{ value }}</a>
{% elif value != 'core.Cep.None' %}
{{ value|safe }}
{% endif %}
</td>
{% endfor %}
</tr>
</thead>
<tbody>
{% for value_list in rows %}
<tr>
{% for value, href in value_list %}
<td>
{% if href %}
<a href="{{ href }}">{{ value }}</a>
{% elif value != 'core.Cep.None' %}
{{ value|safe }}
{% endif %}
</td>
{% endfor %}
</tr>
{% endfor %}
</tbody>
</table>
{% endif %}
</div>
{% include "paginacao.html" %}
</tbody>
</table>
{% endif %}
</div>
{% include "paginacao.html" %}
{% endblock table_content %}
{% endblock base_content %}

104
sapl/templates/materia/materialegislativa_filter.html

@ -2,72 +2,62 @@
{% load i18n %}
{% load crispy_forms_tags %}
{% block actions %}
<div class="actions btn-group pull-right" role="group">
{% if user.is_authenticated %}
<a href="{% url 'sapl.materia:materialegislativa_create' %}" class="btn btn-default">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar Matéria Legislativa {% endblocktrans %}
</a>
{% block actions %}
<div class="actions btn-group pull-right" role="group">
{% if perms.materia %}
<a href="{% url 'sapl.materia:materialegislativa_create' %}" class="btn btn-default">
{% blocktrans with verbose_name=view.verbose_name %} Adicionar Matéria Legislativa {% endblocktrans %}
</a>
{% endif %}
{% if filter_url %}
<a href="{% url 'sapl.materia:pesquisar_materia' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
{% endif %}
{% if filter_url %}
<a href="{% url 'sapl.materia:pesquisar_materia' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
{% endif %}
</div>
{% endblock %}
</div>
{% endblock %}
{% block sections_nav %}
{% endblock %}
{% block detail_content %}
{% if not filter_url %}
{% crispy filter.form %}
{% endif %}
{% block detail_content %}
{% if not filter_url %}
{% crispy filter.form %}
{% endif %}
<p></p>
{% if filter_url %}
<table class="table table-striped table-bordered">
{% if filter_url %}
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr><td><h3>{% trans "Resultados" %}</h3></td></tr>
<tr><td><h3>{% trans "Resultados" %}</h3></td></tr>
</thead>
{% if paginator.count %}
{% if paginator.count > 1 %}
<h3>{% blocktrans with paginator.count as total_materias %}Pesquisa concluída com sucesso! Foram encontradas {{total_materias}} matérias.{% endblocktrans %}</h3>
{% elif paginator.count == 1 %}
<h3>{% trans 'Pesquisa concluída com sucesso! Foi encontrada 1 matéria.'%}</h3>
{% endif %}
<h3>{% blocktrans with paginator.count as total_materias %}Pesquisa concluída com sucesso! Foram encontradas {{total_materias}} matérias.{% endblocktrans %}</h3>
{% elif paginator.count == 1 %}
<h3>{% trans 'Pesquisa concluída com sucesso! Foi encontrada 1 matéria.'%}</h3>
{% endif %}
{% for m in page_obj %}
<tr>
<td>
<strong><a href="{% url 'materia:materialegislativa_detail' m.id %}">{{m.tipo.sigla}} {{m.numero}}/{{m.ano}} - {{m.tipo}}</strong></a></br>
<strong>Autores:</strong>
{% for a in m.autoria_set.all %}
{% if not forloop.first %}
, &nbsp;&nbsp; {{a.autor|default_if_none:"Não Informado"}}
{% else %}
&nbsp;{{a.autor|default_if_none:"Não Informado"}}
{% endif %}
{% endfor %}
</br>
<strong>Localização Atual:</strong> &nbsp;{{m.tramitacao_set.last.unidade_tramitacao_destino|default_if_none:"Não Informada"}}</br>
<strong>Status:</strong> &nbsp;{{m.tramitacao_set.last.status|default_if_none:"Não Informada"}}</br>
<strong>Data da última Tramitação:</strong> &nbsp;{{m.tramitacao_set.last.data_tramitacao|default_if_none:"Não Informada"}}</br>
<strong>Ementa:</strong>&nbsp;{{ m.ementa|safe }}</br>
<p></p>
</tr>
<tr>
<td>
<strong><a href="{% url 'materia:materialegislativa_detail' m.id %}">{{m.tipo.sigla}} {{m.numero}}/{{m.ano}} - {{m.tipo}}</strong></a></br>
<strong>Autores:</strong>
{% for a in m.autoria_set.all %}
{% if not forloop.first %}
, &nbsp;&nbsp; {{a.autor|default_if_none:"Não Informado"}}
{% else %}
&nbsp;{{a.autor|default_if_none:"Não Informado"}}
{% endif %}
{% endfor %}
</br>
<strong>Localização Atual:</strong> &nbsp;{{m.tramitacao_set.last.unidade_tramitacao_destino|default_if_none:"Não Informada"}}</br>
<strong>Status:</strong> &nbsp;{{m.tramitacao_set.last.status|default_if_none:"Não Informada"}}</br>
<strong>Data da última Tramitação:</strong> &nbsp;{{m.tramitacao_set.last.data_tramitacao|default_if_none:"Não Informada"}}</br>
<strong>Ementa:</strong>&nbsp;{{ m.ementa|safe }}</br>
<p></p>
</tr>
{% endfor %}
{% else %}
<tr>
<td>
<h3>Nenhuma matéria encontrada com essas especificações</h3>
</tr>
<tr><td><h3>Nenhuma matéria encontrada com essas especificações</h3></tr>
{% endif %}
</table>
{% include "paginacao.html" %}
{% endif %}
{% endblock detail_content %}
</table>
{% include "paginacao.html" %}
{% endif %}
{% endblock detail_content %}
{% block table_content %}
{% endblock table_content %}

6
sapl/templates/materia/subnav.yaml

@ -11,16 +11,12 @@
url: documentoacessorio_list
- title: {% trans 'Legislação Citada' %}
url: legislacaocitada_list
app_name: 'materia'
- title: {% trans 'Numeração' %}
url: numeracao_list
- title: {% trans 'Tramitação' %}
url: tramitacao_list
- title: {% trans 'Relatoria' %}
url: relatoria_list
# Opção adicionada para chamar o TextoArticulado da matéria.
# para integração foram necessárias apenas criar a url materia_ta em urls.py
# e a view MateriaTaView(IntegracaoTaView) em views.py
# Em nada mais a integração interfere em MateriaLegislativa
- title: {% trans 'Texto' %}
url: materia_ta

82
sapl/templates/menus/mesa_diretora/mesa_diretora.html

@ -1,82 +0,0 @@
{% extends "crud/detail.html" %}
{% load i18n %}
{% block actions %} {% endblock %}
{% block detail_content %}
<form method="POST">
{% csrf_token %}
<fieldset class="form-group">
<legend>Escolha da Legislatura e da Sessão Legislativa</legend>
<div class="row">
<div class="col-md-6">
<label>Escolha uma Legislatura</label>
<select name="legislatura" class="form-control" onChange="form.submit();">
{% for l in legislaturas %}
<option value="{{l.id}}" {% if l == legislatura_selecionada %} selected {% endif %}>
{{l}}
</option>
{% endfor %}
</select>
</div>
<div class="col-md-6">
<label>Escolha uma Sessão Legislativa</label>
<select name="sessao" class="form-control" onChange="form.submit();">
{% for s in sessoes %}
<option value="{{s.id}}" {% if s == sessao_selecionada %} selected {% endif %}>
{{s}}
</option>
{% endfor %}
</select>
</div>
</div>
</fieldset>
<br />
<fieldset class="form-group">
<legend>Escolha da Composição da Mesa Diretora</legend>
<div class="row">
<div class="col-md-4">
<label>Composição da Mesa Diretora</label>
<select multiple size="5" class="form-control" name="composicao_mesa">
{% for p in composicao_mesa %}
<option value="{{p.parlamentar.id}}:{{p.cargo.id}}">
{{p.parlamentar}} || {{p.cargo}}
</option>
{% endfor %}
</select>
</div>
<div class="col-md-4" align="center">
<br /><br />
{% if cargos_vagos %}
{% if perms.parlamentares.add_cargomesa or perms.parlamentares.add_composicaomesa %}
<input type="submit" name="Incluir" Value="Incluir" class="btn btn-primary" />
{% endif %}
{% endif %}
<br />
<br />
{% if perms.parlamentares.add_cargomesa or perms.parlamentares.add_composicaomesa %}
<input type="submit" name="Excluir" Value="Excluir" class="btn btn-danger" />
{% endif %}
</div>
{% if cargos_vagos %}
<div class="col-md-4">
<label>Parlamentare | Cargo</label>
<select class="form-control" name="parlamentar" id="parlamentar">
{% for p in parlamentares %}
<option value="{{p.id}}">{{p.nome_completo}}</option>
{% endfor %}
</select>
<br />
<select class="form-control" name="cargo" id="cargo">
{% for c in cargos_vagos %}
<option value="{{c.id}}">{{c}}</option>
{% endfor %}
</select>
</div>
{% endif %}
</div>
</fieldset>
</form>
{% endblock detail_content %}

8
sapl/templates/menus/subnav.html

@ -12,12 +12,16 @@
</a>
<ul class="dropdown-menu" role="menu">
{% for subitem in item.children %}
<li class="{{subitem.active}}"><a href="{{ subitem.url }}">{% trans subitem.title %}</a></li>
{% if subitem.url %}
<li class="{{subitem.active}}"><a href="{{ subitem.url }}">{% trans subitem.title %}</a></li>
{% endif %}
{% endfor %}
</ul>
</li>
{% else %}
<li class="{{item.active}}"><a href="{{ item.url }}">{% trans item.title %}</a></li>
{% if item.url %}
<li class="{{item.active}}"><a href="{{ item.url }}">{% trans item.title %}</a></li>
{% endif %}
{% endif %}
{% endfor %}
</ul>

1
sapl/templates/parlamentares/subnav.yaml

@ -7,6 +7,7 @@
url: filiacao_list
- title: {% trans 'Dependentes' %}
url: dependente_list
check_permission: parlamentares.list_dependente
- title: {% trans 'Comissões' %}
url: participacao_parlamentar_list
- title: {% trans 'Proposições' %}

73
sapl/templates/protocoloadm/documentoadministrativo_filter.html

@ -14,54 +14,35 @@
</div>
{% if filter_url %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'protocoloadm:pesq_doc_adm' %}" class="btn btn-default">{% trans 'Fazer Nova Pesquisa' %}</a>
<a href="{% url 'protocoloadm:pesq_doc_adm' %}" class="btn btn-default">{% trans 'Fazer Nova Pesquisa' %}</a>
</div>
{% endif %}
{% endblock actions %}
{% block detail_content %}
{% if not filter_url %}
{% crispy filter.form %}
{% endif %}
{% if filter_url %}
<p></p>
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr><td><h3>Resultados</h3></td></tr>
</thead>
{% if page_obj|length %}
{% if numero_res > 1 %}
<h3>Pesquisa concluída com sucesso! Foram encontrados {{numero_res}} documentos.</h3>
{% elif numero_res == 1 %}
<h3>Pesquisa concluída com sucesso! Foi encontrado {{numero_res}} documento.</h3>
{% endif %}
{% for d in page_obj %}
<tr>
<td>
<strong><a href="{% url 'protocoloadm:documentoadministrativo_detail' d.id %}">{{d.tipo.sigla}} {{d.numero}}/{{d.ano}} - {{d.tipo}}</strong></a></br>
<strong>Interessado:</strong>&nbsp;{{ d.interessado|default_if_none:"Não Informado"}}</br>
<strong>Assunto:</strong>&nbsp;{{ d.assunto|safe }}</br>
<p></p>
</tr>
{% endfor %}
{% else %}
<tr>
<td>
<h3>Nenhum documento encontrado com essas especificações</h3>
</tr>
{% block base_content %}
{% if not filter_url %} {% crispy filter.form %} {% endif %}
{% if filter_url %}
<table class="table table-striped table-bordered">
<thead class="thead-default"><tr><td><h3>Resultados</h3></td></tr></thead>
{% if page_obj|length %}
{% if numero_res > 1 %}
<h3>Pesquisa concluída com sucesso! Foram encontrados {{numero_res}} documentos.</h3>
{% elif numero_res == 1 %}
<h3>Pesquisa concluída com sucesso! Foi encontrado {{numero_res}} documento.</h3>
{% endif %}
</table>
{% include "paginacao.html" %}
{% endif %}
{% endblock detail_content %}
{% for d in page_obj %}
<tr>
<td>
<strong><a href="{% url 'protocoloadm:documentoadministrativo_detail' d.id %}">{{d.tipo.sigla}} {{d.numero}}/{{d.ano}} - {{d.tipo}}</strong></a></br>
<strong>Interessado:</strong>&nbsp;{{ d.interessado|default_if_none:"Não Informado"}}</br>
<strong>Assunto:</strong>&nbsp;{{ d.assunto|safe }}</br>
</td>
</tr>
{% endfor %}
{% else %}
<tr><td><h3>Nenhum documento encontrado com essas especificações</h3></tr>
{% endif %}
</table>
{% include "paginacao.html" %}
{% endif %}
{% endblock base_content %}

95
sapl/templates/protocoloadm/protocolo_filter.html

@ -5,76 +5,49 @@
{% block sections_nav %} {% endblock %}
{% block detail_content %}
{% block base_content %}
<h1><b>Pesquisa de Protocolo</b></h1>
<br></br>
{% if filter_url %}
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'protocoloadm:protocolo' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
<div class="actions btn-group pull-right" role="group">
<a href="{% url 'protocoloadm:protocolo' %}" class="btn btn-default">{% trans 'Fazer nova pesquisa' %}</a>
</div>
{% endif %}
{% if not filter_url %}
{% crispy filter.form %}
{% endif %}
{% if filter_url %}
<p></p>
<table class="table table-striped table-bordered">
<thead class="thead-default">
<tr><td><h3>Resultados</h3></td></tr>
</thead>
{% if page_obj|length %}
{% if filter_url %}
{% if numero_res > 1 %}
<h3>Pesquisa concluída com sucesso! Foram encontrados {{numero_res}} protocolos.</h3>
{% elif numero_res == 1 %}
<h3>Pesquisa concluída com sucesso! Foi encontrado {{numero_res}} protocolo.</h3>
{% endif %}
<table class="table table-striped table-bordered">
<thead class="thead-default"><tr><td><h3>Resultados</h3></td></tr></thead>
{% if page_obj|length %}
{% if filter_url %}
{% if numero_res > 1 %}
<h3>Pesquisa concluída com sucesso! Foram encontrados {{numero_res}} protocolos.</h3>
{% elif numero_res == 1 %}
<h3>Pesquisa concluída com sucesso! Foi encontrado {{numero_res}} protocolo.</h3>
{% endif %}
{% for p in page_obj %}
<tr>
<td>
<strong>Protocolo:
<a href="{% url 'protocoloadm:protocolo_mostrar' p.numero p.ano %}">
{{ p.numero|stringformat:'06d' }}/{{ p.ano }}
</a></strong>
&nbsp;&nbsp;<strong>-</strong>&nbsp;&nbsp;
<a href="{% url 'relatorios:relatorio_etiqueta_protocolo' p.numero p.ano %}">
<img src="{% static 'img/etiqueta.png' %}" alt="Etiqueta Individual">
</a></br>
<strong>Assunto:</strong> {{ p.assunto_ementa|default_if_none:"Não Informado"}}</br>
<strong>Data Protocolo:</strong> {{ p.data|date:"d/m/Y"|default_if_none:"Não Informado" }} - Horário: {{ p.hora|date:"G:i:s" }}</br>
<strong>Interessado:</strong> {{ p.interessado }}</br>
<strong>Natureza do Processo:</strong>
{% if p.tipo_processo == 0 %}
Administrativo
{% elif p.tipo_processo == 1 %}
Matéria Legislativa
{% endif %}</br>
<strong>Classificação:</strong> {{ p.tipo_documento|default_if_none:"Não Informado" }} </br>
<p></p>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td>
<h3>Nenhum protocolo encontrado com essas especificações</h3>
</tr>
{% endif %}
{% for p in page_obj %}
<tr>
<td>
<strong>Protocolo:
<a href="{% url 'protocoloadm:protocolo_mostrar' p.numero p.ano %}">{{ p.numero|stringformat:'06d' }}/{{ p.ano }}</a></strong>&nbsp;&nbsp;<strong>-</strong>&nbsp;&nbsp;
<a href="{% url 'relatorios:relatorio_etiqueta_protocolo' p.numero p.ano %}"><img src="{% static 'img/etiqueta.png' %}" alt="Etiqueta Individual"></a></br>
<strong>Assunto:</strong> {{ p.assunto_ementa|default_if_none:"Não Informado"}}</br>
<strong>Data Protocolo:</strong> {{ p.data|date:"d/m/Y"|default_if_none:"Não Informado" }} - Horário: {{ p.hora|date:"G:i:s" }}</br>
<strong>Interessado:</strong> {{ p.interessado }}</br>
<strong>Natureza do Processo:</strong>
{% if p.tipo_processo == 0 %} Administrativo {% elif p.tipo_processo == 1 %} Matéria Legislativa {% endif %}</br>
<strong>Classificação:</strong> {{ p.tipo_documento|default_if_none:"Não Informado" }} </br>
</td>
</tr>
{% endfor %}
{% else %}
<tr><td><h3>Nenhum protocolo encontrado com essas especificações</h3></tr>
{% endif %}
</table>
{% include "paginacao.html" %}
{% endif %}
{% endblock detail_content %}
{% include "paginacao.html" %}
{% endif %}
{% endblock base_content %}

1
sapl/templates/sessao/expedientemateria_form.html

@ -6,6 +6,7 @@
{% block extra_js %}
<script language="Javascript">
document.getElementById("id_observacao").readOnly = true;
function recuperar_materia() {
var tipo_materia = $("#id_tipo_materia").val()

6
sapl/templates/sessao/layouts.yaml

@ -28,11 +28,13 @@ RegistroVotacao:
Orador:
{% trans 'Orador das Explicações Pessoais' %}:
- numero_ordem parlamentar url_discurso
- numero_ordem parlamentar
- url_discurso observacao
OradorExpediente:
{% trans 'Orador do Expediente' %}:
- numero_ordem parlamentar url_discurso
- numero_ordem parlamentar
- url_discurso observacao
ExpedienteMateria:
{% trans 'Matéria do Expediente' %}:

8
sapl/templates/sessao/painel.html

@ -2,6 +2,14 @@
{% load i18n %}
{% load staticfiles %}
{% block actions %} {% endblock %}
{% block title %}
<h1 class="page-header">
Painel Eletrônico <small>({{sessaoplenaria}})</small>
</h1>
{% endblock %}
{% block detail_content %}
<audio type="hidden" id="audio" src="{% static 'audio/ring.mp3' %}"> </audio>

63
sapl/templates/sessao/pauta_sessao_filter.html

@ -5,45 +5,36 @@
{% block sections_nav %} {% endblock %}
{% block detail_content %}
{% block base_content %}
<h1><b>Pesquisar Pauta de Sessão</b></h1>
<br></br>
{% crispy filter.form %}
<p></p>
<table class="table table-striped table-hover">
<thead class="thead-default">
<tr><td><h3>Resultados</h3></td></tr>
</thead>
{% if page_obj|length %}
{% if numero_res > 1 %}
<h3>Foram encontradas {{numero_res}} pautas de sessões.</h3></br>
{% elif numero_res == 1 %}
<h3>Foi encontrada {{numero_res}} pauta de sessão.</h3></br>
{% endif %}
{% for s in page_obj %}
<tr>
<td>
<a href="{% url 'sapl.sessao:pauta_sessao_detail' s.id %}"><strong>{{s}}</strong></br></a>
</td>
<td>
<a href="{% url 'sapl.relatorios:relatorio_sessao_plenaria' s.id %}">
<img src="{% static 'img/file.png' %}">
</a>
</td>
</tr>
{% endfor %}
{% else %}
<tr>
<td>
<h3>Nenhuma Pauta de Sessão encontrada com essas especificações</h3>
</tr>
{% if not filter_url %}
{% crispy filter.form %}
{% endif %}
{% if filter_url %}
<p></p>
<table class="table table-striped table-hover">
<thead class="thead-default"><tr><td><h3>Resultados</h3></td></tr></thead>
{% if page_obj|length %}
{% if numero_res > 1 %}
<h3>Foram encontradas {{numero_res}} pautas de sessões.</h3></br>
{% elif numero_res == 1 %}
<h3>Foi encontrada {{numero_res}} pauta de sessão.</h3></br>
{% endif %}
{% for s in page_obj %}
<tr>
<td><a href="{% url 'sapl.sessao:pauta_sessao_detail' s.id %}"><strong>{{s}}</strong></br></a></td><td>
<a href="{% url 'sapl.relatorios:relatorio_sessao_plenaria' s.id %}"><img src="{% static 'img/file.png' %}"></a>
</td>
</tr>
{% endfor %}
{% else %}
<tr><td><h3>Nenhuma Pauta de Sessão encontrada com essas especificações</h3></tr>
{% endif %}
</table>
{% include "paginacao.html" %}
{% endblock detail_content %}
{% include "paginacao.html" %}
{% endif %}
{% endblock base_content %}

6
sapl/templates/sessao/resumo.html

@ -2,6 +2,12 @@
{% load i18n %}
{% load crispy_forms_tags %}
{% block title %}
<h1 class="page-header">
Resumo <small>({{sessaoplenaria}})</small>
</h1>
{% endblock %}
{% block detail_content %}
<fieldset>
<legend>Identificação Básica</legend>

13
sapl/templates/sessao/sessaoplenaria_filter.html

@ -18,17 +18,18 @@
{% block sections_nav %} {% endblock %}
{% block detail_content %}
{% block base_content %}
<h1><b>Pesquisar Sessão Plenária</b></h1>
<br></br>
{% crispy filter.form %}
{% if not filter_url %}
{% crispy filter.form %}
{% endif %}
{% if filter_url %}
<p></p>
<table class="table table-striped table-hover">
<thead class="thead-default">
<tr><td><h3>Resultados</h3></td></tr>
</thead>
<thead class="thead-default"><tr><td><h3>Resultados</h3></td></tr></thead>
{% if page_obj|length %}
{% if numero_res > 1 %}
<h3>Foram encontradas {{numero_res}} sessões.</h3></br>
@ -53,4 +54,4 @@
</table>
{% include "paginacao.html" %}
{% endif %}
{% endblock detail_content %}
{% endblock base_content %}

5
sapl/templates/sessao/subnav.yaml

@ -1,4 +1,5 @@
{% load i18n %}
{% load i18n common_tags %}
- title: {% trans 'Abertura' %}
children:
- title: {% trans 'Dados Básicos' %}
@ -28,6 +29,6 @@
- title: {% trans 'Painel Eletrônico' %}
url: painel
{% if not 'painel_aberto'|get_config_attr %}check_permission: painel.list_painel{%endif%}
- title: {% trans 'Resumo' %}
url: resumo

22
sapl/utils.py

@ -8,9 +8,10 @@ from django import forms
from django.apps import apps
from django.conf import settings
from django.contrib import admin
from django.contrib.auth.decorators import user_passes_test
from django.contrib.auth.models import Permission
from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.core.exceptions import PermissionDenied, ValidationError
from django.utils.translation import ugettext_lazy as _
from floppyforms import ClearableFileInput
@ -279,6 +280,25 @@ def permissoes(nome_grupo, app_label):
return set(lista_permissoes)
def permission_required_for_app(app_label, login_url=None,
raise_exception=False):
"""
Decorator for views that checks whether a user has a particular permission
enabled, redirecting to the log-in page if necessary.
If the raise_exception parameter is given the PermissionDenied exception
is raised.
"""
def check_perms(user):
if user.has_module_perms(app_label):
return True
# In case the 403 handler should be called raise the exception
if raise_exception:
raise PermissionDenied
# As the last resort, show the login form
return False
return user_passes_test(check_perms, login_url=login_url)
def permissoes_materia():
return permissoes('Operador de Matéria', 'materia')

2
scripts/inicializa_grupos_autorizacoes.py

@ -1,6 +1,6 @@
import os
import django
import django
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "sapl.settings")
django.setup()

74
scripts/test_inicializa_grupos_autorizacoes.py

@ -1,29 +1,94 @@
import pytest
from django.apps import apps
from django.contrib.auth.management import _get_all_permissions
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
import pytest
from django.utils.encoding import force_text
from django.utils.translation import ugettext_lazy as _
from django.utils.translation import string_concat
from inicializa_grupos_autorizacoes import cria_grupos_permissoes
pytestmark = pytest.mark.django_db
apps_com_permissao_padrao = [
'comissoes', 'norma', 'sessao', 'painel']
def create_perms_post_migrate(app):
searched_perms = list()
# The codenames and ctypes that should exist.
ctypes = set()
for klass in list(app.get_models()):
opts = klass._meta
permissions = (
("list_" + opts.model_name,
string_concat(
_('Visualizaçao da lista de'), ' ',
opts.verbose_name_plural)),
("detail_" + opts.model_name,
string_concat(
_('Visualização dos detalhes de'), ' ',
opts.verbose_name_plural)),
)
opts.permissions = tuple(
set(list(permissions) + list(opts.permissions)))
if opts.proxy:
# Force looking up the content types in the current database
# before creating foreign keys to them.
app_label, model = opts.app_label, opts.model_name
try:
ctype = ContentType.objects.get_by_natural_key(
app_label, model)
except:
ctype = ContentType.objects.create(
app_label=app_label, model=model)
else:
ctype = ContentType.objects.get_for_model(klass)
ctypes.add(ctype)
for perm in _get_all_permissions(klass._meta, ctype):
searched_perms.append((ctype, perm))
all_perms = set(Permission.objects.filter(
content_type__in=ctypes,
).values_list(
"content_type", "codename"
))
perms = [
Permission(codename=codename, name=name, content_type=ct)
for ct, (codename, name) in searched_perms
if (ct.pk, codename) not in all_perms
]
Permission.objects.bulk_create(perms)
@pytest.mark.parametrize('app_label', apps_com_permissao_padrao)
def test_grupo_padrao_tem_permissoes_sobre_todo_o_app(app_label):
app = apps.get_app_config(app_label)
create_perms_post_migrate(app)
# código testado
cria_grupos_permissoes()
def gerar_permissoes(app):
for model in app.get_models():
for op in ['add', 'change', 'delete']:
for op in ['add', 'change', 'delete', ]:
yield model, 'Can %s %s' % (op, model._meta.verbose_name)
yield model, force_text(string_concat(
_('Visualizaçao da lista de'), ' ',
model._meta.verbose_name_plural))
yield model, force_text(string_concat(
_('Visualização dos detalhes de'),
' ',
model._meta.verbose_name_plural))
grupo = Group.objects.get(name='Operador de %s' % app.verbose_name)
esperado = set(gerar_permissoes(app))
@ -36,6 +101,9 @@ def test_grupo_padrao_tem_permissoes_sobre_todo_o_app(app_label):
def test_permissoes_extras_sao_apagadas(app_label):
app = apps.get_app_config(app_label)
# create_perms_post_migrate(app)
grupo = Group.objects.create(name='Operador de %s' % app.verbose_name)
permissao_errada = Permission.objects.create(

Loading…
Cancel
Save