Oculta sessões plenárias não iniciadas da consulta pública#3845
Open
joaohortsenado wants to merge 1 commit into
Open
Oculta sessões plenárias não iniciadas da consulta pública#3845joaohortsenado wants to merge 1 commit into
joaohortsenado wants to merge 1 commit into
Conversation
Sessões cadastradas com antecedência ficavam visíveis no portal mesmo com "Publicar pauta?", "Sessão iniciada?" e "Sessão finalizada?" em Não: nenhum desses campos filtrava queryset público. Só publicar_pauta filtrava, e apenas nos dois pontos de entrada da pauta. Passa a esconder do usuário anônimo as sessões marcadas explicitamente como não iniciadas e sem pauta publicada. Usuário autenticado continua vendo todas. A regra fica centralizada em SessaoPlenaria.objects.visiveis_para(user) e é aplicada na pesquisa de sessões, no detalhe, no resumo e no resumo/ata. iniciada nulo conta como visível: o campo nasceu sem default e o default=True só chegou na migração 0027, que não preencheu as linhas existentes, então bases anteriores a out/2018 têm sessões realizadas com o campo em NULL. Também restringe PautaSessaoDetailView, que não filtrava publicar_pauta e expunha por URL a pauta de sessões não publicadas.
edwardoliveira
requested changes
Jul 16, 2026
|
|
||
| class SessaoPlenariaQuerySet(models.QuerySet): | ||
|
|
||
| def visiveis_para(self, user): |
Contributor
There was a problem hiding this comment.
Sinceramente, eu estou na dúvida se deveríamos criar uma subclasse de QuerySet para verificar se usuário está logado e aplicar os filtros. Eu entendo a mudança, mas me parece que essa nova subclasse "doesn't pull its own weight", pois adiciona um ponto a mais de complexidade...
IMO, poderíamos ter uma função utilitária do tipo:
def restringe_sessoes_visiveis(qs, user):
if user.is_authenticated:
return self
return qs.filter(
Q(publicar_pauta=True) |
Q(iniciada=True) |
Q(iniciada__isnull=True))a qual chamaríamos como um wrapper nos pontos chave... Meio que já fazemos isso neste PR, mas mudaria disso:
if not SessaoPlenaria.objects.visiveis_para(
request.user).filter(pk=kwargs.get('pk')).exists():
raise Http404()para isso:
if not restringe_sessoes_visiveis(
SessaoPlenaria.objects.filter(pk=kwargs.get('pk')).exists():
raise Http404()AFAIK, o ORM do Django faz a fusão da cadeia de filters (um dentro de restringe_sessoes_visiveis e outro por fora) em um comando SQL único.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Descrição
Sessões plenárias cadastradas com antecedência ficavam visíveis na consulta pública mesmo com Publicar pauta? = Não, Sessão iniciada? = Não e Sessão finalizada? = Não. Nenhum desses campos filtrava queryset público:
publicar_pautasó era aplicado nos dois pontos de entrada da pauta (PautaSessaoViewePesquisarPautaSessaoView), einiciada/finalizadaserviam apenas para liberar o fluxo operacional de painel/votação.A regra passa a ser: o usuário anônimo só vê a sessão se
publicar_pauta=Trueou seiniciadanão estiver explicitamente marcada comoNão. Usuário autenticado continua vendo todas.Ficou centralizada em
SessaoPlenaria.objects.visiveis_para(user)(sapl/sessao/models.py) e aplicada nos quatro pontos públicos:PesquisarSessaoPlenariaViewFilterViewsem mixin de permissão e queryset abertoSessaoCrud.DetailViewpublic = [RP_DETAIL], qualquer pk acessível por URLResumoView/ResumoAtaViewDetailViewsem filtro — ata de sessão nunca iniciada era legívelPautaSessaoDetailViewpublicar_pauta; expunha por URL a pauta de sessão não publicadaPesquisarPautaSessaoViewnão muda de comportamento: ela já filtravapublicar_pauta=True, o que satisfaz o OR, então oANDresultante é equivalente.iniciadanulo conta como visívelDecisão deliberada, e não detalhe de implementação. Em
0001_initial.pyo campo nasceuNullBooleanFieldsem default; odefault=Truesó chegou na migração0027(out/2018), que é umAlterFielde portanto não preencheu as linhas existentes. Toda sessão anterior a out/2018 está cominiciada = NULLem produção. Umfilter(iniciada=True)literal faria sumir da consulta pública todas as sessões pré-2018 de qualquer casa que roda SAPL desde antes disso.Ponto de atenção para revisão
O default de
iniciadaéTrue. Uma sessão recém-cadastrada continua pública a menos que o operador marque "Sessão iniciada? Não" explicitamente — que é o fluxo já adotado pela casa que abriu o chamado. Se a intenção for que cadastro prévio seja privado por padrão, o default precisa mudar, o que exige migração e afeta todas as casas. Fora do escopo deste PR.Issue Relacionada
Não há issue no GitHub. A origem é o chamado de suporte #600935 (Câmara Municipal de Tamarana/PR), no osTicket do Interlegis: https://suporte.interlegis.leg.br/scp/tickets.php?id=59932
Motivação e Contexto
A casa cadastra as sessões e as matérias da ordem do dia antes da data de realização e precisa que elas fiquem restritas ao uso interno até lá. Hoje o SAPL não tem nenhum campo que controle a visibilidade pública de uma sessão: ela é pública desde o instante em que é salva, e os parâmetros que o operador ajusta não têm o efeito que a interface sugere.
Como Isso Foi Testado?
Ambiente: container a partir da imagem
sapl:dev(Django 2.2.28, Python 3.12), Postgres 10.5,USE_SOLR=False.Foram adicionados 7 testes em
sapl/sessao/tests/test_sessao_view.py, cobrindo:iniciada=False,iniciada=True,iniciada=NULL,publicar_pauta=True) emvisiveis_para;object_list;Resultado em
sapl/sessao+sapl/api: 22 passaram, 8 falharam. As 8 falhas são pré-existentes e não têm relação com esta mudança — confirmado rodando a mesma suíte na árvore limpa viagit stash, onde falham igual:TestResumoView(7 testes) usadef setup(self)no estilo nose, removido no pytest 8;test_numero_duplicado_sessao_plenaria_formespera uma mensagem de erro que o form não emite mais../manage.py makemigrations --checkconfirma que o manager customizado não requer migração.flake8limpo nas linhas adicionadas.Observação à parte:
pytest-djangonão consta de nenhum arquivo emrequirements/, embora opytest.inidependa dele (DJANGO_SETTINGS_MODULE,--reuse-db). Foi preciso instalá-lo à mão para rodar a suíte.Capturas de Tela (se apropriado):
n/a
Tipos de Mudanças
Checklist:
Fora do escopo
O filtro cobre a consulta web. Continuam devolvendo todas as sessões para anônimo, e podem ser alinhados com o mesmo
visiveis_paranum PR seguinte:/api/sessao/sessaoplenaria/(GET público pelo sistema de regras);sapl/api/deprecated.py,AllowAny) — não alterado aqui porque o app pode legitimamente precisar listar sessão interativa antes de iniciar;SessaoPlenariaIndex).