diff --git a/sapl/api/views_materia.py b/sapl/api/views_materia.py index d37658afa..0d5356b0b 100644 --- a/sapl/api/views_materia.py +++ b/sapl/api/views_materia.py @@ -8,7 +8,7 @@ customize, wrapper_queryset_response_for_drf_action from sapl.api.permissions import SaplModelPermissions from sapl.materia.models import TipoMateriaLegislativa, Tramitacao,\ - MateriaLegislativa, Proposicao + MateriaLegislativa, Proposicao, DocumentoAcessorio ApiViewSetConstrutor.build_class( @@ -111,6 +111,19 @@ def anexadas(self, request, *args, **kwargs): return self.list(request, *args, **kwargs) + +@customize(DocumentoAcessorio) +class _DocumentoAcessorioViewSet: + + def get_queryset(self): + user = self.request.user + qs = super().get_queryset() + + if user.is_anonymous or 'materia.change_documentoacessorio' not in user.get_all_permissions(): + qs = qs.exclude(restrito=True) + return qs + + @customize(TipoMateriaLegislativa) class _TipoMateriaLegislativaViewSet: diff --git a/sapl/api/views_protocoloadm.py b/sapl/api/views_protocoloadm.py index 5ebe77ec1..30d033ecf 100644 --- a/sapl/api/views_protocoloadm.py +++ b/sapl/api/views_protocoloadm.py @@ -60,9 +60,12 @@ class _DocumentoAcessorioAdministrativoViewSet: def get_queryset(self): qs = super().get_queryset() + user = self.request.user - if self.request.user.is_anonymous: + if user.is_anonymous or 'protocoloadm.change_documentoacessorioadministrativo' not in user.get_all_permissions(): +# if self.request.user.is_anonymous: qs = qs.exclude(documento__restrito=True) + qs = qs.exclude(restrito=True) return qs diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index b1219d56c..ee6433521 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -330,11 +330,17 @@ def __init__(self, *args, **kwargs): class DocumentoAcessorioForm(FileFieldCheckMixin, ModelForm): data = forms.DateField(required=True) + restrito = forms.ChoiceField( + label=_('Documento Restrito?'), + widget=forms.RadioSelect(), + choices=YES_NO_CHOICES, + initial=False) class Meta: model = DocumentoAcessorio fields = ['tipo', 'nome', 'data', 'autor', - 'ementa', 'indexacao', 'arquivo'] + 'ementa', 'indexacao', 'arquivo', + 'restrito', 'justificativa_restricao'] def clean(self): super(DocumentoAcessorioForm, self).clean() diff --git a/sapl/materia/migrations/0082_auto_20220929_1450.py b/sapl/materia/migrations/0082_auto_20220929_1450.py new file mode 100644 index 000000000..fc613db59 --- /dev/null +++ b/sapl/materia/migrations/0082_auto_20220929_1450.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.28 on 2022-09-29 17:50 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0081_auto_20220321_0934'), + ] + + operations = [ + migrations.AddField( + model_name='documentoacessorio', + name='justificativa_restricao', + field=models.TextField(blank=True, verbose_name='Justificativa de Restrição'), + ), + migrations.AddField( + model_name='documentoacessorio', + name='restrito', + field=models.BooleanField(blank=True, default=False, verbose_name='Restrito'), + ), + ] diff --git a/sapl/materia/models.py b/sapl/materia/models.py index 4c4109354..700cd35a5 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -554,6 +554,11 @@ class DocumentoAcessorio(models.Model): proposicao = GenericRelation('Proposicao', related_query_name='proposicao') data_ultima_atualizacao = models.DateTimeField( blank=True, null=True, auto_now=True, verbose_name=_('Data')) + restrito = models.BooleanField(default=False, + verbose_name=_('Restrito'), + blank=True) + justificativa_restricao = models.TextField( + blank=True, verbose_name=_('Justificativa de Restrição')) class Meta: verbose_name = _('Documento Acessório') diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 755fe2f1e..108ad4224 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -1591,6 +1591,46 @@ def get_context_data(self, **kwargs): context = super(UpdateView, self).get_context_data(**kwargs) return context + class ListView(MasterDetailCrud.ListView): + + def get_queryset(self): + qs = super(MasterDetailCrud.ListView, self).get_queryset() + kwargs = {self.crud.parent_field: self.kwargs['pk']} + exibir_restritos = 'materia.change_documentoacessorio' in self.request.user.get_all_permissions() + if 'o' in self.request.GET: + o = self.request.GET['o'] + indice_field = abs(int(o)) - 1 + if '-' in o: + order_by = '-' + self.list_field_names[indice_field] + else: + order_by = self.list_field_names[indice_field] + if exibir_restritos: + return qs.filter(**kwargs).order_by(order_by, '-data', '-id') + else: + return qs.filter(**kwargs).order_by('restrito', order_by, '-data', '-id') + + if exibir_restritos: + return qs.filter(**kwargs).order_by('-data', '-id') + else: + return qs.filter(**kwargs).order_by('restrito', '-data', '-id') + + class DetailView(MasterDetailCrud.DetailView): + layout_key = 'DocumentoAcessorioAdministrativo' + template_name = "materia/documentoacessorio_detail.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['AppConfig'] = sapl.base.models.AppConfig.objects.all().last() + context['user'] = self.request.user + + doc = DocumentoAcessorio.objects.get( + pk=self.kwargs['pk'] + ) + context['object'] = doc + if doc.restrito and not 'materia.change_documentoacessorio' in self.request.user.get_all_permissions(): + context['title'] = 'Documento Restrito' + return context + class AutoriaCrud(MasterDetailCrud): model = Autoria @@ -2872,13 +2912,15 @@ def form_valid(self, form): return fv -def create_zip_docacessorios(materia): +def create_zip_docacessorios(materia, excluir_restritos): """ Creates in memory zip files """ logger = logging.getLogger(__name__) docs = materia.documentoacessorio_set. \ all().values_list('arquivo', flat=True) + if excluir_restritos: + docs = docs.filter(restrito=False) if not docs: return None, None @@ -2908,10 +2950,14 @@ def create_zip_docacessorios(materia): def get_zip_docacessorios(request, pk): logger = logging.getLogger(__name__) username = 'Usuário anônimo' if request.user.is_anonymous else request.user.username + if request.user.is_anonymous or not 'protocoloadm.change_documentoacessorioadministrativo' in request.user.get_all_permissions(): + excluir_restritos = True + else: + excluir_restritos = False materia = get_object_or_404(MateriaLegislativa, pk=pk) data = None try: - external_name, data = create_zip_docacessorios(materia) + external_name, data = create_zip_docacessorios(materia, excluir_restritos) logger.info( "user= {}. Gerou o zip compilado de documento acessorios".format(username)) except FileNotFoundError: @@ -2940,13 +2986,15 @@ def get_zip_docacessorios(request, pk): return response -def create_pdf_docacessorios(materia): +def create_pdf_docacessorios(materia,excluir_restritos): """ Creates a unified in memory PDF file """ logger = logging.getLogger(__name__) docs = materia.documentoacessorio_set. \ all().values_list('arquivo', flat=True) + if excluir_restritos: + docs = docs.filter(restrito=False) if not docs: return None, None @@ -2981,8 +3029,12 @@ def get_pdf_docacessorios(request, pk): materia = get_object_or_404(MateriaLegislativa, pk=pk) logger = logging.getLogger(__name__) username = 'Usuário anônimo' if request.user.is_anonymous else request.user.username + if request.user.is_anonymous or not 'protocoloadm.change_documentoacessorioadministrativo' in request.user.get_all_permissions(): + excluir_restritos = True + else: + excluir_restritos = False try: - external_name, data = create_pdf_docacessorios(materia) + external_name, data = create_pdf_docacessorios(materia, excluir_restritos) logger.info( "user= {}. Gerou o pdf compilado de documento acessorios".format(username)) except FileNotFoundError: diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 58223f21c..076884efa 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -623,14 +623,22 @@ def __init__(self, *args, **kwargs): class DocumentoAcessorioAdministrativoForm(FileFieldCheckMixin, ModelForm): + restrito = forms.ChoiceField( + label=_('Documento Restrito?'), + widget=forms.RadioSelect(), + choices=YES_NO_CHOICES, + initial=False) + class Meta: model = DocumentoAcessorioAdministrativo fields = ['tipo', 'nome', + 'restrito', 'data', 'autor', 'arquivo', - 'assunto'] + 'assunto', + 'justificativa_restricao'] widgets = { 'data': forms.DateInput(format='%d/%m/%Y') diff --git a/sapl/protocoloadm/migrations/0044_auto_20220923_0946.py b/sapl/protocoloadm/migrations/0044_auto_20220923_0946.py new file mode 100644 index 000000000..75ad59f00 --- /dev/null +++ b/sapl/protocoloadm/migrations/0044_auto_20220923_0946.py @@ -0,0 +1,23 @@ +# Generated by Django 2.2.28 on 2022-09-23 12:46 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('protocoloadm', '0043_auto_20220919_1705'), + ] + + operations = [ + migrations.AddField( + model_name='documentoacessorioadministrativo', + name='justificativa_restricao', + field=models.TextField(blank=True, verbose_name='Justificativa de Restrição'), + ), + migrations.AddField( + model_name='documentoacessorioadministrativo', + name='restrito', + field=models.BooleanField(blank=True, default=False, verbose_name='Restrito'), + ), + ] diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py index 3cdf32735..96735d774 100644 --- a/sapl/protocoloadm/models.py +++ b/sapl/protocoloadm/models.py @@ -362,6 +362,11 @@ class DocumentoAcessorioAdministrativo(models.Model): assunto = models.TextField( blank=True, verbose_name=_('Assunto')) indexacao = models.TextField(blank=True) + restrito = models.BooleanField(default=False, + verbose_name=_('Restrito'), + blank=True) + justificativa_restricao = models.TextField( + blank=True, verbose_name=_('Justificativa de Restrição')) class Meta: verbose_name = _('Documento Acessório') diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 38ffcf42a..bfc697c79 100755 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -398,10 +398,15 @@ def get_success_url(self): class DocumentoAdministrativoMixin: def has_permission(self): + + if self.model == DocumentoAcessorioAdministrativo and 'docadm/' + self.kwargs['pk'] in str(self.request): + doc_adm = DocumentoAdministrativo.objects.get(id=self.kwargs['pk']) + if doc_adm.restrito and not 'protocoloadm.change_documentoacessorioadministrativo' in self.request.user.get_all_permissions(): + return False + app_config = AppConfig.objects.last() if app_config and app_config.documentos_administrativos == 'O': return True - return super().has_permission() @@ -1459,15 +1464,51 @@ class UpdateView(MasterDetailCrud.UpdateView): form_class = DocumentoAcessorioAdministrativoForm class ListView(DocumentoAdministrativoMixin, MasterDetailCrud.ListView): + template_name = "protocoloadm/documentoacessorioadministrativo_list.html" def get_queryset(self): qs = super(MasterDetailCrud.ListView, self).get_queryset() kwargs = {self.crud.parent_field: self.kwargs['pk']} - return qs.filter(**kwargs).order_by('-data', '-id') + exibir_restritos = 'protocoloadm.change_documentoacessorioadministrativo' in self.request.user.get_all_permissions() + if 'o' in self.request.GET: + o = self.request.GET['o'] + indice_field = abs(int(o)) - 1 + if '-' in o: + order_by = '-' + self.list_field_names[indice_field] + else: + order_by = self.list_field_names[indice_field] + if exibir_restritos: + return qs.filter(**kwargs).order_by(order_by, '-data', '-id') + else: + return qs.filter(**kwargs).order_by('restrito', order_by, '-data', '-id') + + if exibir_restritos: + return qs.filter(**kwargs).order_by('-data', '-id') + else: + return qs.filter(**kwargs).order_by('restrito', '-data', '-id') + class DetailView(DocumentoAdministrativoMixin, MasterDetailCrud.DetailView): - pass + layout_key = 'DocumentoAcessorioAdministrativo' + template_name = "protocoloadm/documentoacessorioadministrativo_detail.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['AppConfig'] = sapl.base.models.AppConfig.objects.all().last() + context['user'] = self.request.user + doc_acessorio = DocumentoAcessorioAdministrativo.objects.get( + pk=self.kwargs['pk']) + doc_adm = DocumentoAdministrativo.objects.get( + id=doc_acessorio.documento_id) + if not doc_adm.restrito: + context['doc_adm_restrito'] = False + context['object'] = doc_acessorio + else: + context['doc_adm_restrito'] = True + if (doc_adm.restrito or doc_acessorio.restrito) and not 'protocoloadm.change_documentoacessorioadministrativo' in self.request.user.get_all_permissions(): + context['title'] = 'Documento Restrito' + return context def atualizar_numero_documento(request): diff --git a/sapl/templates/materia/documentoacessorio_detail.html b/sapl/templates/materia/documentoacessorio_detail.html new file mode 100644 index 000000000..1a20cc1cc --- /dev/null +++ b/sapl/templates/materia/documentoacessorio_detail.html @@ -0,0 +1,84 @@ +{% extends "crud/detail_detail.html" %} +{% load i18n common_tags %} +{% load tz %} + +{% block detail_content %} + + {% if not object.restrito or 'materia.change_documentoacessorio' in user.get_all_permissions %} +
+
+
+

{%field_verbose_name object 'tipo'%}

+
+
{{object.tipo}}
+
+
+
+
+
+

{%field_verbose_name object 'autor'%}

+
+
{{object.autor}}
+
+
+
+
+
+
+
+

{%field_verbose_name object 'nome'%}

+
+
{{object.nome}}
+
+
+
+
+
+

{%field_verbose_name object 'data'%}

+
+
{{object.data}}
+
+
+
+
+
+
+
+

{%field_verbose_name object 'arquivo'%}

+
+
+ {% if object.arquivo %} + {{object.arquivo.name}} + {% endif %} +
+
+
+
+
+
+
+
+

{%field_verbose_name object 'restrito'%}

+
+
{% if object.restrito %}Sim{% else %}Não{% endif %}
+
+
+
+
+
+

{%field_verbose_name object 'justificativa_restricao'%}

+
+
{{object.justificativa_restricao}}
+
+
+
+
+ {% else %} +

+ + {% endif %} +{% endblock detail_content %} + diff --git a/sapl/templates/materia/documentoacessorio_list.html b/sapl/templates/materia/documentoacessorio_list.html index 08bae0819..c9d1b6b05 100644 --- a/sapl/templates/materia/documentoacessorio_list.html +++ b/sapl/templates/materia/documentoacessorio_list.html @@ -1,5 +1,68 @@ {% extends "crud/list.html" %} -{% load i18n %} +{% load i18n common_tags %} + +{% block container_table_list %} + {% if not rows %} +

{{ NO_ENTRIES_MSG }}

+ {% else %} +
+
{% blocktrans with verbose_name_plural=view.verbose_name_plural %}Total de {{ verbose_name_plural }}: {{count}}{% endblocktrans %}
+ + + + {% for name in headers %} + + {% endfor %} + + + + {% for doc in object_list %} + + {% if not doc.restrito or 'materia.change_documentoacessorio' in request.user.get_all_permissions %} + + + + + + {% else %} + + {% endif %} + + {% endfor %} + + +
+ {% endif %} +{% endblock container_table_list %} + + {% block base_content %} {{ block.super }}
@@ -10,4 +73,4 @@ {% trans 'Baixar documentos compactados' %}
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/sapl/templates/materia/layouts.yaml b/sapl/templates/materia/layouts.yaml index 202772737..aa6e4561c 100644 --- a/sapl/templates/materia/layouts.yaml +++ b/sapl/templates/materia/layouts.yaml @@ -75,6 +75,8 @@ DocumentoAcessorio: - ementa - indexacao - arquivo + - restrito + - justificativa_restricao Numeracao: {% trans 'Numeração' %}: @@ -165,4 +167,4 @@ ConfigEtiquetaMateriaLegislativa: {% trans 'Configurações de Etiqueta' %}: - largura - altura - - mostrar_em_arquivo \ No newline at end of file + - mostrar_em_arquivo diff --git a/sapl/templates/protocoloadm/documentoacessorioadministrativo_detail.html b/sapl/templates/protocoloadm/documentoacessorioadministrativo_detail.html new file mode 100644 index 000000000..7557a4e77 --- /dev/null +++ b/sapl/templates/protocoloadm/documentoacessorioadministrativo_detail.html @@ -0,0 +1,95 @@ +{% extends "crud/detail_detail.html" %} +{% load i18n common_tags %} +{% load tz %} + +{% block detail_content %} + + {% if not object.restrito and not doc_adm_restrito or 'protocoloadm.change_documentoacessorioadministrativo' in user.get_all_permissions %} +
+
+
+

{%field_verbose_name object 'tipo'%}

+
+
{{object.tipo}}
+
+
+
+
+
+

{%field_verbose_name object 'autor'%}

+
+
{{object.autor}}
+
+
+
+
+
+
+
+

{%field_verbose_name object 'nome'%}

+
+
{{object.nome}}
+
+
+
+
+
+

{%field_verbose_name object 'data'%}

+
+
{{object.data}}
+
+
+
+
+
+
+
+

{%field_verbose_name object 'arquivo'%}

+
+
+ {% if object.arquivo %} + {{object.arquivo.name}} + {% endif %} +
+
+
+
+
+
+
+
+

{%field_verbose_name object 'assunto'%}

+
+
{{object.assunto}}
+
+
+
+
+
+
+
+

{%field_verbose_name object 'restrito'%}

+
+
{% if object.restrito %}Sim{% else %}Não{% endif %}
+
+
+
+
+
+

{%field_verbose_name object 'justificativa_restricao'%}

+
+
{{object.justificativa_restricao}}
+
+
+
+
+ {% else %} +

+ + {% endif %} +{% endblock detail_content %} diff --git a/sapl/templates/protocoloadm/documentoacessorioadministrativo_list.html b/sapl/templates/protocoloadm/documentoacessorioadministrativo_list.html index 6c68a934e..3fa721953 100644 --- a/sapl/templates/protocoloadm/documentoacessorioadministrativo_list.html +++ b/sapl/templates/protocoloadm/documentoacessorioadministrativo_list.html @@ -1,6 +1,66 @@ {% extends "crud/list.html" %} -{% load i18n %} -{% load common_tags %} +{% load i18n common_tags crispy_forms_tags%} + +{% block container_table_list %} + {% if not rows %} +

{{ NO_ENTRIES_MSG }}

+ {% else %} +
+
{% blocktrans with verbose_name_plural=view.verbose_name_plural %}Total de {{ verbose_name_plural }}: {{count}}{% endblocktrans %}
+ + + + {% for name in headers %} + + {% endfor %} + + + + {% for doc in object_list %} + + {% if not doc.restrito or 'protocoloadm.change_documentoacessorioadministrativo' in request.user.get_all_permissions %} + + + + + + {% else %} + + {% endif %} + + {% endfor %} + + +
+ {% endif %} +{% endblock container_table_list %} {% block base_content %} {{ block.super }} @@ -9,4 +69,4 @@ {% trans 'Baixar documentos como PDF único' %} -{% endblock base_content%} \ No newline at end of file +{% endblock base_content%} diff --git a/sapl/templates/protocoloadm/layouts.yaml b/sapl/templates/protocoloadm/layouts.yaml index cbfe3210f..b08ef9997 100644 --- a/sapl/templates/protocoloadm/layouts.yaml +++ b/sapl/templates/protocoloadm/layouts.yaml @@ -24,6 +24,8 @@ DocumentoAcessorioAdministrativo: - nome data - arquivo - assunto + - restrito + - justificativa_restricao StatusTramitacaoAdministrativo: {% trans 'Status Tramitação Administrativo' %}: