Browse Source

Adiciona suporte ao envio de email para confirmação e alteração de

tramitação

Adiciona testes e refatora funções de envio de email
pull/222/head
Edward Ribeiro 10 years ago
parent
commit
3de6022da8
  1. 2
      materia/models.py
  2. 4
      materia/urls.py
  3. 253
      materia/views.py
  4. 9
      sapl/utils.py
  5. 27
      templates/email/acompanhar.html
  6. 16
      templates/email/acompanhar.txt
  7. 1
      templates/email/test_tramitacao.html
  8. 38
      templates/email/tramitacao.html
  9. 27
      templates/email/tramitacao.txt
  10. 1
      templates/materia/acompanhamento_materia.html
  11. 74
      templates/materia/test_email_templates.py

2
materia/models.py

@ -138,7 +138,7 @@ class AcompanhamentoMateria(models.Model):
email = models.CharField( email = models.CharField(
max_length=100, verbose_name=_('Endereço de E-mail')) max_length=100, verbose_name=_('Endereço de E-mail'))
data_cadastro = models.DateField(auto_now_add=True) data_cadastro = models.DateField(auto_now_add=True)
hash = models.CharField(max_length=8) hash = models.CharField(max_length=8) # TODO LOL isso não é um HASH!!!!
confirmado = models.BooleanField(default=False) confirmado = models.BooleanField(default=False)
class Meta: class Meta:

4
materia/urls.py

@ -1,12 +1,8 @@
from django.conf.urls import include, url from django.conf.urls import include, url
<<<<<<< HEAD
from materia.views import (AcompanhamentoConfirmarView, from materia.views import (AcompanhamentoConfirmarView,
AcompanhamentoExcluirView, AcompanhamentoExcluirView,
AcompanhamentoMateriaView, AutoriaEditView, AcompanhamentoMateriaView, AutoriaEditView,
=======
from materia.views import (AcompanhamentoMateriaView, AutoriaEditView,
>>>>>>> Move acompanhamento de matéria para a app de matéria.
AutoriaView, DespachoInicialEditView, AutoriaView, DespachoInicialEditView,
DespachoInicialView, DocumentoAcessorioEditView, DespachoInicialView, DocumentoAcessorioEditView,
DocumentoAcessorioView, FormularioCadastroView, DocumentoAcessorioView, FormularioCadastroView,

253
materia/views.py

@ -10,6 +10,7 @@ from django.core.mail import send_mail
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
from django.http.response import HttpResponseRedirect from django.http.response import HttpResponseRedirect
from django.shortcuts import redirect from django.shortcuts import redirect
from django.template import Context, loader
from django.utils.html import strip_tags from django.utils.html import strip_tags
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic import ListView, TemplateView from django.views.generic import ListView, TemplateView
@ -23,6 +24,8 @@ from crud import build_crud, make_pagination
from norma.models import LegislacaoCitada, NormaJuridica, TipoNormaJuridica from norma.models import LegislacaoCitada, NormaJuridica, TipoNormaJuridica
from parlamentares.models import Partido from parlamentares.models import Partido
from sapl.utils import get_base_url
from .forms import (AcompanhamentoMateriaForm, AutoriaForm, from .forms import (AcompanhamentoMateriaForm, AutoriaForm,
DespachoInicialForm, DocumentoAcessorioForm, DespachoInicialForm, DocumentoAcessorioForm,
FormularioCadastroForm, FormularioSimplificadoForm, FormularioCadastroForm, FormularioSimplificadoForm,
@ -769,11 +772,10 @@ class AcompanhamentoConfirmarView(TemplateView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
materia_id = kwargs['pk'] materia_id = kwargs['pk']
hash_txt = request.GET.get('hash', '') hash_txt = request.GET.get('hash_txt', '')
acompanhar = AcompanhamentoMateria.objects.get(materia_id=materia_id, acompanhar = AcompanhamentoMateria.objects.get(materia_id=materia_id,
hash=hash_txt) hash=hash_txt)
acompanhar.confirmado = True acompanhar.confirmado = True
acompanhar.save() acompanhar.save()
@ -787,10 +789,13 @@ class AcompanhamentoExcluirView(TemplateView):
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
materia_id = kwargs['pk'] materia_id = kwargs['pk']
hash_txt = request.GET.get('hash', '') hash_txt = request.GET.get('hash_txt', '')
try:
AcompanhamentoMateria.objects.get(materia_id=materia_id, AcompanhamentoMateria.objects.get(materia_id=materia_id,
hash=hash_txt).delete() hash=hash_txt).delete()
except ObjectDoesNotExist:
pass
return HttpResponseRedirect(self.get_redirect_url()) return HttpResponseRedirect(self.get_redirect_url())
@ -1004,84 +1009,190 @@ class RelatoriaView(FormMixin, GenericView):
'parlamentares': parlamentares}) 'parlamentares': parlamentares})
def criar_html_email(materia, hash_txt): def load_email_templates(templates, context = {}):
html_tpl = Template('''
<html>
<head></head>
<body bgcolor='#ffffff'>
<p align='center'>
<img src="$image" width='81' height='77'>
</p>
<h2 align='center'><b>$casa_legislativa</b><br/>
Sistema de Apoio ao Processo Legislativo
</h2>
<p>
A seguinte mat&eacute;ria de seu interesse
sofreu tramita&ccedil;&atilde;o registrada
$data_registro
</p>
<h4>
<a href='context.consultas.absolute_url()
/materia/materia_mostrar_proc?cod_materia=
$cod_materia'><b>$descricao_materia</b></a>
<br/><br/>
<b>Autoria: </b>$autoria
</h4>
<p>
<b>Data da a&ccedil;&atilde;o</b>: $data<br/>
<b>Status</b>: $status<br/>
<b>Texto da a&ccedil;&atilde;o</b>: $texto_acao</p>
<hr>
<p>
<a href='$url?hash_txt=$hash_txt'>
Clique aqui para excluir seu e-mail da lista
de envio</a>
<p>
<p>Esta &eacute; uma mensagem autom&aacute;tica.
Por favor, n&atilde;o a responda.</p>
</body>
</html>''')
casa = CasaLegislativa.objects.first() emails = []
casa_nome = (casa.nome + ' de ' + casa.municipio + '-' + casa.uf) 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")
casa_nome = (casa_legislativa.nome + ' de ' + \
casa_legislativa.municipio + '-' + \
casa_legislativa.uf)
base_url = get_base_url(request)
materia_url = reverse('acompanhar_materia', kwargs={'pk': materia.id})
confirmacao_url = reverse('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, hash_txt=''):
if not casa_legislativa:
raise ValueError("Casa Legislativa é obrigatória")
url = reverse('acompanhar_excluir', kwargs={'pk': materia.id}) if not materia:
raise ValueError("Matéria é obrigatória")
casa_nome = (casa_legislativa.nome + ' de ' + \
casa_legislativa.municipio + '-' + \
casa_legislativa.uf)
base_url = get_base_url(request)
url_materia = reverse('acompanhar_materia', kwargs={'pk': materia.id})
url_excluir = reverse('acompanhar_excluir', kwargs={'pk': materia.id})
autores = []
for autoria in materia.autoria_set.all(): for autoria in materia.autoria_set.all():
autoria_html += autoria.autor.nome + "<br/> " autores.append(autoria.autor.nome)
html_body = html_tpl.substitute(image=static('img/logo.png'), templates = load_email_templates(['email/tramitacao.txt',
casa_legislativa=casa_nome, 'email/tramitacao.html'],
data_registro=datetime.now().strftime( {"casa_legislativa":casa_nome,
"data_registro":datetime.now().strftime(
"%d/%m/%Y"), "%d/%m/%Y"),
cod_materia=materia.id, "cod_materia":materia.id,
descricao_materia=materia.ementa, "logotipo": casa_legislativa.logotipo,
autoria=autoria_html, "descricao_materia":materia.ementa,
data=materia.tramitacao_set.last( "autoria": autores,
"data":materia.tramitacao_set.last(
).data_tramitacao, ).data_tramitacao,
status=materia.tramitacao_set.last( "status":materia.tramitacao_set.last(
).status, ).status,
texto_acao=materia.tramitacao_set.last( "texto_acao":materia.tramitacao_set.last(
).texto, ).texto,
hash_txt=hash_txt, "hash_txt":hash_txt,
url=url,) "materia": str(materia),
return html_body "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()
def enviar_emails(materia): sender = 'sapl-test@interlegis.leg.br'
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]
})
destinatarios = AcompanhamentoMateria.objects.filter( enviar_emails(sender, recipients, messages)
materia=materia, return None
def do_envia_email_tramitacao(request, materia):
#
# Envia email de tramitacao para usuarios cadastrados
#
destinatarios = AcompanhamentoMateria.objects.filter(materia=materia,
confirmado=True) confirmado=True)
casa = CasaLegislativa.objects.first()
sender = 'sapl-test@interlegis.leg.br'
subject = "[SAPL] "+ str(materia) +" - Acompanhamento de Materia Legislativa"
messages = []
recipients = []
for destinatario in destinatarios: for destinatario in destinatarios:
corpo_email_html = criar_html_email(materia, destinatario.hash_txt) email_texts = criar_email_tramitacao(request,
send_mail('Mudança de Tramitação', casa,
corpo_email_html, materia,
'sapl-test@interlegis.leg.br', destinatario.hash,)
destinatario, recipients.append(destinatario.email)
fail_silently=True) messages.append({
'recipient': destinatario.email,
'subject': subject,
'txt_message': email_texts[0],
'html_message': email_texts[1]
})
enviar_emails(sender, recipients, messages)
return None
class TramitacaoView(FormMixin, GenericView): class TramitacaoView(FormMixin, GenericView):
@ -1123,9 +1234,8 @@ class TramitacaoView(FormMixin, GenericView):
'object': materia, 'object': materia,
'tramitacoes': tramitacoes_list}) 'tramitacoes': tramitacoes_list})
# Manda por parametro para 'enviar_emails' ? do_envia_email_tramitacao(request, materia)
img_url = request.get_host() + static('img/logo.png')
self.enviar_emails(materia)
return self.form_valid(form) return self.form_valid(form)
else: else:
return self.render_to_response({'form': form, return self.render_to_response({'form': form,
@ -1136,7 +1246,6 @@ class TramitacaoView(FormMixin, GenericView):
pk = self.kwargs['pk'] pk = self.kwargs['pk']
return reverse('tramitacao_materia', kwargs={'pk': pk}) return reverse('tramitacao_materia', kwargs={'pk': pk})
class TramitacaoEditView(FormMixin, GenericView): class TramitacaoEditView(FormMixin, GenericView):
template_name = "materia/tramitacao_edit.html" template_name = "materia/tramitacao_edit.html"
@ -1615,6 +1724,7 @@ class AcompanhamentoMateriaView(FormMixin,
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
pk = self.kwargs['pk'] pk = self.kwargs['pk']
materia = MateriaLegislativa.objects.get(id=pk) materia = MateriaLegislativa.objects.get(id=pk)
return self.render_to_response( return self.render_to_response(
{'form': AcompanhamentoMateriaForm(), {'form': AcompanhamentoMateriaForm(),
'materia': materia}) 'materia': materia})
@ -1644,6 +1754,9 @@ class AcompanhamentoMateriaView(FormMixin,
acompanhar.usuario = usuario.username acompanhar.usuario = usuario.username
acompanhar.confirmado = False acompanhar.confirmado = False
acompanhar.save() acompanhar.save()
do_envia_email_confirmacao(request, materia, email)
else: else:
return self.render_to_response( return self.render_to_response(
{'form': form, {'form': form,

9
sapl/utils.py

@ -21,6 +21,15 @@ def xstr(s):
return '' if s is None else str(s) return '' if s is None else str(s)
def get_base_url(request):
# TODO substituir por Site.objects.get_current().domain
# from django.contrib.sites.models import Site
current_domain = request.get_host()
protocol = 'https' if request.is_secure() else 'http'
return "{0}://{1}".format(protocol, current_domain)
def create_barcode(value): def create_barcode(value):
''' '''
creates a base64 encoded barcode PNG image creates a base64 encoded barcode PNG image

27
templates/email/acompanhar.html

@ -0,0 +1,27 @@
{% load i18n %}
{% load static %}
<html><head></head><body bgcolor='#ffffff'>
<p align='center'>
<img src="{{base_url}}{% if logotipo %}{{ MEDIA_URL }}{{ logotipo }}{% else %}{% static 'img/logo.png' %}{% endif %}"
alt="Logo" class="img-responsive visible-lg-inline-block vcenter" >
</p>
<h2 align='center'><b>{{casa_legislativa}}</b>
<br/>
Sistema de Apoio ao Processo Legislativo
</h2>
<p>Registramos seu pedido para acompanhamento por e-mail da matéria legislativa identificada a seguir:</p>
<a href="{{base_url}}{{materia_url}}">{{materia}}<b> - {{descricao_materia}}</b></a><br/>
{{ementa}}<br/>
</h4>
<p></p>
<p>Para garantia de sua privacidade, solicitamos que ative o recebimento das futuras mensagens clicando no link:</p>
<h4>
<a href="{{base_url}}{{confirmacao_url}}?hash_txt={{hash_txt}}">{{base_url}}{{confirmacao_url}}?hash_txt={{hash_txt}}</a>
</h4>
<br/>
<hr>
<p>Caso não tenha realizado o cadastramento em nosso sistema, favor desconsiderar a presente mensagem<br/>
Esta é uma mensagem automática. Por favor, não responda.</p>
</body>
</html>

16
templates/email/acompanhar.txt

@ -0,0 +1,16 @@
{{casa_legislativa}}
Sistema de Apoio ao Processo Legislativo
>Registramos seu pedido para acompanhamento por e-mail da matéria legislativa identificada a seguir:
{{base_url}}{{materia_url}} - {{materia}} - {{descricao_materia}}
{{ementa}}
Para garantia de sua privacidade, solicitamos que ative o recebimento das futuras mensagens acessando no link:
{{base_url}}{{url_confirmar}}?hash_txt={{hash_txt}}
Caso não tenha realizado o cadastramento em nosso sistema, favor desconsiderar a presente mensagem
Esta é uma mensagem automática. Por favor, não responda.

1
templates/email/test_tramitacao.html

@ -0,0 +1 @@
<html><body>Hello {{name}}</body></html>

38
templates/email/tramitacao.html

@ -0,0 +1,38 @@
{% load i18n %}
{% load static %}
<html>
<head></head>
<body bgcolor='#ffffff'>
<p align='center'>
<img src="{{base_url}}{% if logotipo %}{{ MEDIA_URL }}{{ logotipo }}{% else %}{% static 'img/logo.png' %}{% endif %}"
alt="Logo" class="img-responsive visible-lg-inline-block vcenter" >
</p>
<h2 align='center'><b>{{casa_legislativa}}</b>
<br/>
Sistema de Apoio ao Processo Legislativo
</h2>
<p>A seguinte mat&eacute;ria de seu interesse sofreu
tramita&ccedil;&atilde;o registrada em {{data_registro}}
</p>
<h4>
<a href="{{base_url}}{{materia_url}}"><b>{{materia}} - {{descricao_materia}}</b></a>
<br/><br/>
<b>Autoria:</b></br>
{% for autor in autoria %}
{{ autor }}</br>
{% endfor %}
</h4>
<p></p>
<p>
<b>Data da a&ccedil;&atilde;o</b>: {{data}}<br/>
<b>Status</b>: {{status}}<br/>
<b>Texto da a&ccedil;&atilde;o</b>: {{texto_acao}}</p>
<hr>
<p>
<a href="{{base_url}}{{excluir_url}}?hash_txt={{hash_txt}}">
Clique aqui para excluir seu e-mail da lista de envio</a>
<p>
<p>Esta &eacute; uma mensagem autom&aacute;tica.
Por favor, n&atilde;o a responda.</p>
</body>
</html>

27
templates/email/tramitacao.txt

@ -0,0 +1,27 @@
{{casa_legislativa}}
Sistema de Apoio ao Processo Legislativo
-----------------------------------------
A seguinte matéria de seu interesse sofreu tramitação registrada em {{data_registro}}
Matéria: {{materia}} - {{descricao_materia}}
{{url_materia}}
Autoria:
{% for autor in autoria %}
{{ autor }}
{% endfor %}
Data da ação: {{data}}
Status: {{status}}
Texto da ação: {{texto_acao}}
Acesse o link abaixo para excluir seu e-mail da lista de envio
{{url_excluir_acompanhamento}}?hash_txt={{hash_txt}}
Esta é uma mensagem automática. Por favor, não a responda.

1
templates/materia/acompanhamento_materia.html

@ -18,5 +18,4 @@
{% if error %} <h5 align="center"><font color="#FF0000">{{ error }}</font></h5> {% endif %} {% if error %} <h5 align="center"><font color="#FF0000">{{ error }}</font></h5> {% endif %}
{% crispy form %} {% crispy form %}
{% endblock %} {% endblock %}

74
templates/materia/test_email_templates.py

@ -0,0 +1,74 @@
import pytest
from base.models import CasaLegislativa
from django.core import mail
from model_mommy import mommy
from materia.views import load_email_templates, enviar_email, criar_email_tramitacao
from materia.models import MateriaLegislativa, TipoMateriaLegislativa
def test_email_template_loading():
expected = "<html><body>Hello Django</body></html>"
emails = load_email_templates(['email/test_tramitacao.html'],
context={"name": "Django"})
# strip \n and \r to compare with expected
actual = emails[0].replace('\n', '').replace('\r', '')
assert actual == expected
@pytest.mark.django_db(transaction=False)
def test_email_body_creation_with_empty_materia():
casa = CasaLegislativa.objects.create()
with pytest.raises(ValueError):
criar_email_tramitacao(casa, materia=None)
def test_html_email_body_with_materia():
templates = load_email_templates(['email/tramitacao.txt',
'email/tramitacao.html'],
{"image":'img/logo.png',
"casa_legislativa":"Assembléia Parlamentar",
"data_registro":"25/02/2016",
"cod_materia":"1",
"descricao_materia":"Ementa de teste",
"autoria": ["Autor1", "Autor2"],
"data":"25/02/2016",
"status":"Arquivado",
"texto_acao":"Deliberado",
"hash_txt":"abc01f",
"materia_id": "794",
"base_url": "http://localhost:8000",
"materia_url": "/materia/764/acompanhar-materia",
"excluir_url": "/materia/764/acompanhar-excluir",})
assert len(templates) == 2
def test_enviar_email_distintos():
NUM_MESSAGES = 10
messages = [{'recipient': 'user-' + str(i) + '@test.com',
'subject': 'subject: ' + str(i),
'txt_message': 'txt: ' + str(i),
'html_message': '<html></html>',
} for i in range(NUM_MESSAGES)]
recipients = [m['recipient'] for m in messages]
enviar_email('test@sapl.com', recipients, messages)
assert len(mail.outbox) == NUM_MESSAGES
def test_enviar_same_email():
NUM_MESSAGES = 10
messages = [{'recipient': 'user-' + str(i) + '@test.com',
'subject': 'subject: ' + str(i),
'txt_message': 'txt: ' + str(i),
'html_message': '<html></html>',
} for i in range(NUM_MESSAGES)]
recipients = [m['recipient'] for m in messages]
enviar_email('test@sapl.com', recipients, [messages[0]])
assert len(mail.outbox) == 1
Loading…
Cancel
Save