Repository: interlegis/sapl

Issue:
Usuário operador com acesso indevido a proposições.
O usuário operador está com acesso indevido a proposições via função Atividade Legislativa. Há relação com a #103



Discussion:
Excelente vc ter identificado esse vículo com outra issue, @andreagudo.
A issue #28 não estava clara (e já ajustei a descrição dela).
A issue que trata de autorização (quem pode fazer o que e onde) é a #103.

Ver #565


Resolving patch:
diff --git a/sapl/materia/admin.py b/sapl/materia/admin.py
--- a/sapl/materia/admin.py
+++ b/sapl/materia/admin.py
@@ -1,3 +1,22 @@
+from django.contrib import admin
+from sapl.materia.models import Proposicao
+from sapl.settings import DEBUG
 from sapl.utils import register_all_models_in_admin
 
 register_all_models_in_admin(__name__)
+
+if not DEBUG:
+
+    admin.site.unregister(Proposicao)
+
+    class ProposicaoAdmin(admin.ModelAdmin):
+        def has_add_permission(self, request, obj=None):
+            return False
+
+        def has_change_permission(self, request, obj=None):
+            return False
+
+        def has_delete_permission(self, request, obj=None):
+            return False
+
+    admin.site.register(Proposicao, ProposicaoAdmin)
diff --git a/sapl/materia/views.py b/sapl/materia/views.py
--- a/sapl/materia/views.py
+++ b/sapl/materia/views.py
@@ -4,6 +4,7 @@
 
 from crispy_forms.helper import FormHelper
 from crispy_forms.layout import HTML, Button
+from django.db.models import Q
 from django.conf import settings
 from django.contrib import messages
 from django.contrib.auth.mixins import PermissionRequiredMixin
@@ -31,7 +32,7 @@
 from sapl.norma.models import LegislacaoCitada
 from sapl.utils import (autor_label, autor_modal, gerar_hash_arquivo,
                         get_base_url, permissao_tb_aux, permissoes_autor,
-                        permissoes_materia)
+                        permissoes_materia, permissoes_protocoloadm)
 
 from .forms import (AcompanhamentoMateriaForm, AnexadaForm, AutorForm,
                     AutoriaForm, ConfirmarProposicaoForm, DespachoInicialForm,
@@ -243,11 +244,12 @@ class DeleteView(PermissionRequiredMixin, CrudDeleteView):
         permission_required = permissoes_materia()
 
 
-class ProposicaoDevolvida(ListView):
+class ProposicaoDevolvida(PermissionRequiredMixin, ListView):
     template_name = 'materia/prop_devolvidas_list.html'
     model = Proposicao
     ordering = ['data_envio']
     paginate_by = 10
+    permission_required = permissoes_protocoloadm()
 
     def get_queryset(self):
         return Proposicao.objects.filter(
@@ -265,11 +267,12 @@ def get_context_data(self, **kwargs):
         return context
 
 
-class ProposicaoPendente(ListView):
+class ProposicaoPendente(PermissionRequiredMixin, ListView):
     template_name = 'materia/prop_pendentes_list.html'
     model = Proposicao
     ordering = ['data_envio', 'autor', 'tipo', 'descricao']
     paginate_by = 10
+    permission_required = permissoes_protocoloadm()
 
     def get_queryset(self):
         return Proposicao.objects.filter(
@@ -287,11 +290,12 @@ def get_context_data(self, **kwargs):
         return context
 
 
-class ProposicaoRecebida(ListView):
+class ProposicaoRecebida(PermissionRequiredMixin, ListView):
     template_name = 'materia/prop_recebidas_list.html'
     model = Proposicao
     ordering = ['data_envio']
     paginate_by = 10
+    permission_required = permissoes_protocoloadm()
 
     def get_queryset(self):
         return Proposicao.objects.filter(
@@ -309,9 +313,10 @@ def get_context_data(self, **kwargs):
         return context
 
 
-class ReceberProposicao(CreateView):
+class ReceberProposicao(PermissionRequiredMixin, CreateView):
     template_name = "materia/receber_proposicao.html"
     form_class = ReceberProposicaoForm
+    permission_required = permissoes_protocoloadm()
 
     def get_context_data(self, **kwargs):
         context = super(ReceberProposicao, self).get_context_data(**kwargs)
@@ -341,9 +346,10 @@ def get_success_url(self):
         return reverse('sapl.materia:receber-proposicao')
 
 
-class ConfirmarProposicao(CreateView):
+class ConfirmarProposicao(PermissionRequiredMixin, CreateView):
     template_name = "materia/confirmar_proposicao.html"
     form_class = ConfirmarProposicaoForm
+    permission_required = permissoes_protocoloadm()
 
     def get_context_data(self, **kwargs):
         context = super(ConfirmarProposicao, self).get_context_data(**kwargs)
@@ -433,38 +439,36 @@ def layout_key(self):
 
         def has_permission(self):
             perms = self.get_permission_required()
-            if self.request.user.has_perms(perms):
-                if (Proposicao.objects.filter(
-                   id=self.kwargs['pk'],
-                   autor__user_id=self.request.user.id).exists()):
-                    proposicao = Proposicao.objects.get(
-                        id=self.kwargs['pk'],
-                        autor__user_id=self.request.user.id)
-                    if not proposicao.data_recebimento:
-                        return True
-                    else:
-                        msg = _('Essa proposição já foi recebida. ' +
-                                'Não pode mais ser editada')
-                        messages.add_message(self.request, messages.ERROR, msg)
-                        return False
-            else:
+            if not self.request.user.has_perms(perms):
                 return False
 
+            if (Proposicao.objects.filter(
+               id=self.kwargs['pk'],
+               autor__user_id=self.request.user.id).exists()):
+                proposicao = Proposicao.objects.get(
+                    id=self.kwargs['pk'],
+                    autor__user_id=self.request.user.id)
+                if (not proposicao.data_recebimento or
+                   proposicao.data_devolucao):
+                    return True
+                else:
+                    msg = _('Essa proposição já foi recebida. ' +
+                            'Não pode mais ser editada')
+                    messages.add_message(self.request, messages.ERROR, msg)
+                    return False
+
     class DetailView(PermissionRequiredMixin, CrudDetailView):
         permission_required = permissoes_autor()
 
         def has_permission(self):
             perms = self.get_permission_required()
-            if self.request.user.has_perms(perms):
-                if (Proposicao.objects.filter(
-                   id=self.kwargs['pk'],
-                   autor__user_id=self.request.user.id).exists()):
-                    return True
-                else:
-                    return False
-            else:
+            if not self.request.user.has_perms(perms):
                 return False
 
+            return (Proposicao.objects.filter(
+                id=self.kwargs['pk'],
+                autor__user_id=self.request.user.id).exists())
+
     class ListView(PermissionRequiredMixin, CrudListView):
         ordering = ['-data_envio', 'descricao']
         permission_required = permissoes_autor()
@@ -480,35 +484,69 @@ def get_rows(self, object_list):
                     obj.data_recebimento = 'Não recebida'
                 else:
                     obj.data_recebimento = obj.data_recebimento.strftime(
-                                            "%d/%m/%Y %H:%M")
+                        "%d/%m/%Y %H:%M")
 
             return [self._as_row(obj) for obj in object_list]
 
         def get_queryset(self):
+            # Só tem acesso as Proposicoes criadas por ele que ainda nao foram
+            # recebidas ou foram devolvidas
             lista = Proposicao.objects.filter(
                 autor__user_id=self.request.user.id)
+            lista = lista.filter(
+                Q(data_recebimento__isnull=True) |
+                Q(data_devolucao__isnull=False))
+
             return lista
 
     class DeleteView(PermissionRequiredMixin, CrudDeleteView):
         permission_required = {'materia.delete_proposicao'}
 
+        def has_permission(self):
+            perms = self.get_permission_required()
+            if not self.request.user.has_perms(perms):
+                return False
+
+            return (Proposicao.objects.filter(
+                id=self.kwargs['pk'],
+                autor__user_id=self.request.user.id).exists())
+
         def delete(self, request, *args, **kwargs):
             proposicao = Proposicao.objects.get(id=self.kwargs['pk'])
 
-            if not proposicao.data_envio:
+            if not proposicao.data_envio or proposicao.data_devolucao:
                 proposicao.delete()
                 return HttpResponseRedirect(
                     reverse('sapl.materia:proposicao_list'))
-            else:
+
+            elif not proposicao.data_recebimento:
                 proposicao.data_envio = None
                 proposicao.save()
                 return HttpResponseRedirect(
                     reverse('sapl.materia:proposicao_detail',
                             kwargs={'pk': proposicao.pk}))
 
+            else:
+                msg = _('Essa proposição já foi recebida. ' +
+                        'Não pode mais ser excluída/recuperada')
+                messages.add_message(self.request, messages.ERROR, msg)
+                return HttpResponseRedirect(
+                    reverse('sapl.materia:proposicao_detail',
+                            kwargs={'pk': proposicao.pk}))
+
 
 class ReciboProposicaoView(TemplateView):
     template_name = "materia/recibo_proposicao.html"
+    permission_required = permissoes_autor()
+
+    def has_permission(self):
+            perms = self.get_permission_required()
+            if not self.request.user.has_perms(perms):
+                return False
+
+            return (Proposicao.objects.filter(
+                id=self.kwargs['pk'],
+                autor__user_id=self.request.user.id).exists())
 
     def get_context_data(self, **kwargs):
         context = super(ReciboProposicaoView, self).get_context_data(
@@ -516,8 +554,8 @@ def get_context_data(self, **kwargs):
         proposicao = Proposicao.objects.get(pk=self.kwargs['pk'])
         context.update({'proposicao': proposicao,
                         'hash': gerar_hash_arquivo(
-                                    proposicao.texto_original.path,
-                                    self.kwargs['pk'])})
+                            proposicao.texto_original.path,
+                            self.kwargs['pk'])})
         return context
 
 


Test patch: