From aec15aaa38d19594f6fd121f504245bbfdb81316 Mon Sep 17 00:00:00 2001 From: Edward Oliveira Date: Tue, 13 Oct 2026 16:37:54 -0300 Subject: [PATCH] =?UTF-8?q?Exige=20permiss=C3=A3o=20de=20proposi=C3=A7?= =?UTF-8?q?=C3=A3o=20para=20receber=20e=20confirmar=20proposi=C3=A7=C3=B5e?= =?UTF-8?q?s?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- .../tests/test_proposicao_confirmar.py | 98 +++++++++++++++++++ sapl/materia/views.py | 8 +- 2 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 sapl/materia/tests/test_proposicao_confirmar.py diff --git a/sapl/materia/tests/test_proposicao_confirmar.py b/sapl/materia/tests/test_proposicao_confirmar.py new file mode 100644 index 000000000..327b65d84 --- /dev/null +++ b/sapl/materia/tests/test_proposicao_confirmar.py @@ -0,0 +1,98 @@ +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Permission +from django.contrib.contenttypes.models import ContentType +from django.urls import reverse +from django.utils import timezone +from model_bakery import baker +import pytest + +from sapl.base.models import AppConfig +from sapl.materia.models import (Proposicao, TipoMateriaLegislativa, + TipoProposicao) +from sapl.utils import SEPARADOR_HASH_PROPOSICAO, gerar_hash_arquivo + +PROPOSICAO_PATH = 'sapl/private/proposicao/2026/1/proposicao.pdf' +PERMS_DOCADM = ['add_documentoadministrativo', + 'change_documentoadministrativo', + 'detail_documentoadministrativo'] + + +def _login(client, app_label, *codenames): + user = baker.make(get_user_model(), username=app_label) + user.user_permissions.add(*Permission.objects.filter( + content_type__app_label=app_label, codename__in=codenames)) + client.force_login(user) + return user + + +def _login_docadm(client): + user = _login(client, 'protocoloadm', *PERMS_DOCADM) + assert user.has_module_perms('protocoloadm') + + +def _login_protocolo(client): + _login(client, 'materia', 'detail_proposicao_enviada') + + +def _proposicao_enviada(settings, tmp_path): + settings.MEDIA_ROOT = str(tmp_path) + baker.make(AppConfig) + arquivo = tmp_path / PROPOSICAO_PATH + arquivo.parent.mkdir(parents=True) + arquivo.write_bytes(b'%PDF-1.4 proposicao') + tipo = baker.make( + TipoProposicao, + content_type=ContentType.objects.get_for_model(TipoMateriaLegislativa), + object_id=baker.make(TipoMateriaLegislativa).pk) + proposicao = baker.make(Proposicao, tipo=tipo, + texto_original=PROPOSICAO_PATH, + data_envio=timezone.now()) + hasher = gerar_hash_arquivo(str(arquivo), str(proposicao.pk)) + return proposicao, hasher[1:].split(SEPARADOR_HASH_PROPOSICAO)[0] + + +def _url_confirmar(proposicao, hash_): + return reverse('sapl.materia:proposicao-confirmar', + kwargs={'hash': hash_, 'pk': proposicao.pk}) + + +@pytest.mark.django_db(transaction=False) +def test_receber_exige_permissao_de_proposicao(client): + _login_docadm(client) + url = reverse('sapl.materia:receber-proposicao') + + assert client.get(url).status_code == 403 + + +@pytest.mark.django_db(transaction=False) +def test_receber_operador_de_protocolo(client): + _login_protocolo(client) + url = reverse('sapl.materia:receber-proposicao') + + assert client.get(url).status_code == 200 + + +@pytest.mark.django_db(transaction=False) +def test_confirmar_exige_permissao_de_proposicao(client, settings, tmp_path): + proposicao, hash_ = _proposicao_enviada(settings, tmp_path) + _login_docadm(client) + + response = client.get(_url_confirmar(proposicao, hash_)) + + assert response.status_code == 403 + + +@pytest.mark.django_db(transaction=False) +def test_confirmar_operador_de_protocolo_ve_texto(client, settings, + tmp_path): + settings.DEBUG = False + proposicao, hash_ = _proposicao_enviada(settings, tmp_path) + _login_protocolo(client) + + response = client.get(_url_confirmar(proposicao, hash_)) + + assert response.status_code == 200 + assert proposicao.texto_original.url.encode() in response.content + texto = client.get(proposicao.texto_original.url) + assert texto.status_code == 200 + assert texto['X-Accel-Redirect'] == '/media-interna/' + PROPOSICAO_PATH diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 098ddd191..4ac8a2432 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -576,8 +576,8 @@ class ProposicaoRecebida(PermissionRequiredMixin, ListView): return context -class ReceberProposicao(PermissionRequiredForAppCrudMixin, FormView): - app_label = sapl.protocoloadm.apps.AppConfig.label +class ReceberProposicao(PermissionRequiredMixin, FormView): + permission_required = ('materia.detail_proposicao_enviada', ) template_name = "crud/form.html" form_class = ReceberProposicaoForm @@ -660,8 +660,8 @@ class RetornarProposicao(UpdateView): request, *args, **kwargs) -class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView): - app_label = sapl.protocoloadm.apps.AppConfig.label +class ConfirmarProposicao(PermissionRequiredMixin, UpdateView): + permission_required = ('materia.detail_proposicao_enviada', ) template_name = "materia/confirmar_proposicao.html" model = Proposicao form_class = ConfirmarProposicaoForm, DevolverProposicaoForm