From 9515c049a50d70c68d7838258bdf3c8123fb9264 Mon Sep 17 00:00:00 2001 From: Cesar Augusto de Carvalho Date: Mon, 29 Apr 2019 14:12:47 -0300 Subject: [PATCH] =?UTF-8?q?Fix=20#2720=20-=20Adiciona=20usu=C3=A1rios=20?= =?UTF-8?q?=C3=A0s=20tramita=C3=A7=C3=B5es=20(#2736)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Fix 2720 - Adiciona usuarios em tramitacoes * Corrige os testes * adicionar visualizacao para superusers * adiciona ip e user para docadm * corrige migrations * Adiciona tela usuario em DocAdm e correcoes de testes * Apenas atualiza o usuario e ip na edicao se houve alteracao --- sapl/materia/forms.py | 46 +++++++++++++------ .../migrations/0046_auto_20190417_1212.py | 28 +++++++++++ .../migrations/0048_merge_20190426_0828.py | 16 +++++++ sapl/materia/models.py | 11 ++++- sapl/materia/views.py | 26 +++++++++-- sapl/protocoloadm/forms.py | 41 ++++++++++++----- .../migrations/0019_auto_20190426_0833.py | 28 +++++++++++ sapl/protocoloadm/models.py | 12 ++++- sapl/protocoloadm/tests/test_protocoloadm.py | 2 +- sapl/protocoloadm/views.py | 18 +++++++- sapl/templates/materia/tramitacao_detail.html | 38 +++++++++++++++ .../tramitacaoadministrativo_detail.html | 37 +++++++++++++++ 12 files changed, 270 insertions(+), 33 deletions(-) create mode 100644 sapl/materia/migrations/0046_auto_20190417_1212.py create mode 100644 sapl/materia/migrations/0048_merge_20190426_0828.py create mode 100644 sapl/protocoloadm/migrations/0019_auto_20190426_0833.py create mode 100644 sapl/templates/materia/tramitacao_detail.html diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 27b1250af..82dd8248a 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -461,7 +461,11 @@ class TramitacaoForm(ModelForm): 'unidade_tramitacao_destino', 'data_encaminhamento', 'data_fim_prazo', - 'texto'] + 'texto', + 'user', + 'ip'] + widgets = {'user': forms.HiddenInput(), + 'ip': forms.HiddenInput()} def __init__(self, *args, **kwargs): super(TramitacaoForm, self).__init__(*args, **kwargs) @@ -580,11 +584,15 @@ class TramitacaoUpdateForm(TramitacaoForm): 'data_encaminhamento', 'data_fim_prazo', 'texto', + 'user', + 'ip' ] widgets = { 'data_encaminhamento': forms.DateInput(format='%d/%m/%Y'), 'data_fim_prazo': forms.DateInput(format='%d/%m/%Y'), + 'user': forms.HiddenInput(), + 'ip': forms.HiddenInput() } def clean(self): @@ -593,32 +601,44 @@ class TramitacaoUpdateForm(TramitacaoForm): if not self.is_valid(): return self.cleaned_data + cd = self.cleaned_data + obj = self.instance + ultima_tramitacao = Tramitacao.objects.filter( - materia_id=self.instance.materia_id).order_by( + materia_id=obj.materia_id).order_by( '-data_tramitacao', '-id').first() # Se a Tramitação que está sendo editada não for a mais recente, # ela não pode ter seu destino alterado. - if ultima_tramitacao != self.instance: - if self.cleaned_data['unidade_tramitacao_destino'] != \ - self.instance.unidade_tramitacao_destino: + if ultima_tramitacao != obj: + if cd['unidade_tramitacao_destino'] != \ + obj.unidade_tramitacao_destino: self.logger.error("Você não pode mudar a Unidade de Destino desta " "tramitação para {}, pois irá conflitar com a Unidade " "Local da tramitação seguinte ({})." - .format(self.cleaned_data['unidade_tramitacao_destino'], - self.instance.unidade_tramitacao_destino)) + .format(cd['unidade_tramitacao_destino'], + obj.unidade_tramitacao_destino)) raise ValidationError( 'Você não pode mudar a Unidade de Destino desta ' 'tramitação, pois irá conflitar com a Unidade ' 'Local da tramitação seguinte') + + # Se não houve qualquer alteração em um dos dados, mantém o usuário e ip + if not (cd['data_tramitacao'] != obj.data_tramitacao or \ + cd['unidade_tramitacao_destino'] != obj.unidade_tramitacao_destino or \ + cd['status'] != obj.status or cd['texto'] != obj.texto or \ + cd['data_encaminhamento'] != obj.data_encaminhamento or \ + cd['data_fim_prazo'] != obj.data_fim_prazo or \ + cd['urgente'] != obj.urgente or \ + cd['turno'] != obj.turno): + cd['user'] = obj.user + cd['ip'] = obj.ip + + cd['data_tramitacao'] = obj.data_tramitacao + cd['unidade_tramitacao_local'] = obj.unidade_tramitacao_local - self.cleaned_data['data_tramitacao'] = \ - self.instance.data_tramitacao - self.cleaned_data['unidade_tramitacao_local'] = \ - self.instance.unidade_tramitacao_local - - return self.cleaned_data + return cd class LegislacaoCitadaForm(ModelForm): diff --git a/sapl/materia/migrations/0046_auto_20190417_1212.py b/sapl/materia/migrations/0046_auto_20190417_1212.py new file mode 100644 index 000000000..397114479 --- /dev/null +++ b/sapl/materia/migrations/0046_auto_20190417_1212.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-04-17 15:12 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('materia', '0045_auto_20190415_1050'), + ] + + operations = [ + migrations.AddField( + model_name='tramitacao', + name='ip', + field=models.CharField(blank=True, default='', max_length=30, verbose_name='IP'), + ), + migrations.AddField( + model_name='tramitacao', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='Usuário'), + ), + ] diff --git a/sapl/materia/migrations/0048_merge_20190426_0828.py b/sapl/materia/migrations/0048_merge_20190426_0828.py new file mode 100644 index 000000000..94d624b1d --- /dev/null +++ b/sapl/materia/migrations/0048_merge_20190426_0828.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-04-26 11:28 +from __future__ import unicode_literals + +from django.db import migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0046_auto_20190417_1212'), + ('materia', '0047_auto_20190417_1432'), + ] + + operations = [ + ] diff --git a/sapl/materia/models.py b/sapl/materia/models.py index db535e406..aad491b01 100644 --- a/sapl/materia/models.py +++ b/sapl/materia/models.py @@ -18,7 +18,7 @@ from sapl.parlamentares.models import Parlamentar #from sapl.protocoloadm.models import Protocolo from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, SaplGenericForeignKey, SaplGenericRelation, restringe_tipos_de_arquivo_txt, - texto_upload_path) + texto_upload_path, get_settings_auth_user_model) EM_TRAMITACAO = [(1, 'Sim'), @@ -1003,6 +1003,15 @@ class Tramitacao(models.Model): texto = models.TextField(verbose_name=_('Texto da Ação')) data_fim_prazo = models.DateField( blank=True, null=True, verbose_name=_('Data Fim Prazo')) + user = models.ForeignKey(get_settings_auth_user_model(), + verbose_name=_('Usuário'), + on_delete=models.PROTECT, + null=True, + blank=True) + ip = models.CharField(verbose_name=_('IP'), + max_length=30, + blank=True, + default='') class Meta: verbose_name = _('Tramitação') diff --git a/sapl/materia/views.py b/sapl/materia/views.py index e7a730c8f..a65746ee0 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -53,7 +53,7 @@ from sapl.parlamentares.models import Legislatura from sapl.protocoloadm.models import Protocolo from sapl.settings import MEDIA_ROOT from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, SEPARADOR_HASH_PROPOSICAO, - gerar_hash_arquivo, get_base_url, + gerar_hash_arquivo, get_base_url, get_client_ip, get_mime_type_from_file_extension, montar_row_autor, show_results_filter_set, mail_service_configured) @@ -1189,6 +1189,8 @@ class TramitacaoCrud(MasterDetailCrud): else: initial['unidade_tramitacao_local'] = '' initial['data_tramitacao'] = timezone.now().date() + initial['ip'] = get_client_ip(self.request) + initial['user'] = self.request.user return initial def get_context_data(self, **kwargs): @@ -1234,7 +1236,6 @@ class TramitacaoCrud(MasterDetailCrud): post=self.object, request=self.request) except Exception as e: - # TODO log error msg = _('Tramitação criada, mas e-mail de acompanhamento ' 'de matéria não enviado. Há problemas na configuração ' 'do e-mail.') @@ -1251,6 +1252,12 @@ class TramitacaoCrud(MasterDetailCrud): layout_key = 'TramitacaoUpdate' + def get_initial(self): + initial = super(UpdateView, self).get_initial() + initial['ip'] = get_client_ip(self.request) + initial['user'] = self.request.user + return initial + def form_valid(self, form): self.object = form.save() username = self.request.user.username @@ -1316,6 +1323,15 @@ class TramitacaoCrud(MasterDetailCrud): tramitacao.delete() return HttpResponseRedirect(url) + class DetailView(MasterDetailCrud.DetailView): + + template_name = "materia/tramitacao_detail.html" + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['user'] = self.request.user + return context + def montar_helper_documento_acessorio(self): autor_row = montar_row_autor('autor') @@ -2273,6 +2289,8 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) + user = request.user + ip = get_client_ip(request) t = Tramitacao( materia=materia, data_tramitacao=data_tramitacao, @@ -2285,7 +2303,9 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): urgente=urgente, status_id=request.POST['status'], turno=request.POST['turno'], - texto=request.POST['texto'] + texto=request.POST['texto'], + user=user, + ip=ip ) t.save() try: diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 43f410847..3f237f18f 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -654,7 +654,11 @@ class TramitacaoAdmForm(ModelForm): 'data_encaminhamento', 'data_fim_prazo', 'texto', - ] + 'user', + 'ip'] + widgets = {'user': forms.HiddenInput(), + 'ip': forms.HiddenInput()} + def clean(self): cleaned_data = super(TramitacaoAdmForm, self).clean() @@ -747,7 +751,10 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm): 'data_encaminhamento', 'data_fim_prazo', 'texto', - ] + 'user', + 'ip'] + widgets = {'user': forms.HiddenInput(), + 'ip': forms.HiddenInput()} def clean(self): super(TramitacaoAdmEditForm, self).clean() @@ -755,30 +762,40 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm): if not self.is_valid(): return self.cleaned_data + cd = self.cleaned_data + obj = self.instance + ultima_tramitacao = TramitacaoAdministrativo.objects.filter( - documento_id=self.instance.documento_id).order_by( + documento_id=obj.documento_id).order_by( '-data_tramitacao', '-id').first() # Se a Tramitação que está sendo editada não for a mais recente, # ela não pode ter seu destino alterado. - if ultima_tramitacao != self.instance: - if self.cleaned_data['unidade_tramitacao_destino'] != \ - self.instance.unidade_tramitacao_destino: + if ultima_tramitacao != obj: + if cd['unidade_tramitacao_destino'] != \ + obj.unidade_tramitacao_destino: self.logger.error('Você não pode mudar a Unidade de Destino desta ' 'tramitação (id={}), pois irá conflitar com a Unidade ' - 'Local da tramitação seguinte'.format(self.instance.documento_id)) + 'Local da tramitação seguinte'.format(obj.documento_id)) raise ValidationError( 'Você não pode mudar a Unidade de Destino desta ' 'tramitação, pois irá conflitar com a Unidade ' 'Local da tramitação seguinte') - self.cleaned_data['data_tramitacao'] = \ - self.instance.data_tramitacao - self.cleaned_data['unidade_tramitacao_local'] = \ - self.instance.unidade_tramitacao_local + # Se não houve qualquer alteração em um dos dados, mantém o usuário e ip + if not (cd['data_tramitacao'] != obj.data_tramitacao or \ + cd['unidade_tramitacao_destino'] != obj.unidade_tramitacao_destino or \ + cd['status'] != obj.status or cd['texto'] != obj.texto or \ + cd['data_encaminhamento'] != obj.data_encaminhamento or \ + cd['data_fim_prazo'] != obj.data_fim_prazo): + cd['user'] = obj.user + cd['ip'] = obj.ip - return self.cleaned_data + cd['data_tramitacao'] = obj.data_tramitacao + cd['unidade_tramitacao_local'] = obj.unidade_tramitacao_local + + return cd class AnexadoForm(ModelForm): diff --git a/sapl/protocoloadm/migrations/0019_auto_20190426_0833.py b/sapl/protocoloadm/migrations/0019_auto_20190426_0833.py new file mode 100644 index 000000000..edfdd8904 --- /dev/null +++ b/sapl/protocoloadm/migrations/0019_auto_20190426_0833.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.20 on 2019-04-26 11:33 +from __future__ import unicode_literals + +from django.conf import settings +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ('protocoloadm', '0018_auto_20190314_1532'), + ] + + operations = [ + migrations.AddField( + model_name='tramitacaoadministrativo', + name='ip', + field=models.CharField(blank=True, default='', max_length=30, verbose_name='IP'), + ), + migrations.AddField( + model_name='tramitacaoadministrativo', + name='user', + field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to=settings.AUTH_USER_MODEL, verbose_name='Usuário'), + ), + ] diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py index f792a9cdb..28b11f2cc 100644 --- a/sapl/protocoloadm/models.py +++ b/sapl/protocoloadm/models.py @@ -6,7 +6,8 @@ import reversion from sapl.base.models import Autor from sapl.materia.models import TipoMateriaLegislativa, UnidadeTramitacao -from sapl.utils import RANGE_ANOS, YES_NO_CHOICES, texto_upload_path +from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, texto_upload_path, + get_settings_auth_user_model) @reversion.register() @@ -318,6 +319,15 @@ class TramitacaoAdministrativo(models.Model): blank=True, verbose_name=_('Texto da Ação')) data_fim_prazo = models.DateField( blank=True, null=True, verbose_name=_('Data Fim do Prazo')) + user = models.ForeignKey(get_settings_auth_user_model(), + verbose_name=_('Usuário'), + on_delete=models.PROTECT, + null=True, + blank=True) + ip = models.CharField(verbose_name=_('IP'), + max_length=30, + blank=True, + default='') class Meta: verbose_name = _('Tramitação de Documento Administrativo') diff --git a/sapl/protocoloadm/tests/test_protocoloadm.py b/sapl/protocoloadm/tests/test_protocoloadm.py index f3c167288..cfe68fcd1 100644 --- a/sapl/protocoloadm/tests/test_protocoloadm.py +++ b/sapl/protocoloadm/tests/test_protocoloadm.py @@ -162,7 +162,7 @@ def test_create_tramitacao(admin_client): msg = force_text(_('A origem da nova tramitação deve ser igual ao ' 'destino da última adicionada!')) - + # Verifica se a origem da nova tramitacao é igual ao destino da última assert msg in response.context_data[ 'form'].errors['__all__'] diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 0b0ee4546..fa00e171d 100755 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -1116,6 +1116,8 @@ class TramitacaoAdmCrud(MasterDetailCrud): else: initial['unidade_tramitacao_local'] = '' initial['data_tramitacao'] = timezone.now().date() + initial['ip'] = get_client_ip(self.request) + initial['user'] = self.request.user return initial def get_context_data(self, **kwargs): @@ -1154,6 +1156,12 @@ class TramitacaoAdmCrud(MasterDetailCrud): form_class = TramitacaoAdmEditForm logger = logging.getLogger(__name__) + def get_initial(self): + initial = super(UpdateView, self).get_initial() + initial['ip'] = get_client_ip(self.request) + initial['user'] = self.request.user + return initial + def form_valid(self, form): self.object = form.save() username = self.request.user.username @@ -1162,7 +1170,6 @@ class TramitacaoAdmCrud(MasterDetailCrud): post=self.object, request=self.request) except Exception as e: - # TODO log error self.logger.error('user=' + username + '. Tramitação criada, mas e-mail de acompanhamento de documento ' 'não enviado. A não configuração do servidor de e-mail ' 'impede o envio de aviso de tramitação. ' + str(e)) @@ -1183,7 +1190,14 @@ class TramitacaoAdmCrud(MasterDetailCrud): class DetailView(DocumentoAdministrativoMixin, MasterDetailCrud.DetailView): - pass + + template_name = 'protocoloadm/tramitacaoadministrativo_detail.html' + + def get_context_data(self, **kwargs): + context = super().get_context_data(**kwargs) + context['user'] = self.request.user + return context + class DeleteView(MasterDetailCrud.DeleteView): diff --git a/sapl/templates/materia/tramitacao_detail.html b/sapl/templates/materia/tramitacao_detail.html new file mode 100644 index 000000000..4aaca09b6 --- /dev/null +++ b/sapl/templates/materia/tramitacao_detail.html @@ -0,0 +1,38 @@ +{% extends "crud/detail.html" %} +{% load i18n %} + +{% block detail_content %} + {{ block.super }} + {% if user.is_superuser %} +
+ {% if tramitacao.user %} +
+
+

Usuário

+
+ +
+
+
+ {% endif %} + {% if tramitacao.ip %} +
+
+

IP

+
+
+
+ {{tramitacao.ip}} +
+
+
+
+
+ {% endif %} +
+ {% endif %} +{% endblock detail_content %} \ No newline at end of file diff --git a/sapl/templates/protocoloadm/tramitacaoadministrativo_detail.html b/sapl/templates/protocoloadm/tramitacaoadministrativo_detail.html index 3131bc4be..20e2289c9 100644 --- a/sapl/templates/protocoloadm/tramitacaoadministrativo_detail.html +++ b/sapl/templates/protocoloadm/tramitacaoadministrativo_detail.html @@ -1,5 +1,6 @@ {% extends "crud/detail.html" %} {% load i18n %} + {% block actions %} {% load common_tags %} @@ -13,3 +14,39 @@ {% endif %} {% endblock actions %} + +{% block detail_content %} + {{ block.super }} + {% if user.is_superuser %} +
+ {% if tramitacaoadministrativo.user %} +
+
+

Usuário

+ +
+
+ {% endif %} + {% if tramitacaoadministrativo.ip %} +
+
+

IP

+
+
+
+ {{tramitacaoadministrativo.ip}} +
+
+
+
+
+ {% endif %} +
+ {% endif %} +{% endblock detail_content %}