diff --git a/comissoes/models.py b/comissoes/models.py index 6876debc2..074ffb3e7 100644 --- a/comissoes/models.py +++ b/comissoes/models.py @@ -1,7 +1,7 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ -from model_utils import Choices +from model_utils import Choices from parlamentares.models import Parlamentar from sapl.utils import YES_NO_CHOICES diff --git a/materia/forms.py b/materia/forms.py index 13a4f68a6..5c9434a6e 100644 --- a/materia/forms.py +++ b/materia/forms.py @@ -11,10 +11,11 @@ from norma.models import LegislacaoCitada, TipoNormaJuridica from parlamentares.models import Parlamentar, Partido from sapl.layout import form_actions -from .models import (Anexada, Autor, DespachoInicial, DocumentoAcessorio, - MateriaLegislativa, Numeracao, Origem, Proposicao, - Relatoria, StatusTramitacao, TipoAutor, TipoDocumento, - TipoMateriaLegislativa, Tramitacao, UnidadeTramitacao) +from .models import (AcompanhamentoMateria, Anexada, Autor, DespachoInicial, + DocumentoAcessorio, MateriaLegislativa, Numeracao, Origem, + Proposicao, Relatoria, StatusTramitacao, TipoAutor, + TipoDocumento, TipoMateriaLegislativa, Tramitacao, + UnidadeTramitacao) def get_range_anos(): @@ -109,6 +110,29 @@ class ProposicaoForm(ModelForm): *args, **kwargs) +class AcompanhamentoMateriaForm(ModelForm): + + class Meta: + model = AcompanhamentoMateria + fields = ['email'] + + def __init__(self, *args, **kwargs): + + row1 = sapl.layout.to_row([('email', 10)]) + + row1.append( + Column(form_actions(save_label='Cadastrar'), css_class='col-md-2') + ) + + self.helper = FormHelper() + self.helper.layout = Layout( + Fieldset( + 'Acompanhamento de Matéria por e-mail', row1 + ) + ) + super(AcompanhamentoMateriaForm, self).__init__(*args, **kwargs) + + class DocumentoAcessorioForm(ModelForm): tipo = forms.ModelChoiceField( diff --git a/materia/migrations/0016_auto_20160223_0813.py b/materia/migrations/0016_auto_20160223_0813.py new file mode 100644 index 000000000..0d2cb84a5 --- /dev/null +++ b/materia/migrations/0016_auto_20160223_0813.py @@ -0,0 +1,28 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations +import datetime +from django.utils.timezone import utc + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0015_auto_20160216_1015'), + ] + + operations = [ + migrations.AddField( + model_name='acompanhamentomateria', + name='data_cadastro', + field=models.DateField(auto_now_add=True, default=datetime.datetime(2016, 2, 23, 11, 13, 25, 362112, tzinfo=utc)), + preserve_default=False, + ), + migrations.AddField( + model_name='acompanhamentomateria', + name='usuario', + field=models.CharField(max_length=50, default=''), + preserve_default=False, + ), + ] diff --git a/materia/migrations/0017_acompanhamentomateria_confirmado.py b/materia/migrations/0017_acompanhamentomateria_confirmado.py new file mode 100644 index 000000000..59bd9dac2 --- /dev/null +++ b/materia/migrations/0017_acompanhamentomateria_confirmado.py @@ -0,0 +1,19 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('materia', '0016_auto_20160223_0813'), + ] + + operations = [ + migrations.AddField( + model_name='acompanhamentomateria', + name='confirmado', + field=models.BooleanField(default=False), + ), + ] diff --git a/materia/models.py b/materia/models.py index 5122eb0d6..fe8710e5f 100644 --- a/materia/models.py +++ b/materia/models.py @@ -1,8 +1,8 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ -from model_utils import Choices from comissoes.models import Comissao +from model_utils import Choices from parlamentares.models import Parlamentar, Partido from sapl.utils import YES_NO_CHOICES, xstr @@ -133,11 +133,14 @@ class MateriaLegislativa(models.Model): 'tipo': self.tipo, 'numero': self.numero, 'ano': self.ano} -class AcompanhamentoMateria(models.Model): # AcompMateria +class AcompanhamentoMateria(models.Model): + usuario = models.CharField(max_length=50) materia = models.ForeignKey(MateriaLegislativa) email = models.CharField( max_length=100, verbose_name=_('Endereço de E-mail')) + data_cadastro = models.DateField(auto_now_add=True) hash = models.CharField(max_length=8) + confirmado = models.BooleanField(default=False) class Meta: verbose_name = _('Acompanhamento de Matéria') diff --git a/materia/urls.py b/materia/urls.py index e7ddf4317..3475189c0 100644 --- a/materia/urls.py +++ b/materia/urls.py @@ -1,9 +1,12 @@ from django.conf.urls import include, url -from materia.views import (AutoriaEditView, AutoriaView, - DespachoInicialEditView, DespachoInicialView, - DocumentoAcessorioEditView, DocumentoAcessorioView, - FormularioCadastroView, FormularioSimplificadoView, +from materia.views import (AcompanhamentoConfirmarView, + AcompanhamentoExcluirView, + AcompanhamentoMateriaView, AutoriaEditView, + AutoriaView, DespachoInicialEditView, + DespachoInicialView, DocumentoAcessorioEditView, + DocumentoAcessorioView, FormularioCadastroView, + FormularioSimplificadoView, LegislacaoCitadaEditView, LegislacaoCitadaView, MateriaAnexadaEditView, MateriaAnexadaView, MateriaLegislativaPesquisaView, MateriaTaView, @@ -96,4 +99,12 @@ urlpatterns = [ MateriaLegislativaPesquisaView.as_view(), name='pesquisar_materia'), url(r'^materia/pesquisar-materia-list$', PesquisaMateriaListView.as_view(), name='pesquisar_materia_list'), + url(r'^materia/(?P\d+)/acompanhar-materia/$', + AcompanhamentoMateriaView.as_view(), name='acompanhar_materia'), + url(r'^materia/(?P\d+)/acompanhar-confirmar$', + AcompanhamentoConfirmarView.as_view(), + name='acompanhar_confirmar'), + url(r'^materia/(?P\d+)/acompanhar-excluir$', + AcompanhamentoExcluirView.as_view(), + name='acompanhar_excluir'), ] diff --git a/materia/views.py b/materia/views.py index 6b9c83674..78eb123f9 100644 --- a/materia/views.py +++ b/materia/views.py @@ -1,33 +1,39 @@ from datetime import datetime +from random import choice from re import sub +from string import ascii_letters, digits from django.contrib import messages from django.core.exceptions import ObjectDoesNotExist from django.core.mail import send_mail from django.core.urlresolvers import reverse +from django.http.response import HttpResponseRedirect from django.shortcuts import redirect +from django.template import Context, loader from django.utils.html import strip_tags from django.utils.translation import ugettext_lazy as _ -from django.views.generic import ListView +from django.views.generic import ListView, TemplateView from django.views.generic.edit import FormMixin from vanilla.views import GenericView +from base.models import CasaLegislativa from comissoes.models import Comissao, Composicao from compilacao.views import IntegracaoTaView from crud import Crud, make_pagination from norma.models import LegislacaoCitada, NormaJuridica, TipoNormaJuridica from parlamentares.models import Partido -from sessao.models import AcompanharMateria +from sapl.utils import get_base_url -from .forms import (AutoriaForm, DespachoInicialForm, DocumentoAcessorioForm, +from .forms import (AcompanhamentoMateriaForm, AutoriaForm, + DespachoInicialForm, DocumentoAcessorioForm, FormularioCadastroForm, FormularioSimplificadoForm, LegislacaoCitadaForm, MateriaAnexadaForm, MateriaLegislativaPesquisaForm, NumeracaoForm, ProposicaoForm, RelatoriaForm, TramitacaoForm) -from .models import (Anexada, Autor, Autoria, DespachoInicial, - DocumentoAcessorio, MateriaLegislativa, Numeracao, Orgao, - Origem, Proposicao, RegimeTramitacao, Relatoria, - StatusTramitacao, TipoAutor, TipoDocumento, +from .models import (AcompanhamentoMateria, Anexada, Autor, Autoria, + DespachoInicial, DocumentoAcessorio, MateriaLegislativa, + Numeracao, Orgao, Origem, Proposicao, RegimeTramitacao, + Relatoria, StatusTramitacao, TipoAutor, TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao, Tramitacao, UnidadeTramitacao) @@ -757,6 +763,41 @@ class DocumentoAcessorioView(FormMixin, GenericView): return reverse('documento_acessorio', kwargs={'pk': pk}) +class AcompanhamentoConfirmarView(TemplateView): + + def get_redirect_url(self): + return reverse("sessaoplenaria:list_pauta_sessao") + + def get(self, request, *args, **kwargs): + materia_id = kwargs['pk'] + hash_txt = request.GET.get('hash_txt', '') + + acompanhar = AcompanhamentoMateria.objects.get(materia_id=materia_id, + hash=hash_txt) + acompanhar.confirmado = True + acompanhar.save() + + return HttpResponseRedirect(self.get_redirect_url()) + + +class AcompanhamentoExcluirView(TemplateView): + + def get_redirect_url(self): + return reverse("sessaoplenaria:list_pauta_sessao") + + def get(self, request, *args, **kwargs): + materia_id = kwargs['pk'] + hash_txt = request.GET.get('hash_txt', '') + + try: + AcompanhamentoMateria.objects.get(materia_id=materia_id, + hash=hash_txt).delete() + except ObjectDoesNotExist: + pass + + return HttpResponseRedirect(self.get_redirect_url()) + + class DocumentoAcessorioEditView(FormMixin, GenericView): template_name = "materia/documento_acessorio_edit.html" @@ -966,6 +1007,195 @@ class RelatoriaView(FormMixin, GenericView): 'parlamentares': parlamentares}) +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") + + 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") + + 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(): + autores.append(autoria.autor.nome) + + 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": materia.tramitacao_set.last( + ).data_tramitacao, + "status": materia.tramitacao_set.last( + ).status, + "texto_acao": + materia.tramitacao_set.last().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 = '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] + }) + + enviar_emails(sender, recipients, messages) + return None + + +def do_envia_email_tramitacao(request, materia): + # + # Envia email de tramitacao para usuarios cadastrados + # + destinatarios = AcompanhamentoMateria.objects.filter(materia=materia, + 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: + email_texts = criar_email_tramitacao(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 + + class TramitacaoView(FormMixin, GenericView): template_name = "materia/tramitacao.html" @@ -1005,16 +1235,8 @@ class TramitacaoView(FormMixin, GenericView): 'object': materia, 'tramitacoes': tramitacoes_list}) - corpo_email = ('A tramitação da matéria %s foi alterada.' % materia - ) - destinatarios = AcompanharMateria.objects.values_list( - 'email', flat=True).filter( - materia_cadastrada=materia) - send_mail('Mudança de Tramitação', - corpo_email, - 'sapl-test@interlegis.leg.br', - destinatarios, - fail_silently=True) + do_envia_email_tramitacao(request, materia) + return self.form_valid(form) else: return self.render_to_response({'form': form, @@ -1489,3 +1711,61 @@ class MateriaTaView(IntegracaoTaView): class ProposicaoTaView(IntegracaoTaView): model = Proposicao model_type_foreignkey = TipoProposicao + + +class AcompanhamentoMateriaView(materia_legislativa_crud.CrudDetailView): + template_name = "materia/acompanhamento_materia.html" + + def get_random_chars(self): + s = ascii_letters + digits + return ''.join(choice(s) for i in range(choice([6, 7]))) + + def get(self, request, *args, **kwargs): + pk = self.kwargs['pk'] + materia = MateriaLegislativa.objects.get(id=pk) + + return self.render_to_response( + {'form': AcompanhamentoMateriaForm(), + 'materia': materia}) + + def post(self, request, *args, **kwargs): + form = AcompanhamentoMateriaForm(request.POST) + pk = self.kwargs['pk'] + materia = MateriaLegislativa.objects.get(id=pk) + + if form.is_valid(): + + email = form.cleaned_data['email'] + usuario = request.user + + hash_txt = self.get_random_chars() + + try: + AcompanhamentoMateria.objects.get( + email=email, + materia=materia, + hash=hash_txt) + except ObjectDoesNotExist: + acompanhar = form.save(commit=False) + acompanhar.hash = hash_txt + acompanhar.materia = materia + acompanhar.usuario = usuario.username + acompanhar.confirmado = False + acompanhar.save() + + do_envia_email_confirmacao(request, materia, email) + + else: + return self.render_to_response( + {'form': form, + 'materia': materia, + 'error': 'Essa matéria já está\ + sendo acompanhada por este e-mail.'}) + return self.form_valid(form) + else: + return self.render_to_response( + {'form': form, + 'materia': materia}) + + def get_success_url(self): + return reverse('sessaoplenaria:list_pauta_sessao') diff --git a/norma/models.py b/norma/models.py index a8b95431a..1d9826a1d 100644 --- a/norma/models.py +++ b/norma/models.py @@ -1,9 +1,9 @@ from django.db import models from django.template import defaultfilters from django.utils.translation import ugettext_lazy as _ -from model_utils import Choices from materia.models import MateriaLegislativa +from model_utils import Choices from sapl.utils import YES_NO_CHOICES diff --git a/parlamentares/models.py b/parlamentares/models.py index 71aea7feb..f748a0233 100644 --- a/parlamentares/models.py +++ b/parlamentares/models.py @@ -2,8 +2,8 @@ import datetime from django.db import models from django.utils.translation import ugettext_lazy as _ -from model_utils import Choices +from model_utils import Choices from sapl.utils import YES_NO_CHOICES diff --git a/protocoloadm/models.py b/protocoloadm/models.py index 6b04db2b6..27b405ac6 100644 --- a/protocoloadm/models.py +++ b/protocoloadm/models.py @@ -2,9 +2,9 @@ from uuid import uuid4 from django.db import models from django.utils.translation import ugettext_lazy as _ -from model_utils import Choices from materia.models import Autor, TipoMateriaLegislativa, UnidadeTramitacao +from model_utils import Choices from sapl.utils import YES_NO_CHOICES diff --git a/sapl/utils.py b/sapl/utils.py index f57c90935..7f6eaea08 100644 --- a/sapl/utils.py +++ b/sapl/utils.py @@ -21,6 +21,15 @@ def xstr(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): ''' creates a base64 encoded barcode PNG image diff --git a/sessao/forms.py b/sessao/forms.py index c437a7cff..2aaa0858e 100644 --- a/sessao/forms.py +++ b/sessao/forms.py @@ -1,12 +1,12 @@ from crispy_forms.helper import FormHelper -from crispy_forms.layout import Column, Fieldset, Layout +from crispy_forms.layout import Fieldset, Layout from django import forms from django.forms import ModelForm import sapl from sapl.layout import form_actions -from .models import AcompanharMateria, SessaoPlenaria +from .models import SessaoPlenaria class PresencaForm(forms.Form): @@ -66,29 +66,6 @@ class VotacaoEditForm(forms.Form): pass -class AcompanharMateriaForm(ModelForm): - - class Meta: - model = AcompanharMateria - fields = ['email'] - - def __init__(self, *args, **kwargs): - - row1 = sapl.layout.to_row([('email', 10)]) - - row1.append( - Column(form_actions(save_label='Cadastrar'), css_class='col-md-2') - ) - - self.helper = FormHelper() - self.helper.layout = Layout( - Fieldset( - 'Acompanhamento de Matéria por e-mail', row1 - ) - ) - super(AcompanharMateriaForm, self).__init__(*args, **kwargs) - - class SessaoForm(ModelForm): hora_inicio = forms.CharField(label='Horário Inicio', diff --git a/sessao/migrations/0014_auto_20160223_0813.py b/sessao/migrations/0014_auto_20160223_0813.py new file mode 100644 index 000000000..fa1fc08f2 --- /dev/null +++ b/sessao/migrations/0014_auto_20160223_0813.py @@ -0,0 +1,21 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models, migrations + + +class Migration(migrations.Migration): + + dependencies = [ + ('sessao', '0013_auto_20160216_1015'), + ] + + operations = [ + migrations.RemoveField( + model_name='acompanharmateria', + name='materia_cadastrada', + ), + migrations.DeleteModel( + name='AcompanharMateria', + ), + ] diff --git a/sessao/models.py b/sessao/models.py index b1e24fc43..c8bf89df4 100644 --- a/sessao/models.py +++ b/sessao/models.py @@ -1,8 +1,8 @@ from django.db import models from django.utils.translation import ugettext_lazy as _ -from model_utils import Choices from materia.models import MateriaLegislativa +from model_utils import Choices from parlamentares.models import (CargoMesa, Legislatura, Parlamentar, SessaoLegislativa) from sapl.utils import YES_NO_CHOICES @@ -281,11 +281,3 @@ class SessaoPlenariaPresenca(models.Model): verbose_name = _('Presença em Sessão Plenária') verbose_name_plural = _('Presenças em Sessões Plenárias') ordering = ['parlamentar__nome_parlamentar'] - - -class AcompanharMateria(models.Model): - usuario = models.CharField(max_length=50) - email = models.CharField( - max_length=50, verbose_name=_('Endereço de email')) - data_cadastro = models.DateField(auto_now_add=True) - materia_cadastrada = models.ForeignKey(MateriaLegislativa) diff --git a/sessao/urls.py b/sessao/urls.py index 2d481686d..8e8e17e23 100644 --- a/sessao/urls.py +++ b/sessao/urls.py @@ -1,14 +1,14 @@ from django.conf.urls import include, url from sapl import settings -from sessao.views import (AcompanharMateriaView, EditExpedienteOrdemDiaView, - EditMateriaOrdemDiaView, ExpedienteOrdemDiaView, - ExpedienteView, ExplicacaoDelete, ExplicacaoEdit, - ExplicacaoView, ListExpedienteOrdemDiaView, - ListMateriaOrdemDiaView, MateriaOrdemDiaView, - MesaView, OradorExpedienteDelete, - OradorExpedienteEdit, OradorExpedienteView, - PainelView, PautaExpedienteDetail, PautaOrdemDetail, +from sessao.views import (EditExpedienteOrdemDiaView, EditMateriaOrdemDiaView, + ExpedienteOrdemDiaView, ExpedienteView, + ExplicacaoDelete, ExplicacaoEdit, ExplicacaoView, + ListExpedienteOrdemDiaView, ListMateriaOrdemDiaView, + MateriaOrdemDiaView, MesaView, + OradorExpedienteDelete, OradorExpedienteEdit, + OradorExpedienteView, PainelView, + PautaExpedienteDetail, PautaOrdemDetail, PautaSessaoDetailView, PautaSessaoListView, PresencaOrdemDiaView, PresencaView, ResumoView, SessaoCadastroView, SessaoListView, @@ -95,8 +95,6 @@ urlpatterns_sessao = sessao_crud.urlpatterns + [ PautaExpedienteDetail.as_view(), name='pauta_expediente_detail'), url(r'^pauta-sessao/(?P\d+)/ordem/$', PautaOrdemDetail.as_view(), name='pauta_ordem_detail'), - url(r'^pauta-sessao/(?P\d+)/acompanhar-materia/$', - AcompanharMateriaView.as_view(), name='acompanhar_materia'), ] sessao_urls = urlpatterns_sessao, sessao_crud.namespace, sessao_crud.namespace diff --git a/sessao/views.py b/sessao/views.py index 1e795e169..60ba39c28 100644 --- a/sessao/views.py +++ b/sessao/views.py @@ -16,13 +16,13 @@ from norma.models import NormaJuridica from parlamentares.models import Parlamentar from sessao.serializers import SessaoPlenariaSerializer -from .forms import (AcompanharMateriaForm, ExpedienteForm, ListMateriaForm, - MateriaOrdemDiaForm, MesaForm, OradorDeleteForm, - OradorForm, PresencaForm, SessaoForm, VotacaoEditForm, - VotacaoForm, VotacaoNominalForm) -from .models import (AcompanharMateria, CargoMesa, ExpedienteMateria, - ExpedienteSessao, IntegranteMesa, MateriaLegislativa, - Orador, OradorExpediente, OrdemDia, PresencaOrdemDia, +from .forms import (ExpedienteForm, ListMateriaForm, MateriaOrdemDiaForm, + MesaForm, OradorDeleteForm, OradorForm, PresencaForm, + SessaoForm, VotacaoEditForm, VotacaoForm, + VotacaoNominalForm) +from .models import (CargoMesa, ExpedienteMateria, ExpedienteSessao, + IntegranteMesa, MateriaLegislativa, Orador, + OradorExpediente, OrdemDia, PresencaOrdemDia, RegistroVotacao, SessaoPlenaria, SessaoPlenariaPresenca, TipoExpediente, TipoResultadoVotacao, TipoSessaoPlenaria, VotoParlamentar) @@ -2363,47 +2363,3 @@ class PautaOrdemDetail(sessao_crud.CrudDetailView): 'norma': norma, 'doc_ace': doc_ace, 'tramitacao': tramitacao}) - - -class AcompanharMateriaView(sessao_crud.CrudDetailView): - template_name = "sessao/pauta/acompanhar_materia.html" - - def get(self, request, *args, **kwargs): - pk = self.kwargs['pk'] - materia = MateriaLegislativa.objects.get(id=pk) - return self.render_to_response( - {'form': AcompanharMateriaForm(), - 'materia': materia}) - - def post(self, request, *args, **kwargs): - form = AcompanharMateriaForm(request.POST) - pk = self.kwargs['pk'] - materia = MateriaLegislativa.objects.get(id=pk) - - if form.is_valid(): - - email = form.cleaned_data['email'] - usuario = request.user - try: - AcompanharMateria.objects.get( - email=email, - materia_cadastrada=materia) - except ObjectDoesNotExist: - acompanhar = form.save(commit=False) - acompanhar.materia_cadastrada = materia - acompanhar.usuario = usuario.username - acompanhar.save() - else: - return self.render_to_response( - {'form': form, - 'materia': materia, - 'error': 'Essa matéria já está\ - sendo acompanhada por este e-mail.'}) - return self.form_valid(form) - else: - return self.render_to_response( - {'form': form, - 'materia': materia}) - - def get_success_url(self): - return reverse('sessaoplenaria:list_pauta_sessao') diff --git a/templates/email/acompanhar.html b/templates/email/acompanhar.html new file mode 100644 index 000000000..c95092bf2 --- /dev/null +++ b/templates/email/acompanhar.html @@ -0,0 +1,27 @@ +{% load i18n %} +{% load static %} + +

+ Logo +

+

{{casa_legislativa}} +
+ Sistema de Apoio ao Processo Legislativo +

+

Registramos seu pedido para acompanhamento por e-mail da matéria legislativa identificada a seguir:

+{{materia}} - {{descricao_materia}}
+{{ementa}}
+ +

+

Para garantia de sua privacidade, solicitamos que ative o recebimento das futuras mensagens clicando no link:

+ +

+ {{base_url}}{{confirmacao_url}}?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.

+ + diff --git a/templates/email/acompanhar.txt b/templates/email/acompanhar.txt new file mode 100644 index 000000000..f1745a917 --- /dev/null +++ b/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. diff --git a/templates/email/test_tramitacao.html b/templates/email/test_tramitacao.html new file mode 100644 index 000000000..dfb057fe8 --- /dev/null +++ b/templates/email/test_tramitacao.html @@ -0,0 +1 @@ +Hello {{name}} diff --git a/templates/email/tramitacao.html b/templates/email/tramitacao.html new file mode 100644 index 000000000..6ca454903 --- /dev/null +++ b/templates/email/tramitacao.html @@ -0,0 +1,38 @@ +{% load i18n %} +{% load static %} + + + +

+ Logo +

+

{{casa_legislativa}} +
+ Sistema de Apoio ao Processo Legislativo +

+

A seguinte matéria de seu interesse sofreu + tramitação registrada em {{data_registro}} +

+

+ {{materia}} - {{descricao_materia}} +

+Autoria:
+{% for autor in autoria %} + {{ autor }}
+{% endfor %} +

+

+

+ Data da ação: {{data}}
+ Status: {{status}}
+ Texto da ação: {{texto_acao}}

+
+

+ + Clique aqui para excluir seu e-mail da lista de envio +

+

Esta é uma mensagem automática. + Por favor, não a responda.

+ + diff --git a/templates/email/tramitacao.txt b/templates/email/tramitacao.txt new file mode 100644 index 000000000..0e84653e8 --- /dev/null +++ b/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. diff --git a/templates/sessao/pauta/acompanhar_materia.html b/templates/materia/acompanhamento_materia.html similarity index 100% rename from templates/sessao/pauta/acompanhar_materia.html rename to templates/materia/acompanhamento_materia.html diff --git a/templates/materia/test_email_templates.py b/templates/materia/test_email_templates.py new file mode 100644 index 000000000..8e5b0d57b --- /dev/null +++ b/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 = "Hello Django" + 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': '', + } 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': '', + } 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 diff --git a/templates/sessao/pauta/expediente.html b/templates/sessao/pauta/expediente.html index f462323c9..7eba6583b 100644 --- a/templates/sessao/pauta/expediente.html +++ b/templates/sessao/pauta/expediente.html @@ -39,7 +39,7 @@
- Tramitação{% if expediente.materia.em_tramitacao %} >>> Acompanhar matéria <<<{% endif %} + Tramitação{% if expediente.materia.em_tramitacao %} >>> Acompanhar matéria <<<{% endif %} {% for t in tramitacao %} Data: {{t.data_tramitacao}}
diff --git a/templates/sessao/pauta/ordem.html b/templates/sessao/pauta/ordem.html index ccd7494d1..5e43631c4 100644 --- a/templates/sessao/pauta/ordem.html +++ b/templates/sessao/pauta/ordem.html @@ -48,7 +48,7 @@
- Tramitação{% if ordem.materia.em_tramitacao %} >>> Acompanhar matéria <<<{% endif %} + Tramitação{% if ordem.materia.em_tramitacao %} >>> Acompanhar matéria <<<{% endif %} {% for t in tramitacao %} Data: {{t.data_tramitacao}}