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('''
- ''' ) - ], + ''') + ], Submit('pesquisar', _('Pesquisar'), css_class='float-right', - onclick='return true;'), - css_class='form-group row justify-content-between' - , + onclick='return true;'), + css_class='form-group row justify-content-between', ) - self.form.helper = SaplFormHelper() self.form.helper.form_method = 'GET' self.form.helper.layout = Layout( Fieldset(_('Pesquisar Documento'), - row1, row2, - row3, row4, - row5, buttons,) + row1, row2, + row3, row4, + row5, buttons,) ) @@ -437,7 +432,7 @@ class ProtocoloDocumentoForm(ModelForm): Fieldset(_('Identificação de Documento'), row1, row2), - fieldset, + fieldset, row4, row5, HTML(" "), @@ -452,7 +447,6 @@ class ProtocoloDocumentoForm(ModelForm): self.fields['data_hora_manual'].widget = forms.HiddenInput() - class ProtocoloMateriaForm(ModelForm): logger = logging.getLogger(__name__) @@ -683,7 +677,6 @@ class TramitacaoAdmForm(ModelForm): widgets = {'user': forms.HiddenInput(), 'ip': forms.HiddenInput(), 'ultima_edicao': forms.HiddenInput()} - def __init__(self, *args, **kwargs): super(TramitacaoAdmForm, self).__init__(*args, **kwargs) @@ -782,8 +775,8 @@ class TramitacaoAdmForm(ModelForm): anexados_list = lista_anexados(documento, False) for da in anexados_list: if not da.tramitacaoadministrativo_set.all() \ - or da.tramitacaoadministrativo_set.last() \ - .unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local: + or da.tramitacaoadministrativo_set.last() \ + .unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local: da.tramitacao = False if tramitacao.status.indicador == "F" else True da.save() lista_tramitacao.append(TramitacaoAdministrativo( @@ -800,21 +793,22 @@ class TramitacaoAdmForm(ModelForm): ip=tramitacao.ip, ultima_edicao=tramitacao.ultima_edicao )) - TramitacaoAdministrativo.objects.bulk_create(lista_tramitacao) + TramitacaoAdministrativo.objects.bulk_create(lista_tramitacao) return tramitacao - -# Compara se os campos de duas tramitações são iguais, +# Compara se os campos de duas tramitações são iguais, # exceto os campos id, documento_id e timestamp def compara_tramitacoes_doc(tramitacao1, tramitacao2): if not tramitacao1 or not tramitacao2: return False lst_items = ['id', 'documento_id', 'timestamp', 'ultima_edicao'] - values = [(k,v) for k,v in tramitacao1.__dict__.items() if ((k not in lst_items) and (k[0] != '_'))] - other_values = [(k,v) for k,v in tramitacao2.__dict__.items() if (k not in lst_items and k[0] != '_')] + values = [(k, v) for k, v in tramitacao1.__dict__.items() + if ((k not in lst_items) and (k[0] != '_'))] + other_values = [(k, v) for k, v in tramitacao2.__dict__.items() + if (k not in lst_items and k[0] != '_')] return values == other_values @@ -832,7 +826,7 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm): model = TramitacaoAdministrativo fields = ['data_tramitacao', 'unidade_tramitacao_local', - 'status', + 'status', 'urgente', 'unidade_tramitacao_destino', 'data_encaminhamento', @@ -873,12 +867,13 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm): '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): + # 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 cd['ultima_edicao'] = obj.ultima_edicao @@ -888,10 +883,10 @@ class TramitacaoAdmEditForm(TramitacaoAdmForm): return cd - @transaction.atomic def save(self, commit=True): - ant_tram_principal = TramitacaoAdministrativo.objects.get(id=self.instance.id) + ant_tram_principal = TramitacaoAdministrativo.objects.get( + id=self.instance.id) nova_tram_principal = super(TramitacaoAdmEditForm, self).save(commit) documento = nova_tram_principal.documento documento.tramitacao = False if nova_tram_principal.status.indicador == "F" else True @@ -937,7 +932,7 @@ class AnexadoForm(ModelForm): ano = forms.CharField(label='Ano', required=True) def __init__(self, *args, **kwargs): - return super(AnexadoForm, self).__init__(*args, **kwargs) + return super(AnexadoForm, self).__init__(*args, **kwargs) def clean(self): super(AnexadoForm, self).clean() @@ -951,8 +946,10 @@ class AnexadoForm(ModelForm): data_desanexacao = cleaned_data['data_desanexacao'] if cleaned_data['data_desanexacao'] else data_anexacao if data_anexacao > data_desanexacao: - self.logger.error("Data de anexação posterior à data de desanexação.") - raise ValidationError(_("Data de anexação posterior à data de desanexação.")) + self.logger.error( + "Data de anexação posterior à data de desanexação.") + raise ValidationError( + _("Data de anexação posterior à data de desanexação.")) try: self.logger.info( "Tentando obter objeto DocumentoAdministrativo (numero={}, ano={}, tipo={})." @@ -973,18 +970,20 @@ class AnexadoForm(ModelForm): documento_principal = self.instance.documento_principal if documento_principal == documento_anexado: self.logger.error("O documento não pode ser anexado a si mesmo.") - raise ValidationError(_("O documento não pode ser anexado a si mesmo")) + raise ValidationError( + _("O documento não pode ser anexado a si mesmo")) is_anexado = Anexado.objects.filter(documento_principal=documento_principal, documento_anexado=documento_anexado ).exclude(pk=self.instance.pk).exists() - + if is_anexado: self.logger.error("Documento já se encontra anexado.") raise ValidationError(_('Documento já se encontra anexado')) ciclico = False - anexados_anexado = Anexado.objects.filter(documento_principal=documento_anexado) + anexados_anexado = Anexado.objects.filter( + documento_principal=documento_anexado) while(anexados_anexado and not ciclico): anexados = [] @@ -996,12 +995,14 @@ class AnexadoForm(ModelForm): else: for a in Anexado.objects.filter(documento_principal=anexo.documento_anexado): anexados.append(a) - + anexados_anexado = anexados - + if ciclico: - self.logger.error("O documento não pode ser anexado por um de seus anexados.") - raise ValidationError(_('O documento não pode ser anexado por um de seus anexados')) + self.logger.error( + "O documento não pode ser anexado por um de seus anexados.") + raise ValidationError( + _('O documento não pode ser anexado por um de seus anexados')) cleaned_data['documento_anexado'] = documento_anexado @@ -1036,8 +1037,8 @@ class AnexadoEmLoteFilterSet(django_filters.FilterSet): self.form.helper = SaplFormHelper() self.form.helper.form_method = 'GET' self.form.helper.layout = Layout( - Fieldset(_('Pesquisa de Documentos'), - row1, row2, form_actions(label='Pesquisar')) + Fieldset(_('Pesquisa de Documentos'), + row1, row2, form_actions(label='Pesquisar')) ) @@ -1092,7 +1093,7 @@ class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm): 'user': forms.HiddenInput(), 'ip': forms.HiddenInput(), 'ultima_edicao': forms.HiddenInput() - } + } def clean(self): super(DocumentoAdministrativoForm, self).clean() @@ -1109,7 +1110,6 @@ class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm): tipo_documento = int(self.data['tipo']) ano_documento = int(self.data['ano']) - # não permite atualizar para numero/ano/tipo existente if self.instance.pk: mudanca_doc = numero_documento != self.instance.numero \ @@ -1198,7 +1198,7 @@ class DocumentoAdministrativoForm(FileFieldCheckMixin, ModelForm): def __init__(self, *args, **kwargs): row1 = to_row( - [('tipo', 3), ('numero', 3),('complemento', 3), ('ano', 3)]) + [('tipo', 3), ('numero', 3), ('complemento', 3), ('ano', 3)]) row2 = to_row( [('data', 4), ('numero_protocolo', 4), ('ano_protocolo', 4)]) @@ -1515,7 +1515,6 @@ class TramitacaoEmLoteAdmForm(ModelForm): widgets = {'user': forms.HiddenInput(), 'ip': forms.HiddenInput(), 'ultima_edicao': forms.HiddenInput()} - def __init__(self, *args, **kwargs): super(TramitacaoEmLoteAdmForm, self).__init__(*args, **kwargs) @@ -1529,7 +1528,7 @@ class TramitacaoEmLoteAdmForm(ModelForm): [(ut.pk, ut) for ut in ust if ut.parlamentar]) self.fields['unidade_tramitacao_destino'].choices = unidade_tramitacao_destino self.fields['urgente'].label = "Urgente? *" - + row1 = to_row([ ('data_tramitacao', 4), ('data_encaminhamento', 4), @@ -1666,8 +1665,8 @@ class TramitacaoEmLoteAdmForm(ModelForm): anexados = lista_anexados(doc, False) for da in anexados: if not da.tramitacaoadministrativo_set.all() \ - or da.tramitacaoadministrativo_set.last() \ - .unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local: + or da.tramitacaoadministrativo_set.last() \ + .unidade_tramitacao_destino == tramitacao.unidade_tramitacao_local: da.tramitacao = False if tramitacao.status.indicador == "F" else True da.save() lista_tramitacao.append(TramitacaoAdministrativo( @@ -1720,4 +1719,4 @@ class TramitacaoEmLoteAdmFilterSet(django_filters.FilterSet): self.form.helper.form_method = 'GET' self.form.helper.layout = Layout( Fieldset(_('Tramitação em Lote'), - row1, row2, form_actions(label=_('Pesquisar')))) \ No newline at end of file + row1, row2, form_actions(label=_('Pesquisar')))) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index ed2f0d78f..86522713f 100755 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -1,34 +1,35 @@ from datetime import datetime import logging -import re from random import choice +import re from string import ascii_letters, digits from braces.views import FormValidMessageMixin from django.conf import settings from django.contrib import messages +from django.contrib.admin.views.decorators import staff_member_required from django.contrib.auth.decorators import permission_required from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.contenttypes.models import ContentType from django.core.exceptions import ObjectDoesNotExist -from django.urls import reverse from django.db import transaction from django.db.models import Max, Q from django.http import Http404, HttpResponse, JsonResponse from django.http.response import HttpResponseRedirect from django.shortcuts import redirect +from django.shortcuts import render +from django.urls import reverse from django.utils import timezone from django.utils.translation import ugettext_lazy as _ from django.views.generic import ListView, CreateView, UpdateView from django.views.generic.base import RedirectView, TemplateView from django.views.generic.edit import FormView from django_filters.views import FilterView -from django.contrib.admin.views.decorators import staff_member_required import sapl from sapl.base.email_utils import do_envia_email_confirmacao from sapl.base.models import Autor, CasaLegislativa, AppConfig -from sapl.base.signals import tramitacao_signal, post_delete_signal +from sapl.base.signals import tramitacao_signal from sapl.comissoes.models import Comissao from sapl.crud.base import (Crud, CrudAux, MasterDetailCrud, make_pagination, RP_LIST, RP_DETAIL) @@ -41,9 +42,6 @@ from sapl.utils import (create_barcode, get_base_url, get_client_ip, get_mime_type_from_file_extension, lista_anexados, show_results_filter_set, mail_service_configured, from_date_to_datetime_utc) -from django.shortcuts import render - - from .forms import (AcompanhamentoDocumentoForm, AnexadoEmLoteFilterSet, AnexadoForm, AnularProtocoloAdmForm, compara_tramitacoes_doc, DesvincularDocumentoForm, DesvincularMateriaForm, @@ -367,7 +365,8 @@ class DocumentoAdministrativoCrud(Crud): return self.search_url def form_valid(self, form): - form.instance.complemento = re.sub('\s+', '', form.instance.complemento).upper() + form.instance.complemento = re.sub( + '\s+', '', form.instance.complemento).upper() return super().form_valid(form) class UpdateView(Crud.UpdateView): @@ -381,10 +380,10 @@ class DocumentoAdministrativoCrud(Crud): self.object = form.save() dict_objeto_novo = self.object.__dict__ - + atributos = [ 'tipo_id', 'ano', 'numero', 'data', 'protocolo_id', 'assunto', - 'interessado', 'tramitacao', 'restrito', 'texto_integral','numero_externo', + 'interessado', 'tramitacao', 'restrito', 'texto_integral', 'numero_externo', 'dias_prazo', 'data_fim_prazo', 'observacao' ] @@ -398,8 +397,9 @@ class DocumentoAdministrativoCrud(Crud): self.object.save() break - - form.instance.complemento = re.sub('\s+', '', form.instance.complemento).upper() + + form.instance.complemento = re.sub( + '\s+', '', form.instance.complemento).upper() return super().form_valid(form) @@ -417,17 +417,17 @@ class DocumentoAdministrativoCrud(Crud): if documento.restrito and self.request.user.is_anonymous: return redirect('/') return super(Crud.DetailView, self).get(args, kwargs) - + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - + context['user'] = self.request.user context['documentoadministrativo'] = DocumentoAdministrativo.objects.get( pk=self.kwargs['pk'] ) return context - + def urlize(self, obj, fieldname): a = '%s' % ( reverse( @@ -633,13 +633,14 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, timestamp__isnull=False, timestamp__gte=data_inicio_utc, timestamp__lte=data_fim_utc ) | Q( - timestamp_data_hora_manual__isnull=False, - timestamp_data_hora_manual__gte=data_inicio_utc, - timestamp_data_hora_manual__lte=data_fim_utc, - ) - ).aggregate(Max('numero'))['numero__max'] + timestamp_data_hora_manual__isnull=False, + timestamp_data_hora_manual__gte=data_inicio_utc, + timestamp_data_hora_manual__lte=data_fim_utc, + ) + ).aggregate(Max('numero'))['numero__max'] elif numeracao == 'U': - numero_max = Protocolo.objects.all().aggregate(Max('numero'))['numero__max'] + numero_max = Protocolo.objects.all().aggregate(Max('numero'))[ + 'numero__max'] protocolo.tipo_processo = '0' # TODO validar o significado protocolo.anulado = False @@ -647,7 +648,7 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, inicio_numeracao = AppConfig.objects.first().inicio_numeracao_protocolo numero = int(numero_max) if numero_max else 0 protocolo.numero = ( - (numero + 1 ) if numero and numero >= inicio_numeracao else inicio_numeracao + (numero + 1) if numero and numero >= inicio_numeracao else inicio_numeracao ) protocolo.ano = timezone.now().year @@ -703,7 +704,7 @@ class CriarDocumentoProtocolo(PermissionRequiredMixin, CreateView): tz = timezone.get_current_timezone() doc['ultima_edicao'] = tz.localize(datetime.now()) - + return doc @@ -849,14 +850,15 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): ) ).aggregate(Max('numero'))['numero__max'] elif numeracao == 'U': - numero_max = Protocolo.objects.all().aggregate(Max('numero'))['numero__max'] + numero_max = Protocolo.objects.all().aggregate(Max('numero'))[ + 'numero__max'] inicio_numeracao = AppConfig.objects.first().inicio_numeracao_protocolo numero = int(numero_max) if numero_max else 0 protocolo.numero = ( - (numero + 1 ) if numero and numero >= inicio_numeracao else inicio_numeracao + (numero + 1) if numero and numero >= inicio_numeracao else inicio_numeracao ) - + protocolo.ano = timezone.now().year protocolo.tipo_protocolo = 0 @@ -889,14 +891,14 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): numero=data['numero_materia'], tipo=data['tipo_materia'] ) - + materia.numero_protocolo = protocolo.numero 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() return redirect(self.get_success_url(protocolo)) @@ -1380,11 +1382,11 @@ class TramitacaoAdmCrud(MasterDetailCrud): 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) @@ -1479,13 +1481,13 @@ class DesvincularMateriaView(PermissionRequiredMixin, FormView): ) materia.numero_protocolo = None - + 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() return redirect(self.get_success_url()) @@ -1641,9 +1643,9 @@ class PrimeiraTramitacaoEmLoteAdmView(PermissionRequiredMixin, FilterView): messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) - form = TramitacaoEmLoteAdmForm(request.POST, - initial= {'documentos': documentos_ids, - 'user': user, 'ip':ip, + form = TramitacaoEmLoteAdmForm(request.POST, + initial={'documentos': documentos_ids, + 'user': user, 'ip': ip, 'ultima_edicao': ultima_edicao}) if form.is_valid(): @@ -1724,10 +1726,10 @@ class TramitacaoEmLoteAdmView(PrimeiraTramitacaoEmLoteAdmView): 'documento_id', flat=True) -def apaga_protocolos(request, ano,numero_protocolo=None): - kwargs = {'ano__in':ano} +def apaga_protocolos(request, ano, numero_protocolo=None): + kwargs = {'ano__in': ano} if numero_protocolo: - kwargs.update({'numero__gte':numero_protocolo}) + kwargs.update({'numero__gte': numero_protocolo}) all_protocolos = Protocolo.objects.filter(**kwargs) @@ -1739,12 +1741,12 @@ def apaga_protocolos(request, ano,numero_protocolo=None): ml.numero_protocolo = None ml.save() - for deleted_object in all_protocolos: - post_delete_signal.send(sender=None, - instance=deleted_object, - operation='D', - request=request - ) + # for deleted_object in all_protocolos: + # post_delete_signal.send(sender=None, + # instance=deleted_object, + # operation='D', + # request=request + # ) all_protocolos.delete() @@ -1752,18 +1754,19 @@ def apaga_protocolos(request, ano,numero_protocolo=None): def apaga_protocolos_view(request): if request.method == "GET": if Protocolo.objects.exists(): - intervalo_data = Protocolo.objects.all().distinct('ano').values_list('ano', flat=True).order_by('-ano') + intervalo_data = Protocolo.objects.all().distinct( + 'ano').values_list('ano', flat=True).order_by('-ano') else: intervalo_data = None - return render(request,"protocoloadm/deleta_todos_protocolos.html",{'intervalo_data':intervalo_data}) - + return render(request, "protocoloadm/deleta_todos_protocolos.html", {'intervalo_data': intervalo_data}) + elif request.method == "POST": password = request.POST.get('senha') - valid = request.user.check_password(password) + valid = request.user.check_password(password) if valid: anos = request.POST.getlist('ano') - numero_protocolo = request.POST.get('numero_protocolo') - apaga_protocolos(request,anos,numero_protocolo) - return JsonResponse({'type':'success','msg':''}) + numero_protocolo = request.POST.get('numero_protocolo') + apaga_protocolos(request, anos, numero_protocolo) + return JsonResponse({'type': 'success', 'msg': ''}) else: - return JsonResponse({'type':'error','msg':'Senha Incorreta'}) \ No newline at end of file + return JsonResponse({'type': 'error', 'msg': 'Senha Incorreta'})