diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py index 3cdf32735..3d34ae072 100644 --- a/sapl/protocoloadm/models.py +++ b/sapl/protocoloadm/models.py @@ -6,7 +6,8 @@ from django.utils.functional import cached_property from django.utils.translation import ugettext_lazy as _ from model_utils import Choices -from sapl.base.models import Autor, AppConfig as SaplAppConfig +from sapl.base.models import Autor, AppConfig as SaplAppConfig, \ + DOC_ADM_OSTENSIVO from sapl.materia.models import TipoMateriaLegislativa, UnidadeTramitacao,\ MateriaLegislativa from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, texto_upload_path, @@ -341,6 +342,12 @@ class DocumentoAdministrativo(models.Model): update_fields=update_fields) +def pode_ver_documento_adm(user, documento): + if SaplAppConfig.attr('documentos_administrativos') == DOC_ADM_OSTENSIVO: + return not (documento.restrito and user.is_anonymous) + return user.has_perm('protocoloadm.detail_documentoadministrativo') + + class DocumentoAcessorioAdministrativo(models.Model): documento = models.ForeignKey(DocumentoAdministrativo, on_delete=models.PROTECT) diff --git a/sapl/protocoloadm/tests/test_docadm_acesso.py b/sapl/protocoloadm/tests/test_docadm_acesso.py new file mode 100644 index 000000000..8db4eec77 --- /dev/null +++ b/sapl/protocoloadm/tests/test_docadm_acesso.py @@ -0,0 +1,103 @@ +from django.contrib.auth import get_user_model +from django.contrib.auth.models import Permission +from django.contrib.contenttypes.models import ContentType +from django.core.cache import cache +from django.core.files.uploadedfile import SimpleUploadedFile +from django.urls import reverse +from model_bakery import baker +import pytest + +from sapl.base.models import AppConfig +from sapl.protocoloadm.models import DocumentoAdministrativo + + +@pytest.fixture +def media_tmp(settings, tmp_path): + settings.MEDIA_ROOT = str(tmp_path) + return tmp_path + + +def _config(comportamento): + cache.clear() + AppConfig.objects.all().delete() + baker.make(AppConfig, documentos_administrativos=comportamento) + + +def _documento(restrito): + documento = baker.make(DocumentoAdministrativo, restrito=restrito) + documento.texto_integral = SimpleUploadedFile( + 'texto.pdf', b'%PDF-1.4 conteudo', content_type='application/pdf') + documento.save() + return documento + + +def _client(client, perfil): + if perfil == 'anonimo': + return client + user = baker.make(get_user_model(), username=perfil) + if perfil == 'com_permissao': + ct = ContentType.objects.get_for_model(DocumentoAdministrativo) + perm, _ = Permission.objects.get_or_create( + codename='detail_documentoadministrativo', content_type=ct, + defaults={'name': 'detail'}) + user.user_permissions.add(perm) + client.force_login(user) + return client + + +ACESSO = [ + # (comportamento, restrito, perfil, pode_ver) + ('O', False, 'anonimo', True), + ('O', False, 'sem_permissao', True), + ('O', False, 'com_permissao', True), + ('O', True, 'anonimo', False), + ('O', True, 'sem_permissao', True), + ('O', True, 'com_permissao', True), + ('R', False, 'anonimo', False), + ('R', False, 'sem_permissao', False), + ('R', False, 'com_permissao', True), + ('R', True, 'anonimo', False), + ('R', True, 'sem_permissao', False), + ('R', True, 'com_permissao', True), +] + + +@pytest.mark.django_db(transaction=False) +@pytest.mark.parametrize('comportamento,restrito,perfil,pode_ver', ACESSO) +def test_doc_texto_integral_acesso(client, media_tmp, comportamento, + restrito, perfil, pode_ver): + _config(comportamento) + documento = _documento(restrito) + client = _client(client, perfil) + + response = client.get(reverse('sapl.protocoloadm:doc_texto_integral', + kwargs={'pk': documento.pk})) + + assert response.status_code == (200 if pode_ver else 404) + + +@pytest.mark.django_db(transaction=False) +@pytest.mark.parametrize('comportamento,restrito,perfil,pode_ver', ACESSO) +def test_pdf_docacessorios_acesso(client, media_tmp, comportamento, + restrito, perfil, pode_ver): + _config(comportamento) + documento = baker.make(DocumentoAdministrativo, restrito=restrito) + client = _client(client, perfil) + + response = client.get(reverse('sapl.protocoloadm:merge_docacessorios', + kwargs={'pk': documento.pk})) + + if pode_ver: + assert response.status_code != 404 + else: + assert response.status_code == 404 + + +@pytest.mark.django_db(transaction=False) +@pytest.mark.parametrize('url_name', ['doc_texto_integral', + 'merge_docacessorios']) +def test_docadm_pk_inexistente(client, url_name): + _config('O') + response = client.get(reverse('sapl.protocoloadm:' + url_name, + kwargs={'pk': 999999})) + assert response.status_code == 404 diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 345382438..25c465438 100755 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -42,7 +42,7 @@ from sapl.parlamentares.models import Legislatura, Parlamentar from sapl.protocoloadm.forms import VinculoDocAdminMateriaForm,\ VinculoDocAdminMateriaEmLoteFilterSet from sapl.protocoloadm.models import Protocolo, DocumentoAdministrativo,\ - VinculoDocAdminMateria + VinculoDocAdminMateria, pode_ver_documento_adm from sapl.relatorios.views import relatorio_doc_administrativos from sapl.utils import (create_barcode, get_base_url, get_client_ip, get_mime_type_from_file_extension, lista_anexados, @@ -101,15 +101,9 @@ def recuperar_materia_protocolo(request): def doc_texto_integral(request, pk): - can_see = True + documento = get_object_or_404(DocumentoAdministrativo, pk=pk) - if not request.user.is_authenticated: - app_config = AppConfig.objects.last() - if app_config and app_config.documentos_administrativos == 'R': - can_see = False - - if can_see: - documento = DocumentoAdministrativo.objects.get(pk=pk) + if pode_ver_documento_adm(request.user, documento): if documento.texto_integral: arquivo = documento.texto_integral @@ -127,6 +121,8 @@ def doc_texto_integral(request, pk): def get_pdf_docacessorios(request, pk): documento_administrativo = get_object_or_404(DocumentoAdministrativo, pk=pk) + if not pode_ver_documento_adm(request.user, documento_administrativo): + raise Http404 logger = logging.getLogger(__name__) username = 'Usuário anônimo' if request.user.is_anonymous else request.user.username try: @@ -498,7 +494,7 @@ class DocumentoAdministrativoCrud(Crud): def get(self, *args, **kwargs): pk = self.kwargs['pk'] - documento = DocumentoAdministrativo.objects.get(id=pk) + documento = get_object_or_404(DocumentoAdministrativo, pk=pk) if documento.restrito and self.request.user.is_anonymous: return redirect('/') return super(Crud.DetailView, self).get(args, kwargs)