diff --git a/sapl/base/media.py b/sapl/base/media.py index dc0003f00..3cbe758ae 100644 --- a/sapl/base/media.py +++ b/sapl/base/media.py @@ -6,11 +6,10 @@ from urllib.parse import quote from django.conf import settings from django.http import FileResponse, Http404, HttpResponse -from sapl.materia.models import Proposicao +from sapl.materia.models import Proposicao, pode_ver_proposicao from sapl.protocoloadm.models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo, pode_ver_documento_adm) -from sapl.sessao.models import SessaoPlenaria, restringe_sessoes_visiveis from sapl.utils import EXTENSOES_ATIVAS, tipo_ativo X_ACCEL_PREFIX = '/media-interna/' @@ -21,19 +20,6 @@ PROTEGIDO_RE = re.compile( r'^sapl/[^/]+/(?:documentoadministrativo|' r'documentoacessorioadministrativo|proposicao)/') - -def _pode_ver_proposicao(user, proposicao): - if proposicao.data_recebimento: - return True - if not user.is_authenticated: - return False - if proposicao.autor and proposicao.autor.operadores.filter( - id=user.id).exists(): - return True - return bool(proposicao.data_envio) and user.has_module_perms( - 'protocoloadm') - - RESOLVEDORES = { 'documentoadministrativo': ( DocumentoAdministrativo, 'texto_integral', pode_ver_documento_adm), @@ -41,7 +27,7 @@ RESOLVEDORES = { DocumentoAcessorioAdministrativo, 'arquivo', lambda user, obj: pode_ver_documento_adm(user, obj.documento)), 'proposicao': ( - Proposicao, 'texto_original', _pode_ver_proposicao), + Proposicao, 'texto_original', pode_ver_proposicao), } @@ -62,14 +48,6 @@ def _nome_protegido(request, path): return arquivo.name[2:] if arquivo.name.startswith('./') else arquivo.name -def _sessao_oculta(request, partes): - if request.user.is_authenticated or not partes[3].isdigit(): - return False - qs = SessaoPlenaria.objects.filter(pk=partes[3]) - return qs.exists() and not restringe_sessoes_visiveis( - qs, request.user).exists() - - def media(request, path): partes = path.split('/') if any(p in ('', '.', '..') for p in partes) or '\x00' in path: @@ -78,10 +56,6 @@ def media(request, path): protegido = path.startswith('sapl/private/') or bool( PROTEGIDO_RE.match(path)) nome = _nome_protegido(request, path) if protegido else path - - if path.startswith('sapl/public/sessaoplenaria/') and len(partes) > 4 \ - and _sessao_oculta(request, partes): - raise Http404 nome_arquivo = os.path.basename(nome) content_type = (mimetypes.guess_type(nome_arquivo)[0] or diff --git a/sapl/base/tests/test_media.py b/sapl/base/tests/test_media.py index ef39c79c3..fcdceeca9 100644 --- a/sapl/base/tests/test_media.py +++ b/sapl/base/tests/test_media.py @@ -71,8 +71,9 @@ def _assert_servido(response, path): ('O', True, None, False), ('O', True, 'logado', True), ('R', False, None, False), - ('R', False, 'logado', False), - ('R', True, 'com_permissao', True), + ('R', False, 'logado', True), + ('R', True, None, False), + ('R', True, 'logado', True), ]) def test_documento_administrativo(client, comportamento, restrito, perfil, pode_ver): @@ -81,9 +82,6 @@ def test_documento_administrativo(client, comportamento, restrito, perfil, texto_integral=DOC_PATH) if perfil == 'logado': _login(client, 'logado') - elif perfil == 'com_permissao': - _login(client, 'perm', - 'protocoloadm.detail_documentoadministrativo') response = _get(client, DOC_PATH) @@ -180,7 +178,10 @@ def _proposicao(enviada=False, recebida=False): ('enviada', 'protocolo', True), ('enviada', 'outro', False), ('enviada', None, False), - ('recebida', None, True), + ('recebida', None, False), + ('recebida', 'outro', False), + ('recebida', 'protocolo', True), + ('recebida', 'operador', True), ]) def test_proposicao(client, estado, perfil, pode_ver): operador = _proposicao(enviada=estado == 'enviada', @@ -276,3 +277,17 @@ def test_senha_fraca_nao_redireciona_media(client): assert response.status_code == 200 assert response.has_header('X-Accel-Redirect') + + +@pytest.mark.django_db(transaction=False) +@pytest.mark.parametrize('perfil', [None, 'outro']) +def test_proposicao_texto_recebida_nao_e_publica(client, perfil): + _proposicao(recebida=True) + if perfil: + _login(client, perfil) + pk = Proposicao.objects.get(texto_original=PROPOSICAO_PATH).pk + + response = client.get('/proposicao/texto/%s' % pk) + + assert response.status_code == 302 + assert response['Location'] == '/proposicao/%s' % pk diff --git a/sapl/materia/models.py b/sapl/materia/models.py index bdeb402e3..d3c805c38 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -1154,6 +1154,18 @@ class Proposicao(models.Model): update_fields=update_fields) +def pode_ver_proposicao(user, proposicao): + """Texto original da proposição: nunca público. Operadores do autor veem + sempre; o protocolo vê depois do envio.""" + if not user.is_authenticated: + return False + if proposicao.autor and proposicao.autor.operadores.filter( + id=user.id).exists(): + return True + return bool(proposicao.data_envio) and user.has_module_perms( + 'protocoloadm') + + class HistoricoProposicao(models.Model): STATUS_PROPOSICAO = Choices(('E', 'ENVIADA', _('Enviada')), ('R', 'RECEBIDA', _('Recebida')), diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 59c03001b..2c01e2eb6 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -74,7 +74,7 @@ from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, ReceberProposicaoForm, RelatoriaForm, TramitacaoEmLoteFilterSet, TramitacaoEmLoteForm, UnidadeTramitacaoForm, StatusTramitacaoFilterSet) -from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, DespachoInicial, +from .models import (pode_ver_proposicao, AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, DespachoInicial, DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao, RegimeTramitacao, Relatoria, StatusTramitacao, TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao, @@ -106,14 +106,10 @@ def proposicao_texto(request, pk): username = request.user.username logger.debug('user=' + username + '. Tentando obter objeto Proposicao com pk = {}.'.format(pk)) - proposicao = Proposicao.objects.get(pk=pk) + proposicao = get_object_or_404(Proposicao, pk=pk) if proposicao.texto_original: - if (not proposicao.data_recebimento and - not proposicao.autor.operadores.filter( - id=request.user.id - ).exists() - ): + if not pode_ver_proposicao(request.user, proposicao): logger.error("user=" + username + ". Usuário ({}) não tem permissão para acessar o texto original." .format(request.user.id)) messages.error(request, _( diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py index 3d34ae072..70341cb15 100644 --- a/sapl/protocoloadm/models.py +++ b/sapl/protocoloadm/models.py @@ -343,9 +343,10 @@ class DocumentoAdministrativo(models.Model): 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') + if user.is_authenticated: + return True + return not documento.restrito and SaplAppConfig.attr( + 'documentos_administrativos') == DOC_ADM_OSTENSIVO class DocumentoAcessorioAdministrativo(models.Model): diff --git a/sapl/protocoloadm/tests/test_docadm_acesso.py b/sapl/protocoloadm/tests/test_docadm_acesso.py index 602da119c..df2ca07b0 100644 --- a/sapl/protocoloadm/tests/test_docadm_acesso.py +++ b/sapl/protocoloadm/tests/test_docadm_acesso.py @@ -62,10 +62,10 @@ ACESSO = [ ('O', True, 'sem_permissao', True), ('O', True, 'com_permissao', True), ('R', False, 'anonimo', False), - ('R', False, 'sem_permissao', False), + ('R', False, 'sem_permissao', True), ('R', False, 'com_permissao', True), ('R', True, 'anonimo', False), - ('R', True, 'sem_permissao', False), + ('R', True, 'sem_permissao', True), ('R', True, 'com_permissao', True), ] diff --git a/sapl/sessao/tests/test_sessao_oculta_api.py b/sapl/sessao/tests/test_sessao_oculta_api.py index 32ad80eac..b915ce1d0 100644 --- a/sapl/sessao/tests/test_sessao_oculta_api.py +++ b/sapl/sessao/tests/test_sessao_oculta_api.py @@ -70,16 +70,9 @@ def test_api_mostra_sessao_previa_ao_usuario_autenticado(client, sessoes): @pytest.mark.django_db(transaction=False) -def test_media_de_sessao_previa_oculta_do_anonimo(client, settings, sessoes): +def test_media_de_sessao_e_publica(client, settings, sessoes): settings.DEBUG = False - previa, iniciada = sessoes - - def get(sessao): - return client.get('/media/sapl/public/sessaoplenaria/%s/pauta/p.pdf' - % sessao.pk) - - assert get(previa).status_code == 404 - assert get(iniciada).status_code == 200 - - client.force_login(baker.make(get_user_model())) - assert get(previa).status_code == 200 + for sessao in sessoes: + response = client.get( + '/media/sapl/public/sessaoplenaria/%s/pauta/p.pdf' % sessao.pk) + assert response.status_code == 200