diff --git a/sapl/base/email_utils.py b/sapl/base/email_utils.py index 737449e57..024045edd 100644 --- a/sapl/base/email_utils.py +++ b/sapl/base/email_utils.py @@ -1,4 +1,5 @@ from datetime import datetime as dt +import logging from django.core.mail import EmailMultiAlternatives, get_connection, send_mail from django.core.urlresolvers import reverse @@ -6,10 +7,10 @@ from django.template import Context, loader from django.utils import timezone from sapl.base.models import CasaLegislativa -from sapl.settings import EMAIL_SEND_USER - from sapl.materia.models import AcompanhamentoMateria from sapl.protocoloadm.models import AcompanhamentoDocumento +from sapl.settings import EMAIL_SEND_USER +from sapl.utils import mail_service_configured def load_email_templates(templates, context={}): @@ -94,8 +95,6 @@ def criar_email_confirmacao(base_url, casa_legislativa, doc_mat, tipo, hash_txt= ementa = doc_mat.assunto autores = "" - - templates = load_email_templates(['email/acompanhar.txt', 'email/acompanhar.html'], {"casa_legislativa": casa_nome, @@ -115,6 +114,11 @@ def do_envia_email_confirmacao(base_url, casa, tipo, doc_mat, destinatario): # Envia email de confirmacao para atualizações de tramitação # + if not mail_service_configured(): + logger = logging.getLogger(__name__) + logger.warning(_('Servidor de email não configurado.')) + return + sender = EMAIL_SEND_USER # FIXME i18n if tipo == "materia": @@ -203,12 +207,18 @@ def do_envia_email_tramitacao(base_url, tipo, doc_mat, status, unidade_destino): # # Envia email de tramitacao para usuarios cadastrados # + + if not mail_service_configured(): + logger = logging.getLogger(__name__) + logger.warning(_('Servidor de email não configurado.')) + return + if tipo == "materia": destinatarios = AcompanhamentoMateria.objects.filter(materia=doc_mat, confirmado=True) else: destinatarios = AcompanhamentoDocumento.objects.filter(documento=doc_mat, - confirmado=True) + confirmado=True) casa = CasaLegislativa.objects.first() diff --git a/sapl/base/templatetags/common_tags.py b/sapl/base/templatetags/common_tags.py index 99582016d..4251e54da 100644 --- a/sapl/base/templatetags/common_tags.py +++ b/sapl/base/templatetags/common_tags.py @@ -1,5 +1,8 @@ +import logging + from compressor.utils import get_class from django import template +from django.conf import settings from django.template.defaultfilters import stringfilter from sapl.base.models import AppConfig @@ -8,12 +11,13 @@ from sapl.norma.models import NormaJuridica from sapl.parlamentares.models import Filiacao from sapl.utils import filiacao_data, SEPARADOR_HASH_PROPOSICAO + register = template.Library() @register.simple_tag def define(arg): - return arg + return arg @register.simple_tag @@ -48,8 +52,9 @@ def split(value, arg): def to_str(arg): return str(arg) + @register.filter -def get_last_item_from_list(list,arg): +def get_last_item_from_list(list, arg): return list[arg] @@ -59,14 +64,14 @@ def sort_by_keys(value, key): id_props = [x.id for x in value] qs = Proposicao.objects.filter(pk__in=id_props) key_descricao = {'1': 'data_envio', - '-1': '-data_envio', - '2': 'tipo', - '-2': '-tipo', - '3': 'descricao', - '-3': '-descricao', - '4': 'autor', - '-4': '-autor' - } + '-1': '-data_envio', + '2': 'tipo', + '-2': '-tipo', + '3': 'descricao', + '-3': '-descricao', + '4': 'autor', + '-4': '-autor' + } transformed = qs.order_by(key_descricao[key]) return transformed @@ -74,7 +79,7 @@ def sort_by_keys(value, key): @register.filter def paginacao_limite_inferior(pagina): - return (int(pagina) - 1) * 10 + return (int(pagina) - 1) * 10 @register.filter @@ -103,7 +108,6 @@ def strip_hash(value): return value.split(SEPARADOR_HASH_PROPOSICAO)[0][1:] - @register.filter def get_add_perm(value, arg): perm = value @@ -203,6 +207,7 @@ def url(value): return True return False + @register.filter def audio_url(value): return True if url(value) and value.endswith("mp3") else False @@ -212,11 +217,13 @@ def audio_url(value): def video_url(value): return True if url(value) and value.endswith("mp4") else False + @register.filter def file_extension(value): import pathlib return pathlib.Path(value).suffix.replace('.', '') + @register.filter def cronometro_to_seconds(value): if not AppConfig.attr('cronometro_' + value): diff --git a/sapl/base/views.py b/sapl/base/views.py index bb6dda168..ca122ce9f 100644 --- a/sapl/base/views.py +++ b/sapl/base/views.py @@ -1,5 +1,5 @@ -import os import logging +import os from django.contrib.auth import get_user_model from django.contrib.auth.mixins import PermissionRequiredMixin @@ -33,7 +33,7 @@ from sapl.materia.models import (Autoria, MateriaLegislativa, from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria, SessaoPlenariaPresenca) from sapl.utils import (parlamentares_ativos, - show_results_filter_set) + show_results_filter_set, mail_service_configured) from .forms import (AlterarSenhaForm, CasaLegislativaForm, ConfiguracoesAppForm, RelatorioAtasFilterSet, @@ -170,9 +170,15 @@ class AutorCrud(CrudAux): pk_autor = self.object.id url_reverse = reverse('sapl.base:autor_detail', kwargs={'pk': pk_autor}) - + + if not mail_service_configured(): + self.logger.warning(_('Registro de Autor sem envio de email. ' + 'Servidor de email não configurado.')) + return url_reverse + try: - self.logger.debug('user=' + username + '. Enviando email na edição de Autores.') + self.logger.debug('user={}. Enviando email na edição ' + 'de Autores.'.format(username)) kwargs = {} user = self.object.user @@ -195,13 +201,14 @@ class AutorCrud(CrudAux): "ignore esta mensagem. Caso tenha, clique " + "no link abaixo\n" + url_base + reverse('sapl.base:confirmar_email', kwargs=kwargs)) - remetente = [settings.EMAIL_SEND_USER] + remetente = settings.EMAIL_SEND_USER destinatario = [user.email] send_mail(assunto, mensagem, remetente, destinatario, fail_silently=False) except Exception as e: - self.logger.error('user=' + username + '. Erro no envio de email na edição de Autores. ' + str(e)) - + self.logger.error('user={}. Erro no envio de email na edição de' + ' Autores. {}'.format(username, str(e))) + return url_reverse class CreateView(CrudAux.CreateView): @@ -224,9 +231,15 @@ class AutorCrud(CrudAux): pk_autor = self.object.id url_reverse = reverse('sapl.base:autor_detail', kwargs={'pk': pk_autor}) - + + if not mail_service_configured(): + self.logger.warning(_('Registro de Autor sem envio de email. ' + 'Servidor de email não configurado.')) + return url_reverse + try: - self.logger.debug('user=' + username + '. Enviando email na criação de Autores.') + self.logger.debug('user=' + username + + '. Enviando email na criação de Autores.') kwargs = {} user = self.object.user @@ -250,15 +263,16 @@ class AutorCrud(CrudAux): "ignore esta mensagem. Caso tenha, clique " + "no link abaixo\n" + url_base + reverse('sapl.base:confirmar_email', kwargs=kwargs)) - remetente = [settings.EMAIL_SEND_USER] + remetente = settings.EMAIL_SEND_USER destinatario = [user.email] send_mail(assunto, mensagem, remetente, destinatario, fail_silently=False) except Exception as e: print( _('Erro no envio de email na criação de Autores.')) - self.logger.error('user=' + username + '. Erro no envio de email na criação de Autores. ' + str(e)) - + self.logger.error( + 'user=' + username + '. Erro no envio de email na criação de Autores. ' + str(e)) + return url_reverse @@ -347,18 +361,21 @@ class RelatorioPresencaSessaoView(FilterView): 'ordemdia_porc': 0 }) try: - self.logger.debug('user=' + username + '. Tentando obter presença do parlamentar (pk={}).'.format(p.id)) + self.logger.debug( + 'user=' + username + '. Tentando obter presença do parlamentar (pk={}).'.format(p.id)) sessao_count = presenca_sessao.get(parlamentar_id=p.id)[1] except ObjectDoesNotExist as e: - self.logger.error('user=' + username + '. Erro ao obter presença do parlamentar (pk={}). Definido como 0. '.format(p.id) + str(e)) + self.logger.error( + 'user=' + username + '. Erro ao obter presença do parlamentar (pk={}). Definido como 0. '.format(p.id) + str(e)) sessao_count = 0 try: # Presenças de cada Ordem do Dia - self.logger.info('user=' + username + '. Tentando obter PresencaOrdemDia para o parlamentar pk={}.'.format(p.id)) + self.logger.info( + 'user=' + username + '. Tentando obter PresencaOrdemDia para o parlamentar pk={}.'.format(p.id)) ordemdia_count = presenca_ordem.get(parlamentar_id=p.id)[1] except ObjectDoesNotExist: self.logger.error('user=' + username + '. Erro ao obter PresencaOrdemDia para o parlamentar pk={}. ' - 'Definido como 0.'.format(p.id)) + 'Definido como 0.'.format(p.id)) ordemdia_count = 0 parlamentares_presencas[i].update({ @@ -871,14 +888,16 @@ class HelpTopicView(TemplateView): logger = logging.getLogger(__name__) def get_template_names(self): - + username = self.request.user.username topico = self.kwargs['topic'] try: - self.logger.debug('user=' + username + '. Tentando obter template %s.html.' % topico) + self.logger.debug('user=' + username + + '. Tentando obter template %s.html.' % topico) get_template('ajuda/%s.html' % topico) except TemplateDoesNotExist as e: - self.logger.error('user=' + username + '. Erro ao obter template {}.html. Template não existe. '.format(topico) + str(e)) + self.logger.error( + 'user=' + username + '. Erro ao obter template {}.html. Template não existe. '.format(topico) + str(e)) raise Http404() return ['ajuda/%s.html' % topico] diff --git a/sapl/context_processors.py b/sapl/context_processors.py index 2386c0338..ad1a33d9b 100644 --- a/sapl/context_processors.py +++ b/sapl/context_processors.py @@ -1,4 +1,10 @@ +import logging + +from django.conf import settings +from django.utils.translation import ugettext_lazy as _ + from sapl.base.views import get_casalegislativa +from sapl.utils import mail_service_configured as mail_service_configured_utils def parliament_info(request): @@ -7,3 +13,12 @@ def parliament_info(request): return casa.__dict__ else: return {} + + +def mail_service_configured(request): + + if not mail_service_configured_utils(request): + logger = logging.getLogger(__name__) + logger.warning(_('Servidor de email não configurado.')) + return {'mail_service_configured': False} + return {'mail_service_configured': True} diff --git a/sapl/materia/views.py b/sapl/materia/views.py index d38d73d50..8c1d0bc5d 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -1,9 +1,11 @@ from datetime import datetime +import logging from random import choice from string import ascii_letters, digits from crispy_forms.helper import FormHelper 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 @@ -21,10 +23,11 @@ from django.views.generic.base import RedirectView from django.views.generic.edit import FormView from django_filters.views import FilterView import weasyprint -import logging import sapl +from sapl.base.email_utils import do_envia_email_confirmacao from sapl.base.models import Autor, CasaLegislativa +from sapl.base.signals import tramitacao_signal from sapl.comissoes.models import Comissao, Participacao from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_RESTRICT, STATUS_TA_PRIVATE) @@ -45,9 +48,8 @@ from sapl.protocoloadm.models import Protocolo from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, SEPARADOR_HASH_PROPOSICAO, gerar_hash_arquivo, get_base_url, get_mime_type_from_file_extension, montar_row_autor, - show_results_filter_set) + show_results_filter_set, mail_service_configured) -from sapl.base.email_utils import do_envia_email_confirmacao from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, AdicionarVariasAutoriasFilterSet, DespachoInicialForm, DocumentoAcessorioForm, EtiquetaPesquisaForm, @@ -66,7 +68,6 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, RegimeTramitacao, Relatoria, StatusTramitacao, TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao, Tramitacao, UnidadeTramitacao) -from sapl.base.signals import tramitacao_signal AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia') @@ -94,15 +95,16 @@ def autores_ja_adicionados(materia_pk): def proposicao_texto(request, pk): logger = logging.getLogger(__name__) - username = request.user.username.replace("'","") - logger.debug('user=' + username + '. Tentando obter objeto Proposicao com pk = {}.'.format(pk)) + username = request.user.username.replace("'", "") + logger.debug('user=' + username + + '. Tentando obter objeto Proposicao com pk = {}.'.format(pk)) proposicao = Proposicao.objects.get(pk=pk) if proposicao.texto_original: if (not proposicao.data_recebimento and proposicao.autor.user_id != request.user.id): logger.error("user=" + username + ". Usuário ({}) não tem permissão para acessar o texto original." - .format(request.user.id)) + .format(request.user.id)) messages.error(request, _( 'Você não tem permissão para acessar o texto original.')) return redirect(reverse('sapl.materia:proposicao_detail', @@ -119,7 +121,8 @@ def proposicao_texto(request, pk): response['Content-Disposition'] = ( 'inline; filename="%s"' % arquivo.name.split('/')[-1]) return response - logger.error('user=' + username + '. Objeto Proposicao com pk={} não encontrado.'.format(pk)) + logger.error('user=' + username + + '. Objeto Proposicao com pk={} não encontrado.'.format(pk)) raise Http404 @@ -181,25 +184,28 @@ class CriarProtocoloMateriaView(CreateView): def get_context_data(self, **kwargs): context = super( CriarProtocoloMateriaView, self).get_context_data(**kwargs) - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") try: - self.logger.debug("user=" + username + ". Tentando obter objeto Protocolo.") + self.logger.debug("user=" + username + + ". Tentando obter objeto Protocolo.") protocolo = Protocolo.objects.get(pk=self.kwargs['pk']) except ObjectDoesNotExist as e: - self.logger.error("user=" + username + ". Objeto Protocolo com pk={} não encontrado. ".format(self.kwargs['pk']) + str(e)) + self.logger.error( + "user=" + username + ". Objeto Protocolo com pk={} não encontrado. ".format(self.kwargs['pk']) + str(e)) raise Http404() numero = 1 try: - self.logger.debug("user=" + username + ". Tentando obter materias do último ano.") + self.logger.debug("user=" + username + + ". Tentando obter materias do último ano.") materias_ano = MateriaLegislativa.objects.filter( ano=protocolo.ano, tipo=protocolo.tipo_materia).latest('numero') numero = materias_ano.numero + 1 except ObjectDoesNotExist: self.logger.error("user=" + username + ". Não foram encontradas matérias no último ano ({}). " - "Definido 1 como padrão.".format(protocolo.ano)) + "Definido 1 como padrão.".format(protocolo.ano)) pass # numero ficou com o valor padrão 1 acima context['form'].fields['tipo'].initial = protocolo.tipo_materia @@ -213,13 +219,15 @@ class CriarProtocoloMateriaView(CreateView): def form_valid(self, form): materia = form.save() - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") try: - self.logger.info("user=" + username + ". Tentando obter objeto Procolo com pk={}.".format(self.kwargs['pk'])) + self.logger.info( + "user=" + username + ". Tentando obter objeto Procolo com pk={}.".format(self.kwargs['pk'])) protocolo = Protocolo.objects.get(pk=self.kwargs['pk']) except ObjectDoesNotExist: - self.logger.error('user=' + username + '. Objeto Protocolo com pk={} não encontrado.'.format(self.kwargs['pk'])) + self.logger.error( + 'user=' + username + '. Objeto Protocolo com pk={} não encontrado.'.format(self.kwargs['pk'])) raise Http404() if protocolo.autor: @@ -304,17 +312,19 @@ class ProposicaoTaView(IntegracaoTaView): @permission_required('materia.detail_materialegislativa') def recuperar_materia(request): logger = logging.getLogger(__name__) - username = request.user.username.replace("'","") + username = request.user.username.replace("'", "") tipo = TipoMateriaLegislativa.objects.get(pk=request.GET['tipo']) ano = request.GET.get('ano', '') numeracao = None try: - logger.debug("user=" + username + ". Tentando obter numeração da matéria.") + logger.debug("user=" + username + + ". Tentando obter numeração da matéria.") numeracao = sapl.base.models.AppConfig.objects.last( ).sequencia_numeracao except AttributeError as e: - logger.error("user=" + username + ". " + str(e) + " Numeracao da matéria definida como None.") + logger.error("user=" + username + ". " + str(e) + + " Numeracao da matéria definida como None.") pass if tipo.sequencia_numeracao: @@ -531,7 +541,8 @@ class ReceberProposicao(PermissionRequiredForAppCrudMixin, FormView): except IndexError: messages.error(request, _('Código de recibo mal formado!')) except IOError: - messages.error(request, _('Erro abrindo texto original de proposição')) + messages.error(request, _( + 'Erro abrindo texto original de proposição')) return self.form_invalid(form) def get_success_url(self): @@ -547,25 +558,28 @@ class RetornarProposicao(UpdateView): app_label = sapl.protocoloadm.apps.AppConfig.label template_name = "materia/proposicao_confirm_return.html" model = Proposicao - fields = ['data_envio', 'descricao' ] + fields = ['data_envio', 'descricao'] permission_required = ('materia.detail_proposicao_enviada', ) logger = logging.getLogger(__name__) def dispatch(self, request, *args, **kwargs): - username = request.user.username.replace("'","") + username = request.user.username.replace("'", "") try: - self.logger.info("user=" + username + ". Tentando obter objeto Proposicao com id={}.".format(kwargs['pk'])) + self.logger.info( + "user=" + username + ". Tentando obter objeto Proposicao com id={}.".format(kwargs['pk'])) p = Proposicao.objects.get(id=kwargs['pk']) except: - self.logger.error("user=" + username + ". Objeto Proposicao com id={} não encontrado.".format(kwargs['pk'])) + self.logger.error( + "user=" + username + ". Objeto Proposicao com id={} não encontrado.".format(kwargs['pk'])) raise Http404() if p.autor.user != request.user: - self.logger.error("user=" + username + ". Usuário ({}) sem acesso a esta opção.".format(request.user)) + self.logger.error( + "user=" + username + ". Usuário ({}) sem acesso a esta opção.".format(request.user)) messages.error( - request, - 'Usuário sem acesso a esta opção.' % - request.user) + request, + 'Usuário sem acesso a esta opção.' % + request.user) return redirect('/') return super(RetornarProposicao, self).dispatch( @@ -589,7 +603,7 @@ class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView): return self.object.results['url'] def get_object(self, queryset=None): - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") try: """ @@ -597,7 +611,8 @@ class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView): já recebidas -> data_recebimento != None não enviadas -> data_envio == None """ - self.logger.debug("user=" + username + ". Tentando obter objeto Proposicao.") + self.logger.debug("user=" + username + + ". Tentando obter objeto Proposicao.") proposicao = Proposicao.objects.get(pk=self.kwargs['pk'], data_envio__isnull=False, data_recebimento__isnull=True) @@ -615,7 +630,7 @@ class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView): self.object = proposicao except Exception as e: self.logger.error("user=" + username + ". Objeto Proposicao com atributos (pk={}, data_envio=Not Null, " - "data_recebimento=Null) não encontrado. ".format(self.kwargs['pk']) + str(e)) + "data_recebimento=Null) não encontrado. ".format(self.kwargs['pk']) + str(e)) raise Http404() if not self.object: @@ -736,6 +751,7 @@ class ProposicaoCrud(Crud): 'materia.detail_proposicao_incorporada') logger = logging.getLogger(__name__) + def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context['subnav_template_name'] = '' @@ -746,9 +762,9 @@ class ProposicaoCrud(Crud): return context def get(self, request, *args, **kwargs): - + action = request.GET.get('action', '') - username = request.user.username.replace("'","") + username = request.user.username.replace("'", "") if not action: return Crud.DetailView.get(self, request, *args, **kwargs) @@ -781,8 +797,8 @@ class ProposicaoCrud(Crud): 'Proposição enviada com sucesso.')) try: self.logger.debug("user=" + username + ". Tentando obter número do objeto MateriaLegislativa com " - "atributos tipo={} e ano={}." - .format(p.tipo.tipo_conteudo_related, p.ano)) + "atributos tipo={} e ano={}." + .format(p.tipo.tipo_conteudo_related, p.ano)) numero = MateriaLegislativa.objects.filter(tipo=p.tipo.tipo_conteudo_related, ano=p.ano).last().numero + 1 messages.success(request, _( @@ -790,22 +806,26 @@ class ProposicaoCrud(Crud): 'número que pode não corresponder com a realidade' % (p.tipo, numero, p.ano))) except ValueError as e: - self.logger.error("user=" + username + "." + str(e)) + self.logger.error( + "user=" + username + "." + str(e)) pass except AttributeError as e: - self.logger.error("user=" + username + "." + str(e)) + self.logger.error( + "user=" + username + "." + str(e)) pass except TypeError as e: - self.logger.error("user=" + username + "." + str(e)) + self.logger.error( + "user=" + username + "." + str(e)) pass elif action == 'return': if not p.data_envio: - self.logger.error("user=" + username + ". Proposição (numero={}) ainda não foi enviada.".format(p.numero_proposicao)) + self.logger.error( + "user=" + username + ". Proposição (numero={}) ainda não foi enviada.".format(p.numero_proposicao)) msg_error = _('Proposição ainda não foi enviada.') elif p.data_recebimento: self.logger.error("user=" + username + ". Proposição (numero={}) já foi recebida, não é " - "possível retorná-la.".format(p.numero_proposicao)) + "possível retorná-la.".format(p.numero_proposicao)) msg_error = _('Proposição já foi recebida, não é ' 'possível retorná-la.') else: @@ -816,7 +836,8 @@ class ProposicaoCrud(Crud): ta.privacidade = STATUS_TA_PRIVATE ta.editing_locked = False ta.save() - self.logger.info("user=" + username + ". Proposição (numero={}) Retornada com sucesso.".format(p.numero_proposicao)) + self.logger.info( + "user=" + username + ". Proposição (numero={}) Retornada com sucesso.".format(p.numero_proposicao)) messages.success(request, _( 'Proposição Retornada com sucesso.')) @@ -828,12 +849,14 @@ class ProposicaoCrud(Crud): kwargs={'pk': kwargs['pk']})) def dispatch(self, request, *args, **kwargs): - username = request.user.username.replace("'","") + username = request.user.username.replace("'", "") try: - self.logger.debug("user=" + username + ". Tentando obter objeto Proposicao com pk={}".format(kwargs['pk'])) + self.logger.debug( + "user=" + username + ". Tentando obter objeto Proposicao com pk={}".format(kwargs['pk'])) p = Proposicao.objects.get(id=kwargs['pk']) except Exception as e: - self.logger.error("user=" + username + ". Erro ao obter proposicao com pk={}. Retornando 404. ".format(kwargs['pk']) + str(e)) + self.logger.error( + "user=" + username + ". Erro ao obter proposicao com pk={}. Retornando 404. ".format(kwargs['pk']) + str(e)) raise Http404() if not self.has_permission(): @@ -869,18 +892,18 @@ class ProposicaoCrud(Crud): id=kwargs['pk']).values_list( 'data_envio', 'data_recebimento') - username = request.user.username.replace("'","") + username = request.user.username.replace("'", "") if proposicao: if proposicao[0][0] and proposicao[0][1]: self.logger.error("user=" + username + ". Proposição (id={}) já foi enviada e recebida." - "Não pode mais ser excluida.".format(kwargs['pk'])) + "Não pode mais ser excluida.".format(kwargs['pk'])) 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.error("user=" + username + ". Proposição (id={}) já foi enviada mas ainda não recebida " - "pelo protocolo. Use a opção Recuperar Proposição " - "para depois excluí-la.".format(kwargs['pk'])) + "pelo protocolo. Use a opção Recuperar Proposição " + "para depois excluí-la.".format(kwargs['pk'])) msg = _('Proposição já foi enviada mas ainda não recebida ' 'pelo protocolo. Use a opção Recuperar Proposição ' 'para depois excluí-la.') @@ -899,19 +922,19 @@ class ProposicaoCrud(Crud): proposicao = Proposicao.objects.filter( id=kwargs['pk']).values_list( 'data_envio', 'data_recebimento') - - username = request.user.username.replace("'","") + + username = request.user.username.replace("'", "") if proposicao: if proposicao[0][0] and proposicao[0][1]: self.logger.error('user=' + username + '. Proposição (id={}) já foi enviada e recebida.' - 'Não pode mais ser editada'.format(kwargs['pk'])) + 'Não pode mais ser editada'.format(kwargs['pk'])) 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.error('user=' + username + '. Proposição (id={}) já foi enviada mas ainda não recebida ' - 'pelo protocolo. Use a opção Recuperar Proposição ' - 'para voltar para edição.'.format(kwargs['pk'])) + 'pelo protocolo. Use a opção Recuperar Proposição ' + 'para voltar para edição.'.format(kwargs['pk'])) msg = _('Proposição já foi enviada mas ainda não recebida ' 'pelo protocolo. Use a opção Recuperar Proposição ' 'para voltar para edição.') @@ -924,7 +947,7 @@ class ProposicaoCrud(Crud): def get_success_url(self): tipo_texto = self.request.POST.get('tipo_texto', '') - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") if tipo_texto == 'T': messages.info(self.request, @@ -933,9 +956,9 @@ class ProposicaoCrud(Crud): 'marcada, você será redirecionado para a ' 'edição do Texto Eletrônico.')) self.logger.debug('user=' + username + '. Sempre que uma Proposição é inclusa ou ' - 'alterada e a opção "Texto Articulado " for ' - 'marcada, você será redirecionado para a ' - 'edição do Texto Eletrônico.') + 'alterada e a opção "Texto Articulado " for ' + 'marcada, você será redirecionado para a ' + 'edição do Texto Eletrônico.') return reverse('sapl.materia:proposicao_ta', kwargs={'pk': self.object.pk}) else: @@ -954,7 +977,7 @@ class ProposicaoCrud(Crud): def get_success_url(self): tipo_texto = self.request.POST.get('tipo_texto', '') - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") if tipo_texto == 'T': messages.info(self.request, @@ -964,10 +987,10 @@ class ProposicaoCrud(Crud): 'Texto Eletrônico. Use a opção "Editar Texto" ' 'para construir seu texto.')) self.logger.debug('user=' + username + '. Sempre que uma Proposição é inclusa ou ' - 'alterada e a opção "Texto Articulado " for ' - 'marcada, você será redirecionado para o ' - 'Texto Eletrônico. Use a opção "Editar Texto" ' - 'para construir seu texto.') + 'alterada e a opção "Texto Articulado " for ' + 'marcada, você será redirecionado para o ' + 'Texto Eletrônico. Use a opção "Editar Texto" ' + 'para construir seu texto.') return reverse('sapl.materia:proposicao_ta', kwargs={'pk': self.object.pk}) else: @@ -1037,18 +1060,19 @@ class ReciboProposicaoView(TemplateView): def get(self, request, *args, **kwargs): proposicao = Proposicao.objects.get(pk=self.kwargs['pk']) - username = request.user.username.replace("'","") + username = request.user.username.replace("'", "") if proposicao.data_envio: return TemplateView.get(self, request, *args, **kwargs) if not proposicao.data_envio and not proposicao.data_devolucao: self.logger.error('user=' + username + '. Não é possível gerar recibo para uma ' - 'Proposição (pk={}) ainda não enviada.'.format(self.kwargs['pk'])) + 'Proposição (pk={}) ainda não enviada.'.format(self.kwargs['pk'])) messages.error(request, _('Não é possível gerar recibo para uma ' 'Proposição ainda não enviada.')) elif proposicao.data_devolucao: - self.logger.error("user=" + username + ". Não é possível gerar recibo para proposicao de pk={}.".format(self.kwargs['pk'])) + self.logger.error( + "user=" + username + ". Não é possível gerar recibo para proposicao de pk={}.".format(self.kwargs['pk'])) messages.error(request, _('Não é possível gerar recibo.')) return redirect(reverse('sapl.materia:proposicao_detail', @@ -1067,18 +1091,21 @@ class RelatoriaCrud(MasterDetailCrud): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") try: - self.logger.debug("user=" + username + ". Tentando obter objeto Comissao de pk={}.".format(context['form'].initial['comissao'])) + self.logger.debug("user=" + username + ". Tentando obter objeto Comissao de pk={}.".format( + context['form'].initial['comissao'])) comissao = Comissao.objects.get( pk=context['form'].initial['comissao']) except: - self.logger.error("user=" + username + ". Objeto Comissão de pk={} não encontrado.".format(context['form'].initial['comissao'])) + self.logger.error("user=" + username + ". Objeto Comissão de pk={} não encontrado.".format( + context['form'].initial['comissao'])) pass else: - self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format(context['form'].initial['comissao'])) + self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format( + context['form'].initial['comissao'])) composicao = comissao.composicao_set.order_by( '-periodo__data_inicio').first() participacao = Participacao.objects.filter( @@ -1117,19 +1144,22 @@ class RelatoriaCrud(MasterDetailCrud): logger = logging.getLogger(__name__) def get_context_data(self, **kwargs): - + context = super().get_context_data(**kwargs) - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") try: - self.logger.debug("user=" + username + ". Tentando obter objeto Comissao de pk={}.".format(context['form'].initial['comissao'])) + self.logger.debug("user=" + username + ". Tentando obter objeto Comissao de pk={}.".format( + context['form'].initial['comissao'])) comissao = Comissao.objects.get( pk=context['form'].initial['comissao']) - except ObjectDoesNotExist: - self.logger.error("user=" + username + ". Objeto Comissão de pk={} não encontrado.".format(context['form'].initial['comissao'])) + except ObjectDoesNotExist: + self.logger.error("user=" + username + ". Objeto Comissão de pk={} não encontrado.".format( + context['form'].initial['comissao'])) pass - else: - self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format(context['form'].initial['comissao'])) + else: + self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format( + context['form'].initial['comissao'])) composicao = comissao.composicao_set.order_by( '-periodo__data_inicio').first() participacao = Participacao.objects.filter( @@ -1180,7 +1210,7 @@ class TramitacaoCrud(MasterDetailCrud): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") ultima_tramitacao = Tramitacao.objects.filter( materia_id=self.kwargs['pk']).order_by( @@ -1196,7 +1226,7 @@ class TramitacaoCrud(MasterDetailCrud): ultima_tramitacao.unidade_tramitacao_destino)] else: self.logger.error('user=' + username + '. Unidade de tramitação destino ' - 'da última tramitação não pode ser vazia!') + 'da última tramitação não pode ser vazia!') msg = _('Unidade de tramitação destino ' ' da última tramitação não pode ser vazia!') messages.add_message(self.request, messages.ERROR, msg) @@ -1206,7 +1236,7 @@ class TramitacaoCrud(MasterDetailCrud): def form_valid(self, form): self.object = form.save() - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") if form.instance.status.indicador == 'F': form.instance.materia.em_tramitacao = False @@ -1216,7 +1246,7 @@ class TramitacaoCrud(MasterDetailCrud): try: self.logger.debug("user=" + username + ". Tentando enviar Tramitacao (sender={}, post={}, request={})." - .format(Tramitacao, self.object, self.request)) + .format(Tramitacao, self.object, self.request)) tramitacao_signal.send(sender=Tramitacao, post=self.object, request=self.request) @@ -1226,8 +1256,8 @@ class TramitacaoCrud(MasterDetailCrud): 'de matéria não enviado. Há problemas na configuração ' 'do e-mail.') self.logger.warning('user=' + username + '. Tramitação criada, mas e-mail de acompanhamento ' - 'de matéria não enviado. Há problemas na configuração ' - 'do e-mail. ' + str(e)) + 'de matéria não enviado. Há problemas na configuração ' + 'do e-mail. ' + str(e)) messages.add_message(self.request, messages.WARNING, msg) return HttpResponseRedirect(self.get_success_url()) return super().form_valid(form) @@ -1240,7 +1270,7 @@ class TramitacaoCrud(MasterDetailCrud): def form_valid(self, form): self.object = form.save() - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") if form.instance.status.indicador == 'F': form.instance.materia.em_tramitacao = False @@ -1250,7 +1280,7 @@ class TramitacaoCrud(MasterDetailCrud): try: self.logger.debug("user=" + username + ". Tentando enviar Tramitacao (sender={}, post={}, request={}" - .format(Tramitacao, self.object, self.request)) + .format(Tramitacao, self.object, self.request)) tramitacao_signal.send(sender=Tramitacao, post=self.object, request=self.request) @@ -1289,13 +1319,13 @@ class TramitacaoCrud(MasterDetailCrud): '-data_tramitacao', '-timestamp', '-id').first() - - username = request.user.username.replace("'","") + + username = request.user.username.replace("'", "") if tramitacao.pk != ultima_tramitacao.pk: self.logger.error("user=" + username + ". Não é possível deletar a tramitação de pk={}. " "Somente a última tramitação (pk={}) pode ser deletada!." - .format(tramitacao.pk, ultima_tramitacao.pk)) + .format(tramitacao.pk, ultima_tramitacao.pk)) msg = _('Somente a última tramitação pode ser deletada!') messages.add_message(request, messages.ERROR, msg) return HttpResponseRedirect(url) @@ -1639,8 +1669,9 @@ class AcompanhamentoConfirmarView(TemplateView): logger = logging.getLogger(__name__) def get_redirect_url(self, email): - username = self.request.user.username.replace("'","") - self.logger.debug('user=' + username + '. Esta matéria está sendo acompanhada pelo e-mail: %s' % (email)) + username = self.request.user.username.replace("'", "") + self.logger.debug( + 'user=' + username + '. Esta matéria está sendo acompanhada pelo e-mail: %s' % (email)) msg = _('Esta matéria está sendo acompanhada pelo e-mail: %s') % ( email) messages.add_message(self.request, messages.SUCCESS, msg) @@ -1650,23 +1681,23 @@ class AcompanhamentoConfirmarView(TemplateView): def get(self, request, *args, **kwargs): materia_id = kwargs['pk'] hash_txt = request.GET.get('hash_txt', '') - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") try: self.logger.info("user=" + username + ". Tentando obter objeto AcompanhamentoMateria (materia_id={}, hash={})." - .format(materia_id, hash_txt)) + .format(materia_id, hash_txt)) acompanhar = AcompanhamentoMateria.objects.get( materia_id=materia_id, hash=hash_txt) except ObjectDoesNotExist: self.logger.error("user=" + username + ". Objeto AcompanhamentoMateria(materia_id={}, hash={}) não encontrado." - .format(materia_id, hash_txt)) + .format(materia_id, hash_txt)) raise Http404() except MultipleObjectsReturned as e: - # A melhor solução deve ser permitir que a exceção - # (MultipleObjectsReturned) seja lançada e vá para o log, - # pois só poderá ser causada por um erro de desenvolvimente - self.logger.error('user=' + username + '.' + str(e)) + # A melhor solução deve ser permitir que a exceção + # (MultipleObjectsReturned) seja lançada e vá para o log, + # pois só poderá ser causada por um erro de desenvolvimente + self.logger.error('user=' + username + '.' + str(e)) pass acompanhar.confirmado = True acompanhar.save() @@ -1679,8 +1710,9 @@ class AcompanhamentoExcluirView(TemplateView): logger = logging.getLogger(__name__) def get_success_url(self): - username = self.request.user.username.replace("'","") - self.logger.debug("user=" + username + ". Você parou de acompanhar esta matéria.") + username = self.request.user.username.replace("'", "") + self.logger.debug("user=" + username + + ". Você parou de acompanhar esta matéria.") msg = _('Você parou de acompanhar esta matéria.') messages.add_message(self.request, messages.INFO, msg) return reverse('sapl.materia:materialegislativa_detail', @@ -1689,16 +1721,16 @@ class AcompanhamentoExcluirView(TemplateView): def get(self, request, *args, **kwargs): materia_id = kwargs['pk'] hash_txt = request.GET.get('hash_txt', '') - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") try: self.logger.info("user=" + username + ". Tentando deletar objeto AcompanhamentoMateria (materia_id={}, hash={})." - .format(materia_id, hash_txt)) + .format(materia_id, hash_txt)) AcompanhamentoMateria.objects.get(materia_id=materia_id, hash=hash_txt).delete() except ObjectDoesNotExist: self.logger.error("user=" + username + ". Objeto AcompanhamentoMateria (materia_id={}, hash={}) não encontrado." - .format(materia_id, hash_txt)) + .format(materia_id, hash_txt)) pass return HttpResponseRedirect(self.get_success_url()) @@ -1790,6 +1822,12 @@ class AcompanhamentoMateriaView(CreateView): return ''.join(choice(s) for i in range(choice([6, 7]))) def get(self, request, *args, **kwargs): + if not mail_service_configured(): + self.logger.warning(_('Servidor de email não configurado.')) + messages.error(request, _('Serviço de Acompanhamento de ' + 'Matérias não foi configurado')) + return redirect('/') + pk = self.kwargs['pk'] materia = MateriaLegislativa.objects.get(id=pk) @@ -1798,6 +1836,13 @@ class AcompanhamentoMateriaView(CreateView): 'materia': materia}) def post(self, request, *args, **kwargs): + + if not settings.EMAIL_HOST: + self.logger.warning(_('Servidor de email não configurado.')) + messages.error(request, _('Serviço de Acompanhamento de ' + 'Matérias não foi configurado')) + return redirect('/') + form = AcompanhamentoMateriaForm(request.POST) pk = self.kwargs['pk'] materia = MateriaLegislativa.objects.get(id=pk) @@ -1845,7 +1890,8 @@ class AcompanhamentoMateriaView(CreateView): # Caso esse Acompanhamento já exista # avisa ao usuário que essa matéria já está sendo acompanhada else: - self.logger.debug("user=" + usuario.username + ". Este e-mail já está acompanhando essa matéria.") + self.logger.debug("user=" + usuario.username + + ". Este e-mail já está acompanhando essa matéria.") msg = _('Este e-mail já está acompanhando essa matéria.') messages.add_message(request, messages.INFO, msg) @@ -1966,32 +2012,30 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): return context - def post(self, request, *args, **kwargs): - + marcadas = request.POST.getlist('materia_id') tz = timezone.get_current_timezone() - username = request.user.username.replace("'","") + username = request.user.username.replace("'", "") if len(marcadas) == 0: msg = _('Nenhuma máteria foi selecionada.') messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) - obrigatorios = {'data_tramitacao':'Data da Tramitação', - 'unidade_tramitacao_local':'Unidade Local', - 'unidade_tramitacao_destino':'Unidade Destino', - 'status':'Status', - 'urgente':'Urgente', - 'texto':'Texto da Ação'} - for field,nome in obrigatorios.items(): + obrigatorios = {'data_tramitacao': 'Data da Tramitação', + 'unidade_tramitacao_local': 'Unidade Local', + 'unidade_tramitacao_destino': 'Unidade Destino', + 'status': 'Status', + 'urgente': 'Urgente', + 'texto': 'Texto da Ação'} + for field, nome in obrigatorios.items(): if not request.POST[field]: msg = _('Campo {} deve ser preenchido.'.format(nome)) messages.add_message(request, messages.ERROR, msg) return self.get(request, self.kwargs) - if not request.POST['data_encaminhamento']: data_encaminhamento = None else: @@ -2026,15 +2070,16 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): ) t.save() try: - self.logger.debug("user=" + username + ". Tentando enviar tramitação.") + self.logger.debug("user=" + username + + ". Tentando enviar tramitação.") tramitacao_signal.send(sender=Tramitacao, post=t, request=self.request) - + except Exception as e: self.logger.error('user=' + username + '. Tramitação criada , mas e-mail de acompanhamento ' - 'de matéria não enviado. Há problemas na configuração ' - 'do e-mail. ' + str(e)) + 'de matéria não enviado. Há problemas na configuração ' + 'do e-mail. ' + str(e)) flag_error = True if flag_error: msg = _('Tramitação criada, mas e-mail de acompanhamento ' @@ -2187,16 +2232,16 @@ class FichaSelecionaView(PermissionRequiredMixin, FormView): context['form'].fields['materia'].choices = [ (m.id, str(m)) for m in materia_list] - - username = self.request.user.username.replace("'","") + + username = self.request.user.username.replace("'", "") if context['quantidade'] > 100: self.logger.info('user=' + username + '. Sua pesquisa (tipo={}, data_inicial={}, data_final={}) retornou mais do que ' - '100 impressos. Por questões de ' - 'performance, foram retornados ' - 'apenas os 100 primeiros. Caso ' - 'queira outros, tente fazer uma ' - 'pesquisa mais específica'.format(tipo, data_inicial, data_final)) + '100 impressos. Por questões de ' + 'performance, foram retornados ' + 'apenas os 100 primeiros. Caso ' + 'queira outros, tente fazer uma ' + 'pesquisa mais específica'.format(tipo, data_inicial, data_final)) messages.info(self.request, _('Sua pesquisa retornou mais do que ' '100 impressos. Por questões de ' 'performance, foram retornados ' @@ -2208,14 +2253,16 @@ class FichaSelecionaView(PermissionRequiredMixin, FormView): def form_valid(self, form): context = {} - username = self.request.user.username.replace("'","") + username = self.request.user.username.replace("'", "") try: - self.logger.debug("user=" + username + ". Tentando obter objeto MateriaLegislativa com id={}".format(form.data['materia'])) + self.logger.debug( + "user=" + username + ". Tentando obter objeto MateriaLegislativa com id={}".format(form.data['materia'])) materia = MateriaLegislativa.objects.get( id=form.data['materia']) except ObjectDoesNotExist: - self.logger.error("user=" + username + ". Esta MáteriaLegislativa não existe (id={}).".format(form.data['materia'])) + self.logger.error( + "user=" + username + ". Esta MáteriaLegislativa não existe (id={}).".format(form.data['materia'])) mensagem = _('Esta Máteria não existe!') self.messages.add_message(self.request, messages.INFO, mensagem) diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index 327e64baf..1d68dfce2 100755 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -1,8 +1,10 @@ from datetime import datetime +import logging from random import choice from string import ascii_letters, digits from braces.views import FormValidMessageMixin +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 @@ -21,17 +23,18 @@ from django.views.generic.edit import FormView from django_filters.views import FilterView import sapl -import logging -from sapl.comissoes.models import Comissao +from sapl.base.email_utils import do_envia_email_confirmacao from sapl.base.models import Autor, CasaLegislativa +from sapl.base.signals import tramitacao_signal +from sapl.comissoes.models import Comissao from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.parlamentares.models import Legislatura, Parlamentar from sapl.protocoloadm.models import Protocolo from sapl.utils import (create_barcode, get_base_url, get_client_ip, get_mime_type_from_file_extension, - show_results_filter_set) -from sapl.base.email_utils import do_envia_email_confirmacao + show_results_filter_set, mail_service_configured) + from .forms import (AcompanhamentoDocumentoForm, AnularProcoloAdmForm, DocumentoAcessorioAdministrativoForm, DocumentoAdministrativoFilterSet, @@ -44,7 +47,6 @@ from .forms import (AcompanhamentoDocumentoForm, AnularProcoloAdmForm, from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, DocumentoAdministrativo, StatusTramitacaoAdministrativo, TipoDocumentoAdministrativo, TramitacaoAdministrativo) -from sapl.base.signals import tramitacao_signal TipoDocumentoAdministrativoCrud = CrudAux.build( @@ -63,21 +65,23 @@ def recuperar_materia_protocolo(request): logger = logging.getLogger(__name__) username = request.user.username try: - logger.debug("user=" + username + ". Tentando obter matéria com tipo={}, ano={} e numero={}.".format(tipo, ano, numero)) + logger.debug("user=" + username + + ". Tentando obter matéria com tipo={}, ano={} e numero={}.".format(tipo, ano, numero)) materia = MateriaLegislativa.objects.get( - tipo=tipo, ano=ano,numero=numero) + tipo=tipo, ano=ano, numero=numero) autoria = materia.autoria_set.first() content = {'ementa': materia.ementa.strip(), - 'ano':materia.ano, 'numero':materia.numero} + 'ano': materia.ano, 'numero': materia.numero} if autoria: content.update({'autor': autoria.autor.pk, - 'tipo_autor':autoria.autor.tipo.pk}) + 'tipo_autor': autoria.autor.tipo.pk}) response = JsonResponse(content) except Exception as e: logger.error("user=" + username + ". " + str(e)) - response = JsonResponse({'error':e}) + response = JsonResponse({'error': e}) return response + def doc_texto_integral(request, pk): can_see = True @@ -102,13 +106,15 @@ def doc_texto_integral(request, pk): return response raise Http404 + class AcompanhamentoConfirmarView(TemplateView): logger = logging.getLogger(__name__) def get_redirect_url(self, email): username = self.request.user.username - self.logger.info('user=' + username + '. Este documento está sendo acompanhado pelo e-mail: {}'.format(email)) + self.logger.info( + 'user=' + username + '. Este documento está sendo acompanhado pelo e-mail: {}'.format(email)) msg = _('Este documento está sendo acompanhado pelo e-mail: %s') % ( email) messages.add_message(self.request, messages.SUCCESS, msg) @@ -116,6 +122,7 @@ class AcompanhamentoConfirmarView(TemplateView): kwargs={'pk': self.kwargs['pk']}) def get(self, request, *args, **kwargs): + documento_id = kwargs['pk'] hash_txt = request.GET.get('hash_txt', '') username = request.user.username @@ -146,7 +153,8 @@ class AcompanhamentoExcluirView(TemplateView): def get_success_url(self): username = self.request.user.username - self.logger.info("user=" + username + ". Você parou de acompanhar este Documento (pk={}).".format(self.kwargs['pk'])) + self.logger.info( + "user=" + username + ". Você parou de acompanhar este Documento (pk={}).".format(self.kwargs['pk'])) msg = _('Você parou de acompanhar este Documento.') messages.add_message(self.request, messages.INFO, msg) return reverse('sapl.protocoloadm:documentoadministrativo_detail', @@ -160,7 +168,7 @@ class AcompanhamentoExcluirView(TemplateView): self.logger.debug("user=" + username + ". Tentando obter AcompanhamentoDocumento com documento_id={} e hash={}." .format(documento_id, hash_txt)) AcompanhamentoDocumento.objects.get(documento_id=documento_id, - hash=hash_txt).delete() + hash=hash_txt).delete() except ObjectDoesNotExist: self.logger.error("user=" + username + ". AcompanhamentoDocumento com documento_id={} e hash={} não encontrado." .format(documento_id, hash_txt)) @@ -178,6 +186,12 @@ class AcompanhamentoDocumentoView(CreateView): return ''.join(choice(s) for i in range(choice([6, 7]))) def get(self, request, *args, **kwargs): + if not mail_service_configured(): + self.logger.warning(_('Servidor de email não configurado.')) + messages.error(request, _('Serviço de Acompanhamento de ' + 'Documentos não foi configurado')) + return redirect('/') + pk = self.kwargs['pk'] documento = DocumentoAdministrativo.objects.get(id=pk) @@ -186,6 +200,12 @@ class AcompanhamentoDocumentoView(CreateView): 'documento': documento}) def post(self, request, *args, **kwargs): + if not mail_service_configured(): + self.logger.warning(_('Servidor de email não configurado.')) + messages.error(request, _('Serviço de Acompanhamento de ' + 'Documentos não foi configurado')) + return redirect('/') + form = AcompanhamentoDocumentoForm(request.POST) pk = self.kwargs['pk'] documento = DocumentoAdministrativo.objects.get(id=pk) @@ -233,7 +253,8 @@ class AcompanhamentoDocumentoView(CreateView): # Caso esse Acompanhamento já exista # avisa ao usuário que esse documento já está sendo acompanhado else: - self.logger.info('user=' + request.user.username + '. Este e-mail já está acompanhando esse documento (pk={}).'.format(pk)) + self.logger.info('user=' + request.user.username + + '. Este e-mail já está acompanhando esse documento (pk={}).'.format(pk)) msg = _('Este e-mail já está acompanhando esse documento.') messages.add_message(request, messages.INFO, msg) @@ -474,7 +495,8 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, protocolo = form.save(commit=False) username = self.request.user.username try: - self.logger.debug("user=" + username + ". Tentando obter sequência de numeração.") + self.logger.debug("user=" + username + + ". Tentando obter sequência de numeração.") numeracao = sapl.base.models.AppConfig.objects.last( ).sequencia_numeracao except AttributeError as e: @@ -504,10 +526,13 @@ class ProtocoloDocumentoView(PermissionRequiredMixin, protocolo.tipo_processo = '0' # TODO validar o significado protocolo.anulado = False if not protocolo.numero: - protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 + protocolo.numero = ( + numero['numero__max'] + 1) if numero['numero__max'] else 1 elif protocolo.numero < (numero['numero__max'] + 1) if numero['numero__max'] else 0: - msg = _('Número de protocolo deve ser maior que {}'.format(numero['numero__max'])) - self.logger.error("user=" + username + ". Número de protocolo deve ser maior que {}.".format(numero['numero__max'])) + msg = _('Número de protocolo deve ser maior que {}'.format( + numero['numero__max'])) + self.logger.error( + "user=" + username + ". Número de protocolo deve ser maior que {}.".format(numero['numero__max'])) messages.add_message(self.request, messages.ERROR, msg) return self.render_to_response(self.get_context_data()) protocolo.ano = timezone.now().year @@ -564,7 +589,8 @@ class ProtocoloMostrarView(PermissionRequiredMixin, TemplateView): if protocolo.tipo_materia: self.logger.debug( - "user=" + username + ". Tentando obter objeto MateriaLegislativa com numero_protocolo={} e ano={}." + "user=" + username + + ". Tentando obter objeto MateriaLegislativa com numero_protocolo={} e ano={}." .format(protocolo.numero, protocolo.ano)) materia = MateriaLegislativa.objects.filter( numero_protocolo=protocolo.numero, ano=protocolo.ano) @@ -636,7 +662,8 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): protocolo = form.save(commit=False) username = self.request.user.username try: - self.logger.debug("user=" + username + ". Tentando obter sequência de numeração.") + self.logger.debug("user=" + username + + ". Tentando obter sequência de numeração.") numeracao = sapl.base.models.AppConfig.objects.last( ).sequencia_numeracao except AttributeError: @@ -667,12 +694,14 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView): numero['numero__max'] = 0 if not protocolo.numero: - protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 + protocolo.numero = ( + numero['numero__max'] + 1) if numero['numero__max'] else 1 if numero['numero__max']: if protocolo.numero < (numero['numero__max'] + 1): self.logger.error("user=" + username + ". Número de protocolo ({}) é menor que {}" .format(protocolo.numero, numero['numero__max'])) - msg = _('Número de protocolo deve ser maior que {}').format(numero['numero__max']) + msg = _('Número de protocolo deve ser maior que {}').format( + numero['numero__max']) messages.add_message(self.request, messages.ERROR, msg) return self.render_to_response(self.get_context_data()) protocolo.ano = timezone.now().year @@ -766,11 +795,11 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin, qs = self.get_queryset() qs = qs.prefetch_related("documentoacessorioadministrativo_set", - "tramitacaoadministrativo_set", - "tipo", - "tramitacaoadministrativo_set__status", - "tramitacaoadministrativo_set__unidade_tramitacao_local", - "tramitacaoadministrativo_set__unidade_tramitacao_destino") + "tramitacaoadministrativo_set", + "tipo", + "tramitacaoadministrativo_set__status", + "tramitacaoadministrativo_set__unidade_tramitacao_local", + "tramitacaoadministrativo_set__unidade_tramitacao_destino") if status_tramitacao and unidade_destino: lista = filtra_tramitacao_adm_destino_and_status(status_tramitacao, @@ -788,7 +817,6 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin, if 'o' in self.request.GET and not self.request.GET['o']: qs = qs.order_by('-ano', '-numero') - kwargs.update({ 'queryset': qs, }) @@ -823,14 +851,15 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin, url = '' self.filterset.form.fields['o'].label = _('Ordenação') - - # é usada essa verificação anônima para quando os documentos administrativos - # estão no modo ostensivo, mas podem existir documentos administrativos restritos + + # é usada essa verificação anônima para quando os documentos administrativos + # estão no modo ostensivo, mas podem existir documentos administrativos + # restritos if request.user.is_anonymous(): length = self.object_list.filter(restrito=False).count() else: length = self.object_list.count() - + context = self.get_context_data(filter=self.filterset, filter_url=url, numero_res=length @@ -864,7 +893,7 @@ class TramitacaoAdmCrud(MasterDetailCrud): if local: initial['unidade_tramitacao_local' - ] = local.unidade_tramitacao_destino.pk + ] = local.unidade_tramitacao_destino.pk else: initial['unidade_tramitacao_local'] = '' initial['data_tramitacao'] = timezone.now().date() @@ -905,6 +934,7 @@ class TramitacaoAdmCrud(MasterDetailCrud): class UpdateView(MasterDetailCrud.UpdateView): form_class = TramitacaoAdmEditForm logger = logging.getLogger(__name__) + def form_valid(self, form): self.object = form.save() username = self.request.user.username @@ -918,8 +948,8 @@ class TramitacaoAdmCrud(MasterDetailCrud): 'não enviado. A não configuração do servidor de e-mail ' 'impede o envio de aviso de tramitação. ' + str(e)) msg = _('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') + 'de documento não enviado. A não configuração do' + ' servidor de e-mail impede o envio de aviso de tramitação') messages.add_message(self.request, messages.WARNING, msg) return HttpResponseRedirect(self.get_success_url()) return super().form_valid(form) @@ -1038,8 +1068,8 @@ class DesvincularMateriaView(PermissionRequiredMixin, FormView): def form_valid(self, form): materia = MateriaLegislativa.objects.get(numero=form.cleaned_data['numero'], - ano=form.cleaned_data['ano'], - tipo=form.cleaned_data['tipo']) + ano=form.cleaned_data['ano'], + tipo=form.cleaned_data['tipo']) materia.numero_protocolo = None materia.save() return redirect(self.get_success_url()) diff --git a/sapl/settings.py b/sapl/settings.py index 7e382fc4e..0c3f9935e 100755 --- a/sapl/settings.py +++ b/sapl/settings.py @@ -13,8 +13,8 @@ Quick-start development settings - unsuitable for production See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ """ -import socket import logging +import socket from decouple import config from dj_database_url import parse as db_url @@ -24,6 +24,7 @@ from unipath import Path from .temp_suppress_crispy_form_warnings import \ SUPRESS_CRISPY_FORM_WARNINGS_LOGGING + host = socket.gethostbyname_ex(socket.gethostname())[0] BASE_DIR = Path(__file__).ancestor(1) @@ -181,6 +182,7 @@ TEMPLATES = [ "django.template.context_processors.static", 'django.contrib.messages.context_processors.messages', 'sapl.context_processors.parliament_info', + 'sapl.context_processors.mail_service_configured', ], 'debug': DEBUG }, @@ -223,6 +225,7 @@ EMAIL_USE_TLS = config('EMAIL_USE_TLS', cast=bool, default=True) EMAIL_SEND_USER = config('EMAIL_SEND_USER', cast=str, default='') DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', cast=str, default='') SERVER_EMAIL = config('SERVER_EMAIL', cast=str, default='') +EMAIL_RUNNING = None MAX_DOC_UPLOAD_SIZE = 60 * 1024 * 1024 # 60MB MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB @@ -314,10 +317,10 @@ LOGGING = { 'formatter': 'simple', }, 'applogfile': { - 'level':'INFO', - 'class':'logging.handlers.RotatingFileHandler', + 'level': 'INFO', + 'class': 'logging.handlers.RotatingFileHandler', 'filename': 'sapl.log', - 'maxBytes': 1024*1024*15, # 15MB + 'maxBytes': 1024 * 1024 * 15, # 15MB 'backupCount': 10, 'formatter': 'verbose', }, diff --git a/sapl/templates/materia/materialegislativa_detail.html b/sapl/templates/materia/materialegislativa_detail.html index 93029ca44..db779b396 100644 --- a/sapl/templates/materia/materialegislativa_detail.html +++ b/sapl/templates/materia/materialegislativa_detail.html @@ -2,7 +2,7 @@ {% load i18n %} {% block sub_actions %} {{ block.super }} - {% if object.em_tramitacao %} + {% if object.em_tramitacao and mail_service_configured %}
diff --git a/sapl/templates/materia/materialegislativa_filter.html b/sapl/templates/materia/materialegislativa_filter.html index ecbd49208..cdd408af3 100644 --- a/sapl/templates/materia/materialegislativa_filter.html +++ b/sapl/templates/materia/materialegislativa_filter.html @@ -145,7 +145,7 @@ {% endfor %} {% endif %} - {% if m.em_tramitacao %} + {% if m.em_tramitacao and mail_service_configured %} Acompanhar Matéria {% endif %} diff --git a/sapl/templates/protocoloadm/documentoadministrativo_filter.html b/sapl/templates/protocoloadm/documentoadministrativo_filter.html index 6dbd95276..626f0e7f7 100644 --- a/sapl/templates/protocoloadm/documentoadministrativo_filter.html +++ b/sapl/templates/protocoloadm/documentoadministrativo_filter.html @@ -63,7 +63,7 @@ {% if d.texto_integral %} Texto Integral {% endif %} - {% if d.tramitacao %} + {% if d.tramitacao and mail_service_configured %} Acompanhar Documento {% endif %} diff --git a/sapl/utils.py b/sapl/utils.py index 5c8d6e097..77e1cec2d 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -15,6 +15,7 @@ from django.contrib import admin from django.contrib.contenttypes.fields import (GenericForeignKey, GenericRel, GenericRelation) from django.core.exceptions import ValidationError +from django.core.mail import get_connection from django.db.models import Q from django.utils import six, timezone from django.utils.translation import ugettext_lazy as _ @@ -28,11 +29,13 @@ from unipath.path import Path from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row + # (26/10/2018): O separador foi mudador de '/' para 'K' # por conta dos leitores de códigos de barra, que trocavam # a '/' por '&' ou ';' SEPARADOR_HASH_PROPOSICAO = 'K' + def pil_image(source, exif_orientation=False, **options): return source_generators.pil_image(source, exif_orientation, **options) @@ -767,3 +770,19 @@ def RemoveTag(texto): def remover_acentos(string): return unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode() + + +def mail_service_configured(request=None): + + if settings.EMAIL_RUNNING is None: + result = True + try: + connection = get_connection() + connection.open() + except Exception as e: + result = False + finally: + connection.close() + settings.EMAIL_RUNNING = result + + return settings.EMAIL_RUNNING