Browse Source

Optimise relatorio and sessao views; fix RelatorioMateriasTramitacao 504s

- RelatorioMateriasTramitacao: strip UI-only params before deciding whether
  to run a query, short-circuit RelatorioMixin.get() on permission checks,
  remove redundant per-view @ratelimit decorators (RateLimitMiddleware
  already covers them with stricter checks), and cache get_report_urls_map()
  with lru_cache
- RelatorioMateriasTramitacaoView: rewrite the materia_materiaemtramitacao
  view (migration 0088) to use DISTINCT ON instead of a correlated subquery,
  add a composite index on materia_tramitacao(materia_id, id DESC), and drop
  the now-redundant .distinct() from the filterset queryset
- customize_link_materia (MateriaOrdemDiaCrud / ExpedienteMateriaCrud):
  eliminate per-row N+1 queries via select_related/prefetch_related with
  to_attr caches, resolve sessao_plenaria once per page, and use a flat
  paginate_by=100 instead of the count()-dependent 50/None toggle

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
rate-limiter-2026
Edward Ribeiro 1 week ago
parent
commit
b7ca1609e8
  1. 62
      sapl/materia/migrations/0088_fix_view_materiaemtramitacao.py
  2. 3
      sapl/materia/models.py
  3. 4
      sapl/relatorios/forms.py
  4. 81
      sapl/relatorios/views.py
  5. 212
      sapl/sessao/views.py
  6. 26
      sapl/utils.py

62
sapl/materia/migrations/0088_fix_view_materiaemtramitacao.py

@ -0,0 +1,62 @@
from django.db import migrations, models
_OLD_VIEW = """
create or replace view materia_materiaemtramitacao as
select m.id as id,
m.id as materia_id,
t.id as tramitacao_id,
t.unidade_tramitacao_destino_id as unidade_tramitacao_atual_id
from materia_materialegislativa m
inner join materia_tramitacao t on (m.id = t.materia_id)
where t.id = (select max(id) from materia_tramitacao where materia_id = m.id)
order by m.id DESC
"""
_NEW_VIEW = """
create or replace view materia_materiaemtramitacao as
select distinct on (m.id)
m.id as id,
m.id as materia_id,
t.id as tramitacao_id,
t.unidade_tramitacao_destino_id as unidade_tramitacao_atual_id
from materia_materialegislativa m
inner join materia_tramitacao t on t.materia_id = m.id
order by m.id desc, t.id desc
"""
class Migration(migrations.Migration):
# CREATE INDEX CONCURRENTLY cannot run inside a transaction.
atomic = False
dependencies = [
('materia', '0087_update_viewdb_materiaemtramitacao'),
]
operations = [
migrations.RunSQL(sql=_NEW_VIEW, reverse_sql=_OLD_VIEW),
migrations.SeparateDatabaseAndState(
database_operations=[
migrations.RunSQL(
sql="""
CREATE INDEX CONCURRENTLY IF NOT EXISTS
tram_materia_id_desc
ON materia_tramitacao (materia_id, id DESC)
""",
reverse_sql="""
DROP INDEX CONCURRENTLY IF EXISTS
tram_materia_id_desc
""",
),
],
state_operations=[
migrations.AddIndex(
model_name='tramitacao',
index=models.Index(
fields=['materia', '-id'],
name='tram_materia_id_desc',
),
),
],
),
]

3
sapl/materia/models.py

@ -1350,6 +1350,9 @@ class Tramitacao(models.Model):
verbose_name = _('Tramitação')
verbose_name_plural = _('Tramitações')
ordering = ('-data_tramitacao', '-id')
indexes = [
models.Index(fields=['materia', '-id'], name='tram_materia_id_desc'),
]
def __str__(self):
return _('%(materia)s | %(status)s | %(data)s') % {

4
sapl/relatorios/forms.py

@ -543,9 +543,7 @@ class RelatorioMateriasTramitacaoFilterSet(django_filters.FilterSet):
@property
def qs(self):
parent = super(RelatorioMateriasTramitacaoFilterSet, self).qs
return parent.distinct().order_by(
'-materia__ano', 'materia__tipo', '-materia__numero'
)
return parent.order_by('-materia__ano', 'materia__tipo', '-materia__numero')
class Meta:
model = MateriaEmTramitacao

81
sapl/relatorios/views.py

@ -51,8 +51,7 @@ from sapl.sessao.views import (get_identificacao_basica, get_mesa_diretora,
from sapl.settings import MEDIA_URL
from sapl.settings import STATIC_ROOT
from sapl.utils import LISTA_DE_UFS, TrocaTag, filiacao_data, create_barcode, show_results_filter_set, \
num_materias_por_tipo, parlamentares_ativos, MultiFormatOutputMixin
from sapl.middleware.ratelimit import smart_key, smart_rate
num_materias_por_tipo, parlamentares_ativos, MultiFormatOutputMixin, is_report_allowed
from .templates import (pdf_capa_processo_gerar,
pdf_documento_administrativo_gerar, pdf_espelho_gerar,
pdf_etiqueta_protocolo_gerar, pdf_materia_gerar,
@ -60,8 +59,6 @@ from .templates import (pdf_capa_processo_gerar,
pdf_protocolo_gerar, pdf_sessao_plenaria_gerar)
from sapl.crud.base import make_pagination
from ratelimit.decorators import ratelimit
from django.utils.decorators import method_decorator
def get_kwargs_params(request, fields):
@ -1850,26 +1847,18 @@ class RelatoriosListView(TemplateView):
class RelatorioMixin:
# TODO: verificar se todos os relatorios de sistema/relatorios extendem esse Mixin
def get(self, request, *args, **kwargs):
super(RelatorioMixin, self).get(request)
# TODO: import as global
from sapl.utils import is_report_allowed
if not is_report_allowed(request):
raise Http404()
is_relatorio = request.GET.get('relatorio')
context = self.get_context_data(filter=self.filterset)
if is_relatorio:
if request.GET.get('relatorio'):
filterset_class = self.get_filterset_class()
self.filterset = self.get_filterset(filterset_class)
context = self.get_context_data(filter=self.filterset)
return self.relatorio(request, context)
else:
return self.render_to_response(context)
return super(RelatorioMixin, self).get(request, *args, **kwargs)
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioDocumentosAcessoriosView(RelatorioMixin, FilterView):
model = DocumentoAcessorio
filterset_class = RelatorioDocumentosAcessoriosFilterSet
@ -1914,10 +1903,6 @@ class RelatorioDocumentosAcessoriosView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioVotacoesNominaisView(RelatorioMixin, MultiFormatOutputMixin, FilterView):
model = VotoParlamentar
filterset_class = RelatorioVotacoesNominaisFilterSet
@ -1987,10 +1972,6 @@ class RelatorioVotacoesNominaisView(RelatorioMixin, MultiFormatOutputMixin, Filt
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioAtasView(RelatorioMixin, FilterView):
model = SessaoPlenaria
filterset_class = RelatorioAtasFilterSet
@ -2016,10 +1997,6 @@ class RelatorioAtasView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioPresencaSessaoView(RelatorioMixin, FilterView):
logger = logging.getLogger(__name__)
model = SessaoPlenaria
@ -2254,10 +2231,6 @@ class RelatorioPresencaSessaoView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioHistoricoTramitacaoView(RelatorioMixin, FilterView):
model = MateriaLegislativa
filterset_class = RelatorioHistoricoTramitacaoFilterSet
@ -2315,10 +2288,6 @@ class RelatorioHistoricoTramitacaoView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioDataFimPrazoTramitacaoView(RelatorioMixin, FilterView):
model = MateriaEmTramitacao
filterset_class = RelatorioDataFimPrazoTramitacaoFilterSet
@ -2382,10 +2351,6 @@ class RelatorioDataFimPrazoTramitacaoView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioReuniaoView(RelatorioMixin, FilterView):
model = Reuniao
filterset_class = RelatorioReuniaoFilterSet
@ -2420,10 +2385,6 @@ class RelatorioReuniaoView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioAudienciaView(RelatorioMixin, FilterView):
model = AudienciaPublica
filterset_class = RelatorioAudienciaFilterSet
@ -2458,10 +2419,6 @@ class RelatorioAudienciaView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioMateriasTramitacaoView(RelatorioMixin, FilterView):
model = MateriaEmTramitacao
filterset_class = RelatorioMateriasTramitacaoFilterSet
@ -2576,10 +2533,6 @@ class RelatorioMateriasTramitacaoView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioMateriasPorAnoAutorTipoView(RelatorioMixin, FilterView):
model = MateriaLegislativa
filterset_class = RelatorioMateriasPorAnoAutorTipoFilterSet
@ -2659,10 +2612,6 @@ class RelatorioMateriasPorAnoAutorTipoView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioMateriasPorAutorView(RelatorioMixin, FilterView):
model = MateriaLegislativa
filterset_class = RelatorioMateriasPorAutorFilterSet
@ -2734,10 +2683,6 @@ class RelatorioMateriaAnoAssuntoView(ListView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioNormasPublicadasMesView(RelatorioMixin, FilterView):
model = NormaJuridica
filterset_class = RelatorioNormasMesFilterSet
@ -2778,10 +2723,6 @@ class RelatorioNormasPublicadasMesView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioNormasVigenciaView(RelatorioMixin, FilterView):
model = NormaJuridica
filterset_class = RelatorioNormasVigenciaFilterSet
@ -2846,10 +2787,6 @@ class RelatorioNormasVigenciaView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioHistoricoTramitacaoAdmView(RelatorioMixin, FilterView):
model = DocumentoAdministrativo
filterset_class = RelatorioHistoricoTramitacaoAdmFilterSet
@ -2900,10 +2837,6 @@ class RelatorioHistoricoTramitacaoAdmView(RelatorioMixin, FilterView):
return context
@method_decorator(ratelimit(key=smart_key,
rate=smart_rate,
block=True),
name='dispatch')
class RelatorioNormasPorAutorView(RelatorioMixin, FilterView):
model = NormaJuridica
filterset_class = RelatorioNormasPorAutorFilterSet

212
sapl/sessao/views.py

@ -9,7 +9,7 @@ from django.contrib import messages
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import ObjectDoesNotExist
from django.db.models import Max, Q
from django.db.models import Max, Prefetch, Q
from django.http import JsonResponse
from django.http.response import Http404, HttpResponseRedirect
from django.urls import reverse
@ -174,7 +174,7 @@ def verifica_sessao_iniciada(request, spk, is_leitura=False):
aux_text = 'leitura' if is_leitura else 'votação'
logger.info('user=' + username + '. Não é possível abrir matérias para {}. '
'Esta SessaoPlenaria (id={}) não foi iniciada ou está finalizada.'.format(
aux_text, spk))
aux_text, spk))
msg = _('Não é possível abrir matérias para {}. '
'Esta Sessão Plenária não foi iniciada ou está finalizada.'
' Vá em "Abertura"->"Dados Básicos" e altere os valores dos campos necessários.'.format(aux_text))
@ -226,38 +226,43 @@ def abrir_votacao(request, pk, spk):
def customize_link_materia(context, pk, has_permission, is_expediente):
# sessao_plenaria is the same for every row — resolve once
object_list = context['object_list']
if object_list:
sessao_plenaria = object_list[0].sessao_plenaria
else:
sessao_plenaria = SessaoPlenaria.objects.get(id=pk)
data_sessao = sessao_plenaria.data_fim or sessao_plenaria.data_inicio
for i, row in enumerate(context['rows']):
materia = context['object_list'][i].materia
obj = context['object_list'][i]
obj = object_list[i]
materia = obj.materia # already select_related
url_materia = reverse(
'sapl.materia:materialegislativa_detail', kwargs={'pk': materia.id})
numeracao = materia.numeracao_set.first() if materia.numeracao_set.first() else "-"
todos_autoria = materia.autoria_set.all()
autoria = todos_autoria.filter(primeiro_autor=True)
numeracao = materia._numeracao_prefetch[0] if materia._numeracao_prefetch else "-"
todos_autoria = materia._autoria_prefetch
autoria = [a for a in todos_autoria if a.primeiro_autor]
autor = ', '.join([str(a.autor) for a in autoria]) if autoria else "-"
todos_autores = ', '.join([str(a.autor) for a in todos_autoria]) if autoria else "-"
todos_autores = ', '.join([str(a.autor)
for a in todos_autoria]) if autoria else "-"
num_protocolo = materia.numero_protocolo or "-"
num_protocolo = materia.numero_protocolo if materia.numero_protocolo else "-"
sessao_plenaria = SessaoPlenaria.objects.get(id=pk)
data_sessao = sessao_plenaria.data_fim if sessao_plenaria.data_fim else sessao_plenaria.data_inicio
tramitacao = Tramitacao.objects \
.select_related('materia', 'status', 'materia__tipo') \
.filter(materia=materia, turno__isnull=False, data_tramitacao__lte=data_sessao) \
.exclude(turno__exact='') \
.order_by('-data_tramitacao', '-id') \
.first()
tramitacao = next(
(t for t in materia._tramitacao_prefetch if t.data_tramitacao <= data_sessao),
None,
)
turno = '-'
if tramitacao:
for t in Tramitacao.TURNO_CHOICES:
if t[0] == tramitacao.turno:
turno = t[1]
break
materia_em_tramitacao = MateriaEmTramitacao.objects \
.select_related("materia", "tramitacao") \
.filter(materia=materia) \
.first()
materia_em_tramitacao = materia._met_prefetch[0] if materia._met_prefetch else None
# idUnica para cada materia
idAutor = "autor" + str(i)
idAutores = "autores" + str(i)
@ -283,12 +288,9 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
# url em toda a string de title_materia
context['rows'][i][1] = (title_materia, None)
exist_resultado = obj.registrovotacao_set.filter(
materia=obj.materia).exists()
exist_retirada = obj.retiradapauta_set.filter(
materia=obj.materia).exists()
exist_leitura = obj.registroleitura_set.filter(
materia=obj.materia).exists()
exist_resultado = bool(obj._votacao_prefetch)
exist_retirada = bool(obj._retirada_prefetch)
exist_leitura = bool(obj._leitura_prefetch)
if (obj.tipo_votacao != LEITURA and not exist_resultado and not exist_retirada) or \
(obj.tipo_votacao == LEITURA and not exist_leitura):
@ -410,8 +412,7 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
resultado = '''Não há resultado'''
elif exist_retirada:
retirada = obj.retiradapauta_set.filter(
materia_id=obj.materia_id).last()
retirada = obj._retirada_prefetch[-1]
retirada_descricao = retirada.tipo_de_retirada.descricao
retirada_observacao = retirada.observacao
url = reverse('sapl.sessao:retiradapauta_detail',
@ -423,13 +424,11 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
else:
if obj.tipo_votacao == LEITURA:
resultado = obj.registroleitura_set.filter(
materia_id=obj.materia_id).last()
resultado = obj._leitura_prefetch[-1]
resultado_descricao = "Matéria lida"
resultado_observacao = resultado.observacao
else:
resultado = obj.registrovotacao_set.filter(
materia_id=obj.materia_id).last()
resultado = obj._votacao_prefetch[-1]
resultado_descricao = resultado.tipo_resultado_votacao.nome
resultado_observacao = resultado.observacao
@ -488,11 +487,11 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
'mid': obj.materia_id})
resultado = (
'<a href="%s?page=%s">%s<br/><br/>%s</a>' % (
url,
context.get('page', 1),
resultado_descricao,
resultado_observacao))
'<a href="%s?page=%s">%s<br/><br/>%s</a>' % (
url,
context.get('page', 1),
resultado_descricao,
resultado_observacao))
else:
if obj.tipo_votacao == NOMINAL:
@ -503,7 +502,7 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
'pk': obj.sessao_plenaria_id,
'oid': obj.pk,
'mid': obj.materia_id}) + \
'?&materia=expediente'
'?&materia=expediente'
else:
url = reverse(
'sapl.sessao:votacao_nominal_transparencia',
@ -511,7 +510,7 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
'pk': obj.sessao_plenaria_id,
'oid': obj.pk,
'mid': obj.materia_id}) + \
'?&materia=ordem'
'?&materia=ordem'
resultado = ('<a href="%s">%s<br/>%s</a>' %
(url,
@ -526,7 +525,7 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
'pk': obj.sessao_plenaria_id,
'oid': obj.pk,
'mid': obj.materia_id}) + \
'?&materia=expediente'
'?&materia=expediente'
else:
url = reverse(
'sapl.sessao:votacao_simbolica_transparencia',
@ -534,7 +533,7 @@ def customize_link_materia(context, pk, has_permission, is_expediente):
'pk': obj.sessao_plenaria_id,
'oid': obj.pk,
'mid': obj.materia_id}) + \
'?&materia=ordem'
'?&materia=ordem'
resultado = ('<a href="%s">%s<br/>%s</a>' %
(url,
@ -798,7 +797,7 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
sessao_plenaria=self.kwargs['pk']).aggregate(
Max('numero_ordem'))['numero_ordem__max']
self.initial['numero_ordem'] = (
max_numero_ordem if max_numero_ordem else 0) + 1
max_numero_ordem if max_numero_ordem else 0) + 1
return self.initial
def get_success_url(self):
@ -835,20 +834,58 @@ class MateriaOrdemDiaCrud(MasterDetailCrud):
layout_key = 'OrdemDiaDetail'
class ListView(MasterDetailCrud.ListView):
paginate_by = None
paginate_by = 100
ordering = ['numero_ordem', 'materia', 'resultado']
def get_context_data(self, **kwargs):
if self.get_queryset().count() > 500:
self.paginate_by = 50
else:
self.paginate_by = None
context = super().get_context_data(**kwargs)
has_permition = self.request.user.has_module_perms(AppConfig.label)
return customize_link_materia(context, self.kwargs['pk'], has_permition, False)
def get_queryset(self):
return super().get_queryset().select_related(
'materia', 'materia__tipo', 'sessao_plenaria',
).prefetch_related(
Prefetch(
'materia__materiaemtramitacao_set',
to_attr='_met_prefetch',
),
Prefetch(
'materia__numeracao_set',
to_attr='_numeracao_prefetch',
),
Prefetch(
'materia__autoria_set',
queryset=Autoria.objects.select_related('autor'),
to_attr='_autoria_prefetch',
),
Prefetch(
'materia__tramitacao_set',
queryset=Tramitacao.objects.filter(
turno__isnull=False,
).exclude(turno='').order_by('-data_tramitacao', '-id'),
to_attr='_tramitacao_prefetch',
),
Prefetch(
'registrovotacao_set',
queryset=RegistroVotacao.objects.select_related(
'tipo_resultado_votacao',
),
to_attr='_votacao_prefetch',
),
Prefetch(
'retiradapauta_set',
queryset=RetiradaPauta.objects.select_related(
'tipo_de_retirada',
),
to_attr='_retirada_prefetch',
),
Prefetch(
'registroleitura_set',
to_attr='_leitura_prefetch',
),
)
def recuperar_materia(request):
tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo_materia'])
@ -907,24 +944,60 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
'resultado']
class ListView(MasterDetailCrud.ListView):
paginate_by = None
paginate_by = 100
ordering = ['numero_ordem', 'materia', 'resultado']
def get_context_data(self, **kwargs):
if self.get_queryset().count() > 500:
self.paginate_by = 50
else:
self.paginate_by = None
context = super().get_context_data(**kwargs)
if self.request.GET.get('page'):
context['page'] = self.request.GET.get('page')
has_permition = self.request.user.has_module_perms(AppConfig.label)
return customize_link_materia(context, self.kwargs['pk'], has_permition, True)
def get_queryset(self):
return super().get_queryset().select_related(
'materia', 'materia__tipo', 'sessao_plenaria',
).prefetch_related(
Prefetch(
'materia__materiaemtramitacao_set',
to_attr='_met_prefetch',
),
Prefetch(
'materia__numeracao_set',
to_attr='_numeracao_prefetch',
),
Prefetch(
'materia__autoria_set',
queryset=Autoria.objects.select_related('autor'),
to_attr='_autoria_prefetch',
),
Prefetch(
'materia__tramitacao_set',
queryset=Tramitacao.objects.filter(
turno__isnull=False,
).exclude(turno='').order_by('-data_tramitacao', '-id'),
to_attr='_tramitacao_prefetch',
),
Prefetch(
'registrovotacao_set',
queryset=RegistroVotacao.objects.select_related(
'tipo_resultado_votacao',
),
to_attr='_votacao_prefetch',
),
Prefetch(
'retiradapauta_set',
queryset=RetiradaPauta.objects.select_related(
'tipo_de_retirada',
),
to_attr='_retirada_prefetch',
),
Prefetch(
'registroleitura_set',
to_attr='_leitura_prefetch',
),
)
class CreateView(MasterDetailCrud.CreateView):
form_class = ExpedienteMateriaForm
@ -941,7 +1014,7 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
sessao_plenaria=self.kwargs['pk']).aggregate(
Max('numero_ordem'))['numero_ordem__max']
initial['numero_ordem'] = (
max_numero_ordem if max_numero_ordem else 0) + 1
max_numero_ordem if max_numero_ordem else 0) + 1
return initial
def get_success_url(self):
@ -975,7 +1048,6 @@ class ExpedienteMateriaCrud(MasterDetailCrud):
return initial
class DetailView(MasterDetailCrud.DetailView):
layout_key = 'ExpedienteMateriaDetail'
@ -1426,7 +1498,7 @@ class PresencaView(FormMixin, PresencaMixin, DetailView):
# Id dos parlamentares presentes
marcados = request.POST.getlist('presenca_ativos') \
+ request.POST.getlist('presenca_inativos')
+ request.POST.getlist('presenca_inativos')
# Deletar os que foram desmarcados
deletar = set(presentes_banco) - set(marcados)
@ -1541,7 +1613,7 @@ class PresencaOrdemDiaView(FormMixin, PresencaMixin, DetailView):
# Id dos parlamentares presentes
marcados = request.POST.getlist('presenca_ativos') \
+ request.POST.getlist('presenca_inativos')
+ request.POST.getlist('presenca_inativos')
# Deletar os que foram desmarcados
deletar = set(presentes_banco) - set(marcados)
@ -1803,7 +1875,7 @@ def insere_parlamentar_composicao(request):
username = request.user.username
if request.user.has_perm(
'%s.add_%s' % (
AppConfig.label, IntegranteMesa._meta.model_name)):
AppConfig.label, IntegranteMesa._meta.model_name)):
composicao = IntegranteMesa()
@ -1867,7 +1939,7 @@ def remove_parlamentar_composicao(request):
username = request.user.username
if request.POST and request.user.has_perm(
'%s.delete_%s' % (
AppConfig.label, IntegranteMesa._meta.model_name)):
AppConfig.label, IntegranteMesa._meta.model_name)):
if 'composicao_mesa' in request.POST:
try:
@ -2921,7 +2993,7 @@ class VotacaoView(SessaoPermissionMixin):
username = request.user.username
self.logger.error('user=' + username + '. Problemas ao salvar RegistroVotacao da materia de id={} '
'e da ordem de id={}. '.format(materia_id, ordem_id) + str(
e))
e))
return self.form_invalid(form)
else:
ordem = OrdemDia.objects.get(id=ordem_id)
@ -3991,7 +4063,8 @@ class PautaSessaoDetailView(PautaMultiFormatOutputMixin, DetailView):
'resultado_observacao': resultado_observacao,
'situacao': ultima_tramitacao.status if ultima_tramitacao else _("Não informada"),
'processo': f'{str(numeracao.numero_materia)}/{str(numeracao.ano_materia)}' if numeracao else '-',
'autor': [str(x.autor) for x in Autoria.objects.select_related("autor").filter(materia_id=o.materia_id)],
'autor': [str(x.autor) for x in
Autoria.objects.select_related("autor").filter(materia_id=o.materia_id)],
'turno': get_turno(ultima_tramitacao.turno) if ultima_tramitacao else '',
'periodo': 'ordem dia',
})
@ -4099,7 +4172,6 @@ class PesquisarSessaoPlenariaView(MultiFormatOutputMixin, FilterView):
return r
class PesquisarPautaSessaoView(PesquisarSessaoPlenariaView):
filterset_class = PautaSessaoFilterSet
template_name = 'sessao/pauta_sessao_filter.html'
@ -5338,7 +5410,7 @@ class CorrespondenciaCrud(MasterDetailCrud):
sessao_plenaria=self.kwargs['pk']).aggregate(
Max('numero_ordem'))['numero_ordem__max']
initial['numero_ordem'] = (
max_numero_ordem if max_numero_ordem else 0) + 1
max_numero_ordem if max_numero_ordem else 0) + 1
return initial

26
sapl/utils.py

@ -1,6 +1,6 @@
import csv
import string
from functools import wraps
from functools import lru_cache, wraps
import hashlib
import io
from itertools import groupby, chain
@ -959,13 +959,15 @@ def parlamentares_ativos(data_inicio, data_fim=None):
return Parlamentar.objects.filter(id__in=parlamentares_id)
def show_results_filter_set(qr):
query_params = set(qr.keys())
if ((len(query_params) == 1 and 'iframe' in query_params) or
len(query_params) == 0):
return False
_IGNORED_PARAMS = frozenset({'iframe', 'pesquisar', 'csrfmiddlewaretoken'})
return True
def show_results_filter_set(qr):
meaningful = {
k for k, v in qr.items()
if k not in _IGNORED_PARAMS and v and v.strip()
}
return bool(meaningful)
def sort_lista_chave(lista, chave):
@ -1249,7 +1251,7 @@ class GoogleRecapthaMixin:
return cd
# TODO: cache this map and invalidate on each update
@lru_cache(maxsize=None)
def get_report_urls_map():
from django.urls import get_resolver
from django.urls.base import reverse
@ -1278,13 +1280,11 @@ def get_report_urls_map():
def is_report_allowed(request, url_path=None):
from sapl.utils import get_report_urls_map # TODO: import global
url_map = get_report_urls_map() # TODO: cache this!!! Globally
url_map = get_report_urls_map()
path = url_path if url_path else request.path
authenticated = True if request.user.is_authenticated else False
authenticated = request.user.is_authenticated
if path in url_map.keys():
if path in url_map:
path_metadata = url_map[path]
if not authenticated and path_metadata['public']:
return True

Loading…
Cancel
Save