Browse Source

Merge bdcddb546f into 2938835502

pull/2214/merge
Leandro Roberto da Silva 7 years ago
committed by GitHub
parent
commit
51d236798c
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 0
      sapl/api/base/__init__.py
  2. 147
      sapl/api/base/forms.py
  3. 23
      sapl/api/base/serializers.py
  4. 15
      sapl/api/base/urls.py
  5. 223
      sapl/api/base/views.py
  6. 145
      sapl/api/forms.py
  7. 0
      sapl/api/materia/__init__.py
  8. 0
      sapl/api/materia/forms.py
  9. 19
      sapl/api/materia/serializers.py
  10. 13
      sapl/api/materia/urls.py
  11. 9
      sapl/api/materia/views.py
  12. 147
      sapl/api/serializers.py
  13. 0
      sapl/api/sessao/__init__.py
  14. 0
      sapl/api/sessao/forms.py
  15. 138
      sapl/api/sessao/serializers.py
  16. 15
      sapl/api/sessao/urls.py
  17. 23
      sapl/api/sessao/views.py
  18. 27
      sapl/api/urls.py
  19. 254
      sapl/api/views.py
  20. 9
      sapl/crud/base.py
  21. 10
      sapl/rules/apps.py
  22. 12
      sapl/sessao/forms.py
  23. 37
      sapl/sessao/migrations/0023_auto_20180914_1315.py
  24. 8
      sapl/sessao/models.py
  25. 16
      sapl/sessao/serializers.py
  26. 56
      sapl/sessao/views.py
  27. 2
      sapl/templates/base/relatorios_list.html
  28. 19
      sapl/templates/sessao/expedientemateria_form.html
  29. 2
      sapl/templates/sessao/layouts.yaml

0
sapl/api/base/__init__.py

147
sapl/api/base/forms.py

@ -0,0 +1,147 @@
from django.db.models import Q
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from django_filters.filters import DateFilter, MethodFilter, ModelChoiceFilter
from rest_framework import serializers
from rest_framework.filters import FilterSet
from sapl.api.forms import SaplGenericRelationSearchFilterSet,\
SearchForFieldFilter
from sapl.base.models import Autor, TipoAutor
from sapl.parlamentares.models import Legislatura
class AutorChoiceFilterSet(SaplGenericRelationSearchFilterSet):
q = MethodFilter()
tipo = ModelChoiceFilter(queryset=TipoAutor.objects.all())
class Meta:
model = Autor
fields = ['q',
'tipo',
'nome', ]
def filter_q(self, queryset, value):
return SaplGenericRelationSearchFilterSet.filter_q(
self, queryset, value).distinct('nome').order_by('nome')
class AutorSearchForFieldFilterSet(AutorChoiceFilterSet):
q = SearchForFieldFilter()
class Meta(AutorChoiceFilterSet.Meta):
pass
def filter_q(self, queryset, value):
value[0] = value[0].split(',')
value[1] = value[1].split(',')
params = {}
for key, v in list(zip(value[0], value[1])):
if v in ['True', 'False']:
v = '1' if v == 'True' else '0'
params[key] = v
return queryset.filter(**params).distinct('nome').order_by('nome')
class AutoresPossiveisFilterSet(FilterSet):
data_relativa = DateFilter(method='filter_data_relativa')
tipo = MethodFilter(required=True)
class Meta:
model = Autor
fields = ['data_relativa', 'tipo', ]
def filter_data_relativa(self, queryset, name, value):
return queryset
def filter_tipo(self, queryset, value):
try:
tipo = TipoAutor.objects.get(pk=value)
except:
raise serializers.ValidationError(_('Tipo de Autor inexistente.'))
qs = queryset.filter(tipo=tipo)
return qs
@property
def qs(self):
qs = super().qs
data_relativa = self.form.cleaned_data['data_relativa'] \
if 'data_relativa' in self.form.cleaned_data else None
tipo = self.form.cleaned_data['tipo'] \
if 'tipo' in self.form.cleaned_data else None
if not tipo:
return qs
else:
tipo = TipoAutor.objects.get(pk=tipo)
if not tipo.content_type:
return qs
filter_for_model = 'filter_%s' % tipo.content_type.model
if not hasattr(self, filter_for_model):
return qs
if not data_relativa:
data_relativa = timezone.now()
return getattr(self, filter_for_model)(qs, data_relativa).distinct()
def filter_parlamentar(self, queryset, data_relativa):
# não leva em conta afastamentos
legislatura_relativa = Legislatura.objects.filter(
data_inicio__lte=data_relativa,
data_fim__gte=data_relativa).first()
q = Q(
parlamentar_set__mandato__data_inicio_mandato__lte=data_relativa,
parlamentar_set__mandato__data_fim_mandato__isnull=True) | Q(
parlamentar_set__mandato__data_inicio_mandato__lte=data_relativa,
parlamentar_set__mandato__data_fim_mandato__gte=data_relativa)
if legislatura_relativa.atual():
q = q & Q(parlamentar_set__ativo=True)
return queryset.filter(q)
def filter_comissao(self, queryset, data_relativa):
return queryset.filter(
Q(comissao_set__data_extincao__isnull=True,
comissao_set__data_fim_comissao__isnull=True) |
Q(comissao_set__data_extincao__gte=data_relativa,
comissao_set__data_fim_comissao__isnull=True) |
Q(comissao_set__data_extincao__gte=data_relativa,
comissao_set__data_fim_comissao__isnull=True) |
Q(comissao_set__data_extincao__isnull=True,
comissao_set__data_fim_comissao__gte=data_relativa) |
Q(comissao_set__data_extincao__gte=data_relativa,
comissao_set__data_fim_comissao__gte=data_relativa),
comissao_set__data_criacao__lte=data_relativa)
def filter_frente(self, queryset, data_relativa):
return queryset.filter(
Q(frente_set__data_extincao__isnull=True) |
Q(frente_set__data_extincao__gte=data_relativa),
frente_set__data_criacao__lte=data_relativa)
def filter_bancada(self, queryset, data_relativa):
return queryset.filter(
Q(bancada_set__data_extincao__isnull=True) |
Q(bancada_set__data_extincao__gte=data_relativa),
bancada_set__data_criacao__lte=data_relativa)
def filter_bloco(self, queryset, data_relativa):
return queryset.filter(
Q(bloco_set__data_extincao__isnull=True) |
Q(bloco_set__data_extincao__gte=data_relativa),
bloco_set__data_criacao__lte=data_relativa)
def filter_orgao(self, queryset, data_relativa):
# na implementação, não havia regras a implementar para orgao
return queryset

23
sapl/api/base/serializers.py

@ -0,0 +1,23 @@
from rest_framework import serializers
from sapl.api.serializers import ModelChoiceSerializer,\
ModelChoiceObjectRelatedField
from sapl.base.models import Autor
class AutorChoiceSerializer(ModelChoiceSerializer):
def get_text(self, obj):
return obj.nome
class Meta:
model = Autor
fields = ['id', 'nome']
class AutorSerializer(serializers.ModelSerializer):
autor_related = ModelChoiceObjectRelatedField(read_only=True)
class Meta:
model = Autor
fields = '__all__'

15
sapl/api/base/urls.py

@ -0,0 +1,15 @@
from django.conf.urls import url
from sapl.api.base.views import AutorListView, AutoresPossiveisListView,\
AutoresProvaveisListView
# Não adicione app_name
# app_name = AppConfig.name
urlpatterns = [
url(r'^autor/$', AutorListView.as_view(), name='autor_list'),
url(r'^autor/provaveis',
AutoresProvaveisListView.as_view(), name='autores_provaveis_list'),
url(r'^autor/possiveis',
AutoresPossiveisListView.as_view(), name='autores_possiveis_list'),
]

223
sapl/api/base/views.py

@ -0,0 +1,223 @@
from django.db.models import Q
from django.http import Http404
from django.utils.translation import ugettext_lazy as _
from rest_framework.filters import DjangoFilterBackend
from rest_framework.generics import ListAPIView
from rest_framework.permissions import (IsAuthenticated,
IsAuthenticatedOrReadOnly)
from sapl.api.base.forms import AutoresPossiveisFilterSet,\
AutorSearchForFieldFilterSet, AutorChoiceFilterSet
from sapl.api.base.serializers import AutorChoiceSerializer, AutorSerializer
from sapl.api.serializers import (ChoiceSerializer)
from sapl.base.models import Autor, TipoAutor
from sapl.utils import SaplGenericRelation, sapl_logger
class AutorListView(ListAPIView):
"""
Listagem de Autores com filtro para autores cadastrados
e/ou possíveis autores.
- tr - tipo do resultado
Prepera Lista de Autores para 3 cenários distintos
- default = 1
= 1 -> para (value, text) usados geralmente
em combobox, radiobox, checkbox, etc com pesquisa básica
de Autores feita pelo django-filter
-> processo usado nas pesquisas, o mais usado.
= 3 -> Devolve instancias da classe Autor filtradas pelo
django-filter
- tipo - chave primária do Tipo de Autor a ser filtrado
- q - busca textual no nome do Autor ou em fields_search
declarados no field SaplGenericRelation das GenericFks
A busca textual acontece via django-filter com a
variável `tr` igual 1 ou 3. Em caso contrário,
o django-filter é desativado e a busca é feita
no model do ContentType associado ao tipo.
- q_0 / q_1 - q_0 é opcional e quando usado, faz o código ignorar "q"...
q_0 -> campos lookup a serem filtrados em qualquer Model
que implemente SaplGenericRelation
q_1 -> o valor que será pesquisado no lookup de q_0
q_0 e q_1 podem ser separados por ","... isso dará a
possibilidade de filtrar mais de um campo.
http://localhost:8000
/api/autor?tr=1&q_0=parlamentar_set__ativo&q_1=False
/api/autor?tr=1&q_0=parlamentar_set__ativo&q_1=True
/api/autor?tr=3&q_0=parlamentar_set__ativo&q_1=False
/api/autor?tr=3&q_0=parlamentar_set__ativo&q_1=True
http://localhost:8000
/api/autor?tr=1
&q_0=parlamentar_set__nome_parlamentar__icontains,
parlamentar_set__ativo
&q_1=Carvalho,False
/api/autor?tr=1
&q_0=parlamentar_set__nome_parlamentar__icontains,
parlamentar_set__ativo
&q_1=Carvalho,True
/api/autor?tr=3
&q_0=parlamentar_set__nome_parlamentar__icontains,
parlamentar_set__ativo
&q_1=Carvalho,False
/api/autor?tr=3
&q_0=parlamentar_set__nome_parlamentar__icontains,
parlamentar_set__ativo
&q_1=Carvalho,True
não importa o campo que vc passe de qualquer dos Models
ligados... é possível ver que models são esses,
na ocasião do commit deste texto, executando:
In [6]: from sapl.utils import models_with_gr_for_model
In [7]: models_with_gr_for_model(Autor)
Out[7]:
[sapl.parlamentares.models.Parlamentar,
sapl.parlamentares.models.Frente,
sapl.comissoes.models.Comissao,
sapl.materia.models.Orgao,
sapl.sessao.models.Bancada,
sapl.sessao.models.Bloco]
qualquer atributo destes models podem ser passados
para busca
"""
TR_AUTOR_CHOICE_SERIALIZER = 1
TR_AUTOR_SERIALIZER = 3
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all()
model = Autor
filter_class = AutorChoiceFilterSet
filter_backends = (DjangoFilterBackend, )
serializer_class = AutorChoiceSerializer
@property
def tr(self):
try:
tr = int(self.request.GET.get
('tr', AutorListView.TR_AUTOR_CHOICE_SERIALIZER))
assert tr in (
AutorListView.TR_AUTOR_CHOICE_SERIALIZER,
AutorListView.TR_AUTOR_SERIALIZER), sapl_logger.info(
_("Tipo do Resultado a ser fornecido não existe!"))
except:
return AutorListView.TR_AUTOR_CHOICE_SERIALIZER
else:
return tr
def get(self, request, *args, **kwargs):
if self.tr == AutorListView.TR_AUTOR_SERIALIZER:
self.serializer_class = AutorSerializer
self.permission_classes = (IsAuthenticated,)
if self.filter_class and 'q_0' in request.GET:
self.filter_class = AutorSearchForFieldFilterSet
return ListAPIView.get(self, request, *args, **kwargs)
class AutoresProvaveisListView(ListAPIView):
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all()
model = Autor
filter_class = None
filter_backends = []
serializer_class = ChoiceSerializer
def get_queryset(self):
params = {'content_type__isnull': False}
tipo = ''
try:
tipo = int(self.request.GET.get('tipo', ''))
if tipo:
params['id'] = tipo
except:
pass
tipos = TipoAutor.objects.filter(**params)
if not tipos.exists() and tipo:
raise Http404()
r = []
for tipo in tipos:
q = self.request.GET.get('q', '').strip()
model_class = tipo.content_type.model_class()
fields = list(filter(
lambda field: isinstance(field, SaplGenericRelation) and
field.related_model == Autor,
model_class._meta.get_fields(include_hidden=True)))
"""
fields - é um array de SaplGenericRelation que deve possuir o
atributo fields_search. Verifique na documentação da classe
a estrutura de fields_search.
"""
assert len(fields) >= 1, (_(
'Não foi encontrado em %(model)s um atributo do tipo '
'SaplGenericRelation que use o model %(model_autor)s') % {
'model': model_class._meta.verbose_name,
'model_autor': Autor._meta.verbose_name})
qs = model_class.objects.all()
q_filter = Q()
if q:
for item in fields:
if item.related_model != Autor:
continue
q_fs = Q()
for field in item.fields_search:
q_fs = q_fs | Q(**{'%s%s' % (
field[0],
field[1]): q})
q_filter = q_filter & q_fs
qs = qs.filter(q_filter).distinct(
fields[0].fields_search[0][0]).order_by(
fields[0].fields_search[0][0])
else:
qs = qs.order_by(fields[0].fields_search[0][0])
qs = qs.values_list(
'id', fields[0].fields_search[0][0])
r += list(qs)
if tipos.count() > 1:
r.sort(key=lambda x: x[1].upper())
return r
class AutoresPossiveisListView(ListAPIView):
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all()
model = Autor
pagination_class = None
filter_class = AutoresPossiveisFilterSet
serializer_class = AutorChoiceSerializer

145
sapl/api/forms.py

@ -1,15 +1,10 @@
from django.db.models import Q from django.db.models import Q
from django.forms.fields import CharField, MultiValueField from django.forms.fields import CharField, MultiValueField
from django.forms.widgets import MultiWidget, TextInput from django.forms.widgets import MultiWidget, TextInput
from django.utils import timezone from django_filters.filters import MethodFilter
from django.utils.translation import ugettext_lazy as _
from django_filters.filters import DateFilter, MethodFilter, ModelChoiceFilter
from rest_framework import serializers
from rest_framework.compat import django_filters from rest_framework.compat import django_filters
from rest_framework.filters import FilterSet from rest_framework.filters import FilterSet
from sapl.base.models import Autor, TipoAutor
from sapl.parlamentares.models import Legislatura
from sapl.utils import generic_relations_for_model from sapl.utils import generic_relations_for_model
@ -87,141 +82,3 @@ class SearchForFieldField(MultiValueField):
class SearchForFieldFilter(django_filters.filters.MethodFilter): class SearchForFieldFilter(django_filters.filters.MethodFilter):
field_class = SearchForFieldField field_class = SearchForFieldField
class AutorChoiceFilterSet(SaplGenericRelationSearchFilterSet):
q = MethodFilter()
tipo = ModelChoiceFilter(queryset=TipoAutor.objects.all())
class Meta:
model = Autor
fields = ['q',
'tipo',
'nome', ]
def filter_q(self, queryset, value):
return SaplGenericRelationSearchFilterSet.filter_q(
self, queryset, value).distinct('nome').order_by('nome')
class AutorSearchForFieldFilterSet(AutorChoiceFilterSet):
q = SearchForFieldFilter()
class Meta(AutorChoiceFilterSet.Meta):
pass
def filter_q(self, queryset, value):
value[0] = value[0].split(',')
value[1] = value[1].split(',')
params = {}
for key, v in list(zip(value[0], value[1])):
if v in ['True', 'False']:
v = '1' if v == 'True' else '0'
params[key] = v
return queryset.filter(**params).distinct('nome').order_by('nome')
class AutoresPossiveisFilterSet(FilterSet):
data_relativa = DateFilter(method='filter_data_relativa')
tipo = MethodFilter()
class Meta:
model = Autor
fields = ['data_relativa', 'tipo', ]
def filter_data_relativa(self, queryset, name, value):
return queryset
def filter_tipo(self, queryset, value):
try:
tipo = TipoAutor.objects.get(pk=value)
except:
raise serializers.ValidationError(_('Tipo de Autor inexistente.'))
qs = queryset.filter(tipo=tipo)
return qs
@property
def qs(self):
qs = super().qs
data_relativa = self.form.cleaned_data['data_relativa'] \
if 'data_relativa' in self.form.cleaned_data else None
tipo = self.form.cleaned_data['tipo'] \
if 'tipo' in self.form.cleaned_data else None
if not tipo and not data_relativa:
return qs
if tipo:
# não precisa de try except, já foi validado em filter_tipo
tipo = TipoAutor.objects.get(pk=tipo)
if not tipo.content_type:
return qs
filter_for_model = 'filter_%s' % tipo.content_type.model
if not hasattr(self, filter_for_model):
return qs
if not data_relativa:
data_relativa = timezone.now()
return getattr(self, filter_for_model)(qs, data_relativa).distinct()
def filter_parlamentar(self, queryset, data_relativa):
# não leva em conta afastamentos
legislatura_relativa = Legislatura.objects.filter(
data_inicio__lte=data_relativa,
data_fim__gte=data_relativa).first()
q = Q(
parlamentar_set__mandato__data_inicio_mandato__lte=data_relativa,
parlamentar_set__mandato__data_fim_mandato__isnull=True) | Q(
parlamentar_set__mandato__data_inicio_mandato__lte=data_relativa,
parlamentar_set__mandato__data_fim_mandato__gte=data_relativa)
if legislatura_relativa.atual():
q = q & Q(parlamentar_set__ativo=True)
return queryset.filter(q)
def filter_comissao(self, queryset, data_relativa):
return queryset.filter(
Q(comissao_set__data_extincao__isnull=True,
comissao_set__data_fim_comissao__isnull=True) |
Q(comissao_set__data_extincao__gte=data_relativa,
comissao_set__data_fim_comissao__isnull=True) |
Q(comissao_set__data_extincao__gte=data_relativa,
comissao_set__data_fim_comissao__isnull=True) |
Q(comissao_set__data_extincao__isnull=True,
comissao_set__data_fim_comissao__gte=data_relativa) |
Q(comissao_set__data_extincao__gte=data_relativa,
comissao_set__data_fim_comissao__gte=data_relativa),
comissao_set__data_criacao__lte=data_relativa)
def filter_frente(self, queryset, data_relativa):
return queryset.filter(
Q(frente_set__data_extincao__isnull=True) |
Q(frente_set__data_extincao__gte=data_relativa),
frente_set__data_criacao__lte=data_relativa)
def filter_bancada(self, queryset, data_relativa):
return queryset.filter(
Q(bancada_set__data_extincao__isnull=True) |
Q(bancada_set__data_extincao__gte=data_relativa),
bancada_set__data_criacao__lte=data_relativa)
def filter_bloco(self, queryset, data_relativa):
return queryset.filter(
Q(bloco_set__data_extincao__isnull=True) |
Q(bloco_set__data_extincao__gte=data_relativa),
bloco_set__data_criacao__lte=data_relativa)
def filter_orgao(self, queryset, data_relativa):
# na implementação, não havia regras a implementar para orgao
return queryset

0
sapl/api/materia/__init__.py

0
sapl/api/materia/forms.py

19
sapl/api/materia/serializers.py

@ -0,0 +1,19 @@
from rest_framework.filters import DjangoFilterBackend
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin
from rest_framework.permissions import IsAuthenticated
from rest_framework.viewsets import GenericViewSet
from sapl.api.materia.views import MateriaLegislativaSerializer
from sapl.materia.models import MateriaLegislativa
class MateriaLegislativaViewSet(ListModelMixin,
RetrieveModelMixin,
GenericViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = MateriaLegislativaSerializer
queryset = MateriaLegislativa.objects.all()
filter_backends = (DjangoFilterBackend,)
filter_fields = ('numero', 'ano', 'tipo', )

13
sapl/api/materia/urls.py

@ -0,0 +1,13 @@
from rest_framework.routers import DefaultRouter
from sapl.api.materia.serializers import MateriaLegislativaViewSet
# Não adicione app_name
# app_name = AppConfig.name
router = DefaultRouter()
router.register(r'materia', MateriaLegislativaViewSet)
urlpatterns = [
]

9
sapl/api/materia/views.py

@ -0,0 +1,9 @@
from rest_framework import serializers
from sapl.materia.models import MateriaLegislativa
class MateriaLegislativaSerializer(serializers.ModelSerializer):
class Meta:
model = MateriaLegislativa
fields = '__all__'

147
sapl/api/serializers.py

@ -1,9 +1,5 @@
from rest_framework import serializers from rest_framework import serializers
from sapl.base.models import Autor, CasaLegislativa
from sapl.materia.models import MateriaLegislativa
from sapl.sessao.models import OrdemDia, SessaoPlenaria
class ChoiceSerializer(serializers.Serializer): class ChoiceSerializer(serializers.Serializer):
value = serializers.SerializerMethodField() value = serializers.SerializerMethodField()
@ -29,146 +25,3 @@ class ModelChoiceObjectRelatedField(serializers.RelatedField):
def to_representation(self, value): def to_representation(self, value):
return ModelChoiceSerializer(value).data return ModelChoiceSerializer(value).data
class AutorChoiceSerializer(ModelChoiceSerializer):
def get_text(self, obj):
return obj.nome
class Meta:
model = Autor
fields = ['id', 'nome']
class AutorSerializer(serializers.ModelSerializer):
autor_related = ModelChoiceObjectRelatedField(read_only=True)
class Meta:
model = Autor
fields = '__all__'
class MateriaLegislativaSerializer(serializers.ModelSerializer):
class Meta:
model = MateriaLegislativa
fields = '__all__'
class SessaoPlenariaSerializer(serializers.ModelSerializer):
codReuniao = serializers.SerializerMethodField('get_pk_sessao')
codReuniaoPrincipal = serializers.SerializerMethodField('get_pk_sessao')
txtTituloReuniao = serializers.SerializerMethodField('get_name')
txtSiglaOrgao = serializers.SerializerMethodField('get_sigla_orgao')
txtApelido = serializers.SerializerMethodField('get_name')
txtNomeOrgao = serializers.SerializerMethodField('get_nome_orgao')
codEstadoReuniao = serializers.SerializerMethodField(
'get_estadoSessaoPlenaria')
txtTipoReuniao = serializers.SerializerMethodField('get_tipo_sessao')
txtObjeto = serializers.SerializerMethodField('get_assunto_sessao')
txtLocal = serializers.SerializerMethodField('get_endereco_orgao')
bolReuniaoConjunta = serializers.SerializerMethodField(
'get_reuniao_conjunta')
bolHabilitarEventoInterativo = serializers.SerializerMethodField(
'get_iterativo')
idYoutube = serializers.SerializerMethodField('get_url')
codEstadoTransmissaoYoutube = serializers.SerializerMethodField(
'get_estadoTransmissaoYoutube')
datReuniaoString = serializers.SerializerMethodField('get_date')
# Constantes SessaoPlenaria (de 1-9) (apenas 3 serão usados)
SESSAO_FINALIZADA = 4
SESSAO_EM_ANDAMENTO = 3
SESSAO_CONVOCADA = 2
# Constantes EstadoTranmissaoYoutube (de 0 a 2)
TRANSMISSAO_ENCERRADA = 2
TRANSMISSAO_EM_ANDAMENTO = 1
SEM_TRANSMISSAO = 0
class Meta:
model = SessaoPlenaria
fields = (
'codReuniao',
'codReuniaoPrincipal',
'txtTituloReuniao',
'txtSiglaOrgao',
'txtApelido',
'txtNomeOrgao',
'codEstadoReuniao',
'txtTipoReuniao',
'txtObjeto',
'txtLocal',
'bolReuniaoConjunta',
'bolHabilitarEventoInterativo',
'idYoutube',
'codEstadoTransmissaoYoutube',
'datReuniaoString'
)
def __init__(self, *args, **kwargs):
super(SessaoPlenariaSerializer, self).__init__(args, kwargs)
def get_pk_sessao(self, obj):
return obj.pk
def get_name(self, obj):
return obj.__str__()
def get_estadoSessaoPlenaria(self, obj):
if obj.finalizada:
return self.SESSAO_FINALIZADA
elif obj.iniciada:
return self.SESSAO_EM_ANDAMENTO
else:
return self.SESSAO_CONVOCADA
def get_tipo_sessao(self, obj):
return obj.tipo.__str__()
def get_url(self, obj):
return obj.url_video if obj.url_video else None
def get_iterativo(self, obj):
return obj.interativa if obj.interativa else False
def get_date(self, obj):
return "{} {}{}".format(
obj.data_inicio.strftime("%d/%m/%Y"),
obj.hora_inicio,
":00"
)
def get_estadoTransmissaoYoutube(self, obj):
if obj.url_video:
if obj.finalizada:
return self.TRANSMISSAO_ENCERRADA
else:
return self.TRANSMISSAO_EM_ANDAMENTO
else:
return self.SEM_TRANSMISSAO
def get_assunto_sessao(self, obj):
pauta_sessao = ''
ordem_dia = OrdemDia.objects.filter(sessao_plenaria=obj.pk)
pauta_sessao = ', '.join([i.materia.__str__() for i in ordem_dia])
return str(pauta_sessao)
def get_endereco_orgao(self, obj):
return self.casa().endereco
def get_reuniao_conjunta(self, obj):
return False
def get_sigla_orgao(self, obj):
return self.casa().sigla
def get_nome_orgao(self, obj):
return self.casa().nome
def casa(self):
casa = CasaLegislativa.objects.first()
return casa

0
sapl/api/sessao/__init__.py

0
sapl/api/sessao/forms.py

138
sapl/api/sessao/serializers.py

@ -0,0 +1,138 @@
from rest_framework import serializers
from sapl.base.models import CasaLegislativa
from sapl.sessao.models import SessaoPlenaria, OrdemDia
class SessaoPlenariaOldSerializer(serializers.ModelSerializer):
codReuniao = serializers.SerializerMethodField('get_pk_sessao')
codReuniaoPrincipal = serializers.SerializerMethodField('get_pk_sessao')
txtTituloReuniao = serializers.SerializerMethodField('get_name')
txtSiglaOrgao = serializers.SerializerMethodField('get_sigla_orgao')
txtApelido = serializers.SerializerMethodField('get_name')
txtNomeOrgao = serializers.SerializerMethodField('get_nome_orgao')
codEstadoReuniao = serializers.SerializerMethodField(
'get_estadoSessaoPlenaria')
txtTipoReuniao = serializers.SerializerMethodField('get_tipo_sessao')
txtObjeto = serializers.SerializerMethodField('get_assunto_sessao')
txtLocal = serializers.SerializerMethodField('get_endereco_orgao')
bolReuniaoConjunta = serializers.SerializerMethodField(
'get_reuniao_conjunta')
bolHabilitarEventoInterativo = serializers.SerializerMethodField(
'get_iterativo')
idYoutube = serializers.SerializerMethodField('get_url')
codEstadoTransmissaoYoutube = serializers.SerializerMethodField(
'get_estadoTransmissaoYoutube')
datReuniaoString = serializers.SerializerMethodField('get_date')
# Constantes SessaoPlenaria (de 1-9) (apenas 3 serão usados)
SESSAO_FINALIZADA = 4
SESSAO_EM_ANDAMENTO = 3
SESSAO_CONVOCADA = 2
# Constantes EstadoTranmissaoYoutube (de 0 a 2)
TRANSMISSAO_ENCERRADA = 2
TRANSMISSAO_EM_ANDAMENTO = 1
SEM_TRANSMISSAO = 0
class Meta:
model = SessaoPlenaria
fields = (
'codReuniao',
'codReuniaoPrincipal',
'txtTituloReuniao',
'txtSiglaOrgao',
'txtApelido',
'txtNomeOrgao',
'codEstadoReuniao',
'txtTipoReuniao',
'txtObjeto',
'txtLocal',
'bolReuniaoConjunta',
'bolHabilitarEventoInterativo',
'idYoutube',
'codEstadoTransmissaoYoutube',
'datReuniaoString'
)
def __init__(self, *args, **kwargs):
super(SessaoPlenariaOldSerializer, self).__init__(args, kwargs)
def get_pk_sessao(self, obj):
return obj.pk
def get_name(self, obj):
return obj.__str__()
def get_estadoSessaoPlenaria(self, obj):
if obj.finalizada:
return self.SESSAO_FINALIZADA
elif obj.iniciada:
return self.SESSAO_EM_ANDAMENTO
else:
return self.SESSAO_CONVOCADA
def get_tipo_sessao(self, obj):
return obj.tipo.__str__()
def get_url(self, obj):
return obj.url_video if obj.url_video else None
def get_iterativo(self, obj):
return obj.interativa if obj.interativa else False
def get_date(self, obj):
return "{} {}{}".format(
obj.data_inicio.strftime("%d/%m/%Y"),
obj.hora_inicio,
":00"
)
def get_estadoTransmissaoYoutube(self, obj):
if obj.url_video:
if obj.finalizada:
return self.TRANSMISSAO_ENCERRADA
else:
return self.TRANSMISSAO_EM_ANDAMENTO
else:
return self.SEM_TRANSMISSAO
def get_assunto_sessao(self, obj):
pauta_sessao = ''
ordem_dia = OrdemDia.objects.filter(sessao_plenaria=obj.pk)
pauta_sessao = ', '.join([i.materia.__str__() for i in ordem_dia])
return str(pauta_sessao)
def get_endereco_orgao(self, obj):
return self.casa().endereco
def get_reuniao_conjunta(self, obj):
return False
def get_sigla_orgao(self, obj):
return self.casa().sigla
def get_nome_orgao(self, obj):
return self.casa().nome
def casa(self):
casa = CasaLegislativa.objects.first()
return casa
class SessaoPlenariaSerializer(serializers.ModelSerializer):
class Meta:
model = SessaoPlenaria
fields = ('tipo',
'sessao_legislativa',
'legislatura',
'data_inicio',
'hora_inicio',
'hora_fim',
'url_video',
'iniciada',
'finalizada'
)

15
sapl/api/sessao/urls.py

@ -0,0 +1,15 @@
from django.conf.urls import include, url
from rest_framework.routers import DefaultRouter
from sapl.api.sessao.views import SessaoPlenariaViewSet,\
SessaoPlenariaOldViewSet
# Não adicione app_name
# app_name = AppConfig.name
router = DefaultRouter()
router.register(r'sessao-plenaria-old', SessaoPlenariaOldViewSet,
base_name='sessao-plenaria-old')
router.register(r'sessao-plenaria', SessaoPlenariaViewSet)
urlpatterns = [
]

23
sapl/api/sessao/views.py

@ -0,0 +1,23 @@
from rest_framework.filters import DjangoFilterBackend
from rest_framework.permissions import AllowAny
from rest_framework.viewsets import ReadOnlyModelViewSet
from sapl.api.sessao.serializers import SessaoPlenariaOldSerializer,\
SessaoPlenariaSerializer
from sapl.sessao.models import SessaoPlenaria
class SessaoPlenariaOldViewSet(ReadOnlyModelViewSet):
permission_classes = (AllowAny,)
serializer_class = SessaoPlenariaOldSerializer
queryset = SessaoPlenaria.objects.all()
filter_backends = (DjangoFilterBackend,)
filter_fields = ('data_inicio', 'data_fim', 'interativa')
class SessaoPlenariaViewSet(ReadOnlyModelViewSet):
permission_classes = (AllowAny,)
serializer_class = SessaoPlenariaSerializer
queryset = SessaoPlenaria.objects.all()

27
sapl/api/urls.py

@ -2,32 +2,28 @@ from django.conf import settings
from django.conf.urls import include, url from django.conf.urls import include, url
from rest_framework.routers import DefaultRouter from rest_framework.routers import DefaultRouter
from sapl.api.views import (AutoresPossiveisListView, AutoresProvaveisListView, import sapl.api.base.urls
AutorListView, MateriaLegislativaViewSet, import sapl.api.materia.urls
ModelChoiceView, SessaoPlenariaViewSet) import sapl.api.sessao.urls
from sapl.api.views import ModelChoiceView, TimeRefreshDatabaseView
from .apps import AppConfig from .apps import AppConfig
app_name = AppConfig.name app_name = AppConfig.name
router = DefaultRouter() router = DefaultRouter()
router.register(r'materia', MateriaLegislativaViewSet) router.registry += sapl.api.materia.urls.router.registry + \
router.register(r'sessao-plenaria', SessaoPlenariaViewSet) sapl.api.sessao.urls.router.registry
urlpatterns_router = router.urls urlpatterns_router = router.urls
urlpatterns_api = [ urlpatterns_api = [
url(r'^autor/provaveis',
AutoresProvaveisListView.as_view(), name='autores_provaveis_list'),
url(r'^autor/possiveis',
AutoresPossiveisListView.as_view(), name='autores_possiveis_list'),
url(r'^autor', AutorListView.as_view(), name='autor_list'),
url(r'^model/(?P<content_type>\d+)/(?P<pk>\d*)$', url(r'^model/(?P<content_type>\d+)/(?P<pk>\d*)$',
ModelChoiceView.as_view(), name='model_list'), ModelChoiceView.as_view(), name='model_list'),
url(r'time_refresh$',
TimeRefreshDatabaseView.as_view(), name="time_refresh")
] ]
if settings.DEBUG: if settings.DEBUG:
@ -35,6 +31,9 @@ if settings.DEBUG:
url(r'^docs', include('rest_framework_docs.urls')), ] url(r'^docs', include('rest_framework_docs.urls')), ]
urlpatterns = [ urlpatterns = [
url(r'^api/', include(sapl.api.materia.urls)),
url(r'^api/', include(sapl.api.sessao.urls)),
url(r'^api/', include(sapl.api.base.urls)),
url(r'^api/', include(urlpatterns_api)), url(r'^api/', include(urlpatterns_api)),
url(r'^api/', include(urlpatterns_router)) url(r'^api/', include(urlpatterns_router))
] ]

254
sapl/api/views.py

@ -1,25 +1,12 @@
from django.apps import apps
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db.models import Q
from django.http import Http404
from django.utils.translation import ugettext_lazy as _
from rest_framework.filters import DjangoFilterBackend
from rest_framework.generics import ListAPIView from rest_framework.generics import ListAPIView
from rest_framework.mixins import ListModelMixin, RetrieveModelMixin from rest_framework.permissions import (IsAuthenticated, AllowAny)
from rest_framework.permissions import (AllowAny, IsAuthenticated, from rest_framework.response import Response
IsAuthenticatedOrReadOnly) from rest_framework.views import APIView
from rest_framework.viewsets import GenericViewSet
from sapl.api.forms import (AutorChoiceFilterSet, AutoresPossiveisFilterSet, from sapl.api.serializers import ModelChoiceSerializer
AutorSearchForFieldFilterSet) from sapl.rules.apps import AppConfig
from sapl.api.serializers import (AutorChoiceSerializer, AutorSerializer,
ChoiceSerializer,
MateriaLegislativaSerializer,
ModelChoiceSerializer,
SessaoPlenariaSerializer)
from sapl.base.models import Autor, TipoAutor
from sapl.materia.models import MateriaLegislativa
from sapl.sessao.models import SessaoPlenaria
from sapl.utils import SaplGenericRelation, sapl_logger
class ModelChoiceView(ListAPIView): class ModelChoiceView(ListAPIView):
@ -43,232 +30,9 @@ class ModelChoiceView(ListAPIView):
return self.model.objects.all() return self.model.objects.all()
class AutorListView(ListAPIView): class TimeRefreshDatabaseView(APIView):
"""
Listagem de Autores com filtro para autores cadastrados
e/ou possíveis autores.
- tr - tipo do resultado permission_classes = (AllowAny,)
Prepera Lista de Autores para 3 cenários distintos
- default = 1
= 1 -> para (value, text) usados geralmente
em combobox, radiobox, checkbox, etc com pesquisa básica
de Autores feita pelo django-filter
-> processo usado nas pesquisas, o mais usado.
= 3 -> Devolve instancias da classe Autor filtradas pelo
django-filter
- tipo - chave primária do Tipo de Autor a ser filtrado
- q - busca textual no nome do Autor ou em fields_search
declarados no field SaplGenericRelation das GenericFks
A busca textual acontece via django-filter com a
variável `tr` igual 1 ou 3. Em caso contrário,
o django-filter é desativado e a busca é feita
no model do ContentType associado ao tipo.
- q_0 / q_1 - q_0 é opcional e quando usado, faz o código ignorar "q"...
q_0 -> campos lookup a serem filtrados em qualquer Model
que implemente SaplGenericRelation
q_1 -> o valor que será pesquisado no lookup de q_0
q_0 e q_1 podem ser separados por ","... isso dará a
possibilidade de filtrar mais de um campo.
http://localhost:8000
/api/autor?tr=1&q_0=parlamentar_set__ativo&q_1=False
/api/autor?tr=1&q_0=parlamentar_set__ativo&q_1=True
/api/autor?tr=3&q_0=parlamentar_set__ativo&q_1=False
/api/autor?tr=3&q_0=parlamentar_set__ativo&q_1=True
http://localhost:8000
/api/autor?tr=1
&q_0=parlamentar_set__nome_parlamentar__icontains,
parlamentar_set__ativo
&q_1=Carvalho,False
/api/autor?tr=1
&q_0=parlamentar_set__nome_parlamentar__icontains,
parlamentar_set__ativo
&q_1=Carvalho,True
/api/autor?tr=3
&q_0=parlamentar_set__nome_parlamentar__icontains,
parlamentar_set__ativo
&q_1=Carvalho,False
/api/autor?tr=3
&q_0=parlamentar_set__nome_parlamentar__icontains,
parlamentar_set__ativo
&q_1=Carvalho,True
não importa o campo que vc passe de qualquer dos Models
ligados... é possível ver que models são esses,
na ocasião do commit deste texto, executando:
In [6]: from sapl.utils import models_with_gr_for_model
In [7]: models_with_gr_for_model(Autor)
Out[7]:
[sapl.parlamentares.models.Parlamentar,
sapl.parlamentares.models.Frente,
sapl.comissoes.models.Comissao,
sapl.materia.models.Orgao,
sapl.sessao.models.Bancada,
sapl.sessao.models.Bloco]
qualquer atributo destes models podem ser passados
para busca
"""
TR_AUTOR_CHOICE_SERIALIZER = 1
TR_AUTOR_SERIALIZER = 3
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all()
model = Autor
filter_class = AutorChoiceFilterSet
filter_backends = (DjangoFilterBackend, )
serializer_class = AutorChoiceSerializer
@property
def tr(self):
try:
tr = int(self.request.GET.get
('tr', AutorListView.TR_AUTOR_CHOICE_SERIALIZER))
assert tr in (
AutorListView.TR_AUTOR_CHOICE_SERIALIZER,
AutorListView.TR_AUTOR_SERIALIZER), sapl_logger.info(
_("Tipo do Resultado a ser fornecido não existe!"))
except:
return AutorListView.TR_AUTOR_CHOICE_SERIALIZER
else:
return tr
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
return Response({'last_global_refresh_time': apps.get_app_config('rules').time_refresh})
if self.tr == AutorListView.TR_AUTOR_SERIALIZER:
self.serializer_class = AutorSerializer
self.permission_classes = (IsAuthenticated,)
if self.filter_class and 'q_0' in request.GET:
self.filter_class = AutorSearchForFieldFilterSet
return ListAPIView.get(self, request, *args, **kwargs)
class AutoresProvaveisListView(ListAPIView):
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all()
model = Autor
filter_class = None
filter_backends = []
serializer_class = ChoiceSerializer
def get_queryset(self):
params = {'content_type__isnull': False}
tipo = ''
try:
tipo = int(self.request.GET.get('tipo', ''))
if tipo:
params['id'] = tipo
except:
pass
tipos = TipoAutor.objects.filter(**params)
if not tipos.exists() and tipo:
raise Http404()
r = []
for tipo in tipos:
q = self.request.GET.get('q', '').strip()
model_class = tipo.content_type.model_class()
fields = list(filter(
lambda field: isinstance(field, SaplGenericRelation) and
field.related_model == Autor,
model_class._meta.get_fields(include_hidden=True)))
"""
fields - é um array de SaplGenericRelation que deve possuir o
atributo fields_search. Verifique na documentação da classe
a estrutura de fields_search.
"""
assert len(fields) >= 1, (_(
'Não foi encontrado em %(model)s um atributo do tipo '
'SaplGenericRelation que use o model %(model_autor)s') % {
'model': model_class._meta.verbose_name,
'model_autor': Autor._meta.verbose_name})
qs = model_class.objects.all()
q_filter = Q()
if q:
for item in fields:
if item.related_model != Autor:
continue
q_fs = Q()
for field in item.fields_search:
q_fs = q_fs | Q(**{'%s%s' % (
field[0],
field[1]): q})
q_filter = q_filter & q_fs
qs = qs.filter(q_filter).distinct(
fields[0].fields_search[0][0]).order_by(
fields[0].fields_search[0][0])
else:
qs = qs.order_by(fields[0].fields_search[0][0])
qs = qs.values_list(
'id', fields[0].fields_search[0][0])
r += list(qs)
if tipos.count() > 1:
r.sort(key=lambda x: x[1].upper())
return r
class AutoresPossiveisListView(ListAPIView):
permission_classes = (IsAuthenticatedOrReadOnly,)
queryset = Autor.objects.all()
model = Autor
pagination_class = None
filter_class = AutoresPossiveisFilterSet
serializer_class = AutorChoiceSerializer
class MateriaLegislativaViewSet(ListModelMixin,
RetrieveModelMixin,
GenericViewSet):
permission_classes = (IsAuthenticated,)
serializer_class = MateriaLegislativaSerializer
queryset = MateriaLegislativa.objects.all()
filter_backends = (DjangoFilterBackend,)
filter_fields = ('numero', 'ano', 'tipo', )
class SessaoPlenariaViewSet(ListModelMixin,
RetrieveModelMixin,
GenericViewSet):
permission_classes = (AllowAny,)
serializer_class = SessaoPlenariaSerializer
queryset = SessaoPlenaria.objects.all()
filter_backends = (DjangoFilterBackend,)
filter_fields = ('data_inicio', 'data_fim', 'interativa')

9
sapl/crud/base.py

@ -17,8 +17,8 @@ from django.http.response import Http404
from django.shortcuts import redirect from django.shortcuts import redirect
from django.utils.decorators import classonlymethod from django.utils.decorators import classonlymethod
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 import (CreateView, DeleteView, DetailView, ListView, from django.views.generic import (CreateView, DeleteView, DetailView, ListView,
UpdateView) UpdateView)
from django.views.generic.base import ContextMixin from django.views.generic.base import ContextMixin
@ -30,6 +30,7 @@ from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL,
from sapl.settings import BASE_DIR from sapl.settings import BASE_DIR
from sapl.utils import normalize from sapl.utils import normalize
logger = logging.getLogger(BASE_DIR.name) 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 = \
@ -411,9 +412,12 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
m = self.model m = self.model
fn = fn.split('__') fn = fn.split('__')
for f in fn: for f in fn:
if not f:
continue
f = m._meta.get_field(f) f = m._meta.get_field(f)
if hasattr(f, 'related_model') and f.related_model: if hasattr(f, 'related_model') and f.related_model:
m = f.related_model m = f.related_model
if f:
s.append(force_text(f.verbose_name)) s.append(force_text(f.verbose_name))
s = ' / '.join(s) s = ' / '.join(s)
r.append(s) r.append(s)
@ -440,6 +444,9 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView):
if isinstance(name, tuple): if isinstance(name, tuple):
s = '' s = ''
for j, n in enumerate(name): for j, n in enumerate(name):
if not n:
s += '<br>'
continue
m = obj m = obj
n = n.split('__') n = n.split('__')
for f in n[:-1]: for f in n[:-1]:

10
sapl/rules/apps.py

@ -6,7 +6,10 @@ from django.contrib.auth import get_user_model
from django.contrib.auth.management import _get_all_permissions from django.contrib.auth.management import _get_all_permissions
from django.core import exceptions from django.core import exceptions
from django.db import models, router from django.db import models, router
from django.db.models.signals import post_save, post_delete
from django.db.utils import DEFAULT_DB_ALIAS from django.db.utils import DEFAULT_DB_ALIAS
from django.dispatch.dispatcher import receiver
from django.utils import timezone
from django.utils.translation import string_concat from django.utils.translation import string_concat
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
import reversion import reversion
@ -21,6 +24,7 @@ class AppConfig(django.apps.AppConfig):
name = 'sapl.rules' name = 'sapl.rules'
label = 'rules' label = 'rules'
verbose_name = _('Regras de Acesso') verbose_name = _('Regras de Acesso')
time_refresh = timezone.now()
def create_proxy_permissions( def create_proxy_permissions(
@ -254,3 +258,9 @@ models.signals.post_migrate.connect(
models.signals.pre_delete.connect( models.signals.pre_delete.connect(
receiver=revision_pre_delete_signal, receiver=revision_pre_delete_signal,
dispatch_uid="pre_delete_signal") dispatch_uid="pre_delete_signal")
@receiver([post_save, post_delete])
def refresh_time_update_base(sender, instance, **kwargs):
rule_app = apps.get_app_config('rules')
rule_app.time_refresh = timezone.now()

12
sapl/sessao/forms.py

@ -1,6 +1,5 @@
from datetime import datetime from datetime import datetime
import django_filters
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML, Button, Fieldset, Layout from crispy_forms.layout import HTML, Button, Fieldset, Layout
from django import forms from django import forms
@ -9,6 +8,7 @@ from django.core.exceptions import ObjectDoesNotExist, ValidationError
from django.db import transaction from django.db import transaction
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, TipoAutor from sapl.base.models import Autor, TipoAutor
from sapl.crispy_layout_mixin import form_actions, to_row from sapl.crispy_layout_mixin import form_actions, to_row
@ -98,7 +98,6 @@ class SessaoPlenariaForm(ModelForm):
else: # create else: # create
raise error raise error
# Condições da verificação # Condições da verificação
abertura_entre_leg = leg.data_inicio <= abertura <= leg.data_fim abertura_entre_leg = leg.data_inicio <= abertura <= leg.data_fim
abertura_entre_sl = sl.data_inicio <= abertura <= sl.data_fim abertura_entre_sl = sl.data_inicio <= abertura <= sl.data_fim
@ -112,7 +111,8 @@ class SessaoPlenariaForm(ModelForm):
if encerramento < abertura: if encerramento < abertura:
raise ValidationError("A data de encerramento não pode ser " raise ValidationError("A data de encerramento não pode ser "
"anterior a data de abertura.") "anterior a data de abertura.")
# Verifica se a data de abertura está entre a data de início e fim da legislatura # Verifica se a data de abertura está entre a data de início e fim
# da legislatura
if abertura_entre_leg and encerramento_entre_leg: if abertura_entre_leg and encerramento_entre_leg:
if abertura_entre_sl and encerramento_entre_sl: if abertura_entre_sl and encerramento_entre_sl:
pass pass
@ -164,7 +164,6 @@ class SessaoPlenariaForm(ModelForm):
"datas de início e fim tanto Legislatura " "datas de início e fim tanto Legislatura "
"quanto da Sessão Legislativa.") "quanto da Sessão Legislativa.")
# Verificações com a data de encerramento vazia # Verificações com a data de encerramento vazia
else: else:
if abertura_entre_leg: if abertura_entre_leg:
@ -454,7 +453,6 @@ class SessaoPlenariaFilterSet(django_filters.FilterSet):
# pré-popula o campo do formulário com o ano corrente # pré-popula o campo do formulário com o ano corrente
self.form.fields['data_inicio__year'].initial = timezone.now().year self.form.fields['data_inicio__year'].initial = timezone.now().year
row1 = to_row( row1 = to_row(
[('data_inicio__year', 3), [('data_inicio__year', 3),
('data_inicio__month', 3), ('data_inicio__month', 3),
@ -569,7 +567,8 @@ class OradorExpedienteForm(ModelForm):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
super(OradorExpedienteForm, self).__init__(*args, **kwargs) super(OradorExpedienteForm, self).__init__(*args, **kwargs)
legislatura_vigente = SessaoPlenaria.objects.get(pk=kwargs['initial']['id_sessao']).legislatura legislatura_vigente = SessaoPlenaria.objects.get(
pk=kwargs['initial']['id_sessao']).legislatura
if legislatura_vigente: if legislatura_vigente:
self.fields['parlamentar'].queryset = \ self.fields['parlamentar'].queryset = \
@ -597,7 +596,6 @@ class OradorExpedienteForm(ModelForm):
return self.cleaned_data return self.cleaned_data
class Meta: class Meta:
model = OradorExpediente model = OradorExpediente
exclude = ['sessao_plenaria'] exclude = ['sessao_plenaria']

37
sapl/sessao/migrations/0023_auto_20180914_1315.py

@ -0,0 +1,37 @@
# -*- coding: utf-8 -*-
# Generated by Django 1.9.13 on 2018-09-14 16:15
from __future__ import unicode_literals
from django.db import migrations, models
def limpa_observacao_igual_ementa(apps, schema_editor):
ExpedienteMateria = apps.get_model('sessao', 'ExpedienteMateria')
OrdemDia = apps.get_model('sessao', 'OrdemDia')
q = models.Q(observacao__iexact=models.F('materia__ementa'))
ExpedienteMateria.objects.filter(q).update(observacao='')
OrdemDia.objects.filter(q).update(observacao='')
class Migration(migrations.Migration):
dependencies = [
('sessao', '0022_auto_20180618_1625'),
]
operations = [
migrations.AlterField(
model_name='expedientemateria',
name='observacao',
field=models.TextField(blank=True, verbose_name='Observação'),
),
migrations.AlterField(
model_name='ordemdia',
name='observacao',
field=models.TextField(blank=True, verbose_name='Observação'),
),
migrations.RunPython(limpa_observacao_igual_ementa),
]

8
sapl/sessao/models.py

@ -1,10 +1,10 @@
from operator import xor from operator import xor
import reversion
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from model_utils import Choices from model_utils import Choices
import reversion
from sapl.base.models import Autor from sapl.base.models import Autor
from sapl.materia.models import MateriaLegislativa from sapl.materia.models import MateriaLegislativa
@ -237,7 +237,7 @@ class AbstractOrdemDia(models.Model):
verbose_name=_('Matéria')) verbose_name=_('Matéria'))
data_ordem = models.DateField(verbose_name=_('Data da Sessão')) data_ordem = models.DateField(verbose_name=_('Data da Sessão'))
observacao = models.TextField( observacao = models.TextField(
blank=True, verbose_name=_('Ementa')) blank=True, verbose_name=_('Observação'))
numero_ordem = models.PositiveIntegerField(verbose_name=_('Nº Ordem')) numero_ordem = models.PositiveIntegerField(verbose_name=_('Nº Ordem'))
resultado = models.TextField(blank=True, verbose_name=_('Resultado')) resultado = models.TextField(blank=True, verbose_name=_('Resultado'))
tipo_votacao = models.PositiveIntegerField( tipo_votacao = models.PositiveIntegerField(
@ -254,6 +254,10 @@ class AbstractOrdemDia(models.Model):
class Meta: class Meta:
abstract = True abstract = True
@property
def ementa(self):
return self.materia.ementa
def __str__(self): def __str__(self):
return 'Ordem do Dia/Expediente: %s - %s em %s' % ( return 'Ordem do Dia/Expediente: %s - %s em %s' % (
self.numero_ordem, self.materia, self.sessao_plenaria) self.numero_ordem, self.materia, self.sessao_plenaria)

16
sapl/sessao/serializers.py

@ -1,19 +1,3 @@
from rest_framework import serializers from rest_framework import serializers
from .models import SessaoPlenaria from .models import SessaoPlenaria
class SessaoPlenariaSerializer(serializers.Serializer):
class Meta:
model = SessaoPlenaria
fields = ('tipo',
'sessao_legislativa',
'legislatura',
'data_inicio',
'hora_inicio',
'hora_fim',
'url_video',
'iniciada',
'finalizada'
)

56
sapl/sessao/views.py

@ -1,5 +1,5 @@
from re import sub
from operator import itemgetter from operator import itemgetter
from re import sub
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import permission_required
@ -49,6 +49,7 @@ from .models import (Bancada, Bloco, CargoBancada, CargoMesa,
SessaoPlenaria, SessaoPlenariaPresenca, TipoExpediente, SessaoPlenaria, 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, '')
@ -389,7 +390,8 @@ def get_presencas_generic(model, sessao, legislatura):
presentes = [p.parlamentar for p in presencas] presentes = [p.parlamentar for p in presencas]
presentes = sorted(presentes, key=lambda x: remover_acentos(x.nome_parlamentar)) presentes = sorted(
presentes, key=lambda x: remover_acentos(x.nome_parlamentar))
mandato = Mandato.objects.filter( mandato = Mandato.objects.filter(
legislatura=legislatura).order_by('parlamentar__nome_parlamentar') legislatura=legislatura).order_by('parlamentar__nome_parlamentar')
@ -408,7 +410,8 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
public = [RP_LIST, RP_DETAIL] public = [RP_LIST, RP_DETAIL]
class BaseMixin(MasterDetailCrud.BaseMixin): class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['numero_ordem', 'materia', 'materia__ementa', list_field_names = ['numero_ordem', 'materia',
('materia__ementa', '', 'observacao'),
'resultado'] 'resultado']
class CreateView(MasterDetailCrud.CreateView): class CreateView(MasterDetailCrud.CreateView):
@ -439,17 +442,18 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
return initial return initial
class DetailView(MasterDetailCrud.DetailView): class DetailView(MasterDetailCrud.DetailView):
layout_key = 'OrdemDiaDetail' layout_key = 'OrdemDiaDetail'
class ListView(MasterDetailCrud.ListView): class ListView(MasterDetailCrud.ListView):
paginate_by = None paginate_by = None
ordering = ['numero_ordem', 'materia', 'resultado'] ordering = ['numero_ordem', 'materia', 'resultado']
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
has_permition = self.request.user.has_module_perms(AppConfig.label) has_permition = self.request.user.has_module_perms(AppConfig.label)
return customize_link_materia(context, self.kwargs['pk'], has_permition, False) return customize_link_materia(context, self.kwargs['pk'], has_permition, False)
def recuperar_materia(request): def recuperar_materia(request):
tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo_materia']) tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo_materia'])
numero = request.GET['numero_materia'] numero = request.GET['numero_materia']
@ -476,7 +480,8 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
class BaseMixin(MasterDetailCrud.BaseMixin): class BaseMixin(MasterDetailCrud.BaseMixin):
list_field_names = ['numero_ordem', 'materia', list_field_names = ['numero_ordem', 'materia',
'materia__ementa', 'resultado'] ('materia__ementa', '', 'observacao'),
'resultado']
class ListView(MasterDetailCrud.ListView): class ListView(MasterDetailCrud.ListView):
paginate_by = None paginate_by = None
@ -544,7 +549,6 @@ class OradorExpedienteCrud(OradorCrud):
return reverse('sapl.sessao:oradorexpediente_list', return reverse('sapl.sessao:oradorexpediente_list',
kwargs={'pk': self.kwargs['pk']}) kwargs={'pk': self.kwargs['pk']})
class UpdateView(MasterDetailCrud.UpdateView): class UpdateView(MasterDetailCrud.UpdateView):
form_class = OradorExpedienteForm form_class = OradorExpedienteForm
@ -778,7 +782,8 @@ class PainelView(PermissionRequiredForAppCrudMixin, TemplateView):
cronometro_discurso = AppsAppConfig.attr('cronometro_discurso') cronometro_discurso = AppsAppConfig.attr('cronometro_discurso')
cronometro_aparte = AppsAppConfig.attr('cronometro_aparte') cronometro_aparte = AppsAppConfig.attr('cronometro_aparte')
cronometro_ordem = AppsAppConfig.attr('cronometro_ordem') cronometro_ordem = AppsAppConfig.attr('cronometro_ordem')
cronometro_consideracoes = AppsAppConfig.attr('cronometro_consideracoes') cronometro_consideracoes = AppsAppConfig.attr(
'cronometro_consideracoes')
if (not cronometro_discurso or not cronometro_aparte if (not cronometro_discurso or not cronometro_aparte
or not cronometro_ordem or not cronometro_consideracoes): or not cronometro_ordem or not cronometro_consideracoes):
@ -999,15 +1004,18 @@ class MesaView(FormMixin, DetailView):
cargos_vagos = list(set(cargos) - set(cargos_ocupados)) cargos_vagos = list(set(cargos) - set(cargos_ocupados))
# FIX-ME: tem formas melhores de fazer isso, poupando linhas. # FIX-ME: tem formas melhores de fazer isso, poupando linhas.
parlamentares = Legislatura.objects.get(id=sessao.legislatura_id).mandato_set.all() parlamentares = Legislatura.objects.get(
id=sessao.legislatura_id).mandato_set.all()
parlamentares_ocupados = [m.parlamentar for m in mesa] parlamentares_ocupados = [m.parlamentar for m in mesa]
parlamentares_vagos = list( parlamentares_vagos = list(
set( set(
[p.parlamentar for p in parlamentares]) - set( [p.parlamentar for p in parlamentares]) - set(
parlamentares_ocupados)) parlamentares_ocupados))
org_parlamentares_vagos = parlamentares_vagos org_parlamentares_vagos = parlamentares_vagos
org_parlamentares_vagos.sort(key=lambda x: remover_acentos(x.nome_parlamentar)) org_parlamentares_vagos.sort(
org_parlamentares_vagos = [p for p in org_parlamentares_vagos if p.ativo] key=lambda x: remover_acentos(x.nome_parlamentar))
org_parlamentares_vagos = [
p for p in org_parlamentares_vagos if p.ativo]
# Se todos os cargos estiverem ocupados, a listagem de parlamentares # Se todos os cargos estiverem ocupados, a listagem de parlamentares
# deve ser renderizada vazia # deve ser renderizada vazia
if not cargos_vagos: if not cargos_vagos:
@ -1825,7 +1833,8 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
elif self.expediente: elif self.expediente:
expediente_id = kwargs['oid'] expediente_id = kwargs['oid']
try: try:
materia_votacao = ExpedienteMateria.objects.get(id=expediente_id) materia_votacao = ExpedienteMateria.objects.get(
id=expediente_id)
except ObjectDoesNotExist: except ObjectDoesNotExist:
raise Http404() raise Http404()
@ -1923,7 +1932,8 @@ class VotacaoNominalAbstract(SessaoPermissionMixin):
return self.form_invalid(form) return self.form_invalid(form)
def form_invalid(self, form): def form_invalid(self, form):
errors_tuple = [(form[e].label, form.errors[e]) for e in form.errors if e in form.fields] errors_tuple = [(form[e].label, form.errors[e])
for e in form.errors if e in form.fields]
error_message = '''<ul>''' error_message = '''<ul>'''
for e in errors_tuple: for e in errors_tuple:
error_message += '''<li><b>%s</b>: %s</li>''' % (e[0], e[1][0]) error_message += '''<li><b>%s</b>: %s</li>''' % (e[0], e[1][0])
@ -2000,8 +2010,10 @@ class VotacaoNominalEditAbstract(SessaoPermissionMixin):
elif self.expediente: elif self.expediente:
expediente_id = kwargs['oid'] expediente_id = kwargs['oid']
expediente = ExpedienteMateria.objects.filter(id=expediente_id).last() expediente = ExpedienteMateria.objects.filter(
votacao = RegistroVotacao.objects.filter(expediente_id=expediente_id).last() id=expediente_id).last()
votacao = RegistroVotacao.objects.filter(
expediente_id=expediente_id).last()
if not expediente or not votacao: if not expediente or not votacao:
raise Http404() raise Http404()
@ -2120,9 +2132,11 @@ class VotacaoNominalTransparenciaDetailView(TemplateView):
materia_votacao = self.request.GET.get('materia', None) materia_votacao = self.request.GET.get('materia', None)
if materia_votacao == 'ordem': if materia_votacao == 'ordem':
votacao = RegistroVotacao.objects.filter(ordem=self.kwargs['oid']).last() votacao = RegistroVotacao.objects.filter(
ordem=self.kwargs['oid']).last()
elif materia_votacao == 'expediente': elif materia_votacao == 'expediente':
votacao = RegistroVotacao.objects.filter(expediente=self.kwargs['oid']).last() votacao = RegistroVotacao.objects.filter(
expediente=self.kwargs['oid']).last()
else: else:
raise Http404() raise Http404()
@ -2203,9 +2217,11 @@ class VotacaoSimbolicaTransparenciaDetailView(TemplateView):
materia_votacao = self.request.GET.get('materia', None) materia_votacao = self.request.GET.get('materia', None)
if materia_votacao == 'ordem': if materia_votacao == 'ordem':
votacao = RegistroVotacao.objects.filter(ordem=self.kwargs['oid']).last() votacao = RegistroVotacao.objects.filter(
ordem=self.kwargs['oid']).last()
elif materia_votacao == 'expediente': elif materia_votacao == 'expediente':
votacao = RegistroVotacao.objects.filter(expediente=self.kwargs['oid']).last() votacao = RegistroVotacao.objects.filter(
expediente=self.kwargs['oid']).last()
else: else:
raise Http404() raise Http404()
@ -2230,6 +2246,7 @@ class VotacaoSimbolicaTransparenciaDetailView(TemplateView):
for tipo in TipoResultadoVotacao.objects.all(): for tipo in TipoResultadoVotacao.objects.all():
yield tipo yield tipo
class VotacaoExpedienteView(SessaoPermissionMixin): class VotacaoExpedienteView(SessaoPermissionMixin):
""" """
@ -2413,7 +2430,8 @@ class VotacaoExpedienteEditView(SessaoPermissionMixin):
expediente_id = kwargs['oid'] expediente_id = kwargs['oid']
if int(request.POST['anular_votacao']) == 1: if int(request.POST['anular_votacao']) == 1:
RegistroVotacao.objects.filter(expediente_id=expediente_id).delete() RegistroVotacao.objects.filter(
expediente_id=expediente_id).delete()
expediente = ExpedienteMateria.objects.get( expediente = ExpedienteMateria.objects.get(
sessao_plenaria_id=self.object.id, sessao_plenaria_id=self.object.id,

2
sapl/templates/base/relatorios_list.html

@ -42,5 +42,5 @@
</tr> </tr>
</tbody> </tbody>
</table> </table>
</fieldset </fieldset>
{% endblock base_content %} {% endblock base_content %}

19
sapl/templates/sessao/expedientemateria_form.html

@ -6,7 +6,7 @@
{% block extra_js %} {% block extra_js %}
<script language="Javascript"> <script language="Javascript">
document.getElementById("id_observacao").readOnly = true; //document.getElementById("id_observacao").readOnly = true;
function recuperar_materia() { function recuperar_materia() {
var tipo_materia = $("#id_tipo_materia").val() var tipo_materia = $("#id_tipo_materia").val()
@ -14,11 +14,21 @@
var ano_materia = $("#id_ano_materia").val() var ano_materia = $("#id_ano_materia").val()
if (tipo_materia && numero_materia && ano_materia) { if (tipo_materia && numero_materia && ano_materia) {
$.get("/sessao/recuperar-materia",{tipo_materia: tipo_materia, $.get("/sessao/recuperar-materia", {
tipo_materia: tipo_materia,
numero_materia: numero_materia, numero_materia: numero_materia,
ano_materia: ano_materia}, ano_materia: ano_materia
},
function(data, status) { function(data, status) {
$("#id_observacao").val(data.ementa); if ($(".ementa-materia").length === 0) {
$("#div_id_tipo_materia").closest('.row-fluid').after(
$('<div class="row-fluid"/>').append(
$('<div class="col-xs-12"/>').append(
$('<div class="alert alert-info ementa-materia"/>').html(data.ementa))))
}
else {
$('.ementa-materia').html(data.ementa)
}
}); });
} }
} }
@ -26,6 +36,7 @@
for (i = 0; i < fields.length; i++) { for (i = 0; i < fields.length; i++) {
$(fields[i]).change(recuperar_materia); $(fields[i]).change(recuperar_materia);
} }
recuperar_materia()
</script> </script>
{% endblock %} {% endblock %}

2
sapl/templates/sessao/layouts.yaml

@ -56,12 +56,14 @@ OrdemDia:
ExpedienteMateriaDetail: ExpedienteMateriaDetail:
{% trans 'Matérias do Expediente' %}: {% trans 'Matérias do Expediente' %}:
- materia - materia
- ementa
- tipo_votacao - tipo_votacao
- observacao - observacao
OrdemDiaDetail: OrdemDiaDetail:
{% trans 'Matérias da Ordem do Dia' %}: {% trans 'Matérias da Ordem do Dia' %}:
- materia - materia
- ementa
- tipo_votacao - tipo_votacao
- observacao - observacao

Loading…
Cancel
Save