diff --git a/sapl/materia/email_utils.py b/sapl/base/email_utils.py similarity index 56% rename from sapl/materia/email_utils.py rename to sapl/base/email_utils.py index 3dc6b220d..737449e57 100644 --- a/sapl/materia/email_utils.py +++ b/sapl/base/email_utils.py @@ -8,7 +8,8 @@ from django.utils import timezone from sapl.base.models import CasaLegislativa from sapl.settings import EMAIL_SEND_USER -from .models import AcompanhamentoMateria +from sapl.materia.models import AcompanhamentoMateria +from sapl.protocoloadm.models import AcompanhamentoDocumento def load_email_templates(templates, context={}): @@ -61,56 +62,73 @@ def enviar_emails(sender, recipients, messages): fail_silently=False) -def criar_email_confirmacao(base_url, casa_legislativa, materia, hash_txt=''): +def criar_email_confirmacao(base_url, casa_legislativa, doc_mat, tipo, hash_txt=''): if not casa_legislativa: raise ValueError("Casa Legislativa é obrigatória") - if not materia: - raise ValueError("Matéria é obrigatória") + if not doc_mat: + if tipo == "materia": + msg = "Matéria é obrigatória" + else: + msg = "Documento é obrigatório" + raise ValueError(msg) # FIXME i18n - casa_nome = (casa_legislativa.nome + ' de ' + - casa_legislativa.municipio + '-' + - casa_legislativa.uf) + casa_nome = ("{} de {} - {}".format(casa_legislativa.nome, + casa_legislativa.municipio, + casa_legislativa.uf)) + + if tipo == "materia": + doc_mat_url = reverse('sapl.materia:materialegislativa_detail', + kwargs={'pk': doc_mat.id}) + confirmacao_url = reverse('sapl.materia:acompanhar_confirmar', + kwargs={'pk': doc_mat.id}) + ementa = doc_mat.ementa + autores = [autoria.autor.nome for autoria in doc_mat.autoria_set.all()] + else: + doc_mat_url = reverse('sapl.protocoloadm:documentoadministrativo_detail', + kwargs={'pk': doc_mat.id}) + confirmacao_url = reverse('sapl.protocoloadm:acompanhar_confirmar', + kwargs={'pk': doc_mat.id}) + ementa = doc_mat.assunto + autores = "" - 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, + "descricao_materia": ementa, "autoria": autores, "hash_txt": hash_txt, "base_url": base_url, - "materia": str(materia), - "materia_url": materia_url, + "materia": str(doc_mat), + "materia_url": doc_mat_url, "confirmacao_url": confirmacao_url, }) return templates -def do_envia_email_confirmacao(base_url, casa, materia, destinatario): +def do_envia_email_confirmacao(base_url, casa, tipo, doc_mat, 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" + if tipo == "materia": + msg = " - Ative o Acompanhamento da Matéria" + else: + msg = " - Ative o Acompanhamento de Documento" + subject = "[SAPL] {} {}".format(str(doc_mat), msg) messages = [] recipients = [] email_texts = criar_email_confirmacao(base_url, casa, - materia, + doc_mat, + tipo, destinatario.hash,) recipients.append(destinatario.email) messages.append({ @@ -123,30 +141,41 @@ def do_envia_email_confirmacao(base_url, casa, materia, destinatario): enviar_emails(sender, recipients, messages) -def criar_email_tramitacao(base_url, casa_legislativa, materia, status, +def criar_email_tramitacao(base_url, casa_legislativa, tipo, doc_mat, status, unidade_destino, hash_txt=''): if not casa_legislativa: raise ValueError("Casa Legislativa é obrigatória") - if not materia: - raise ValueError("Matéria é obrigatória") + if not doc_mat: + if tipo == "materia": + msg = "Matéria é obrigatória" + else: + msg = "Documento é obrigatório" + raise ValueError(msg) # 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}) + casa_nome = ("{} de {} - {}".format(casa_legislativa.nome, + casa_legislativa.municipio, + casa_legislativa.uf)) + if tipo == "materia": + doc_mat_url = reverse('sapl.materia:tramitacao_list', + kwargs={'pk': doc_mat.id}) + url_excluir = reverse('sapl.materia:acompanhar_excluir', + kwargs={'pk': doc_mat.id}) + + ementa = doc_mat.ementa + autores = [autoria.autor.nome for autoria in doc_mat.autoria_set.all()] + tramitacao = doc_mat.tramitacao_set.last() - autores = [] - for autoria in materia.autoria_set.all(): - autores.append(autoria.autor.nome) - - tramitacao = materia.tramitacao_set.last() + else: + doc_mat_url = reverse('sapl.protocoloadm:tramitacaoadministrativo_list', + kwargs={'pk': doc_mat.id}) + url_excluir = reverse('sapl.protocoloadm:acompanhar_excluir', + kwargs={'pk': doc_mat.id}) + autores = "" + ementa = doc_mat.assunto + tramitacao = doc_mat.tramitacaoadministrativo_set.last() templates = load_email_templates(['email/tramitacao.txt', 'email/tramitacao.html'], @@ -154,34 +183,42 @@ def criar_email_tramitacao(base_url, casa_legislativa, materia, status, "data_registro": dt.strftime( timezone.now(), "%d/%m/%Y"), - "cod_materia": materia.id, + "cod_materia": doc_mat.id, "logotipo": casa_legislativa.logotipo, - "descricao_materia": materia.ementa, + "descricao_materia": ementa, "autoria": autores, "data": tramitacao.data_tramitacao, "status": status, "localizacao": unidade_destino, "texto_acao": tramitacao.texto, "hash_txt": hash_txt, - "materia": str(materia), + "materia": str(doc_mat), "base_url": base_url, - "materia_url": url_materia, + "materia_url": doc_mat_url, "excluir_url": url_excluir}) return templates -def do_envia_email_tramitacao(base_url, materia, status, unidade_destino): +def do_envia_email_tramitacao(base_url, tipo, doc_mat, status, unidade_destino): # # Envia email de tramitacao para usuarios cadastrados # - destinatarios = AcompanhamentoMateria.objects.filter(materia=materia, - confirmado=True) + if tipo == "materia": + destinatarios = AcompanhamentoMateria.objects.filter(materia=doc_mat, + confirmado=True) + else: + destinatarios = AcompanhamentoDocumento.objects.filter(documento=doc_mat, + confirmado=True) + casa = CasaLegislativa.objects.first() sender = EMAIL_SEND_USER - # FIXME i18n - subject = "[SAPL] " + str(materia) + \ - " - Acompanhamento de Materia Legislativa" + # FIXME i18nn + if tipo == "materia": + msg = " - Acompanhamento de Matéria Legislativa" + else: + msg = " - Acompanhamento de Documento" + subject = "[SAPL] {} {}".format(str(doc_mat), msg) connection = get_connection() connection.open() @@ -190,10 +227,11 @@ def do_envia_email_tramitacao(base_url, materia, status, unidade_destino): try: email_texts = criar_email_tramitacao(base_url, casa, - materia, + tipo, + doc_mat, status, unidade_destino, - destinatario.hash,) + destinatario.hash) email = EmailMultiAlternatives( subject, diff --git a/sapl/base/receivers.py b/sapl/base/receivers.py new file mode 100644 index 000000000..b2176be14 --- /dev/null +++ b/sapl/base/receivers.py @@ -0,0 +1,42 @@ +from django.db.models.signals import post_delete, post_save +from django.dispatch import receiver + +from sapl.materia.models import Tramitacao +from sapl.protocoloadm.models import TramitacaoAdministrativo +from sapl.base.signals import tramitacao_signal +from sapl.utils import get_base_url + +from sapl.base.email_utils import do_envia_email_tramitacao + + +@receiver(tramitacao_signal) +def handle_tramitacao_signal(sender, **kwargs): + tramitacao = kwargs.get("post") + request = kwargs.get("request") + if 'protocoloadm' in str(sender): + doc_mat = tramitacao.documento + tipo = "documento" + elif 'materia' in str(sender): + tipo = "materia" + doc_mat = tramitacao.materia + + do_envia_email_tramitacao( + get_base_url(request), + tipo, + doc_mat, + tramitacao.status, + tramitacao.unidade_tramitacao_destino) + + +@receiver(post_delete) +def status_tramitacao_materia(sender, instance, **kwargs): + if isinstance(sender, TramitacaoAdministrativo): + if instance.status.indicador == 'F': + materia = instance.materia + materia.em_tramitacao = True + materia.save() + elif isinstance(sender, TramitacaoAdministrativo): + if instance.status.indicador == 'F': + documento = instance.documento + documento.tramitacao = True + documento.save() diff --git a/sapl/materia/signals.py b/sapl/base/signals.py similarity index 100% rename from sapl/materia/signals.py rename to sapl/base/signals.py diff --git a/sapl/materia/apps.py b/sapl/materia/apps.py index bb4f72f73..2cc3559ae 100644 --- a/sapl/materia/apps.py +++ b/sapl/materia/apps.py @@ -8,4 +8,4 @@ class AppConfig(apps.AppConfig): verbose_name = _('Matéria') def ready(self): - from . import receivers + from sapl.base import receivers diff --git a/sapl/materia/receivers.py b/sapl/materia/receivers.py deleted file mode 100644 index 945c6636e..000000000 --- a/sapl/materia/receivers.py +++ /dev/null @@ -1,29 +0,0 @@ -from django.db.models.signals import post_delete, post_save -from django.dispatch import receiver - -from sapl.materia.models import Tramitacao -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) - - -@receiver(post_delete, sender=Tramitacao) -def status_tramitacao_materia(sender, instance, **kwargs): - if instance.status.indicador == 'F': - materia = instance.materia - materia.em_tramitacao = True - materia.save() diff --git a/sapl/materia/tests/test_email_templates.py b/sapl/materia/tests/test_email_templates.py index aac13cbb7..32b2f7ec8 100644 --- a/sapl/materia/tests/test_email_templates.py +++ b/sapl/materia/tests/test_email_templates.py @@ -1,6 +1,6 @@ from django.core import mail -from sapl.materia.email_utils import enviar_emails, load_email_templates +from sapl.base.email_utils import enviar_emails, load_email_templates def test_email_template_loading(): diff --git a/sapl/materia/views.py b/sapl/materia/views.py index 9e738dbe9..767726a97 100644 --- a/sapl/materia/views.py +++ b/sapl/materia/views.py @@ -46,7 +46,7 @@ from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, get_mime_type_from_file_extension, montar_row_autor, show_results_filter_set) -from .email_utils import do_envia_email_confirmacao +from sapl.base.email_utils import do_envia_email_confirmacao from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, AdicionarVariasAutoriasFilterSet, DespachoInicialForm, DocumentoAcessorioForm, EtiquetaPesquisaForm, @@ -65,7 +65,7 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria, RegimeTramitacao, Relatoria, StatusTramitacao, TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoProposicao, Tramitacao, UnidadeTramitacao) -from .signals import tramitacao_signal +from sapl.base.signals import tramitacao_signal AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia') @@ -1114,7 +1114,7 @@ class TramitacaoCrud(MasterDetailCrud): msg = _('Tramitação criada, mas e-mail de acompanhamento ' 'de matéria não enviado. Há problemas na configuração ' 'do e-mail.') - messages.add_message(self.request, messages.ERROR, msg) + messages.add_message(self.request, messages.WARNING, msg) return HttpResponseRedirect(self.get_success_url()) return super().form_valid(form) @@ -1141,7 +1141,7 @@ class TramitacaoCrud(MasterDetailCrud): msg = _('Tramitação atualizada, mas e-mail de acompanhamento ' 'de matéria não enviado. Há problemas na configuração ' 'do e-mail.') - messages.add_message(self.request, messages.ERROR, msg) + messages.add_message(self.request, messages.WARNING, msg) return HttpResponseRedirect(self.get_success_url()) return super().form_valid(form) @@ -1683,6 +1683,7 @@ class AcompanhamentoMateriaView(CreateView): do_envia_email_confirmacao(base_url, casa, + "materia", materia, destinatario) @@ -1876,9 +1877,9 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView): flag_error = True if flag_error: msg = _('Tramitação criada, mas e-mail de acompanhamento ' - 'de matéria não enviado. Há problemas na configuração ' - 'do e-mail.') - messages.add_message(self.request, messages.ERROR, msg) + 'de matéria não enviado. A não configuração do servidor de e-mail ' + 'impede o envio de aviso de tramitação') + messages.add_message(self.request, messages.WARNING, msg) status = StatusTramitacao.objects.get(id=request.POST['status']) diff --git a/sapl/protocoloadm/apps.py b/sapl/protocoloadm/apps.py index 8697e58d9..98e28ea36 100644 --- a/sapl/protocoloadm/apps.py +++ b/sapl/protocoloadm/apps.py @@ -6,3 +6,6 @@ class AppConfig(apps.AppConfig): name = 'sapl.protocoloadm' label = 'protocoloadm' verbose_name = _('Protocolo Administrativo') + + def ready(self): + from sapl.base import receivers diff --git a/sapl/protocoloadm/forms.py b/sapl/protocoloadm/forms.py index 9985f522f..8c441ad93 100644 --- a/sapl/protocoloadm/forms.py +++ b/sapl/protocoloadm/forms.py @@ -2,7 +2,7 @@ import django_filters from crispy_forms.bootstrap import InlineRadios from crispy_forms.helper import FormHelper -from crispy_forms.layout import HTML, Button, Fieldset, Layout +from crispy_forms.layout import HTML, Button, Column, Fieldset, Layout from django import forms from django.core.exceptions import (MultipleObjectsReturned, ObjectDoesNotExist, ValidationError) @@ -19,7 +19,8 @@ from sapl.materia.models import (MateriaLegislativa, TipoMateriaLegislativa, from sapl.utils import (RANGE_ANOS, YES_NO_CHOICES, AnoNumeroOrderingFilter, RangeWidgetOverride, autor_label, autor_modal) -from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo, +from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, + DocumentoAdministrativo, Protocolo, TipoDocumentoAdministrativo, TramitacaoAdministrativo) @@ -39,6 +40,28 @@ EM_TRAMITACAO = [('', '---------'), (0, 'Sim'), (1, 'Não')] +class AcompanhamentoDocumentoForm(ModelForm): + + class Meta: + model = AcompanhamentoDocumento + fields = ['email'] + + def __init__(self, *args, **kwargs): + + row1 = to_row([('email', 10)]) + + row1.append( + Column(form_actions(label='Cadastrar'), css_class='col-md-2') + ) + + self.helper = FormHelper() + self.helper.layout = Layout( + Fieldset( + _('Acompanhamento de Documento por e-mail'), row1 + ) + ) + super(AcompanhamentoDocumentoForm, self).__init__(*args, **kwargs) + class ProtocoloFilterSet(django_filters.FilterSet): diff --git a/sapl/protocoloadm/migrations/0008_acompanhamentodocumento.py b/sapl/protocoloadm/migrations/0008_acompanhamentodocumento.py new file mode 100644 index 000000000..dcc25ed45 --- /dev/null +++ b/sapl/protocoloadm/migrations/0008_acompanhamentodocumento.py @@ -0,0 +1,32 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.9.13 on 2018-09-27 15:24 +from __future__ import unicode_literals + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + dependencies = [ + ('protocoloadm', '0007_auto_20180924_1724'), + ] + + operations = [ + migrations.CreateModel( + name='AcompanhamentoDocumento', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('usuario', models.CharField(max_length=50)), + ('email', models.EmailField(max_length=100, verbose_name='E-mail')), + ('data_cadastro', models.DateField(auto_now_add=True)), + ('hash', models.CharField(max_length=8)), + ('confirmado', models.BooleanField(default=False)), + ('documento', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='protocoloadm.DocumentoAdministrativo')), + ], + options={ + 'verbose_name_plural': 'Acompanhamentos de Documento', + 'verbose_name': 'Acompanhamento de Documento', + }, + ), + ] diff --git a/sapl/protocoloadm/models.py b/sapl/protocoloadm/models.py index 52bd9ad22..908aac542 100644 --- a/sapl/protocoloadm/models.py +++ b/sapl/protocoloadm/models.py @@ -298,3 +298,30 @@ class TramitacaoAdministrativo(models.Model): return _('%(documento)s - %(status)s') % { 'documento': self.documento, 'status': self.status } + +@reversion.register() +class AcompanhamentoDocumento(models.Model): + usuario = models.CharField(max_length=50) + documento = models.ForeignKey(DocumentoAdministrativo, on_delete=models.CASCADE) + email = models.EmailField( + max_length=100, verbose_name=_('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 Documento') + verbose_name_plural = _('Acompanhamentos de Documento') + + def __str__(self): + if self.data_cadastro is None: + return _('%(documento)s - %(email)s') % { + 'documento': self.documento, + 'email': self.email + } + else: + return _('%(documento)s - %(email)s - Registrado em: %(data)s') % { + 'documento': self.documento, + 'email': self.email, + 'data': str(self.data_cadastro.strftime('%d/%m/%Y')) + } diff --git a/sapl/protocoloadm/tests/test_docadm_email_templates.py b/sapl/protocoloadm/tests/test_docadm_email_templates.py new file mode 100644 index 000000000..ec79098fa --- /dev/null +++ b/sapl/protocoloadm/tests/test_docadm_email_templates.py @@ -0,0 +1,65 @@ +from django.core import mail + +from sapl.base.email_utils import enviar_emails, load_email_templates + + +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 + + +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": "Assunto de teste", + "data": "25/02/2016", + "status": "Arquivado", + "texto_acao": "Deliberado", + "hash_txt": "abc01f", + "materia_id": "794", + "base_url": "http://localhost:8000", + "materia_url": + "/docadm/764/acompanhar-documento", + "excluir_url": + "/docadm/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_emails('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_emails('test@sapl.com', recipients, [messages[0]]) + assert len(mail.outbox) == 1 diff --git a/sapl/protocoloadm/urls.py b/sapl/protocoloadm/urls.py index 8ed9216f2..67d5edb65 100644 --- a/sapl/protocoloadm/urls.py +++ b/sapl/protocoloadm/urls.py @@ -1,6 +1,9 @@ from django.conf.urls import include, url -from sapl.protocoloadm.views import (AnularProtocoloAdmView, +from sapl.protocoloadm.views import (AcompanhamentoDocumentoView, + AcompanhamentoConfirmarView, + AcompanhamentoExcluirView, + AnularProtocoloAdmView, ComprovanteProtocoloView, CriarDocumentoProtocolo, DocumentoAcessorioAdministrativoCrud, @@ -56,6 +59,15 @@ urlpatterns_protocolo = [ url(r'^protocoloadm/(?P\d+)/protocolo-mostrar$', ProtocoloMostrarView.as_view(), name='protocolo_mostrar'), + url(r'^docadm/(?P\d+)/acompanhar-documento/$', + AcompanhamentoDocumentoView.as_view(), name='acompanhar_documento'), + url(r'^docadm/(?P\d+)/acompanhar-confirmar$', + AcompanhamentoConfirmarView.as_view(), + name='acompanhar_confirmar'), + url(r'^docadm/(?P\d+)/acompanhar-excluir$', + AcompanhamentoExcluirView.as_view(), + name='acompanhar_excluir'), + url(r'^protocoloadm/(?P\d+)/continuar$', diff --git a/sapl/protocoloadm/views.py b/sapl/protocoloadm/views.py index d58b1e11b..67ea62d5d 100644 --- a/sapl/protocoloadm/views.py +++ b/sapl/protocoloadm/views.py @@ -1,3 +1,6 @@ +from datetime import datetime +from random import choice +from string import ascii_letters, digits from braces.views import FormValidMessageMixin from django.contrib import messages @@ -18,25 +21,30 @@ from django.views.generic.edit import FormView from django_filters.views import FilterView import sapl -from sapl.base.models import Autor +from sapl.base.models import Autor, CasaLegislativa 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_client_ip, +from sapl.utils import (create_barcode, get_base_url, get_client_ip, get_mime_type_from_file_extension, show_results_filter_set) - -from .forms import (AnularProcoloAdmForm, DocumentoAcessorioAdministrativoForm, +from sapl.base.email_utils import do_envia_email_confirmacao +from .forms import (AcompanhamentoDocumentoForm, AnularProcoloAdmForm, + DocumentoAcessorioAdministrativoForm, DocumentoAdministrativoFilterSet, DocumentoAdministrativoForm, ProtocoloDocumentForm, ProtocoloFilterSet, ProtocoloMateriaForm, - TramitacaoAdmEditForm, TramitacaoAdmForm, DesvincularDocumentoForm, DesvincularMateriaForm, - filtra_tramitacao_adm_destino_and_status, filtra_tramitacao_adm_destino, filtra_tramitacao_adm_status) -from .models import (DocumentoAcessorioAdministrativo, DocumentoAdministrativo, - StatusTramitacaoAdministrativo, + TramitacaoAdmEditForm, TramitacaoAdmForm, + DesvincularDocumentoForm, DesvincularMateriaForm, + filtra_tramitacao_adm_destino_and_status, + filtra_tramitacao_adm_destino, filtra_tramitacao_adm_status) +from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, + DocumentoAdministrativo, StatusTramitacaoAdministrativo, TipoDocumentoAdministrativo, TramitacaoAdministrativo) +from sapl.base.signals import tramitacao_signal + TipoDocumentoAdministrativoCrud = CrudAux.build( TipoDocumentoAdministrativo, '') @@ -89,6 +97,136 @@ def doc_texto_integral(request, pk): return response raise Http404 +class AcompanhamentoConfirmarView(TemplateView): + + def get_redirect_url(self, email): + msg = _('Este documento está sendo acompanhado pelo e-mail: %s') % ( + email) + messages.add_message(self.request, messages.SUCCESS, msg) + return reverse('sapl.protocoloadm:documentoadministrativo_detail', + kwargs={'pk': self.kwargs['pk']}) + + def get(self, request, *args, **kwargs): + documento_id = kwargs['pk'] + hash_txt = request.GET.get('hash_txt', '') + + try: + acompanhar = AcompanhamentoDocumento.objects.get( + documento_id=documento_id, + hash=hash_txt) + except ObjectDoesNotExist: + raise Http404() + # except MultipleObjectsReturned: + # A melhor solução deve ser permitir que a exceção + # (MultipleObjectsReturned) seja lançada e vá para o log, + # pois só poderá ser causada por um erro de desenvolvimente + + acompanhar.confirmado = True + acompanhar.save() + + return HttpResponseRedirect(self.get_redirect_url(acompanhar.email)) + + +class AcompanhamentoExcluirView(TemplateView): + + def get_success_url(self): + msg = _('Você parou de acompanhar este Documento.') + messages.add_message(self.request, messages.INFO, msg) + return reverse('sapl.protocoloadm:documentoadministrativo_detail', + kwargs={'pk': self.kwargs['pk']}) + + def get(self, request, *args, **kwargs): + materia_id = kwargs['pk'] + hash_txt = request.GET.get('hash_txt', '') + + try: + AcompanhamentoDocumento.objects.get(documento_id=documento_id, + hash=hash_txt).delete() + except ObjectDoesNotExist: + pass + + return HttpResponseRedirect(self.get_success_url()) + + +class AcompanhamentoDocumentoView(CreateView): + template_name = "protocoloadm/acompanhamento_documento.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'] + documento = DocumentoAdministrativo.objects.get(id=pk) + + return self.render_to_response( + {'form': AcompanhamentoDocumentoForm(), + 'documento': documento}) + + def post(self, request, *args, **kwargs): + form = AcompanhamentoDocumentoForm(request.POST) + pk = self.kwargs['pk'] + documento = DocumentoAdministrativo.objects.get(id=pk) + + if form.is_valid(): + email = form.cleaned_data['email'] + usuario = request.user + + hash_txt = self.get_random_chars() + + acompanhar = AcompanhamentoDocumento.objects.get_or_create( + documento=documento, + email=form.data['email']) + + # Se o segundo elemento do retorno do get_or_create for True + # quer dizer que o elemento não existia + if acompanhar[1]: + acompanhar = acompanhar[0] + acompanhar.hash = hash_txt + acompanhar.usuario = usuario.username + acompanhar.confirmado = False + acompanhar.save() + + base_url = get_base_url(request) + + destinatario = AcompanhamentoDocumento.objects.get( + documento=documento, + email=email, + confirmado=False) + casa = CasaLegislativa.objects.first() + + do_envia_email_confirmacao(base_url, + casa, + "documento", + documento, + 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 deste documento.') + messages.add_message(request, messages.SUCCESS, msg) + + # Caso esse Acompanhamento já exista + # avisa ao usuário que esse documento já está sendo acompanhado + else: + msg = _('Este e-mail já está acompanhando esse documento.') + messages.add_message(request, messages.INFO, msg) + + return self.render_to_response( + {'form': form, + 'documento': documento, + 'error': _('Esse documento já está\ + sendo acompanhada por este e-mail.')}) + return HttpResponseRedirect(self.get_success_url()) + else: + return self.render_to_response( + {'form': form, + 'documento': documento}) + + def get_success_url(self): + return reverse('sapl.protocoloadm:documentoadministrativo_detail', + kwargs={'pk': self.kwargs['pk']}) + class DocumentoAdministrativoMixin: @@ -686,8 +824,38 @@ class TramitacaoAdmCrud(MasterDetailCrud): 'unidade_tramitacao_local'].widget.attrs['disabled'] = True return context + def form_valid(self, form): + self.object = form.save() + + try: + tramitacao_signal.send(sender=TramitacaoAdministrativo, + post=self.object, + request=self.request) + except Exception as e: + # TODO log error + msg = _('Tramitação criada, mas e-mail de acompanhamento ' + 'de documento não enviado. A não configuração do' + ' servidor de e-mail impede o envio de aviso de tramitação') + messages.add_message(self.request, messages.WARNING, msg) + return HttpResponseRedirect(self.get_success_url()) + return super().form_valid(form) + class UpdateView(MasterDetailCrud.UpdateView): form_class = TramitacaoAdmEditForm + def form_valid(self, form): + self.object = form.save() + try: + tramitacao_signal.send(sender=TramitacaoAdministrativo, + post=self.object, + request=self.request) + except Exception as e: + # TODO log error + msg = _('Tramitação criada, mas e-mail de acompanhamento ' + 'de documento não enviado. A não configuração do' + ' servidor de e-mail impede o envio de aviso de tramitação') + messages.add_message(self.request, messages.WARNING, msg) + return HttpResponseRedirect(self.get_success_url()) + return super().form_valid(form) class ListView(DocumentoAdministrativoMixin, MasterDetailCrud.ListView): diff --git a/sapl/rules/map_rules.py b/sapl/rules/map_rules.py index 47a43d9e1..1a2d1fe8b 100644 --- a/sapl/rules/map_rules.py +++ b/sapl/rules/map_rules.py @@ -302,6 +302,7 @@ rules_group_anonymous = { 'group': SAPL_GROUP_ANONYMOUS, 'rules': [ (materia.AcompanhamentoMateria, [RP_ADD, RP_DELETE]), + (protocoloadm.AcompanhamentoDocumento, [RP_ADD, RP_DELETE]), ] } diff --git a/sapl/rules/tests/test_rules.py b/sapl/rules/tests/test_rules.py index 07302bae5..e1ed7f7e4 100644 --- a/sapl/rules/tests/test_rules.py +++ b/sapl/rules/tests/test_rules.py @@ -11,6 +11,7 @@ from sapl.compilacao.models import (PerfilEstruturalTextoArticulado, TipoDispositivo, TipoDispositivoRelationship) from sapl.materia.models import AcompanhamentoMateria +from sapl.protocoloadm.models import AcompanhamentoDocumento from sapl.rules import SAPL_GROUPS, map_rules from sapl.test_urls import create_perms_post_migrate from scripts.lista_permissions_in_decorators import \ @@ -61,6 +62,7 @@ __fp__in__test_permission_of_models_in_rules_patterns = { PerfilEstruturalTextoArticulado], map_rules.RP_CHANGE: [AcompanhamentoMateria, + AcompanhamentoDocumento, TipoDispositivo, TipoDispositivoRelationship, PerfilEstruturalTextoArticulado], @@ -71,11 +73,13 @@ __fp__in__test_permission_of_models_in_rules_patterns = { PerfilEstruturalTextoArticulado], map_rules.RP_LIST: [AcompanhamentoMateria, + AcompanhamentoDocumento, TipoDispositivo, TipoDispositivoRelationship, PerfilEstruturalTextoArticulado], map_rules.RP_DETAIL: [AcompanhamentoMateria, + AcompanhamentoDocumento, TipoDispositivo, TipoDispositivoRelationship, PerfilEstruturalTextoArticulado] diff --git a/sapl/templates/email/acompanhar_documento.html b/sapl/templates/email/acompanhar_documento.html new file mode 100644 index 000000000..f90558568 --- /dev/null +++ b/sapl/templates/email/acompanhar_documento.html @@ -0,0 +1,25 @@ +{% load i18n %} +{% load static %} + + +

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

+ +

Registramos seu pedido para acompanhamento por e-mail do documento administrativo identificado a seguir:

+{{documento}} - {{descricao_documento}}
+{{assunto}}
+ +

+

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/sapl/templates/email/acompanhar_documento.txt b/sapl/templates/email/acompanhar_documento.txt new file mode 100644 index 000000000..eab05d7d1 --- /dev/null +++ b/sapl/templates/email/acompanhar_documento.txt @@ -0,0 +1,16 @@ +{{casa_legislativa}} + +Sistema de Apoio ao Processo Legislativo + +>Registramos seu pedido para acompanhamento por e-mail do documento administrativo identificado a seguir: + +{{base_url}}{{documento_url}} - {{documento}} - {{descricao_documento}} + +{{assunto}} + +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/sapl/templates/email/tramitacao.html b/sapl/templates/email/tramitacao.html index 4b30a1dc5..362fc563a 100644 --- a/sapl/templates/email/tramitacao.html +++ b/sapl/templates/email/tramitacao.html @@ -13,10 +13,12 @@

{{materia}} - {{descricao_materia}}

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

diff --git a/sapl/templates/email/tramitacao.txt b/sapl/templates/email/tramitacao.txt index f0a06687a..bb68a87a0 100644 --- a/sapl/templates/email/tramitacao.txt +++ b/sapl/templates/email/tramitacao.txt @@ -8,12 +8,12 @@ A seguinte matéria, de seu interesse, sofreu Tramitação registrada em {{data_ Matéria: {{materia}} - {{descricao_materia}} {{url_materia}} - +{% if autoria %} Autoria: {% for autor in autoria %} {{ autor }} {% endfor %} - +{% endif %} Data da ação: {{data}} Status: {{status}} diff --git a/sapl/templates/protocoloadm/acompanhamento_documento.html b/sapl/templates/protocoloadm/acompanhamento_documento.html new file mode 100644 index 000000000..b6526cc52 --- /dev/null +++ b/sapl/templates/protocoloadm/acompanhamento_documento.html @@ -0,0 +1,21 @@ +{% extends "crud/detail.html" %} +{% load i18n %} +{% load crispy_forms_tags %} +{% block actions %} {% endblock %} +{% block detail_content %} + +

Acompanhamento de Documento

+
+
+
Tipo: {{documento.tipo.sigla}} - {{documento.tipo.descricao}}
+
Número: {{documento.numero}}
+
Ano: {{documento.ano}}
+ +
+
+
Assunto: {{documento.assunto|safe}}
+
+ +{% if error %}
{{ error }}
{% endif %} +{% crispy form %} +{% endblock %} diff --git a/sapl/templates/protocoloadm/documentoadministrativo_filter.html b/sapl/templates/protocoloadm/documentoadministrativo_filter.html index e87962273..6dbd95276 100644 --- a/sapl/templates/protocoloadm/documentoadministrativo_filter.html +++ b/sapl/templates/protocoloadm/documentoadministrativo_filter.html @@ -63,6 +63,9 @@ {% if d.texto_integral %} Texto Integral
{% endif %} + {% if d.tramitacao %} + Acompanhar Documento + {% endif %}