Browse Source

Fix #2342 (#2354)

* Fix #2432

Insere verificação de serviço de email configurado. Assume que
EMAIL_HOST vazio é serviço desativado não enviando, assim, email na
edição/adição de autor, bem como desativando acesso via get/post e
por link de "Acompanhar Matéria" na lista de resultados da
pesquisa de matéria e na tela de detalhes de matérias.
Comportamento análogo para Documentos Administrativos.

* impl test de conexão

* Corrige tipo de remetente

rementente de um email é único e seu envio não é feito através de uma
lista... estudando a execução do send_mail descobri a RFC 2822 que
define rementente da seguinte forma:

From: "Joe Q. Public" <john.q.public@example.com>

portanto,

ou se envia uma string neste formato, o que faz com que mais execução
deva ser feita para um padrão interno de processamento, ou envia-se uma
tupla e não uma lista da seguinte forma

("Joe Q. Public", "john.q.public@exemple.com")

então por que com um servidor configurado o remetente estava
funcionando?

possivelmente ninguem ainda tinha seguindo o formato completo acima
apresentado na definição de EMAIL_SEND_USER...

fazendo isso:
EMAIL_SEND_USER = john.q.public@example.com

em vez disso:
EMAIL_SEND_USER = Joe Q. Public <john.q.public@example.com>

ocorre que esta segunda forma (a correta), melhor apresenta o email ao
usuário, colocando em sua caixa de entrada de email um nome
significativo e não o username.

* faz teste de conexão de email apenas no início do sapl
pull/2365/head
Leandro Roberto da Silva 6 years ago
committed by Edward
parent
commit
ca038b9805
  1. 18
      sapl/base/email_utils.py
  2. 9
      sapl/base/templatetags/common_tags.py
  3. 45
      sapl/base/views.py
  4. 15
      sapl/context_processors.py
  5. 127
      sapl/materia/views.py
  6. 68
      sapl/protocoloadm/views.py
  7. 5
      sapl/settings.py
  8. 2
      sapl/templates/materia/materialegislativa_detail.html
  9. 2
      sapl/templates/materia/materialegislativa_filter.html
  10. 2
      sapl/templates/protocoloadm/documentoadministrativo_filter.html
  11. 19
      sapl/utils.py

18
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,6 +207,12 @@ 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)

9
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,6 +11,7 @@ from sapl.norma.models import NormaJuridica
from sapl.parlamentares.models import Filiacao
from sapl.utils import filiacao_data, SEPARADOR_HASH_PROPOSICAO
register = template.Library()
@ -48,6 +52,7 @@ def split(value, arg):
def to_str(arg):
return str(arg)
@register.filter
def get_last_item_from_list(list, arg):
return list[arg]
@ -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):

45
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,
@ -171,8 +171,14 @@ class AutorCrud(CrudAux):
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,12 +201,13 @@ 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
@ -225,8 +232,14 @@ class AutorCrud(CrudAux):
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,14 +263,15 @@ 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,14 +361,17 @@ 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={}. '
@ -875,10 +892,12 @@ class HelpTopicView(TemplateView):
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]

15
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}

127
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')
@ -95,7 +96,8 @@ 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))
logger.debug('user=' + username +
'. Tentando obter objeto Proposicao com pk = {}.'.format(pk))
proposicao = Proposicao.objects.get(pk=pk)
if proposicao.texto_original:
@ -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
@ -184,15 +187,18 @@ class CriarProtocoloMateriaView(CreateView):
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')
@ -216,10 +222,12 @@ class CriarProtocoloMateriaView(CreateView):
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:
@ -310,11 +318,13 @@ def recuperar_materia(request):
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):
@ -554,14 +565,17 @@ class RetornarProposicao(UpdateView):
def dispatch(self, request, *args, **kwargs):
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.' %
@ -597,7 +611,8 @@ class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView):
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)
@ -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'] = ''
@ -790,18 +806,22 @@ 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 é "
@ -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.'))
@ -830,10 +851,12 @@ class ProposicaoCrud(Crud):
def dispatch(self, request, *args, **kwargs):
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():
@ -1048,7 +1071,8 @@ class ReciboProposicaoView(TemplateView):
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',
@ -1070,15 +1094,18 @@ class RelatoriaCrud(MasterDetailCrud):
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(
@ -1122,14 +1149,17 @@ class RelatoriaCrud(MasterDetailCrud):
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']))
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(
@ -1640,7 +1670,8 @@ class AcompanhamentoConfirmarView(TemplateView):
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))
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)
@ -1680,7 +1711,8 @@ class AcompanhamentoExcluirView(TemplateView):
def get_success_url(self):
username = self.request.user.username.replace("'", "")
self.logger.debug("user=" + username + ". Você parou de acompanhar esta matéria.")
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',
@ -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,7 +2012,6 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
return context
def post(self, request, *args, **kwargs):
marcadas = request.POST.getlist('materia_id')
@ -1991,7 +2036,6 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs)
if not request.POST['data_encaminhamento']:
data_encaminhamento = None
else:
@ -2026,7 +2070,8 @@ 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)
@ -2211,11 +2256,13 @@ class FichaSelecionaView(PermissionRequiredMixin, FormView):
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)

68
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,7 +65,8 @@ 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)
autoria = materia.autoria_set.first()
@ -78,6 +81,7 @@ def recuperar_materia_protocolo(request):
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',
@ -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
@ -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,
})
@ -825,7 +853,8 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
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
# 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:
@ -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

5
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

2
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 %}
<div class="actions btn-group btn-group-sm" role="group">
<a href="{% url 'sapl.materia:acompanhar_materia' object.id %}" class="btn btn-default">Acompanhar Matéria</a>
</div>

2
sapl/templates/materia/materialegislativa_filter.html

@ -145,7 +145,7 @@
{% endfor %}
{% endif %}
<p></p>
{% if m.em_tramitacao %}
{% if m.em_tramitacao and mail_service_configured %}
<a href="{% url 'sapl.materia:acompanhar_materia' m.id %}">Acompanhar Matéria</a>
{% endif %}
</td>

2
sapl/templates/protocoloadm/documentoadministrativo_filter.html

@ -63,7 +63,7 @@
{% if d.texto_integral %}
<strong><a href="{{ d.texto_integral.url }}">Texto Integral</a></strong></br>
{% endif %}
{% if d.tramitacao %}
{% if d.tramitacao and mail_service_configured %}
<a href="{% url 'sapl.protocoloadm:acompanhar_documento' d.id %}">Acompanhar Documento</a>
{% endif %}
</td>

19
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

Loading…
Cancel
Save