diff --git a/sapl/base/receivers.py b/sapl/base/receivers.py index 5685c5c15..41490c5c7 100644 --- a/sapl/base/receivers.py +++ b/sapl/base/receivers.py @@ -1,13 +1,15 @@ +import inspect import logging +from django.conf import settings from django.core import serializers -from django.db.models.signals import post_delete +from django.db.models.signals import post_delete, post_save from django.dispatch import receiver from django.utils import timezone from sapl.base.email_utils import do_envia_email_tramitacao from sapl.base.models import AuditLog -from sapl.base.signals import tramitacao_signal, post_delete_signal, post_save_signal +from sapl.base.signals import tramitacao_signal from sapl.materia.models import Tramitacao from sapl.protocoloadm.models import TramitacaoAdministrativo from sapl.utils import get_base_url @@ -46,28 +48,53 @@ def status_tramitacao_materia(sender, instance, **kwargs): documento.save() -@receiver(post_delete_signal) -@receiver(post_save_signal) -def audit_log(sender, **kwargs): - logger = logging.getLogger(__name__) +def audit_log_function(sender, **kwargs): + + try: + if not sender._meta.app_config.name.startswith('sapl'): + return + except: + # não é necessário usar logger, aqui é usada apenas para + # eliminar um o if complexo + return instance = kwargs.get('instance') - operation = kwargs.get('operation') - user = kwargs.get('request').user - model_name = instance.__class__.__name__ - app_name = instance._meta.app_label - object_id = instance.id - data = serializers.serialize('json', [instance]) + if instance._meta.model == AuditLog: + return - if len(data) > AuditLog.MAX_DATA_LENGTH: - data = data[:AuditLog.MAX_DATA_LENGTH] + logger = logging.getLogger(__name__) - if user: - username = user.username - else: - username = '' + u = None + pilha_de_execucao = inspect.stack() + for i in pilha_de_execucao: + if i.function == 'migrate': + return + r = i.frame.f_locals.get('request', None) + try: + if r.user._meta.label == settings.AUTH_USER_MODEL: + u = r.user + break + except: + # não é necessário usar logger, aqui é usada apenas para + # eliminar um o if complexo + pass try: + operation = kwargs.get('operation') + user = u + model_name = instance.__class__.__name__ + app_name = instance._meta.app_label + object_id = instance.id + data = serializers.serialize('json', [instance]) + + if len(data) > AuditLog.MAX_DATA_LENGTH: + data = data[:AuditLog.MAX_DATA_LENGTH] + + if user: + username = user.username + else: + username = '' + AuditLog.objects.create(username=username, operation=operation, model_name=model_name, @@ -78,3 +105,14 @@ def audit_log(sender, **kwargs): except Exception as e: logger.error('Error saving auditing log object') logger.error(e) + + +@receiver(post_delete) +def audit_log_post_delete(sender, **kwargs): + audit_log_function(sender, operation='D', **kwargs) + + +@receiver(post_save) +def audit_log_post_save(sender, **kwargs): + operation = 'C' if kwargs.get('created') else 'U' + audit_log_function(sender, operation=operation, **kwargs) diff --git a/sapl/base/signals.py b/sapl/base/signals.py index a2caf67df..b2cda2028 100644 --- a/sapl/base/signals.py +++ b/sapl/base/signals.py @@ -46,6 +46,3 @@ def cria_models_tipo_autor(app_config=None, verbosity=2, interactive=True, post_migrate.connect(receiver=cria_models_tipo_autor) -post_delete_signal = django.dispatch.Signal(providing_args=['instance', 'request']) - -post_save_signal = django.dispatch.Signal(providing_args=['instance', 'operation', 'request']) diff --git a/sapl/crud/base.py b/sapl/crud/base.py index 5306076a6..7dc872216 100644 --- a/sapl/crud/base.py +++ b/sapl/crud/base.py @@ -22,7 +22,6 @@ from django.views.generic import (CreateView, DeleteView, DetailView, ListView, from django.views.generic.base import ContextMixin from django.views.generic.list import MultipleObjectMixin -from sapl.base.signals import post_delete_signal, post_save_signal from sapl.crispy_layout_mixin import CrispyLayoutFormMixin, get_field_display from sapl.crispy_layout_mixin import SaplFormHelper from sapl.rules.map_rules import (RP_ADD, RP_CHANGE, RP_DELETE, RP_DETAIL, @@ -626,37 +625,8 @@ class CrudListView(PermissionRequiredContainerCrudMixin, ListView): return queryset -class AuditLogMixin(object): - - def delete(self, request, *args, **kwargs): - # Classe deve implementar um get_object(), i.e., deve ser uma View - deleted_object = self.get_object() - try: - return super(AuditLogMixin, self).delete(request, args, kwargs) - finally: - post_delete_signal.send(sender=None, - instance=deleted_object, - operation='D', - request=self.request) - - # SAVE/UPDATE method - def form_valid(self, form): - try: - if not form.instance.pk: - operation = 'C' - else: - operation = 'U' - return super(AuditLogMixin, self).form_valid(form) - finally: - post_save_signal.send(sender=None, - instance=form.instance, - operation=operation, - request=self.request - ) - - class CrudCreateView(PermissionRequiredContainerCrudMixin, - FormMessagesMixin, AuditLogMixin, CreateView): + FormMessagesMixin, CreateView): permission_required = (RP_ADD,) logger = logging.getLogger(__name__) @@ -874,7 +844,7 @@ class CrudDetailView(PermissionRequiredContainerCrudMixin, class CrudUpdateView(PermissionRequiredContainerCrudMixin, - FormMessagesMixin, AuditLogMixin, UpdateView): + FormMessagesMixin, UpdateView): permission_required = (RP_CHANGE,) logger = logging.getLogger(__name__) @@ -905,7 +875,7 @@ class CrudUpdateView(PermissionRequiredContainerCrudMixin, class CrudDeleteView(PermissionRequiredContainerCrudMixin, - FormMessagesMixin, AuditLogMixin, DeleteView): + FormMessagesMixin, DeleteView): permission_required = (RP_DELETE,) logger = logging.getLogger(__name__) diff --git a/sapl/materia/forms.py b/sapl/materia/forms.py index 1bd594ab0..66d56af04 100644 --- a/sapl/materia/forms.py +++ b/sapl/materia/forms.py @@ -1,30 +1,28 @@ -import django_filters import logging import os -import sapl from crispy_forms.bootstrap import Alert, InlineRadios from crispy_forms.layout import (Button, Field, Fieldset, HTML, Layout, Row) - from django import forms from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist, ValidationError from django.core.files.base import File -from django.urls import reverse from django.db import models, transaction from django.db.models import F, Max, Q from django.forms import ModelChoiceField, ModelForm, widgets from django.forms.forms import Form from django.forms.models import ModelMultipleChoiceField from django.forms.widgets import CheckboxSelectMultiple, HiddenInput, Select +from django.urls import reverse from django.utils import timezone from django.utils.encoding import force_text from django.utils.html import format_html from django.utils.safestring import mark_safe from django.utils.translation import ugettext_lazy as _ +import django_filters +import sapl from sapl.base.models import AppConfig, Autor, TipoAutor -from sapl.base.signals import post_save_signal from sapl.comissoes.models import Comissao, Composicao, Participacao from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_PUBLIC, STATUS_TA_PRIVATE) @@ -34,8 +32,8 @@ from sapl.materia.models import (AssuntoMateria, Autoria, MateriaAssunto, MateriaLegislativa, Orgao, RegimeTramitacao, StatusTramitacao, TipoDocumento, TipoProposicao, - UnidadeTramitacao,ConfigEtiquetaMateriaLegislativa) -from sapl.norma.models import (LegislacaoCitada, NormaJuridica, + UnidadeTramitacao, ConfigEtiquetaMateriaLegislativa) +from sapl.norma.models import (LegislacaoCitada, NormaJuridica, TipoNormaJuridica) from sapl.parlamentares.models import Legislatura, Partido, Parlamentar from sapl.protocoloadm.models import (Anexado, DocumentoAdministrativo, @@ -211,8 +209,10 @@ class MateriaLegislativaForm(FileFieldCheckMixin, ModelForm): if protocolo: if not Protocolo.objects.filter(numero=protocolo, ano=ano).exists(): - self.logger.warning("Protocolo %s/%s não existe" % (protocolo, ano)) - raise ValidationError(_('Protocolo %s/%s não existe' % (protocolo, ano))) + self.logger.warning( + "Protocolo %s/%s não existe" % (protocolo, ano)) + raise ValidationError( + _('Protocolo %s/%s não existe' % (protocolo, ano))) if protocolo_antigo != protocolo: exist_materia = MateriaLegislativa.objects.filter( @@ -472,7 +472,7 @@ class TramitacaoForm(ModelForm): 'user', 'ip', 'ultima_edicao'] - + widgets = {'user': forms.HiddenInput(), 'ip': forms.HiddenInput(), 'ultima_edicao': forms.HiddenInput()} @@ -525,7 +525,8 @@ class TramitacaoForm(ModelForm): if cleaned_data['data_tramitacao'] > timezone.now().date(): self.logger.warning('A data de tramitação informada ({}) não é menor ou igual a data de hoje!' .format(cleaned_data['data_tramitacao'])) - msg = _('A data de tramitação deve ser menor ou igual a data de hoje!') + msg = _( + 'A data de tramitação deve ser menor ou igual a data de hoje!') raise ValidationError(msg) if (ultima_tramitacao and @@ -539,9 +540,10 @@ class TramitacaoForm(ModelForm): if data_enc_form: if data_enc_form < data_tram_form: - msg = _('A data de encaminhamento deve ser maior que a data de tramitação!') + msg = _( + 'A data de encaminhamento deve ser maior que a data de tramitação!') self.logger.warning("A data de encaminhamento ({}) deve ser maior que a data de tramitação! ({})" - .format(data_enc_form, data_tram_form)) + .format(data_enc_form, data_tram_form)) raise ValidationError(msg) if data_prazo_form: @@ -668,14 +670,15 @@ class TramitacaoUpdateForm(TramitacaoForm): 'Você não pode mudar a Unidade de Destino desta ' 'tramitação, pois irá conflitar com a Unidade ' 'Local da tramitação seguinte') - - 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'] != str(obj.urgente) or \ - cd['turno'] != obj.turno): - ### Se não ocorreram alterações, o usuário, ip, data e hora da última edição (real) são mantidos + + 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'] != str(obj.urgente) or + cd['turno'] != obj.turno): + # Se não ocorreram alterações, o usuário, ip, data e hora da última + # edição (real) são mantidos cd['user'] = obj.user cd['ip'] = obj.ip cd['ultima_edicao'] = obj.ultima_edicao @@ -698,7 +701,8 @@ class TramitacaoUpdateForm(TramitacaoForm): if tramitar_anexadas: anexadas_list = lista_anexados(materia) for ma in anexadas_list: - tram_anexada = ma.tramitacao_set.order_by('-data_tramitacao', '-id').first() + tram_anexada = ma.tramitacao_set.order_by( + '-data_tramitacao', '-id').first() if compara_tramitacoes_mat(ant_tram_principal, tram_anexada): tram_anexada.status = nova_tram_principal.status tram_anexada.data_tramitacao = nova_tram_principal.data_tramitacao @@ -907,7 +911,8 @@ class AnexadaForm(ModelForm): except ObjectDoesNotExist: msg = _('A {} {}/{} não existe no cadastro de matérias legislativas.' .format(cleaned_data['tipo'], cleaned_data['numero'], cleaned_data['ano'])) - self.logger.warning("A matéria a ser anexada não existe no cadastro de matérias legislativas.") + self.logger.warning( + "A matéria a ser anexada não existe no cadastro de matérias legislativas.") raise ValidationError(msg) materia_principal = self.instance.materia_principal @@ -1118,7 +1123,7 @@ class MateriaLegislativaFilterSet(django_filters.FilterSet): ), Fieldset(_('Origem externa'), row10, row11 - ), + ), Fieldset(_('Pesquisa Avançada'), row3, HTML(autor_label), @@ -1644,7 +1649,6 @@ class TramitacaoEmLoteForm(ModelForm): widgets = {'user': forms.HiddenInput(), 'ip': forms.HiddenInput(), 'ultima_edicao': forms.HiddenInput()} - def __init__(self, *args, **kwargs): super(TramitacaoEmLoteForm, self).__init__(*args, **kwargs) @@ -1746,7 +1750,8 @@ class TramitacaoEmLoteForm(ModelForm): if data_enc_form < data_tram_form: self.logger.warning('A data de encaminhamento ({}) deve ser maior que a data de tramitação ({})!' .format(data_enc_form, data_tram_form)) - msg = _('A data de encaminhamento deve ser maior que a data de tramitação!') + msg = _( + 'A data de encaminhamento deve ser maior que a data de tramitação!') raise ValidationError(msg) if data_prazo_form: @@ -1763,7 +1768,7 @@ class TramitacaoEmLoteForm(ModelForm): @transaction.atomic def save(self, commit=True): cd = self.cleaned_data - + materias = self.initial['materias'] user = self.initial['user'] if 'user' in self.initial else None ip = self.initial['ip'] if 'ip' in self.initial else '' @@ -2555,7 +2560,8 @@ class ConfirmarProposicaoForm(ProposicaoForm): data_fim__year__gte=timezone.now().year).first() ano_inicio = legislatura.data_inicio.year ano_fim = legislatura.data_fim.year - nm = Protocolo.objects.filter(ano__gte=ano_inicio, ano__lte=ano_fim).aggregate(Max('numero')) + nm = Protocolo.objects.filter( + ano__gte=ano_inicio, ano__lte=ano_fim).aggregate(Max('numero')) else: # numeracao == 'U' ou não informada nm = Protocolo.objects.all().aggregate(Max('numero')) @@ -2923,9 +2929,8 @@ class MateriaPesquisaSimplesForm(forms.Form): return cleaned_data + class ConfigEtiquetaMateriaLegislativaForms(ModelForm): class Meta: model = ConfigEtiquetaMateriaLegislativa fields = '__all__' - - \ No newline at end of file diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 2545064ad..b630bc164 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -1,46 +1,43 @@ +from datetime import datetime +from datetime import datetime +from io import BytesIO import itertools import logging import os -import sapl +from random import choice import shutil +from string import ascii_letters, digits import tempfile -import weasyprint import time - -from crispy_forms.layout import HTML -from datetime import datetime -from random import choice -from string import ascii_letters, digits -from datetime import datetime -from PyPDF4 import PdfFileReader, PdfFileMerger import zipfile -from io import BytesIO +from PyPDF4 import PdfFileReader, PdfFileMerger +from crispy_forms.layout import HTML from django.conf import settings from django.contrib import messages from django.contrib.auth.decorators import permission_required from django.contrib.auth.mixins import PermissionRequiredMixin from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned, ValidationError -from django.urls import reverse from django.db.models import Max, Q from django.http import HttpResponse, JsonResponse from django.http.response import Http404, HttpResponseRedirect from django.shortcuts import get_object_or_404, redirect +from django.shortcuts import render from django.template import loader, RequestContext +from django.urls import reverse from django.utils import formats, timezone from django.utils.translation import ugettext_lazy as _ from django.views.generic import CreateView, ListView, TemplateView, UpdateView from django.views.generic.base import RedirectView from django.views.generic.edit import FormView -from django.shortcuts import render - - from django_filters.views import FilterView +import weasyprint +import sapl from sapl.base.email_utils import do_envia_email_confirmacao from sapl.base.models import Autor, CasaLegislativa, AppConfig as BaseAppConfig -from sapl.base.signals import tramitacao_signal, post_delete_signal, post_save_signal +from sapl.base.signals import tramitacao_signal from sapl.comissoes.models import Comissao, Participacao, Composicao from sapl.compilacao.models import STATUS_TA_IMMUTABLE_RESTRICT, STATUS_TA_PRIVATE from sapl.compilacao.views import IntegracaoTaView @@ -51,7 +48,7 @@ from sapl.materia.forms import (AnexadaForm, AutoriaForm, AutoriaMultiCreateForm ConfirmarProposicaoForm, DevolverProposicaoForm, DespachoInicialCreateForm, LegislacaoCitadaForm, MateriaPesquisaSimplesForm, OrgaoForm, ProposicaoForm, - TipoProposicaoForm, TramitacaoForm, TramitacaoUpdateForm,ConfigEtiquetaMateriaLegislativaForms) + TipoProposicaoForm, TramitacaoForm, TramitacaoUpdateForm, ConfigEtiquetaMateriaLegislativaForms) from sapl.norma.models import LegislacaoCitada from sapl.parlamentares.models import Legislatura from sapl.protocoloadm.models import Protocolo @@ -59,7 +56,7 @@ from sapl.settings import MAX_DOC_UPLOAD_SIZE, MEDIA_ROOT from sapl.utils import (autor_label, autor_modal, gerar_hash_arquivo, get_base_url, get_client_ip, get_mime_type_from_file_extension, lista_anexados, mail_service_configured, montar_row_autor, SEPARADOR_HASH_PROPOSICAO, - show_results_filter_set, YES_NO_CHOICES,get_tempfile_dir) + show_results_filter_set, YES_NO_CHOICES, get_tempfile_dir) from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, AnexadaEmLoteFilterSet, AdicionarVariasAutoriasFilterSet, @@ -75,7 +72,7 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, De DocumentoAcessorio, MateriaAssunto, MateriaLegislativa, Numeracao, Orgao, Origem, Proposicao, RegimeTramitacao, Relatoria, StatusTramitacao, TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao, - Tramitacao, UnidadeTramitacao,ConfigEtiquetaMateriaLegislativa) + Tramitacao, UnidadeTramitacao, ConfigEtiquetaMateriaLegislativa) AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia') @@ -230,16 +227,16 @@ class CriarProtocoloMateriaView(CreateView): return context def form_valid(self, form): - materia = form.save() + materia = form.save() materia.user = self.request.user materia.ip = get_client_ip(self.request) - + tz = timezone.get_current_timezone() materia.ultima_edicao = tz.localize(datetime.now()) - + materia.save() - + username = self.request.user.username try: @@ -787,7 +784,7 @@ class ProposicaoCrud(Crud): context['title'] = '%s (%s)' % ( self.object, self.object.autor) - + context['user'] = self.request.user context['proposicao'] = Proposicao.objects.get( pk=self.kwargs['pk'] @@ -812,7 +809,8 @@ class ProposicaoCrud(Crud): elif p.data_envio: msg_error = _('Proposição já foi enviada.') elif not p.texto_original and not p.texto_articulado.exists(): - msg_error = _('Proposição não possui nenhum tipo de Texto associado.') + msg_error = _( + 'Proposição não possui nenhum tipo de Texto associado.') else: if p.texto_articulado.exists(): ta = p.texto_articulado.first() @@ -820,7 +818,8 @@ class ProposicaoCrud(Crud): ta.editing_locked = True ta.save() - receber_recibo = BaseAppConfig.attr('receber_recibo_proposicao') + receber_recibo = BaseAppConfig.attr( + 'receber_recibo_proposicao') if not receber_recibo: ta = p.texto_articulado.first() @@ -830,7 +829,8 @@ class ProposicaoCrud(Crud): p.data_envio = timezone.now() p.save() - messages.success(request, _('Proposição enviada com sucesso.')) + messages.success(request, _( + 'Proposição enviada com sucesso.')) try: self.logger.debug("User={}. Tentando obter número do objeto MateriaLegislativa " "com atributos tipo={} e ano={}." @@ -845,13 +845,16 @@ class ProposicaoCrud(Crud): "número que pode não corresponder com a realidade" .format(p.tipo, numero, p.ano))) except ValueError as e: - self.logger.warning("User=" + username + ". " + str(e)) + self.logger.warning( + "User=" + username + ". " + str(e)) pass except AttributeError as e: - self.logger.warning("User=" + username + ". " + str(e)) + self.logger.warning( + "User=" + username + ". " + str(e)) pass except TypeError as e: - self.logger.warning("User=" + username + ". " + str(e)) + self.logger.warning( + "User=" + username + ". " + str(e)) pass elif action == 'return': @@ -862,7 +865,8 @@ class ProposicaoCrud(Crud): elif p.data_recebimento: self.logger.warning("User={}. Proposição (numero={}) já foi recebida, " "não é possível retorná-la.".format(username, p.numero_proposicao)) - msg_error = _('Proposição já foi recebida, não é possível retorná-la.') + msg_error = _( + 'Proposição já foi recebida, não é possível retorná-la.') else: p.data_envio = None p.save() @@ -873,7 +877,8 @@ class ProposicaoCrud(Crud): ta.save() self.logger.info("User={}. Proposição (numero={}) Retornada com sucesso." .format(username, p.numero_proposicao)) - messages.success(request, _('Proposição Retornada com sucesso.')) + messages.success(request, _( + 'Proposição Retornada com sucesso.')) if msg_error: messages.error(request, msg_error) @@ -884,7 +889,8 @@ class ProposicaoCrud(Crud): def dispatch(self, request, *args, **kwargs): username = request.user.username try: - self.logger.debug("User={}. Tentando obter objeto Proposicao com pk={}".format(username, kwargs['pk'])) + self.logger.debug("User={}. Tentando obter objeto Proposicao com pk={}".format( + username, kwargs['pk'])) p = Proposicao.objects.get(id=kwargs['pk']) except Exception as e: self.logger.warning("User={}. Erro ao obter proposicao com pk={}. Retornando 404. {}" @@ -915,7 +921,8 @@ class ProposicaoCrud(Crud): logger = logging.getLogger(__name__) def _action_is_valid(self, request, *args, **kwargs): - proposicao = Proposicao.objects.filter(id=kwargs['pk']).values_list('data_envio', 'data_recebimento') + proposicao = Proposicao.objects.filter( + id=kwargs['pk']).values_list('data_envio', 'data_recebimento') username = request.user.username @@ -923,7 +930,8 @@ class ProposicaoCrud(Crud): if proposicao[0][0] and proposicao[0][1]: self.logger.warning("User={}. Proposição (id={}) já foi enviada e recebida." "Não pode mais ser excluida.".format(username, kwargs['pk'])) - msg = _('Proposição já foi enviada e recebida. Não pode mais ser excluida.') + msg = _( + 'Proposição já foi enviada e recebida. Não pode mais ser excluida.') elif proposicao[0][0] and not proposicao[0][1]: self.logger.warning("""\ User={}. Proposição (id={}) já foi enviada, mas ainda não recebida pelo protocolo. \ @@ -972,11 +980,12 @@ class ProposicaoCrud(Crud): self.object.ultima_edicao = tz.localize(datetime.now()) self.object.save() break - + return super().form_valid(form) def _action_is_valid(self, request, *args, **kwargs): - proposicao = Proposicao.objects.filter(id=kwargs['pk']).values_list('data_envio', 'data_recebimento') + proposicao = Proposicao.objects.filter( + id=kwargs['pk']).values_list('data_envio', 'data_recebimento') username = request.user.username @@ -985,7 +994,8 @@ class ProposicaoCrud(Crud): if proposicao[0][0] and proposicao[0][1]: self.logger.warning('User={}. Proposição (id={}) já foi enviada e recebida. ' 'Não pode mais ser editada'.format(username, kwargs['pk'])) - msg = _('Proposição já foi enviada e recebida. Não pode mais ser editada') + msg = _( + 'Proposição já foi enviada e recebida. Não pode mais ser editada') elif proposicao[0][0] and not proposicao[0][1]: self.logger.warning("""\ User={}. Proposição (id={}) já foi enviada, mas ainda não recebida pelo protocolo. \ @@ -1023,7 +1033,7 @@ class ProposicaoCrud(Crud): initial['user'] = self.request.user initial['ip'] = get_client_ip(self.request) - + tz = timezone.get_current_timezone() initial['ultima_edicao'] = tz.localize(datetime.now()) @@ -1064,14 +1074,17 @@ class ProposicaoCrud(Crud): if obj.data_recebimento is None: obj.data_recebimento = 'Não recebida' if obj.data_envio else 'Não enviada' else: - obj.data_recebimento = timezone.localtime(obj.data_recebimento) - obj.data_recebimento = formats.date_format(obj.data_recebimento, "DATETIME_FORMAT") + obj.data_recebimento = timezone.localtime( + obj.data_recebimento) + obj.data_recebimento = formats.date_format( + obj.data_recebimento, "DATETIME_FORMAT") if obj.data_envio is None: obj.data_envio = 'Em elaboração...' else: obj.data_envio = timezone.localtime(obj.data_envio) - obj.data_envio = formats.date_format(obj.data_envio, "DATETIME_FORMAT") + obj.data_envio = formats.date_format( + obj.data_envio, "DATETIME_FORMAT") return [self._as_row(obj) for obj in object_list] @@ -1149,7 +1162,8 @@ class RelatoriaCrud(MasterDetailCrud): materia = MateriaLegislativa.objects.get(id=self.kwargs['pk']) loc_atual = Tramitacao.objects.\ - filter(materia=materia).order_by('-data_tramitacao', '-id').first() + filter(materia=materia).order_by( + '-data_tramitacao', '-id').first() if loc_atual is None: localizacao = -1 @@ -1165,7 +1179,7 @@ class RelatoriaCrud(MasterDetailCrud): elif loc_atual.unidade_tramitacao_destino.parlamentar: # 1 = Parlamentar tipo_unidade_tramitacao_destino = "Parlamentar" - + unidade_tramitacao_destino = loc_atual.unidade_tramitacao_destino return { 'comissao': localizacao, 'tipo_unidade_tramitacao_destino': tipo_unidade_tramitacao_destino, @@ -1304,7 +1318,7 @@ class TramitacaoCrud(MasterDetailCrud): def get_initial(self): initial = super(UpdateView, self).get_initial() - + initial['ip'] = get_client_ip(self.request) initial['user'] = self.request.user @@ -1353,7 +1367,8 @@ class TramitacaoCrud(MasterDetailCrud): url = reverse('sapl.materia:tramitacao_list', kwargs={'pk': materia.id}) - ultima_tramitacao = materia.tramitacao_set.order_by('-data_tramitacao', '-id').first() + ultima_tramitacao = materia.tramitacao_set.order_by( + '-data_tramitacao', '-id').first() if tramitacao.pk != ultima_tramitacao.pk: username = request.user.username @@ -1373,20 +1388,22 @@ class TramitacaoCrud(MasterDetailCrud): if tramitar_anexadas: mat_anexadas = lista_anexados(materia) for ma in mat_anexadas: - tram_anexada = ma.tramitacao_set.order_by('-data_tramitacao', '-id').first() + tram_anexada = ma.tramitacao_set.order_by( + '-data_tramitacao', '-id').first() if compara_tramitacoes_mat(tram_anexada, tramitacao): tramitacoes_deletar.append(tram_anexada) if ma.tramitacao_set.count() == 0: ma.em_tramitacao = False ma.save() - Tramitacao.objects.filter(id__in=[t.id for t in tramitacoes_deletar]).delete() + Tramitacao.objects.filter( + id__in=[t.id for t in tramitacoes_deletar]).delete() # TODO: otimizar para passar a lista de matérias - for tramitacao in tramitacoes_deletar: - post_delete_signal.send(sender=None, - instance=tramitacao, - operation='C', - request=self.request) + # for tramitacao in tramitacoes_deletar: + # post_delete_signal.send(sender=None, + # instance=tramitacao, + # operation='C', + # request=self.request) return HttpResponseRedirect(url) @@ -1741,10 +1758,10 @@ class MateriaLegislativaCrud(Crud): if dict_objeto_antigo[atributo] != dict_objeto_novo[atributo]: self.object.user = self.request.user self.object.ip = get_client_ip(self.request) - + tz = timezone.get_current_timezone() self.object.ultima_edicao = tz.localize(datetime.now()) - + self.object.save() break @@ -2164,8 +2181,8 @@ class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView): if request.FILES['arquivo'].size > MAX_DOC_UPLOAD_SIZE: msg = _("O arquivo Anexo de Texto Integral deve ser menor que {0:.1f} MB, \ - o tamanho atual desse arquivo é {1:.1f} MB" \ - .format((MAX_DOC_UPLOAD_SIZE/1024)/1024, (request.FILES['arquivo'].size/1024)/1024)) + o tamanho atual desse arquivo é {1:.1f} MB" + .format((MAX_DOC_UPLOAD_SIZE / 1024) / 1024, (request.FILES['arquivo'].size / 1024) / 1024)) messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) @@ -2356,7 +2373,6 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): logger = logging.getLogger(__name__) - def get_context_data(self, **kwargs): context = super(PrimeiraTramitacaoEmLoteView, self).get_context_data(**kwargs) @@ -2378,8 +2394,8 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): if self.primeira_tramitacao: context['title'] = _('Primeira Tramitação em Lote') # Pega somente documentos que não possuem tramitação - context['object_list'] = [obj for obj in context['object_list'] - if obj.tramitacao_set.order_by('-data_tramitacao', '-id').all().count() == 0] + context['object_list'] = [obj for obj in context['object_list'] + if obj.tramitacao_set.order_by('-data_tramitacao', '-id').all().count() == 0] else: context['title'] = _('Tramitação em Lote') context['form'].fields['unidade_tramitacao_local'].initial = UnidadeTramitacao.objects.get( @@ -2394,9 +2410,9 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): def post(self, request, *args, **kwargs): user = request.user ip = get_client_ip(request) - + tz = timezone.get_current_timezone() - ultima_edicao = tz.localize(datetime.now()) + ultima_edicao = tz.localize(datetime.now()) materias_ids = request.POST.getlist('materias') if not materias_ids: @@ -2404,34 +2420,34 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) - form = TramitacaoEmLoteForm(request.POST, - initial= {'materias': materias_ids, - 'user': user, 'ip':ip, - 'ultima_edicao': ultima_edicao}) + form = TramitacaoEmLoteForm(request.POST, + initial={'materias': materias_ids, + 'user': user, 'ip': ip, + 'ultima_edicao': ultima_edicao}) if form.is_valid(): form.save() msg = _('Tramitação completa.') - self.logger.info('user=' + user.username + '. Tramitação completa.') + self.logger.info('user=' + user.username + + '. Tramitação completa.') messages.add_message(request, messages.SUCCESS, msg) return self.get_success_url() return self.form_invalid(form) - def get_success_url(self): return HttpResponseRedirect(reverse('sapl.materia:primeira_tramitacao_em_lote')) - def form_invalid(self, form, *args, **kwargs): for key, erros in form.errors.items(): - if not key=='__all__': - [messages.add_message(self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros] + if not key == '__all__': + [messages.add_message( + self.request, messages.ERROR, form.fields[key].label + ": " + e) for e in erros] else: - [messages.add_message(self.request, messages.ERROR, e) for e in erros] - return self.get(self.request, kwargs, {'form':form}) - + [messages.add_message(self.request, messages.ERROR, e) + for e in erros] + return self.get(self.request, kwargs, {'form': form}) class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView): @@ -2653,7 +2669,7 @@ class MateriaPesquisaSimplesView(PermissionRequiredMixin, FormView): if form.cleaned_data.get('data_inicial'): kwargs.update({'data_apresentacao__gte': form.cleaned_data['data_inicial'], 'data_apresentacao__lte': form.cleaned_data['data_final']}) - + materias = MateriaLegislativa.objects.filter( **kwargs).order_by('-numero', 'ano') @@ -2724,8 +2740,10 @@ def create_zip_docacessorios(materia): docs_path = [os.path.join(MEDIA_ROOT, i) for i in docs] if not docs_path: - raise FileNotFoundError("Não há arquivos PDF cadastrados em documentos acessorios.") - logger.info("Gerando compilado PDF de documentos acessorios com {} documentos".format(docs_path)) + raise FileNotFoundError( + "Não há arquivos PDF cadastrados em documentos acessorios.") + logger.info( + "Gerando compilado PDF de documentos acessorios com {} documentos".format(docs_path)) _zipfile = BytesIO() @@ -2737,7 +2755,8 @@ def create_zip_docacessorios(materia): logger.error(e) raise e - external_name = "mat_{}_{}_docacessorios.zip".format(materia.numero, materia.ano) + external_name = "mat_{}_{}_docacessorios.zip".format( + materia.numero, materia.ano) return external_name, _zipfile.getvalue() @@ -2748,7 +2767,8 @@ def get_zip_docacessorios(request, pk): data = None try: external_name, data = create_zip_docacessorios(materia) - logger.info("user= {}. Gerou o zip compilado de documento acessorios".format(username)) + logger.info( + "user= {}. Gerou o zip compilado de documento acessorios".format(username)) except FileNotFoundError: logger.error("user= {}.Não há arquivos cadastrados".format(username)) msg = _('Não há arquivos cadastrados nesses documentos acessórios.') @@ -2787,9 +2807,11 @@ def create_pdf_docacessorios(materia): # TODO: o for-comprehension abaixo filtra os arquivos não PDF. # TODO: o que fazer com os arquivos não PDF? converter? ignorar? - docs_path = [os.path.join(MEDIA_ROOT, i) for i in docs if i.lower().endswith('pdf')] + docs_path = [os.path.join(MEDIA_ROOT, i) + for i in docs if i.lower().endswith('pdf')] if not docs_path: - raise FileNotFoundError("Não há arquivos PDF cadastrados em documentos acessorios.") + raise FileNotFoundError( + "Não há arquivos PDF cadastrados em documentos acessorios.") logger.info("Gerando compilado PDF de documentos acessorios com {} documentos" .format(docs_path)) merged_pdf = '{}/mat_{}_{}_docacessorios.pdf'.format( @@ -2805,7 +2827,8 @@ def create_pdf_docacessorios(materia): merger.write(data) merger.close() - external_name = "mat_{}_{}_docacessorios.pdf".format(materia.numero, materia.ano) + external_name = "mat_{}_{}_docacessorios.pdf".format( + materia.numero, materia.ano) return external_name, data.getvalue() @@ -2815,7 +2838,8 @@ def get_pdf_docacessorios(request, pk): username = 'Usuário anônimo' if request.user.is_anonymous else request.user.username try: external_name, data = create_pdf_docacessorios(materia) - logger.info("user= {}. Gerou o pdf compilado de documento acessorios".format(username)) + logger.info( + "user= {}. Gerou o pdf compilado de documento acessorios".format(username)) except FileNotFoundError: logger.error("user= {}.Não há arquivos cadastrados".format(username)) msg = _('Não há arquivos cadastrados nesses documentos acessórios.') @@ -2824,7 +2848,7 @@ def get_pdf_docacessorios(request, pk): kwargs={'pk': pk})) except Exception as e: logger.error("user= {}.Um erro inesperado ocorreu na criação do pdf de documentos acessorios: {}" - .format(username,str(e))) + .format(username, str(e))) msg = _('Um erro inesperado ocorreu. Entre em contato com o suporte do SAPL.') messages.add_message(request, messages.ERROR, msg) return redirect(reverse('sapl.materia:documentoacessorio_list', @@ -2845,7 +2869,8 @@ def get_pdf_docacessorios(request, pk): def configEtiquetaMateriaLegislativaCrud(request): config = ConfigEtiquetaMateriaLegislativa.objects.last() if request.method == "POST": - form = ConfigEtiquetaMateriaLegislativaForms(request.POST, instance=config) + form = ConfigEtiquetaMateriaLegislativaForms( + request.POST, instance=config) if form.is_valid(): config = form.save(commit=False) config.published_date = timezone.now() diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index a732aed65..357764a7a 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -1,11 +1,9 @@ -import re -import django_filters import logging +import re from crispy_forms.bootstrap import InlineRadios, Alert, FormActions from crispy_forms.layout import (Button, Column, Div, Fieldset, HTML, Layout, Submit) - from django import forms from django.core.exceptions import (MultipleObjectsReturned, ObjectDoesNotExist, ValidationError) @@ -14,12 +12,12 @@ from django.db.models import Max from django.forms import ModelForm from django.utils import timezone from django.utils.translation import ugettext_lazy as _ +import django_filters from sapl.base.models import Autor, TipoAutor, AppConfig -from sapl.base.signals import post_save_signal from sapl.crispy_layout_mixin import (form_actions, SaplFormHelper, SaplFormLayout, to_row) -from sapl.materia.models import (MateriaLegislativa, +from sapl.materia.models import (MateriaLegislativa, TipoMateriaLegislativa, UnidadeTramitacao) from sapl.protocoloadm.models import Protocolo @@ -176,7 +174,6 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet): o = AnoNumeroOrderingFilter(help_text='') - class Meta(FilterOverridesMetaMixin): model = DocumentoAdministrativo fields = ['tipo', @@ -203,14 +200,14 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet): row2 = to_row( [('numero', 5), - ('complemento',2), + ('complemento', 2), ('ano', 5)]) row3 = to_row( [('protocolo__numero', 4), ('numero_externo', 4), ('data', 4) - ]) + ]) row4 = to_row( [('interessado', 6), @@ -224,28 +221,26 @@ class DocumentoAdministrativoFilterSet(django_filters.FilterSet): ]) buttons = FormActions( - *[ - HTML(''' + *[ + HTML('''