Browse Source

Fix #2342 (#2354)

* Fix #2432

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

* impl test de conexão

* Corrige tipo de remetente

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

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

portanto,

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

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

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

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

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

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

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

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

18
sapl/base/email_utils.py

@ -1,4 +1,5 @@
from datetime import datetime as dt from datetime import datetime as dt
import logging
from django.core.mail import EmailMultiAlternatives, get_connection, send_mail from django.core.mail import EmailMultiAlternatives, get_connection, send_mail
from django.core.urlresolvers import reverse from django.core.urlresolvers import reverse
@ -6,10 +7,10 @@ from django.template import Context, loader
from django.utils import timezone from django.utils import timezone
from sapl.base.models import CasaLegislativa from sapl.base.models import CasaLegislativa
from sapl.settings import EMAIL_SEND_USER
from sapl.materia.models import AcompanhamentoMateria from sapl.materia.models import AcompanhamentoMateria
from sapl.protocoloadm.models import AcompanhamentoDocumento from sapl.protocoloadm.models import AcompanhamentoDocumento
from sapl.settings import EMAIL_SEND_USER
from sapl.utils import mail_service_configured
def load_email_templates(templates, context={}): def load_email_templates(templates, context={}):
@ -94,8 +95,6 @@ def criar_email_confirmacao(base_url, casa_legislativa, doc_mat, tipo, hash_txt=
ementa = doc_mat.assunto ementa = doc_mat.assunto
autores = "" autores = ""
templates = load_email_templates(['email/acompanhar.txt', templates = load_email_templates(['email/acompanhar.txt',
'email/acompanhar.html'], 'email/acompanhar.html'],
{"casa_legislativa": casa_nome, {"casa_legislativa": casa_nome,
@ -115,6 +114,11 @@ def do_envia_email_confirmacao(base_url, casa, tipo, doc_mat, destinatario):
# Envia email de confirmacao para atualizações de tramitação # Envia email de confirmacao para atualizações de tramitação
# #
if not mail_service_configured():
logger = logging.getLogger(__name__)
logger.warning(_('Servidor de email não configurado.'))
return
sender = EMAIL_SEND_USER sender = EMAIL_SEND_USER
# FIXME i18n # FIXME i18n
if tipo == "materia": if tipo == "materia":
@ -203,6 +207,12 @@ def do_envia_email_tramitacao(base_url, tipo, doc_mat, status, unidade_destino):
# #
# Envia email de tramitacao para usuarios cadastrados # Envia email de tramitacao para usuarios cadastrados
# #
if not mail_service_configured():
logger = logging.getLogger(__name__)
logger.warning(_('Servidor de email não configurado.'))
return
if tipo == "materia": if tipo == "materia":
destinatarios = AcompanhamentoMateria.objects.filter(materia=doc_mat, destinatarios = AcompanhamentoMateria.objects.filter(materia=doc_mat,
confirmado=True) confirmado=True)

9
sapl/base/templatetags/common_tags.py

@ -1,5 +1,8 @@
import logging
from compressor.utils import get_class from compressor.utils import get_class
from django import template from django import template
from django.conf import settings
from django.template.defaultfilters import stringfilter from django.template.defaultfilters import stringfilter
from sapl.base.models import AppConfig from sapl.base.models import AppConfig
@ -8,6 +11,7 @@ from sapl.norma.models import NormaJuridica
from sapl.parlamentares.models import Filiacao from sapl.parlamentares.models import Filiacao
from sapl.utils import filiacao_data, SEPARADOR_HASH_PROPOSICAO from sapl.utils import filiacao_data, SEPARADOR_HASH_PROPOSICAO
register = template.Library() register = template.Library()
@ -48,6 +52,7 @@ def split(value, arg):
def to_str(arg): def to_str(arg):
return str(arg) return str(arg)
@register.filter @register.filter
def get_last_item_from_list(list, arg): def get_last_item_from_list(list, arg):
return list[arg] return list[arg]
@ -103,7 +108,6 @@ def strip_hash(value):
return value.split(SEPARADOR_HASH_PROPOSICAO)[0][1:] return value.split(SEPARADOR_HASH_PROPOSICAO)[0][1:]
@register.filter @register.filter
def get_add_perm(value, arg): def get_add_perm(value, arg):
perm = value perm = value
@ -203,6 +207,7 @@ def url(value):
return True return True
return False return False
@register.filter @register.filter
def audio_url(value): def audio_url(value):
return True if url(value) and value.endswith("mp3") else False return True if url(value) and value.endswith("mp3") else False
@ -212,11 +217,13 @@ def audio_url(value):
def video_url(value): def video_url(value):
return True if url(value) and value.endswith("mp4") else False return True if url(value) and value.endswith("mp4") else False
@register.filter @register.filter
def file_extension(value): def file_extension(value):
import pathlib import pathlib
return pathlib.Path(value).suffix.replace('.', '') return pathlib.Path(value).suffix.replace('.', '')
@register.filter @register.filter
def cronometro_to_seconds(value): def cronometro_to_seconds(value):
if not AppConfig.attr('cronometro_' + value): if not AppConfig.attr('cronometro_' + value):

45
sapl/base/views.py

@ -1,5 +1,5 @@
import os
import logging import logging
import os
from django.contrib.auth import get_user_model from django.contrib.auth import get_user_model
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
@ -33,7 +33,7 @@ from sapl.materia.models import (Autoria, MateriaLegislativa,
from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria, from sapl.sessao.models import (PresencaOrdemDia, SessaoPlenaria,
SessaoPlenariaPresenca) SessaoPlenariaPresenca)
from sapl.utils import (parlamentares_ativos, from sapl.utils import (parlamentares_ativos,
show_results_filter_set) show_results_filter_set, mail_service_configured)
from .forms import (AlterarSenhaForm, CasaLegislativaForm, from .forms import (AlterarSenhaForm, CasaLegislativaForm,
ConfiguracoesAppForm, RelatorioAtasFilterSet, ConfiguracoesAppForm, RelatorioAtasFilterSet,
@ -171,8 +171,14 @@ class AutorCrud(CrudAux):
url_reverse = reverse('sapl.base:autor_detail', url_reverse = reverse('sapl.base:autor_detail',
kwargs={'pk': pk_autor}) kwargs={'pk': pk_autor})
if not mail_service_configured():
self.logger.warning(_('Registro de Autor sem envio de email. '
'Servidor de email não configurado.'))
return url_reverse
try: try:
self.logger.debug('user=' + username + '. Enviando email na edição de Autores.') self.logger.debug('user={}. Enviando email na edição '
'de Autores.'.format(username))
kwargs = {} kwargs = {}
user = self.object.user user = self.object.user
@ -195,12 +201,13 @@ class AutorCrud(CrudAux):
"ignore esta mensagem. Caso tenha, clique " + "ignore esta mensagem. Caso tenha, clique " +
"no link abaixo\n" + url_base + "no link abaixo\n" + url_base +
reverse('sapl.base:confirmar_email', kwargs=kwargs)) reverse('sapl.base:confirmar_email', kwargs=kwargs))
remetente = [settings.EMAIL_SEND_USER] remetente = settings.EMAIL_SEND_USER
destinatario = [user.email] destinatario = [user.email]
send_mail(assunto, mensagem, remetente, destinatario, send_mail(assunto, mensagem, remetente, destinatario,
fail_silently=False) fail_silently=False)
except Exception as e: except Exception as e:
self.logger.error('user=' + username + '. Erro no envio de email na edição de Autores. ' + str(e)) self.logger.error('user={}. Erro no envio de email na edição de'
' Autores. {}'.format(username, str(e)))
return url_reverse return url_reverse
@ -225,8 +232,14 @@ class AutorCrud(CrudAux):
url_reverse = reverse('sapl.base:autor_detail', url_reverse = reverse('sapl.base:autor_detail',
kwargs={'pk': pk_autor}) kwargs={'pk': pk_autor})
if not mail_service_configured():
self.logger.warning(_('Registro de Autor sem envio de email. '
'Servidor de email não configurado.'))
return url_reverse
try: try:
self.logger.debug('user=' + username + '. Enviando email na criação de Autores.') self.logger.debug('user=' + username +
'. Enviando email na criação de Autores.')
kwargs = {} kwargs = {}
user = self.object.user user = self.object.user
@ -250,14 +263,15 @@ class AutorCrud(CrudAux):
"ignore esta mensagem. Caso tenha, clique " + "ignore esta mensagem. Caso tenha, clique " +
"no link abaixo\n" + url_base + "no link abaixo\n" + url_base +
reverse('sapl.base:confirmar_email', kwargs=kwargs)) reverse('sapl.base:confirmar_email', kwargs=kwargs))
remetente = [settings.EMAIL_SEND_USER] remetente = settings.EMAIL_SEND_USER
destinatario = [user.email] destinatario = [user.email]
send_mail(assunto, mensagem, remetente, destinatario, send_mail(assunto, mensagem, remetente, destinatario,
fail_silently=False) fail_silently=False)
except Exception as e: except Exception as e:
print( print(
_('Erro no envio de email na criação de Autores.')) _('Erro no envio de email na criação de Autores.'))
self.logger.error('user=' + username + '. Erro no envio de email na criação de Autores. ' + str(e)) self.logger.error(
'user=' + username + '. Erro no envio de email na criação de Autores. ' + str(e))
return url_reverse return url_reverse
@ -347,14 +361,17 @@ class RelatorioPresencaSessaoView(FilterView):
'ordemdia_porc': 0 'ordemdia_porc': 0
}) })
try: try:
self.logger.debug('user=' + username + '. Tentando obter presença do parlamentar (pk={}).'.format(p.id)) self.logger.debug(
'user=' + username + '. Tentando obter presença do parlamentar (pk={}).'.format(p.id))
sessao_count = presenca_sessao.get(parlamentar_id=p.id)[1] sessao_count = presenca_sessao.get(parlamentar_id=p.id)[1]
except ObjectDoesNotExist as e: except ObjectDoesNotExist as e:
self.logger.error('user=' + username + '. Erro ao obter presença do parlamentar (pk={}). Definido como 0. '.format(p.id) + str(e)) self.logger.error(
'user=' + username + '. Erro ao obter presença do parlamentar (pk={}). Definido como 0. '.format(p.id) + str(e))
sessao_count = 0 sessao_count = 0
try: try:
# Presenças de cada Ordem do Dia # Presenças de cada Ordem do Dia
self.logger.info('user=' + username + '. Tentando obter PresencaOrdemDia para o parlamentar pk={}.'.format(p.id)) self.logger.info(
'user=' + username + '. Tentando obter PresencaOrdemDia para o parlamentar pk={}.'.format(p.id))
ordemdia_count = presenca_ordem.get(parlamentar_id=p.id)[1] ordemdia_count = presenca_ordem.get(parlamentar_id=p.id)[1]
except ObjectDoesNotExist: except ObjectDoesNotExist:
self.logger.error('user=' + username + '. Erro ao obter PresencaOrdemDia para o parlamentar pk={}. ' self.logger.error('user=' + username + '. Erro ao obter PresencaOrdemDia para o parlamentar pk={}. '
@ -875,10 +892,12 @@ class HelpTopicView(TemplateView):
username = self.request.user.username username = self.request.user.username
topico = self.kwargs['topic'] topico = self.kwargs['topic']
try: try:
self.logger.debug('user=' + username + '. Tentando obter template %s.html.' % topico) self.logger.debug('user=' + username +
'. Tentando obter template %s.html.' % topico)
get_template('ajuda/%s.html' % topico) get_template('ajuda/%s.html' % topico)
except TemplateDoesNotExist as e: except TemplateDoesNotExist as e:
self.logger.error('user=' + username + '. Erro ao obter template {}.html. Template não existe. '.format(topico) + str(e)) self.logger.error(
'user=' + username + '. Erro ao obter template {}.html. Template não existe. '.format(topico) + str(e))
raise Http404() raise Http404()
return ['ajuda/%s.html' % topico] return ['ajuda/%s.html' % topico]

15
sapl/context_processors.py

@ -1,4 +1,10 @@
import logging
from django.conf import settings
from django.utils.translation import ugettext_lazy as _
from sapl.base.views import get_casalegislativa from sapl.base.views import get_casalegislativa
from sapl.utils import mail_service_configured as mail_service_configured_utils
def parliament_info(request): def parliament_info(request):
@ -7,3 +13,12 @@ def parliament_info(request):
return casa.__dict__ return casa.__dict__
else: else:
return {} return {}
def mail_service_configured(request):
if not mail_service_configured_utils(request):
logger = logging.getLogger(__name__)
logger.warning(_('Servidor de email não configurado.'))
return {'mail_service_configured': False}
return {'mail_service_configured': True}

127
sapl/materia/views.py

@ -1,9 +1,11 @@
from datetime import datetime from datetime import datetime
import logging
from random import choice from random import choice
from string import ascii_letters, digits from string import ascii_letters, digits
from crispy_forms.helper import FormHelper from crispy_forms.helper import FormHelper
from crispy_forms.layout import HTML from crispy_forms.layout import HTML
from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
@ -21,10 +23,11 @@ from django.views.generic.base import RedirectView
from django.views.generic.edit import FormView from django.views.generic.edit import FormView
from django_filters.views import FilterView from django_filters.views import FilterView
import weasyprint import weasyprint
import logging
import sapl import sapl
from sapl.base.email_utils import do_envia_email_confirmacao
from sapl.base.models import Autor, CasaLegislativa from sapl.base.models import Autor, CasaLegislativa
from sapl.base.signals import tramitacao_signal
from sapl.comissoes.models import Comissao, Participacao from sapl.comissoes.models import Comissao, Participacao
from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_RESTRICT, from sapl.compilacao.models import (STATUS_TA_IMMUTABLE_RESTRICT,
STATUS_TA_PRIVATE) STATUS_TA_PRIVATE)
@ -45,9 +48,8 @@ from sapl.protocoloadm.models import Protocolo
from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, SEPARADOR_HASH_PROPOSICAO, from sapl.utils import (YES_NO_CHOICES, autor_label, autor_modal, SEPARADOR_HASH_PROPOSICAO,
gerar_hash_arquivo, get_base_url, gerar_hash_arquivo, get_base_url,
get_mime_type_from_file_extension, montar_row_autor, get_mime_type_from_file_extension, montar_row_autor,
show_results_filter_set) show_results_filter_set, mail_service_configured)
from sapl.base.email_utils import do_envia_email_confirmacao
from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm, from .forms import (AcessorioEmLoteFilterSet, AcompanhamentoMateriaForm,
AdicionarVariasAutoriasFilterSet, DespachoInicialForm, AdicionarVariasAutoriasFilterSet, DespachoInicialForm,
DocumentoAcessorioForm, EtiquetaPesquisaForm, DocumentoAcessorioForm, EtiquetaPesquisaForm,
@ -66,7 +68,6 @@ from .models import (AcompanhamentoMateria, Anexada, AssuntoMateria, Autoria,
RegimeTramitacao, Relatoria, StatusTramitacao, RegimeTramitacao, Relatoria, StatusTramitacao,
TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa, TipoDocumento, TipoFimRelatoria, TipoMateriaLegislativa,
TipoProposicao, Tramitacao, UnidadeTramitacao) TipoProposicao, Tramitacao, UnidadeTramitacao)
from sapl.base.signals import tramitacao_signal
AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia') AssuntoMateriaCrud = CrudAux.build(AssuntoMateria, 'assunto_materia')
@ -95,7 +96,8 @@ def autores_ja_adicionados(materia_pk):
def proposicao_texto(request, pk): def proposicao_texto(request, pk):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
username = request.user.username.replace("'", "") username = request.user.username.replace("'", "")
logger.debug('user=' + username + '. Tentando obter objeto Proposicao com pk = {}.'.format(pk)) logger.debug('user=' + username +
'. Tentando obter objeto Proposicao com pk = {}.'.format(pk))
proposicao = Proposicao.objects.get(pk=pk) proposicao = Proposicao.objects.get(pk=pk)
if proposicao.texto_original: if proposicao.texto_original:
@ -119,7 +121,8 @@ def proposicao_texto(request, pk):
response['Content-Disposition'] = ( response['Content-Disposition'] = (
'inline; filename="%s"' % arquivo.name.split('/')[-1]) 'inline; filename="%s"' % arquivo.name.split('/')[-1])
return response return response
logger.error('user=' + username + '. Objeto Proposicao com pk={} não encontrado.'.format(pk)) logger.error('user=' + username +
'. Objeto Proposicao com pk={} não encontrado.'.format(pk))
raise Http404 raise Http404
@ -184,15 +187,18 @@ class CriarProtocoloMateriaView(CreateView):
username = self.request.user.username.replace("'", "") username = self.request.user.username.replace("'", "")
try: try:
self.logger.debug("user=" + username + ". Tentando obter objeto Protocolo.") self.logger.debug("user=" + username +
". Tentando obter objeto Protocolo.")
protocolo = Protocolo.objects.get(pk=self.kwargs['pk']) protocolo = Protocolo.objects.get(pk=self.kwargs['pk'])
except ObjectDoesNotExist as e: except ObjectDoesNotExist as e:
self.logger.error("user=" + username + ". Objeto Protocolo com pk={} não encontrado. ".format(self.kwargs['pk']) + str(e)) self.logger.error(
"user=" + username + ". Objeto Protocolo com pk={} não encontrado. ".format(self.kwargs['pk']) + str(e))
raise Http404() raise Http404()
numero = 1 numero = 1
try: try:
self.logger.debug("user=" + username + ". Tentando obter materias do último ano.") self.logger.debug("user=" + username +
". Tentando obter materias do último ano.")
materias_ano = MateriaLegislativa.objects.filter( materias_ano = MateriaLegislativa.objects.filter(
ano=protocolo.ano, ano=protocolo.ano,
tipo=protocolo.tipo_materia).latest('numero') tipo=protocolo.tipo_materia).latest('numero')
@ -216,10 +222,12 @@ class CriarProtocoloMateriaView(CreateView):
username = self.request.user.username.replace("'", "") username = self.request.user.username.replace("'", "")
try: try:
self.logger.info("user=" + username + ". Tentando obter objeto Procolo com pk={}.".format(self.kwargs['pk'])) self.logger.info(
"user=" + username + ". Tentando obter objeto Procolo com pk={}.".format(self.kwargs['pk']))
protocolo = Protocolo.objects.get(pk=self.kwargs['pk']) protocolo = Protocolo.objects.get(pk=self.kwargs['pk'])
except ObjectDoesNotExist: except ObjectDoesNotExist:
self.logger.error('user=' + username + '. Objeto Protocolo com pk={} não encontrado.'.format(self.kwargs['pk'])) self.logger.error(
'user=' + username + '. Objeto Protocolo com pk={} não encontrado.'.format(self.kwargs['pk']))
raise Http404() raise Http404()
if protocolo.autor: if protocolo.autor:
@ -310,11 +318,13 @@ def recuperar_materia(request):
numeracao = None numeracao = None
try: try:
logger.debug("user=" + username + ". Tentando obter numeração da matéria.") logger.debug("user=" + username +
". Tentando obter numeração da matéria.")
numeracao = sapl.base.models.AppConfig.objects.last( numeracao = sapl.base.models.AppConfig.objects.last(
).sequencia_numeracao ).sequencia_numeracao
except AttributeError as e: except AttributeError as e:
logger.error("user=" + username + ". " + str(e) + " Numeracao da matéria definida como None.") logger.error("user=" + username + ". " + str(e) +
" Numeracao da matéria definida como None.")
pass pass
if tipo.sequencia_numeracao: if tipo.sequencia_numeracao:
@ -531,7 +541,8 @@ class ReceberProposicao(PermissionRequiredForAppCrudMixin, FormView):
except IndexError: except IndexError:
messages.error(request, _('Código de recibo mal formado!')) messages.error(request, _('Código de recibo mal formado!'))
except IOError: except IOError:
messages.error(request, _('Erro abrindo texto original de proposição')) messages.error(request, _(
'Erro abrindo texto original de proposição'))
return self.form_invalid(form) return self.form_invalid(form)
def get_success_url(self): def get_success_url(self):
@ -554,14 +565,17 @@ class RetornarProposicao(UpdateView):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
username = request.user.username.replace("'", "") username = request.user.username.replace("'", "")
try: try:
self.logger.info("user=" + username + ". Tentando obter objeto Proposicao com id={}.".format(kwargs['pk'])) self.logger.info(
"user=" + username + ". Tentando obter objeto Proposicao com id={}.".format(kwargs['pk']))
p = Proposicao.objects.get(id=kwargs['pk']) p = Proposicao.objects.get(id=kwargs['pk'])
except: except:
self.logger.error("user=" + username + ". Objeto Proposicao com id={} não encontrado.".format(kwargs['pk'])) self.logger.error(
"user=" + username + ". Objeto Proposicao com id={} não encontrado.".format(kwargs['pk']))
raise Http404() raise Http404()
if p.autor.user != request.user: if p.autor.user != request.user:
self.logger.error("user=" + username + ". Usuário ({}) sem acesso a esta opção.".format(request.user)) self.logger.error(
"user=" + username + ". Usuário ({}) sem acesso a esta opção.".format(request.user))
messages.error( messages.error(
request, request,
'Usuário sem acesso a esta opção.' % 'Usuário sem acesso a esta opção.' %
@ -597,7 +611,8 @@ class ConfirmarProposicao(PermissionRequiredForAppCrudMixin, UpdateView):
recebidas -> data_recebimento != None recebidas -> data_recebimento != None
não enviadas -> data_envio == None não enviadas -> data_envio == None
""" """
self.logger.debug("user=" + username + ". Tentando obter objeto Proposicao.") self.logger.debug("user=" + username +
". Tentando obter objeto Proposicao.")
proposicao = Proposicao.objects.get(pk=self.kwargs['pk'], proposicao = Proposicao.objects.get(pk=self.kwargs['pk'],
data_envio__isnull=False, data_envio__isnull=False,
data_recebimento__isnull=True) data_recebimento__isnull=True)
@ -736,6 +751,7 @@ class ProposicaoCrud(Crud):
'materia.detail_proposicao_incorporada') 'materia.detail_proposicao_incorporada')
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
context['subnav_template_name'] = '' context['subnav_template_name'] = ''
@ -790,18 +806,22 @@ class ProposicaoCrud(Crud):
'número que pode não corresponder com a realidade' 'número que pode não corresponder com a realidade'
% (p.tipo, numero, p.ano))) % (p.tipo, numero, p.ano)))
except ValueError as e: except ValueError as e:
self.logger.error("user=" + username + "." + str(e)) self.logger.error(
"user=" + username + "." + str(e))
pass pass
except AttributeError as e: except AttributeError as e:
self.logger.error("user=" + username + "." + str(e)) self.logger.error(
"user=" + username + "." + str(e))
pass pass
except TypeError as e: except TypeError as e:
self.logger.error("user=" + username + "." + str(e)) self.logger.error(
"user=" + username + "." + str(e))
pass pass
elif action == 'return': elif action == 'return':
if not p.data_envio: if not p.data_envio:
self.logger.error("user=" + username + ". Proposição (numero={}) ainda não foi enviada.".format(p.numero_proposicao)) self.logger.error(
"user=" + username + ". Proposição (numero={}) ainda não foi enviada.".format(p.numero_proposicao))
msg_error = _('Proposição ainda não foi enviada.') msg_error = _('Proposição ainda não foi enviada.')
elif p.data_recebimento: elif p.data_recebimento:
self.logger.error("user=" + username + ". Proposição (numero={}) já foi recebida, não é " self.logger.error("user=" + username + ". Proposição (numero={}) já foi recebida, não é "
@ -816,7 +836,8 @@ class ProposicaoCrud(Crud):
ta.privacidade = STATUS_TA_PRIVATE ta.privacidade = STATUS_TA_PRIVATE
ta.editing_locked = False ta.editing_locked = False
ta.save() ta.save()
self.logger.info("user=" + username + ". Proposição (numero={}) Retornada com sucesso.".format(p.numero_proposicao)) self.logger.info(
"user=" + username + ". Proposição (numero={}) Retornada com sucesso.".format(p.numero_proposicao))
messages.success(request, _( messages.success(request, _(
'Proposição Retornada com sucesso.')) 'Proposição Retornada com sucesso.'))
@ -830,10 +851,12 @@ class ProposicaoCrud(Crud):
def dispatch(self, request, *args, **kwargs): def dispatch(self, request, *args, **kwargs):
username = request.user.username.replace("'", "") username = request.user.username.replace("'", "")
try: try:
self.logger.debug("user=" + username + ". Tentando obter objeto Proposicao com pk={}".format(kwargs['pk'])) self.logger.debug(
"user=" + username + ". Tentando obter objeto Proposicao com pk={}".format(kwargs['pk']))
p = Proposicao.objects.get(id=kwargs['pk']) p = Proposicao.objects.get(id=kwargs['pk'])
except Exception as e: except Exception as e:
self.logger.error("user=" + username + ". Erro ao obter proposicao com pk={}. Retornando 404. ".format(kwargs['pk']) + str(e)) self.logger.error(
"user=" + username + ". Erro ao obter proposicao com pk={}. Retornando 404. ".format(kwargs['pk']) + str(e))
raise Http404() raise Http404()
if not self.has_permission(): if not self.has_permission():
@ -1048,7 +1071,8 @@ class ReciboProposicaoView(TemplateView):
messages.error(request, _('Não é possível gerar recibo para uma ' messages.error(request, _('Não é possível gerar recibo para uma '
'Proposição ainda não enviada.')) 'Proposição ainda não enviada.'))
elif proposicao.data_devolucao: elif proposicao.data_devolucao:
self.logger.error("user=" + username + ". Não é possível gerar recibo para proposicao de pk={}.".format(self.kwargs['pk'])) self.logger.error(
"user=" + username + ". Não é possível gerar recibo para proposicao de pk={}.".format(self.kwargs['pk']))
messages.error(request, _('Não é possível gerar recibo.')) messages.error(request, _('Não é possível gerar recibo.'))
return redirect(reverse('sapl.materia:proposicao_detail', return redirect(reverse('sapl.materia:proposicao_detail',
@ -1070,15 +1094,18 @@ class RelatoriaCrud(MasterDetailCrud):
username = self.request.user.username.replace("'", "") username = self.request.user.username.replace("'", "")
try: try:
self.logger.debug("user=" + username + ". Tentando obter objeto Comissao de pk={}.".format(context['form'].initial['comissao'])) self.logger.debug("user=" + username + ". Tentando obter objeto Comissao de pk={}.".format(
context['form'].initial['comissao']))
comissao = Comissao.objects.get( comissao = Comissao.objects.get(
pk=context['form'].initial['comissao']) pk=context['form'].initial['comissao'])
except: except:
self.logger.error("user=" + username + ". Objeto Comissão de pk={} não encontrado.".format(context['form'].initial['comissao'])) self.logger.error("user=" + username + ". Objeto Comissão de pk={} não encontrado.".format(
context['form'].initial['comissao']))
pass pass
else: else:
self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format(context['form'].initial['comissao'])) self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format(
context['form'].initial['comissao']))
composicao = comissao.composicao_set.order_by( composicao = comissao.composicao_set.order_by(
'-periodo__data_inicio').first() '-periodo__data_inicio').first()
participacao = Participacao.objects.filter( participacao = Participacao.objects.filter(
@ -1122,14 +1149,17 @@ class RelatoriaCrud(MasterDetailCrud):
username = self.request.user.username.replace("'", "") username = self.request.user.username.replace("'", "")
try: try:
self.logger.debug("user=" + username + ". Tentando obter objeto Comissao de pk={}.".format(context['form'].initial['comissao'])) self.logger.debug("user=" + username + ". Tentando obter objeto Comissao de pk={}.".format(
context['form'].initial['comissao']))
comissao = Comissao.objects.get( comissao = Comissao.objects.get(
pk=context['form'].initial['comissao']) pk=context['form'].initial['comissao'])
except ObjectDoesNotExist: except ObjectDoesNotExist:
self.logger.error("user=" + username + ". Objeto Comissão de pk={} não encontrado.".format(context['form'].initial['comissao'])) self.logger.error("user=" + username + ". Objeto Comissão de pk={} não encontrado.".format(
context['form'].initial['comissao']))
pass pass
else: else:
self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format(context['form'].initial['comissao'])) self.logger.info("user=" + username + ". Objeto Comissao de pk={} obtido com sucesso.".format(
context['form'].initial['comissao']))
composicao = comissao.composicao_set.order_by( composicao = comissao.composicao_set.order_by(
'-periodo__data_inicio').first() '-periodo__data_inicio').first()
participacao = Participacao.objects.filter( participacao = Participacao.objects.filter(
@ -1640,7 +1670,8 @@ class AcompanhamentoConfirmarView(TemplateView):
def get_redirect_url(self, email): def get_redirect_url(self, email):
username = self.request.user.username.replace("'", "") username = self.request.user.username.replace("'", "")
self.logger.debug('user=' + username + '. Esta matéria está sendo acompanhada pelo e-mail: %s' % (email)) self.logger.debug(
'user=' + username + '. Esta matéria está sendo acompanhada pelo e-mail: %s' % (email))
msg = _('Esta matéria está sendo acompanhada pelo e-mail: %s') % ( msg = _('Esta matéria está sendo acompanhada pelo e-mail: %s') % (
email) email)
messages.add_message(self.request, messages.SUCCESS, msg) messages.add_message(self.request, messages.SUCCESS, msg)
@ -1680,7 +1711,8 @@ class AcompanhamentoExcluirView(TemplateView):
def get_success_url(self): def get_success_url(self):
username = self.request.user.username.replace("'", "") username = self.request.user.username.replace("'", "")
self.logger.debug("user=" + username + ". Você parou de acompanhar esta matéria.") self.logger.debug("user=" + username +
". Você parou de acompanhar esta matéria.")
msg = _('Você parou de acompanhar esta matéria.') msg = _('Você parou de acompanhar esta matéria.')
messages.add_message(self.request, messages.INFO, msg) messages.add_message(self.request, messages.INFO, msg)
return reverse('sapl.materia:materialegislativa_detail', return reverse('sapl.materia:materialegislativa_detail',
@ -1790,6 +1822,12 @@ class AcompanhamentoMateriaView(CreateView):
return ''.join(choice(s) for i in range(choice([6, 7]))) return ''.join(choice(s) for i in range(choice([6, 7])))
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if not mail_service_configured():
self.logger.warning(_('Servidor de email não configurado.'))
messages.error(request, _('Serviço de Acompanhamento de '
'Matérias não foi configurado'))
return redirect('/')
pk = self.kwargs['pk'] pk = self.kwargs['pk']
materia = MateriaLegislativa.objects.get(id=pk) materia = MateriaLegislativa.objects.get(id=pk)
@ -1798,6 +1836,13 @@ class AcompanhamentoMateriaView(CreateView):
'materia': materia}) 'materia': materia})
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
if not settings.EMAIL_HOST:
self.logger.warning(_('Servidor de email não configurado.'))
messages.error(request, _('Serviço de Acompanhamento de '
'Matérias não foi configurado'))
return redirect('/')
form = AcompanhamentoMateriaForm(request.POST) form = AcompanhamentoMateriaForm(request.POST)
pk = self.kwargs['pk'] pk = self.kwargs['pk']
materia = MateriaLegislativa.objects.get(id=pk) materia = MateriaLegislativa.objects.get(id=pk)
@ -1845,7 +1890,8 @@ class AcompanhamentoMateriaView(CreateView):
# Caso esse Acompanhamento já exista # Caso esse Acompanhamento já exista
# avisa ao usuário que essa matéria já está sendo acompanhada # avisa ao usuário que essa matéria já está sendo acompanhada
else: else:
self.logger.debug("user=" + usuario.username + ". Este e-mail já está acompanhando essa matéria.") self.logger.debug("user=" + usuario.username +
". Este e-mail já está acompanhando essa matéria.")
msg = _('Este e-mail já está acompanhando essa matéria.') msg = _('Este e-mail já está acompanhando essa matéria.')
messages.add_message(request, messages.INFO, msg) messages.add_message(request, messages.INFO, msg)
@ -1966,7 +2012,6 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
return context return context
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
marcadas = request.POST.getlist('materia_id') marcadas = request.POST.getlist('materia_id')
@ -1991,7 +2036,6 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
messages.add_message(request, messages.ERROR, msg) messages.add_message(request, messages.ERROR, msg)
return self.get(request, self.kwargs) return self.get(request, self.kwargs)
if not request.POST['data_encaminhamento']: if not request.POST['data_encaminhamento']:
data_encaminhamento = None data_encaminhamento = None
else: else:
@ -2026,7 +2070,8 @@ class PrimeiraTramitacaoEmLoteView(PermissionRequiredMixin, FilterView):
) )
t.save() t.save()
try: try:
self.logger.debug("user=" + username + ". Tentando enviar tramitação.") self.logger.debug("user=" + username +
". Tentando enviar tramitação.")
tramitacao_signal.send(sender=Tramitacao, tramitacao_signal.send(sender=Tramitacao,
post=t, post=t,
request=self.request) request=self.request)
@ -2211,11 +2256,13 @@ class FichaSelecionaView(PermissionRequiredMixin, FormView):
username = self.request.user.username.replace("'", "") username = self.request.user.username.replace("'", "")
try: try:
self.logger.debug("user=" + username + ". Tentando obter objeto MateriaLegislativa com id={}".format(form.data['materia'])) self.logger.debug(
"user=" + username + ". Tentando obter objeto MateriaLegislativa com id={}".format(form.data['materia']))
materia = MateriaLegislativa.objects.get( materia = MateriaLegislativa.objects.get(
id=form.data['materia']) id=form.data['materia'])
except ObjectDoesNotExist: except ObjectDoesNotExist:
self.logger.error("user=" + username + ". Esta MáteriaLegislativa não existe (id={}).".format(form.data['materia'])) self.logger.error(
"user=" + username + ". Esta MáteriaLegislativa não existe (id={}).".format(form.data['materia']))
mensagem = _('Esta Máteria não existe!') mensagem = _('Esta Máteria não existe!')
self.messages.add_message(self.request, messages.INFO, mensagem) self.messages.add_message(self.request, messages.INFO, mensagem)

68
sapl/protocoloadm/views.py

@ -1,8 +1,10 @@
from datetime import datetime from datetime import datetime
import logging
from random import choice from random import choice
from string import ascii_letters, digits from string import ascii_letters, digits
from braces.views import FormValidMessageMixin from braces.views import FormValidMessageMixin
from django.conf import settings
from django.contrib import messages from django.contrib import messages
from django.contrib.auth.decorators import permission_required from django.contrib.auth.decorators import permission_required
from django.contrib.auth.mixins import PermissionRequiredMixin from django.contrib.auth.mixins import PermissionRequiredMixin
@ -21,17 +23,18 @@ from django.views.generic.edit import FormView
from django_filters.views import FilterView from django_filters.views import FilterView
import sapl import sapl
import logging from sapl.base.email_utils import do_envia_email_confirmacao
from sapl.comissoes.models import Comissao
from sapl.base.models import Autor, CasaLegislativa from sapl.base.models import Autor, CasaLegislativa
from sapl.base.signals import tramitacao_signal
from sapl.comissoes.models import Comissao
from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination from sapl.crud.base import Crud, CrudAux, MasterDetailCrud, make_pagination
from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa from sapl.materia.models import MateriaLegislativa, TipoMateriaLegislativa
from sapl.parlamentares.models import Legislatura, Parlamentar from sapl.parlamentares.models import Legislatura, Parlamentar
from sapl.protocoloadm.models import Protocolo from sapl.protocoloadm.models import Protocolo
from sapl.utils import (create_barcode, get_base_url, get_client_ip, from sapl.utils import (create_barcode, get_base_url, get_client_ip,
get_mime_type_from_file_extension, get_mime_type_from_file_extension,
show_results_filter_set) show_results_filter_set, mail_service_configured)
from sapl.base.email_utils import do_envia_email_confirmacao
from .forms import (AcompanhamentoDocumentoForm, AnularProcoloAdmForm, from .forms import (AcompanhamentoDocumentoForm, AnularProcoloAdmForm,
DocumentoAcessorioAdministrativoForm, DocumentoAcessorioAdministrativoForm,
DocumentoAdministrativoFilterSet, DocumentoAdministrativoFilterSet,
@ -44,7 +47,6 @@ from .forms import (AcompanhamentoDocumentoForm, AnularProcoloAdmForm,
from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo, from .models import (AcompanhamentoDocumento, DocumentoAcessorioAdministrativo,
DocumentoAdministrativo, StatusTramitacaoAdministrativo, DocumentoAdministrativo, StatusTramitacaoAdministrativo,
TipoDocumentoAdministrativo, TramitacaoAdministrativo) TipoDocumentoAdministrativo, TramitacaoAdministrativo)
from sapl.base.signals import tramitacao_signal
TipoDocumentoAdministrativoCrud = CrudAux.build( TipoDocumentoAdministrativoCrud = CrudAux.build(
@ -63,7 +65,8 @@ def recuperar_materia_protocolo(request):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
username = request.user.username username = request.user.username
try: try:
logger.debug("user=" + username + ". Tentando obter matéria com tipo={}, ano={} e numero={}.".format(tipo, ano, numero)) logger.debug("user=" + username +
". Tentando obter matéria com tipo={}, ano={} e numero={}.".format(tipo, ano, numero))
materia = MateriaLegislativa.objects.get( materia = MateriaLegislativa.objects.get(
tipo=tipo, ano=ano, numero=numero) tipo=tipo, ano=ano, numero=numero)
autoria = materia.autoria_set.first() autoria = materia.autoria_set.first()
@ -78,6 +81,7 @@ def recuperar_materia_protocolo(request):
response = JsonResponse({'error': e}) response = JsonResponse({'error': e})
return response return response
def doc_texto_integral(request, pk): def doc_texto_integral(request, pk):
can_see = True can_see = True
@ -102,13 +106,15 @@ def doc_texto_integral(request, pk):
return response return response
raise Http404 raise Http404
class AcompanhamentoConfirmarView(TemplateView): class AcompanhamentoConfirmarView(TemplateView):
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def get_redirect_url(self, email): def get_redirect_url(self, email):
username = self.request.user.username username = self.request.user.username
self.logger.info('user=' + username + '. Este documento está sendo acompanhado pelo e-mail: {}'.format(email)) self.logger.info(
'user=' + username + '. Este documento está sendo acompanhado pelo e-mail: {}'.format(email))
msg = _('Este documento está sendo acompanhado pelo e-mail: %s') % ( msg = _('Este documento está sendo acompanhado pelo e-mail: %s') % (
email) email)
messages.add_message(self.request, messages.SUCCESS, msg) messages.add_message(self.request, messages.SUCCESS, msg)
@ -116,6 +122,7 @@ class AcompanhamentoConfirmarView(TemplateView):
kwargs={'pk': self.kwargs['pk']}) kwargs={'pk': self.kwargs['pk']})
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
documento_id = kwargs['pk'] documento_id = kwargs['pk']
hash_txt = request.GET.get('hash_txt', '') hash_txt = request.GET.get('hash_txt', '')
username = request.user.username username = request.user.username
@ -146,7 +153,8 @@ class AcompanhamentoExcluirView(TemplateView):
def get_success_url(self): def get_success_url(self):
username = self.request.user.username username = self.request.user.username
self.logger.info("user=" + username + ". Você parou de acompanhar este Documento (pk={}).".format(self.kwargs['pk'])) self.logger.info(
"user=" + username + ". Você parou de acompanhar este Documento (pk={}).".format(self.kwargs['pk']))
msg = _('Você parou de acompanhar este Documento.') msg = _('Você parou de acompanhar este Documento.')
messages.add_message(self.request, messages.INFO, msg) messages.add_message(self.request, messages.INFO, msg)
return reverse('sapl.protocoloadm:documentoadministrativo_detail', return reverse('sapl.protocoloadm:documentoadministrativo_detail',
@ -178,6 +186,12 @@ class AcompanhamentoDocumentoView(CreateView):
return ''.join(choice(s) for i in range(choice([6, 7]))) return ''.join(choice(s) for i in range(choice([6, 7])))
def get(self, request, *args, **kwargs): def get(self, request, *args, **kwargs):
if not mail_service_configured():
self.logger.warning(_('Servidor de email não configurado.'))
messages.error(request, _('Serviço de Acompanhamento de '
'Documentos não foi configurado'))
return redirect('/')
pk = self.kwargs['pk'] pk = self.kwargs['pk']
documento = DocumentoAdministrativo.objects.get(id=pk) documento = DocumentoAdministrativo.objects.get(id=pk)
@ -186,6 +200,12 @@ class AcompanhamentoDocumentoView(CreateView):
'documento': documento}) 'documento': documento})
def post(self, request, *args, **kwargs): def post(self, request, *args, **kwargs):
if not mail_service_configured():
self.logger.warning(_('Servidor de email não configurado.'))
messages.error(request, _('Serviço de Acompanhamento de '
'Documentos não foi configurado'))
return redirect('/')
form = AcompanhamentoDocumentoForm(request.POST) form = AcompanhamentoDocumentoForm(request.POST)
pk = self.kwargs['pk'] pk = self.kwargs['pk']
documento = DocumentoAdministrativo.objects.get(id=pk) documento = DocumentoAdministrativo.objects.get(id=pk)
@ -233,7 +253,8 @@ class AcompanhamentoDocumentoView(CreateView):
# Caso esse Acompanhamento já exista # Caso esse Acompanhamento já exista
# avisa ao usuário que esse documento já está sendo acompanhado # avisa ao usuário que esse documento já está sendo acompanhado
else: else:
self.logger.info('user=' + request.user.username + '. Este e-mail já está acompanhando esse documento (pk={}).'.format(pk)) self.logger.info('user=' + request.user.username +
'. Este e-mail já está acompanhando esse documento (pk={}).'.format(pk))
msg = _('Este e-mail já está acompanhando esse documento.') msg = _('Este e-mail já está acompanhando esse documento.')
messages.add_message(request, messages.INFO, msg) messages.add_message(request, messages.INFO, msg)
@ -474,7 +495,8 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
protocolo = form.save(commit=False) protocolo = form.save(commit=False)
username = self.request.user.username username = self.request.user.username
try: try:
self.logger.debug("user=" + username + ". Tentando obter sequência de numeração.") self.logger.debug("user=" + username +
". Tentando obter sequência de numeração.")
numeracao = sapl.base.models.AppConfig.objects.last( numeracao = sapl.base.models.AppConfig.objects.last(
).sequencia_numeracao ).sequencia_numeracao
except AttributeError as e: except AttributeError as e:
@ -504,10 +526,13 @@ class ProtocoloDocumentoView(PermissionRequiredMixin,
protocolo.tipo_processo = '0' # TODO validar o significado protocolo.tipo_processo = '0' # TODO validar o significado
protocolo.anulado = False protocolo.anulado = False
if not protocolo.numero: if not protocolo.numero:
protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 protocolo.numero = (
numero['numero__max'] + 1) if numero['numero__max'] else 1
elif protocolo.numero < (numero['numero__max'] + 1) if numero['numero__max'] else 0: elif protocolo.numero < (numero['numero__max'] + 1) if numero['numero__max'] else 0:
msg = _('Número de protocolo deve ser maior que {}'.format(numero['numero__max'])) msg = _('Número de protocolo deve ser maior que {}'.format(
self.logger.error("user=" + username + ". Número de protocolo deve ser maior que {}.".format(numero['numero__max'])) numero['numero__max']))
self.logger.error(
"user=" + username + ". Número de protocolo deve ser maior que {}.".format(numero['numero__max']))
messages.add_message(self.request, messages.ERROR, msg) messages.add_message(self.request, messages.ERROR, msg)
return self.render_to_response(self.get_context_data()) return self.render_to_response(self.get_context_data())
protocolo.ano = timezone.now().year protocolo.ano = timezone.now().year
@ -564,7 +589,8 @@ class ProtocoloMostrarView(PermissionRequiredMixin, TemplateView):
if protocolo.tipo_materia: if protocolo.tipo_materia:
self.logger.debug( self.logger.debug(
"user=" + username + ". Tentando obter objeto MateriaLegislativa com numero_protocolo={} e ano={}." "user=" + username +
". Tentando obter objeto MateriaLegislativa com numero_protocolo={} e ano={}."
.format(protocolo.numero, protocolo.ano)) .format(protocolo.numero, protocolo.ano))
materia = MateriaLegislativa.objects.filter( materia = MateriaLegislativa.objects.filter(
numero_protocolo=protocolo.numero, ano=protocolo.ano) numero_protocolo=protocolo.numero, ano=protocolo.ano)
@ -636,7 +662,8 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
protocolo = form.save(commit=False) protocolo = form.save(commit=False)
username = self.request.user.username username = self.request.user.username
try: try:
self.logger.debug("user=" + username + ". Tentando obter sequência de numeração.") self.logger.debug("user=" + username +
". Tentando obter sequência de numeração.")
numeracao = sapl.base.models.AppConfig.objects.last( numeracao = sapl.base.models.AppConfig.objects.last(
).sequencia_numeracao ).sequencia_numeracao
except AttributeError: except AttributeError:
@ -667,12 +694,14 @@ class ProtocoloMateriaView(PermissionRequiredMixin, CreateView):
numero['numero__max'] = 0 numero['numero__max'] = 0
if not protocolo.numero: if not protocolo.numero:
protocolo.numero = (numero['numero__max'] + 1) if numero['numero__max'] else 1 protocolo.numero = (
numero['numero__max'] + 1) if numero['numero__max'] else 1
if numero['numero__max']: if numero['numero__max']:
if protocolo.numero < (numero['numero__max'] + 1): if protocolo.numero < (numero['numero__max'] + 1):
self.logger.error("user=" + username + ". Número de protocolo ({}) é menor que {}" self.logger.error("user=" + username + ". Número de protocolo ({}) é menor que {}"
.format(protocolo.numero, numero['numero__max'])) .format(protocolo.numero, numero['numero__max']))
msg = _('Número de protocolo deve ser maior que {}').format(numero['numero__max']) msg = _('Número de protocolo deve ser maior que {}').format(
numero['numero__max'])
messages.add_message(self.request, messages.ERROR, msg) messages.add_message(self.request, messages.ERROR, msg)
return self.render_to_response(self.get_context_data()) return self.render_to_response(self.get_context_data())
protocolo.ano = timezone.now().year protocolo.ano = timezone.now().year
@ -788,7 +817,6 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
if 'o' in self.request.GET and not self.request.GET['o']: if 'o' in self.request.GET and not self.request.GET['o']:
qs = qs.order_by('-ano', '-numero') qs = qs.order_by('-ano', '-numero')
kwargs.update({ kwargs.update({
'queryset': qs, 'queryset': qs,
}) })
@ -825,7 +853,8 @@ class PesquisarDocumentoAdministrativoView(DocumentoAdministrativoMixin,
self.filterset.form.fields['o'].label = _('Ordenação') self.filterset.form.fields['o'].label = _('Ordenação')
# é usada essa verificação anônima para quando os documentos administrativos # é usada essa verificação anônima para quando os documentos administrativos
# estão no modo ostensivo, mas podem existir documentos administrativos restritos # estão no modo ostensivo, mas podem existir documentos administrativos
# restritos
if request.user.is_anonymous(): if request.user.is_anonymous():
length = self.object_list.filter(restrito=False).count() length = self.object_list.filter(restrito=False).count()
else: else:
@ -905,6 +934,7 @@ class TramitacaoAdmCrud(MasterDetailCrud):
class UpdateView(MasterDetailCrud.UpdateView): class UpdateView(MasterDetailCrud.UpdateView):
form_class = TramitacaoAdmEditForm form_class = TramitacaoAdmEditForm
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def form_valid(self, form): def form_valid(self, form):
self.object = form.save() self.object = form.save()
username = self.request.user.username username = self.request.user.username

5
sapl/settings.py

@ -13,8 +13,8 @@ Quick-start development settings - unsuitable for production
See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/ See https://docs.djangoproject.com/en/1.8/howto/deployment/checklist/
""" """
import socket
import logging import logging
import socket
from decouple import config from decouple import config
from dj_database_url import parse as db_url from dj_database_url import parse as db_url
@ -24,6 +24,7 @@ from unipath import Path
from .temp_suppress_crispy_form_warnings import \ from .temp_suppress_crispy_form_warnings import \
SUPRESS_CRISPY_FORM_WARNINGS_LOGGING SUPRESS_CRISPY_FORM_WARNINGS_LOGGING
host = socket.gethostbyname_ex(socket.gethostname())[0] host = socket.gethostbyname_ex(socket.gethostname())[0]
BASE_DIR = Path(__file__).ancestor(1) BASE_DIR = Path(__file__).ancestor(1)
@ -181,6 +182,7 @@ TEMPLATES = [
"django.template.context_processors.static", "django.template.context_processors.static",
'django.contrib.messages.context_processors.messages', 'django.contrib.messages.context_processors.messages',
'sapl.context_processors.parliament_info', 'sapl.context_processors.parliament_info',
'sapl.context_processors.mail_service_configured',
], ],
'debug': DEBUG 'debug': DEBUG
}, },
@ -223,6 +225,7 @@ EMAIL_USE_TLS = config('EMAIL_USE_TLS', cast=bool, default=True)
EMAIL_SEND_USER = config('EMAIL_SEND_USER', cast=str, default='') EMAIL_SEND_USER = config('EMAIL_SEND_USER', cast=str, default='')
DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', cast=str, default='') DEFAULT_FROM_EMAIL = config('DEFAULT_FROM_EMAIL', cast=str, default='')
SERVER_EMAIL = config('SERVER_EMAIL', cast=str, default='') SERVER_EMAIL = config('SERVER_EMAIL', cast=str, default='')
EMAIL_RUNNING = None
MAX_DOC_UPLOAD_SIZE = 60 * 1024 * 1024 # 60MB MAX_DOC_UPLOAD_SIZE = 60 * 1024 * 1024 # 60MB
MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB MAX_IMAGE_UPLOAD_SIZE = 2 * 1024 * 1024 # 2MB

2
sapl/templates/materia/materialegislativa_detail.html

@ -2,7 +2,7 @@
{% load i18n %} {% load i18n %}
{% block sub_actions %} {% block sub_actions %}
{{ block.super }} {{ block.super }}
{% if object.em_tramitacao %} {% if object.em_tramitacao and mail_service_configured %}
<div class="actions btn-group btn-group-sm" role="group"> <div class="actions btn-group btn-group-sm" role="group">
<a href="{% url 'sapl.materia:acompanhar_materia' object.id %}" class="btn btn-default">Acompanhar Matéria</a> <a href="{% url 'sapl.materia:acompanhar_materia' object.id %}" class="btn btn-default">Acompanhar Matéria</a>
</div> </div>

2
sapl/templates/materia/materialegislativa_filter.html

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

2
sapl/templates/protocoloadm/documentoadministrativo_filter.html

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

19
sapl/utils.py

@ -15,6 +15,7 @@ from django.contrib import admin
from django.contrib.contenttypes.fields import (GenericForeignKey, GenericRel, from django.contrib.contenttypes.fields import (GenericForeignKey, GenericRel,
GenericRelation) GenericRelation)
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.core.mail import get_connection
from django.db.models import Q from django.db.models import Q
from django.utils import six, timezone from django.utils import six, timezone
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
@ -28,11 +29,13 @@ from unipath.path import Path
from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row from sapl.crispy_layout_mixin import SaplFormLayout, form_actions, to_row
# (26/10/2018): O separador foi mudador de '/' para 'K' # (26/10/2018): O separador foi mudador de '/' para 'K'
# por conta dos leitores de códigos de barra, que trocavam # por conta dos leitores de códigos de barra, que trocavam
# a '/' por '&' ou ';' # a '/' por '&' ou ';'
SEPARADOR_HASH_PROPOSICAO = 'K' SEPARADOR_HASH_PROPOSICAO = 'K'
def pil_image(source, exif_orientation=False, **options): def pil_image(source, exif_orientation=False, **options):
return source_generators.pil_image(source, exif_orientation, **options) return source_generators.pil_image(source, exif_orientation, **options)
@ -767,3 +770,19 @@ def RemoveTag(texto):
def remover_acentos(string): def remover_acentos(string):
return unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode() return unicodedata.normalize('NFKD', string).encode('ASCII', 'ignore').decode()
def mail_service_configured(request=None):
if settings.EMAIL_RUNNING is None:
result = True
try:
connection = get_connection()
connection.open()
except Exception as e:
result = False
finally:
connection.close()
settings.EMAIL_RUNNING = result
return settings.EMAIL_RUNNING

Loading…
Cancel
Save