Browse Source

Fix #1151 refatorar email (#1193)

* Refatora email tramitacao

* Inicia a refatoracao

* Abre uma só conexão para múltiplos emails

* Insere mensagem de feedback ao desacompanhar alguma matéria

* Pequenos ajustes
pull/1194/head
Eduardo Calil 8 years ago
committed by Edward
parent
commit
e77be4927c
  1. 4
      sapl/materia/apps.py
  2. 211
      sapl/materia/email_utils.py
  3. 19
      sapl/materia/receivers.py
  4. 13
      sapl/materia/signals.py
  5. 2
      sapl/materia/tests/test_email_templates.py
  6. 2
      sapl/materia/urls.py
  7. 281
      sapl/materia/views.py

4
sapl/materia/apps.py

@ -7,5 +7,5 @@ class AppConfig(apps.AppConfig):
label = 'materia'
verbose_name = _('Matéria')
# def ready(self):
# from . import signals
def ready(self):
from . import signals

211
sapl/materia/email_utils.py

@ -0,0 +1,211 @@
from datetime import datetime
from django.core.mail import EmailMultiAlternatives, get_connection, send_mail
from django.core.urlresolvers import reverse
from django.template import Context, loader
from sapl.base.models import CasaLegislativa
from sapl.settings import EMAIL_SEND_USER
from .models import AcompanhamentoMateria
def load_email_templates(templates, context={}):
emails = []
for t in templates:
tpl = loader.get_template(t)
email = tpl.render(Context(context))
if t.endswith(".html"):
email = email.replace('\n', '').replace('\r', '')
emails.append(email)
return emails
def enviar_emails(sender, recipients, messages):
'''
Recipients is a string list of email addresses
Messages is an array of dicts of the form:
{'recipient': 'address', # useless????
'subject': 'subject text',
'txt_message': 'text message',
'html_message': 'html message'
}
'''
if len(messages) == 1:
# sends an email simultaneously to all recipients
send_mail(messages[0]['subject'],
messages[0]['txt_message'],
sender,
recipients,
html_message=messages[0]['html_message'],
fail_silently=False)
elif len(recipients) > len(messages):
raise ValueError("Message list should have size 1 \
or equal recipient list size. \
recipients: %s, messages: %s" % (recipients, messages)
)
else:
# sends an email simultaneously to all reciepients
for (d, m) in zip(recipients, messages):
send_mail(m['subject'],
m['txt_message'],
sender,
[d],
html_message=m['html_message'],
fail_silently=False)
def criar_email_confirmacao(base_url, casa_legislativa, materia, hash_txt=''):
if not casa_legislativa:
raise ValueError("Casa Legislativa é obrigatória")
if not materia:
raise ValueError("Matéria é obrigatória")
# FIXME i18n
casa_nome = (casa_legislativa.nome + ' de ' +
casa_legislativa.municipio + '-' +
casa_legislativa.uf)
materia_url = reverse('sapl.materia:materialegislativa_detail',
kwargs={'pk': materia.id})
confirmacao_url = reverse('sapl.materia:acompanhar_confirmar',
kwargs={'pk': materia.id})
autores = []
for autoria in materia.autoria_set.all():
autores.append(autoria.autor.nome)
templates = load_email_templates(['email/acompanhar.txt',
'email/acompanhar.html'],
{"casa_legislativa": casa_nome,
"logotipo": casa_legislativa.logotipo,
"descricao_materia": materia.ementa,
"autoria": autores,
"hash_txt": hash_txt,
"base_url": base_url,
"materia": str(materia),
"materia_url": materia_url,
"confirmacao_url": confirmacao_url, })
return templates
def do_envia_email_confirmacao(base_url, casa, materia, destinatario):
#
# Envia email de confirmacao para atualizações de tramitação
#
sender = EMAIL_SEND_USER
# FIXME i18n
subject = "[SAPL] " + str(materia) + " - Ative o Acompanhamento da Materia"
messages = []
recipients = []
email_texts = criar_email_confirmacao(base_url,
casa,
materia,
destinatario.hash,)
recipients.append(destinatario.email)
messages.append({
'recipient': destinatario.email,
'subject': subject,
'txt_message': email_texts[0],
'html_message': email_texts[1]
})
enviar_emails(sender, recipients, messages)
def criar_email_tramitacao(base_url, casa_legislativa, materia, status,
unidade_destino, hash_txt=''):
if not casa_legislativa:
raise ValueError("Casa Legislativa é obrigatória")
if not materia:
raise ValueError("Matéria é obrigatória")
# FIXME i18n
casa_nome = (casa_legislativa.nome + ' de ' +
casa_legislativa.municipio + '-' +
casa_legislativa.uf)
url_materia = reverse('sapl.materia:tramitacao_list',
kwargs={'pk': materia.id})
url_excluir = reverse('sapl.materia:acompanhar_excluir',
kwargs={'pk': materia.id})
autores = []
for autoria in materia.autoria_set.all():
autores.append(autoria.autor.nome)
tramitacao = materia.tramitacao_set.last()
templates = load_email_templates(['email/tramitacao.txt',
'email/tramitacao.html'],
{"casa_legislativa": casa_nome,
"data_registro": datetime.now().strftime(
"%d/%m/%Y"),
"cod_materia": materia.id,
"logotipo": casa_legislativa.logotipo,
"descricao_materia": materia.ementa,
"autoria": autores,
"data": tramitacao.data_tramitacao,
"status": status,
"localizacao": unidade_destino,
"texto_acao": tramitacao.texto,
"hash_txt": hash_txt,
"materia": str(materia),
"base_url": base_url,
"materia_url": url_materia,
"excluir_url": url_excluir})
return templates
def do_envia_email_tramitacao(base_url, materia, status, unidade_destino):
#
# Envia email de tramitacao para usuarios cadastrados
#
destinatarios = AcompanhamentoMateria.objects.filter(materia=materia,
confirmado=True)
casa = CasaLegislativa.objects.first()
sender = EMAIL_SEND_USER
# FIXME i18n
subject = "[SAPL] " + str(materia) + \
" - Acompanhamento de Materia Legislativa"
connection = get_connection()
connection.open()
for destinatario in destinatarios:
try:
email_texts = criar_email_tramitacao(base_url,
casa,
materia,
status,
unidade_destino,
destinatario.hash,)
email = EmailMultiAlternatives(
subject,
email_texts[0],
sender,
[destinatario.email],
connection=connection)
email.attach_alternative(email_texts[1], "text/html")
email.send()
# Garantia de que, mesmo com o lançamento de qualquer exceção,
# a conexão será fechada
except Exception:
connection.close()
raise Exception('Erro ao enviar e-mail de acompanhamento de matéria.')
connection.close()

19
sapl/materia/receivers.py

@ -0,0 +1,19 @@
from django.dispatch import receiver
from sapl.materia.signals import tramitacao_signal
from sapl.utils import get_base_url
from .email_utils import do_envia_email_tramitacao
@receiver(tramitacao_signal)
def handle_tramitacao_signal(sender, **kwargs):
tramitacao = kwargs.get("post")
request = kwargs.get("request")
materia = tramitacao.materia
do_envia_email_tramitacao(
get_base_url(request),
materia,
tramitacao.status,
tramitacao.unidade_tramitacao_destino)

13
sapl/materia/signals.py

@ -1,10 +1,15 @@
from django.db.models.signals import post_delete, post_save
import django.dispatch
from sapl.utils import delete_texto, save_texto
from .models import DocumentoAcessorio, MateriaLegislativa
post_save.connect(save_texto, sender=MateriaLegislativa)
post_save.connect(save_texto, sender=DocumentoAcessorio)
post_delete.connect(delete_texto, sender=MateriaLegislativa)
post_delete.connect(delete_texto, sender=DocumentoAcessorio)
tramitacao_signal = django.dispatch.Signal(providing_args=['post', 'request'])
# post_save.connect(save_texto, sender=MateriaLegislativa)
# post_save.connect(save_texto, sender=DocumentoAcessorio)
# post_delete.connect(delete_texto, sender=MateriaLegislativa)
# post_delete.connect(delete_texto, sender=DocumentoAcessorio)

2
sapl/materia/tests/test_email_templates.py

@ -1,6 +1,6 @@
from django.core import mail
from sapl.materia.views import enviar_emails, load_email_templates
from sapl.materia.email_utils import enviar_emails, load_email_templates
def test_email_template_loading():

2
sapl/materia/urls.py

@ -25,6 +25,8 @@ from sapl.materia.views import (AcompanhamentoConfirmarView,
from .apps import AppConfig
from . import receivers
app_name = AppConfig.name
urlpatterns_materia = [

281
sapl/materia/views.py

@ -7,13 +7,11 @@ from crispy_forms.layout import HTML
from django.contrib import messages
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
from django.core.mail import send_mail
from django.core.exceptions import ObjectDoesNotExist, MultipleObjectsReturned
from django.core.urlresolvers import reverse
from django.http import HttpResponse, JsonResponse
from django.http.response import Http404, HttpResponseRedirect
from django.shortcuts import get_object_or_404, redirect
from django.template import Context, loader
from django.utils import formats
from django.utils.translation import ugettext_lazy as _
from django.views.generic import CreateView, ListView, TemplateView, UpdateView
@ -37,12 +35,13 @@ from sapl.materia.forms import (AnexadaForm, ConfirmarProposicaoForm,
TramitacaoUpdateForm)
from sapl.norma.models import LegislacaoCitada
from sapl.protocoloadm.models import Protocolo
from sapl.settings import EMAIL_SEND_USER
from sapl.utils import (TURNO_TRAMITACAO_CHOICES, YES_NO_CHOICES, autor_label,
autor_modal, gerar_hash_arquivo, get_base_url,
montar_row_autor)
import sapl
from .email_utils import do_envia_email_confirmacao
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AdicionarVariasAutoriasFilterSet, DespachoInicialForm,
DocumentoAcessorioForm, MateriaAssuntoForm,
@ -59,6 +58,8 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria,
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa,
TipoProposicao, Tramitacao, UnidadeTramitacao)
from .signals import tramitacao_signal
AssuntoMateriaCrud = Crud.build(AssuntoMateria, 'assunto_materia')
@ -906,47 +907,27 @@ class TramitacaoCrud(MasterDetailCrud):
self.initial['data_tramitacao'] = datetime.now()
return self.initial
def post(self, request, *args, **kwargs):
materia = MateriaLegislativa.objects.get(id=kwargs['pk'])
if 'status' in request.POST and request.POST['status']:
status = StatusTramitacao.objects.filter(
id=request.POST['status']).first()
unidade_destino = UnidadeTramitacao.objects.get(
id=request.POST['unidade_tramitacao_destino']
)
texto = request.POST['texto']
data_tramitacao = request.POST['data_tramitacao']
do_envia_email_tramitacao(
request, materia, status,
unidade_destino, texto, data_tramitacao)
return super(CreateView, self).post(request, *args, **kwargs)
def form_valid(self, form):
self.object = form.save()
tramitacao_signal.send(sender=Tramitacao,
post=self.object,
request=self.request)
return super().form_valid(form)
class UpdateView(MasterDetailCrud.UpdateView):
form_class = TramitacaoUpdateForm
def post(self, request, *args, **kwargs):
materia = MateriaLegislativa.objects.get(
tramitacao__id=kwargs['pk'])
if 'status' in request.POST and request.POST['status']:
status = StatusTramitacao.objects.filter(
id=request.POST['status']).first()
unidade_destino = UnidadeTramitacao.objects.get(
id=request.POST['unidade_tramitacao_destino']
)
texto = request.POST['texto']
data_tramitacao = request.POST['data_tramitacao']
do_envia_email_tramitacao(
request, materia, status,
unidade_destino, texto, data_tramitacao)
return super(UpdateView, self).post(request, *args, **kwargs)
@property
def layout_key(self):
return 'TramitacaoUpdate'
def form_valid(self, form):
self.object = form.save()
tramitacao_signal.send(sender=Tramitacao,
post=self.object,
request=self.request)
return super().form_valid(form)
class ListView(MasterDetailCrud.ListView):
def get_queryset(self):
@ -1301,6 +1282,8 @@ class AcompanhamentoConfirmarView(TemplateView):
class AcompanhamentoExcluirView(TemplateView):
def get_success_url(self):
msg = _('Você parou de acompanhar esta matéria.')
messages.add_message(self.request, messages.INFO, msg)
return reverse('sapl.materia:materialegislativa_detail',
kwargs={'pk': self.kwargs['pk']})
@ -1416,7 +1399,20 @@ class AcompanhamentoMateriaView(CreateView):
acompanhar.usuario = usuario.username
acompanhar.confirmado = False
acompanhar.save()
do_envia_email_confirmacao(request, materia, email)
base_url = get_base_url(request)
destinatario = AcompanhamentoMateria.objects.get(
materia=materia,
email=email,
confirmado=False)
casa = CasaLegislativa.objects.first()
do_envia_email_confirmacao(base_url,
casa,
materia,
destinatario)
msg = _('Foi enviado um e-mail de confirmação. Confira sua caixa \
de mensagens e clique no link que nós enviamos para \
confirmar o acompanhamento desta matéria.')
@ -1444,207 +1440,6 @@ class AcompanhamentoMateriaView(CreateView):
kwargs={'pk': self.kwargs['pk']})
def load_email_templates(templates, context={}):
emails = []
for t in templates:
tpl = loader.get_template(t)
email = tpl.render(Context(context))
if t.endswith(".html"):
email = email.replace('\n', '').replace('\r', '')
emails.append(email)
return emails
def criar_email_confirmacao(request, casa_legislativa, materia, hash_txt=''):
if not casa_legislativa:
raise ValueError("Casa Legislativa é obrigatória")
if not materia:
raise ValueError("Matéria é obrigatória")
# FIXME i18n
casa_nome = (casa_legislativa.nome + ' de ' +
casa_legislativa.municipio + '-' +
casa_legislativa.uf)
base_url = get_base_url(request)
materia_url = reverse('sapl.materia:materialegislativa_detail',
kwargs={'pk': materia.id})
confirmacao_url = reverse('sapl.materia:acompanhar_confirmar',
kwargs={'pk': materia.id})
autores = []
for autoria in materia.autoria_set.all():
autores.append(autoria.autor.nome)
templates = load_email_templates(['email/acompanhar.txt',
'email/acompanhar.html'],
{"casa_legislativa": casa_nome,
"logotipo": casa_legislativa.logotipo,
"descricao_materia": materia.ementa,
"autoria": autores,
"hash_txt": hash_txt,
"base_url": base_url,
"materia": str(materia),
"materia_url": materia_url,
"confirmacao_url": confirmacao_url, })
return templates
def criar_email_tramitacao(
request, casa_legislativa, materia, status,
unidade_destino, texto, data_tramitacao, hash_txt=''):
if not casa_legislativa:
raise ValueError("Casa Legislativa é obrigatória")
if not materia:
raise ValueError("Matéria é obrigatória")
# FIXME i18n
casa_nome = (casa_legislativa.nome + ' de ' +
casa_legislativa.municipio + '-' +
casa_legislativa.uf)
base_url = get_base_url(request)
url_materia = reverse('sapl.materia:tramitacao_list',
kwargs={'pk': materia.id})
url_excluir = reverse('sapl.materia:acompanhar_excluir',
kwargs={'pk': materia.id})
autores = []
for autoria in materia.autoria_set.all():
autores.append(autoria.autor.nome)
tramitacao = materia.tramitacao_set.last()
templates = load_email_templates(['email/tramitacao.txt',
'email/tramitacao.html'],
{"casa_legislativa": casa_nome,
"data_registro": datetime.now().strftime(
"%d/%m/%Y"),
"cod_materia": materia.id,
"logotipo": casa_legislativa.logotipo,
"descricao_materia": materia.ementa,
"autoria": autores,
"data": data_tramitacao,
"status": status,
"localizacao": unidade_destino,
"texto_acao": texto,
"hash_txt": hash_txt,
"materia": str(materia),
"base_url": base_url,
"materia_url": url_materia,
"excluir_url": url_excluir})
return templates
def enviar_emails(sender, recipients, messages):
'''
Recipients is a string list of email addresses
Messages is an array of dicts of the form:
{'recipient': 'address', # useless????
'subject': 'subject text',
'txt_message': 'text message',
'html_message': 'html message'
}
'''
if len(messages) == 1:
# sends an email simultaneously to all recipients
send_mail(messages[0]['subject'],
messages[0]['txt_message'],
sender,
recipients,
html_message=messages[0]['html_message'],
fail_silently=False)
elif len(recipients) > len(messages):
raise ValueError("Message list should have size 1 \
or equal recipient list size. \
recipients: %s, messages: %s" % (recipients, messages)
)
else:
# sends an email simultaneously to all reciepients
for (d, m) in zip(recipients, messages):
send_mail(m['subject'],
m['txt_message'],
sender,
[d],
html_message=m['html_message'],
fail_silently=False)
return None
def do_envia_email_confirmacao(request, materia, email):
#
# Envia email de confirmacao para atualizações de tramitação
#
destinatario = AcompanhamentoMateria.objects.get(materia=materia,
email=email,
confirmado=False)
casa = CasaLegislativa.objects.first()
sender = EMAIL_SEND_USER
# FIXME i18n
subject = "[SAPL] " + str(materia) + " - Ative o Acompanhamento da Materia"
messages = []
recipients = []
email_texts = criar_email_confirmacao(request,
casa,
materia,
destinatario.hash,)
recipients.append(destinatario.email)
messages.append({
'recipient': destinatario.email,
'subject': subject,
'txt_message': email_texts[0],
'html_message': email_texts[1]
})
enviar_emails(sender, recipients, messages)
return None
def do_envia_email_tramitacao(
request, materia, status, unidade_destino, texto, data_tramitacao):
#
# Envia email de tramitacao para usuarios cadastrados
#
destinatarios = AcompanhamentoMateria.objects.filter(materia=materia,
confirmado=True)
casa = CasaLegislativa.objects.first()
sender = EMAIL_SEND_USER
# FIXME i18n
subject = "[SAPL] " + str(materia) + \
" - Acompanhamento de Materia Legislativa"
messages = []
recipients = []
for destinatario in destinatarios:
email_texts = criar_email_tramitacao(request,
casa,
materia,
status,
unidade_destino,
texto,
data_tramitacao,
destinatario.hash,)
recipients.append(destinatario.email)
messages.append({
'recipient': destinatario.email,
'subject': subject,
'txt_message': email_texts[0],
'html_message': email_texts[1],
})
enviar_emails(sender, recipients, messages)
class DocumentoAcessorioEmLoteView(PermissionRequiredMixin, FilterView):
filterset_class = AcessorioEmLoteFilterSet
template_name = 'materia/em_lote/acessorio.html'
@ -1787,10 +1582,10 @@ class TramitacaoEmLoteView(PrimeiraTramitacaoEmLoteView):
qr = self.request.GET.copy()
if ('tramitacao__status' in qr and
'tramitacao__unidade_tramitacao_destino' in qr and
qr['tramitacao__status'] and
qr['tramitacao__unidade_tramitacao_destino']
):
'tramitacao__unidade_tramitacao_destino' in qr and
qr['tramitacao__status'] and
qr['tramitacao__unidade_tramitacao_destino']
):
lista = filtra_tramitacao_destino_and_status(
qr['tramitacao__status'],
qr['tramitacao__unidade_tramitacao_destino'])

Loading…
Cancel
Save